#include "FluidBlock.h" #include #include "Dimension.h" #include "FluidContainer.h" #include "Game.h" FluidBlock::FluidBlock(int typeId, Framework::Vec3 pos, int dimensionId, Framework::Vec3 lightWeights) : Block(typeId, pos, dimensionId, 0), lightWeights(lightWeights), neighborChanged(1), nextFlow(0), maxFlowDistance(8) { transparent = 1; passable = 1; hp = 1; maxHP = 1; hardness = -1.f; speedModifier = 0.5f; interactable = 0; flowOptions = 0; distanceToSource = 0; } FluidBlock::~FluidBlock() {} bool FluidBlock::onTick(TickQueue* zQueue, int numTicks, bool& blocked) { if (neighborChanged) { nextFlow -= numTicks; if (nextFlow <= 0) { const FluidBlockType* zType = dynamic_cast(zBlockType()); if (zType) { nextFlow = zType->getTicktsToFlow(); } else { nextFlow = 0; } neighborChanged = 0; doFlow(); } return true; } return false; } void FluidBlock::onPostTick() {} void FluidBlock::setNeighbourType(Direction dir, int type) { Block::setNeighbourType(dir, type); neighborChanged = 1; } void FluidBlock::sendModelInfo(NetworkMessage* zMessage) { zMessage->addressBlock(this); char* msg = new char[3]; msg[0] = 2; // fluid amount change *(msg + 1) = flowOptions; *(msg + 2) = distanceToSource; zMessage->setMessage(msg, 3); } void FluidBlock::doFlow() { bool doesFlowSidewards = 1; if (((zNeighbours[getDirectionIndex(Direction::BOTTOM)] && zNeighbours[getDirectionIndex(Direction::BOTTOM)] ->zBlockType() == zBlockType() || neighbourTypes[getDirectionIndex(Direction::BOTTOM)] == BlockTypeEnum::AIR) && distanceToSource) || distanceToSource >= maxFlowDistance) { doesFlowSidewards = 0; } bool changed = false; int minNeighborDistance = maxFlowDistance; char nextFlowOptions = 0; for (int i = 0; i < 6; i++) { Direction dir = getDirectionFromIndex(i); if (dir & Direction::TOP) { if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType()) { FluidBlock* neighbour = dynamic_cast(zNeighbours[i]); minNeighborDistance = 0; nextFlowOptions = (char)getOppositeDirection(dir); } continue; } if (neighbourTypes[i] == BlockTypeEnum::AIR) { if (dir & Direction::BOTTOM || doesFlowSidewards) { Game::INSTANCE->doLater([this, dir, i]() { if (neighbourTypes[i] == BlockTypeEnum::AIR) { Block* belowBlock = zBlockType()->createBlockAt( getPos() + getDirection(dir), getDimensionId(), 0); FluidBlock* fluidBlock = dynamic_cast(belowBlock); if (fluidBlock) { fluidBlock->distanceToSource = dir & Direction::BOTTOM ? 1 : distanceToSource + 1; fluidBlock->flowOptions = (char)dir; Game::INSTANCE->zDimension(getDimensionId()) ->placeBlock( getPos() + getDirection(dir), belowBlock); } else { Framework::Logging::error() << "created flow fuild block is not an " "instance of FluidBlock"; belowBlock->release(); } } }); } } else if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType()) { if (dir & Direction::BOTTOM) continue; FluidBlock* neighbour = dynamic_cast(zNeighbours[i]); if (neighbour) { if (neighbour->distanceToSource < minNeighborDistance) { minNeighborDistance = neighbour->distanceToSource; nextFlowOptions = (char)getOppositeDirection(dir); } else if (neighbour->distanceToSource == minNeighborDistance) { nextFlowOptions = (char)getOppositeDirection(dir); } } } } if (distanceToSource) { if (minNeighborDistance + 1 > distanceToSource) { distanceToSource = minNeighborDistance + 1; flowOptions = 0; // reavaluated next tick changed = true; } } if (distanceToSource > maxFlowDistance) { distanceToSource = maxFlowDistance; Game::INSTANCE->doLater([this]() { setHP(0.f); }); } if (changed) { broadcastModelInfoChange(); neighborChanged = 1; for (int i = 0; i < 6; i++) { Direction dir = getDirectionFromIndex(i); if (dir & (Direction::TOP | Direction::BOTTOM)) continue; if (zNeighbours[i] && zNeighbours[i]->zBlockType() == zBlockType()) { FluidBlock* neighbour = dynamic_cast(zNeighbours[i]); if (neighbour) { neighbour->neighborChanged = 1; } } } } } bool FluidBlock::isInteractable(const Item* zItem) const { return distanceToSource == 0 && dynamic_cast(zItem); } void FluidBlock::filterPassingLight(unsigned char rgb[3]) const { rgb[0] = (unsigned char)(rgb[0] * lightWeights.x); rgb[1] = (unsigned char)(rgb[1] * lightWeights.y); rgb[2] = (unsigned char)(rgb[2] * lightWeights.z); } TickSourceType FluidBlock::isTickSource() const { return TickSourceType::AFTER_WORLD_UPDATE; } bool FluidBlock::needsTick() const { return neighborChanged; } char FluidBlock::getDistanceToSource() const { return distanceToSource; } char FluidBlock::getFlowOptions() const { return flowOptions; } FluidBlockType::FluidBlockType() : BlockType(), lightWeights(1.f, 1.f, 1.f), ticktsToFlow(20), flowDistance(8), hungerRecoveryPerL(0.f), thirstRecoveryPerL(0.f), heat(10.f) {} void FluidBlockType::loadSuperBlock( Block* zBlock, Framework::StreamReader* zReader, int dimensionId) const { FluidBlock* block = dynamic_cast(zBlock); zReader->lese(&block->flowOptions, 1); zReader->lese(&block->distanceToSource, 1); block->nextFlow = ticktsToFlow; block->maxFlowDistance = flowDistance; BlockType::loadSuperBlock(zBlock, zReader, dimensionId); } void FluidBlockType::saveSuperBlock( Block* zBlock, Framework::StreamWriter* zWriter) const { FluidBlock* block = dynamic_cast(zBlock); zWriter->schreibe(&block->flowOptions, 1); zWriter->schreibe(&block->distanceToSource, 1); 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, lightWeights); result->nextFlow = ticktsToFlow; result->maxFlowDistance = flowDistance; return result; } bool FluidBlockType::isFluid() const { return true; } ItemType* FluidBlockType::createItemType() const { return 0; } void FluidBlockType::setTicktsToFlow(int ticksToFlow) { this->ticktsToFlow = ticksToFlow; } int FluidBlockType::getTicktsToFlow() const { return ticktsToFlow; } void FluidBlockType::setFlowDistance(unsigned char flowDistance) { this->flowDistance = flowDistance; } unsigned char FluidBlockType::getFlowDistance() const { return flowDistance; } void FluidBlockType::setLightWeights(Framework::Vec3 lightWeights) { this->lightWeights = lightWeights; } Framework::Vec3 FluidBlockType::getLightWeights() const { return lightWeights; } void FluidBlockType::setHungerRecoveryPerL(float hungerRecoveryPerL) { this->hungerRecoveryPerL = hungerRecoveryPerL; } float FluidBlockType::getHungerRecoveryPerL() const { return hungerRecoveryPerL; } void FluidBlockType::setThirstRecoveryPerL(float thirstRecoveryPerL) { this->thirstRecoveryPerL = thirstRecoveryPerL; } float FluidBlockType::getThirstRecoveryPerL() const { return thirstRecoveryPerL; } void FluidBlockType::setHeat(float heat) { this->heat = heat; } float FluidBlockType::getHeat() const { return heat; } FluidBlockTypeFactory::FluidBlockTypeFactory() : BlockTypeFactoryBase() {} FluidBlockType* FluidBlockTypeFactory::createValue( Framework::JSON::JSONObject* zJson) const { return new FluidBlockType(); } void FluidBlockTypeFactory::fromJson( FluidBlockType* zResult, Framework::JSON::JSONObject* zJson) const { zResult->setLightWeights( Framework::Vec3((float)zJson->zValue("lightWeight") ->asObject() ->zValue("red") ->asNumber() ->getNumber(), (float)zJson->zValue("lightWeight") ->asObject() ->zValue("green") ->asNumber() ->getNumber(), (float)zJson->zValue("lightWeight") ->asObject() ->zValue("blue") ->asNumber() ->getNumber())); zResult->setTicktsToFlow( (int)zJson->zValue("ticksToFlow")->asNumber()->getNumber()); zResult->setFlowDistance( (char)zJson->zValue("flowDistance")->asNumber()->getNumber()); zResult->setHungerRecoveryPerL( (float)zJson->zValue("hungerRecoveryPerL")->asNumber()->getNumber()); zResult->setThirstRecoveryPerL( (float)zJson->zValue("thirstRecoveryPerL")->asNumber()->getNumber()); zResult->setHeat((float)zJson->zValue("heat")->asNumber()->getNumber()); BlockTypeFactoryBase::fromJson(zResult, zJson); } void FluidBlockTypeFactory::toJson( FluidBlockType* zObject, Framework::JSON::JSONObject* zResult) const { Framework::JSON::JSONObject* lightWeight = new Framework::JSON::JSONObject(); lightWeight->addValue( "red", new Framework::JSON::JSONNumber(zObject->getLightWeights().x)); lightWeight->addValue( "green", new Framework::JSON::JSONNumber(zObject->getLightWeights().y)); lightWeight->addValue( "blue", new Framework::JSON::JSONNumber(zObject->getLightWeights().z)); zResult->addValue("lightWeight", lightWeight); zResult->addValue("ticksToFlow", new Framework::JSON::JSONNumber((double)zObject->getTicktsToFlow())); zResult->addValue("flowDistance", new Framework::JSON::JSONNumber((double)zObject->getFlowDistance())); zResult->addValue("hungerRecoveryPerL", new Framework::JSON::JSONNumber( (double)zObject->getHungerRecoveryPerL())); zResult->addValue("thirstRecoveryPerL", new Framework::JSON::JSONNumber( (double)zObject->getThirstRecoveryPerL())); zResult->addValue( "heat", new Framework::JSON::JSONNumber((double)zObject->getHeat())); BlockTypeFactoryBase::toJson(zObject, zResult); } JSONObjectValidationBuilder* FluidBlockTypeFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return BlockTypeFactoryBase::addToValidator( builder->withRequiredObject("lightWeight") ->withRequiredNumber("red") ->whichIsGreaterOrEqual(0.0) ->whichIsLessOrEqual(1.0) ->finishNumber() ->withRequiredNumber("green") ->whichIsGreaterOrEqual(0.0) ->whichIsLessOrEqual(1.0) ->finishNumber() ->withRequiredNumber("blue") ->whichIsGreaterOrEqual(0.0) ->whichIsLessOrEqual(1.0) ->finishNumber() ->finishObject() ->withRequiredNumber("ticksToFlow") ->whichIsGreaterOrEqual(1.0) ->finishNumber() ->withRequiredNumber("flowDistance") ->whichIsGreaterOrEqual(0.0) ->finishNumber() ->withRequiredNumber("hungerRecoveryPerL") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.0) ->finishNumber() ->withRequiredNumber("thirstRecoveryPerL") ->whichIsGreaterOrEqual(0.0) ->withDefault(0.0) ->finishNumber() ->withRequiredNumber("heat") ->withDefault(10.0) ->finishNumber()); } Framework::Text FluidBlockTypeFactory::getTypeToken() const { return "fluid"; }