-
-
Notifications
You must be signed in to change notification settings - Fork 185
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Redstone comparators reading inventory changes do not always cause updates to nearby redstone components #1750
Comments
Confirmed on 21.4.13-beta (in NeoDev). As I understand it, the problem here is not that redstone comparators in NeoForge only send updates when the signal strength changes, but that the signal strength actually changes for a very brief moment due to the design of Minecraft's inventories. The actual cause of the problem
However, when the source container--in this case, a chest--is called to extract an item, and later to reset the slot in order to 'reverse' the extract, it also calls As you can infer then, because both the extraction and its reversal cause the chest's analog output to be updated, there is a brief window where the analog output dips down to 0 (because the one item in the chest is extracted) and then goes back up to 1 (because the extraction is reversed). That change in analog output is what triggers the comparator to update, thus causing the reported behavior. Indeed, this can be confirmed if you insert another item in the chest. By having two items in the chest, the analog output of the chest stays at 1 even when the first item is extracted and un-extracted by the hopper, thus causing the piston to not flip in sync with the lever. You can confirm this even more if you put exactly enough items in the chest such that taking out one item causes the analog output to change one level. For example, putting a stack and 60 (totalling 124 items) of items in the chest also shows the same behavior as one item (as seen via the piston and lever). That is because a stack and 60 (124) produces an analog signal of 2, while a stack and 59 (123) produces an analog signal of 1. Why NeoForge doesn't trigger the problemNeoForge doesn't trigger the reported behavior because it uses its own item extraction method that respects the The only way I was able to 'reintroduce' the reported behavior was to manually extract and un-extract an item in @@ -18,6 +18,7 @@ import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.DropperBlock;
import net.minecraft.world.level.block.HopperBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.ChestBlockEntity;
import net.minecraft.world.level.block.entity.CrafterBlockEntity;
import net.minecraft.world.level.block.entity.DispenserBlockEntity;
import net.minecraft.world.level.block.entity.Hopper;
@@ -41,6 +42,10 @@ public class VanillaInventoryCodeHooks {
return getSourceItemHandler(level, dest)
.map(itemHandlerResult -> {
IItemHandler handler = itemHandlerResult.getKey();
+ if (itemHandlerResult.getValue() instanceof ChestBlockEntity entity) {
+ ItemStack stack = entity.removeItem(0, 1);
+ entity.setItem(0, stack);
+ }
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack extractItem = handler.extractItem(i, 1, true); By inserting that code, which does the same "extraction then un-extraction" routine by vanilla containers, we cause the analog output to change as stated above and the reported behavior to be reintroduced. Potential solutionAs a potential solution, we could adapt a solution conceptually similar to the above: modify That way, any source object that implements both the An example of the potential solution follows: @@ -42,9 +43,27 @@ public class VanillaInventoryCodeHooks {
.map(itemHandlerResult -> {
IItemHandler handler = itemHandlerResult.getKey();
+ boolean vanillaExtracted = false;
for (int i = 0; i < handler.getSlots(); i++) {
ItemStack extractItem = handler.extractItem(i, 1, true);
if (!extractItem.isEmpty()) {
+ // Mimic HopperBlockEntity#tryTakeInItemFromSlot's behavior of extracting then un-extracting from a slot, to fix #1750
+ // Only do this once per extract operation, which should be enough to mimic the needed behavior
+ if (!vanillaExtracted && itemHandlerResult.getValue() instanceof Container container) {
+ ItemStack originalStack = container.getItem(i);
+ int originalCount = originalStack.getCount();
+ // #removeItem returns a new stack with the requested count, and shrinks the old existing stack
+ container.removeItem(i, 1);
+
+ // Grow the existing stack back to its original count
+ originalStack.setCount(originalCount);
+ // If the existing stack was emptied, reset the stack back into its slot
+ if (originalCount == 1) {
+ container.setItem(i, originalStack);
+ }
+ vanillaExtracted = true;
+ }
+
for (int j = 0; j < dest.getContainerSize(); j++) {
ItemStack destStack = dest.getItem(j);
if (dest.canPlaceItem(j, extractItem) && (destStack.isEmpty() || destStack.getCount() < d
estStack.getMaxStackSize() && destStack.getCount() < dest.getMaxStackSize() && ItemStack.isSameItemSameComponents(extractItem, destStack))) { |
The potential solution would still be different from vanilla, as the reaction of comparators can differ depending on whether the signal strength of the inventory is reduced by the item extraction attempt. In Lithium's hopper optimizations, I defined the relevant different comparator update patterns that are detectable.
The original report (with one item in the chest) should give the update pattern DECREMENT_UPDATE_INCREMENT_UPDATE. I define two types of comparator updates: Update with signal strength change and update without signal strength change. Vanilla sends up to I will post a few screenshots of the setups detecting the difference in a while |
I believe the mod loader should not change vanilla's behavior. The complexity of emulating these vanilla comparator update patterns probably doesn't belong into a mod loader either. I propose to always send all comparator updates that vanilla sends |
Minecraft Version: 1.21.3
NeoForge Version: 21.3.11-beta
Logs: No log needed
Steps to Reproduce:
Description of issue:
The behavior with neoforge is different from vanilla behavior, breaking certain redstone contraptions. Neoforge redstone comparators seem to only send updates to nearby redstone components when their signal strength actually changes. In vanilla, each inventory update causes the comparator to send updates. Even a player clicking into an empty slot does.
In the setup, the deviation can be observed during step 3:
The piston does not extend or retract when neoforge is installed.
When using vanilla, the piston extends and retracts together with the lever power.
The text was updated successfully, but these errors were encountered: