caution: version not fully compatible with 1.18, structure locations are same but generation is different (it won't be fixed, so upgrade on your own risk)
975 lines
55 KiB
Diff
975 lines
55 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Apehum <apehumchik@gmail.com>
|
|
Date: Thu, 9 Dec 2021 02:18:17 +0800
|
|
Subject: [PATCH] Feature Secure Seed
|
|
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
index 26345494ce190b5cd2ab58dd7d4b046796767b20..5212a4fc7ce68e4345882b9f25b7e410883a951d 100644
|
|
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
|
@@ -148,7 +148,8 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
this.playerIdleTimeout = this.getMutable("player-idle-timeout", 0);
|
|
this.whiteList = this.getMutable("white-list", false);
|
|
this.enforceSecureProfile = this.get("enforce-secure-profile", false);
|
|
- this.worldGenProperties = new DedicatedServerProperties.WorldGenProperties(this.get("level-seed", ""), (JsonObject) this.get("generator-settings", (s) -> {
|
|
+ // Matter - Feature Secure Seed
|
|
+ this.worldGenProperties = new DedicatedServerProperties.WorldGenProperties(this.get("level-seed", ""), this.get("feature-level-seed", ""), (JsonObject) this.get("generator-settings", (s) -> {
|
|
return GsonHelper.parse(!s.isEmpty() ? s : "{}");
|
|
}, new JsonObject()), this.get("generate-structures", true), (String) this.get("level-type", (s) -> {
|
|
return s.toLowerCase(Locale.ROOT);
|
|
@@ -225,10 +226,14 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
|
return this.worldGenSettings;
|
|
}
|
|
|
|
- public static record WorldGenProperties(String levelSeed, JsonObject generatorSettings, boolean generateStructures, String levelType) {
|
|
-
|
|
+ public static record WorldGenProperties(String levelSeed, String featureSeed, JsonObject generatorSettings, boolean generateStructures, String levelType) {
|
|
private static final Map<String, ResourceKey<WorldPreset>> LEGACY_PRESET_NAMES = Map.of("default", WorldPresets.NORMAL, "largebiomes", WorldPresets.LARGE_BIOMES);
|
|
|
|
+ // Matter todo: check why?
|
|
+ public String featureSeed() {
|
|
+ return this.featureSeed;
|
|
+ }
|
|
+
|
|
public WorldGenSettings create(RegistryAccess dynamicRegistryManager) {
|
|
long i = WorldGenSettings.parseSeed(this.levelSeed()).orElse(RandomSource.create().nextLong());
|
|
Registry<WorldPreset> iregistry = dynamicRegistryManager.registryOrThrow(Registry.WORLD_PRESET_REGISTRY);
|
|
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
index 378cc1f9e19eb9b18037ab8af92f65897e15a405..33cb2fc823624b40a32c6f5513abb073214a8ffd 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -48,6 +48,7 @@ import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
import net.minecraft.world.level.storage.LevelData;
|
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
|
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet; // Paper
|
|
+import su.plo.matter.Globals;
|
|
|
|
public class ServerChunkCache extends ChunkSource {
|
|
|
|
@@ -1140,6 +1141,8 @@ public class ServerChunkCache extends ChunkSource {
|
|
}
|
|
|
|
public ChunkGenerator getGenerator() {
|
|
+ // Matter
|
|
+ Globals.setupGlobals(level);
|
|
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 8043a1aa9d785c78e220ea54a6ffa7388f2d501e..253698b4006ec45fa09198b8e39fddf33af3882b 100644
|
|
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
@@ -170,6 +170,10 @@ import org.bukkit.event.world.TimeSkipEvent;
|
|
// CraftBukkit end
|
|
import it.unimi.dsi.fastutil.ints.IntArrayList; // Paper
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+// Matter end
|
|
+
|
|
public class ServerLevel extends Level implements WorldGenLevel {
|
|
|
|
public static final BlockPos END_SPAWN_POINT = new BlockPos(100, 50, 0);
|
|
@@ -524,6 +528,7 @@ public class ServerLevel extends Level implements WorldGenLevel {
|
|
}
|
|
chunkgenerator.conf = spigotConfig; // Spigot
|
|
// CraftBukkit end
|
|
+ Globals.setupGlobals(this); // Matter
|
|
boolean flag2 = minecraftserver.forceSynchronousWrites();
|
|
DataFixer datafixer = minecraftserver.getFixerUpper();
|
|
EntityPersistentStorage<Entity> entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, 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 7e85ad7ba31bbb32ea1e1dff5d1c83e7ce68b4b3..94a1868843407d421e6aa3b7719cff6727eb113c 100644
|
|
--- a/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
|
+++ b/src/main/java/net/minecraft/world/entity/monster/Slime.java
|
|
@@ -338,7 +338,7 @@ 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
|
|
+ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || world.getChunk(chunkcoordintpair.x, chunkcoordintpair.z).isSlimeChunk(); // Spigot // Paper // Matter
|
|
|
|
// 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 8d7d10f620b30c35d2ef580ea914f2c62054a785..c06ee8618b58806e7114f0c253dcc48e4386bf14 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkAccess.java
|
|
@@ -50,6 +50,7 @@ import net.minecraft.world.level.material.Fluid;
|
|
import net.minecraft.world.ticks.SerializableTickContainer;
|
|
import net.minecraft.world.ticks.TickContainerAccess;
|
|
import org.slf4j.Logger;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
|
|
public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiomeSource, StructureAccess {
|
|
|
|
@@ -77,6 +78,11 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
|
|
protected final LevelHeightAccessor levelHeightAccessor;
|
|
protected final LevelChunkSection[] sections;
|
|
|
|
+ // Matter start
|
|
+ private boolean slimeChunk;
|
|
+ private boolean hasComputedSlimeChunk;
|
|
+ // Matter end
|
|
+
|
|
// 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);
|
|
@@ -147,6 +153,17 @@ public abstract class ChunkAccess implements BlockGetter, BiomeManager.NoiseBiom
|
|
public final Registry<Biome> biomeRegistry;
|
|
// CraftBukkit end
|
|
|
|
+ // Matter start
|
|
+ public boolean isSlimeChunk() {
|
|
+ if (!hasComputedSlimeChunk) {
|
|
+ hasComputedSlimeChunk = true;
|
|
+ slimeChunk = WorldgenCryptoRandom.seedSlimeChunk(chunkPos.x, chunkPos.z).nextInt(10) == 0;
|
|
+ }
|
|
+
|
|
+ return slimeChunk;
|
|
+ }
|
|
+ // Matter end
|
|
+
|
|
private static void replaceMissingSections(LevelHeightAccessor world, Registry<Biome> biome, LevelChunkSection[] sectionArray) {
|
|
for (int i = 0; i < sectionArray.length; ++i) {
|
|
if (sectionArray[i] == null) {
|
|
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 cdfe2589ca598263d58a11a978e176ab3ecb87e6..805510b9eeec2c48bfe2aae680483b1286daca24 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java
|
|
@@ -86,6 +86,11 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemp
|
|
import org.apache.commons.lang3.mutable.MutableBoolean;
|
|
import org.slf4j.Logger;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
+// Matter end
|
|
+
|
|
public abstract class ChunkGenerator {
|
|
|
|
private static final Logger LOGGER = LogUtils.getLogger();
|
|
@@ -234,15 +239,9 @@ public abstract class ChunkGenerator {
|
|
int j = concentricringsstructureplacement.count();
|
|
int k = concentricringsstructureplacement.spread();
|
|
HolderSet<Biome> holderset = concentricringsstructureplacement.preferredBiomes();
|
|
- RandomSource randomsource = RandomSource.create();
|
|
+ // Matter
|
|
+ RandomSource randomsource = new WorldgenCryptoRandom(0, 0, Globals.Salt.STRONGHOLDS, 0);
|
|
|
|
- // Paper start
|
|
- if (this.conf.strongholdSeed != null && this.structureSets.getResourceKey(holder).orElse(null) == net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS) {
|
|
- randomsource.setSeed(this.conf.strongholdSeed);
|
|
- } else {
|
|
- randomsource.setSeed(this instanceof FlatLevelSource ? 0L : randomstate.legacyLevelSeed());
|
|
- }
|
|
- // Paper end
|
|
double d0 = randomsource.nextDouble() * 3.141592653589793D * 2.0D;
|
|
int l = 0;
|
|
int i1 = 0;
|
|
@@ -514,8 +513,12 @@ public abstract class ChunkGenerator {
|
|
return structure.step().ordinal();
|
|
}));
|
|
List<FeatureSorter.StepFeatureData> list = (List) this.featuresPerStep.get();
|
|
- WorldgenRandom seededrandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
|
+ // Matter start - Feature Secure Seed
|
|
+ WorldgenRandom seededrandom = new WorldgenCryptoRandom(
|
|
+ blockposition.getX(), blockposition.getZ(), Globals.Salt.UNDEFINED, 0
|
|
+ );
|
|
long i = seededrandom.setDecorationSeed(generatoraccessseed.getSeed(), blockposition.getX(), blockposition.getZ());
|
|
+ // Matter end
|
|
Set<Holder<Biome>> set = new ObjectArraySet();
|
|
|
|
ChunkPos.rangeClosed(sectionposition.chunk(), 1).forEach((chunkcoordintpair1) -> {
|
|
@@ -774,9 +777,11 @@ public abstract class ChunkGenerator {
|
|
ArrayList<StructureSet.StructureSelectionEntry> arraylist = new ArrayList(list.size());
|
|
|
|
arraylist.addAll(list);
|
|
- WorldgenRandom seededrandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
-
|
|
- seededrandom.setLargeFeatureSeed(seed, chunkcoordintpair.x, chunkcoordintpair.z);
|
|
+ // Matter start - Feature Secure Seed
|
|
+ WorldgenRandom seededrandom = new WorldgenCryptoRandom(
|
|
+ chunkcoordintpair.x, chunkcoordintpair.z, Globals.Salt.GENERATE_FEATURE, 0
|
|
+ );
|
|
+ // Matter end
|
|
int j = 0;
|
|
|
|
StructureSet.StructureSelectionEntry structureset_a1;
|
|
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
|
index e6240f891e396d91e31b02fdf3084be77e9d6697..06d4013467b55bb5096f410eb1abb4bcbeb9e8a3 100644
|
|
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
|
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
|
|
@@ -27,6 +27,10 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
|
import net.minecraft.world.level.levelgen.blending.Blender;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+// Matter end
|
|
+
|
|
public class ChunkStatus {
|
|
|
|
public static final int MAX_STRUCTURE_DISTANCE = 8;
|
|
@@ -270,6 +274,7 @@ public class ChunkStatus {
|
|
}
|
|
|
|
public CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> generate(Executor executor, ServerLevel world, ChunkGenerator generator, StructureTemplateManager structureTemplateManager, ThreadedLevelLightEngine lightingProvider, Function<ChunkAccess, CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>> fullChunkConverter, List<ChunkAccess> chunks, boolean regenerate) {
|
|
+ Globals.setupGlobals(world); // Matter
|
|
ChunkAccess ichunkaccess = (ChunkAccess) chunks.get(chunks.size() / 2);
|
|
ProfiledDuration profiledduration = JvmProfiler.INSTANCE.onChunkGenerate(ichunkaccess.getPos(), world.dimension(), this.name);
|
|
CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>> completablefuture = this.generationTask.doWork(this, executor, world, generator, structureTemplateManager, lightingProvider, fullChunkConverter, chunks, ichunkaccess, regenerate);
|
|
diff --git a/src/main/java/net/minecraft/world/level/levelgen/WorldGenSettings.java b/src/main/java/net/minecraft/world/level/levelgen/WorldGenSettings.java
|
|
index 503c23d15cdeaee84ab81859ceeafb0d437d2f6c..b6fd578921ad0656d51ffa1f3d065fdce628d217 100644
|
|
--- a/src/main/java/net/minecraft/world/level/levelgen/WorldGenSettings.java
|
|
+++ b/src/main/java/net/minecraft/world/level/levelgen/WorldGenSettings.java
|
|
@@ -23,9 +23,21 @@ import net.minecraft.world.level.dimension.DimensionType;
|
|
import net.minecraft.world.level.dimension.LevelStem;
|
|
import org.apache.commons.lang3.StringUtils;
|
|
|
|
+// Matter start
|
|
+import java.util.stream.LongStream;
|
|
+
|
|
+import su.plo.matter.Globals;
|
|
+// Matter end
|
|
+
|
|
public class WorldGenSettings {
|
|
- public static final Codec<WorldGenSettings> CODEC = RecordCodecBuilder.create((instance) -> {
|
|
- return instance.group(Codec.LONG.fieldOf("seed").stable().forGetter(WorldGenSettings::seed), Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldGenSettings::generateStructures), Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldGenSettings::generateBonusChest), RegistryCodecs.dataPackAwareCodec(Registry.LEVEL_STEM_REGISTRY, Lifecycle.stable(), LevelStem.CODEC).xmap(LevelStem::sortMap, Function.identity()).fieldOf("dimensions").forGetter(WorldGenSettings::dimensions), Codec.STRING.optionalFieldOf("legacy_custom_options").stable().forGetter((worldGenSettings) -> {
|
|
+ // Matter start - Feature Secure Seed
|
|
+ public static final Codec<WorldGenSettings> CODEC = RecordCodecBuilder.<WorldGenSettings>create((instance) -> {
|
|
+ return instance.group(Codec.LONG.fieldOf("seed").stable().forGetter(WorldGenSettings::seed),
|
|
+ Codec.LONG_STREAM.fieldOf("feature_seed").stable().forGetter((settings) -> LongStream.of(settings.featureSeed())),
|
|
+ Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldGenSettings::generateStructures),
|
|
+ Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldGenSettings::generateBonusChest),
|
|
+ RegistryCodecs.dataPackAwareCodec(Registry.LEVEL_STEM_REGISTRY, Lifecycle.stable(), LevelStem.CODEC).xmap(LevelStem::sortMap, Function.identity()).fieldOf("dimensions").forGetter(WorldGenSettings::dimensions),
|
|
+ Codec.STRING.optionalFieldOf("legacy_custom_options").stable().forGetter((worldGenSettings) -> { // Matter end
|
|
return worldGenSettings.legacyCustomOptions;
|
|
})).apply(instance, instance.stable(WorldGenSettings::new));
|
|
}).comapFlatMap(WorldGenSettings::guardExperimental, Function.identity());
|
|
@@ -35,6 +47,9 @@ public class WorldGenSettings {
|
|
private final Registry<LevelStem> dimensions;
|
|
private final Optional<String> legacyCustomOptions;
|
|
|
|
+ // Matter - Feature Secure Seed
|
|
+ private final long[] featureSeed;
|
|
+
|
|
private DataResult<WorldGenSettings> guardExperimental() {
|
|
LevelStem levelStem = this.dimensions.get(LevelStem.OVERWORLD);
|
|
if (levelStem == null) {
|
|
@@ -48,15 +63,24 @@ public class WorldGenSettings {
|
|
return LevelStem.stable(this.dimensions);
|
|
}
|
|
|
|
- public WorldGenSettings(long seed, boolean generateStructures, boolean bonusChest, Registry<LevelStem> options) {
|
|
- this(seed, generateStructures, bonusChest, options, Optional.empty());
|
|
+ // Matter start - Feature Secure Seed
|
|
+ public WorldGenSettings(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest, Registry<LevelStem> options) {
|
|
+ this(seed, featureSeed, generateStructures, bonusChest, options, Optional.empty());
|
|
+ // Matter end - Feature Secure Seed
|
|
LevelStem levelStem = options.get(LevelStem.OVERWORLD);
|
|
if (levelStem == null) {
|
|
throw new IllegalStateException("Overworld settings missing");
|
|
}
|
|
}
|
|
|
|
- private WorldGenSettings(long seed, boolean generateStructures, boolean bonusChest, Registry<LevelStem> options, Optional<String> legacyCustomOptions) {
|
|
+ // Matter start - Feature Secure Seed
|
|
+ private WorldGenSettings(long seed, LongStream featureSeed, boolean generateStructures, boolean bonusChest, Registry<LevelStem> options, Optional<String> legacyCustomOptions) {
|
|
+ this(seed, featureSeed.toArray(), generateStructures, bonusChest, options, legacyCustomOptions);
|
|
+ }
|
|
+
|
|
+ private WorldGenSettings(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest, Registry<LevelStem> options, Optional<String> legacyCustomOptions) {
|
|
+ this.featureSeed = featureSeed;
|
|
+ // Matter end - Feature Secure Seed
|
|
this.seed = seed;
|
|
this.generateStructures = generateStructures;
|
|
this.generateBonusChest = bonusChest;
|
|
@@ -68,6 +92,12 @@ public class WorldGenSettings {
|
|
return this.seed;
|
|
}
|
|
|
|
+ // Matter start - Feature Secure Seed
|
|
+ public long[] featureSeed() {
|
|
+ return this.featureSeed;
|
|
+ }
|
|
+ // Matter end
|
|
+
|
|
public boolean generateStructures() {
|
|
return this.generateStructures;
|
|
}
|
|
@@ -79,7 +109,8 @@ public class WorldGenSettings {
|
|
public static WorldGenSettings replaceOverworldGenerator(RegistryAccess dynamicRegistryManager, WorldGenSettings generatorOptions, ChunkGenerator chunkGenerator) {
|
|
Registry<DimensionType> registry = dynamicRegistryManager.registryOrThrow(Registry.DIMENSION_TYPE_REGISTRY);
|
|
Registry<LevelStem> registry2 = withOverworld(registry, generatorOptions.dimensions(), chunkGenerator);
|
|
- return new WorldGenSettings(generatorOptions.seed(), generatorOptions.generateStructures(), generatorOptions.generateBonusChest(), registry2);
|
|
+ // Matter - Feature Secure Seed
|
|
+ return new WorldGenSettings(generatorOptions.seed(), Globals.createRandomWorldSeed(), generatorOptions.generateStructures(), generatorOptions.generateBonusChest(), registry2);
|
|
}
|
|
|
|
public static Registry<LevelStem> withOverworld(Registry<DimensionType> dimensionTypeRegistry, Registry<LevelStem> options, ChunkGenerator overworldGenerator) {
|
|
@@ -140,19 +171,24 @@ public class WorldGenSettings {
|
|
}
|
|
|
|
public WorldGenSettings withBonusChest() {
|
|
- return new WorldGenSettings(this.seed, this.generateStructures, true, this.dimensions, this.legacyCustomOptions);
|
|
+ // Matter - Feature Secure Seed
|
|
+ return new WorldGenSettings(this.seed, this.featureSeed, this.generateStructures, true, this.dimensions, this.legacyCustomOptions);
|
|
}
|
|
|
|
public WorldGenSettings withStructuresToggled() {
|
|
- return new WorldGenSettings(this.seed, !this.generateStructures, this.generateBonusChest, this.dimensions);
|
|
+ // Matter - Feature Secure Seed
|
|
+ return new WorldGenSettings(this.seed, this.featureSeed, !this.generateStructures, this.generateBonusChest, this.dimensions);
|
|
}
|
|
|
|
public WorldGenSettings withBonusChestToggled() {
|
|
- return new WorldGenSettings(this.seed, this.generateStructures, !this.generateBonusChest, this.dimensions);
|
|
+ // Matter - Feature Secure Seed
|
|
+ return new WorldGenSettings(this.seed, this.featureSeed, this.generateStructures, !this.generateBonusChest, this.dimensions);
|
|
}
|
|
|
|
public WorldGenSettings withSeed(boolean hardcore, OptionalLong seed) {
|
|
long l = seed.orElse(this.seed);
|
|
+ // Matter - Feature Secure Seed
|
|
+ long[] featureSeed = Globals.createRandomWorldSeed();
|
|
Registry<LevelStem> registry;
|
|
if (seed.isPresent()) {
|
|
WritableRegistry<LevelStem> writableRegistry = new MappedRegistry<>(Registry.LEVEL_STEM_REGISTRY, Lifecycle.experimental(), (Function<LevelStem, Holder.Reference<LevelStem>>)null);
|
|
@@ -169,9 +205,11 @@ public class WorldGenSettings {
|
|
|
|
WorldGenSettings worldGenSettings;
|
|
if (this.isDebug()) {
|
|
- worldGenSettings = new WorldGenSettings(l, false, false, registry);
|
|
+ // Matter - Feature Secure Seed
|
|
+ worldGenSettings = new WorldGenSettings(l, featureSeed, false, false, registry);
|
|
} else {
|
|
- worldGenSettings = new WorldGenSettings(l, this.generateStructures(), this.generateBonusChest() && !hardcore, registry);
|
|
+ // Matter - Feature Secure Seed
|
|
+ worldGenSettings = new WorldGenSettings(l, featureSeed, this.generateStructures(), this.generateBonusChest() && !hardcore, registry);
|
|
}
|
|
|
|
return worldGenSettings;
|
|
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 512942f75552b0b068e9eebcee55ee9d0ac6e5d7..53f8db3b881a1edc6729e7b4730f2f4de3cf8ec1 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
|
|
@@ -25,6 +25,11 @@ import net.minecraft.world.level.levelgen.feature.configurations.GeodeConfigurat
|
|
import net.minecraft.world.level.levelgen.synth.NormalNoise;
|
|
import net.minecraft.world.level.material.FluidState;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
+// Matter end
|
|
+
|
|
public class GeodeFeature extends Feature<GeodeConfiguration> {
|
|
private static final Direction[] DIRECTIONS = Direction.values();
|
|
|
|
@@ -42,7 +47,8 @@ public class GeodeFeature extends Feature<GeodeConfiguration> {
|
|
int j = geodeConfiguration.maxGenOffset;
|
|
List<Pair<BlockPos, Integer>> list = Lists.newLinkedList();
|
|
int k = geodeConfiguration.distributionPoints.sample(randomSource);
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed()));
|
|
+ // Matter - Feature Secure Seed
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(0, 0, Globals.Salt.GEODE_FEATURE, 0);
|
|
NormalNoise normalNoise = NormalNoise.create(worldgenRandom, -4, 1.0D);
|
|
List<BlockPos> list2 = Lists.newLinkedList();
|
|
double d = (double)k / (double)geodeConfiguration.outerWallDistance.getMaxValue();
|
|
diff --git a/src/main/java/net/minecraft/world/level/levelgen/presets/WorldPreset.java b/src/main/java/net/minecraft/world/level/levelgen/presets/WorldPreset.java
|
|
index a2f448d3eb94bdfc99c4810cca08b56741c0b0b5..ec21a02832e88eba5d2566b557cc887006b62786 100644
|
|
--- a/src/main/java/net/minecraft/world/level/levelgen/presets/WorldPreset.java
|
|
+++ b/src/main/java/net/minecraft/world/level/levelgen/presets/WorldPreset.java
|
|
@@ -16,8 +16,13 @@ import net.minecraft.resources.ResourceKey;
|
|
import net.minecraft.world.level.dimension.LevelStem;
|
|
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+// Matter end
|
|
+
|
|
public class WorldPreset {
|
|
- public static final Codec<WorldPreset> DIRECT_CODEC = RecordCodecBuilder.create((instance) -> {
|
|
+ // Matter - compile fix
|
|
+ public static final Codec<WorldPreset> DIRECT_CODEC = RecordCodecBuilder.<WorldPreset>create((instance) -> {
|
|
return instance.group(Codec.unboundedMap(ResourceKey.codec(Registry.LEVEL_STEM_REGISTRY), LevelStem.CODEC).fieldOf("dimensions").forGetter((preset) -> {
|
|
return preset.dimensions;
|
|
})).apply(instance, WorldPreset::new);
|
|
@@ -42,7 +47,8 @@ public class WorldPreset {
|
|
}
|
|
|
|
public WorldGenSettings createWorldGenSettings(long seed, boolean generateStructures, boolean bonusChest) {
|
|
- return new WorldGenSettings(seed, generateStructures, bonusChest, this.createRegistry());
|
|
+ // Matter - Feature Secure Seed
|
|
+ return new WorldGenSettings(seed, Globals.createRandomWorldSeed(), generateStructures, bonusChest, this.createRegistry());
|
|
}
|
|
|
|
public WorldGenSettings recreateWorldGenSettings(WorldGenSettings generatorOptions) {
|
|
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 b8649eab719a1b71dc686386a8db756eefb9802e..9508419308c82e5935a858233d04e327365c00ff 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
|
|
@@ -37,6 +37,11 @@ import net.minecraft.world.level.levelgen.structure.pieces.PiecesContainer;
|
|
import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder;
|
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
+// Matter end
|
|
+
|
|
public abstract class Structure {
|
|
public static final Codec<Structure> DIRECT_CODEC = Registry.STRUCTURE_TYPES.byNameCodec().dispatch(Structure::type, StructureType::codec);
|
|
public static final Codec<Holder<Structure>> CODEC = RegistryFileCodec.create(Registry.STRUCTURE_REGISTRY, DIRECT_CODEC);
|
|
@@ -157,9 +162,11 @@ public abstract class Structure {
|
|
}
|
|
|
|
private static WorldgenRandom makeRandom(long seed, ChunkPos chunkPos) {
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setLargeFeatureSeed(seed, chunkPos.x, chunkPos.z);
|
|
- return worldgenRandom;
|
|
+ // Matter start - Feature Secure Seed
|
|
+ return new WorldgenCryptoRandom(
|
|
+ chunkPos.x, chunkPos.z, Globals.Salt.GENERATE_FEATURE, seed
|
|
+ );
|
|
+ // Matter end
|
|
}
|
|
}
|
|
|
|
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 638e2c868342ae133717936487d4048cde2fafc0..26f9afc05f843addaf05e7df9329b8d075f11321 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
|
|
@@ -11,8 +11,13 @@ import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
|
import net.minecraft.world.level.levelgen.RandomState;
|
|
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
+// Matter end
|
|
+
|
|
public class RandomSpreadStructurePlacement extends StructurePlacement {
|
|
- public static final Codec<RandomSpreadStructurePlacement> CODEC = RecordCodecBuilder.mapCodec((instance) -> {
|
|
+ public static final Codec<RandomSpreadStructurePlacement> CODEC = RecordCodecBuilder.<RandomSpreadStructurePlacement>mapCodec((instance) -> { // Matter - compile fix
|
|
return placementCodec(instance).and(instance.group(Codec.intRange(0, 4096).fieldOf("spacing").forGetter(RandomSpreadStructurePlacement::spacing), Codec.intRange(0, 4096).fieldOf("separation").forGetter(RandomSpreadStructurePlacement::separation), RandomSpreadType.CODEC.optionalFieldOf("spread_type", RandomSpreadType.LINEAR).forGetter(RandomSpreadStructurePlacement::spreadType))).apply(instance, RandomSpreadStructurePlacement::new);
|
|
}).flatXmap((placement) -> {
|
|
return placement.spacing <= placement.separation ? DataResult.error("Spacing has to be larger than separation") : DataResult.success(placement);
|
|
@@ -47,8 +52,11 @@ public class RandomSpreadStructurePlacement extends StructurePlacement {
|
|
public ChunkPos getPotentialStructureChunk(long seed, int x, int z) {
|
|
int i = Math.floorDiv(x, this.spacing);
|
|
int j = Math.floorDiv(z, this.spacing);
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setLargeFeatureWithSalt(seed, i, j, this.salt());
|
|
+ // Matter start
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ i, j, Globals.Salt.POTENTIONAL_FEATURE, this.salt
|
|
+ );
|
|
+ // Matter end
|
|
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 df4ef6c9dd5747f7d8eebeff149bcfab96832864..10c9308537a2e7ae9b466712863b1eaa6b066f02 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
|
|
@@ -17,6 +17,8 @@ import net.minecraft.world.level.levelgen.LegacyRandomSource;
|
|
import net.minecraft.world.level.levelgen.RandomState;
|
|
import net.minecraft.world.level.levelgen.WorldgenRandom;
|
|
import net.minecraft.world.level.levelgen.structure.StructureSet;
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
|
|
public abstract class StructurePlacement {
|
|
public static final Codec<StructurePlacement> CODEC = Registry.STRUCTURE_PLACEMENT_TYPE.byNameCodec().dispatch(StructurePlacement::type, StructurePlacementType::codec);
|
|
@@ -78,32 +80,43 @@ public abstract class StructurePlacement {
|
|
public abstract StructurePlacementType<?> type();
|
|
|
|
private static boolean probabilityReducer(long seed, int regionX, int regionZ, int salt, float frequency) {
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setLargeFeatureWithSalt(seed, regionX, regionZ, salt);
|
|
+ // Matter start
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ regionX, regionZ, Globals.Salt.UNDEFINED, salt
|
|
+ );
|
|
+ // Matter end
|
|
return worldgenRandom.nextFloat() < frequency;
|
|
}
|
|
|
|
private static boolean legacyProbabilityReducerWithDouble(long seed, int i, int chunkX, int chunkZ, float frequency) {
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setLargeFeatureSeed(seed, chunkX, chunkZ);
|
|
+ // Matter start
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ chunkX, chunkZ, Globals.Salt.MINESHAFT_FEATURE, 0
|
|
+ );
|
|
+ // Matter end
|
|
return worldgenRandom.nextDouble() < (double)frequency;
|
|
}
|
|
|
|
private static boolean legacyArbitrarySaltProbabilityReducer(long seed, int i, int regionX, int regionZ, float frequency) {
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setLargeFeatureWithSalt(seed, regionX, regionZ, 10387320);
|
|
+ // Matter start
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ regionX, regionZ, Globals.Salt.BURIED_TREASURE_FEATURE, 0
|
|
+ );
|
|
+ // Matter end
|
|
return worldgenRandom.nextFloat() < frequency;
|
|
}
|
|
|
|
private static boolean legacyPillagerOutpostReducer(long seed, int i, int j, int k, float frequency) {
|
|
int l = j >> 4;
|
|
int m = k >> 4;
|
|
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
|
- worldgenRandom.setSeed((long)(l ^ m << 4) ^ seed);
|
|
+ // Matter - Secure Feature Seed
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ l, m, Globals.Salt.PILLAGER_OUTPOST_FEATURE, 0
|
|
+ );
|
|
+ // Matter end
|
|
worldgenRandom.nextInt();
|
|
return worldgenRandom.nextInt((int)(1.0F / frequency)) == 0;
|
|
}
|
|
-
|
|
/** @deprecated */
|
|
@Deprecated
|
|
public static record ExclusionZone(Holder<StructureSet> otherSet, int chunkCount) {
|
|
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 33a886cd55bb6af2e4b8fcc6bb05465ee3fe4186..f058feee1b62ba20102e6d3ff0eac1df7e07c7c0 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
|
|
@@ -40,6 +40,11 @@ import net.minecraft.world.phys.shapes.VoxelShape;
|
|
import org.apache.commons.lang3.mutable.MutableObject;
|
|
import org.slf4j.Logger;
|
|
|
|
+// Matter start
|
|
+import su.plo.matter.Globals;
|
|
+import su.plo.matter.WorldgenCryptoRandom;
|
|
+// Matter end
|
|
+
|
|
public class JigsawPlacement {
|
|
static final Logger LOGGER = LogUtils.getLogger();
|
|
|
|
@@ -48,7 +53,11 @@ public class JigsawPlacement {
|
|
ChunkGenerator chunkGenerator = context.chunkGenerator();
|
|
StructureTemplateManager structureTemplateManager = context.structureTemplateManager();
|
|
LevelHeightAccessor levelHeightAccessor = context.heightAccessor();
|
|
- WorldgenRandom worldgenRandom = context.random();
|
|
+ // Matter start
|
|
+ WorldgenRandom worldgenRandom = new WorldgenCryptoRandom(
|
|
+ context.chunkPos().x, context.chunkPos().z, Globals.Salt.JIGSAW_PLACEMENT, 0
|
|
+ );
|
|
+ // Matter end
|
|
Registry<StructureTemplatePool> registry = registryAccess.registryOrThrow(Registry.TEMPLATE_POOL_REGISTRY);
|
|
Rotation rotation = Rotation.getRandom(worldgenRandom);
|
|
StructureTemplatePool structureTemplatePool = structurePool.value();
|
|
@@ -235,18 +244,21 @@ public class JigsawPlacement {
|
|
if (!boundingBox2.isInside(structureBlockInfox.pos.relative(JigsawBlock.getFrontFacing(structureBlockInfox.state)))) {
|
|
return 0;
|
|
} else {
|
|
- ResourceLocation resourceLocation = new ResourceLocation(structureBlockInfox.nbt.getString("pool"));
|
|
- Optional<StructureTemplatePool> optional = this.pools.getOptional(resourceLocation);
|
|
- Optional<StructureTemplatePool> optional2 = optional.flatMap((pool) -> {
|
|
+ // Mater start - compile fix
|
|
+ ResourceLocation poolLocation = new ResourceLocation(structureBlockInfox.nbt.getString("pool"));
|
|
+ Optional<StructureTemplatePool> pool1 = this.pools.getOptional(poolLocation);
|
|
+ Optional<StructureTemplatePool> pool2 = pool1.flatMap((pool) -> {
|
|
return this.pools.getOptional(pool.getFallback());
|
|
});
|
|
- int i = optional.map((pool) -> {
|
|
+
|
|
+ int i1 = pool1.map((pool) -> {
|
|
return pool.getMaxSize(this.structureTemplateManager);
|
|
}).orElse(0);
|
|
- int j = optional2.map((pool) -> {
|
|
+ int j1 = pool2.map((pool) -> {
|
|
return pool.getMaxSize(this.structureTemplateManager);
|
|
}).orElse(0);
|
|
- return Math.max(i, j);
|
|
+ return Math.max(i1, j1);
|
|
+ // Mater end - compile fix
|
|
}
|
|
}).max().orElse(0);
|
|
} else {
|
|
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 2d4a14e8c3f876186c417b9e4284a95f65cf9cd5..991010f818dcb26581a09341201087379b52ee04 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;
|
|
|
|
public class EndCityStructure extends Structure {
|
|
public static final Codec<EndCityStructure> 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 36cd894c3a9261d6c3bda7178f4b4d4f1045bd11..e9cade3b86f6e24c6fa2064d6bbb92b322e640c8 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
|
|
@@ -17,6 +17,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;
|
|
|
|
public class MineshaftStructure extends Structure {
|
|
public static final Codec<MineshaftStructure> CODEC = RecordCodecBuilder.create((instance) -> {
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
index 947b0b10fb965f30513fd0df5bc0910fb9cb9a71..05d7e197da45579a28ef0180d6f43a5ab1da794f 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
|
|
@@ -207,7 +207,8 @@ 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
|
|
+ // Matter - Feature Secure Seed
|
|
+ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks ||worldServer.getChunk(this.getX(), this.getZ()).isSlimeChunk();
|
|
}
|
|
|
|
@Override
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
index 7899ae5e60ee2b30c6d4d7056c59bb38cc05b7c8..c8ce729ea50ed2f4bdd2cafdadb7278cfef1f5a2 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
@@ -238,6 +238,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
|
|
import org.yaml.snakeyaml.error.MarkedYAMLException;
|
|
|
|
import net.md_5.bungee.api.chat.BaseComponent; // Spigot
|
|
+import su.plo.matter.Globals;
|
|
|
|
import javax.annotation.Nullable; // Paper
|
|
import javax.annotation.Nonnull; // Paper
|
|
@@ -1193,7 +1194,8 @@ public final class CraftServer implements Server {
|
|
LevelSettings worldSettings;
|
|
// See MinecraftServer.a(String, String, long, WorldType, JsonElement)
|
|
if (worlddata == null) {
|
|
- DedicatedServerProperties.WorldGenProperties properties = new DedicatedServerProperties.WorldGenProperties(Objects.toString(creator.seed()), GsonHelper.parse((creator.generatorSettings().isEmpty()) ? "{}" : creator.generatorSettings()), creator.generateStructures(), creator.type().name().toLowerCase(Locale.ROOT));
|
|
+ // Matter
|
|
+ DedicatedServerProperties.WorldGenProperties properties = new DedicatedServerProperties.WorldGenProperties(Objects.toString(creator.seed()), Globals.seedToString(Globals.createRandomWorldSeed()), GsonHelper.parse((creator.generatorSettings().isEmpty()) ? "{}" : creator.generatorSettings()), creator.generateStructures(), creator.type().name().toLowerCase(Locale.ROOT));
|
|
|
|
WorldGenSettings generatorsettings = properties.create(this.console.registryAccess());
|
|
worldSettings = new LevelSettings(name, GameType.byId(this.getDefaultGameMode().getValue()), hardcore, Difficulty.EASY, false, new GameRules(), console.datapackconfiguration);
|
|
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..c8f77c791ce10bb85244c55682c743a7bd65f8d6
|
|
--- /dev/null
|
|
+++ b/src/main/java/su/plo/matter/Globals.java
|
|
@@ -0,0 +1,87 @@
|
|
+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<Integer> dimension = ThreadLocal.withInitial(() -> 0);
|
|
+
|
|
+ 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
|
|
+ }
|
|
+
|
|
+ public static void setupGlobals(ServerLevel world) {
|
|
+ long[] seed = world.getServer().getWorldData().worldGenSettings().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;
|
|
+ }
|
|
+
|
|
+ public static Optional<long[]> parseSeed(String seedStr) {
|
|
+ if (seedStr.isEmpty()) return Optional.empty();
|
|
+
|
|
+ try {
|
|
+ long[] seed = new long[WORLD_SEED_LONGS];
|
|
+ BigInteger seedBigInt = new BigInteger(seedStr);
|
|
+ if (seedBigInt.signum() < 0) {
|
|
+ seedBigInt = seedBigInt.and(BigInteger.ONE.shiftLeft(WORLD_SEED_BITS).subtract(BigInteger.ONE));
|
|
+ }
|
|
+ for (int i = 0; i < WORLD_SEED_LONGS; i++) {
|
|
+ BigInteger[] divRem = seedBigInt.divideAndRemainder(BigInteger.ONE.shiftLeft(64));
|
|
+ seed[i] = divRem[1].longValue();
|
|
+ seedBigInt = divRem[0];
|
|
+ }
|
|
+ return Optional.of(seed);
|
|
+ } catch (NumberFormatException ignored) {
|
|
+ return Optional.empty();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public static String seedToString(long[] seed) {
|
|
+ BigInteger seedBigInt = BigInteger.ZERO;
|
|
+ for (int i = WORLD_SEED_LONGS - 1; i >= 0; i--) {
|
|
+ BigInteger val = BigInteger.valueOf(seed[i]);
|
|
+ if (val.signum() < 0) {
|
|
+ val = val.add(BigInteger.ONE.shiftLeft(64));
|
|
+ }
|
|
+ seedBigInt = seedBigInt.shiftLeft(64).add(val);
|
|
+ }
|
|
+
|
|
+ return seedBigInt.toString();
|
|
+ }
|
|
+}
|
|
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..d18b15ca0b6585f08b30b019c8c17a0f641c8be0
|
|
--- /dev/null
|
|
+++ b/src/main/java/su/plo/matter/Hashing.java
|
|
@@ -0,0 +1,74 @@
|
|
+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
|
|
+ }
|
|
+}
|
|
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..1d76b84a4d9eeeb975efe9d7ba2440d31ab41ce7
|
|
--- /dev/null
|
|
+++ b/src/main/java/su/plo/matter/WorldgenCryptoRandom.java
|
|
@@ -0,0 +1,140 @@
|
|
+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 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<long[]> LAST_SEEN_WORLD_SEED = ThreadLocal.withInitial(() -> new long[Globals.WORLD_SEED_LONGS]);
|
|
+ private static final ThreadLocal<long[]> HASHED_WORLD_SEED = ThreadLocal.withInitial(() -> HASHED_ZERO_SEED);
|
|
+
|
|
+ private final long[] worldSeed = new long[Globals.WORLD_SEED_LONGS];
|
|
+ private final long[] randomBits = new long[8];
|
|
+ private int randomBitIndex;
|
|
+ private static final int MAX_RANDOM_BIT_INDEX = 64 * 8;
|
|
+ private static final int LOG2_MAX_RANDOM_BIT_INDEX = 9;
|
|
+ private long counter;
|
|
+ private final long[] message = new long[16];
|
|
+ private final long[] cachedInternalState = new long[16];
|
|
+
|
|
+ public WorldgenCryptoRandom(int x, int z, Globals.Salt typeSalt, long salt) {
|
|
+ super(new LegacyRandomSource(0L));
|
|
+ this.setSecureSeed(x, z, typeSalt, salt);
|
|
+ }
|
|
+
|
|
+ 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 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);
|
|
+ }
|
|
+
|
|
+ public static RandomSource seedSlimeChunk(int chunkX, int chunkZ) {
|
|
+ return new WorldgenCryptoRandom(chunkX, chunkZ, Globals.Salt.SLIME_CHUNK, 0);
|
|
+ }
|
|
+}
|