Skip to content

Commit

Permalink
refactor: use mixin to remap threading fixes rather than hardcoded in…
Browse files Browse the repository at this point in the history
…termediary names
  • Loading branch information
ishland committed Oct 21, 2024
1 parent df01d50 commit 404e068
Show file tree
Hide file tree
Showing 18 changed files with 215 additions and 150 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public void export(MixinEnvironment env, String name, boolean force, ClassNode c
}

@Override
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
ASMTransformerMakeVolatile.transform(targetClass);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,138 +2,33 @@

import com.ishland.c2me.base.common.util.ASMUtils;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.ClassNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ASMTransformerMakeVolatile {

static final Logger LOGGER = LoggerFactory.getLogger("C2ME (c2me-fixes-worldgen-threading-issues) ASM Transformer");

private static final Map<String, List<String>> makeVolatileFields = new HashMap<>();
private static final Map<String, List<String>> makeVolatileFieldsMapped;

static {
makeVolatileFields.put(
"net/minecraft/class_3353$class_3354", // net/minecraft/structure/MineshaftGenerator$MineshaftCorridor
List.of(
"field_14414:Z" // hasSpawner:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3390$class_3402", // net/minecraft/structure/NetherFortressGenerator$BridgePlatform
List.of(
"field_14498:Z" // hasBlazeSpawner:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3390$class_3398", // net/minecraft/structure/NetherFortressGenerator$CorridorLeftTurn
List.of(
"field_14496:Z" // containsChest:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3390$class_3400", // net/minecraft/structure/NetherFortressGenerator$CorridorRightTurn
List.of(
"field_14497:Z" // containsChest:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3390$class_3407", // net/minecraft/structure/NetherFortressGenerator$Start
List.of(
"field_14506:Lnet/minecraft/class_3390$class_3404;" // lastPiece:Lnet/minecraft/structure/NetherFortressGenerator$PieceData;
)
);
makeVolatileFields.put(
"net/minecraft/class_3366$class_3388", // net/minecraft/structure/OceanMonumentGenerator$PieceSetting
List.of(
"field_14485:Z", // used:Z
"field_14484:Z", // not mapped by yarn
"field_14483:I" // not mapped by yarn
)
);
makeVolatileFields.put(
"net/minecraft/class_3366$class_3374", // net/minecraft/structure/OceanMonumentGenerator$Base
List.of(
"field_14464:Lnet/minecraft/class_3366$class_3388;", // not mapped by yarn
"field_14466:Lnet/minecraft/class_3366$class_3388;" // not mapped by yarn
)
);
makeVolatileFields.put(
"net/minecraft/class_3470", // net/minecraft/structure/SimpleStructurePiece
List.of(
"field_15432:Lnet/minecraft/class_2338;" // pos:Lnet/minecraft/util/math/BlockPos;
)
);
makeVolatileFields.put(
"net/minecraft/class_3421$class_3422", // net/minecraft/structure/StrongholdGenerator$ChestCorridor
List.of(
"field_15268:Z" // chestGenerated:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3421$class_3428", // net/minecraft/structure/StrongholdGenerator$PortalRoom
List.of(
"field_15279:Z" // spawnerPlaced:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3421$class_3434", // net/minecraft/structure/StrongholdGenerator$Start
List.of(
"field_15284:Lnet/minecraft/class_3421$class_3427;", // lastPiece:Lnet/minecraft/structure/StrongholdGenerator$PieceData;
"field_15283:Lnet/minecraft/class_3421$class_3428;" // portalRoom:Lnet/minecraft/structure/StrongholdGenerator$PortalRoom;
)
);
makeVolatileFields.put(
"net/minecraft/class_3418", // net/minecraft/structure/StructurePieceWithDimensions
List.of(
"field_15241:I" // hPos:I
)
);
makeVolatileFields.put(
"net/minecraft/class_3447", // net/minecraft/structure/SwampHutGenerator
List.of(
"field_15322:Z", // hasWitch:Z
"field_16445:Z" // hasCat:Z
)
);
makeVolatileFields.put(
"net/minecraft/class_3471$class_3476", // net/minecraft/structure/WoodlandMansionGenerator$GenerationPiece
List.of(
"field_15450:Lnet/minecraft/class_2470;", // rotation:Lnet/minecraft/util/BlockRotation;
"field_15449:Lnet/minecraft/class_2338;", // position:Lnet/minecraft/util/math/BlockPos;
"field_15448:Ljava/lang/String;" // template:Ljava/lang/String;
)
);

makeVolatileFieldsMapped = makeVolatileFields.entrySet().stream()
.map(entry -> {
String mappedClassName = ASMUtils.mappingResolver.mapClassName(ASMUtils.INTERMEDIARY, entry.getKey().replace('/', '.')).replace('.', '/');
List<String> mappedFieldNames = entry.getValue().stream()
.map(fieldName -> {
String[] split = fieldName.split(":");
return ASMUtils.mappingResolver.mapFieldName(ASMUtils.INTERMEDIARY, entry.getKey().replace('/', '.'), split[0], split[1]) + ":" + ASMUtils.remapFieldDescriptor(split[1]);
}).toList();
return new KeyValue<>(mappedClassName, mappedFieldNames);
}).collect(Collectors.toMap(KeyValue::key, KeyValue::value));
}

public static void transform(ClassNode classNode) {
final List<String> pendingFields = makeVolatileFieldsMapped.get(classNode.name);
if (pendingFields != null) {
// LOGGER.debug("Transforming class {}", classNode.name.replace('/', '.'));
classNode.fields.stream()
.filter(fieldNode -> pendingFields.contains(fieldNode.name + ":" + fieldNode.desc))
.forEach(fieldNode -> {
LOGGER.debug("Making field L{};{}:{} volatile", classNode.name, fieldNode.name, fieldNode.desc);
fieldNode.access |= Opcodes.ACC_VOLATILE;
});
}
classNode.fields.stream()
.filter(fieldNode ->
Stream.concat(Stream.ofNullable(fieldNode.visibleAnnotations), Stream.ofNullable(fieldNode.invisibleAnnotations))
.flatMap(Collection::stream)
.anyMatch(annotationNode -> Type.getDescriptor(MakeVolatile.class).equals(annotationNode.desc))
)
.forEach(fieldNode -> {
LOGGER.debug("Making field L{};{}:{} volatile", classNode.name, fieldNode.name, fieldNode.desc);
fieldNode.access |= Opcodes.ACC_VOLATILE;
});
}

private record KeyValue<K, V>(K key, V value) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.asm;

public @interface MakeVolatile {
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.MineshaftGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(MineshaftGenerator.MineshaftCorridor.class)
public class MixinMineshaftGeneratorMineshaftCorridor {

@MakeVolatile
@Shadow private boolean hasSpawner;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.NetherFortressGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(NetherFortressGenerator.BridgePlatform.class)
public class MixinNetherFortressGeneratorBridgePlatform {

@MakeVolatile
@Shadow private boolean hasBlazeSpawner;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.NetherFortressGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(NetherFortressGenerator.CorridorLeftTurn.class)
public class MixinNetherFortressGeneratorCorridorLeftTurn {

@MakeVolatile
@Shadow private boolean containsChest;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.NetherFortressGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(NetherFortressGenerator.CorridorRightTurn.class)
public class MixinNetherFortressGeneratorCorridorRightTurn {

@MakeVolatile
@Shadow private boolean containsChest;

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
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 net.minecraft.structure.NetherFortressGenerator;
import org.objectweb.asm.Opcodes;
Expand All @@ -19,6 +20,9 @@ public class MixinNetherFortressGeneratorStart {
@Shadow public List<NetherFortressGenerator.PieceData> bridgePieces;
@Shadow public List<NetherFortressGenerator.PieceData> corridorPieces;

@MakeVolatile
@Shadow public NetherFortressGenerator.PieceData lastPiece;

@Redirect(method = "<init>(Lnet/minecraft/util/math/random/Random;II)V", at = @At(value = "FIELD", target = "Lnet/minecraft/structure/NetherFortressGenerator$PieceData;generatedCount:I", opcode = Opcodes.PUTFIELD))
private void redirectSetPieceDataGeneratedCount(NetherFortressGenerator.PieceData pieceData, int value) {
((INetherFortressGeneratorPieceData) pieceData).getGeneratedCountAtomic().set(value);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.OceanMonumentGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(OceanMonumentGenerator.Base.class)
public class MixinOceanMonumentGeneratorBase {

@MakeVolatile
@Shadow private OceanMonumentGenerator.PieceSetting entryPieceSetting;

@MakeVolatile
@Shadow private OceanMonumentGenerator.PieceSetting coreRoomPieceSetting;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.OceanMonumentGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(OceanMonumentGenerator.PieceSetting.class)
public class MixinOceanMonumentGeneratorPieceSetting {

@MakeVolatile
@Shadow private boolean used;

@MakeVolatile
@Shadow private boolean field_14484;

@MakeVolatile
@Shadow private int field_14483;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.ShiftableStructurePiece;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(ShiftableStructurePiece.class)
public class MixinShiftableStructurePiece {

@MakeVolatile
@Shadow protected int hPos;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.StrongholdGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(StrongholdGenerator.ChestCorridor.class)
public class MixinStrongholdGeneratorChestCorridor {

@MakeVolatile
@Shadow private boolean chestGenerated;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.StrongholdGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(StrongholdGenerator.PortalRoom.class)
public class MixinStrongholdGeneratorPortalRoom {

@MakeVolatile
@Shadow private boolean spawnerPlaced;

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.StrongholdGenerator;
import net.minecraft.structure.StructurePiece;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
Expand All @@ -19,6 +21,12 @@ public class MixinStrongholdGeneratorStart {
@Mutable
@Shadow @Final public List<StructurePiece> pieces;

@MakeVolatile
@Shadow public volatile StrongholdGenerator.PieceData lastPiece;

@MakeVolatile
@Shadow @Nullable public StrongholdGenerator.@Nullable PortalRoom portalRoom;

@Inject(method = "<init>*", at = @At("RETURN"))
private void onInit(CallbackInfo info) {
this.pieces = Collections.synchronizedList(pieces);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.ishland.c2me.fixes.worldgen.threading_issues.mixin.threading;

import com.ishland.c2me.fixes.worldgen.threading_issues.asm.MakeVolatile;
import net.minecraft.structure.SwampHutGenerator;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;

@Mixin(SwampHutGenerator.class)
public class MixinSwampHutGenerator {

@MakeVolatile
@Shadow private boolean hasWitch;

@MakeVolatile
@Shadow private boolean hasCat;

}
Loading

0 comments on commit 404e068

Please sign in to comment.