|
@@ -7,7 +7,10 @@ FluidBlock::FluidBlock(int typeId,
|
|
|
int dimensionId,
|
|
|
Vec3<float> lightWeights)
|
|
|
: Block(typeId, 0, pos, dimensionId, 0),
|
|
|
- lightWeights(lightWeights)
|
|
|
+ lightWeights(lightWeights),
|
|
|
+ neighborChanged(1),
|
|
|
+ nextFlow(0),
|
|
|
+ maxFlowDistance(8)
|
|
|
{
|
|
|
transparent = 1;
|
|
|
passable = 1;
|
|
@@ -17,111 +20,43 @@ FluidBlock::FluidBlock(int typeId,
|
|
|
speedModifier = 0.5f;
|
|
|
tickSource = 1;
|
|
|
interactable = 0;
|
|
|
- fluidAmount = 0;
|
|
|
- lastBroadcastedAmount = fluidAmount;
|
|
|
+ flowOptions = 0;
|
|
|
+ distanceToSource = 0;
|
|
|
}
|
|
|
|
|
|
FluidBlock::~FluidBlock() {}
|
|
|
|
|
|
bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked)
|
|
|
{
|
|
|
- nextFlow = 0;
|
|
|
- int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)];
|
|
|
- if (bottom == BlockTypeEnum::AIR)
|
|
|
+ if (neighborChanged)
|
|
|
{
|
|
|
- nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (zNeighbours[getDirectionIndex(Direction::BOTTOM)]
|
|
|
- && bottom == zBlockType()->getId())
|
|
|
- {
|
|
|
- Inventory* array[2]
|
|
|
- = {zNeighbours[getDirectionIndex(Direction::BOTTOM)], this};
|
|
|
- MultipleInventoryLock lock(array, 2);
|
|
|
- FluidBlock* below = dynamic_cast<FluidBlock*>(
|
|
|
- zNeighbours[getDirectionIndex(Direction::BOTTOM)]);
|
|
|
- if (below->fluidAmount < 1000)
|
|
|
- {
|
|
|
- short transferAmount = (short)MIN(
|
|
|
- this->fluidAmount, (short)1000 - below->fluidAmount);
|
|
|
- below->fluidAmount
|
|
|
- = (short)(below->fluidAmount + transferAmount);
|
|
|
- this->fluidAmount = (short)(this->fluidAmount - transferAmount);
|
|
|
- }
|
|
|
- }
|
|
|
- short neighborCount = 0;
|
|
|
- Inventory* others[4];
|
|
|
- for (int i = 0; i < 6; i++)
|
|
|
- {
|
|
|
- if (getDirectionFromIndex(i) != Direction::BOTTOM
|
|
|
- && getDirectionFromIndex(i) != Direction::TOP)
|
|
|
- {
|
|
|
- if (neighbourTypes[i] == typeId && zNeighbours[i])
|
|
|
- {
|
|
|
- others[neighborCount] = zNeighbours[i];
|
|
|
- neighborCount++;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (neighborCount > 0)
|
|
|
+ nextFlow -= numTicks;
|
|
|
+ if (nextFlow <= 0)
|
|
|
{
|
|
|
- Inventory* array[5]
|
|
|
- = {this, others[0], others[1], others[2], others[3]};
|
|
|
- MultipleInventoryLock lock(array, neighborCount + 1);
|
|
|
- // all neighbot fluid blocks are locked now
|
|
|
- FluidBlock* otherFluids[4];
|
|
|
- for (int i = 0; i < neighborCount; i++)
|
|
|
+ const FluidBlockType* zType
|
|
|
+ = dynamic_cast<const FluidBlockType*>(zBlockType());
|
|
|
+ if (zType)
|
|
|
{
|
|
|
- otherFluids[i] = dynamic_cast<FluidBlock*>(others[i]);
|
|
|
+ nextFlow = zType->getTicktsToFlow();
|
|
|
}
|
|
|
- // order other fluids increasing by fluid amount
|
|
|
- sortByAmound(otherFluids, neighborCount);
|
|
|
- short distCount = 0;
|
|
|
- short targetAmount = 0;
|
|
|
- for (int i = 1; i <= neighborCount; i++)
|
|
|
- {
|
|
|
- int fluidAmount = this->fluidAmount;
|
|
|
- for (int j = 0; j < i; j++)
|
|
|
- {
|
|
|
- fluidAmount += otherFluids[j]->fluidAmount;
|
|
|
- }
|
|
|
- if (fluidAmount / (i + 1) < this->fluidAmount)
|
|
|
- {
|
|
|
- targetAmount = (short)(fluidAmount / (i + 1));
|
|
|
- distCount = (short)i;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- for (int i = 0; i < distCount; i++)
|
|
|
- {
|
|
|
- short transferAmount
|
|
|
- = (short)(targetAmount - otherFluids[i]->fluidAmount);
|
|
|
- otherFluids[i]->fluidAmount
|
|
|
- = (short)(otherFluids[i]->fluidAmount + transferAmount);
|
|
|
- this->fluidAmount = (short)(this->fluidAmount - transferAmount);
|
|
|
- }
|
|
|
- } // unlock
|
|
|
- neighborCount = 0;
|
|
|
- for (int i = 0; i < 6; i++)
|
|
|
- {
|
|
|
- if (getDirectionFromIndex(i) != Direction::BOTTOM
|
|
|
- && getDirectionFromIndex(i) != Direction::TOP)
|
|
|
+ else
|
|
|
{
|
|
|
- int neighbor = neighbourTypes[i];
|
|
|
- if (neighbor == BlockTypeEnum::AIR
|
|
|
- && fluidAmount > neighborCount + 1)
|
|
|
- {
|
|
|
- nextFlow |= 1 << i;
|
|
|
- neighborCount++;
|
|
|
- }
|
|
|
+ nextFlow = 0;
|
|
|
}
|
|
|
+ neighborChanged = 0;
|
|
|
+ doFlow();
|
|
|
}
|
|
|
+ return true;
|
|
|
}
|
|
|
- return 1;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+void FluidBlock::onPostTick() {}
|
|
|
+
|
|
|
+void FluidBlock::setNeighbourType(Direction dir, int type)
|
|
|
+{
|
|
|
+ Block::setNeighbourType(dir, type);
|
|
|
+ neighborChanged = 1;
|
|
|
}
|
|
|
|
|
|
void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
|
|
@@ -129,122 +64,93 @@ void FluidBlock::sendModelInfo(NetworkMessage* zMessage)
|
|
|
zMessage->addressBlock(this);
|
|
|
char* msg = new char[3];
|
|
|
msg[0] = 2; // fluid amount change
|
|
|
- *(short*)(msg + 1) = fluidAmount;
|
|
|
+ *(msg + 1) = flowOptions;
|
|
|
+ *(msg + 2) = distanceToSource;
|
|
|
zMessage->setMessage(msg, 3);
|
|
|
}
|
|
|
|
|
|
-void FluidBlock::broadcastAmount()
|
|
|
+void FluidBlock::broadcastFlow()
|
|
|
{
|
|
|
- if (lastBroadcastedAmount != fluidAmount)
|
|
|
- {
|
|
|
- lastBroadcastedAmount = fluidAmount;
|
|
|
- NetworkMessage* changeMsg = new NetworkMessage();
|
|
|
- sendModelInfo(changeMsg);
|
|
|
- Game::INSTANCE->broadcastMessage(changeMsg);
|
|
|
- }
|
|
|
+ NetworkMessage* changeMsg = new NetworkMessage();
|
|
|
+ sendModelInfo(changeMsg);
|
|
|
+ Game::INSTANCE->broadcastMessage(changeMsg);
|
|
|
}
|
|
|
|
|
|
-void FluidBlock::onPostTick()
|
|
|
+void FluidBlock::doFlow()
|
|
|
{
|
|
|
- if (nextFlow != 0)
|
|
|
+ bool changed = false;
|
|
|
+ for (int i = 0; i < 6; i++)
|
|
|
{
|
|
|
- Game::INSTANCE->doLater([this]() {
|
|
|
- for (int i = 0; i < 6; i++)
|
|
|
- {
|
|
|
- if ((nextFlow | (1 << i)) == nextFlow)
|
|
|
+ Direction dir = getDirectionFromIndex(i);
|
|
|
+ if (dir & Direction::TOP) continue;
|
|
|
+ if (neighbourTypes[i] == BlockTypeEnum::AIR)
|
|
|
+ {
|
|
|
+ Game::INSTANCE->doLater([this, dir, i]() {
|
|
|
+ if (neighbourTypes[i] == BlockTypeEnum::AIR)
|
|
|
{
|
|
|
- Vec3<int> pos
|
|
|
- = getPos() + getDirection(getDirectionFromIndex(i));
|
|
|
- if (neighbourTypes[i] == BlockTypeEnum::AIR)
|
|
|
+ Block* belowBlock = zBlockType()->createBlockAt(
|
|
|
+ getPos() + getDirection(dir), getDimensionId(), 0);
|
|
|
+ FluidBlock* fluidBlock
|
|
|
+ = dynamic_cast<FluidBlock*>(belowBlock);
|
|
|
+ if (fluidBlock)
|
|
|
{
|
|
|
- FluidBlock* spawn = new FluidBlock(
|
|
|
- typeId, pos, dimensionId, lightWeights);
|
|
|
- spawn->fluidAmount = 1;
|
|
|
+ fluidBlock->distanceToSource
|
|
|
+ = dir & Direction::BOTTOM
|
|
|
+ ? 1
|
|
|
+ : distanceToSource + 1;
|
|
|
+ fluidBlock->flowOptions = (char)dir;
|
|
|
Game::INSTANCE->zDimension(getDimensionId())
|
|
|
- ->placeBlock(pos, spawn);
|
|
|
- fluidAmount--;
|
|
|
+ ->placeBlock(
|
|
|
+ getPos() + getDirection(dir), belowBlock);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ std::cout
|
|
|
+ << "ERROR: created flow fuild block is not an "
|
|
|
+ "instance of FluidBlock\n";
|
|
|
+ belowBlock->release();
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
- if (fluidAmount == 0)
|
|
|
- {
|
|
|
- Game::INSTANCE->zDimension(getDimensionId())
|
|
|
- ->placeBlock(getPos(),
|
|
|
- StaticRegistry<BlockType>::INSTANCE
|
|
|
- .zElement(BlockTypeEnum::AIR)
|
|
|
- ->createBlockAt(getPos(), dimensionId, 0));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- broadcastAmount();
|
|
|
- }
|
|
|
- });
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-void FluidBlock::sortByAmound(FluidBlock** array, int count)
|
|
|
-{
|
|
|
- if (count == 2)
|
|
|
- {
|
|
|
- if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[0];
|
|
|
- array[0] = array[1];
|
|
|
- array[1] = tmp;
|
|
|
- }
|
|
|
- }
|
|
|
- else if (count == 3)
|
|
|
- {
|
|
|
- if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[0];
|
|
|
- array[0] = array[1];
|
|
|
- array[1] = tmp;
|
|
|
+ });
|
|
|
}
|
|
|
- if (array[1]->fluidAmount > array[2]->fluidAmount)
|
|
|
+ else if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType())
|
|
|
{
|
|
|
- FluidBlock* tmp = array[1];
|
|
|
- array[1] = array[2];
|
|
|
- array[2] = tmp;
|
|
|
- }
|
|
|
- if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[0];
|
|
|
- array[0] = array[1];
|
|
|
- array[1] = tmp;
|
|
|
+ if (dir & Direction::BOTTOM) continue;
|
|
|
+ FluidBlock* neighbour = dynamic_cast<FluidBlock*>(zNeighbours[i]);
|
|
|
+ if (neighbour)
|
|
|
+ {
|
|
|
+ if (distanceToSource > neighbour->distanceToSource + 1)
|
|
|
+ {
|
|
|
+ distanceToSource = neighbour->distanceToSource + 1;
|
|
|
+ flowOptions = (char)getOppositeDirection(dir);
|
|
|
+ changed = true;
|
|
|
+ }
|
|
|
+ else if (distanceToSource == neighbour->distanceToSource + 1)
|
|
|
+ {
|
|
|
+ char tmp = flowOptions;
|
|
|
+ flowOptions |= (char)getOppositeDirection(dir);
|
|
|
+ changed |= tmp != flowOptions;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
- else if (count == 4)
|
|
|
+ if (changed)
|
|
|
{
|
|
|
- if (array[0]->fluidAmount > array[1]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[0];
|
|
|
- array[0] = array[1];
|
|
|
- array[1] = tmp;
|
|
|
- }
|
|
|
- if (array[2]->fluidAmount > array[3]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[2];
|
|
|
- array[2] = array[3];
|
|
|
- array[3] = tmp;
|
|
|
- }
|
|
|
- if (array[0]->fluidAmount > array[2]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[0];
|
|
|
- array[0] = array[2];
|
|
|
- array[2] = tmp;
|
|
|
- }
|
|
|
- if (array[1]->fluidAmount > array[3]->fluidAmount)
|
|
|
- {
|
|
|
- FluidBlock* tmp = array[1];
|
|
|
- array[1] = array[3];
|
|
|
- array[3] = tmp;
|
|
|
- }
|
|
|
- if (array[1]->fluidAmount > array[2]->fluidAmount)
|
|
|
+ broadcastFlow();
|
|
|
+ neighborChanged = 1;
|
|
|
+ for (int i = 0; i < 6; i++)
|
|
|
{
|
|
|
- FluidBlock* tmp = array[1];
|
|
|
- array[1] = array[2];
|
|
|
- array[2] = tmp;
|
|
|
+ Direction dir = getDirectionFromIndex(i);
|
|
|
+ if (dir & (Direction::TOP | Direction::BOTTOM)) continue;
|
|
|
+ if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType())
|
|
|
+ {
|
|
|
+ FluidBlock* neighbour
|
|
|
+ = dynamic_cast<FluidBlock*>(zNeighbours[i]);
|
|
|
+ if (neighbour)
|
|
|
+ {
|
|
|
+ neighbour->neighborChanged = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -256,25 +162,37 @@ void FluidBlock::filterPassingLight(unsigned char rgb[3]) const
|
|
|
rgb[2] = (unsigned char)(rgb[2] * lightWeights.z);
|
|
|
}
|
|
|
|
|
|
-short FluidBlock::getFluidAmount() const
|
|
|
+char FluidBlock::getDistanceToSource() const
|
|
|
{
|
|
|
- return fluidAmount;
|
|
|
+ return distanceToSource;
|
|
|
+}
|
|
|
+
|
|
|
+char FluidBlock::getFlowOptions() const
|
|
|
+{
|
|
|
+ return flowOptions;
|
|
|
}
|
|
|
|
|
|
FluidBlockType::FluidBlockType(int id,
|
|
|
ModelInfo model,
|
|
|
const char* name,
|
|
|
int mapColor,
|
|
|
- Vec3<float> lightWeights)
|
|
|
+ Vec3<float> lightWeights,
|
|
|
+ int ticktsToFlow,
|
|
|
+ char flowDistance)
|
|
|
: BlockType(id, 0, model, 1, 10, 0, name, true, mapColor),
|
|
|
- lightWeights(lightWeights)
|
|
|
+ lightWeights(lightWeights),
|
|
|
+ ticktsToFlow(ticktsToFlow),
|
|
|
+ flowDistance(flowDistance)
|
|
|
{}
|
|
|
|
|
|
void FluidBlockType::loadSuperBlock(
|
|
|
Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const
|
|
|
{
|
|
|
FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
|
|
|
- zReader->lese((char*)&block->fluidAmount, 2);
|
|
|
+ zReader->lese(&block->flowOptions, 1);
|
|
|
+ zReader->lese(&block->distanceToSource, 1);
|
|
|
+ block->nextFlow = ticktsToFlow;
|
|
|
+ block->maxFlowDistance = flowDistance;
|
|
|
BlockType::loadSuperBlock(zBlock, zReader, dimensionId);
|
|
|
}
|
|
|
|
|
@@ -282,7 +200,8 @@ void FluidBlockType::saveSuperBlock(
|
|
|
Block* zBlock, Framework::StreamWriter* zWriter) const
|
|
|
{
|
|
|
FluidBlock* block = dynamic_cast<FluidBlock*>(zBlock);
|
|
|
- zWriter->schreibe((char*)&block->fluidAmount, 2);
|
|
|
+ zWriter->schreibe(&block->flowOptions, 1);
|
|
|
+ zWriter->schreibe(&block->distanceToSource, 1);
|
|
|
BlockType::saveSuperBlock(zBlock, zWriter);
|
|
|
}
|
|
|
|
|
@@ -296,11 +215,22 @@ Block* FluidBlockType::createBlock(
|
|
|
{
|
|
|
FluidBlock* result
|
|
|
= new FluidBlock(getId(), position, dimensionId, lightWeights);
|
|
|
- result->fluidAmount = 1000;
|
|
|
+ result->nextFlow = ticktsToFlow;
|
|
|
+ result->maxFlowDistance = flowDistance;
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
bool FluidBlockType::isFluid() const
|
|
|
{
|
|
|
return true;
|
|
|
+}
|
|
|
+
|
|
|
+int FluidBlockType::getTicktsToFlow() const
|
|
|
+{
|
|
|
+ return ticktsToFlow;
|
|
|
+}
|
|
|
+
|
|
|
+char FluidBlockType::getFlowDistance() const
|
|
|
+{
|
|
|
+ return flowDistance;
|
|
|
}
|