Skip to content

Commit ed07b5e

Browse files
committed
WorldDiff: structure starts comparison
1 parent d1abe96 commit ed07b5e

File tree

3 files changed

+90
-20
lines changed

3 files changed

+90
-20
lines changed

tests/world-diff/src/main/java/com/ishland/c2me/tests/worlddiff/ComparisonSession.java

Lines changed: 68 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.google.common.collect.ImmutableSet;
44
import com.ibm.asyncutil.locks.AsyncSemaphore;
55
import com.ibm.asyncutil.locks.FairAsyncSemaphore;
6+
import com.ishland.c2me.tests.worlddiff.mixin.IChunkSerializer;
67
import com.ishland.c2me.tests.worlddiff.mixin.IStorageIoWorker;
78
import com.ishland.c2me.tests.worlddiff.mixin.IWorldUpdater;
89
import com.mojang.datafixers.util.Pair;
@@ -18,13 +19,17 @@
1819
import net.minecraft.nbt.NbtOps;
1920
import net.minecraft.resource.DataPackSettings;
2021
import net.minecraft.resource.FileResourcePackProvider;
22+
import net.minecraft.resource.ResourceManager;
2123
import net.minecraft.resource.ResourcePackManager;
2224
import net.minecraft.resource.ResourcePackSource;
2325
import net.minecraft.resource.ResourceType;
2426
import net.minecraft.resource.VanillaDataPackProvider;
2527
import net.minecraft.server.SaveLoader;
2628
import net.minecraft.server.command.CommandManager;
2729
import net.minecraft.state.property.Property;
30+
import net.minecraft.structure.StructureContext;
31+
import net.minecraft.structure.StructureManager;
32+
import net.minecraft.structure.StructureStart;
2833
import net.minecraft.util.Identifier;
2934
import net.minecraft.util.Util;
3035
import net.minecraft.util.WorldSavePath;
@@ -43,6 +48,7 @@
4348
import net.minecraft.world.chunk.ChunkSection;
4449
import net.minecraft.world.chunk.ChunkStatus;
4550
import net.minecraft.world.chunk.PalettedContainer;
51+
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
4652
import net.minecraft.world.level.storage.LevelStorage;
4753
import net.minecraft.world.storage.StorageIoWorker;
4854
import net.minecraft.world.updater.WorldUpdater;
@@ -95,6 +101,14 @@ public void compareChunks() {
95101
final int totalChunks = chunks.size();
96102
final StorageIoWorker regionBaseIo = baseWorld.regionIoWorkers.get(world);
97103
final StorageIoWorker regionTargetIo = targetWorld.regionIoWorkers.get(world);
104+
final StructureContext baseStructureContext = new StructureContext(baseWorld.resourceManager, baseWorld.dynamicRegistryManager, baseWorld.structureManager);
105+
final StructureContext targetStructureContext = new StructureContext(targetWorld.resourceManager, targetWorld.dynamicRegistryManager, targetWorld.structureManager);
106+
// final Function<ConfiguredStructureFeature<?, ?>, ConcurrentHashMap<ChunkPos, ArrayList<StructureStart>>> newConcurrentHashMap = k -> new ConcurrentHashMap<>();
107+
// final Function<ChunkPos, ArrayList<StructureStart>> newArrayList = k -> new ArrayList<>();
108+
// ConcurrentHashMap<ConfiguredStructureFeature<?, ?>, ConcurrentHashMap<ChunkPos, ArrayList<StructureStart>>> baseStructureStarts = new ConcurrentHashMap<>();
109+
// ConcurrentHashMap<ConfiguredStructureFeature<?, ?>, ConcurrentHashMap<ChunkPos, ArrayList<StructureStart>>> targetStructureStarts = new ConcurrentHashMap<>();
110+
final Registry<ConfiguredStructureFeature<?, ?>> baseStructureFeatureRegistry = baseWorld.dynamicRegistryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_KEY);
111+
final Registry<ConfiguredStructureFeature<?, ?>> targetStructureFeatureRegistry = targetWorld.dynamicRegistryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_KEY);
98112
AtomicLong completedChunks = new AtomicLong();
99113
AtomicLong completedBlocks = new AtomicLong();
100114
AtomicLong differenceBlocks = new AtomicLong();
@@ -106,6 +120,23 @@ public void compareChunks() {
106120
if (ChunkSerializer.getChunkType(chunkDataBase) == ChunkStatus.ChunkType.PROTOCHUNK
107121
|| ChunkSerializer.getChunkType(chunkDataBase) == ChunkStatus.ChunkType.PROTOCHUNK)
108122
return null;
123+
124+
final Map<ConfiguredStructureFeature<?, ?>, StructureStart> baseStructures = IChunkSerializer.invokeReadStructureStarts(baseStructureContext, chunkDataBase.getCompound("structures"), baseWorld.saveProperties.getGeneratorOptions().getSeed());
125+
// .forEach((configuredStructureFeature, structureStart) -> baseStructureStarts.computeIfAbsent(configuredStructureFeature, newConcurrentHashMap).computeIfAbsent(structureStart.getPos(), newArrayList).add(structureStart));
126+
final Map<ConfiguredStructureFeature<?, ?>, StructureStart> targetStructures = IChunkSerializer.invokeReadStructureStarts(targetStructureContext, chunkDataTarget.getCompound("structures"), targetWorld.saveProperties.getGeneratorOptions().getSeed());
127+
// .forEach((configuredStructureFeature, structureStart) -> targetStructureStarts.computeIfAbsent(configuredStructureFeature, newConcurrentHashMap).computeIfAbsent(structureStart.getPos(), newArrayList).add(structureStart));
128+
129+
baseStructures.forEach((configuredStructureFeature, baseStructureStart) -> {
130+
final Identifier id = baseStructureFeatureRegistry.getId(configuredStructureFeature);
131+
final StructureStart targetStructureStart = targetStructures.get(targetStructureFeatureRegistry.get(id));
132+
if (targetStructureStart == null) System.out.printf("%s not found in target world in chunk %s\n", id, pos);
133+
});
134+
targetStructures.forEach((configuredStructureFeature, targetStructureStart) -> {
135+
final Identifier id = targetStructureFeatureRegistry.getId(configuredStructureFeature);
136+
final StructureStart baseStructureStart = baseStructures.get(baseStructureFeatureRegistry.get(id));
137+
if (baseStructureStart == null) System.out.printf("%s not found in base world in chunk %s\n", id, pos);
138+
});
139+
109140
final Map<ChunkSectionPos, ChunkSection> sectionsBase = readSections(pos, chunkDataBase, baseWorld.dynamicRegistryManager.get(Registry.BIOME_KEY));
110141
final Map<ChunkSectionPos, ChunkSection> sectionsTarget = readSections(pos, chunkDataTarget, baseWorld.dynamicRegistryManager.get(Registry.BIOME_KEY));
111142
sectionsBase.forEach((chunkSectionPos, chunkSectionBase) -> {
@@ -149,6 +180,9 @@ public void compareChunks() {
149180
} catch (InterruptedException ignored) {
150181
}
151182
}
183+
184+
185+
152186
System.err.printf("Comparison completed for %s: block state differences: %d / %d (%.4f%%)\n",
153187
world, differenceBlocks.get(), completedBlocks.get(), differenceBlocks.get() / completedBlocks.floatValue() * 100.0);
154188
System.err.print(blockDifference + "\n");
@@ -215,15 +249,15 @@ private static WorldHandle getWorldHandle(File worldFolder, String description)
215249
new FileResourcePackProvider(session.getDirectory(WorldSavePath.DATAPACKS).toFile(), ResourcePackSource.PACK_SOURCE_WORLD)
216250
);
217251

218-
SaveLoader lv2;
252+
SaveLoader saveLoader;
219253
try {
220254
SaveLoader.FunctionLoaderConfig lv = new SaveLoader.FunctionLoaderConfig(
221255
resourcePackManager,
222256
CommandManager.RegistrationEnvironment.DEDICATED,
223257
2,
224258
false
225259
);
226-
lv2 = SaveLoader.ofLoaded(
260+
saveLoader = SaveLoader.ofLoaded(
227261
lv,
228262
() -> {
229263
DataPackSettings dataPackSettings = session.getDataPackSettings();
@@ -253,10 +287,10 @@ private static WorldHandle getWorldHandle(File worldFolder, String description)
253287
throw new RuntimeException(var38);
254288
}
255289

256-
lv2.refresh();
257-
DynamicRegistryManager.Immutable lv = lv2.dynamicRegistryManager();
258-
// serverPropertiesLoader.getPropertiesHandler().getGeneratorOptions(lv);
259-
SaveProperties saveProperties = lv2.saveProperties();
290+
saveLoader.refresh();
291+
DynamicRegistryManager.Immutable registryManager = saveLoader.dynamicRegistryManager();
292+
// serverPropertiesLoader.getPropertiesHandler().getGeneratorOptions(registryManager);
293+
SaveProperties saveProperties = saveLoader.saveProperties();
260294
if (saveProperties == null) {
261295
resourcePackManager.close();
262296
throw new FileNotFoundException();
@@ -277,26 +311,40 @@ private static WorldHandle getWorldHandle(File worldFolder, String description)
277311
poiIoWorkers.put(world, new StorageIoWorker(session.getWorldDirectory(world).resolve("poi"), true, "poi") {
278312
});
279313
}
280-
return new WorldHandle(chunkPosesMap, regionIoWorkers, poiIoWorkers, lv, () -> {
281-
System.out.println("Shutting down IOWorkers...");
282-
Stream.concat(regionIoWorkers.values().stream(), poiIoWorkers.values().stream()).forEach(storageIoWorker -> {
283-
storageIoWorker.completeAll(true).join();
284-
try {
285-
storageIoWorker.close();
286-
} catch (IOException e) {
287-
e.printStackTrace();
314+
return new WorldHandle(
315+
chunkPosesMap,
316+
regionIoWorkers,
317+
poiIoWorkers,
318+
saveProperties,
319+
new StructureManager(saveLoader.resourceManager(), session, Schemas.getFixer()),
320+
saveLoader.resourceManager(),
321+
resourcePackManager,
322+
registryManager,
323+
() -> {
324+
System.out.println("Shutting down IOWorkers...");
325+
Stream.concat(regionIoWorkers.values().stream(), poiIoWorkers.values().stream()).forEach(storageIoWorker -> {
326+
storageIoWorker.completeAll(true).join();
327+
try {
328+
storageIoWorker.close();
329+
} catch (IOException e) {
330+
e.printStackTrace();
331+
}
332+
});
333+
System.out.println("Closing world");
334+
resourcePackManager.close();
335+
session.close();
336+
System.out.println("World closed");
288337
}
289-
});
290-
System.out.println("Closing world");
291-
resourcePackManager.close();
292-
session.close();
293-
System.out.println("World closed");
294-
});
338+
);
295339
}
296340

297341
public record WorldHandle(HashMap<RegistryKey<World>, List<ChunkPos>> chunkPosesMap,
298342
HashMap<RegistryKey<World>, StorageIoWorker> regionIoWorkers,
299343
HashMap<RegistryKey<World>, StorageIoWorker> poiIoWorkers,
344+
SaveProperties saveProperties,
345+
StructureManager structureManager,
346+
ResourceManager resourceManager,
347+
ResourcePackManager resourcePackManager,
300348
DynamicRegistryManager dynamicRegistryManager,
301349
Closeable handle) {
302350
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.ishland.c2me.tests.worlddiff.mixin;
2+
3+
import net.minecraft.nbt.NbtCompound;
4+
import net.minecraft.structure.StructureContext;
5+
import net.minecraft.structure.StructureStart;
6+
import net.minecraft.world.ChunkSerializer;
7+
import net.minecraft.world.gen.feature.ConfiguredStructureFeature;
8+
import org.spongepowered.asm.mixin.Mixin;
9+
import org.spongepowered.asm.mixin.gen.Invoker;
10+
11+
import java.util.Map;
12+
13+
@Mixin(ChunkSerializer.class)
14+
public interface IChunkSerializer {
15+
16+
@Invoker
17+
static Map<ConfiguredStructureFeature<?, ?>, StructureStart> invokeReadStructureStarts(StructureContext context, NbtCompound nbt, long worldSeed) {
18+
throw new AbstractMethodError();
19+
}
20+
21+
}

tests/world-diff/src/main/resources/c2meworlddiff.mixins.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"compatibilityLevel": "JAVA_16",
66
"mixinPriority": 1100,
77
"mixins": [
8+
"IChunkSerializer",
89
"IDynamicRegistryManager",
910
"IStorageIoWorker",
1011
"IWorldUpdater",

0 commit comments

Comments
 (0)