#include "FluidBlock.h" #include "Game.h" FluidBlock::FluidBlock(int typeId, Framework::Vec3 pos, int dimensionId) : Block(typeId, 0, pos, dimensionId, 0) { transparent = 1; passable = 1; hp = 1; maxHP = 1; hardness = -1.f; speedModifier = 0.5f; tickSource = 1; interactable = 0; fluidAmount = 0; lastBroadcastedAmount = fluidAmount; } FluidBlock::~FluidBlock() {} bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked) { nextFlow = 0; int bottom = neighbourTypes[getDirectionIndex(Direction::BOTTOM)]; if (bottom == BlockTypeEnum::AIR) { 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( 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) { 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); 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) { int neighbor = neighbourTypes[i]; if (neighbor == BlockTypeEnum::AIR && fluidAmount > neighborCount + 1) { nextFlow |= 1 << i; neighborCount++; } } } } return 1; } void FluidBlock::sendModelInfo(NetworkMessage* zMessage) { zMessage->addressBlock(this); char* msg = new char[3]; msg[0] = 2; // fluid amount change *(short*)(msg + 1) = fluidAmount; zMessage->setMessage(msg, 3); } void FluidBlock::broadcastAmount() { if (lastBroadcastedAmount != fluidAmount) { lastBroadcastedAmount = fluidAmount; NetworkMessage* changeMsg = new NetworkMessage(); sendModelInfo(changeMsg); Game::INSTANCE->broadcastMessage(changeMsg); } } 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, dimensionId); 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(), 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) { 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, int mapColor) : BlockType(id, 0, model, 1, 10, 0, name, true, mapColor) {} 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, int dimensionId) const { FluidBlock* result = new FluidBlock(getId(), position, dimensionId); result->fluidAmount = 1000; return result; }