diff --git a/patches/server/0056-Leaf-Secure-Seed.patch b/patches/server/0056-Leaf-Secure-Seed.patch new file mode 100644 index 0000000..412abbe --- /dev/null +++ b/patches/server/0056-Leaf-Secure-Seed.patch @@ -0,0 +1,850 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: adabugra <57899270+adabugra@users.noreply.github.com> +Date: Sun, 5 Jan 2025 12:32:26 +0300 +Subject: [PATCH] Leaf: Secure Seed + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/SecureSeedConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/SecureSeedConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fc4a7abc3b814edf6b19333b326d3d47f4ccaf78 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/SecureSeedConfig.java +@@ -0,0 +1,23 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class SecureSeedConfig implements IConfigModule { ++ ++ @ConfigInfo(baseName = "enabled", comments = ++ "Once you enable secure seed, all ores and structures are generated with 1024-bit seed\n" + ++ " instead of using 64-bit seed in vanilla, made seed cracker become impossible.") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "secure-seed"; ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +index c3ec370b83b895be0f03662e3884fa4a2442a2a6..d53679891422a4a9cd13382869469c4848db8ede 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java +@@ -166,7 +166,17 @@ public class DedicatedServerProperties extends Settings { + return GsonHelper.parse(!s1.isEmpty() ? s1 : "{}"); + }, new JsonObject()), (String) this.get("level-type", (s1) -> { +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index ca47a512452ae425160e30dc7c4a79f40aa97a26..0701c559bc81f265e8f07885af8b08ebf7025ccd 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -675,6 +675,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + + public ChunkGenerator getGenerator() { ++ su.plo.matter.Globals.setupGlobals(level); // Leaf - Matter - Feature Secure Seed + return this.chunkMap.generator(); + } + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index f8dfaa6170962f5b06a0a8ccbf3d8677381babcf..c910b06fdf90434502185d7784b02b1adeab4c8a 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -630,6 +630,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + chunkgenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkgenerator, gen); + } + // CraftBukkit end ++ su.plo.matter.Globals.setupGlobals(this); // Leaf - Matter - Feature Secure Seed + boolean flag2 = minecraftserver.forceSynchronousWrites(); + DataFixer datafixer = minecraftserver.getFixerUpper(); + EntityPersistentStorage entitypersistentstorage = new EntityStorage(new SimpleRegionStorage(new RegionStorageInfo(convertable_conversionsession.getLevelId(), resourcekey, "entities"), convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, DataFixTypes.ENTITY_CHUNK), this, minecraftserver); +diff --git a/src/main/java/net/minecraft/world/entity/monster/Slime.java b/src/main/java/net/minecraft/world/entity/monster/Slime.java +index 72346a7e5269c91e3143933ac37e65ad9639b791..2103769c0a3171e594181308510aedf7a1a3c768 100644 +--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java ++++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java +@@ -353,7 +353,12 @@ public class Slime extends Mob implements Enemy { + } + + ChunkPos chunkcoordintpair = new ChunkPos(pos); +- boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper ++ // Leaf start - Matter - Feature Secure Seed ++ boolean isSlimeChunk = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? world.getChunk(chunkcoordintpair.x, chunkcoordintpair.z).isSlimeChunk() ++ : WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper ++ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || isSlimeChunk; ++ // Leaf end - Matter - Feature Secure Seed + + // Paper start - Replace rules for Height in Slime Chunks + final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +index f87abb22dd161b2b74401086de80dc95c9ac2dbb..84e92f9f51d82c77f101484b51fd119386756da7 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java +@@ -85,6 +85,11 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + protected final LevelHeightAccessor levelHeightAccessor; + protected final LevelChunkSection[] sections; + ++ // Leaf start - Matter - Feature Secure Seed ++ private boolean slimeChunk; ++ private boolean hasComputedSlimeChunk; ++ // Leaf end - Matter - Feature Secure Seed ++ + // CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading. + private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); + public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY); +@@ -189,6 +194,17 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh + return GameEventListenerRegistry.NOOP; + } + ++ // Leaf start - Matter - Feature Secure Seed ++ public boolean isSlimeChunk() { ++ if (!hasComputedSlimeChunk) { ++ hasComputedSlimeChunk = true; ++ slimeChunk = su.plo.matter.WorldgenCryptoRandom.seedSlimeChunk(chunkPos.x, chunkPos.z).nextInt(10) == 0; ++ } ++ ++ return slimeChunk; ++ } ++ // Leaf end - Matter - Feature Secure Seed ++ + public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper + @Nullable + public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean moved); +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +index 7f6dd454e0794739dc1861f768aaed86c484afe7..bf5dce738e84e6b19743bf46b35e6116024d9f0e 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -345,7 +345,11 @@ public abstract class ChunkGenerator { + return structure.step().ordinal(); + })); + List list = (List) this.featuresPerStep.get(); +- WorldgenRandom seededrandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed())); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom seededrandom = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? new su.plo.matter.WorldgenCryptoRandom(blockposition.getX(), blockposition.getZ(), su.plo.matter.Globals.Salt.UNDEFINED, 0) ++ : new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed())); ++ // Leaf end - Matter - Feature Secure Seed + long i = seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), blockposition.getX(), blockposition.getZ()); + Set> set = new ObjectArraySet(); + +@@ -584,9 +588,18 @@ public abstract class ChunkGenerator { + ArrayList arraylist = new ArrayList(list.size()); + + arraylist.addAll(list); +- WorldgenRandom seededrandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- +- seededrandom.setLargeFeatureSeed(placementCalculator.getLevelSeed(), chunkcoordintpair.x, chunkcoordintpair.z); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom seededrandom; ++ if (me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { ++ seededrandom = new su.plo.matter.WorldgenCryptoRandom( ++ chunkcoordintpair.x, chunkcoordintpair.z, su.plo.matter.Globals.Salt.GENERATE_FEATURE, 0 ++ ); ++ } else { ++ seededrandom = new WorldgenRandom(new LegacyRandomSource(0L)); ++ ++ seededrandom.setLargeFeatureSeed(placementCalculator.getLevelSeed(), chunkcoordintpair.x, chunkcoordintpair.z); ++ } ++ // Leaf end - Matter - Feature Secure Seed + int i = 0; + + StructureSet.StructureSelectionEntry structureset_a1; +diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java +index a20520a6bd28bae1cee82258ac49d9753faba2bd..2dba92926251c0c123d4dc9beb473a7078cc40cb 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java ++++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java +@@ -224,8 +224,12 @@ public class ChunkGeneratorStructureState { + List> list = new ArrayList(j); + int k = placement.spread(); + HolderSet holderset = placement.preferredBiomes(); +- RandomSource randomsource = RandomSource.create(); ++ // Leaf start - Matter - Feature Secure Seed ++ RandomSource randomsource = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? new su.plo.matter.WorldgenCryptoRandom(0, 0, su.plo.matter.Globals.Salt.STRONGHOLDS, 0) ++ : RandomSource.create(); + ++ if (!me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { + // Paper start - Add missing structure set seed configs + if (this.conf.strongholdSeed != null && structureSetEntry.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) { + randomsource.setSeed(this.conf.strongholdSeed); +@@ -233,6 +237,7 @@ public class ChunkGeneratorStructureState { + // Paper end - Add missing structure set seed configs + randomsource.setSeed(this.concentricRingsSeed); + } // Paper - Add missing structure set seed configs ++ }// Leaf end - Matter - Feature Secure Seed + double d0 = randomsource.nextDouble() * Math.PI * 2.0D; + int l = 0; + int i1 = 0; +diff --git a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStep.java b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStep.java +index f9aad1b8c02b70e620efdc2a58cadf4fff0f3ed5..78d6553fc4cbe18bb94f477f890f02d8970af35d 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/status/ChunkStep.java ++++ b/src/main/java/net/minecraft/world/level/chunk/status/ChunkStep.java +@@ -60,6 +60,7 @@ public final class ChunkStep implements ca.spottedleaf.moonrise.patches.chunk_sy + } + + public CompletableFuture apply(WorldGenContext context, StaticCache2D staticCache2D, ChunkAccess chunk) { ++ su.plo.matter.Globals.setupGlobals(context.level()); // Leaf - Matter - Feature Secure Seed + if (chunk.getPersistedStatus().isBefore(this.targetStatus)) { + ProfiledDuration profiledDuration = JvmProfiler.INSTANCE.onChunkGenerate(chunk.getPos(), context.level().dimension(), this.targetStatus.getName()); + return this.task.doWork(context, this, staticCache2D, chunk).thenApply(generated -> this.completeChunkGeneration(generated, profiledDuration)); +diff --git a/src/main/java/net/minecraft/world/level/levelgen/WorldOptions.java b/src/main/java/net/minecraft/world/level/levelgen/WorldOptions.java +index 41c19e4e7bde4632879da564f52f3d373de27ec4..fd3ebfff98ab67082a4cfe482dc5ef66a95206c0 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/WorldOptions.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/WorldOptions.java +@@ -9,17 +9,35 @@ import net.minecraft.util.RandomSource; + import org.apache.commons.lang3.StringUtils; + + public class WorldOptions { ++ // Leaf start - Matter - Feature Secure Seed ++ private static final com.google.gson.Gson gson = new com.google.gson.Gson(); ++ private static final boolean isSecureSeedEnabled = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled; + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( +- instance -> instance.group( +- Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed), +- Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures), +- Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest), +- Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(generatorOptions -> generatorOptions.legacyCustomOptions) +- ) +- .apply(instance, instance.stable(WorldOptions::new)) ++ instance -> isSecureSeedEnabled ++ ? instance.group( ++ Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed), ++ Codec.STRING.fieldOf("feature_seed").orElse(gson.toJson(su.plo.matter.Globals.createRandomWorldSeed())).stable().forGetter(WorldOptions::featureSeedSerialize), ++ Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures), ++ Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest), ++ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(generatorOptions -> generatorOptions.legacyCustomOptions) ++ ) ++ .apply(instance, instance.stable(WorldOptions::new)) ++ : instance.group( ++ Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed), ++ Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures), ++ Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest), ++ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(generatorOptions -> generatorOptions.legacyCustomOptions) ++ ) ++ .apply(instance, instance.stable(WorldOptions::new)) + ); +- public static final WorldOptions DEMO_OPTIONS = new WorldOptions((long)"North Carolina".hashCode(), true, true); ++ // Leaf end - Matter - Feature Secure Seed ++ // Leaf start - Matter - Feature Secure Seed ++ public static final WorldOptions DEMO_OPTIONS = isSecureSeedEnabled ++ ? new WorldOptions((long) "North Carolina".hashCode(), su.plo.matter.Globals.createRandomWorldSeed(), true, true) ++ : new WorldOptions("North Carolina".hashCode(), true, true); ++ // Leaf end - Matter - Feature Secure Seed + private final long seed; ++ private long[] featureSeed = su.plo.matter.Globals.createRandomWorldSeed(); // Leaf - Matter - Feature Secure Seed + private final boolean generateStructures; + private final boolean generateBonusChest; + private final Optional legacyCustomOptions; +@@ -28,14 +46,35 @@ public class WorldOptions { + this(seed, generateStructures, bonusChest, Optional.empty()); + } + ++ // Leaf start - Matter - Feature Secure Seed ++ public WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest) { ++ this(seed, featureSeed, generateStructures, bonusChest, Optional.empty()); ++ } ++ ++ private WorldOptions(long seed, String featureSeedJson, boolean generateStructures, boolean bonusChest, Optional legacyCustomOptions) { ++ this(seed, gson.fromJson(featureSeedJson, long[].class), generateStructures, bonusChest, legacyCustomOptions); ++ } ++ // Leaf end - Matter - Feature Secure Seed ++ + public static WorldOptions defaultWithRandomSeed() { +- return new WorldOptions(randomSeed(), true, false); ++ // Leaf start - Matter - Feature Secure Seed ++ return isSecureSeedEnabled ++ ? new WorldOptions(randomSeed(), su.plo.matter.Globals.createRandomWorldSeed(), true, false) ++ : new WorldOptions(randomSeed(), true, false); ++ // Leaf end - Matter - Feature Secure Seed + } + + public static WorldOptions testWorldWithRandomSeed() { + return new WorldOptions(randomSeed(), false, false); + } + ++ // Leaf start - Matter - Feature Secure Seed ++ private WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest, Optional legacyCustomOptions) { ++ this(seed, generateStructures, bonusChest, legacyCustomOptions); ++ this.featureSeed = featureSeed; ++ } ++ // Leaf end - Matter - Feature Secure Seed ++ + private WorldOptions(long seed, boolean generateStructures, boolean bonusChest, Optional legacyCustomOptions) { + this.seed = seed; + this.generateStructures = generateStructures; +@@ -47,6 +86,16 @@ public class WorldOptions { + return this.seed; + } + ++ // Leaf start - Matter - Feature Secure Seed ++ public long[] featureSeed() { ++ return this.featureSeed; ++ } ++ ++ public String featureSeedSerialize() { ++ return gson.toJson(this.featureSeed); ++ } ++ // Leaf end - Matter - Feature Secure Seed ++ + public boolean generateStructures() { + return this.generateStructures; + } +@@ -59,17 +108,25 @@ public class WorldOptions { + return this.legacyCustomOptions.isPresent(); + } + ++ // Leaf start - Matter - Feature Secure Seed + public WorldOptions withBonusChest(boolean bonusChest) { +- return new WorldOptions(this.seed, this.generateStructures, bonusChest, this.legacyCustomOptions); ++ return isSecureSeedEnabled ++ ? new WorldOptions(this.seed, this.featureSeed, this.generateStructures, bonusChest, this.legacyCustomOptions) ++ : new WorldOptions(this.seed, this.generateStructures, bonusChest, this.legacyCustomOptions); + } + + public WorldOptions withStructures(boolean structures) { +- return new WorldOptions(this.seed, structures, this.generateBonusChest, this.legacyCustomOptions); ++ return isSecureSeedEnabled ++ ? new WorldOptions(this.seed, this.featureSeed, structures, this.generateBonusChest, this.legacyCustomOptions) ++ : new WorldOptions(this.seed, structures, this.generateBonusChest, this.legacyCustomOptions); + } + + public WorldOptions withSeed(OptionalLong seed) { +- return new WorldOptions(seed.orElse(randomSeed()), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions); ++ return isSecureSeedEnabled ++ ? new WorldOptions(seed.orElse(randomSeed()), su.plo.matter.Globals.createRandomWorldSeed(), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions) ++ : new WorldOptions(seed.orElse(randomSeed()), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions); + } ++ // Leaf end - Matter - Feature Secure Seed + + public static OptionalLong parseSeed(String seed) { + seed = seed.trim(); +diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/GeodeFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/GeodeFeature.java +index 270db8b29cdf65e9bb932637425214eefeca86b7..c699b671449434355fc23b4c703099ac192064f8 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/feature/GeodeFeature.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/feature/GeodeFeature.java +@@ -41,7 +41,11 @@ public class GeodeFeature extends Feature { + int j = geodeConfiguration.maxGenOffset; + List> list = Lists.newLinkedList(); + int k = geodeConfiguration.distributionPoints.sample(randomSource); +- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed())); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom worldgenRandom = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? new su.plo.matter.WorldgenCryptoRandom(0, 0, su.plo.matter.Globals.Salt.GEODE_FEATURE, 0) ++ : new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed())); ++ // Leaf end - Matter - Feature Secure Seed + NormalNoise normalNoise = NormalNoise.create(worldgenRandom, -4, 1.0); + List list2 = Lists.newLinkedList(); + double d = (double)k / (double)geodeConfiguration.outerWallDistance.getMaxValue(); +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java +index 13f7fce1959c0f44e047616674198176e667067f..11ad7f9e8a050f69b6936d0a31136ece7450b49e 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/Structure.java +@@ -248,6 +248,13 @@ public abstract class Structure { + } + + private static WorldgenRandom makeRandom(long seed, ChunkPos chunkPos) { ++ // Leaf start - Matter - Feature Secure Seed ++ if (me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { ++ return new su.plo.matter.WorldgenCryptoRandom( ++ chunkPos.x, chunkPos.z, su.plo.matter.Globals.Salt.GENERATE_FEATURE, seed ++ ); ++ } ++ // Leaf end - Matter - Feature Secure Seed + WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); + worldgenRandom.setLargeFeatureSeed(seed, chunkPos.x, chunkPos.z); + return worldgenRandom; +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java +index f873a0a0734b4fe74ba5b5f8ae0cc3c78fa76b9f..a9724579c41a591462c2b85659433cd41fff217e 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java +@@ -71,8 +71,17 @@ public class RandomSpreadStructurePlacement extends StructurePlacement { + public ChunkPos getPotentialStructureChunk(long seed, int chunkX, int chunkZ) { + int i = Math.floorDiv(chunkX, this.spacing); + int j = Math.floorDiv(chunkZ, this.spacing); +- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- worldgenRandom.setLargeFeatureWithSalt(seed, i, j, this.salt()); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom worldgenRandom; ++ if (me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { ++ worldgenRandom = new su.plo.matter.WorldgenCryptoRandom( ++ i, j, su.plo.matter.Globals.Salt.POTENTIONAL_FEATURE, this.salt ++ ); ++ } else { ++ worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); ++ worldgenRandom.setLargeFeatureWithSalt(seed, i, j, this.salt()); ++ } ++ // Leaf end - Matter - Feature Secure Seed + int k = this.spacing - this.separation; + int l = this.spreadType.evaluate(worldgenRandom, k); + int m = this.spreadType.evaluate(worldgenRandom, k); +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java +index cbf13e4f2da6a27619e9bc9a7cd73bb6e69cad2a..47171ec6f2c00c79e66af974ec32bbf1f88c1ebb 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java +@@ -118,8 +118,17 @@ public abstract class StructurePlacement { + public abstract StructurePlacementType type(); + + private static boolean probabilityReducer(long seed, int salt, int chunkX, int chunkZ, float frequency, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here +- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); +- worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom worldgenRandom; ++ if (me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { ++ worldgenRandom = new su.plo.matter.WorldgenCryptoRandom( ++ chunkX, chunkZ, su.plo.matter.Globals.Salt.UNDEFINED, salt ++ ); ++ } else { ++ worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L)); ++ worldgenRandom.setLargeFeatureWithSalt(seed, salt, chunkX, chunkZ); ++ } ++ // Leaf end - Matter - Feature Secure Seed + return worldgenRandom.nextFloat() < frequency; + } + +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/src/main/java/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java +index 65a0d9e7dd742732974774daabce02e9e52039ac..e4aa8f17f3a1fc0bdea43386f2dfdb7464a9b288 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java +@@ -64,7 +64,11 @@ public class JigsawPlacement { + ChunkGenerator chunkGenerator = context.chunkGenerator(); + StructureTemplateManager structureTemplateManager = context.structureTemplateManager(); + LevelHeightAccessor levelHeightAccessor = context.heightAccessor(); +- WorldgenRandom worldgenRandom = context.random(); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldgenRandom worldgenRandom = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? new su.plo.matter.WorldgenCryptoRandom(context.chunkPos().x, context.chunkPos().z, su.plo.matter.Globals.Salt.JIGSAW_PLACEMENT, 0) ++ : context.random(); ++ // Leaf end - Matter - Feature Secure Seed + Registry registry = registryAccess.lookupOrThrow(Registries.TEMPLATE_POOL); + Rotation rotation = Rotation.getRandom(worldgenRandom); + StructureTemplatePool structureTemplatePool = structurePool.unwrapKey() +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/structures/EndCityStructure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/structures/EndCityStructure.java +index 712c6431d63e0b1a1edd9d7de9b13c46a1acb469..35dc49d90aa6d660a60fb76efddb530f9ec59666 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/structures/EndCityStructure.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/structures/EndCityStructure.java +@@ -10,6 +10,7 @@ import net.minecraft.world.level.levelgen.structure.Structure; + import net.minecraft.world.level.levelgen.structure.StructurePiece; + import net.minecraft.world.level.levelgen.structure.StructureType; + import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder; ++//import su.plo.matter.WorldgenCryptoRandom; // Leaf - Matter - Feature Secure Seed + + public class EndCityStructure extends Structure { + public static final MapCodec CODEC = simpleCodec(EndCityStructure::new); +diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/structures/MineshaftStructure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/structures/MineshaftStructure.java +index 7f4c5e9355a6f562f668e9b8134bfe65dde35f90..7a1c21696f6531c7dded774f45073df16732f252 100644 +--- a/src/main/java/net/minecraft/world/level/levelgen/structure/structures/MineshaftStructure.java ++++ b/src/main/java/net/minecraft/world/level/levelgen/structure/structures/MineshaftStructure.java +@@ -20,6 +20,7 @@ import net.minecraft.world.level.levelgen.WorldgenRandom; + import net.minecraft.world.level.levelgen.structure.Structure; + import net.minecraft.world.level.levelgen.structure.StructureType; + import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder; ++//import su.plo.matter.WorldgenCryptoRandom; // Leaf - Matter - Feature Secure Seed + + public class MineshaftStructure extends Structure { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +index 4791e013e8257f57b5db6f974dc05829b911cfa0..f9eb72f761d50c585145c3a43e2c88ae058cc265 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +@@ -206,7 +206,12 @@ public class CraftChunk implements Chunk { + @Override + public boolean isSlimeChunk() { + // 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk +- return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper ++ // Leaf start - Matter - Feature Secure Seed ++ boolean isSlimeChunk = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? worldServer.getChunk(this.getX(), this.getZ()).isSlimeChunk() ++ : WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper ++ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || isSlimeChunk; ++ // Leaf end - Matter - Feature Secure Seed + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index 4fe9d348b6f14224d4095dcd8ff0a16a1d61589c..e8a9351f40fdcd8ea47632677be52308f9f72b5d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -1426,7 +1426,11 @@ public final class CraftServer implements Server { + iregistrycustom_dimension = leveldataanddimensions.dimensions().dimensionsRegistryAccess(); + } else { + LevelSettings worldsettings; +- WorldOptions worldoptions = new WorldOptions(creator.seed(), creator.generateStructures(), false); ++ // Leaf start - Matter - Feature Secure Seed ++ WorldOptions worldoptions = me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled ++ ? new WorldOptions(creator.seed(), su.plo.matter.Globals.createRandomWorldSeed(), creator.generateStructures(), false) ++ : new WorldOptions(creator.seed(), creator.generateStructures(), false); ++ // Leaf end - Matter - Feature Secure Seed + WorldDimensions worlddimensions; + + DedicatedServerProperties.WorldDimensionData properties = new DedicatedServerProperties.WorldDimensionData(GsonHelper.parse((creator.generatorSettings().isEmpty()) ? "{}" : creator.generatorSettings()), creator.type().name().toLowerCase(Locale.ROOT)); +diff --git a/src/main/java/su/plo/matter/Globals.java b/src/main/java/su/plo/matter/Globals.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e1db02231b6c10c2da98e24147b5377fb0b8179c +--- /dev/null ++++ b/src/main/java/su/plo/matter/Globals.java +@@ -0,0 +1,94 @@ ++package su.plo.matter; ++ ++import com.google.common.collect.Iterables; ++import net.minecraft.server.level.ServerLevel; ++ ++import java.math.BigInteger; ++import java.security.SecureRandom; ++import java.util.Optional; ++ ++public class Globals { ++ public static final int WORLD_SEED_LONGS = 16; ++ public static final int WORLD_SEED_BITS = WORLD_SEED_LONGS * 64; ++ ++ public static final long[] worldSeed = new long[WORLD_SEED_LONGS]; ++ public static final ThreadLocal dimension = ThreadLocal.withInitial(() -> 0); ++ ++ public static void setupGlobals(ServerLevel world) { ++ if (!me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) return; ++ ++ long[] seed = world.getServer().getWorldData().worldGenOptions().featureSeed(); ++ System.arraycopy(seed, 0, worldSeed, 0, WORLD_SEED_LONGS); ++ int worldIndex = Iterables.indexOf(world.getServer().levelKeys(), it -> it == world.dimension()); ++ if (worldIndex == -1) ++ worldIndex = world.getServer().levelKeys().size(); // if we are in world construction it may not have been added to the map yet ++ dimension.set(worldIndex); ++ } ++ ++ public static long[] createRandomWorldSeed() { ++ long[] seed = new long[WORLD_SEED_LONGS]; ++ SecureRandom rand = new SecureRandom(); ++ for (int i = 0; i < WORLD_SEED_LONGS; i++) { ++ seed[i] = rand.nextLong(); ++ } ++ return seed; ++ } ++ ++ // 1024-bit string -> 16 * 64 long[] ++ public static Optional parseSeed(String seedStr) { ++ if (seedStr.isEmpty()) return Optional.empty(); ++ ++ if (seedStr.length() != WORLD_SEED_BITS) { ++ throw new IllegalArgumentException("Secure seed length must be " + WORLD_SEED_BITS + "-bit but found " + seedStr.length() + "-bit."); ++ } ++ ++ long[] seed = new long[WORLD_SEED_LONGS]; ++ ++ for (int i = 0; i < WORLD_SEED_LONGS; i++) { ++ int start = i * 64; ++ int end = start + 64; ++ String seedSection = seedStr.substring(start, end); ++ ++ BigInteger seedInDecimal = new BigInteger(seedSection, 2); ++ seed[i] = seedInDecimal.longValue(); ++ } ++ ++ return Optional.of(seed); ++ } ++ ++ // 16 * 64 long[] -> 1024-bit string ++ public static String seedToString(long[] seed) { ++ StringBuilder sb = new StringBuilder(); ++ ++ for (long longV : seed) { ++ // Convert to 64-bit binary string per long ++ // Use format to keep 64-bit length, and use 0 to complete space ++ String binaryStr = String.format("%64s", Long.toBinaryString(longV)).replace(' ', '0'); ++ ++ sb.append(binaryStr); ++ } ++ ++ return sb.toString(); ++ } ++ ++ public enum Salt { ++ UNDEFINED, ++ BASTION_FEATURE, ++ WOODLAND_MANSION_FEATURE, ++ MINESHAFT_FEATURE, ++ BURIED_TREASURE_FEATURE, ++ NETHER_FORTRESS_FEATURE, ++ PILLAGER_OUTPOST_FEATURE, ++ GEODE_FEATURE, ++ NETHER_FOSSIL_FEATURE, ++ OCEAN_MONUMENT_FEATURE, ++ RUINED_PORTAL_FEATURE, ++ POTENTIONAL_FEATURE, ++ GENERATE_FEATURE, ++ JIGSAW_PLACEMENT, ++ STRONGHOLDS, ++ POPULATION, ++ DECORATION, ++ SLIME_CHUNK ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/su/plo/matter/Hashing.java b/src/main/java/su/plo/matter/Hashing.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6f0fca108ac61566bda3c1ac16911ced86af47a1 +--- /dev/null ++++ b/src/main/java/su/plo/matter/Hashing.java +@@ -0,0 +1,73 @@ ++package su.plo.matter; ++ ++public class Hashing { ++ // https://en.wikipedia.org/wiki/BLAKE_(hash_function) ++ // https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java ++ ++ private final static long[] blake2b_IV = { ++ 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, ++ 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, ++ 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L ++ }; ++ ++ private final static byte[][] blake2b_sigma = { ++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, ++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, ++ {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, ++ {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, ++ {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, ++ {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, ++ {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, ++ {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, ++ {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, ++ {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, ++ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, ++ {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} ++ }; ++ ++ public static long[] hashWorldSeed(long[] worldSeed) { ++ long[] result = blake2b_IV.clone(); ++ result[0] ^= 0x01010040; ++ hash(worldSeed, result, new long[16], 0, false); ++ return result; ++ } ++ ++ public static void hash(long[] message, long[] chainValue, long[] internalState, long messageOffset, boolean isFinal) { ++ assert message.length == 16; ++ assert chainValue.length == 8; ++ assert internalState.length == 16; ++ ++ System.arraycopy(chainValue, 0, internalState, 0, chainValue.length); ++ System.arraycopy(blake2b_IV, 0, internalState, chainValue.length, 4); ++ internalState[12] = messageOffset ^ blake2b_IV[4]; ++ internalState[13] = blake2b_IV[5]; ++ if (isFinal) internalState[14] = ~blake2b_IV[6]; ++ internalState[15] = blake2b_IV[7]; ++ ++ for (int round = 0; round < 12; round++) { ++ G(message[blake2b_sigma[round][0]], message[blake2b_sigma[round][1]], 0, 4, 8, 12, internalState); ++ G(message[blake2b_sigma[round][2]], message[blake2b_sigma[round][3]], 1, 5, 9, 13, internalState); ++ G(message[blake2b_sigma[round][4]], message[blake2b_sigma[round][5]], 2, 6, 10, 14, internalState); ++ G(message[blake2b_sigma[round][6]], message[blake2b_sigma[round][7]], 3, 7, 11, 15, internalState); ++ G(message[blake2b_sigma[round][8]], message[blake2b_sigma[round][9]], 0, 5, 10, 15, internalState); ++ G(message[blake2b_sigma[round][10]], message[blake2b_sigma[round][11]], 1, 6, 11, 12, internalState); ++ G(message[blake2b_sigma[round][12]], message[blake2b_sigma[round][13]], 2, 7, 8, 13, internalState); ++ G(message[blake2b_sigma[round][14]], message[blake2b_sigma[round][15]], 3, 4, 9, 14, internalState); ++ } ++ ++ for (int i = 0; i < 8; i++) { ++ chainValue[i] ^= internalState[i] ^ internalState[i + 8]; ++ } ++ } ++ ++ private static void G(long m1, long m2, int posA, int posB, int posC, int posD, long[] internalState) { ++ internalState[posA] = internalState[posA] + internalState[posB] + m1; ++ internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 32); ++ internalState[posC] = internalState[posC] + internalState[posD]; ++ internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE ++ internalState[posA] = internalState[posA] + internalState[posB] + m2; ++ internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 16); ++ internalState[posC] = internalState[posC] + internalState[posD]; ++ internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE ++ } ++} +\ No newline at end of file +diff --git a/src/main/java/su/plo/matter/WorldgenCryptoRandom.java b/src/main/java/su/plo/matter/WorldgenCryptoRandom.java +new file mode 100644 +index 0000000000000000000000000000000000000000..aa19e4bac4f4f128330faccbe5389b02afdf4887 +--- /dev/null ++++ b/src/main/java/su/plo/matter/WorldgenCryptoRandom.java +@@ -0,0 +1,160 @@ ++package su.plo.matter; ++ ++import net.minecraft.util.Mth; ++import net.minecraft.util.RandomSource; ++import net.minecraft.world.level.levelgen.LegacyRandomSource; ++import net.minecraft.world.level.levelgen.WorldgenRandom; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Arrays; ++ ++ ++public class WorldgenCryptoRandom extends WorldgenRandom { ++ // hash the world seed to guard against badly chosen world seeds ++ private static final long[] HASHED_ZERO_SEED = Hashing.hashWorldSeed(new long[Globals.WORLD_SEED_LONGS]); ++ private static final ThreadLocal LAST_SEEN_WORLD_SEED = ThreadLocal.withInitial(() -> new long[Globals.WORLD_SEED_LONGS]); ++ private static final ThreadLocal HASHED_WORLD_SEED = ThreadLocal.withInitial(() -> HASHED_ZERO_SEED); ++ ++ private static final int MAX_RANDOM_BIT_INDEX = 64 * 8; ++ private static final int LOG2_MAX_RANDOM_BIT_INDEX = 9; ++ private final long[] worldSeed = new long[Globals.WORLD_SEED_LONGS]; ++ private final long[] randomBits = new long[8]; ++ private final long[] message = new long[16]; ++ private final long[] cachedInternalState = new long[16]; ++ private int randomBitIndex; ++ private long counter; ++ ++ public WorldgenCryptoRandom(int x, int z, Globals.Salt typeSalt, long salt) { ++ super(new LegacyRandomSource(0L)); ++ if (typeSalt != null) { ++ this.setSecureSeed(x, z, typeSalt, salt); ++ } ++ } ++ ++ public static RandomSource seedSlimeChunk(int chunkX, int chunkZ) { ++ return new WorldgenCryptoRandom(chunkX, chunkZ, Globals.Salt.SLIME_CHUNK, 0); ++ } ++ ++ public void setSecureSeed(int x, int z, Globals.Salt typeSalt, long salt) { ++ System.arraycopy(Globals.worldSeed, 0, this.worldSeed, 0, Globals.WORLD_SEED_LONGS); ++ message[0] = ((long) x << 32) | ((long) z & 0xffffffffL); ++ message[1] = ((long) Globals.dimension.get() << 32) | ((long) salt & 0xffffffffL); ++ message[2] = typeSalt.ordinal(); ++ message[3] = counter = 0; ++ randomBitIndex = MAX_RANDOM_BIT_INDEX; ++ } ++ ++ private long[] getHashedWorldSeed() { ++ if (!Arrays.equals(worldSeed, LAST_SEEN_WORLD_SEED.get())) { ++ HASHED_WORLD_SEED.set(Hashing.hashWorldSeed(worldSeed)); ++ System.arraycopy(worldSeed, 0, LAST_SEEN_WORLD_SEED.get(), 0, Globals.WORLD_SEED_LONGS); ++ } ++ return HASHED_WORLD_SEED.get(); ++ } ++ ++ private void moreRandomBits() { ++ message[3] = counter++; ++ System.arraycopy(getHashedWorldSeed(), 0, randomBits, 0, 8); ++ Hashing.hash(message, randomBits, cachedInternalState, 64, true); ++ } ++ ++ private long getBits(int count) { ++ if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) { ++ moreRandomBits(); ++ randomBitIndex -= MAX_RANDOM_BIT_INDEX; ++ } ++ ++ int alignment = randomBitIndex & 63; ++ if ((randomBitIndex >>> 6) == ((randomBitIndex + count) >>> 6)) { ++ long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << count) - 1); ++ randomBitIndex += count; ++ return result; ++ } else { ++ long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << (64 - alignment)) - 1); ++ randomBitIndex += count; ++ if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) { ++ moreRandomBits(); ++ randomBitIndex -= MAX_RANDOM_BIT_INDEX; ++ } ++ alignment = randomBitIndex & 63; ++ result <<= alignment; ++ result |= (randomBits[randomBitIndex >>> 6] >>> (64 - alignment)) & ((1L << alignment) - 1); ++ ++ return result; ++ } ++ } ++ ++ @Override ++ public @NotNull RandomSource fork() { ++ WorldgenCryptoRandom fork = new WorldgenCryptoRandom(0, 0, null, 0); ++ ++ System.arraycopy(Globals.worldSeed, 0, fork.worldSeed, 0, Globals.WORLD_SEED_LONGS); ++ fork.message[0] = this.message[0]; ++ fork.message[1] = this.message[1]; ++ fork.message[2] = this.message[2]; ++ fork.message[3] = this.message[3]; ++ fork.randomBitIndex = this.randomBitIndex; ++ fork.counter = this.counter; ++ fork.nextLong(); ++ ++ return fork; ++ } ++ ++ @Override ++ public int next(int bits) { ++ return (int) getBits(bits); ++ } ++ ++ @Override ++ public void consumeCount(int count) { ++ randomBitIndex += count; ++ if (randomBitIndex >= MAX_RANDOM_BIT_INDEX * 2) { ++ randomBitIndex -= MAX_RANDOM_BIT_INDEX; ++ counter += randomBitIndex >>> LOG2_MAX_RANDOM_BIT_INDEX; ++ randomBitIndex &= MAX_RANDOM_BIT_INDEX - 1; ++ randomBitIndex += MAX_RANDOM_BIT_INDEX; ++ } ++ } ++ ++ @Override ++ public int nextInt(int bound) { ++ int bits = Mth.ceillog2(bound); ++ int result; ++ do { ++ result = (int) getBits(bits); ++ } while (result >= bound); ++ ++ return result; ++ } ++ ++ @Override ++ public long nextLong() { ++ return getBits(64); ++ } ++ ++ @Override ++ public double nextDouble() { ++ return getBits(53) * 0x1.0p-53; ++ } ++ ++ @Override ++ public long setDecorationSeed(long worldSeed, int blockX, int blockZ) { ++ setSecureSeed(blockX, blockZ, Globals.Salt.POPULATION, 0); ++ return ((long) blockX << 32) | ((long) blockZ & 0xffffffffL); ++ } ++ ++ @Override ++ public void setFeatureSeed(long populationSeed, int index, int step) { ++ setSecureSeed((int) (populationSeed >> 32), (int) populationSeed, Globals.Salt.DECORATION, index + 10000L * step); ++ } ++ ++ @Override ++ public void setLargeFeatureSeed(long worldSeed, int chunkX, int chunkZ) { ++ super.setLargeFeatureSeed(worldSeed, chunkX, chunkZ); ++ } ++ ++ @Override ++ public void setLargeFeatureWithSalt(long worldSeed, int regionX, int regionZ, int salt) { ++ super.setLargeFeatureWithSalt(worldSeed, regionX, regionZ, salt); ++ } ++} +\ No newline at end of file diff --git a/patches/server/0057-Leaf-SecureSeed-Command.patch b/patches/server/0057-Leaf-SecureSeed-Command.patch new file mode 100644 index 0000000..5299b02 --- /dev/null +++ b/patches/server/0057-Leaf-SecureSeed-Command.patch @@ -0,0 +1,28 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: adabugra <57899270+adabugra@users.noreply.github.com> +Date: Sun, 5 Jan 2025 12:40:06 +0300 +Subject: [PATCH] Leaf: SecureSeed Command + + +diff --git a/src/main/java/net/minecraft/server/commands/SeedCommand.java b/src/main/java/net/minecraft/server/commands/SeedCommand.java +index 0b500b19a99fa6c2740c0db350a166462668df9c..1b82a5cc73cf7916146d6687a225256615551507 100644 +--- a/src/main/java/net/minecraft/server/commands/SeedCommand.java ++++ b/src/main/java/net/minecraft/server/commands/SeedCommand.java +@@ -12,6 +12,17 @@ public class SeedCommand { + long l = context.getSource().getLevel().getSeed(); + Component component = ComponentUtils.copyOnClickText(String.valueOf(l)); + context.getSource().sendSuccess(() -> Component.translatable("commands.seed.success", component), false); ++ ++ // Leaf start - Matter - SecureSeed Command ++ if (me.earthme.luminol.config.modules.misc.SecureSeedConfig.enabled) { ++ su.plo.matter.Globals.setupGlobals(context.getSource().getLevel()); ++ String seedStr = su.plo.matter.Globals.seedToString(su.plo.matter.Globals.worldSeed); ++ Component featureSeedComponent = ComponentUtils.copyOnClickText(seedStr); ++ ++ context.getSource().sendSuccess(() -> Component.translatable(("Feature seed: %s"), featureSeedComponent), false); ++ } ++ // Leaf end - Matter - SecureSeed Command ++ + return (int)l; + })); + }