Skip to content

Instantly share code, notes, and snippets.

@Rseding91
Created February 7, 2020 19:53
Show Gist options
  • Save Rseding91/a1aad6c8667e1e56865dcb697d0d5083 to your computer and use it in GitHub Desktop.
Save Rseding91/a1aad6c8667e1e56865dcb697d0d5083 to your computer and use it in GitHub Desktop.
void CraftingMachine::update()
{
assert(this->isActive());
assert(!this->isToBeDeconstructed());
/** Attempts to craft the current recipe (setting up the recipe if its a furnace) and returns the results of the attempt. */
ProductionResult result = this->useRecipeOnSource();
bool goToSleep = false;
switch (result)
{
/** No power can mean 1 of 4 things:
* 1. Electric energy source that is out of power: there's no alarm condition for "power available" - sleep is not allowed.
* 2. Burner energy source that is out of power but has items to burn: 1 tick is required to burn the item - sleep is not allowed.
* 3. Burner energy source that is out of power and has no items to burn: sleep is allowed since postTransferHook will be called
* when fuel is inserted into the CraftingMachine's fuel inventory.
* 4. Heat energy source that is out of power: there's no alarm condition for "power available" - sleep is not allowed. */
case ProductionResult::NoPower:
goToSleep = this->energySource->isBurnerSource() && !this->energySource->hasEnergyPotentially();
break;
/** No recipe can mean 1 of 2 things:
* 1. A furnace that can't smelt what ever may be in its inventory (invalid item or not enough for the recipe) : sleep is allowed
* since postTransferHook will be called when more items are inserted into the input inventory.
* 2. A AssemblingMachine that has no recipe set: sleep is allowed since the recipe setup method will wake up the CraftingMachine.*/
case ProductionResult::NoRecipe:
if (this->isFurnace())
this->inputWakeUpList.alarm();
[[fallthrough]];
/** No item inventory - rare but if it happens the CraftingMachine can't do work so it's put to sleep. */
case ProductionResult::NoItemInventory:
/** No fluid inventory - rare but if it happens the CraftingMachine can't do work so it's put to sleep. */
case ProductionResult::NoFluidInventory:
/** Item product overload - too many items in the output inventory to finish the current recipe-in-progress: sleep is allowed
* since postTransferHook will be called when the output inventory count is reduced.*/
case ProductionResult::ItemProductionOverload:
/** Item ingredient shortage - not enough items in the input inventory to craft the recipe: sleep is allowed
* since postTransferHook will be called when the input inventory count is increased.*/
case ProductionResult::ItemIngredientShortage:
this->flags.setShowWorkingVisualizations(false);
goToSleep = true;
break;
case ProductionResult::FluidProductionOverload:
case ProductionResult::FluidIngredientShortage:
this->flags.setShowWorkingVisualizations(false);
break;
case ProductionResult::Success:
{
uint32_t tick = this->getMap().entityTick;
this->workingVisualisationFadeout = Math::min(uint8_t(this->getCurrentFadeout(tick) + 1), WorkingVisualisations::FADOUT_TICK_COUNT);
this->tickOfLastFadoutValue = tick;
break;
}
case ProductionResult::None:
break;
}
bool isOutputOverload = false;
if (this->hasRecipe())
{
const Recipe* recipe = this->getRecipe();
if (recipe->hasItemIngredient() && recipe->hasFluidProduct() &&
this->isFluidBoxManagerActive())
{
ProductionResult outputOverloadStatus = this->hasProductOverload(*this->getRecipe());
/** If the CraftingMachine had a fluid product overload last update and it no longer does
* the inputWakeUpList needs to be alarmed: input inserters will not input during a product overload.*/
if (this->getRecipe()->hasItemIngredient() &&
outputOverloadStatus == ProductionResult::Success &&
this->flags.getFluidOutputOverloadedLastUpdate())
this->inputWakeUpList.alarm();
isOutputOverload = (outputOverloadStatus == ProductionResult::FluidProductionOverload);
}
}
this->flags.setFluidOutputOverloadedLastUpdate(isOutputOverload);
// we check against current version of outputOverload
// there was a bug earlier when instead of current overload status we would check one made directly after FluidBox::update
// however useRecipeOnSource can change outputOverloadStatus (by pouring products into the output fluidbox)
// while at the same time returning ItemIngredientShortage hence resulting in sleep request
if (goToSleep && !isOutputOverload)
{
this->flags.setShowWorkingVisualizations(false);
this->tryToGetToSleep(result);
}
// Only burner and fluid energy sources require manual updating
if (this->energySource->isBurnerSource() || this->energySource->isFluidSource())
this->energySource->update(this, result == ProductionResult::Success || result == ProductionResult::NoPower);
if (this->isActive())
this->setHadFullUpdateTick();
else
this->clearHadFullUpdateTick();
}
ProductionResult CraftingMachine::useRecipeOnSource()
{
prefetch(this->energySource);
prefetch(static_cast<char*>(static_cast<void*>(this->energySource)) + hardware_constructive_interference_size);
if (!this->hasRecipe())
return ProductionResult::NoRecipe;
const Recipe* recipe = this->getRecipe();
const double recipeEnergy = recipe->getEnergyRequired();
// Use productivity first because it can have > 100% of normal energy.
// e.g. - 200% productivity of a recipe that produces 1 per tick would mean 2 bonus per tick
while (this->bonusProduction + GlobalContext::minimumCountableDoubleValue >= recipeEnergy)
{
ProductionResult useBonusResults = this->useBonusProduction(*recipe);
if (useBonusResults != ProductionResult::Success)
return useBonusResults;
if (!this->shouldContinueCrafting())
return useBonusResults;
}
if (this->energyStoredInProduct >= recipeEnergy)
{
ProductionResult useStoredResults = this->useEnergyStoredInProduct(*recipe);
if (useStoredResults != ProductionResult::Success)
return useStoredResults;
if (!this->shouldContinueCrafting())
return useStoredResults;
}
bool takeIngredients = false;
if (this->energyStoredInProduct == 0)
{
ProductionResult canTakeResults = this->canTakeIngredients(*recipe);
// The canTakeIngredients could update this->recipeID.
// I have to update the local recipe pointer if that happened.
if (recipe->getID() != this->recipeID)
recipe = this->getRecipe();
if (canTakeResults != ProductionResult::Success)
return canTakeResults;
takeIngredients = true;
}
double performance = this->extractEnergyAndPollute();
if (performance <= 0)
{
this->flags.setShowWorkingVisualizations(false);
return ProductionResult::NoPower;
}
else
{
if (takeIngredients)
{
this->takeIngredients(*recipe);
this->energyStoredInProduct += this->extraEnergyForProduct;
this->extraEnergyForProduct = 0;
}
this->setupWorkingVisualisationFrames(performance);
}
return ProductionResult::Success;
}
void CraftingMachine::tryToGetToSleep(ProductionResult sleepReason)
{
assert(sleepReason != ProductionResult::Success);
// Don't sleep if there's no recipe (furnace with fluid inputs) or fluid in the output fluidboxes (assembling machine with fluid to output)
if (this->isFluidBoxManagerActive() && (sleepReason == ProductionResult::NoRecipe || this->fluidBoxManager->hasFluidInOutputFluidboxes()))
return;
this->sleepReason = sleepReason;
this->setActive(false, *this);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment