mirror of
https://github.com/MinecraftForge/MinecraftForge
synced 2026-08-22 04:26:10 -04:00
Fix redstone update order not matching vanilla. (#10392)
Fix redstone updates for comparators going up/down incorrectly. Related: #9973 Fix game test structure rotations being inconsistant (#10391) Co-authored-by: LexManos <LexManos@gmail.com>
This commit is contained in:
parent
f35dce7eb3
commit
ea597ff45a
9 changed files with 190 additions and 4 deletions
|
|
@ -1,12 +1,17 @@
|
|||
--- a/net/minecraft/core/Direction.java
|
||||
+++ b/net/minecraft/core/Direction.java
|
||||
@@ -49,6 +_,10 @@
|
||||
@@ -49,6 +_,15 @@
|
||||
private final Vec3i normal;
|
||||
private final Vec3 normalVec3;
|
||||
private static final Direction[] VALUES = values();
|
||||
+ private static final List<Direction> VALUES_VIEW = java.util.Collections.unmodifiableList(Arrays.asList(VALUES));
|
||||
+ public static final List<Direction> valuesView() {
|
||||
+ return VALUES_VIEW;
|
||||
+ }
|
||||
+ // In vanilla updates are notified only on the horizontal plane, in Forge we also notify up and down
|
||||
+ private static final List<Direction> UPDATE_ORDER = java.util.Collections.unmodifiableList(Stream.concat(Plane.HORIZONTAL.stream(), Plane.VERTICAL.stream()).toList());
|
||||
+ public static final List<Direction> getUpdateOrder() {
|
||||
+ return UPDATE_ORDER;
|
||||
+ }
|
||||
private static final Direction[] BY_3D_DATA = Arrays.stream(VALUES)
|
||||
.sorted(Comparator.comparingInt(p_235687_ -> p_235687_.data3d))
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
--- a/net/minecraft/gametest/framework/GameTestInfo.java
|
||||
+++ b/net/minecraft/gametest/framework/GameTestInfo.java
|
||||
@@ -265,7 +_,7 @@
|
||||
BlockPos blockpos = this.getOrCalculateNorthwestCorner();
|
||||
this.structureBlockEntity = StructureUtils.prepareTestStructure(this, blockpos, this.getRotation(), this.level);
|
||||
this.structureBlockPos = this.structureBlockEntity.getBlockPos();
|
||||
- StructureUtils.addCommandBlockAndButtonToStartTest(this.structureBlockPos, new BlockPos(1, 0, -1), this.getRotation(), this.level);
|
||||
+ StructureUtils.addCommandBlockAndButtonToStartTest(this.structureBlockPos, new BlockPos(1, 0, -1), Rotation.NONE, this.level); // Forge: The control blocks are always in the North West Corner
|
||||
StructureUtils.encaseStructure(this.getStructureBounds(), this.level, !this.testFunction.skyAccess());
|
||||
this.listeners.forEach(p_127630_ -> p_127630_.testStructureLoaded(this));
|
||||
return this;
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
--- a/net/minecraft/gametest/framework/ReportGameListener.java
|
||||
+++ b/net/minecraft/gametest/framework/ReportGameListener.java
|
||||
@@ -151,7 +_,7 @@
|
||||
private static BlockPos getBeaconPos(GameTestInfo p_344999_) {
|
||||
BlockPos blockpos = p_344999_.getStructureBlockPos();
|
||||
BlockPos blockpos1 = new BlockPos(-1, -2, -1);
|
||||
- return StructureTemplate.transform(blockpos.offset(blockpos1), Mirror.NONE, p_344999_.getRotation(), blockpos);
|
||||
+ return blockpos.offset(blockpos1); // Forge: The control blocks are always in the North West Corner
|
||||
}
|
||||
|
||||
private static void updateBeaconGlass(GameTestInfo p_343978_, Block p_344076_) {
|
||||
@@ -167,8 +_,8 @@
|
||||
ServerLevel serverlevel = p_177739_.getLevel();
|
||||
BlockPos blockpos = p_177739_.getStructureBlockPos();
|
||||
BlockPos blockpos1 = new BlockPos(-1, 0, -1);
|
||||
- BlockPos blockpos2 = StructureTemplate.transform(blockpos.offset(blockpos1), Mirror.NONE, p_177739_.getRotation(), blockpos);
|
||||
- serverlevel.setBlockAndUpdate(blockpos2, Blocks.LECTERN.defaultBlockState().rotate(p_177739_.getRotation()));
|
||||
+ BlockPos blockpos2 = blockpos.offset(blockpos1); // Forge: The control blocks are always in the North West Corner
|
||||
+ serverlevel.setBlockAndUpdate(blockpos2, Blocks.LECTERN.defaultBlockState());
|
||||
BlockState blockstate = serverlevel.getBlockState(blockpos2);
|
||||
ItemStack itemstack = createBook(p_177739_.getTestName(), p_177739_.isRequired(), p_177740_);
|
||||
LecternBlock.tryPlaceBook(null, serverlevel, blockpos2, blockstate, itemstack);
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
--- a/net/minecraft/gametest/framework/StructureUtils.java
|
||||
+++ b/net/minecraft/gametest/framework/StructureUtils.java
|
||||
@@ -132,10 +_,16 @@
|
||||
.orElseThrow(() -> new IllegalStateException("Missing test structure: " + p_311701_.getStructureName()))
|
||||
.getSize();
|
||||
BoundingBox boundingbox = getStructureBoundingBox(p_311042_, vec3i, p_310584_);
|
||||
- BlockPos blockpos = getStartCorner(p_311701_, p_311042_, p_310584_, p_312330_);
|
||||
+ BlockPos blockpos = getStartCorner(p_311701_, p_311042_, Rotation.NONE, p_312330_); // Forge: The control blocks are always in the North West Corner
|
||||
forceLoadChunks(boundingbox, p_312330_);
|
||||
clearSpaceForStructure(boundingbox, p_312330_);
|
||||
- return createStructureBlock(p_311701_, blockpos.below(), p_310584_, p_312330_);
|
||||
+ var entity = createStructureBlock(p_311701_, blockpos.below(), p_310584_, p_312330_);
|
||||
+ //Forge: We need to offset the structure so that it will load within bounds.
|
||||
+ if (p_310584_ != Rotation.NONE) {
|
||||
+ var rotated = StructureTemplate.getZeroPositionWithTransform(BlockPos.ZERO, Mirror.NONE, p_310584_, entity.getStructureSize().getX(), entity.getStructureSize().getZ());
|
||||
+ entity.setStructurePos(rotated.offset(new BlockPos(0, 1, 0)));
|
||||
+ }
|
||||
+ return entity;
|
||||
}
|
||||
|
||||
public static void encaseStructure(AABB p_330422_, ServerLevel p_331249_, boolean p_328180_) {
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
--- a/net/minecraft/gametest/framework/TestCommand.java
|
||||
+++ b/net/minecraft/gametest/framework/TestCommand.java
|
||||
@@ -313,7 +_,11 @@
|
||||
return Optional.empty();
|
||||
} else {
|
||||
TestFunction testfunction = optional.get();
|
||||
- GameTestInfo gametestinfo = new GameTestInfo(testfunction, structureblockentity.getRotation(), p_328153_, p_330368_);
|
||||
+ // Forge: The rotation is stored in the structure block, and added in the GameTestInfo constructor.
|
||||
+ // So reverse it to find the manually specified rotation so the test runs the same every time.
|
||||
+ var steps = StructureUtils.getRotationStepsForRotation(structureblockentity.getRotation()) - StructureUtils.getRotationStepsForRotation(testfunction.rotation());
|
||||
+ if (steps < 0) steps += 4;
|
||||
+ GameTestInfo gametestinfo = new GameTestInfo(testfunction, StructureUtils.getRotationForRotationSteps(steps), p_328153_, p_330368_);
|
||||
gametestinfo.setStructureBlockPos(p_332856_);
|
||||
return !verifyStructureExists(p_328153_, gametestinfo.getStructureName()) ? Optional.empty() : Optional.of(gametestinfo);
|
||||
}
|
||||
|
|
@ -157,12 +157,12 @@
|
|||
T t = p_261885_.tryCast(enderdragonpart);
|
||||
if (t != null && p_261688_.test(t)) {
|
||||
p_262071_.add(t);
|
||||
@@ -919,16 +_,15 @@
|
||||
@@ -919,17 +_,16 @@
|
||||
public abstract Scoreboard getScoreboard();
|
||||
|
||||
public void updateNeighbourForOutputSignal(BlockPos p_46718_, Block p_46719_) {
|
||||
- for (Direction direction : Direction.Plane.HORIZONTAL) {
|
||||
+ for (Direction direction : Direction.valuesView()) {
|
||||
+ for (Direction direction : Direction.getUpdateOrder()) {
|
||||
BlockPos blockpos = p_46718_.relative(direction);
|
||||
if (this.hasChunkAt(blockpos)) {
|
||||
BlockState blockstate = this.getBlockState(blockpos);
|
||||
|
|
@ -174,10 +174,12 @@
|
|||
blockpos = blockpos.relative(direction);
|
||||
blockstate = this.getBlockState(blockpos);
|
||||
- if (blockstate.is(Blocks.COMPARATOR)) {
|
||||
- this.neighborChanged(blockstate, blockpos, p_46719_, null, false);
|
||||
+ if (blockstate.getWeakChanges(this, blockpos)) {
|
||||
this.neighborChanged(blockstate, blockpos, p_46719_, null, false);
|
||||
+ blockstate.onNeighborChange(this, blockpos, p_46718_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1031,6 +_,20 @@
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Copyright (c) Forge Development LLC and contributors
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.debug.gameplay.redstone;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.gametest.framework.GameTest;
|
||||
import net.minecraft.gametest.framework.GameTestHelper;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BarrelBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
||||
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
|
||||
import net.minecraftforge.test.BaseTestMod;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
import net.minecraftforge.gametest.GameTestHolder;
|
||||
|
||||
/**
|
||||
* Redstone update orders are important in many contraptions as there are pistons and other things that could conflict with each other.
|
||||
* These tests verify just that, two pistons pushing the same block.
|
||||
*
|
||||
* Partial verification/fix for https://github.com/MinecraftForge/MinecraftForge/issues/9973
|
||||
*/
|
||||
@Mod(UpdateOrder.MODID)
|
||||
@GameTestHolder("forge." + UpdateOrder.MODID)
|
||||
public class UpdateOrder extends BaseTestMod {
|
||||
public static final String MODID = "update_order";
|
||||
private static final int PISTON_DELAY = 4;
|
||||
|
||||
public UpdateOrder(FMLJavaModLoadingContext context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@GameTest(template = "update_order:update_order", rotationSteps = 0)
|
||||
public static void south(GameTestHelper helper) {
|
||||
var chestPos = new BlockPos(0, 1, 0);
|
||||
helper.assertBlockPresent(Blocks.CHEST, chestPos);
|
||||
var chest = helper.<ChestBlockEntity>getBlockEntity(chestPos);
|
||||
chest.setItem(0, new ItemStack(Items.DIRT));
|
||||
|
||||
helper.runAfterDelay(PISTON_DELAY, () -> {
|
||||
var expectedPos = new BlockPos(2, 1, 3);
|
||||
helper.assertBlockPresent(Blocks.WHITE_WOOL, expectedPos);
|
||||
helper.succeed();
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "update_order:update_order", rotationSteps = 1)
|
||||
public static void west(GameTestHelper helper) {
|
||||
var chestPos = new BlockPos(0, 1, 0);
|
||||
helper.assertBlockPresent(Blocks.CHEST, chestPos);
|
||||
var chest = helper.<ChestBlockEntity>getBlockEntity(chestPos);
|
||||
chest.setItem(0, new ItemStack(Items.DIRT));
|
||||
|
||||
helper.runAfterDelay(PISTON_DELAY, () -> {
|
||||
var expectedPos = new BlockPos(2, 1, 3);
|
||||
helper.assertBlockPresent(Blocks.WHITE_WOOL, expectedPos);
|
||||
helper.succeed();
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "update_order:update_order", rotationSteps = 2)
|
||||
public static void north(GameTestHelper helper) {
|
||||
var chestPos = new BlockPos(0, 1, 0);
|
||||
helper.assertBlockPresent(Blocks.CHEST, chestPos);
|
||||
var chest = helper.<ChestBlockEntity>getBlockEntity(chestPos);
|
||||
chest.setItem(0, new ItemStack(Items.DIRT));
|
||||
|
||||
helper.runAfterDelay(4, () -> {
|
||||
var expectedPos = new BlockPos(3, 1, 2);
|
||||
helper.assertBlockPresent(Blocks.WHITE_WOOL, expectedPos);
|
||||
helper.succeed();
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "update_order:update_order", rotationSteps = 3)
|
||||
public static void east(GameTestHelper helper) {
|
||||
var chestPos = new BlockPos(0, 1, 0);
|
||||
helper.assertBlockPresent(Blocks.CHEST, chestPos);
|
||||
var chest = helper.<ChestBlockEntity>getBlockEntity(chestPos);
|
||||
chest.setItem(0, new ItemStack(Items.DIRT));
|
||||
|
||||
helper.runAfterDelay(PISTON_DELAY, () -> {
|
||||
var expectedPos = new BlockPos(2, 1, 3);
|
||||
helper.assertBlockPresent(Blocks.WHITE_WOOL, expectedPos);
|
||||
helper.succeed();
|
||||
});
|
||||
}
|
||||
|
||||
@GameTest(template = "update_order:upward_update")
|
||||
public static void up(GameTestHelper helper) {
|
||||
var chestPos = new BlockPos(0, 1, 2);
|
||||
var expectedPos = new BlockPos(2, 1, 0);
|
||||
var unexpectedPos = new BlockPos(0, 4, 0);
|
||||
helper.assertBlockPresent(Blocks.BARREL, chestPos);
|
||||
helper.assertBlockPresent(Blocks.AIR, expectedPos);
|
||||
helper.assertBlockPresent(Blocks.AIR, unexpectedPos);
|
||||
var chest = helper.<BarrelBlockEntity>getBlockEntity(chestPos);
|
||||
chest.setItem(0, new ItemStack(Items.DIRT));
|
||||
|
||||
helper.runAfterDelay(10, () -> { // There are a lot of things happening, give it a few ticks
|
||||
helper.assertBlockNotPresent(Blocks.WHITE_WOOL, unexpectedPos);
|
||||
helper.assertBlockPresent(Blocks.WHITE_WOOL, expectedPos);
|
||||
helper.succeed();
|
||||
});
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue