mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-02-16 02:20:44 +00:00
fix levelstem injection not working for main worlds
This commit is contained in:
committed by
Julian Krings
parent
1c5eb8b910
commit
7fa1484b21
@@ -5,6 +5,7 @@ import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.INMSBinding;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
@@ -78,11 +79,10 @@ import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NMSBinding implements INMSBinding {
|
||||
|
||||
@@ -94,6 +94,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -574,8 +575,9 @@ public class NMSBinding implements INMSBinding {
|
||||
|
||||
public void inject(long seed, Engine engine, World world) {
|
||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||
}
|
||||
|
||||
@@ -637,38 +639,79 @@ public class NMSBinding implements INMSBinding {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -679,4 +722,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getOrThrow(key).generator()
|
||||
), Lifecycle.stable());
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.registryKeySet().forEach(key -> {
|
||||
var value = source.get(key);
|
||||
var info = source.lifecycle(value);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -91,6 +91,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -543,8 +544,9 @@ public class NMSBinding implements INMSBinding {
|
||||
|
||||
public void inject(long seed, Engine engine, World world) {
|
||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||
}
|
||||
|
||||
@@ -638,38 +640,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -680,4 +723,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getOrThrow(key).generator()
|
||||
), Lifecycle.stable());
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.registryKeySet().forEach(key -> {
|
||||
var value = source.get(key);
|
||||
var info = source.lifecycle(value);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,14 +8,14 @@ import java.io.DataOutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -91,6 +91,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -543,8 +544,9 @@ public class NMSBinding implements INMSBinding {
|
||||
|
||||
public void inject(long seed, Engine engine, World world) {
|
||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||
}
|
||||
|
||||
@@ -639,38 +641,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return registry.getHolderOrThrow(ResourceKey.create(Registries.BIOME, CraftNamespacedKey.toMinecraft(biome.getKey())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -681,4 +724,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getOrThrow(key).generator()
|
||||
), Lifecycle.stable());
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.registryKeySet().forEach(key -> {
|
||||
var value = source.get(key);
|
||||
var info = source.lifecycle(value);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,12 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.util.nbt.tag.CompoundTag;
|
||||
@@ -96,6 +99,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -551,8 +555,9 @@ public class NMSBinding implements INMSBinding {
|
||||
|
||||
public void inject(long seed, Engine engine, World world) {
|
||||
var chunkMap = ((CraftWorld)world).getHandle().getChunkSource().chunkMap;
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
|
||||
chunkMap.generator = new IrisChunkGenerator(chunkMap.generator, seed, engine, world);
|
||||
}
|
||||
@@ -661,38 +666,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -703,4 +749,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getOrThrow(key).generator()
|
||||
), RegistrationInfo.BUILT_IN);
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.registryKeySet().forEach(key -> {
|
||||
var value = source.get(key);
|
||||
var info = source.registrationInfo(key).orElse(null);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,12 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
@@ -93,6 +96,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -551,8 +555,9 @@ public class NMSBinding implements INMSBinding {
|
||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||
worldGenContextField.setAccessible(true);
|
||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
|
||||
var newContext = new WorldGenContext(
|
||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||
@@ -665,38 +670,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public com.volmit.iris.core.nms.container.Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().registryOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new com.volmit.iris.core.nms.container.Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.registryOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.registryOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.registry(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -707,4 +753,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getOrThrow(key).generator()
|
||||
), RegistrationInfo.BUILT_IN);
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.registryKeySet().forEach(key -> {
|
||||
var value = source.get(key);
|
||||
var info = source.registrationInfo(key).orElse(null);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,9 +6,13 @@ import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.util.scheduling.J;
|
||||
import lombok.SneakyThrows;
|
||||
@@ -82,6 +86,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -540,8 +545,9 @@ public class NMSBinding implements INMSBinding {
|
||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||
worldGenContextField.setAccessible(true);
|
||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
|
||||
var newContext = new WorldGenContext(
|
||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||
@@ -654,38 +660,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -696,4 +743,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getValueOrThrow(key).generator()
|
||||
), RegistrationInfo.BUILT_IN);
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.listElementIds().forEach(key -> {
|
||||
var value = source.getValue(key);
|
||||
var info = source.registrationInfo(key).orElse(null);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.volmit.iris.Iris;
|
||||
import com.volmit.iris.core.nms.INMSBinding;
|
||||
import com.volmit.iris.core.nms.container.AutoClosing;
|
||||
import com.volmit.iris.core.nms.container.BiomeColor;
|
||||
import com.volmit.iris.core.nms.container.Pair;
|
||||
import com.volmit.iris.core.nms.datapack.DataVersion;
|
||||
import com.volmit.iris.engine.data.cache.AtomicCache;
|
||||
import com.volmit.iris.engine.framework.Engine;
|
||||
@@ -72,6 +74,8 @@ import java.lang.reflect.Modifier;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class NMSBinding implements INMSBinding {
|
||||
private final KMap<Biome, Object> baseBiomeCache = new KMap<>();
|
||||
@@ -81,6 +85,7 @@ public class NMSBinding implements INMSBinding {
|
||||
private final AtomicCache<MCAIdMapper<BlockState>> registryCache = new AtomicCache<>();
|
||||
private final AtomicCache<MCAPalette<BlockState>> globalCache = new AtomicCache<>();
|
||||
private final AtomicCache<RegistryAccess> registryAccess = new AtomicCache<>();
|
||||
private final ReentrantLock dataContextLock = new ReentrantLock(true);
|
||||
private final AtomicCache<Method> byIdRef = new AtomicCache<>();
|
||||
private Field biomeStorageCache = null;
|
||||
|
||||
@@ -539,8 +544,9 @@ public class NMSBinding implements INMSBinding {
|
||||
var worldGenContextField = getField(chunkMap.getClass(), WorldGenContext.class);
|
||||
worldGenContextField.setAccessible(true);
|
||||
var worldGenContext = (WorldGenContext) worldGenContextField.get(chunkMap);
|
||||
if (!chunkMap.level.dimension().location().getPath().startsWith("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type!", world.getName());
|
||||
var dimensionType = chunkMap.level.dimensionTypeRegistration().unwrapKey().orElse(null);
|
||||
if (dimensionType != null && !dimensionType.location().getNamespace().equals("iris"))
|
||||
Iris.error("Loaded world %s with invalid dimension type! (%s)", world.getName(), dimensionType.location().toString());
|
||||
|
||||
var newContext = new WorldGenContext(
|
||||
worldGenContext.level(), new IrisChunkGenerator(worldGenContext.generator(), seed, engine, world),
|
||||
@@ -653,38 +659,79 @@ public class NMSBinding implements INMSBinding {
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AutoClosing injectLevelStems() {
|
||||
return inject(this::supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SneakyThrows
|
||||
public World createWorld(WorldCreator creator) {
|
||||
public Pair<Integer, AutoClosing> injectUncached(boolean overworld, boolean nether, boolean end) {
|
||||
var reg = registry();
|
||||
var field = getField(RegistryAccess.ImmutableRegistryAccess.class, Map.class);
|
||||
field.setAccessible(true);
|
||||
|
||||
AutoClosing closing = inject(old -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), true, overworld, nether, end)
|
||||
)
|
||||
);
|
||||
|
||||
var injected = ((CraftServer) Bukkit.getServer()).getServer().worldLoader.datapackDimensions().lookupOrThrow(Registries.LEVEL_STEM);
|
||||
var old = (Map<ResourceKey<? extends Registry<?>>, Registry<?>>) field.get(reg);
|
||||
var fake = new HashMap<>(old);
|
||||
fake.put(Registries.LEVEL_STEM, injected);
|
||||
field.set(reg, fake);
|
||||
|
||||
return new Pair<>(
|
||||
injected.size(),
|
||||
new AutoClosing(() -> {
|
||||
closing.close();
|
||||
field.set(reg, old);
|
||||
}));
|
||||
}
|
||||
|
||||
private WorldLoader.DataLoadContext supplier(WorldLoader.DataLoadContext old) {
|
||||
return dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess(old.datapackDimensions(), false, true, true, true)
|
||||
));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private AutoClosing inject(Function<WorldLoader.DataLoadContext, WorldLoader.DataLoadContext> transformer) {
|
||||
if (!dataContextLock.tryLock()) throw new IllegalStateException("Failed to inject data context!");
|
||||
|
||||
var server = ((CraftServer) Bukkit.getServer());
|
||||
var field = getField(MinecraftServer.class, WorldLoader.DataLoadContext.class);
|
||||
var nmsServer = server.getServer();
|
||||
var old = nmsServer.worldLoader;
|
||||
|
||||
field.setAccessible(true);
|
||||
field.set(nmsServer, dataLoadContext.aquire(() -> new WorldLoader.DataLoadContext(
|
||||
old.resources(),
|
||||
old.dataConfiguration(),
|
||||
old.datapackWorldgen(),
|
||||
createRegistryAccess()
|
||||
)));
|
||||
field.set(nmsServer, transformer.apply(old));
|
||||
|
||||
try {
|
||||
return server.createWorld(creator);
|
||||
} finally {
|
||||
return new AutoClosing(() -> {
|
||||
field.set(nmsServer, old);
|
||||
}
|
||||
dataContextLock.unlock();
|
||||
});
|
||||
}
|
||||
|
||||
private RegistryAccess.Frozen createRegistryAccess() {
|
||||
private RegistryAccess.Frozen createRegistryAccess(RegistryAccess.Frozen datapack, boolean copy, boolean overworld, boolean nether, boolean end) {
|
||||
var access = registry();
|
||||
var dimensions = access.lookupOrThrow(Registries.DIMENSION_TYPE);
|
||||
var levelStems = access.lookupOrThrow(Registries.LEVEL_STEM);
|
||||
|
||||
var fake = new MappedRegistry<>(Registries.LEVEL_STEM, Lifecycle.experimental());
|
||||
register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
register(fake, levelStems, dimensions, LevelStem.END);
|
||||
if (overworld) register(fake, levelStems, dimensions, LevelStem.OVERWORLD);
|
||||
if (nether) register(fake, levelStems, dimensions, LevelStem.NETHER);
|
||||
if (end) register(fake, levelStems, dimensions, LevelStem.END);
|
||||
copy(fake, datapack.lookup(Registries.LEVEL_STEM).orElse(null));
|
||||
|
||||
if (copy) copy(fake, levelStems);
|
||||
|
||||
return new RegistryAccess.Frozen.ImmutableRegistryAccess(List.of(fake.freeze())).freeze();
|
||||
}
|
||||
@@ -695,4 +742,14 @@ public class NMSBinding implements INMSBinding {
|
||||
levelStems.getValueOrThrow(key).generator()
|
||||
), RegistrationInfo.BUILT_IN);
|
||||
}
|
||||
|
||||
private void copy(MappedRegistry<LevelStem> target, Registry<LevelStem> source) {
|
||||
if (source == null) return;
|
||||
source.listElementIds().forEach(key -> {
|
||||
var value = source.getValue(key);
|
||||
var info = source.registrationInfo(key).orElse(null);
|
||||
if (value != null && info != null && !target.containsKey(key))
|
||||
target.register(key, value, info);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user