mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-08-27 12:41:43 +00:00
d
d
This commit is contained in:
+2
-18
@@ -19,6 +19,7 @@
|
||||
package art.arcane.iris.modded;
|
||||
|
||||
import art.arcane.iris.nativegen.NativeStructureGenerationException;
|
||||
import art.arcane.iris.nativegen.NativeStructureGenerationKeys;
|
||||
import art.arcane.iris.nativegen.NativeStructureFactory;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.spi.PlatformStructureHooks;
|
||||
@@ -225,22 +226,15 @@ public final class ModdedStructureHooks implements PlatformStructureHooks {
|
||||
|
||||
@Override
|
||||
public List<String> reachableStructureKeys(PlatformWorld world) {
|
||||
List<String> keys = new ArrayList<>();
|
||||
ServerLevel level = requireLevel(world, "resolve reachable structures");
|
||||
try {
|
||||
BiomeSource source = level.getChunkSource().getGenerator().getBiomeSource();
|
||||
Set<String> possibleBiomes = possibleBiomeKeys(source);
|
||||
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
for (Map.Entry<ResourceKey<Structure>, Structure> entry : registry.entrySet()) {
|
||||
if (hasPossibleBiome(entry.getValue(), possibleBiomes)) {
|
||||
keys.add(entry.getKey().identifier().toString());
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(NativeStructureGenerationKeys.reachable(level, possibleBiomes));
|
||||
} catch (RuntimeException error) {
|
||||
throw new IllegalStateException("Iris failed to resolve reachable structures for modded level '"
|
||||
+ level.dimension().identifier() + "'", error);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -401,16 +395,6 @@ public final class ModdedStructureHooks implements PlatformStructureHooks {
|
||||
return keys;
|
||||
}
|
||||
|
||||
private static boolean hasPossibleBiome(Structure structure, Set<String> possibleBiomeKeys) {
|
||||
for (Holder<Biome> holder : structure.biomes()) {
|
||||
Optional<ResourceKey<Biome>> key = holder.unwrapKey();
|
||||
if (key.isPresent() && possibleBiomeKeys.contains(key.get().identifier().toString())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static ServerLevel level(PlatformWorld world) {
|
||||
return world instanceof ModdedPlatformWorld moddedWorld ? moddedWorld.level() : null;
|
||||
}
|
||||
|
||||
+4
@@ -54,6 +54,9 @@ import static art.arcane.iris.modded.command.ModdedCommandFeedback.USAGE_ICON;
|
||||
final class ModdedCommandHelp {
|
||||
private static final int PAGE_SIZE = 17;
|
||||
private static final int PAGE_BUTTON_WIDTH = 10;
|
||||
private static final TextKey COMMAND_UNREGISTERED = TextKey.of(
|
||||
"iris.modded.help.entry.command.unregistered",
|
||||
"Print every structure excluded from goto completion and its exact reason to the server console");
|
||||
private static final Map<String, List<Entry>> SECTIONS = new LinkedHashMap<>();
|
||||
|
||||
static {
|
||||
@@ -98,6 +101,7 @@ final class ModdedCommandHelp {
|
||||
Entry.command("biome", "<key>", ModdedHelpMessages.COMMAND_BIOME_FIND_AN_IRIS_BIOME),
|
||||
Entry.command("region", "<key>", ModdedHelpMessages.COMMAND_REGION_FIND_AN_IRIS_REGION),
|
||||
Entry.command("object", "<key>", ModdedHelpMessages.COMMAND_OBJECT_FIND_AN_OBJECT_PLACEMENT),
|
||||
Entry.command("unregistered", "", COMMAND_UNREGISTERED),
|
||||
Entry.command("structure", "<key>", ModdedHelpMessages.COMMAND_STRUCTURE_FIND_AN_IRIS_PLACED_OR_NATIVE_DATAPACK_STRUCTURE),
|
||||
Entry.command("poi", "<type>", ModdedHelpMessages.COMMAND_POI_FIND_A_SUPPORTED_POINT_OF_INTEREST)
|
||||
));
|
||||
|
||||
+90
-13
@@ -21,6 +21,10 @@ package art.arcane.iris.modded.command;
|
||||
import art.arcane.iris.core.pack.PackDirectoryResolver;
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
||||
import art.arcane.iris.engine.framework.StructureReachability;
|
||||
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.engine.object.NativeStructureGenerationStatus;
|
||||
import art.arcane.iris.modded.IrisModdedChunkGenerator;
|
||||
import art.arcane.iris.modded.ModdedEngineBootstrap;
|
||||
import art.arcane.iris.modded.ModdedServerLevels;
|
||||
@@ -41,11 +45,16 @@ import org.slf4j.LoggerFactory;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.TreeSet;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
final class ModdedCommandSuggestions {
|
||||
static final SuggestionProvider<CommandSourceStack> BIOME_KEYS = (CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) -> suggestBiomeKeys(context, builder);
|
||||
@@ -103,22 +112,62 @@ final class ModdedCommandSuggestions {
|
||||
}
|
||||
|
||||
static CompletableFuture<Suggestions> suggestStructureKeys(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) {
|
||||
ModdedCommandFeedback.tab(context.getSource());
|
||||
CommandSourceStack source = context.getSource();
|
||||
ModdedCommandFeedback.tab(source);
|
||||
try {
|
||||
Engine engine = IrisModdedCommands.engineFor(context.getSource().getLevel());
|
||||
Collection<String> irisKeys = engine == null ? List.of() : IrisStructureLocator.placedKeys(engine);
|
||||
Registry<Structure> registry = context.getSource().getServer().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
List<String> nativeKeys = new ArrayList<>(registry.keySet().size());
|
||||
for (Identifier identifier : registry.keySet()) {
|
||||
nativeKeys.add(identifier.toString());
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
return builder.buildFuture();
|
||||
}
|
||||
return SharedSuggestionProvider.suggest(combineStructureKeys(irisKeys, nativeKeys), builder);
|
||||
boolean nativeGenerationEnabled =
|
||||
source.getServer().getWorldGenSettings().options().generateStructures();
|
||||
Collection<String> irisKeys = IrisStructureLocator.locatableEditableKeys(engine);
|
||||
Set<String> reachableNativeKeys = StructureReachability.reachableKeys(engine);
|
||||
Registry<Structure> registry = source.getServer().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
List<String> nativeKeys = new ArrayList<>(registry.keySet().size());
|
||||
Set<String> registeredKeys = new HashSet<>(registry.keySet().size());
|
||||
for (Identifier identifier : registry.keySet()) {
|
||||
String key = identifier.toString();
|
||||
registeredKeys.add(normalizeKey(key));
|
||||
IrisNativeStructureDecision decision = NativeStructureGenerationPolicy.resolve(engine, key, false);
|
||||
boolean nativePlacement = IrisStructureLocator.hasNativePlacement(engine, key);
|
||||
boolean locatableNativePlacement = nativePlacement
|
||||
&& IrisStructureLocator.hasLocatableNativePlacement(engine, key);
|
||||
boolean locatableEditableReplacement = !nativePlacement
|
||||
&& decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS
|
||||
&& IrisStructureLocator.hasLocatableEditablePlacement(engine, key);
|
||||
if (isEligibleRegisteredStructure(decision, nativePlacement,
|
||||
locatableNativePlacement, locatableEditableReplacement,
|
||||
reachableNativeKeys.contains(normalizeKey(key)), nativeGenerationEnabled)) {
|
||||
nativeKeys.add(key);
|
||||
}
|
||||
}
|
||||
Collection<String> unregisteredIrisKeys = eligibleUnregisteredEditableKeys(
|
||||
irisKeys, registeredKeys,
|
||||
(String candidate) -> IrisStructureLocator.hasNativePlacement(engine, candidate));
|
||||
return SharedSuggestionProvider.suggest(
|
||||
combineStructureKeys(unregisteredIrisKeys, nativeKeys), builder);
|
||||
} catch (Throwable e) {
|
||||
warnTabFailure("structure keys", context.getSource(), e);
|
||||
warnTabFailure("structure keys", source, e);
|
||||
}
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
static boolean isEligibleRegisteredStructure(IrisNativeStructureDecision decision,
|
||||
boolean nativePlacement,
|
||||
boolean locatableNativePlacement,
|
||||
boolean locatableEditableReplacement,
|
||||
boolean reachable,
|
||||
boolean nativeGenerationEnabled) {
|
||||
if (decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS) {
|
||||
return locatableEditableReplacement
|
||||
|| nativeGenerationEnabled && nativePlacement && locatableNativePlacement;
|
||||
}
|
||||
return nativeGenerationEnabled && decision.generate()
|
||||
&& (reachable || nativePlacement && locatableNativePlacement);
|
||||
}
|
||||
|
||||
static void warnTabFailure(String suggestion, CommandSourceStack source, Throwable error) {
|
||||
String origin = tabOrigin(source);
|
||||
if (!REPORTED_TAB_FAILURES.add(suggestion + '|' + origin + '|' + error.getClass().getName())) {
|
||||
@@ -142,10 +191,38 @@ final class ModdedCommandSuggestions {
|
||||
}
|
||||
|
||||
static List<String> combineStructureKeys(Collection<String> irisKeys, Collection<String> nativeKeys) {
|
||||
Set<String> combined = new TreeSet<>();
|
||||
combined.addAll(irisKeys);
|
||||
combined.addAll(nativeKeys);
|
||||
return List.copyOf(combined);
|
||||
Map<String, String> combined = new TreeMap<>();
|
||||
addStructureKeys(combined, irisKeys);
|
||||
addStructureKeys(combined, nativeKeys);
|
||||
return List.copyOf(combined.values());
|
||||
}
|
||||
|
||||
static List<String> eligibleUnregisteredEditableKeys(
|
||||
Collection<String> irisKeys, Set<String> normalizedRegisteredKeys,
|
||||
Predicate<String> nativePlacement) {
|
||||
List<String> filtered = new ArrayList<>(irisKeys.size());
|
||||
for (String key : irisKeys) {
|
||||
String normalizedKey = normalizeKey(key);
|
||||
if (!normalizedKey.isEmpty()
|
||||
&& !normalizedRegisteredKeys.contains(normalizedKey)
|
||||
&& !nativePlacement.test(key)) {
|
||||
filtered.add(key.trim());
|
||||
}
|
||||
}
|
||||
return List.copyOf(filtered);
|
||||
}
|
||||
|
||||
private static void addStructureKeys(Map<String, String> combined, Collection<String> keys) {
|
||||
for (String key : keys) {
|
||||
String normalizedKey = normalizeKey(key);
|
||||
if (!normalizedKey.isEmpty()) {
|
||||
combined.putIfAbsent(normalizedKey, key.trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static String normalizeKey(String key) {
|
||||
return key == null ? "" : key.trim().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
private static CompletableFuture<Suggestions> suggestPackNames(CommandContext<CommandSourceStack> context, SuggestionsBuilder builder) {
|
||||
|
||||
+3
@@ -242,6 +242,9 @@ final class ModdedCommandTree {
|
||||
.then(Commands.literal("object")
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(ModdedCommandSuggestions.OBJECT_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedLocateCommands.gotoObject(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
.then(Commands.literal("unregistered")
|
||||
.executes((CommandContext<CommandSourceStack> context) ->
|
||||
ModdedUnregisteredStructures.print(context.getSource())))
|
||||
.then(Commands.literal("structure")
|
||||
.then(Commands.argument("key", StringArgumentType.greedyString()).suggests(ModdedCommandSuggestions.STRUCTURE_KEYS)
|
||||
.executes((CommandContext<CommandSourceStack> context) -> ModdedLocateCommands.gotoStructure(context.getSource(), StringArgumentType.getString(context, "key")))))
|
||||
|
||||
+82
-26
@@ -26,6 +26,7 @@ import art.arcane.iris.engine.framework.GenerationSessionLease;
|
||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||
import art.arcane.iris.engine.framework.Locator;
|
||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
||||
import art.arcane.iris.engine.framework.StructureReachability;
|
||||
import art.arcane.iris.engine.framework.WrongEngineBroException;
|
||||
import art.arcane.iris.engine.object.IrisBiome;
|
||||
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
|
||||
@@ -157,7 +158,8 @@ final class ModdedLocateCommands {
|
||||
}
|
||||
Optional<NativeStructureTarget> resolved = resolveNativeStructure(source, level, engine, key);
|
||||
if (resolved.isEmpty()) {
|
||||
if (IrisStructureLocator.isPlaced(engine, key)) {
|
||||
if (!IrisStructureLocator.hasNativePlacement(engine, key)
|
||||
&& IrisStructureLocator.hasLocatableEditablePlacement(engine, key)) {
|
||||
locateIrisStructure(source, level, engine, player, key);
|
||||
return 1;
|
||||
}
|
||||
@@ -166,31 +168,74 @@ final class ModdedLocateCommands {
|
||||
}
|
||||
NativeStructureTarget target = resolved.get();
|
||||
IrisNativeStructureDecision decision = NativeStructureGenerationPolicy.resolve(engine, target.key(), false);
|
||||
if (!decision.generate()
|
||||
&& decision.status() != NativeStructureGenerationStatus.REPLACED_BY_IRIS) {
|
||||
IrisModdedCommands.fail(source, NativeStructureGenerationPolicy.generationStatusMessage(
|
||||
target.key(), decision.status()));
|
||||
boolean nativeGenerationEnabled =
|
||||
source.getServer().getWorldGenSettings().options().generateStructures();
|
||||
boolean nativePlacement = IrisStructureLocator.hasNativePlacement(engine, target.key());
|
||||
boolean locatableNativePlacement = nativePlacement
|
||||
&& IrisStructureLocator.hasLocatableNativePlacement(engine, target.key());
|
||||
boolean locatableEditableReplacement = !nativePlacement
|
||||
&& decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS
|
||||
&& IrisStructureLocator.hasLocatableEditablePlacement(engine, target.key());
|
||||
boolean reachable = StructureReachability.isReachable(engine, target.key());
|
||||
if (!ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
decision, nativePlacement, locatableNativePlacement, locatableEditableReplacement,
|
||||
reachable, nativeGenerationEnabled)) {
|
||||
IrisModdedCommands.fail(source, registeredStructureUnavailableMessage(
|
||||
target.key(), target.availability(), decision,
|
||||
nativePlacement, locatableNativePlacement,
|
||||
nativeGenerationEnabled, reachable));
|
||||
return 0;
|
||||
}
|
||||
if (decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS) {
|
||||
if (!IrisStructureLocator.hasNativePlacement(engine, target.key())) {
|
||||
locateIrisStructure(source, level, engine, player, target.key());
|
||||
return 1;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCHING_NATIVE_STRUCTURE_WITHIN_CHUNKS, MessageArgument.untrusted("value", target.key()), MessageArgument.untrusted("NATIVESTRUCTURELOCATERADIUS", NATIVE_STRUCTURE_LOCATE_RADIUS)));
|
||||
runNativeStructureLocate(source, level, player, target);
|
||||
if (locatableEditableReplacement) {
|
||||
locateIrisStructure(source, level, engine, player, target.key());
|
||||
return 1;
|
||||
}
|
||||
if (!IrisStructureLocator.hasNativePlacement(engine, target.key())
|
||||
&& target.availability() != NativeStructureAvailability.AVAILABLE) {
|
||||
IrisModdedCommands.fail(source, nativeUnavailableMessage(target.key(), target.availability()));
|
||||
return 0;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_SEARCHING_NATIVE_STRUCTURE_WITHIN_CHUNKS, MessageArgument.untrusted("value", target.key()), MessageArgument.untrusted("NATIVESTRUCTURELOCATERADIUS", NATIVE_STRUCTURE_LOCATE_RADIUS)));
|
||||
runNativeStructureLocate(source, level, player, target);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static String registeredStructureUnavailableMessage(
|
||||
String key, NativeStructureAvailability nativeAvailability,
|
||||
IrisNativeStructureDecision decision,
|
||||
boolean nativePlacement, boolean locatableNativePlacement,
|
||||
boolean nativeGenerationEnabled, boolean reachable) {
|
||||
if (!decision.generate()
|
||||
&& decision.status() != NativeStructureGenerationStatus.REPLACED_BY_IRIS) {
|
||||
return NativeStructureGenerationPolicy.generationStatusMessage(key, decision.status());
|
||||
}
|
||||
if (decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS) {
|
||||
if (nativePlacement && !nativeGenerationEnabled) {
|
||||
return withInactiveNativePlacement(
|
||||
nativeUnavailableMessage(key, NativeStructureAvailability.WORLD_DISABLED),
|
||||
nativePlacement, locatableNativePlacement);
|
||||
}
|
||||
return "Iris replacement " + key
|
||||
+ " is configured, but every matching placement has non-positive density or a Y band "
|
||||
+ "outside this world's height range.";
|
||||
}
|
||||
if (!nativeGenerationEnabled) {
|
||||
return withInactiveNativePlacement(
|
||||
nativeUnavailableMessage(key, NativeStructureAvailability.WORLD_DISABLED),
|
||||
nativePlacement, locatableNativePlacement);
|
||||
}
|
||||
NativeStructureAvailability availability = nativeAvailability;
|
||||
if (availability == NativeStructureAvailability.AVAILABLE && !reachable) {
|
||||
availability = NativeStructureAvailability.NO_PLACEMENT;
|
||||
}
|
||||
return withInactiveNativePlacement(
|
||||
nativeUnavailableMessage(key, availability), nativePlacement, locatableNativePlacement);
|
||||
}
|
||||
|
||||
private static String withInactiveNativePlacement(
|
||||
String reason, boolean nativePlacement, boolean locatableNativePlacement) {
|
||||
if (!nativePlacement || locatableNativePlacement) {
|
||||
return reason;
|
||||
}
|
||||
return reason + " A matching Iris nativeStructures placement is also configured, but has non-positive "
|
||||
+ "density or a Y band outside this world's height range.";
|
||||
}
|
||||
|
||||
private static void locateIrisStructure(CommandSourceStack source, ServerLevel level, Engine engine,
|
||||
ServerPlayer player, String key) {
|
||||
MinecraftServer server = source.getServer();
|
||||
@@ -311,7 +356,7 @@ final class ModdedLocateCommands {
|
||||
case AVAILABLE -> available++;
|
||||
case WORLD_DISABLED, FILTERED -> disabled++;
|
||||
case IRIS_SUPPRESSED -> suppressed++;
|
||||
case BIOME_UNREACHABLE -> unreachableBiomes++;
|
||||
case EMPTY_BIOME_FILTER, BIOME_UNREACHABLE -> unreachableBiomes++;
|
||||
case NO_PLACEMENT -> unsupported++;
|
||||
}
|
||||
}
|
||||
@@ -361,25 +406,28 @@ final class ModdedLocateCommands {
|
||||
return Optional.of(new NativeStructureTarget(key, holder.get(), availability));
|
||||
}
|
||||
|
||||
private static NativeStructureAvailability nativeAvailability(CommandSourceStack source, ServerLevel level,
|
||||
Engine engine, String key,
|
||||
Holder.Reference<Structure> holder) {
|
||||
static NativeStructureAvailability nativeAvailability(CommandSourceStack source, ServerLevel level,
|
||||
Engine engine, String key,
|
||||
Holder.Reference<Structure> holder) {
|
||||
boolean worldEnabled = source.getServer().getWorldGenSettings().options().generateStructures();
|
||||
IrisNativeStructureDecision decision = NativeStructureGenerationPolicy.resolve(engine, key, false);
|
||||
boolean selected = decision.status() != NativeStructureGenerationStatus.DISABLED_BY_PACK;
|
||||
boolean suppressed = decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS;
|
||||
boolean biomeFilterEmpty = holder.value().biomes().stream().findAny().isEmpty();
|
||||
ChunkGenerator chunkGenerator = level.getChunkSource().getGenerator();
|
||||
boolean biomeReachable = chunkGenerator instanceof IrisModdedChunkGenerator irisGenerator
|
||||
&& irisGenerator.isNativeStructureReachable(holder);
|
||||
boolean hasPlacement = false;
|
||||
if (worldEnabled && selected && !suppressed && biomeReachable) {
|
||||
if (worldEnabled && selected && !suppressed && !biomeFilterEmpty && biomeReachable) {
|
||||
hasPlacement = !level.getChunkSource().getGeneratorState().getPlacementsForStructure(holder).isEmpty();
|
||||
}
|
||||
return classifyNativeAvailability(worldEnabled, selected, suppressed, biomeReachable, hasPlacement);
|
||||
return classifyNativeAvailability(
|
||||
worldEnabled, selected, suppressed, biomeFilterEmpty, biomeReachable, hasPlacement);
|
||||
}
|
||||
|
||||
static NativeStructureAvailability classifyNativeAvailability(boolean worldEnabled, boolean selected,
|
||||
boolean suppressed, boolean biomeReachable,
|
||||
boolean suppressed, boolean biomeFilterEmpty,
|
||||
boolean biomeReachable,
|
||||
boolean hasPlacement) {
|
||||
if (!worldEnabled) {
|
||||
return NativeStructureAvailability.WORLD_DISABLED;
|
||||
@@ -390,6 +438,9 @@ final class ModdedLocateCommands {
|
||||
if (suppressed) {
|
||||
return NativeStructureAvailability.IRIS_SUPPRESSED;
|
||||
}
|
||||
if (biomeFilterEmpty) {
|
||||
return NativeStructureAvailability.EMPTY_BIOME_FILTER;
|
||||
}
|
||||
if (!biomeReachable) {
|
||||
return NativeStructureAvailability.BIOME_UNREACHABLE;
|
||||
}
|
||||
@@ -399,15 +450,19 @@ final class ModdedLocateCommands {
|
||||
return NativeStructureAvailability.AVAILABLE;
|
||||
}
|
||||
|
||||
private static String nativeUnavailableMessage(String key, NativeStructureAvailability availability) {
|
||||
static String nativeUnavailableMessage(String key, NativeStructureAvailability availability) {
|
||||
return switch (availability) {
|
||||
case WORLD_DISABLED -> "Native structure generation is disabled for this world, so " + key + " cannot generate or be located.";
|
||||
case FILTERED -> NativeStructureGenerationPolicy.generationStatusMessage(
|
||||
key, NativeStructureGenerationStatus.DISABLED_BY_PACK);
|
||||
case IRIS_SUPPRESSED -> NativeStructureGenerationPolicy.generationStatusMessage(
|
||||
key, NativeStructureGenerationStatus.REPLACED_BY_IRIS);
|
||||
case EMPTY_BIOME_FILTER -> "Native structure " + key
|
||||
+ " has a biome tag or filter that resolves to zero registered biomes.";
|
||||
case BIOME_UNREACHABLE -> "Native structure " + key + " cannot generate because none of its required biomes are produced by this Iris pack.";
|
||||
case NO_PLACEMENT -> "Native structure " + key + " is registered, but its structure set has no placement supported by this dimension's generator state.";
|
||||
case NO_PLACEMENT -> "Native structure " + key
|
||||
+ " is registered and biome-compatible, but has no active positive-weight, "
|
||||
+ "positive-frequency structure-set placement in this dimension's generator state.";
|
||||
case AVAILABLE -> "Native structure " + key + " is available.";
|
||||
};
|
||||
}
|
||||
@@ -531,6 +586,7 @@ final class ModdedLocateCommands {
|
||||
WORLD_DISABLED,
|
||||
FILTERED,
|
||||
IRIS_SUPPRESSED,
|
||||
EMPTY_BIOME_FILTER,
|
||||
BIOME_UNREACHABLE,
|
||||
NO_PLACEMENT
|
||||
}
|
||||
|
||||
+204
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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.command;
|
||||
|
||||
import art.arcane.iris.engine.framework.Engine;
|
||||
import art.arcane.iris.engine.framework.IrisStructureLocator;
|
||||
import art.arcane.iris.engine.framework.NativeStructureGenerationPolicy;
|
||||
import art.arcane.iris.engine.framework.StructureReachability;
|
||||
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.engine.object.NativeStructureGenerationStatus;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
final class ModdedUnregisteredStructures {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger("Iris");
|
||||
|
||||
private ModdedUnregisteredStructures() {
|
||||
}
|
||||
|
||||
static int print(CommandSourceStack source) {
|
||||
ServerLevel level = source.getLevel();
|
||||
Engine engine = IrisModdedCommands.engineFor(level);
|
||||
if (engine == null) {
|
||||
IrisModdedCommands.fail(source,
|
||||
"This dimension is not generated by Iris, so it has no Iris structure eligibility report.");
|
||||
return 0;
|
||||
}
|
||||
try {
|
||||
List<ExcludedStructure> excluded = collect(source, level, engine);
|
||||
String dimension = level.dimension().identifier().toString();
|
||||
long unregistered = excluded.stream()
|
||||
.filter((ExcludedStructure entry) -> entry.status() == ReportStatus.UNREGISTERED)
|
||||
.count();
|
||||
long unplaced = excluded.stream()
|
||||
.filter((ExcludedStructure entry) -> entry.status() == ReportStatus.UNPLACED)
|
||||
.count();
|
||||
long hidden = excluded.size() - unregistered - unplaced;
|
||||
LOGGER.info("[Iris goto unregistered] {} structure candidate(s) excluded from /iris goto structure in {}",
|
||||
excluded.size(), dimension);
|
||||
for (ExcludedStructure entry : excluded) {
|
||||
LOGGER.info("[Iris goto unregistered] [{}] {} - {}",
|
||||
entry.status().label(), entry.key(), entry.reason());
|
||||
}
|
||||
LOGGER.info("[Iris goto unregistered] Inventory scope is the live registry, this pack's "
|
||||
+ "nativeStructures placements, and structureLoader editable resources. This is deterministic "
|
||||
+ "eligibility analysis and performs no chunk search; absent unmanaged datapack resources "
|
||||
+ "cannot be inferred after registry loading.");
|
||||
IrisModdedCommands.ok(source, "Iris wrote " + excluded.size() + " structure candidate(s) for "
|
||||
+ dimension + " to the server console (" + hidden + " excluded, "
|
||||
+ unregistered + " unregistered, " + unplaced + " unplaced).");
|
||||
return 1;
|
||||
} catch (Throwable error) {
|
||||
LOGGER.error("Iris failed to build the excluded structure report for {}",
|
||||
level.dimension().identifier(), error);
|
||||
IrisModdedCommands.fail(source,
|
||||
"Iris could not build the excluded structure report; see the server console.");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static List<ExcludedStructure> collect(CommandSourceStack source, ServerLevel level, Engine engine) {
|
||||
boolean nativeGenerationEnabled =
|
||||
source.getServer().getWorldGenSettings().options().generateStructures();
|
||||
Set<String> reachableNativeKeys = StructureReachability.reachableKeys(engine);
|
||||
Registry<Structure> registry = source.getServer().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
Map<String, ExcludedStructure> excluded = new TreeMap<>();
|
||||
Set<String> registeredKeys = new HashSet<>(registry.keySet().size());
|
||||
Set<String> eligibleRegisteredKeys = new HashSet<>(registry.keySet().size());
|
||||
for (Identifier identifier : registry.keySet()) {
|
||||
String key = identifier.toString();
|
||||
String normalizedKey = ModdedCommandSuggestions.normalizeKey(key);
|
||||
registeredKeys.add(normalizedKey);
|
||||
Optional<Holder.Reference<Structure>> holder = registry.get(identifier);
|
||||
if (holder.isEmpty()) {
|
||||
excluded.put(normalizedKey, new ExcludedStructure(ReportStatus.EXCLUDED,
|
||||
key, "The live structure registry contains this key but has no bound structure holder."));
|
||||
continue;
|
||||
}
|
||||
IrisNativeStructureDecision decision = NativeStructureGenerationPolicy.resolve(engine, key, false);
|
||||
boolean nativePlacement = IrisStructureLocator.hasNativePlacement(engine, key);
|
||||
boolean locatableNativePlacement = nativePlacement
|
||||
&& IrisStructureLocator.hasLocatableNativePlacement(engine, key);
|
||||
boolean locatableEditableReplacement = !nativePlacement
|
||||
&& decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS
|
||||
&& IrisStructureLocator.hasLocatableEditablePlacement(engine, key);
|
||||
boolean reachable = reachableNativeKeys.contains(normalizedKey);
|
||||
if (ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
decision, nativePlacement, locatableNativePlacement,
|
||||
locatableEditableReplacement, reachable, nativeGenerationEnabled)) {
|
||||
eligibleRegisteredKeys.add(normalizedKey);
|
||||
continue;
|
||||
}
|
||||
ModdedLocateCommands.NativeStructureAvailability availability =
|
||||
ModdedLocateCommands.nativeAvailability(source, level, engine, key, holder.get());
|
||||
String reason = ModdedLocateCommands.registeredStructureUnavailableMessage(
|
||||
key, availability, decision, nativePlacement, locatableNativePlacement,
|
||||
nativeGenerationEnabled, reachable);
|
||||
excluded.put(normalizedKey, new ExcludedStructure(ReportStatus.EXCLUDED, key, reason));
|
||||
}
|
||||
List<String> absentNativeKeys = missingConfiguredNativeKeys(
|
||||
IrisStructureLocator.placedKeys(engine), registeredKeys,
|
||||
(String key) -> IrisStructureLocator.hasNativePlacement(engine, key));
|
||||
for (String key : absentNativeKeys) {
|
||||
String normalizedKey = ModdedCommandSuggestions.normalizeKey(key);
|
||||
excluded.putIfAbsent(normalizedKey, new ExcludedStructure(ReportStatus.UNREGISTERED, key,
|
||||
"Configured by an Iris nativeStructures placement, but absent from the live structure registry; "
|
||||
+ "install or enable the datapack or mod that provides this key."));
|
||||
}
|
||||
if (engine.getData().getStructureLoader() != null) {
|
||||
for (String key : engine.getData().getStructureLoader().getPossibleKeys()) {
|
||||
String normalizedKey = ModdedCommandSuggestions.normalizeKey(key);
|
||||
if (normalizedKey.isEmpty() || eligibleRegisteredKeys.contains(normalizedKey)
|
||||
|| excluded.containsKey(normalizedKey)) {
|
||||
continue;
|
||||
}
|
||||
boolean registered = registeredKeys.contains(normalizedKey);
|
||||
boolean nativePlacement = IrisStructureLocator.hasNativePlacement(engine, key);
|
||||
boolean locatableEditable = IrisStructureLocator.hasLocatableEditablePlacement(engine, key);
|
||||
if (!registered && !nativePlacement && locatableEditable) {
|
||||
continue;
|
||||
}
|
||||
boolean configured = IrisStructureLocator.hasEditablePlacement(engine, key);
|
||||
excluded.putIfAbsent(normalizedKey, new ExcludedStructure(
|
||||
ReportStatus.UNPLACED, key.trim(), editableExclusionReason(configured)));
|
||||
}
|
||||
}
|
||||
return List.copyOf(excluded.values());
|
||||
}
|
||||
|
||||
static List<String> missingConfiguredNativeKeys(
|
||||
Collection<String> placedKeys, Set<String> normalizedRegisteredKeys,
|
||||
Predicate<String> nativePlacement) {
|
||||
Map<String, String> missing = new TreeMap<>();
|
||||
for (String key : placedKeys) {
|
||||
String normalizedKey = ModdedCommandSuggestions.normalizeKey(key);
|
||||
if (!normalizedKey.isEmpty()
|
||||
&& !normalizedRegisteredKeys.contains(normalizedKey)
|
||||
&& nativePlacement.test(key)) {
|
||||
missing.putIfAbsent(normalizedKey, key.trim());
|
||||
}
|
||||
}
|
||||
return List.copyOf(missing.values());
|
||||
}
|
||||
|
||||
static String editableExclusionReason(boolean configured) {
|
||||
if (!configured) {
|
||||
return "Editable Iris structure resource is loaded, but no biome, region, or dimension structure "
|
||||
+ "placement references it.";
|
||||
}
|
||||
return "Editable Iris structure resource is referenced by a placement, but every matching placement "
|
||||
+ "has non-positive density or a Y band outside this world's height range.";
|
||||
}
|
||||
|
||||
enum ReportStatus {
|
||||
EXCLUDED("excluded"),
|
||||
UNREGISTERED("unregistered"),
|
||||
UNPLACED("unplaced");
|
||||
|
||||
private final String label;
|
||||
|
||||
ReportStatus(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
String label() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
||||
record ExcludedStructure(ReportStatus status, String key, String reason) {
|
||||
}
|
||||
}
|
||||
+2
@@ -39,6 +39,7 @@ public class IrisModdedCommandParityTest {
|
||||
child(iris, "height");
|
||||
child(iris, "worlds");
|
||||
child(iris, "accesslist");
|
||||
child(child(iris, "goto"), "unregistered");
|
||||
|
||||
CommandNode<CommandSourceStack> edit = child(iris, "edit");
|
||||
child(edit, "b");
|
||||
@@ -75,6 +76,7 @@ public class IrisModdedCommandParityTest {
|
||||
assertTrue(ModdedCommandHelp.documents("studio", "pkg"));
|
||||
assertTrue(ModdedCommandHelp.documents("object", "we"));
|
||||
assertTrue(ModdedCommandHelp.documents("world", "mainworld"));
|
||||
assertTrue(ModdedCommandHelp.documents("goto", "unregistered"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+173
-14
@@ -1,5 +1,7 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.engine.object.IrisNativeStructureDecision;
|
||||
import art.arcane.iris.engine.object.NativeStructureGenerationStatus;
|
||||
import art.arcane.iris.nativegen.NativeStructureLocateResults;
|
||||
import com.mojang.datafixers.util.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -8,6 +10,8 @@ import org.junit.Test;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -49,7 +53,7 @@ public class IrisModdedStructureCommandTest {
|
||||
String source = source("ModdedLocateCommands.java");
|
||||
String suggestions = source("ModdedCommandSuggestions.java");
|
||||
|
||||
assertTrue(source.contains("IrisStructureLocator.isPlaced(engine, key)"));
|
||||
assertTrue(source.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(source.contains("registry.get(identifier)"));
|
||||
assertTrue(source.contains("getPlacementsForStructure(holder)"));
|
||||
assertTrue(source.contains("generator.findNearestMapStructure("));
|
||||
@@ -57,7 +61,7 @@ public class IrisModdedStructureCommandTest {
|
||||
assertTrue(source.contains("HolderSet.direct(target.holder())"));
|
||||
assertFalse(source.contains("NativeStructureLocateCapability"));
|
||||
assertTrue(source.contains("boolean teleported = player.teleportTo("));
|
||||
assertTrue(suggestions.contains("combineStructureKeys(irisKeys, nativeKeys)"));
|
||||
assertTrue(suggestions.contains("combineStructureKeys(unregisteredIrisKeys, nativeKeys)"));
|
||||
assertTrue(source.contains("irisGenerator.isNativeStructureReachable(holder)"));
|
||||
assertTrue(source.contains("LocateStatus.SEARCH_LIMIT_REACHED"));
|
||||
assertTrue(source.contains("IRIS_MODDED_COMMANDS_UNABLE_LOCATE_IRIS_PLACED_STRUCTURE_DENSITY_SEARCH_SAFETY_LIMIT_WAS"));
|
||||
@@ -68,6 +72,148 @@ public class IrisModdedStructureCommandTest {
|
||||
assertFalse(source.contains("at[2] + 8"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registeredStructureEligibilityMatchesGotoAndSuggestions() {
|
||||
IrisNativeStructureDecision nativeDecision = decision(NativeStructureGenerationStatus.GENERATE_NATIVE);
|
||||
IrisNativeStructureDecision replacementDecision = decision(
|
||||
NativeStructureGenerationStatus.REPLACED_BY_IRIS);
|
||||
IrisNativeStructureDecision disabledDecision = decision(
|
||||
NativeStructureGenerationStatus.DISABLED_BY_PACK);
|
||||
|
||||
assertTrue(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
nativeDecision, false, false, false, true, true));
|
||||
assertTrue(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
nativeDecision, true, true, false, false, true));
|
||||
assertFalse(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
nativeDecision, true, false, false, false, true));
|
||||
assertFalse(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
nativeDecision, true, true, false, true, false));
|
||||
assertTrue(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
replacementDecision, false, false, true, false, false));
|
||||
assertTrue(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
replacementDecision, true, true, false, false, true));
|
||||
assertFalse(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
replacementDecision, true, true, false, false, false));
|
||||
assertFalse(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
replacementDecision, false, false, false, true, true));
|
||||
assertFalse(ModdedCommandSuggestions.isEligibleRegisteredStructure(
|
||||
disabledDecision, true, true, true, true, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureSuggestionsDedupeAndSortPlacedAndNativeKeys() {
|
||||
List<String> suggestions = ModdedCommandSuggestions.combineStructureKeys(
|
||||
List.of("towns_and_towers:village_forest", "minecraft:village_plains",
|
||||
"towns_and_towers:village_forest", "MINECRAFT:VILLAGE_PLAINS"),
|
||||
List.of("minecraft:stronghold", "minecraft:village_plains"));
|
||||
|
||||
assertEquals(List.of("minecraft:stronghold", "minecraft:village_plains",
|
||||
"towns_and_towers:village_forest"), suggestions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureSuggestionsCannotReintroduceRegistryOrNativePlacementCollisions() {
|
||||
List<String> suggestions = ModdedCommandSuggestions.eligibleUnregisteredEditableKeys(
|
||||
List.of("iris:custom", "minecraft:disabled", "MINECRAFT:UNREACHABLE",
|
||||
"iris:native_collision"),
|
||||
Set.of("minecraft:disabled", "minecraft:unreachable"),
|
||||
(String key) -> key.equalsIgnoreCase("iris:native_collision"));
|
||||
|
||||
assertEquals(List.of("iris:custom"), suggestions);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisteredReportFindsOnlyConfiguredNativeKeysAbsentFromRegistry() {
|
||||
List<String> missing = ModdedUnregisteredStructures.missingConfiguredNativeKeys(
|
||||
List.of("iris:editable", "missing:native", "MISSING:NATIVE", "registered:native"),
|
||||
Set.of("registered:native"),
|
||||
(String key) -> key.equalsIgnoreCase("missing:native")
|
||||
|| key.equalsIgnoreCase("registered:native"));
|
||||
|
||||
assertEquals(List.of("missing:native"), missing);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisteredReportDistinguishesEveryNativeExclusionReason() {
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.WORLD_DISABLED,
|
||||
ModdedLocateCommands.classifyNativeAvailability(false, true, false, false, true, true));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.FILTERED,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, false, false, false, true, true));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.IRIS_SUPPRESSED,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, true, true, false, true, true));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.EMPTY_BIOME_FILTER,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, true, false, true, false, false));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.BIOME_UNREACHABLE,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, true, false, false, false, false));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.NO_PLACEMENT,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, true, false, false, true, false));
|
||||
assertEquals(ModdedLocateCommands.NativeStructureAvailability.AVAILABLE,
|
||||
ModdedLocateCommands.classifyNativeAvailability(true, true, false, false, true, true));
|
||||
|
||||
assertTrue(ModdedLocateCommands.nativeUnavailableMessage(
|
||||
"towns_and_towers:exclusive",
|
||||
ModdedLocateCommands.NativeStructureAvailability.EMPTY_BIOME_FILTER)
|
||||
.contains("resolves to zero registered biomes"));
|
||||
assertTrue(ModdedLocateCommands.nativeUnavailableMessage(
|
||||
"minecraft:village_plains",
|
||||
ModdedLocateCommands.NativeStructureAvailability.NO_PLACEMENT)
|
||||
.contains("no active positive-weight, positive-frequency structure-set placement"));
|
||||
String combined = ModdedLocateCommands.registeredStructureUnavailableMessage(
|
||||
"towns_and_towers:exclusive",
|
||||
ModdedLocateCommands.NativeStructureAvailability.EMPTY_BIOME_FILTER,
|
||||
decision(NativeStructureGenerationStatus.GENERATE_NATIVE),
|
||||
true, false, true, false);
|
||||
assertTrue(combined.contains("resolves to zero registered biomes"));
|
||||
assertTrue(combined.contains("matching Iris nativeStructures placement is also configured"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisteredReportExplainsEditablePlacementState() {
|
||||
assertTrue(ModdedUnregisteredStructures.editableExclusionReason(false)
|
||||
.contains("no biome, region, or dimension structure placement"));
|
||||
assertTrue(ModdedUnregisteredStructures.editableExclusionReason(true)
|
||||
.contains("non-positive density or a Y band outside"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void unregisteredCommandUsesGotoEligibilityAndPrintsToConsole() throws IOException {
|
||||
String command = source("ModdedUnregisteredStructures.java");
|
||||
String tree = source("ModdedCommandTree.java");
|
||||
|
||||
assertTrue(tree.contains("Commands.literal(\"unregistered\")"));
|
||||
assertTrue(tree.contains("ModdedUnregisteredStructures.print(context.getSource())"));
|
||||
assertTrue(command.contains("ModdedCommandSuggestions.isEligibleRegisteredStructure("));
|
||||
assertTrue(command.contains("ModdedLocateCommands.registeredStructureUnavailableMessage("));
|
||||
assertTrue(command.contains("engine.getData().getStructureLoader().getPossibleKeys()"));
|
||||
assertTrue(command.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(command.contains("LOGGER.info(\"[Iris goto unregistered] [{}] {} - {}\""));
|
||||
assertTrue(command.contains("UNREGISTERED(\"unregistered\")"));
|
||||
assertFalse(command.contains("DatapackIngestService"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void structureSuggestionsUseActiveLevelAvailability() throws IOException {
|
||||
String suggestions = source("ModdedCommandSuggestions.java");
|
||||
int methodStart = suggestions.indexOf("static CompletableFuture<Suggestions> suggestStructureKeys(");
|
||||
int methodEnd = suggestions.indexOf("static boolean isEligibleRegisteredStructure(", methodStart);
|
||||
String method = suggestions.substring(methodStart, methodEnd);
|
||||
|
||||
assertTrue(method.contains("ServerLevel level = source.getLevel()"));
|
||||
assertTrue(method.contains("Engine engine = IrisModdedCommands.engineFor(level)"));
|
||||
assertFalse(method.contains("IrisStructureLocator.locatableKeys(engine)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.locatableEditableKeys(engine)"));
|
||||
assertTrue(method.contains("StructureReachability.reachableKeys(engine)"));
|
||||
assertTrue(method.contains("NativeStructureGenerationPolicy.resolve(engine, key, false)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableNativePlacement(engine, key)"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, key)"));
|
||||
assertTrue(method.contains("reachableNativeKeys.contains(normalizeKey(key))"));
|
||||
assertTrue(method.contains("nativeGenerationEnabled"));
|
||||
assertTrue(method.contains("eligibleUnregisteredEditableKeys("));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasNativePlacement(engine, candidate)"));
|
||||
assertFalse(method.contains("NativeStructureGenerationKeys.active(level)"));
|
||||
assertFalse(method.contains("getPlacementsForStructure"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void generatorLocateUsesEveryIrisPlacedNativeStructure() throws IOException {
|
||||
String source = moddedSource("ModdedNativeStructureStage.java");
|
||||
@@ -111,20 +257,29 @@ public class IrisModdedStructureCommandTest {
|
||||
int methodEnd = source.indexOf("private static void locateIrisStructure(", methodStart);
|
||||
String method = source.substring(methodStart, methodEnd);
|
||||
int nativeResolution = method.indexOf("resolveNativeStructure(source, level, engine, key)");
|
||||
int genericIrisLookup = method.indexOf("IrisStructureLocator.isPlaced(engine, key)", nativeResolution);
|
||||
int policyResolution = method.indexOf("NativeStructureGenerationPolicy.resolve(engine, target.key(), false)", genericIrisLookup);
|
||||
int replacementCheck = method.indexOf(
|
||||
"decision.status() == NativeStructureGenerationStatus.REPLACED_BY_IRIS", policyResolution);
|
||||
int replacementLocate = method.indexOf("runNativeStructureLocate(source, level, player, target)",
|
||||
replacementCheck);
|
||||
int editableIrisLookup = method.indexOf(
|
||||
"IrisStructureLocator.hasLocatableEditablePlacement(engine, key)", nativeResolution);
|
||||
int policyResolution = method.indexOf(
|
||||
"NativeStructureGenerationPolicy.resolve(engine, target.key(), false)", editableIrisLookup);
|
||||
int eligibilityCheck = method.indexOf(
|
||||
"ModdedCommandSuggestions.isEligibleRegisteredStructure(", policyResolution);
|
||||
int replacementLocate = method.indexOf(
|
||||
"locateIrisStructure(source, level, engine, player, target.key())", eligibilityCheck);
|
||||
int nativeLocate = method.indexOf("runNativeStructureLocate(source, level, player, target)",
|
||||
replacementLocate);
|
||||
|
||||
assertTrue(nativeResolution >= 0);
|
||||
assertTrue(genericIrisLookup > nativeResolution);
|
||||
assertTrue(policyResolution > genericIrisLookup);
|
||||
assertTrue(replacementCheck > policyResolution);
|
||||
assertTrue(replacementLocate > replacementCheck);
|
||||
assertTrue(method.contains("!IrisStructureLocator.hasNativePlacement(engine, target.key())"));
|
||||
assertTrue(method.contains("&& target.availability() != NativeStructureAvailability.AVAILABLE"));
|
||||
assertTrue(editableIrisLookup > nativeResolution);
|
||||
assertTrue(policyResolution > editableIrisLookup);
|
||||
assertTrue(eligibilityCheck > policyResolution);
|
||||
assertTrue(replacementLocate > eligibilityCheck);
|
||||
assertTrue(nativeLocate > replacementLocate);
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableNativePlacement(engine, target.key())"));
|
||||
assertTrue(method.contains("IrisStructureLocator.hasLocatableEditablePlacement(engine, target.key())"));
|
||||
assertTrue(method.contains("!IrisStructureLocator.hasNativePlacement(engine, key)"));
|
||||
assertTrue(method.contains("StructureReachability.isReachable(engine, target.key())"));
|
||||
assertTrue(method.contains("getWorldGenSettings().options().generateStructures()"));
|
||||
assertFalse(method.contains("IrisStructureLocator.isPlaced(engine, key)"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -175,4 +330,8 @@ public class IrisModdedStructureCommandTest {
|
||||
.resolve("../modded-common/src/main/java")
|
||||
.normalize();
|
||||
}
|
||||
|
||||
private IrisNativeStructureDecision decision(NativeStructureGenerationStatus status) {
|
||||
return new IrisNativeStructureDecision(status, 0, null, false, false, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user