mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 14:00:26 +00:00
Reserved Iris ingest namespaces
- Mod ingest never selects the irisworldgen namespace or a namespace equal to a dimension key of the source pack or any installed Iris pack, so Iris's own scoped and legacy alias biomes are not adopted - Explicitly requesting one of those namespaces is refused - A namespace that belongs to a loaded mod is never treated as an Iris dimension alias namespace
This commit is contained in:
1 parent
b8aabd4fd1
commit
9481a9ecf0
2 files changed
+128
-6
No files matched your search
@@ -19,6 +19,7 @@
|
|||||||
package art.arcane.iris.pack.ingest;
|
package art.arcane.iris.pack.ingest;
|
||||||
|
|
||||||
import art.arcane.iris.pack.AtomicDirectoryPublisher;
|
import art.arcane.iris.pack.AtomicDirectoryPublisher;
|
||||||
|
import art.arcane.iris.pack.PackDirectoryResolver;
|
||||||
import art.arcane.iris.pack.ingest.catalog.CatalogBiome;
|
import art.arcane.iris.pack.ingest.catalog.CatalogBiome;
|
||||||
import art.arcane.iris.pack.ingest.catalog.CatalogNamespace;
|
import art.arcane.iris.pack.ingest.catalog.CatalogNamespace;
|
||||||
import art.arcane.iris.pack.ingest.catalog.CatalogPlacedFeature;
|
import art.arcane.iris.pack.ingest.catalog.CatalogPlacedFeature;
|
||||||
@@ -29,6 +30,7 @@ import art.arcane.iris.structure.nativegen.IrisImportedFeatureControl;
|
|||||||
import art.arcane.iris.studio.workspace.IrisProjectCopier;
|
import art.arcane.iris.studio.workspace.IrisProjectCopier;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.FileAlreadyExistsException;
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -43,9 +45,11 @@ import java.util.Objects;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public final class ModIngester {
|
public final class ModIngester {
|
||||||
private static final Set<String> RESERVED_NAMESPACES = Set.of("minecraft", "c", "iris");
|
private static final Set<String> RESERVED_NAMESPACES = Set.of("minecraft", "c", "iris", "irisworldgen");
|
||||||
|
private static final String JSON = ".json";
|
||||||
|
|
||||||
private ModIngester() {
|
private ModIngester() {
|
||||||
}
|
}
|
||||||
@@ -58,7 +62,7 @@ public final class ModIngester {
|
|||||||
if (Files.exists(source.resolve(IngestManifest.PATH), LinkOption.NOFOLLOW_LINKS)) {
|
if (Files.exists(source.resolve(IngestManifest.PATH), LinkOption.NOFOLLOW_LINKS)) {
|
||||||
throw new IOException("Source pack " + source + " was written by mod ingest; ingest from its original pack instead.");
|
throw new IOException("Source pack " + source + " was written by mod ingest; ingest from its original pack instead.");
|
||||||
}
|
}
|
||||||
Set<String> namespaces = selectNamespaces(request);
|
Set<String> namespaces = selectNamespaces(request, reservedNamespaces(request.catalog(), source, target.getParent()));
|
||||||
requireReplaceableTarget(target, request.replaceTarget());
|
requireReplaceableTarget(target, request.replaceTarget());
|
||||||
String targetKey = target.getFileName().toString();
|
String targetKey = target.getFileName().toString();
|
||||||
Files.createDirectories(target.getParent());
|
Files.createDirectories(target.getParent());
|
||||||
@@ -96,13 +100,13 @@ public final class ModIngester {
|
|||||||
return new ModIngestReport(target, items, IngestManifest.summary(targetKey, pack, namespaces, items));
|
return new ModIngestReport(target, items, IngestManifest.summary(targetKey, pack, namespaces, items));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Set<String> selectNamespaces(ModIngestRequest request) {
|
private static Set<String> selectNamespaces(ModIngestRequest request, Set<String> reserved) {
|
||||||
Set<String> selected = new TreeSet<>();
|
Set<String> selected = new TreeSet<>();
|
||||||
if (!request.namespaces().isEmpty()) {
|
if (!request.namespaces().isEmpty()) {
|
||||||
for (String namespace : request.namespaces()) {
|
for (String namespace : request.namespaces()) {
|
||||||
String normalized = namespace.trim().toLowerCase(Locale.ROOT);
|
String normalized = namespace.trim().toLowerCase(Locale.ROOT);
|
||||||
if (RESERVED_NAMESPACES.contains(normalized)) {
|
if (reserved.contains(normalized)) {
|
||||||
throw new IllegalArgumentException("Namespace " + normalized + " cannot be ingested; it belongs to Minecraft or Iris.");
|
throw new IllegalArgumentException("Namespace " + normalized + " cannot be ingested; it belongs to Minecraft, Iris, or an installed Iris pack dimension.");
|
||||||
}
|
}
|
||||||
selected.add(normalized);
|
selected.add(normalized);
|
||||||
}
|
}
|
||||||
@@ -121,10 +125,40 @@ public final class ModIngester {
|
|||||||
for (CatalogStructure structure : catalog.structures()) {
|
for (CatalogStructure structure : catalog.structures()) {
|
||||||
selected.add(WorldgenCatalogIndex.namespaceOf(structure.key()));
|
selected.add(WorldgenCatalogIndex.namespaceOf(structure.key()));
|
||||||
}
|
}
|
||||||
selected.removeAll(RESERVED_NAMESPACES);
|
selected.removeAll(reserved);
|
||||||
return selected;
|
return selected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Set<String> reservedNamespaces(WorldgenCatalog catalog, Path source, Path packsRoot) throws IOException {
|
||||||
|
Set<String> dimensionKeys = new TreeSet<>(dimensionKeys(source));
|
||||||
|
for (File pack : PackDirectoryResolver.listVisiblePackDirectories(packsRoot.toFile())) {
|
||||||
|
dimensionKeys.addAll(dimensionKeys(pack.toPath()));
|
||||||
|
}
|
||||||
|
for (CatalogNamespace namespace : catalog.namespaces()) {
|
||||||
|
dimensionKeys.remove(namespace.namespace());
|
||||||
|
}
|
||||||
|
Set<String> reserved = new TreeSet<>(RESERVED_NAMESPACES);
|
||||||
|
reserved.addAll(dimensionKeys);
|
||||||
|
return reserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Set<String> dimensionKeys(Path pack) throws IOException {
|
||||||
|
Path dimensions = pack.resolve("dimensions");
|
||||||
|
if (!Files.isDirectory(dimensions, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
|
return Set.of();
|
||||||
|
}
|
||||||
|
Set<String> keys = new TreeSet<>();
|
||||||
|
try (Stream<Path> files = Files.list(dimensions)) {
|
||||||
|
for (Path file : files.toList()) {
|
||||||
|
String name = file.getFileName().toString();
|
||||||
|
if (name.endsWith(JSON) && Files.isRegularFile(file, LinkOption.NOFOLLOW_LINKS)) {
|
||||||
|
keys.add(name.substring(0, name.length() - JSON.length()).toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
private static Set<String> unselectedFeatureNamespaces(WorldgenCatalog catalog, Set<String> selected) {
|
private static Set<String> unselectedFeatureNamespaces(WorldgenCatalog catalog, Set<String> selected) {
|
||||||
Set<String> unselected = new TreeSet<>();
|
Set<String> unselected = new TreeSet<>();
|
||||||
for (CatalogPlacedFeature feature : catalog.placedFeatures()) {
|
for (CatalogPlacedFeature feature : catalog.placedFeatures()) {
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Iris is a World Generator for Minecraft Bukkit Servers
|
||||||
|
* Copyright (c) 2022 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.pack.ingest;
|
||||||
|
|
||||||
|
import art.arcane.iris.pack.ingest.catalog.CatalogBiome;
|
||||||
|
import art.arcane.iris.pack.ingest.catalog.WorldgenCatalog;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.TemporaryFolder;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class IngestReservedNamespaceTest {
|
||||||
|
@Rule
|
||||||
|
public TemporaryFolder folder = new TemporaryFolder();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void defaultIngestNeverAdoptsIrisRegisteredBiomes() throws Exception {
|
||||||
|
Path root = folder.getRoot().toPath();
|
||||||
|
Path source = ModIngestFixture.writeSourcePack(root);
|
||||||
|
ModIngestFixture.write(root.resolve("packs").resolve("underworld"), "dimensions/underworld.json", "{\"name\": \"Underworld\"}");
|
||||||
|
Path target = root.resolve("packs").resolve("modded");
|
||||||
|
|
||||||
|
ModIngestReport report = ModIngester.ingest(new ModIngestRequest(source, target, "overworld", catalog(), Set.of(), false));
|
||||||
|
|
||||||
|
assertNull(ModIngestFixture.item(report, "irisworldgen:packs/6f76/dimensions/6f76/biomes/dunes"));
|
||||||
|
assertNull(ModIngestFixture.item(report, "overworld:dunes"));
|
||||||
|
assertNull(ModIngestFixture.item(report, "underworld:ash_fields"));
|
||||||
|
assertTrue(report.items().stream().noneMatch(item -> Set.of("irisworldgen", "overworld", "underworld").contains(item.namespace())));
|
||||||
|
assertEquals(List.of("examplemod", "othermod"),
|
||||||
|
ModIngestFixture.strings(ModIngestFixture.readJson(target.resolve("ingest/manifest.json")).get("namespaces")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void explicitIrisNamespacesAreRefused() throws Exception {
|
||||||
|
Path root = folder.getRoot().toPath();
|
||||||
|
Path source = ModIngestFixture.writeSourcePack(root);
|
||||||
|
Path target = root.resolve("packs").resolve("modded");
|
||||||
|
|
||||||
|
for (String namespace : List.of("irisworldgen", "overworld")) {
|
||||||
|
assertThrows(namespace, IllegalArgumentException.class, () -> ModIngester.ingest(
|
||||||
|
new ModIngestRequest(source, target, "overworld", catalog(), Set.of(namespace), false)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static WorldgenCatalog catalog() {
|
||||||
|
WorldgenCatalog fixture = ModIngestFixture.catalog();
|
||||||
|
List<CatalogBiome> biomes = new ArrayList<>(fixture.biomes());
|
||||||
|
biomes.add(biome("irisworldgen:packs/6f76/dimensions/6f76/biomes/dunes"));
|
||||||
|
biomes.add(biome("overworld:dunes"));
|
||||||
|
biomes.add(biome("underworld:ash_fields"));
|
||||||
|
return new WorldgenCatalog(fixture.format(), fixture.minecraftVersion(), fixture.platform(),
|
||||||
|
fixture.capturedAtEpochMillis(), fixture.contentFingerprint(), fixture.namespaces(), biomes,
|
||||||
|
fixture.placedFeatures(), fixture.structures(), fixture.dimensionTypes(), fixture.levelStems());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CatalogBiome biome(String key) {
|
||||||
|
List<List<String>> steps = new ArrayList<>(11);
|
||||||
|
for (int index = 0; index < 11; index++) {
|
||||||
|
steps.add(List.of());
|
||||||
|
}
|
||||||
|
return new CatalogBiome(key, 1.5F, 0.1F, true, List.of("minecraft:is_overworld"), steps, List.of(), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user