From 28e6f6b6bf6969ae464755562b1701696bc2cbe8 Mon Sep 17 00:00:00 2001 From: ishland Date: Wed, 11 Dec 2024 16:42:56 +0800 Subject: [PATCH] fix: missed threading fixes in stronghold and nether fortress --- .../INetherFortressGeneratorPieceData.java | 9 ---- .../common/XPieceDataExtension.java | 7 +++ .../MixinNetherFortressGeneratorPiece.java | 8 ++-- ...MixinNetherFortressGeneratorPieceData.java | 22 ++++++---- .../MixinNetherFortressGeneratorStart.java | 10 +++-- .../threading/MixinStrongholdGenerator.java | 43 +++++++++++-------- .../MixinStrongholdGeneratorPieceData.java | 40 +++++++++++++++++ ...ixes-worldgen-threading-issues.mixins.json | 1 + 8 files changed, 97 insertions(+), 43 deletions(-) delete mode 100644 c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/INetherFortressGeneratorPieceData.java create mode 100644 c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/XPieceDataExtension.java create mode 100644 c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGeneratorPieceData.java diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/INetherFortressGeneratorPieceData.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/INetherFortressGeneratorPieceData.java deleted file mode 100644 index 653759402..000000000 --- a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/INetherFortressGeneratorPieceData.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.ishland.c2me.fixes.worldgen.threading_issues.common; - -import java.util.concurrent.atomic.AtomicInteger; - -public interface INetherFortressGeneratorPieceData { - - AtomicInteger getGeneratedCountAtomic(); - -} diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/XPieceDataExtension.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/XPieceDataExtension.java new file mode 100644 index 000000000..cfc69ed2c --- /dev/null +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/common/XPieceDataExtension.java @@ -0,0 +1,7 @@ +package com.ishland.c2me.fixes.worldgen.threading_issues.common; + +public interface XPieceDataExtension { + + ThreadLocal c2me$getGeneratedCountThreadLocal(); + +} diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPiece.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPiece.java index b303617e3..602f87e73 100644 --- a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPiece.java +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPiece.java @@ -1,6 +1,6 @@ package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading; -import com.ishland.c2me.fixes.worldgen.threading_issues.common.INetherFortressGeneratorPieceData; +import com.ishland.c2me.fixes.worldgen.threading_issues.common.XPieceDataExtension; import net.minecraft.structure.NetherFortressGenerator; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; @@ -10,14 +10,14 @@ @Mixin(NetherFortressGenerator.Piece.class) public class MixinNetherFortressGeneratorPiece { - @Redirect(method = "checkRemainingPieces", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.GETFIELD)) + @Redirect(method = {"checkRemainingPieces", "pickPiece"}, at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.GETFIELD)) private int redirectGetPieceDataGeneratedCount(NetherFortressGenerator.PieceData pieceData) { - return ((INetherFortressGeneratorPieceData) pieceData).getGeneratedCountAtomic().get(); + return ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().get(); } @Redirect(method = "pickPiece", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD)) private void redirectIncrementPieceDataGeneratedCount(NetherFortressGenerator.PieceData pieceData, int value) { // TODO Check when updating minecraft version - ((INetherFortressGeneratorPieceData) pieceData).getGeneratedCountAtomic().incrementAndGet(); + ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().set(value); } } diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPieceData.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPieceData.java index 1d6db8066..859ab4b57 100644 --- a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPieceData.java +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorPieceData.java @@ -1,35 +1,39 @@ package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading; -import com.ishland.c2me.fixes.worldgen.threading_issues.common.INetherFortressGeneratorPieceData; +import com.ishland.c2me.fixes.worldgen.threading_issues.common.XPieceDataExtension; import net.minecraft.structure.NetherFortressGenerator; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Dynamic; import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import java.util.concurrent.atomic.AtomicInteger; - @Mixin(NetherFortressGenerator.PieceData.class) -public class MixinNetherFortressGeneratorPieceData implements INetherFortressGeneratorPieceData { +public class MixinNetherFortressGeneratorPieceData implements XPieceDataExtension { - private final AtomicInteger generatedCountAtomic = new AtomicInteger(); + @Unique + private final ThreadLocal generatedCountThreadLocal = ThreadLocal.withInitial(() -> 0); @Dynamic @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.GETFIELD)) private int redirectGetGeneratedCount(NetherFortressGenerator.PieceData pieceData) { - return this.generatedCountAtomic.get(); + return this.generatedCountThreadLocal.get(); } @SuppressWarnings("MixinAnnotationTarget") @Dynamic @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD), require = 0, expect = 0) private void redirectSetGeneratedCount(NetherFortressGenerator.PieceData pieceData, int value) { - this.generatedCountAtomic.set(value); + if (value == 0) { + generatedCountThreadLocal.remove(); + } else { + this.generatedCountThreadLocal.set(value); + } } @Override - public AtomicInteger getGeneratedCountAtomic() { - return this.generatedCountAtomic; + public ThreadLocal c2me$getGeneratedCountThreadLocal() { + return this.generatedCountThreadLocal; } } diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorStart.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorStart.java index f5c7f88b2..52c67bb79 100644 --- a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorStart.java +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinNetherFortressGeneratorStart.java @@ -1,7 +1,7 @@ package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading; import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile; -import com.ishland.c2me.fixes.worldgen.threading_issues.common.INetherFortressGeneratorPieceData; +import com.ishland.c2me.fixes.worldgen.threading_issues.common.XPieceDataExtension; import net.minecraft.structure.NetherFortressGenerator; import org.objectweb.asm.Opcodes; import org.spongepowered.asm.mixin.Mixin; @@ -23,9 +23,13 @@ public class MixinNetherFortressGeneratorStart { @MakeVolatile @Shadow public NetherFortressGenerator.PieceData lastPiece; - @Redirect(method = "(Lnet/minecraft/util/math/random/Random;II)V", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD)) + @Redirect(method = "(Lnet/minecraft/util/math/random/Random;II)V", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD), require = 2) private void redirectSetPieceDataGeneratedCount(NetherFortressGenerator.PieceData pieceData, int value) { - ((INetherFortressGeneratorPieceData) pieceData).getGeneratedCountAtomic().set(value); + if (value == 0) { + ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().remove(); + } else { + ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().set(value); + } } @Inject(method = "*", at = @At("RETURN")) diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGenerator.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGenerator.java index 1071566eb..0592e579d 100644 --- a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGenerator.java +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGenerator.java @@ -1,42 +1,49 @@ package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading; import com.ishland.c2me.fixes.worldgen.threading_issues.common.IStrongholdGenerator; +import com.ishland.c2me.fixes.worldgen.threading_issues.common.XPieceDataExtension; import net.minecraft.structure.StrongholdGenerator; import org.objectweb.asm.Opcodes; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; -import java.util.Arrays; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; @Mixin(StrongholdGenerator.class) public class MixinStrongholdGenerator implements IStrongholdGenerator { - @Shadow @Final private static StrongholdGenerator.PieceData[] ALL_PIECES; - @Shadow private static List possiblePieces; + @Unique + private static final ThreadLocal> possiblePiecesThreadLocal = ThreadLocal.withInitial(() -> new ArrayList<>()); + @Unique private static final ThreadLocal totalWeightThreadLocal = ThreadLocal.withInitial(() -> 0); + @Unique private static final ThreadLocal> activePieceTypeThreadLocal = new ThreadLocal<>(); - @Redirect(method = "init", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator;possiblePieces:Ljava/util/List;", opcode = Opcodes.PUTSTATIC)) - private static void redirectAssignList(List value) { - possiblePieces = Collections.synchronizedList(value); - final List pieceDataList = Arrays.asList(ALL_PIECES); - pieceDataList.forEach(pieceData -> pieceData.generatedCount = 0); - possiblePieces.addAll(pieceDataList); + @Redirect(method = "init", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator;possiblePieces:Ljava/util/List;", opcode = Opcodes.PUTSTATIC), require = 1) + private static void redirectSetPossiblePieces(List value) { + possiblePiecesThreadLocal.set(value); } - @Redirect(method = "init", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD)) - private static void redirectSetGeneratedCount(StrongholdGenerator.PieceData pieceData, int value) { - // no-op + @Redirect(method = {"init", "checkRemainingPieces", "pickPiece"}, at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator;possiblePieces:Ljava/util/List;", opcode = Opcodes.GETSTATIC), require = 4) + private static List redirectGetPossiblePieces() { + return possiblePiecesThreadLocal.get(); + } + + @Redirect(method = {"checkRemainingPieces", "pickPiece"}, at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator$PieceData;generatedCount:I", opcode = Opcodes.GETFIELD), require = 2) + private static int redirectGetGeneratedCount(StrongholdGenerator.PieceData instance) { + return ((XPieceDataExtension) instance).c2me$getGeneratedCountThreadLocal().get(); } - @Redirect(method = "init", at = @At(value = "INVOKE", target = "Ljava/util/List;add(Ljava/lang/Object;)Z")) - private static boolean redirectListAdd(List list, E e) { - return false; // no-op + @Redirect(method = {"init", "pickPiece"}, at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD), require = 2) + private static void redirectSetGeneratedCount(StrongholdGenerator.PieceData pieceData, int value) { + if (value == 0) { + ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().remove(); + } else { + ((XPieceDataExtension) pieceData).c2me$getGeneratedCountThreadLocal().set(value); + } } @Redirect(method = "checkRemainingPieces", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator;totalWeight:I", opcode = Opcodes.PUTSTATIC)) diff --git a/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGeneratorPieceData.java b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGeneratorPieceData.java new file mode 100644 index 000000000..908772840 --- /dev/null +++ b/c2me-fixes-worldgen-threading-issues/src/main/java/com/ishland/c2me/fixes/worldgen/threading_issues/mixin/threading/MixinStrongholdGeneratorPieceData.java @@ -0,0 +1,40 @@ +package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading; + +import com.ishland.c2me.fixes.worldgen.threading_issues.common.XPieceDataExtension; +import net.minecraft.structure.StrongholdGenerator; +import org.objectweb.asm.Opcodes; +import org.spongepowered.asm.mixin.Dynamic; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Redirect; + +@Mixin(StrongholdGenerator.PieceData.class) +public class MixinStrongholdGeneratorPieceData implements XPieceDataExtension { + + @Unique + private final ThreadLocal generatedCountThreadLocal = ThreadLocal.withInitial(() -> 0); + + @Dynamic + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator$PieceData;generatedCount:I", opcode = Opcodes.GETFIELD), require = 2) + private int redirectGetGeneratedCount(StrongholdGenerator.PieceData pieceData) { + return this.generatedCountThreadLocal.get(); + } + + @SuppressWarnings("MixinAnnotationTarget") + @Dynamic + @Redirect(method = "*", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/StrongholdGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD), require = 0, expect = 0) + private void redirectSetGeneratedCount(StrongholdGenerator.PieceData pieceData, int value) { + if (value == 0) { + generatedCountThreadLocal.remove(); + } else { + this.generatedCountThreadLocal.set(value); + } + } + + @Override + public ThreadLocal c2me$getGeneratedCountThreadLocal() { + return this.generatedCountThreadLocal; + } + +} diff --git a/c2me-fixes-worldgen-threading-issues/src/main/resources/c2me-fixes-worldgen-threading-issues.mixins.json b/c2me-fixes-worldgen-threading-issues/src/main/resources/c2me-fixes-worldgen-threading-issues.mixins.json index a5a2f6db5..b0ed8d8fe 100644 --- a/c2me-fixes-worldgen-threading-issues/src/main/resources/c2me-fixes-worldgen-threading-issues.mixins.json +++ b/c2me-fixes-worldgen-threading-issues/src/main/resources/c2me-fixes-worldgen-threading-issues.mixins.json @@ -23,6 +23,7 @@ "threading.MixinShiftableStructurePiece", "threading.MixinStrongholdGenerator", "threading.MixinStrongholdGeneratorChestCorridor", + "threading.MixinStrongholdGeneratorPieceData", "threading.MixinStrongholdGeneratorPortalRoom", "threading.MixinStrongholdGeneratorSpiralStaircase", "threading.MixinStrongholdGeneratorStart",