Skip to content

Commit

Permalink
Merge pull request #28 from Steveplays28/fix-threadlocal-random-off-t…
Browse files Browse the repository at this point in the history
…hread-access

Fix off-thread access of `ThreadLocalRandom`
  • Loading branch information
nyuppo authored Apr 18, 2024
2 parents 5ca0730 + 1090448 commit 8169653
Show file tree
Hide file tree
Showing 12 changed files with 32 additions and 29 deletions.
17 changes: 11 additions & 6 deletions src/main/java/com/github/nyuppo/config/Variants.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
import net.minecraft.registry.tag.BiomeTags;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.random.CheckedRandom;
import net.minecraft.util.math.random.Random;
import net.minecraft.util.math.random.RandomSplitter;
import net.minecraft.world.biome.Biome;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -150,12 +152,15 @@ public static EntityType<?> getMob(String mobId) {
throw new IllegalArgumentException("Unknown mob identifier: " + mobId);
}

public static MobVariant getRandomVariant(EntityType<?> mob, Random random, @Nullable RegistryEntry<Biome> spawnBiome, @Nullable BreedingResultData breedingResultData, @Nullable Float moonSize) {
public static MobVariant getRandomVariant(EntityType<?> mob, long randomSeed, @Nullable RegistryEntry<Biome> spawnBiome, @Nullable BreedingResultData breedingResultData, @Nullable Float moonSize) {
ArrayList<MobVariant> variants = getVariants(mob);
if (variants.isEmpty()) {
return getDefaultVariant(mob);
}

// Split the random to ensure no off-thread access of ThreadLocalRandom occurs
// This fixes issues with Distant Horizons and C2ME
var random = new CheckedRandom(randomSeed);
// Handle modifiers
Iterator<MobVariant> i = variants.iterator();
MobVariant variant;
Expand Down Expand Up @@ -199,7 +204,7 @@ public static MobVariant getRandomVariant(EntityType<?> mob, Random random, @Nul
}

// Create weighted bag from variants
VariantBag bag = new VariantBag(mob, random, variants);
VariantBag bag = new VariantBag(mob, variants);

// If we've been provided 2 parents
if (breedingResultData != null) {
Expand All @@ -217,11 +222,11 @@ public static MobVariant getRandomVariant(EntityType<?> mob, Random random, @Nul
return random.nextBoolean() ? breedingResultData.parent1() : breedingResultData.parent2();
}
} else { // If there are specialized results, switch to that pool
bag = new VariantBag(mob, random, possibleVariants);
bag = new VariantBag(mob, possibleVariants);
}
}

return bag.getRandomEntry();
return bag.getRandomEntry(random);
}

