mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-11-01 08:50:06 +00:00
Refused unstageable takeovers
- Datapack staging refuses a takeover it cannot stage when the level has applied takeover state or Iris generation history, instead of silently leaving the mod generator in place - A level's retained generation history now stages its takeover even when the installed pack is gone - Takeover pack names and dimension keys are resolved to the installed folder and file names before staging, reconciliation, and recording, and the takeover command stores that form - Reconciliation refuses to switch an applied level to an uninstalled pack before moving any data, and leaves a never-applied level untouched until its pack is installed
This commit is contained in:
1 parent
cf0587c112
commit
038833e614
7 files changed
+361
-71
No files matched your search
+85
-5
@@ -18,13 +18,16 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.volmlib.util.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -36,6 +39,8 @@ public final class ModdedDimensionTakeovers {
|
||||
private static final String GENERATOR_TYPE = "irisworldgen:iris";
|
||||
private static final String PLACEHOLDER_BIOME_SOURCE = "minecraft:fixed";
|
||||
private static final String PLACEHOLDER_BIOME = "minecraft:plains";
|
||||
private static final String DIMENSIONS = "dimensions";
|
||||
private static final String JSON = ".json";
|
||||
|
||||
private ModdedDimensionTakeovers() {
|
||||
}
|
||||
@@ -80,13 +85,12 @@ public final class ModdedDimensionTakeovers {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static void writeLevelStems(Path datapackRoot, Map<String, String> configured,
|
||||
Map<String, String> stagedDimensionTypes) throws IOException {
|
||||
public static void writeLevelStems(Path datapackRoot, Map<String, String> configured, StagedTypes staged,
|
||||
Path worldRoot) throws IOException {
|
||||
for (ModdedDimensionTakeover takeover : parseAll(configured)) {
|
||||
String typeRef = stagedDimensionTypes.get(takeover.pack() + ":" + takeover.packDimension());
|
||||
String typeRef = staged.typeRef(takeover, worldRoot);
|
||||
if (typeRef == null) {
|
||||
ModdedIrisLog.error("Iris skipped the dimension takeover of {}: pack '{}' dimension '{}' is not installed or failed validation, so the dimension keeps its own generator",
|
||||
takeover.levelKey(), takeover.pack(), takeover.packDimension());
|
||||
skipUnstaged(takeover, staged, worldRoot);
|
||||
continue;
|
||||
}
|
||||
writeLevelStem(datapackRoot, takeover, typeRef);
|
||||
@@ -95,6 +99,40 @@ public final class ModdedDimensionTakeovers {
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, String> configured() throws IOException {
|
||||
return canonical(ModdedModConfig.get().dimensionTakeovers(), IrisPlatforms.get().packsFolderNoCreate().toPath());
|
||||
}
|
||||
|
||||
static Map<String, String> canonical(Map<String, String> configured, Path packsRoot) throws IOException {
|
||||
Map<String, String> canonical = new TreeMap<>();
|
||||
for (ModdedDimensionTakeover takeover : parseAll(configured)) {
|
||||
canonical.put(takeover.levelKey(), canonical(takeover, packsRoot).packRef());
|
||||
}
|
||||
return Map.copyOf(canonical);
|
||||
}
|
||||
|
||||
public static ModdedDimensionTakeover canonical(ModdedDimensionTakeover takeover, Path packsRoot) throws IOException {
|
||||
Path pack = packsRoot.resolve(takeover.pack());
|
||||
if (!Files.isDirectory(pack)) {
|
||||
return takeover;
|
||||
}
|
||||
String packName = sameIgnoringCase(pack.toRealPath().getFileName().toString(), takeover.pack());
|
||||
Path dimensions = pack.resolve(DIMENSIONS);
|
||||
Path dimensionFile = dimensions.resolve(takeover.packDimension() + JSON);
|
||||
String dimension = takeover.packDimension();
|
||||
if (Files.isRegularFile(dimensionFile)) {
|
||||
String relative = dimensions.toRealPath().relativize(dimensionFile.toRealPath()).toString()
|
||||
.replace(File.separatorChar, '/');
|
||||
dimension = sameIgnoringCase(relative.substring(0, relative.length() - JSON.length()), takeover.packDimension());
|
||||
}
|
||||
return new ModdedDimensionTakeover(takeover.levelKey(), packName, dimension);
|
||||
}
|
||||
|
||||
public static boolean installed(ModdedDimensionTakeover takeover, Path packsRoot) {
|
||||
return Files.isRegularFile(packsRoot.resolve(takeover.pack()).resolve(DIMENSIONS)
|
||||
.resolve(takeover.packDimension() + JSON));
|
||||
}
|
||||
|
||||
public static Set<String> changedLevels(Map<String, String> applied, Map<String, String> configured) {
|
||||
Set<String> levels = new TreeSet<>(applied.keySet());
|
||||
levels.addAll(configured.keySet());
|
||||
@@ -107,6 +145,32 @@ public final class ModdedDimensionTakeovers {
|
||||
return changed;
|
||||
}
|
||||
|
||||
private static void skipUnstaged(ModdedDimensionTakeover takeover, StagedTypes staged, Path worldRoot) throws IOException {
|
||||
String reason = "pack '" + takeover.pack() + "' dimension '" + takeover.packDimension()
|
||||
+ "' is not installed or failed validation" + caseHint(takeover, staged);
|
||||
if (worldRoot != null && ModdedTakeoverReconciler.hasTakeoverRecord(worldRoot, takeover.levelKey())) {
|
||||
throw new IOException("Iris refused to stage the dimension takeover of " + takeover.levelKey() + ": " + reason
|
||||
+ ", and the level already has an applied takeover or Iris generation history. Restore the pack, or run /iris world takeover "
|
||||
+ takeover.levelKey() + " off to hand the level back to its own generator.");
|
||||
}
|
||||
ModdedIrisLog.error("Iris skipped the dimension takeover of {}: {}, so the dimension keeps its own generator and the takeover stays unapplied",
|
||||
takeover.levelKey(), reason);
|
||||
}
|
||||
|
||||
private static String caseHint(ModdedDimensionTakeover takeover, StagedTypes staged) {
|
||||
String wanted = takeover.pack() + ":" + takeover.packDimension();
|
||||
for (String installed : staged.installed().keySet()) {
|
||||
if (installed.equalsIgnoreCase(wanted)) {
|
||||
return "; pack names and dimension keys are case-sensitive, the installed dimension is " + installed;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String sameIgnoringCase(String actual, String configured) {
|
||||
return actual.equalsIgnoreCase(configured) ? actual : configured;
|
||||
}
|
||||
|
||||
public static String fingerprint(Map<String, String> configured) {
|
||||
StringBuilder canonical = new StringBuilder();
|
||||
for (Map.Entry<String, String> entry : new TreeMap<>(configured).entrySet()) {
|
||||
@@ -114,4 +178,20 @@ public final class ModdedDimensionTakeovers {
|
||||
}
|
||||
return canonical.toString();
|
||||
}
|
||||
|
||||
public record StagedTypes(Map<String, String> installed, Map<Path, String> retained) {
|
||||
public static StagedTypes create() {
|
||||
return new StagedTypes(new LinkedHashMap<>(), new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
String typeRef(ModdedDimensionTakeover takeover, Path worldRoot) {
|
||||
if (worldRoot != null) {
|
||||
String retainedType = retained.get(takeover.storageFolder(worldRoot).toAbsolutePath().normalize());
|
||||
if (retainedType != null) {
|
||||
return retainedType;
|
||||
}
|
||||
}
|
||||
return installed.get(takeover.pack() + ":" + takeover.packDimension());
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
-13
@@ -324,7 +324,7 @@ public final class ModdedForcedDatapack {
|
||||
false
|
||||
);
|
||||
digest.update(inputFingerprint.getBytes(StandardCharsets.UTF_8));
|
||||
digest.update(ModdedDimensionTakeovers.fingerprint(ModdedModConfig.get().dimensionTakeovers())
|
||||
digest.update(ModdedDimensionTakeovers.fingerprint(ModdedDimensionTakeovers.configured())
|
||||
.getBytes(StandardCharsets.UTF_8));
|
||||
return HexFormat.of().formatHex(digest.digest());
|
||||
}
|
||||
@@ -335,7 +335,7 @@ public final class ModdedForcedDatapack {
|
||||
|
||||
int packCount = 0;
|
||||
KList<String> presetIds = new KList<>();
|
||||
Map<String, String> stagedDimensionTypes = new LinkedHashMap<>();
|
||||
ModdedDimensionTakeovers.StagedTypes stagedDimensionTypes = ModdedDimensionTakeovers.StagedTypes.create();
|
||||
Path worldRoot = worldRootOrNull();
|
||||
Set<PackSelection> legacySelections = unadoptedSelections(worldRoot);
|
||||
List<File> packRoots = compilationPackRoots(worldRoot);
|
||||
@@ -347,7 +347,7 @@ public final class ModdedForcedDatapack {
|
||||
}
|
||||
if (!ModdedEngineBootstrap.loader().clientEnvironment()) {
|
||||
ModdedDimensionTakeovers.writeLevelStems(stagingDirectory,
|
||||
ModdedModConfig.get().dimensionTakeovers(), stagedDimensionTypes);
|
||||
ModdedDimensionTakeovers.configured(), stagedDimensionTypes, worldRoot);
|
||||
}
|
||||
|
||||
IrisDatapackCompiler.installRetainedRegistrySources(packRoots, List.of(stagingDirectory.toFile()), fixer);
|
||||
@@ -370,7 +370,7 @@ public final class ModdedForcedDatapack {
|
||||
private static boolean stagePack(PackStageContext context, IDataFixer fixer, Path stagingDirectory,
|
||||
Map<String, KSet<String>> seenBiomes,
|
||||
KList<String> presetIds,
|
||||
Map<String, String> stagedDimensionTypes) throws IOException {
|
||||
ModdedDimensionTakeovers.StagedTypes stagedDimensionTypes) throws IOException {
|
||||
File sourcePack = context.packRoot().toFile();
|
||||
PackValidationResult validation;
|
||||
try {
|
||||
@@ -400,7 +400,7 @@ public final class ModdedForcedDatapack {
|
||||
stagingDirectory.getParent(), PACK_FOLDER + ".pack-" + sourcePack.getName() + "-");
|
||||
Map<String, KSet<String>> packBiomes = new LinkedHashMap<>();
|
||||
KList<String> packPresetIds = new KList<>();
|
||||
Map<String, String> packDimensionTypes = new LinkedHashMap<>();
|
||||
ModdedDimensionTakeovers.StagedTypes packDimensionTypes = ModdedDimensionTakeovers.StagedTypes.create();
|
||||
KList<File> packFolders = new KList<>();
|
||||
packFolders.add(packStagingDirectory.toFile());
|
||||
boolean installed;
|
||||
@@ -423,7 +423,8 @@ public final class ModdedForcedDatapack {
|
||||
mergeDirectory(packStagingDirectory, stagingDirectory);
|
||||
mergeBiomes(seenBiomes, packBiomes);
|
||||
presetIds.addAll(packPresetIds);
|
||||
stagedDimensionTypes.putAll(packDimensionTypes);
|
||||
stagedDimensionTypes.installed().putAll(packDimensionTypes.installed());
|
||||
stagedDimensionTypes.retained().putAll(packDimensionTypes.retained());
|
||||
return true;
|
||||
} finally {
|
||||
try {
|
||||
@@ -483,7 +484,7 @@ public final class ModdedForcedDatapack {
|
||||
private static boolean installPack(PackStageContext context, IDataFixer fixer, KList<File> folders,
|
||||
Map<String, KSet<String>> seenBiomes,
|
||||
KList<String> presetIds,
|
||||
Map<String, String> dimensionTypes) throws IOException {
|
||||
ModdedDimensionTakeovers.StagedTypes dimensionTypes) throws IOException {
|
||||
File packFolder = context.packRoot().toFile();
|
||||
String packName = context.packName();
|
||||
File dimensionsDirectory = new File(packFolder, "dimensions");
|
||||
@@ -531,8 +532,11 @@ public final class ModdedForcedDatapack {
|
||||
context
|
||||
);
|
||||
}
|
||||
if (context.retainedDimensionRoot() != null) {
|
||||
dimensionTypes.retained().put(context.retainedDimensionRoot(), typeRef);
|
||||
}
|
||||
if (context.emitPresets()) {
|
||||
dimensionTypes.put(packName + ":" + dimensionKey, typeRef);
|
||||
dimensionTypes.installed().put(packName + ":" + dimensionKey, typeRef);
|
||||
if (!dimension.hasBorrowedDimensionType()) {
|
||||
String presetRef = ModdedWorldgenIds.presetRef(packName, dimensionKey);
|
||||
writeWorldPreset(folders, packName, dimensionKey, presetRef);
|
||||
@@ -830,13 +834,13 @@ public final class ModdedForcedDatapack {
|
||||
GenerationEpoch.DimensionContract contract = retained.epoch().dimensionContract();
|
||||
Optional<ModdedWorldgenIds.ScopedDimension> scoped = ModdedWorldgenIds.scopedDimensionType(contract.dimensionTypeKey());
|
||||
if (scoped.isEmpty()) {
|
||||
return PackStageContext.retained(normalizedRoot, retainedPackName(retained.epoch(), normalizedRoot), retained.epoch());
|
||||
return PackStageContext.retained(normalizedRoot, retainedPackName(retained.epoch(), normalizedRoot), retained);
|
||||
}
|
||||
ModdedWorldgenIds.ScopedDimension identity = scoped.get();
|
||||
if (!identity.dimension().equals(contract.dimensionKey())) {
|
||||
throw new IOException("Retained Iris dimension type identity does not match its epoch contract.");
|
||||
}
|
||||
return PackStageContext.retained(normalizedRoot, identity.pack(), retained.epoch());
|
||||
return PackStageContext.retained(normalizedRoot, identity.pack(), retained);
|
||||
}
|
||||
|
||||
String packName = normalizedRoot.getFileName().toString();
|
||||
@@ -918,7 +922,8 @@ public final class ModdedForcedDatapack {
|
||||
boolean emitLegacyDimensionTypeAlias,
|
||||
boolean required,
|
||||
Set<String> legacyDimensions,
|
||||
GenerationRegistryContract retainedContract
|
||||
GenerationRegistryContract retainedContract,
|
||||
Path retainedDimensionRoot
|
||||
) implements IrisCustomBiomeAliasResolver {
|
||||
private static PackStageContext installed(
|
||||
Path packRoot,
|
||||
@@ -934,6 +939,7 @@ public final class ModdedForcedDatapack {
|
||||
true,
|
||||
false,
|
||||
Set.copyOf(legacyDimensions),
|
||||
null,
|
||||
null
|
||||
);
|
||||
}
|
||||
@@ -941,8 +947,9 @@ public final class ModdedForcedDatapack {
|
||||
private static PackStageContext retained(
|
||||
Path packRoot,
|
||||
String packName,
|
||||
GenerationEpoch epoch
|
||||
RetainedPack retained
|
||||
) {
|
||||
GenerationEpoch epoch = retained.epoch();
|
||||
return new PackStageContext(
|
||||
packRoot,
|
||||
packName,
|
||||
@@ -952,7 +959,8 @@ public final class ModdedForcedDatapack {
|
||||
true,
|
||||
true,
|
||||
Set.of(),
|
||||
epoch.registryContract()
|
||||
epoch.registryContract(),
|
||||
retained.history().paths().dimensionRoot().toAbsolutePath().normalize()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+60
-28
@@ -18,6 +18,7 @@
|
||||
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.spi.IrisPlatforms;
|
||||
import art.arcane.iris.world.history.GenerationEpoch;
|
||||
import art.arcane.iris.world.history.GenerationHistory;
|
||||
import art.arcane.iris.world.history.GenerationHistoryPaths;
|
||||
@@ -42,6 +43,7 @@ import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
import java.util.function.BiPredicate;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class ModdedTakeoverReconciler {
|
||||
private static final String STATE_FILE = "data/irisworldgen/dimension-takeovers.json";
|
||||
@@ -53,7 +55,7 @@ public final class ModdedTakeoverReconciler {
|
||||
public static void reconcileEarly() {
|
||||
try {
|
||||
ModdedModConfig config = ModdedModConfig.get();
|
||||
Map<String, String> configured = config.dimensionTakeovers();
|
||||
Map<String, String> configured = ModdedDimensionTakeovers.configured();
|
||||
Path worldRoot = MainWorldService.configuredWorldRootIfPresent();
|
||||
if (worldRoot == null) {
|
||||
if (!configured.isEmpty()) {
|
||||
@@ -63,17 +65,17 @@ public final class ModdedTakeoverReconciler {
|
||||
return;
|
||||
}
|
||||
Path recoveryParent = ModdedEngineBootstrap.loader().configDir().resolve("irisworldgen");
|
||||
Result result = reconcile(worldRoot, configured, config.takeoverProblems(), recoveryParent);
|
||||
Path packsRoot = IrisPlatforms.get().packsFolderNoCreate().toPath();
|
||||
Result result = reconcile(new Request(worldRoot, configured, config.takeoverProblems(),
|
||||
(ModdedDimensionTakeover takeover) -> ModdedDimensionTakeovers.installed(takeover, packsRoot), recoveryParent));
|
||||
if (!result.adoptedLevels().isEmpty()) {
|
||||
ModdedIrisLog.info("Iris dimension takeover recorded for {}: their existing Iris generation history already uses the configured pack",
|
||||
result.adoptedLevels());
|
||||
}
|
||||
Set<String> quarantined = new TreeSet<>(result.changedLevels());
|
||||
quarantined.removeAll(result.adoptedLevels());
|
||||
if (quarantined.isEmpty()) {
|
||||
if (result.quarantinedLevels().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ModdedIrisLog.warn("Iris dimension takeover changed for {}: {}", quarantined,
|
||||
ModdedIrisLog.warn("Iris dimension takeover changed for {}: {}", result.quarantinedLevels(),
|
||||
result.recovery() == null
|
||||
? "no existing chunk data to quarantine"
|
||||
: "moved their chunk, entity, POI, and Iris Mantle data to " + result.recovery()
|
||||
@@ -89,9 +91,8 @@ public final class ModdedTakeoverReconciler {
|
||||
if (worldRoot.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<String, String> configured = ModdedModConfig.get().dimensionTakeovers();
|
||||
try {
|
||||
recordApplied(worldRoot.get(), configured,
|
||||
recordApplied(worldRoot.get(), ModdedDimensionTakeovers.configured(),
|
||||
(String levelKey, String packRef) -> generatesFrom(server, levelKey, packRef));
|
||||
} catch (IOException | RuntimeException failure) {
|
||||
ModdedIrisLog.error("Iris is stopping the server because it could not record the applied dimension takeovers under {}; an unrecorded takeover would be quarantined on the next start",
|
||||
@@ -118,42 +119,69 @@ public final class ModdedTakeoverReconciler {
|
||||
return Map.copyOf(recorded);
|
||||
}
|
||||
|
||||
static Result reconcile(Path worldRoot, Map<String, String> configured, List<String> configProblems,
|
||||
Path recoveryParent) throws IOException {
|
||||
requireReadableConfig(worldRoot, configProblems);
|
||||
static Result reconcile(Request request) throws IOException {
|
||||
Path worldRoot = request.worldRoot();
|
||||
requireReadableConfig(worldRoot, request.configProblems());
|
||||
Map<String, String> applied = readApplied(worldRoot);
|
||||
Set<String> changed = ModdedDimensionTakeovers.changedLevels(applied, configured);
|
||||
if (changed.isEmpty()) {
|
||||
return new Result(changed, Set.of(), null);
|
||||
}
|
||||
Set<String> changed = ModdedDimensionTakeovers.changedLevels(applied, request.configured());
|
||||
Map<String, String> state = new TreeMap<>(applied);
|
||||
Set<String> quarantined = new TreeSet<>();
|
||||
Set<String> adopted = new TreeSet<>();
|
||||
List<Path> sources = new ArrayList<>();
|
||||
for (String level : changed) {
|
||||
Path storage = ModdedDimensionTakeover.storageFolder(worldRoot, level);
|
||||
String packRef = configured.get(level);
|
||||
if (packRef != null && historyMatches(storage, ModdedDimensionTakeover.parse(level, packRef))) {
|
||||
state.put(level, packRef);
|
||||
adopted.add(level);
|
||||
continue;
|
||||
}
|
||||
String packRef = request.configured().get(level);
|
||||
if (packRef == null) {
|
||||
state.remove(level);
|
||||
quarantined.add(level);
|
||||
continue;
|
||||
}
|
||||
ModdedDimensionTakeover takeover = ModdedDimensionTakeover.parse(level, packRef);
|
||||
Path storage = takeover.storageFolder(worldRoot);
|
||||
if (historyMatches(storage, takeover)) {
|
||||
state.put(level, packRef);
|
||||
adopted.add(level);
|
||||
} else if (request.installed().test(takeover)) {
|
||||
quarantined.add(level);
|
||||
} else {
|
||||
refuseOrSkipUninstalled(worldRoot, applied, takeover);
|
||||
}
|
||||
}
|
||||
List<Path> sources = new ArrayList<>();
|
||||
for (String level : quarantined) {
|
||||
Path storage = ModdedDimensionTakeover.storageFolder(worldRoot, level);
|
||||
for (String folder : ModdedDimensionStorage.chunkDataFolders()) {
|
||||
sources.add(storage.resolve(folder));
|
||||
}
|
||||
}
|
||||
Path recovery = recoveryParent.resolve("takeover-recovery-" + UUID.randomUUID());
|
||||
List<Path> moved = ModdedWorldQuarantine.move(worldRoot, sources, recovery);
|
||||
Path recovery = request.recoveryParent().resolve("takeover-recovery-" + UUID.randomUUID());
|
||||
List<Path> moved = sources.isEmpty() ? List.of() : ModdedWorldQuarantine.move(worldRoot, sources, recovery);
|
||||
if (!state.equals(applied)) {
|
||||
writeApplied(worldRoot, state);
|
||||
}
|
||||
return new Result(changed, Set.copyOf(adopted), moved.isEmpty() ? null : recovery);
|
||||
return new Result(Set.copyOf(quarantined), Set.copyOf(adopted), moved.isEmpty() ? null : recovery);
|
||||
}
|
||||
|
||||
static boolean hasTakeoverRecord(Path worldRoot, String levelKey) throws IOException {
|
||||
return readApplied(worldRoot).containsKey(levelKey) || hasGenerationHistory(
|
||||
ModdedDimensionTakeover.storageFolder(worldRoot, levelKey));
|
||||
}
|
||||
|
||||
private static void refuseOrSkipUninstalled(Path worldRoot, Map<String, String> applied,
|
||||
ModdedDimensionTakeover takeover) throws IOException {
|
||||
if (applied.containsKey(takeover.levelKey()) || hasGenerationHistory(takeover.storageFolder(worldRoot))) {
|
||||
throw new IOException("Iris refused to switch the dimension takeover of " + takeover.levelKey() + " to "
|
||||
+ takeover.packRef() + ": pack '" + takeover.pack() + "' dimension '" + takeover.packDimension()
|
||||
+ "' is not installed, and the level already has an applied takeover or Iris generation history. Install the pack or restore the previous takeover.");
|
||||
}
|
||||
ModdedIrisLog.error("Iris left {} untouched: its takeover pack '{}' dimension '{}' is not installed",
|
||||
takeover.levelKey(), takeover.pack(), takeover.packDimension());
|
||||
}
|
||||
|
||||
private static boolean hasGenerationHistory(Path storage) {
|
||||
return Files.exists(GenerationHistoryPaths.forDimension(storage).generationRoot(), LinkOption.NOFOLLOW_LINKS);
|
||||
}
|
||||
|
||||
static boolean historyMatches(Path storage, ModdedDimensionTakeover takeover) throws IOException {
|
||||
if (!Files.exists(GenerationHistoryPaths.forDimension(storage).generationRoot(), LinkOption.NOFOLLOW_LINKS)) {
|
||||
if (!hasGenerationHistory(storage)) {
|
||||
return false;
|
||||
}
|
||||
GenerationEpoch epoch = GenerationHistory.inspectPacks(storage).manifest().activeEpoch();
|
||||
@@ -225,6 +253,10 @@ public final class ModdedTakeoverReconciler {
|
||||
}
|
||||
}
|
||||
|
||||
record Result(Set<String> changedLevels, Set<String> adoptedLevels, Path recovery) {
|
||||
record Request(Path worldRoot, Map<String, String> configured, List<String> configProblems,
|
||||
Predicate<ModdedDimensionTakeover> installed, Path recoveryParent) {
|
||||
}
|
||||
|
||||
record Result(Set<String> quarantinedLevels, Set<String> adoptedLevels, Path recovery) {
|
||||
}
|
||||
}
|
||||
+15
-5
@@ -27,6 +27,7 @@ import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeWorldGenerators;
|
||||
import art.arcane.iris.modded.MainWorldService;
|
||||
import art.arcane.iris.modded.ModdedDimensionTakeover;
|
||||
import art.arcane.iris.modded.ModdedDimensionTakeovers;
|
||||
import art.arcane.iris.modded.ModdedForcedDatapack;
|
||||
import art.arcane.iris.modded.ModdedDimensionManager;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
@@ -46,6 +47,7 @@ import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeModdedServer;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
@@ -320,12 +322,20 @@ public final class ModdedWorldCommands {
|
||||
if (blockIfPackBroken(source, takeover.levelKey(), pack) || !loadPackDimension(source, pack, takeover.packDimension())) {
|
||||
return 0;
|
||||
}
|
||||
ModdedModConfig.setDimensionTakeover(takeover);
|
||||
ModdedForcedDatapack.scheduleRegeneration("dimension takeover of " + takeover.levelKey());
|
||||
ModdedDimensionTakeover canonical;
|
||||
try {
|
||||
canonical = ModdedDimensionTakeovers.canonical(takeover, ModdedPackCommands.packsRoot().toPath());
|
||||
} catch (IOException unreadable) {
|
||||
ModdedIrisLog.error("Iris could not resolve the takeover pack {} for {}", takeover.packRef(), takeover.levelKey(), unreadable);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.errorDetail(unreadable));
|
||||
return 0;
|
||||
}
|
||||
ModdedModConfig.setDimensionTakeover(canonical);
|
||||
ModdedForcedDatapack.scheduleRegeneration("dimension takeover of " + canonical.levelKey());
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_TAKEOVER_SET,
|
||||
MessageArgument.untrusted("dimensionId", takeover.levelKey()),
|
||||
MessageArgument.untrusted("pack", pack),
|
||||
MessageArgument.untrusted("packDimension", takeover.packDimension())));
|
||||
MessageArgument.untrusted("dimensionId", canonical.levelKey()),
|
||||
MessageArgument.untrusted("pack", canonical.pack()),
|
||||
MessageArgument.untrusted("packDimension", canonical.packDimension())));
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.MODDED_WORLD_COMMANDS_TAKEOVER_RESTART_REQUIRED));
|
||||
return 1;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user