mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 05:50:39 +00:00
Derived retained borrowed pack names
- Retained borrowed-type packs take their pack name from the scoped biome aliases recorded in their generation history instead of the dimension key - Scoped legacy biome aliases of retained borrowed packs now match the definitions their worlds reference - A retained pack whose recorded aliases name several packs is refused instead of staged with a guessed name
This commit is contained in:
1 parent
4244aa4ea7
commit
a0c9d48601
3 files changed
+155
-1
No files matched your search
+11
-1
@@ -830,7 +830,7 @@ public final class ModdedForcedDatapack {
|
|||||||
GenerationEpoch.DimensionContract contract = retained.epoch().dimensionContract();
|
GenerationEpoch.DimensionContract contract = retained.epoch().dimensionContract();
|
||||||
Optional<ModdedWorldgenIds.ScopedDimension> scoped = ModdedWorldgenIds.scopedDimensionType(contract.dimensionTypeKey());
|
Optional<ModdedWorldgenIds.ScopedDimension> scoped = ModdedWorldgenIds.scopedDimensionType(contract.dimensionTypeKey());
|
||||||
if (scoped.isEmpty()) {
|
if (scoped.isEmpty()) {
|
||||||
return PackStageContext.retained(normalizedRoot, contract.dimensionKey(), retained.epoch());
|
return PackStageContext.retained(normalizedRoot, retainedPackName(retained.epoch(), normalizedRoot), retained.epoch());
|
||||||
}
|
}
|
||||||
ModdedWorldgenIds.ScopedDimension identity = scoped.get();
|
ModdedWorldgenIds.ScopedDimension identity = scoped.get();
|
||||||
if (!identity.dimension().equals(contract.dimensionKey())) {
|
if (!identity.dimension().equals(contract.dimensionKey())) {
|
||||||
@@ -849,6 +849,16 @@ public final class ModdedForcedDatapack {
|
|||||||
return PackStageContext.installed(normalizedRoot, packName, legacyDimensions);
|
return PackStageContext.installed(normalizedRoot, packName, legacyDimensions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String retainedPackName(GenerationEpoch epoch, Path packRoot) throws IOException {
|
||||||
|
String dimensionKey = epoch.dimensionContract().dimensionKey();
|
||||||
|
Set<String> packs = ModdedWorldgenIds.aliasPacks(epoch.registryContract(), dimensionKey);
|
||||||
|
if (packs.size() > 1) {
|
||||||
|
throw new IOException("Retained Iris generation pack at " + packRoot
|
||||||
|
+ " records scoped biome aliases from several packs " + packs + ".");
|
||||||
|
}
|
||||||
|
return packs.isEmpty() ? dimensionKey : packs.iterator().next();
|
||||||
|
}
|
||||||
|
|
||||||
private static RetainedPack retainedPack(Path packRoot) throws IOException {
|
private static RetainedPack retainedPack(Path packRoot) throws IOException {
|
||||||
Path epochRoot = packRoot.getParent();
|
Path epochRoot = packRoot.getParent();
|
||||||
Path epochsRoot = epochRoot == null ? null : epochRoot.getParent();
|
Path epochsRoot = epochRoot == null ? null : epochRoot.getParent();
|
||||||
|
|||||||
@@ -2,12 +2,17 @@ package art.arcane.iris.modded;
|
|||||||
|
|
||||||
import art.arcane.iris.generation.runtime.Engine;
|
import art.arcane.iris.generation.runtime.Engine;
|
||||||
import art.arcane.iris.generation.terrain.IrisDimension;
|
import art.arcane.iris.generation.terrain.IrisDimension;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContract;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContract.PhysicalResourceKey;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContractFactory;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.HexFormat;
|
import java.util.HexFormat;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
|
||||||
public final class ModdedWorldgenIds {
|
public final class ModdedWorldgenIds {
|
||||||
private static final String NAMESPACE = "irisworldgen";
|
private static final String NAMESPACE = "irisworldgen";
|
||||||
@@ -68,6 +73,41 @@ public final class ModdedWorldgenIds {
|
|||||||
return Optional.of(new ScopedDimension(pack, dimension));
|
return Optional.of(new ScopedDimension(pack, dimension));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Set<String> aliasPacks(GenerationRegistryContract contract, String dimension) {
|
||||||
|
Set<String> packs = new TreeSet<>();
|
||||||
|
for (PhysicalResourceKey key : contract.definitions().keySet()) {
|
||||||
|
if (!GenerationRegistryContractFactory.BIOME_REGISTRY.equals(key.registryKey())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Optional<ScopedDimension> scoped = scopedBiome(key.resourceKey());
|
||||||
|
if (scoped.isPresent() && scoped.get().dimension().equals(dimension)) {
|
||||||
|
packs.add(scoped.get().pack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return packs;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Optional<ScopedDimension> scopedBiome(String biomeRef) {
|
||||||
|
String prefix = NAMESPACE + ":";
|
||||||
|
if (biomeRef == null || !biomeRef.startsWith(prefix)) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String[] parts = biomeRef.substring(prefix.length()).split("/", 6);
|
||||||
|
if (parts.length != 6
|
||||||
|
|| !"packs".equals(parts[0])
|
||||||
|
|| !"dimensions".equals(parts[2])
|
||||||
|
|| !"biomes".equals(parts[4])
|
||||||
|
|| parts[5].isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
String pack = decode(parts[1]);
|
||||||
|
String dimension = decode(parts[3]);
|
||||||
|
if (pack == null || dimension == null) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
return Optional.of(new ScopedDimension(pack, dimension));
|
||||||
|
}
|
||||||
|
|
||||||
public static String displayName(String presetPath) {
|
public static String displayName(String presetPath) {
|
||||||
String[] parts = presetPath.split("/");
|
String[] parts = presetPath.split("/");
|
||||||
if (parts.length != 5 || !"packs".equals(parts[0])
|
if (parts.length != 5 || !"packs".equals(parts[0])
|
||||||
|
|||||||
+104
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Servers
|
||||||
|
* Copyright (c) 2026 Arcane Arts (Volmit Software)
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package art.arcane.iris.modded;
|
||||||
|
|
||||||
|
import art.arcane.iris.world.history.GenerationEpoch;
|
||||||
|
import art.arcane.iris.world.history.GenerationEpochContractFactory;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContract;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContract.PhysicalResourceKey;
|
||||||
|
import art.arcane.iris.world.history.GenerationRegistryContractFactory;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
|
||||||
|
public class ModdedRetainedPackNameTest {
|
||||||
|
private static final String FINGERPRINT = "11".repeat(32);
|
||||||
|
private static final Path PACK_ROOT = Path.of("/srv/world/dimensions/aether/the_aether/iris/generation/epochs/e/pack");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void borrowedRetainedPackTakesItsNameFromTheRecordedScopedBiomeAliases() throws IOException {
|
||||||
|
GenerationEpoch epoch = epoch("aether:the_aether", "sky", List.of(
|
||||||
|
ModdedWorldgenIds.biomeRef("skypack", "sky", "meadow"),
|
||||||
|
"sky:meadow",
|
||||||
|
"iris:biomes/" + "ab".repeat(32)));
|
||||||
|
|
||||||
|
assertEquals("skypack", ModdedForcedDatapack.retainedPackName(epoch, PACK_ROOT));
|
||||||
|
assertEquals(List.of(ModdedWorldgenIds.biomeRef("skypack", "sky", "meadow"), "sky:meadow"),
|
||||||
|
ModdedWorldgenIds.legacyBiomeRefs(ModdedForcedDatapack.retainedPackName(epoch, PACK_ROOT), "sky", "meadow"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void scopedAliasesOfOtherDimensionsAreIgnored() throws IOException {
|
||||||
|
GenerationEpoch epoch = epoch("aether:the_aether", "sky", List.of(
|
||||||
|
ModdedWorldgenIds.biomeRef("otherpack", "ground", "meadow"),
|
||||||
|
ModdedWorldgenIds.biomeRef("skypack", "sky", "meadow")));
|
||||||
|
|
||||||
|
assertEquals("skypack", ModdedForcedDatapack.retainedPackName(epoch, PACK_ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void borrowedRetainedPackWithoutScopedAliasesKeepsTheDimensionKey() throws IOException {
|
||||||
|
GenerationEpoch epoch = epoch("aether:the_aether", "sky", List.of("iris:biomes/" + "ab".repeat(32)));
|
||||||
|
|
||||||
|
assertEquals("sky", ModdedForcedDatapack.retainedPackName(epoch, PACK_ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void aliasesFromSeveralPacksAreRefused() {
|
||||||
|
GenerationEpoch epoch = epoch("aether:the_aether", "sky", List.of(
|
||||||
|
ModdedWorldgenIds.biomeRef("skypack", "sky", "meadow"),
|
||||||
|
ModdedWorldgenIds.biomeRef("otherpack", "sky", "meadow")));
|
||||||
|
|
||||||
|
IOException refused = assertThrows(IOException.class, () -> ModdedForcedDatapack.retainedPackName(epoch, PACK_ROOT));
|
||||||
|
assertEquals(true, refused.getMessage().contains(PACK_ROOT.toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static GenerationEpoch epoch(String dimensionTypeKey, String dimensionKey, List<String> biomeKeys) {
|
||||||
|
Map<PhysicalResourceKey, String> definitions = new TreeMap<>();
|
||||||
|
for (String biome : biomeKeys) {
|
||||||
|
definitions.put(new PhysicalResourceKey(GenerationRegistryContractFactory.BIOME_REGISTRY, biome), FINGERPRINT);
|
||||||
|
}
|
||||||
|
GenerationEpoch.DimensionContract dimension = new GenerationEpoch.DimensionContract(
|
||||||
|
dimensionKey,
|
||||||
|
dimensionTypeKey,
|
||||||
|
"NORMAL",
|
||||||
|
"OVERWORLD",
|
||||||
|
127,
|
||||||
|
0,
|
||||||
|
256,
|
||||||
|
256,
|
||||||
|
1D,
|
||||||
|
false,
|
||||||
|
"none",
|
||||||
|
0,
|
||||||
|
"0".repeat(64),
|
||||||
|
GenerationEpochContractFactory.CURRENT_DIMENSION_TYPE_FINGERPRINT_SCHEMA,
|
||||||
|
FINGERPRINT
|
||||||
|
);
|
||||||
|
return GenerationEpoch.create(new GenerationEpoch.Spec(FINGERPRINT, 1, 5L, 1, 1, 1, FINGERPRINT, dimension,
|
||||||
|
GenerationRegistryContract.fromDefinitions(definitions)));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user