#include "FluidBlock.h" #include "Game.h" FluidBlock::FluidBlock(int typeId, Framework::Vec3 pos) : Block(typeId, 0, pos, 0) { transparent = 1; passable = 1; hp = 1; maxHP = 1; hardness = -1.f; speedModifier = 0.5f; tickSource = 1; interactable = 0; fluidAmount = 0; } FluidBlock::~FluidBlock() {} bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked) { nextFlow = 0; int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)]; if (bottom != zBlockType()->getId()) { if (bottom == BlockTypeEnum::AIR) { nextFlow |= 1 << getDirectionIndex(Direction::BOTTOM); } else { if (zNeighbours[getDirectionIndex(Direction::BOTTOM)] && zNeighbours[getDirectionIndex(Direction::BOTTOM)] ->zBlockType() ->getId() == typeId) { Inventory* array[2] = {zNeighbours[getDirectionIndex(Direction::BOTTOM)], this}; MultipleInventoryLock lock(array, 2); FluidBlock* below = dynamic_cast( zNeighbours[getDirectionIndex(Direction::BOTTOM)]); if (below->fluidAmount < 1000) { int transferAmount = MIN(this->fluidAmount, 1000 - below->fluidAmount); below->fluidAmount += transferAmount; this->fluidAmount -= transferAmount; } } int neighborCount = 0; Inventory* others[4]; for (int i = 1; i < 5; i++) { if (neighbourTypes[i] == BlockTypeEnum::FLUID && zNeighbours[i] && zNeighbours[i]->zBlockType()->getId() == typeId) { others[neighborCount] = zNeighbours[i]; neighborCount++; } } if (neighborCount > 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++) { otherFluids[i] = dynamic_cast(others[i]); } // order other fluids increasing by fluid amount sortByAmound(otherFluids, neighborCount); int distCount = 0; int 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 = fluidAmount / (i + 1); distCount = i; } else { break; } } for (int i = 0; i < distCount; i++) { int transferAmount = targetAmount - otherFluids[i]->fluidAmount; otherFluids[i]->fluidAmount += transferAmount; this->fluidAmount -= transferAmount; } // TODO: distribute fluids } // unlock neighborCount = 0; for (int i = 1; i < 5; i++) { int neighbor = neighbourTypes[i]; if (neighbor == BlockTypeEnum::AIR && fluidAmount > neighborCount + 1) { nextFlow |= 1 << i; neighborCount++; } } } } } void FluidBlock::onPostTick() { if (nextFlow != 0) { Game::INSTANCE->doLater([this]() { for (int i = 0; i < 6; i++) { if ((nextFlow | (1 << i)) == nextFlow) { Vec3 pos = getPos() + getDirection(getDirectionFromIndex(i)); if (neighbourTypes[i] == BlockTypeEnum::AIR) { FluidBlock* spawn = new FluidBlock(typeId, pos); spawn->fluidAmount = 1; Game::INSTANCE->zDimension(getDimensionId()) ->placeBlock(pos, spawn); fluidAmount--; } } } if (fluidAmount == 0) { Game::INSTANCE->zDimension(getDimensionId()) ->placeBlock(getPos(), StaticRegistry::INSTANCE .zElement(BlockTypeEnum::AIR) ->createBlockAt(getPos(), 0)); } }); } } 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) { 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; } } else if (count == 4) { 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) { FluidBlock* tmp = array[1]; array[1] = array[2]; array[2] = tmp; } } } FluidBlockType::FluidBlockType(int id, ModelInfo model, const char* name) : BlockType(id, 0, model, 1, 10, 0, name) {} void FluidBlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const { FluidBlock* block = dynamic_cast(zBlock); zReader->lese((char*)&block->fluidAmount, 2); BlockType::loadSuperBlock(zBlock, zReader, dimensionId); } void FluidBlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter) const { FluidBlock* block = dynamic_cast(zBlock); zWriter->schreibe((char*)&block->fluidAmount, 2); BlockType::saveSuperBlock(zBlock, zWriter); } Item* FluidBlockType::createItem() const { return 0; } Block* FluidBlockType::createBlock(Framework::Vec3 position) const { FluidBlock* result = new FluidBlock(getId(), position); result->fluidAmount = 1000; return result; }