diff --git a/CHANGELOG.md b/CHANGELOG.md index 11efb0d..1d87851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.0] - 2024-12-16 + +### Changed + +- Save any unused detla/elapsed time (remainingDeltaTime) to the next tick + in order to process against any inputted cook items, ie provided by hopper. + if none is found then remainingDeltaTime is reset to 0. +- Refactored to use Accessors and Invokers instead of accesstransformer.cfg +- Refactored to use mixin best practices to rename properties. this can cause a + one-time loss of elapsed time on first load of furnace. + +### Added + +- Saving new data -> remainingDeltaTime + ## [1.0.1] - 2024-12-13 ### Changed diff --git a/build.gradle b/build.gradle index 9251bda..9a7d92a 100644 --- a/build.gradle +++ b/build.gradle @@ -84,6 +84,6 @@ publishing { } } -loom { - accessWidenerPath = file("src/main/resources/everfurnace.accesswidener") -} \ No newline at end of file +//loom { +// accessWidenerPath = file("src/main/resources/everfurnace.accesswidener") +//} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index b0793ee..9f4281c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,7 +9,7 @@ yarn_mappings=1.21.4+build.1 loader_version=0.16.9 # Mod Properties -mod_version=1.0.1 +mod_version=1.1.0 maven_group=gottsch archives_base_name=everfurnace diff --git a/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/ModFurnaceBlockEntityMixin.java b/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/EverFurnaceBlockEntity.java similarity index 51% rename from src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/ModFurnaceBlockEntityMixin.java rename to src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/EverFurnaceBlockEntity.java index f034e84..db97162 100644 --- a/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/ModFurnaceBlockEntityMixin.java +++ b/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/EverFurnaceBlockEntity.java @@ -45,23 +45,31 @@ * Created by Mark Gottschling on 12/05/2024 */ @Mixin(AbstractFurnaceBlockEntity.class) -public abstract class ModFurnaceBlockEntityMixin extends LockableContainerBlockEntity implements SidedInventory, RecipeUnlocker, RecipeInputProvider { //}, IModFurnaceBlockEntityMixin { +public abstract class EverFurnaceBlockEntity extends LockableContainerBlockEntity implements SidedInventory, RecipeUnlocker, RecipeInputProvider { //}, IModFurnaceBlockEntityMixin { + @Unique + private static final int INPUT_SLOT = 0; + @Unique + private static final int FUEL_SLOT = 1; + @Unique + private static final int OUTPUT_SLOT = 2; + @Unique + private static final String LAST_GAME_TIME_TAG = "everfurnace_lastGameTime"; @Unique - private long lastGameTime; + private long everfurnace$lastGameTime; - protected ModFurnaceBlockEntityMixin(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { + protected EverFurnaceBlockEntity(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { super(blockEntityType, blockPos, blockState); } @Inject(method = "writeNbt", at = @At("TAIL")) - private void onSave(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup, CallbackInfo ci) { - nbt.putLong("lastGameTime", this.lastGameTime); + private void onSave(NbtCompound nbt, RegistryWrapper.WrapperLookup registries, CallbackInfo ci) { + nbt.putLong(LAST_GAME_TIME_TAG, getEverfurnace$lastGameTime()); } @Inject(method = "readNbt", at = @At("TAIL")) - private void onLoad(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLookup, CallbackInfo ci) { - this.lastGameTime = nbt.getLong("lastGameTime"); + private void onLoad(NbtCompound nbt, RegistryWrapper.WrapperLookup registries, CallbackInfo ci) { + setEverfurnace$lastGameTime(nbt.getLong(LAST_GAME_TIME_TAG)); } /** @@ -75,13 +83,14 @@ private void onLoad(NbtCompound nbt, RegistryWrapper.WrapperLookup registryLooku @Inject(method = "tick", at = @At("HEAD")) // target more specifically somewhere closer to the actual calculations? private static void onTick(ServerWorld world, BlockPos pos, BlockState state, AbstractFurnaceBlockEntity blockEntity, CallbackInfo ci) { // cast block entity as a mixin block entity - ModFurnaceBlockEntityMixin blockEntityMixin = (ModFurnaceBlockEntityMixin)(Object) blockEntity; + EverFurnaceBlockEntity blockEntityMixin = (EverFurnaceBlockEntity)(Object) blockEntity; + IEverFurnaceBlockEntity everFurnaceBlockEntity = (IEverFurnaceBlockEntity) ((Object) blockEntity); // record last world time - long localLastGameTime = blockEntityMixin.getLastGameTime(); - blockEntityMixin.setLastGameTime(blockEntity.getWorld().getTime()); + long localLastGameTime = blockEntityMixin.getEverfurnace$lastGameTime(); + blockEntityMixin.setEverfurnace$lastGameTime(blockEntity.getWorld().getTime()); - if (!blockEntity.isBurning()){ + if (!everFurnaceBlockEntity.callIsBurning()){ return; } @@ -98,38 +107,40 @@ private static void onTick(ServerWorld world, BlockPos pos, BlockState state, Ab * validations * ////////////////////// */ - ItemStack cookStack = blockEntity.inventory.get(AbstractFurnaceBlockEntity.INPUT_SLOT_INDEX); + ItemStack cookStack = everFurnaceBlockEntity.getInventory().get(INPUT_SLOT); if (cookStack.isEmpty()) return; // get the output stack - ItemStack outputStack = blockEntity.inventory.get(AbstractFurnaceBlockEntity.OUTPUT_SLOT_INDEX); + ItemStack outputStack = everFurnaceBlockEntity.getInventory().get(OUTPUT_SLOT); // return if it is already maxed out if (!outputStack.isEmpty() && outputStack.getCount() == blockEntity.getMaxCountPerStack()) return; // test if can accept recipe output SingleStackRecipeInput singleStackRecipeInput = new SingleStackRecipeInput(cookStack); - RecipeEntry recipeEntry; - recipeEntry = (RecipeEntry)blockEntity.matchGetter.getFirstMatch(singleStackRecipeInput, world).orElse(null); + RecipeEntry recipeEntry; + recipeEntry = (RecipeEntry)everFurnaceBlockEntity.getMatchGetter().getFirstMatch(singleStackRecipeInput, world).orElse(null); - if (!AbstractFurnaceBlockEntity.canAcceptRecipeOutput(blockEntity.getWorld().getRegistryManager(), recipeEntry, singleStackRecipeInput, blockEntity.inventory, blockEntity.getMaxCountPerStack())) return; + if (!IEverFurnaceBlockEntity.callCanAcceptRecipeOutput(blockEntity.getWorld().getRegistryManager(), recipeEntry, singleStackRecipeInput, everFurnaceBlockEntity.getInventory(), blockEntity.getMaxCountPerStack())) return; ///////////////////////// /* * begin processing */ // calculate totalBurnTimeRemaining - ItemStack fuelStack = blockEntity.inventory.get(AbstractFurnaceBlockEntity.FUEL_SLOT_INDEX); + ItemStack fuelStack = everFurnaceBlockEntity.getInventory().get(FUEL_SLOT); if (fuelStack.isEmpty()) return; // have to calculate fuel time as it is no longer calculated during readNbt() as in 1.21.1 - if (blockEntity.litTotalTime == 0) { - blockEntity.litTotalTime = blockEntity.getFuelTime(blockEntity.getWorld().getFuelRegistry(), fuelStack); + if (everFurnaceBlockEntity.getLitTotalTime() == 0) { + everFurnaceBlockEntity.setLitTotalTime(everFurnaceBlockEntity.callGetFuelTime(blockEntity.getWorld().getFuelRegistry(), fuelStack)); } - long totalBurnTimeRemaining = (long) (fuelStack.getCount() - 1) * blockEntity.litTotalTime + blockEntity.litTimeRemaining; + long totalBurnTimeRemaining = (long) (fuelStack.getCount() - 1) * everFurnaceBlockEntity.getLitTotalTime() + + everFurnaceBlockEntity.getLitTimeRemaining(); // calculate totalCookTimeRemaining - long totalCookTimeRemaining = (long) (cookStack.getCount() -1) * blockEntity.cookingTotalTime + (blockEntity.cookingTotalTime - blockEntity.cookingTimeSpent); + long totalCookTimeRemaining = (long) (cookStack.getCount() -1) * everFurnaceBlockEntity.getCookingTotalTime() + + (everFurnaceBlockEntity.getCookingTotalTime() - everFurnaceBlockEntity.getCookingTimeSpent()); // determine the max amount of time that can be used before one or both input run out. long maxInputTime = Math.min(totalBurnTimeRemaining, totalCookTimeRemaining); @@ -140,97 +151,105 @@ private static void onTick(ServerWorld world, BlockPos pos, BlockState state, Ab */ long actualAppliedTime = Math.min(deltaTime, maxInputTime); - if (actualAppliedTime < blockEntity.litTotalTime) { + if (actualAppliedTime < everFurnaceBlockEntity.getLitTotalTime()) { // reduce burn time - blockEntity.litTimeRemaining =- (int) actualAppliedTime; - if (blockEntity.litTimeRemaining <= 0) { + everFurnaceBlockEntity.setLitTimeRemaining(everFurnaceBlockEntity.getLitTimeRemaining() + - (int) actualAppliedTime); + + if (everFurnaceBlockEntity.getLitTimeRemaining() <= 0) { Item fuelItem = fuelStack.getItem(); // reduce the size of the fuel stack fuelStack.decrement(1); if (fuelStack.isEmpty()) { - blockEntity.litTimeRemaining = 0; - blockEntity.inventory.set(1, fuelItem.getRecipeRemainder()); + everFurnaceBlockEntity.setLitTimeRemaining(0); + everFurnaceBlockEntity.getInventory().set(1, fuelItem.getRecipeRemainder()); } else { - blockEntity.litTimeRemaining =+ blockEntity.litTotalTime; + everFurnaceBlockEntity.setLitTimeRemaining(everFurnaceBlockEntity.getLitTimeRemaining() + - everFurnaceBlockEntity.getLitTotalTime()); } } } else { - int quotient = (int) (Math.floorDivExact(actualAppliedTime, blockEntity.litTotalTime)); - long remainder = actualAppliedTime % blockEntity.litTotalTime; + int quotient = (int) (Math.floorDivExact(actualAppliedTime, everFurnaceBlockEntity.getLitTotalTime() + )); + long remainder = actualAppliedTime % everFurnaceBlockEntity.getLitTotalTime(); // reduced stack by quotient Item fuelItem = fuelStack.getItem(); fuelStack.decrement(quotient); // reduce litTimeRemaining by remainder - blockEntity.litTimeRemaining =- (int)remainder; - if (blockEntity.litTimeRemaining <= 0) { + everFurnaceBlockEntity.setLitTimeRemaining(everFurnaceBlockEntity.getLitTimeRemaining() - (int) remainder); + if (everFurnaceBlockEntity.getLitTimeRemaining() <= 0) { // reduce the size of the fuel stack fuelStack.decrement(1); } if (fuelStack.isEmpty()) { - blockEntity.litTimeRemaining = 0; - blockEntity.inventory.set(1, fuelItem.getRecipeRemainder()); + everFurnaceBlockEntity.setLitTimeRemaining(0); + everFurnaceBlockEntity.getInventory().set(1, fuelItem.getRecipeRemainder()); } else { - blockEntity.litTimeRemaining =+ blockEntity.litTotalTime; + everFurnaceBlockEntity.setLitTimeRemaining(everFurnaceBlockEntity.getLitTimeRemaining() + everFurnaceBlockEntity.getLitTotalTime()); } } - if (actualAppliedTime < blockEntity.cookingTotalTime) { + if (actualAppliedTime < everFurnaceBlockEntity.getCookingTotalTime()) { // increment cook time - blockEntity.cookingTimeSpent =+ (int) actualAppliedTime; - if (blockEntity.cookingTimeSpent >= blockEntity.cookingTotalTime) { - if (AbstractFurnaceBlockEntity.craftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, blockEntity.inventory, blockEntity.getMaxCountPerStack())) { + everFurnaceBlockEntity.setCookingTimeSpent(everFurnaceBlockEntity.getCookingTimeSpent() + + (int) actualAppliedTime); + if (everFurnaceBlockEntity.getCookingTimeSpent() >= everFurnaceBlockEntity.getCookingTotalTime()) { + if (IEverFurnaceBlockEntity.callCraftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, everFurnaceBlockEntity.getInventory(), blockEntity.getMaxCountPerStack())) { blockEntity.setLastRecipe(recipeEntry); } if (cookStack.isEmpty()) { - blockEntity.cookingTimeSpent = 0; - blockEntity.cookingTotalTime = 0; + everFurnaceBlockEntity.setCookingTimeSpent(0); + everFurnaceBlockEntity.setCookingTotalTime(0); } else { - blockEntity.cookingTotalTime -= blockEntity.cookingTotalTime; + everFurnaceBlockEntity.setCookingTimeSpent(everFurnaceBlockEntity.getCookingTimeSpent() + - everFurnaceBlockEntity.getCookingTotalTime()); } } } // actual applied time is greated that cook time total, // there, need to apply a factor of else { - int quotient = (int) (Math.floorDivExact(actualAppliedTime, blockEntity.cookingTotalTime)); - long remainder = actualAppliedTime % blockEntity.cookingTotalTime; + int quotient = (int) (Math.floorDivExact(actualAppliedTime, everFurnaceBlockEntity.getCookingTotalTime())); + long remainder = actualAppliedTime % everFurnaceBlockEntity.getCookingTotalTime(); // reduced stack by quotient boolean isSuccessful = false; for (int iterations = 0; iterations < quotient; iterations++) { - isSuccessful |= AbstractFurnaceBlockEntity.craftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, blockEntity.inventory, blockEntity.getMaxCountPerStack()); + isSuccessful |= IEverFurnaceBlockEntity.callCraftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, everFurnaceBlockEntity.getInventory(), blockEntity.getMaxCountPerStack()); } // update last recipe if (isSuccessful) blockEntity.setLastRecipe(recipeEntry); // increment cook time - blockEntity.cookingTimeSpent =+ (int) remainder; - if (blockEntity.cookingTimeSpent >= blockEntity.cookingTotalTime) { - if (AbstractFurnaceBlockEntity.craftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, blockEntity.inventory, blockEntity.getMaxCountPerStack())) { + everFurnaceBlockEntity.setCookingTimeSpent(everFurnaceBlockEntity.getCookingTimeSpent() + + (int) remainder); + if (everFurnaceBlockEntity.getCookingTimeSpent() >= everFurnaceBlockEntity.getCookingTotalTime()) { + if (IEverFurnaceBlockEntity.callCraftRecipe(world.getRegistryManager(), recipeEntry, singleStackRecipeInput, everFurnaceBlockEntity.getInventory(), blockEntity.getMaxCountPerStack())) { blockEntity.setLastRecipe(recipeEntry); } if (cookStack.isEmpty()) { - blockEntity.cookingTimeSpent = 0; - blockEntity.cookingTotalTime = 0; + everFurnaceBlockEntity.setCookingTimeSpent(0); + everFurnaceBlockEntity.setCookingTotalTime(0); } else { - blockEntity.cookingTotalTime -= blockEntity.cookingTotalTime; + everFurnaceBlockEntity.setCookingTimeSpent(everFurnaceBlockEntity.getCookingTimeSpent() + - everFurnaceBlockEntity.getCookingTotalTime()); } } } - if(!blockEntity.isBurning()) { - state = state.with(AbstractFurnaceBlock.LIT, Boolean.valueOf(blockEntity.isBurning())); + if(!everFurnaceBlockEntity.callIsBurning()) { + state = state.with(AbstractFurnaceBlock.LIT, Boolean.valueOf(everFurnaceBlockEntity.callIsBurning())); world.setBlockState(pos, state, Block.NOTIFY_ALL); AbstractFurnaceBlockEntity.markDirty(world, pos, state); } } @Unique - public long getLastGameTime() { - return this.lastGameTime; + public long getEverfurnace$lastGameTime() { + return this.everfurnace$lastGameTime; } @Unique - public void setLastGameTime(long gameTime) { - this.lastGameTime = gameTime; + public void setEverfurnace$lastGameTime(long gameTime) { + this.everfurnace$lastGameTime = gameTime; } } diff --git a/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/IEverFurnaceBlockEntity.java b/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/IEverFurnaceBlockEntity.java new file mode 100644 index 0000000..662d544 --- /dev/null +++ b/src/main/java/mod/gottsch/fabric/everfurnace/core/mixin/IEverFurnaceBlockEntity.java @@ -0,0 +1,91 @@ +/* + * This file is part of EverFurnace. + * Copyright (c) 2024 Mark Gottschling (gottsch) + * + * EverFurnace is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * EverFurnace is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with EverFurnace. If not, see . + */ +package mod.gottsch.fabric.everfurnace.core.mixin; + +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; +import net.minecraft.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.item.FuelRegistry; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.AbstractCookingRecipe; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeEntry; +import net.minecraft.recipe.ServerRecipeManager; +import net.minecraft.recipe.input.SingleStackRecipeInput; +import net.minecraft.registry.DynamicRegistryManager; +import net.minecraft.registry.RegistryKey; +import net.minecraft.util.collection.DefaultedList; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +/** + * Created by Mark Gottschling on 12/13/2024 + */ +@Mixin(AbstractFurnaceBlockEntity.class) +public interface IEverFurnaceBlockEntity { + + @Accessor + int getLitTimeRemaining(); + @Accessor("litTimeRemaining") + public void setLitTimeRemaining(int litTimeRemaining); + + @Accessor + int getLitTotalTime(); + @Accessor("litTotalTime") + public void setLitTotalTime(int litTotalTime); + + @Accessor + int getCookingTimeSpent(); + @Accessor("cookingTimeSpent") + public void setCookingTimeSpent(int cookingTimeSpent); + + @Accessor + int getCookingTotalTime(); + @Accessor + public void setCookingTotalTime(int cookingTotalTime); + + @Accessor + DefaultedList getInventory(); + + @Accessor + ServerRecipeManager.MatchGetter getMatchGetter(); + + + @Invoker + public boolean callIsBurning(); + +// @Invoker +// public boolean callCanBurn(RegistryAccess pRecipe, @Nullable RecipeHolder pInventory, NonNullList pMaxStackSize, int p_155008_); + +// @Invoker +// public boolean callBurn(RegistryAccess pRecipe, @Nullable RecipeHolder pInventory, NonNullList pMaxStackSize, int p_267157_); + + @Invoker + public int callGetFuelTime(FuelRegistry fuelRegistry, ItemStack stack); + + @Invoker + public static boolean callCraftRecipe(DynamicRegistryManager dynamicRegistryManager, @Nullable RecipeEntry recipe, SingleStackRecipeInput input, DefaultedList inventory, int maxCount) { + throw new AssertionError(); + } + + @Invoker + public static boolean callCanAcceptRecipeOutput(DynamicRegistryManager dynamicRegistryManager, @Nullable RecipeEntry recipe, SingleStackRecipeInput input, DefaultedList inventory, int maxCount) { + throw new AssertionError(); + } +} diff --git a/src/main/resources/everfurnace.accesswidener b/src/main/resources/everfurnace.accesswidener index 46e2956..509104b 100644 --- a/src/main/resources/everfurnace.accesswidener +++ b/src/main/resources/everfurnace.accesswidener @@ -3,7 +3,9 @@ accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity INPUT_SLO accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity FUEL_SLOT_INDEX I accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity OUTPUT_SLOT_INDEX I accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity inventory Lnet/minecraft/util/collection/DefaultedList; +# litTotalTime = fuelTime accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity litTotalTime I +# litTimeRemaining = burnTime accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity litTimeRemaining I accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity cookingTotalTime I accessible field net/minecraft/block/entity/AbstractFurnaceBlockEntity cookingTimeSpent I diff --git a/src/main/resources/everfurnace.mixins.json b/src/main/resources/everfurnace.mixins.json index 050de13..eec2ecc 100644 --- a/src/main/resources/everfurnace.mixins.json +++ b/src/main/resources/everfurnace.mixins.json @@ -3,7 +3,8 @@ "package": "mod.gottsch.fabric.everfurnace.core.mixin", "compatibilityLevel": "JAVA_21", "mixins": [ - "ModFurnaceBlockEntityMixin" + "EverFurnaceBlockEntity", + "IEverFurnaceBlockEntity" ], "injectors": { "defaultRequire": 1 diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 441d8fb..b750282 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -33,6 +33,5 @@ }, "suggests": { "another-mod": "*" - }, - "accessWidener" : "everfurnace.accesswidener" + } } \ No newline at end of file