@Nullable
Expand Down Expand Up @@ -251,9 +256,9 @@ public static MobVariant getChildVariant(EntityType<?> mob, ServerWorld world, P
String[] parent2VariantId = parent2Nbt.getString("Variant").split(":");
MobVariant parent2Variant = Variants.getVariant(mob, new Identifier(parent2VariantId[0], parent2VariantId[1]));

return Variants.getRandomVariant(mob, world.getRandom(), world.getBiome(parent1.getBlockPos()), new BreedingResultData(parent1Variant, parent2Variant), null);
return Variants.getRandomVariant(mob, world.getRandom().nextLong(), world.getBiome(parent1.getBlockPos()), new BreedingResultData(parent1Variant, parent2Variant), null);
} else {
return Variants.getRandomVariant(mob, world.getRandom(), world.getBiome(parent1.getBlockPos()), null, null);
return Variants.getRandomVariant(mob, world.getRandom().nextLong(), world.getBiome(parent1.getBlockPos()), null, null);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/github/nyuppo/mixin/CatVariantsMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.CAT, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.CAT, ((CatEntity)(Object)this).getWorld().getRandom(), ((CatEntity)(Object)this).getWorld().getBiome(((CatEntity)(Object)this).getBlockPos()), null, ((CatEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.CAT, ((CatEntity)(Object)this).getWorld().getRandom().nextLong(), ((CatEntity)(Object)this).getWorld().getBiome(((CatEntity)(Object)this).getBlockPos()), null, ((CatEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -64,7 +64,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.CAT, world.getRandom(), world.getBiome(((CatEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.CAT, world.getRandom().nextLong(), world.getBiome(((CatEntity)(Object)this).getBlockPos()), null, world.getMoonSize());

if (world.toServerWorld().getStructureAccessor().getStructureContaining(((CatEntity)(Object)this).getBlockPos(), StructureTags.CATS_SPAWN_AS_BLACK).hasChildren()) {
MobVariant allBlack = Variants.getVariantNullable(EntityType.CAT, new Identifier("all_black"));
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/github/nyuppo/mixin/ChickenEggMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class ChickenEggMixin {
at = @At("STORE")
)
private ChickenEntity mixin(ChickenEntity chickenEntity) {
MobVariant variant = Variants.getRandomVariant(EntityType.CHICKEN, chickenEntity.getWorld().getRandom(), chickenEntity.getWorld().getBiome(chickenEntity.getBlockPos()), null, chickenEntity.getWorld().getMoonSize());
MobVariant variant = Variants.getRandomVariant(EntityType.CHICKEN, chickenEntity.getWorld().getRandom().nextLong(), chickenEntity.getWorld().getBiome(chickenEntity.getBlockPos()), null, chickenEntity.getWorld().getMoonSize());

NbtCompound newNbt = new NbtCompound();
chickenEntity.writeNbt(newNbt);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.CHICKEN, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.CHICKEN, ((ChickenEntity)(Object)this).getWorld().getRandom(), ((ChickenEntity)(Object)this).getWorld().getBiome(((ChickenEntity)(Object)this).getBlockPos()), null, ((ChickenEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.CHICKEN, ((ChickenEntity)(Object)this).getWorld().getRandom().nextLong(), ((ChickenEntity)(Object)this).getWorld().getBiome(((ChickenEntity)(Object)this).getBlockPos()), null, ((ChickenEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -64,7 +64,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.CHICKEN, world.getRandom(), world.getBiome(((ChickenEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.CHICKEN, world.getRandom().nextLong(), world.getBiome(((ChickenEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}

@Inject(
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/github/nyuppo/mixin/CowVariantsMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.COW, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.COW, ((CowEntity)(Object)this).getWorld().getRandom(), ((CowEntity)(Object)this).getWorld().getBiome(((CowEntity)(Object)this).getBlockPos()), null, ((CowEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.COW, ((CowEntity)(Object)this).getWorld().getRandom().nextLong(), ((CowEntity)(Object)this).getWorld().getBiome(((CowEntity)(Object)this).getBlockPos()), null, ((CowEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -62,7 +62,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.COW, world.getRandom(), world.getBiome(((CowEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.COW, world.getRandom().nextLong(), world.getBiome(((CowEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}

@Inject(
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/github/nyuppo/mixin/PigVariantsMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.PIG, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.PIG, ((PigEntity)(Object)this).getWorld().getRandom(), ((PigEntity)(Object)this).getWorld().getBiome(((PigEntity)(Object)this).getBlockPos()), null, ((PigEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.PIG, ((PigEntity)(Object)this).getWorld().getRandom().nextLong(), ((PigEntity)(Object)this).getWorld().getBiome(((PigEntity)(Object)this).getBlockPos()), null, ((PigEntity)(Object)this).getWorld().getMoonSize());
}
isMuddy = nbt.getBoolean(MoreMobVariants.MUDDY_NBT_KEY);
muddyTimeLeft = nbt.getInt(MoreMobVariants.MUDDY_TIMEOUT_NBT_KEY);
Expand All @@ -72,7 +72,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.PIG, world.getRandom(), world.getBiome(((PigEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.PIG, world.getRandom().nextLong(), world.getBiome(((PigEntity)(Object)this).getBlockPos()), null, world.getMoonSize());

// 2% chance of pig starting muddy if in swamp
if (world.getBiome(((PigEntity)(Object)this).getBlockPos()).isIn(BiomeTags.RUINED_PORTAL_SWAMP_HAS_STRUCTURE) && world.getRandom().nextDouble() < 0.02) {
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/github/nyuppo/mixin/SheepVariantsMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.SHEEP, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.SHEEP, ((SheepEntity)(Object)this).getWorld().getRandom(), ((SheepEntity)(Object)this).getWorld().getBiome(((SheepEntity)(Object)this).getBlockPos()), null, ((SheepEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.SHEEP, ((SheepEntity)(Object)this).getWorld().getRandom().nextLong(), ((SheepEntity)(Object)this).getWorld().getBiome(((SheepEntity)(Object)this).getBlockPos()), null, ((SheepEntity)(Object)this).getWorld().getMoonSize());
}
hornColour = nbt.getString(MoreMobVariants.SHEEP_HORN_COLOUR_NBT_KEY);

Expand All @@ -69,7 +69,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.SHEEP, world.getRandom(), world.getBiome(((SheepEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.SHEEP, world.getRandom().nextLong(), world.getBiome(((SheepEntity)(Object)this).getBlockPos()), null, world.getMoonSize());

SheepHornSettings.SheepHornColour colour = SheepHornSettings.getRandomSheepHornColour(world.getRandom(), world.getBiome(((SheepEntity)(Object)this).getBlockPos()));
if (colour != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.SKELETON, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.SKELETON, ((SkeletonEntity)(Object)this).getWorld().getRandom(), ((SkeletonEntity)(Object)this).getWorld().getBiome(((SkeletonEntity)(Object)this).getBlockPos()), null, ((SkeletonEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.SKELETON, ((SkeletonEntity)(Object)this).getWorld().getRandom().nextLong(), ((SkeletonEntity)(Object)this).getWorld().getBiome(((SkeletonEntity)(Object)this).getBlockPos()), null, ((SkeletonEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -60,6 +60,6 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.SKELETON, world.getRandom(), world.getBiome(((SkeletonEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.SKELETON, world.getRandom().nextLong(), world.getBiome(((SkeletonEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.SPIDER, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.SPIDER, ((SpiderEntity)(Object)this).getWorld().getRandom(), ((SpiderEntity)(Object)this).getWorld().getBiome(((SpiderEntity)(Object)this).getBlockPos()), null, ((SpiderEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.SPIDER, ((SpiderEntity)(Object)this).getWorld().getRandom().nextLong(), ((SpiderEntity)(Object)this).getWorld().getBiome(((SpiderEntity)(Object)this).getBlockPos()), null, ((SpiderEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -60,6 +60,6 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.SPIDER, world.getRandom(), world.getBiome(((SpiderEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.SPIDER, world.getRandom().nextLong(), world.getBiome(((SpiderEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}
}
4 changes: 2 additions & 2 deletions src/main/java/com/github/nyuppo/mixin/WolfVariantsMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.WOLF, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.WOLF, ((WolfEntity)(Object)this).getWorld().getRandom(), ((WolfEntity)(Object)this).getWorld().getBiome(((WolfEntity)(Object)this).getBlockPos()), null, ((WolfEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.WOLF, ((WolfEntity)(Object)this).getWorld().getRandom().nextLong(), ((WolfEntity)(Object)this).getWorld().getBiome(((WolfEntity)(Object)this).getBlockPos()), null, ((WolfEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -64,7 +64,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.WOLF, world.getRandom(), world.getBiome(((WolfEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.WOLF, world.getRandom().nextLong(), world.getBiome(((WolfEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}

@Inject(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {
variant = Variants.getVariant(EntityType.ZOMBIE, MoreMobVariants.id(nbt.getString(MoreMobVariants.NBT_KEY)));
}
} else {
variant = Variants.getRandomVariant(EntityType.ZOMBIE, ((ZombieEntity)(Object)this).getWorld().getRandom(), ((ZombieEntity)(Object)this).getWorld().getBiome(((ZombieEntity)(Object)this).getBlockPos()), null, ((ZombieEntity)(Object)this).getWorld().getMoonSize());
variant = Variants.getRandomVariant(EntityType.ZOMBIE, ((ZombieEntity)(Object)this).getWorld().getRandom().nextLong(), ((ZombieEntity)(Object)this).getWorld().getBiome(((ZombieEntity)(Object)this).getBlockPos()), null, ((ZombieEntity)(Object)this).getWorld().getMoonSize());
}

// Update all players in the event that this is from modifying entity data with a command
Expand All @@ -60,6 +60,6 @@ protected void onReadCustomDataFromNbt(NbtCompound nbt, CallbackInfo ci) {

@Override
protected void onInitialize(ServerWorldAccess world, LocalDifficulty difficulty, SpawnReason spawnReason, @Nullable EntityData entityData, @Nullable NbtCompound entityNbt, CallbackInfoReturnable<EntityData> ci) {
variant = Variants.getRandomVariant(EntityType.ZOMBIE, world.getRandom(), world.getBiome(((ZombieEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
variant = Variants.getRandomVariant(EntityType.ZOMBIE, world.getRandom().nextLong(), world.getBiome(((ZombieEntity)(Object)this).getBlockPos()), null, world.getMoonSize());
}
}
6 changes: 2 additions & 4 deletions src/main/java/com/github/nyuppo/util/VariantBag.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,10 @@ private class Entry {

private List<Entry> entries = new ArrayList<>();
private double accumulatedWeight;
private final Random random;
private final EntityType<?> mob;

public VariantBag(EntityType<?> mob, Random random, List<MobVariant> variants) {
public VariantBag(EntityType<?> mob, List<MobVariant> variants) {
this.mob = mob;
this.random = random;
for (MobVariant variant : variants) {
addEntry(variant);
}
Expand All @@ -35,7 +33,7 @@ public void addEntry(MobVariant variant) {
entries.add(e);
}

public MobVariant getRandomEntry() {
public MobVariant getRandomEntry(Random random) {
double r = random.nextDouble() * accumulatedWeight;

for (Entry entry : entries) {
Expand Down

0 comments on commit 8169653

Please sign in to comment.