#include "FireBasedProcessingBlockComponent.h" #include "Block.h" #include "ItemFilter.h" #include "Recipie.h" #include "RecipieList.h" #include "RecipieLoader.h" FireBasedProcessingBlockComponent::FireBasedProcessingBlockComponent() : BlockComponent(), burnLight(0), ticksNeeded(0), currentRecipie(0), maxFuelBuffer(0), fuelBuffer(0), burning(0) {} FireBasedProcessingBlockComponent::~FireBasedProcessingBlockComponent() {} bool FireBasedProcessingBlockComponent::findRecipie() { bool changed = 0; RecipieList* zRecipies = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup.getText()); if (zRecipies) { zBlock->lock(); Recipie* recipie = zRecipies->zFirstRecipie(this); if (recipie) { recipie->consumeInputs(this); currentRecipie = recipie; ticksNeeded = recipie->getTicksNeeded(); changed = 1; } zBlock->unlock(); } return changed; } bool FireBasedProcessingBlockComponent::consumeFuel() { bool changed = 0; zBlock->lock(); ItemSlot* fireStartingSlot = 0; ItemSlot* fuelSlot = 0; for (ItemSlot* slot : *zBlock) { if (slot->zStack()) { if (!burning && !fireStartingSlot && slot->getName().istGleich(fireStartingInventorySlotName) && fireStartingItemFilter->matchItem(slot->zStack()->zItem())) { fireStartingSlot = slot; } if (!fuelSlot && slot->getName().istGleich(fuelInventorySlotName) && fuelItemFilter->matchItem(slot->zStack()->zItem())) { fuelSlot = slot; } if (fuelSlot && fireStartingSlot) { break; } } } if (burning) { if (fuelSlot) { ItemStack* fuelStack = fuelSlot->takeItemsOut(1, Direction::NO_DIRECTION); if (fuelStack) { // TODO: check if item is burnable and how much fuel it provides fuelBuffer += 100; maxFuelBuffer = fuelBuffer; fuelStack->release(); changed = 1; } else { if (fuelBuffer == 0) { burning = false; } } } else { if (fuelBuffer == 0) { burning = false; } } } else { if (fuelSlot && fireStartingSlot) { ItemStack* fuelStack = fuelSlot->takeItemsOut(1, Direction::NO_DIRECTION); ItemStack* fireStartingStack = fireStartingSlot->takeItemsOut(1, Direction::NO_DIRECTION); if (fuelStack && fireStartingStack) { // TODO: check if item is burnable and how much fuel it provides fuelBuffer += 100; maxFuelBuffer = fuelBuffer; burning = true; fuelStack->release(); fireStartingStack->release(); changed = 1; } } } zBlock->unlock(); return changed; } void FireBasedProcessingBlockComponent::createProgressMessage( NetworkMessage* message) const { char* msg = new char[8]; *(int*)msg = currentRecipie ? currentRecipie->getTicksNeeded() : 0; *(int*)(msg + 4) = currentRecipie ? currentRecipie->getTicksNeeded() - ticksNeeded : 0; message->setMessage(msg, 8); } void FireBasedProcessingBlockComponent::createFuelMessage( NetworkMessage* message) const { char* msg = new char[8]; *(int*)msg = maxFuelBuffer; *(int*)(msg + 4) = fuelBuffer; message->setMessage(msg, 8); } void FireBasedProcessingBlockComponent::initialize(Block* zBlock) { this->zBlock = zBlock; } bool FireBasedProcessingBlockComponent::tick(int numTicks) { bool active = 0; bool progressChanged = 0; bool fuelChanged = 0; while (numTicks > 0) { if (!fuelBuffer) { fuelChanged |= consumeFuel(); } if (!burning) { break; } if (!currentRecipie) { progressChanged |= findRecipie(); } bool processed = false; if (currentRecipie) { int possibleTicks = fuelBuffer / currentRecipie->getFuelPerTickNeeded(); if (!possibleTicks) { fuelChanged |= consumeFuel(); possibleTicks = fuelBuffer / currentRecipie->getFuelPerTickNeeded(); } if (possibleTicks >= numTicks) { if (numTicks >= ticksNeeded) { numTicks -= ticksNeeded; fuelBuffer -= currentRecipie->getFuelPerTickNeeded() * ticksNeeded; zBlock->lock(); currentRecipie->produceOutputs(this); zBlock->unlock(); ticksNeeded = 0; currentRecipie = 0; } else { ticksNeeded -= numTicks; fuelBuffer -= currentRecipie->getFuelPerTickNeeded() * numTicks; numTicks = 0; } progressChanged = 1; fuelChanged = 1; processed = true; } else { if (possibleTicks >= ticksNeeded) { numTicks -= ticksNeeded; fuelBuffer -= currentRecipie->getFuelPerTickNeeded() * ticksNeeded; zBlock->lock(); currentRecipie->produceOutputs(this); zBlock->unlock(); ticksNeeded = 0; currentRecipie = 0; processed = true; fuelChanged = 1; progressChanged = 1; } else { numTicks -= possibleTicks; fuelBuffer -= currentRecipie->getFuelPerTickNeeded() * possibleTicks; ticksNeeded -= possibleTicks; processed = possibleTicks > 0; progressChanged = possibleTicks > 0; fuelChanged = possibleTicks > 0; } } } if (!processed) { // burning without recipie if (fuelBuffer >= numTicks) { fuelBuffer -= numTicks; numTicks = 0; fuelChanged = 1; } else { fuelChanged = fuelBuffer > 0; numTicks -= fuelBuffer; fuelBuffer = 0; } } active = 1; } if (fuelChanged) { NetworkMessage* fuelMessage = new NetworkMessage(); createFuelMessage(fuelMessage); fuelObservable.notifyObservers(fuelMessage); } if (progressChanged) { NetworkMessage* progressMessage = new NetworkMessage(); createProgressMessage(progressMessage); progressObservable.notifyObservers(progressMessage); } return active; } void FireBasedProcessingBlockComponent::api(Framework::StreamReader* zRequest, NetworkMessage* zResponse, Entity* zSource) { char type; zRequest->lese(&type, 1); switch (type) { case 0: // subscribe to fuel { char idLen; zRequest->lese(&idLen, 1); char* id = new char[idLen + 1]; zRequest->lese(id, idLen); id[(int)idLen] = 0; int processor; zRequest->lese((char*)&processor, 4); fuelObservable.addObserver(zSource, id, processor); createFuelMessage(zResponse); zResponse->addressUIElement(id, processor); break; } case 1: // subscribe to progress { char idLen; zRequest->lese(&idLen, 1); char* id = new char[idLen + 1]; zRequest->lese(id, idLen); id[(int)idLen] = 0; int processor; zRequest->lese((char*)&processor, 4); progressObservable.addObserver(zSource, id, processor); createProgressMessage(zResponse); zResponse->addressUIElement(id, processor); break; } case 2: // unsubscribe to fuel { char idLen; zRequest->lese(&idLen, 1); char* id = new char[idLen + 1]; zRequest->lese(id, idLen); id[(int)idLen] = 0; int processor; zRequest->lese((char*)&processor, 4); fuelObservable.removeObserver(zSource, id, processor); break; } case 3: // unsubscribe to progress { char idLen; zRequest->lese(&idLen, 1); char* id = new char[idLen + 1]; zRequest->lese(id, idLen); id[(int)idLen] = 0; int processor; zRequest->lese((char*)&processor, 4); progressObservable.removeObserver(zSource, id, processor); break; } } } Framework::XML::Element* FireBasedProcessingBlockComponent::getTooltipUIML() const { if (currentRecipie) { Framework::XML::Element* result = new Framework::XML::Element( ""); Framework::Text content; content.append() << "Processing: "; int first = 1; for (const ItemInfo& output : currentRecipie->getOutput()) { if (!first) { content.append() << ", "; } content.append() << output.count << " " << Game::INSTANCE->zItemType(output.type)->getTooltipUIML(); first = 0; } content.append() << " (" << (int)((ticksNeeded / currentRecipie->getTicksNeeded()) * 100) << "%)"; result->setText(content); } return 0; } bool FireBasedProcessingBlockComponent::isAllAvailable( Framework::RCArray& inputs) { return zBlock->isAllAvailable(inputs, inputInventorySlotName); } bool FireBasedProcessingBlockComponent::hasFreeSpace( const Item* zItem, int amount) { int addable = zBlock->numberOfAddableItems( zItem, NO_DIRECTION, inputInventorySlotName); return addable >= amount; } void FireBasedProcessingBlockComponent::consume( Framework::RCArray& inputs) { zBlock->consume(inputs, inputInventorySlotName); } void FireBasedProcessingBlockComponent::addCraftingResult(ItemStack* zStack) { TargetSlotNameItemFilter filter(outputInventorySlotName); zBlock->unsaveAddItem(zStack, NO_DIRECTION, &filter); } Framework::Vec3 FireBasedProcessingBlockComponent::getStorageLocation() const { return zBlock->getLocation(); } int FireBasedProcessingBlockComponent::getStorageDimensionId() const { return zBlock->getDimensionId(); } void FireBasedProcessingBlockComponent::loadComponent( Framework::StreamReader* zReader) { zReader->lese((char*)&ticksNeeded, 4); zReader->lese((char*)&maxFuelBuffer, 4); zReader->lese((char*)&fuelBuffer, 4); zReader->lese((char*)&burning, 1); int index = 0; zReader->lese((char*)&index, 4); if (index >= 0) { // TODO: add unique recipie ids to enshure correct loading after // recipies were changed, added or removed RecipieList* recipies = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup); if (recipies && index < recipies->getRecipieCount()) { currentRecipie = recipies->zRecipie(index); } } } void FireBasedProcessingBlockComponent::saveComponent( Framework::StreamWriter* zWriter) const { zWriter->schreibe((char*)&ticksNeeded, 4); zWriter->schreibe((char*)&maxFuelBuffer, 4); zWriter->schreibe((char*)&fuelBuffer, 4); zWriter->schreibe((char*)&burning, 1); int index = -1; if (currentRecipie) { // TODO: add unique recipie ids to enshure correct loading after // recipies were changed, added or removed RecipieList* recipies = Game::INSTANCE->zRecipies()->zRecipieList(recipieGroup); if (recipies) { index = recipies->getRecipieIndex(currentRecipie); } } zWriter->schreibe((char*)&index, 4); } bool FireBasedProcessingBlockComponent::isLightSource() const { return 1; } int FireBasedProcessingBlockComponent::getLightColor() const { return burning ? burnLight : 0; } FireBasedProcessingBlockComponentFactory:: FireBasedProcessingBlockComponentFactory() : SubTypeFactory() {} FireBasedProcessingBlockComponent* FireBasedProcessingBlockComponentFactory::fromJson( Framework::JSON::JSONObject* zJson) const { FireBasedProcessingBlockComponent* component = new FireBasedProcessingBlockComponent(); if (zJson->hasValue("fireStartingItemFilter")) { component->fireStartingItemFilter = Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("fireStartingItemFilter")); } else { component->fireStartingItemFilter = new AnyItemFilter(); } if (zJson->hasValue("fuelItemFilter")) { component->fuelItemFilter = Game::INSTANCE->zTypeRegistry()->fromJson( zJson->zValue("fuelItemFilter")); } else { component->fuelItemFilter = new AnyItemFilter(); } component->recipieGroup = zJson->zValue("recipieGroup")->asString()->getString(); component->fuelInventorySlotName = zJson->zValue("fuelInventorySlotName")->asString()->getString(); component->fireStartingInventorySlotName = zJson->zValue("fireStartingInventorySlotName") ->asString() ->getString(); component->inputInventorySlotName = zJson->zValue("inputInventorySlotName")->asString()->getString(); component->outputInventorySlotName = zJson->zValue("outputInventorySlotName")->asString()->getString(); component->burnLight = (int)zJson->zValue("lightColor")->asString()->getString(); return component; } Framework::JSON::JSONObject* FireBasedProcessingBlockComponentFactory::toJsonObject( FireBasedProcessingBlockComponent* zObject) const { Framework::JSON::JSONObject* result = new Framework::JSON::JSONObject(); result->addValue("fireStartingItemFilter", Game::INSTANCE->zTypeRegistry()->toJson( zObject->fireStartingItemFilter)); result->addValue("fuelItemFilter", Game::INSTANCE->zTypeRegistry()->toJson(zObject->fuelItemFilter)); result->addValue("recipieGroup", new Framework::JSON::JSONString(zObject->recipieGroup.getText())); result->addValue("fuelInventorySlotName", new Framework::JSON::JSONString( zObject->fuelInventorySlotName.getText())); result->addValue("fireStartingInventorySlotName", new Framework::JSON::JSONString( zObject->fireStartingInventorySlotName.getText())); result->addValue("inputInventorySlotName", new Framework::JSON::JSONString( zObject->inputInventorySlotName.getText())); result->addValue("outputInventorySlotName", new Framework::JSON::JSONString( zObject->outputInventorySlotName.getText())); Framework::Text color = "0x"; color.appendHex(zObject->burnLight); result->addValue("lightColor", new Framework::JSON::JSONString(color)); return result; } JSONObjectValidationBuilder* FireBasedProcessingBlockComponentFactory::addToValidator( JSONObjectValidationBuilder* builder) const { return builder ->withRequiredAttribute("fireStartingItemFilter", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredAttribute("fuelItemFilter", Game::INSTANCE->zTypeRegistry()->getValidator()) ->withRequiredString("recipieGroup") ->finishString() ->withRequiredString("fuelInventorySlotName") ->finishString() ->withRequiredString("fireStartingInventorySlotName") ->finishString() ->withRequiredString("inputInventorySlotName") ->finishString() ->withRequiredString("outputInventorySlotName") ->finishString() ->withRequiredString("lightColor") ->whichStartsWithMatch("0x") ->withDefault("0x0") ->finishString(); return builder; } const char* FireBasedProcessingBlockComponentFactory::getTypeToken() const { return "fireBasedProcessing"; }