mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-25 13:30:08 +00:00
Cleanup
This commit is contained in:
1 parent
a6149b27c9
commit
65ae3f1b45
18 files changed
+1664
-86
No files matched your search
@@ -74,7 +74,7 @@ import java.util.Set;
|
||||
|
||||
@Director(name = "find", origin = DirectorOrigin.PLAYER, description = "Iris Find commands", descriptionKey = "iris.director.commandfind.director.iris_find_commands", aliases = "goto")
|
||||
public class CommandFind implements DirectorExecutor {
|
||||
@Director(description = "Find a biome", descriptionKey = "iris.director.commandfind.director.find_biome")
|
||||
@Director(description = "Find a biome", sync = true, descriptionKey = "iris.director.commandfind.director.find_biome")
|
||||
public void biome(
|
||||
@Param(description = "The biome to look for", descriptionKey = "iris.director.commandfind.param.biome_look", customHandler = ReachableBiomeHandler.class)
|
||||
IrisBiome biome,
|
||||
|
||||
+92
-7
@@ -31,6 +31,9 @@ import art.arcane.iris.generation.runtime.GenerationSessionException;
|
||||
import art.arcane.iris.generation.runtime.GenerationSessionLease;
|
||||
import art.arcane.iris.structure.placement.IrisStructureLocator;
|
||||
import art.arcane.iris.generation.locator.Locator;
|
||||
import art.arcane.iris.generation.locator.BiomeLocator;
|
||||
import art.arcane.iris.generation.subterrain.SubterrainPosition;
|
||||
import art.arcane.iris.world.history.SavedBiomeRuntime;
|
||||
import art.arcane.iris.structure.nativegen.NativeStructureGenerationPolicy;
|
||||
import art.arcane.iris.structure.placement.StructureReachability;
|
||||
import art.arcane.iris.generation.runtime.WrongEngineBroException;
|
||||
@@ -82,7 +85,7 @@ final class ModdedLocateCommands {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_UNKNOWN_BIOME_2, MessageArgument.untrusted("key", key)));
|
||||
return 0;
|
||||
}
|
||||
locate(source, level, engine, player, Locator.surfaceBiome(biome.getLoadKey()), "biome " + biome.getLoadKey());
|
||||
locate(source, level, engine, player, BiomeLocator.forBiome(engine, biome.getLoadKey(), player.blockY()), "biome " + biome.getLoadKey());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -545,12 +548,12 @@ final class ModdedLocateCommands {
|
||||
previous.cancel(true);
|
||||
}
|
||||
search.whenComplete((Position2 at, Throwable error) -> completeLocate(
|
||||
source, level, engine, player, label, server, playerId, search, at, error));
|
||||
source, level, engine, player, label, server, playerId, search, locator, at, error));
|
||||
}
|
||||
|
||||
private static void completeLocate(NativeCommandSource source, NativeWorld level, Engine engine,
|
||||
NativeProtocolPlayer player, String label, NativeModdedServer server, UUID playerId,
|
||||
CompletableFuture<Position2> search, Position2 at, Throwable error) {
|
||||
CompletableFuture<Position2> search, Locator<?> locator, Position2 at, Throwable error) {
|
||||
if (ACTIVE_LOCATE_REQUESTS.get(playerId) != search) {
|
||||
return;
|
||||
}
|
||||
@@ -576,15 +579,77 @@ final class ModdedLocateCommands {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (locator instanceof BiomeLocator caveLocator) {
|
||||
prepareCaveLocate(new CaveLocateRequest(source, level, engine, player, label, server, playerId,
|
||||
search, caveLocator, at));
|
||||
return;
|
||||
}
|
||||
server.execute(() -> {
|
||||
if (ACTIVE_LOCATE_REQUESTS.remove(playerId, search)) {
|
||||
teleportToLocateResult(source, level, engine, player, label, at);
|
||||
teleportToLocateResult(source, level, engine, player, label, locator, at, Optional.empty());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void teleportToLocateResult(NativeCommandSource source, NativeWorld level, Engine engine,
|
||||
NativeProtocolPlayer player, String label, Position2 at) {
|
||||
private static void prepareCaveLocate(CaveLocateRequest request) {
|
||||
CompletableFuture.supplyAsync(() -> resolveCavePosition(request))
|
||||
.whenComplete((target, error) -> request.server().execute(() -> loadCaveDestination(request, target, error)));
|
||||
}
|
||||
|
||||
private static SubterrainPosition resolveCavePosition(CaveLocateRequest request) {
|
||||
try (GenerationSessionLease lease = request.engine().acquireGenerationLease("modded_cave_position");
|
||||
IrisContext.Scope ignored = IrisContext.open(request.engine(), lease.sessionId(), null)) {
|
||||
return request.locator().position(request.engine(), request.at());
|
||||
} catch (GenerationSessionException error) {
|
||||
throw new CompletionException(error);
|
||||
}
|
||||
}
|
||||
|
||||
private static void loadCaveDestination(CaveLocateRequest request, SubterrainPosition target, Throwable error) {
|
||||
if (ACTIVE_LOCATE_REQUESTS.get(request.playerId()) != request.search()) {
|
||||
return;
|
||||
}
|
||||
if (error != null) {
|
||||
failCaveLocate(request, error);
|
||||
return;
|
||||
}
|
||||
if (target == null || !request.player().connected() || !request.player().inWorld(request.level())) {
|
||||
if (ACTIVE_LOCATE_REQUESTS.remove(request.playerId(), request.search())) {
|
||||
IrisModdedCommands.fail(request.source(), "The cave destination is no longer available.");
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
request.level().getBlock(target.x(), target.y(), target.z());
|
||||
request.locator().prepareRead(request.engine(), new Position2(target.x() >> 4, target.z() >> 4))
|
||||
.whenComplete((read, failure) -> request.server().execute(() -> finishCaveLocate(request, target, read, failure)));
|
||||
} catch (RuntimeException failure) {
|
||||
failCaveLocate(request, failure);
|
||||
}
|
||||
}
|
||||
|
||||
private static void finishCaveLocate(CaveLocateRequest request, SubterrainPosition target,
|
||||
Optional<SavedBiomeRuntime.ReadSession> read, Throwable error) {
|
||||
if (error != null) {
|
||||
failCaveLocate(request, error);
|
||||
return;
|
||||
}
|
||||
if (ACTIVE_LOCATE_REQUESTS.remove(request.playerId(), request.search())) {
|
||||
teleportToLocateResult(request.source(), request.level(), request.engine(), request.player(),
|
||||
request.label(), request.locator(), request.at(), Optional.of(new CaveDestination(target, read)));
|
||||
}
|
||||
}
|
||||
|
||||
private static void failCaveLocate(CaveLocateRequest request, Throwable error) {
|
||||
ModdedIrisLog.error("Iris cave locate failed for {}", request.label(), error);
|
||||
if (ACTIVE_LOCATE_REQUESTS.remove(request.playerId(), request.search())) {
|
||||
IrisModdedCommands.fail(request.source(), "Could not prepare the cave destination. See the server log for details.");
|
||||
}
|
||||
}
|
||||
|
||||
static void teleportToLocateResult(NativeCommandSource source, NativeWorld level, Engine engine,
|
||||
NativeProtocolPlayer player, String label, Locator<?> locator, Position2 at,
|
||||
Optional<CaveDestination> caveDestination) {
|
||||
// Same liveness guards the structure completion path has: the search can take up to
|
||||
// two minutes, and the captured NativeProtocolPlayer may be gone or elsewhere by then.
|
||||
if (!player.connected()) {
|
||||
@@ -600,6 +665,17 @@ final class ModdedLocateCommands {
|
||||
try (GenerationSessionLease lease = engine.acquireGenerationLease("modded_locator_teleport");
|
||||
IrisContext.Scope ignored = IrisContext.open(engine, lease.sessionId(), null)) {
|
||||
int blockY = engine.getMinHeight() + engine.getHeight(blockX, blockZ, false) + 2;
|
||||
if (locator instanceof BiomeLocator caveLocator) {
|
||||
CaveDestination prepared = caveDestination.orElseThrow();
|
||||
SubterrainPosition landing = caveLocator.landing(engine, level, prepared.target(), prepared.read());
|
||||
if (landing == null) {
|
||||
IrisModdedCommands.fail(source, "No safe cave landing found for " + label + ".");
|
||||
return;
|
||||
}
|
||||
blockX = landing.x();
|
||||
blockY = landing.y();
|
||||
blockZ = landing.z();
|
||||
}
|
||||
boolean teleported = player.teleport(level, blockX + 0.5D, blockY, blockZ + 0.5D);
|
||||
if (!teleported) {
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(
|
||||
@@ -611,7 +687,8 @@ final class ModdedLocateCommands {
|
||||
return;
|
||||
}
|
||||
IrisModdedCommands.ok(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_TELEPORTED_AT_2, MessageArgument.untrusted("label", label), MessageArgument.untrusted("blockX", blockX), MessageArgument.untrusted("blockY", blockY), MessageArgument.untrusted("blockZ", blockZ)));
|
||||
} catch (GenerationSessionException e) {
|
||||
} catch (GenerationSessionException | RuntimeException e) {
|
||||
ModdedIrisLog.error("Iris locate teleport failed for {}", label, e);
|
||||
IrisModdedCommands.fail(source, IrisLanguage.plain(ModdedCommandMessages.IRIS_MODDED_COMMANDS_ENGINE_CHANGED_WHILE_LOCATING_TRY_AGAIN, MessageArgument.untrusted("label", label)));
|
||||
}
|
||||
}
|
||||
@@ -635,6 +712,14 @@ final class ModdedLocateCommands {
|
||||
NO_PLACEMENT
|
||||
}
|
||||
|
||||
record CaveDestination(SubterrainPosition target, Optional<SavedBiomeRuntime.ReadSession> read) {
|
||||
}
|
||||
|
||||
private record CaveLocateRequest(NativeCommandSource source, NativeWorld level, Engine engine,
|
||||
NativeProtocolPlayer player, String label, NativeModdedServer server,
|
||||
UUID playerId, CompletableFuture<Position2> search, BiomeLocator locator, Position2 at) {
|
||||
}
|
||||
|
||||
private record NativeStructureTarget(String key, NativeStructureQueries.Reference holder,
|
||||
NativeStructureAvailability availability) {
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
package art.arcane.iris.modded.command;
|
||||
|
||||
import art.arcane.iris.generation.context.IrisContext;
|
||||
import art.arcane.iris.generation.locator.BiomeLocator;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.generation.runtime.GenerationSessionLease;
|
||||
import art.arcane.iris.generation.subterrain.SubterrainPosition;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeCommandSource;
|
||||
import art.arcane.volmlib.nativelib.minecraft26_2.modded.NativeProtocolPlayer;
|
||||
import art.arcane.volmlib.nativelib.terrain.NativeWorld;
|
||||
import art.arcane.volmlib.util.math.Position2;
|
||||
import org.junit.Test;
|
||||
import org.mockito.MockedStatic;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyDouble;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class ModdedCaveLocateTest {
|
||||
@Test
|
||||
public void caveTeleportUsesValidatedUndergroundPosition() throws Exception {
|
||||
Fixture fixture = new Fixture();
|
||||
when(fixture.player.teleport(fixture.world, 8.5, -42, 8.5)).thenReturn(true);
|
||||
try (MockedStatic<IrisModdedCommands> commands = mockStatic(IrisModdedCommands.class);
|
||||
MockedStatic<IrisContext> context = mockStatic(IrisContext.class)) {
|
||||
fixture.context(context);
|
||||
fixture.teleport();
|
||||
verify(fixture.player).teleport(fixture.world, 8.5, -42, 8.5);
|
||||
commands.verify(() -> IrisModdedCommands.ok(eq(fixture.source), anyString()));
|
||||
commands.verify(() -> IrisModdedCommands.fail(eq(fixture.source), anyString()), never());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void failedTeleportNeverReportsSuccess() throws Exception {
|
||||
Fixture fixture = new Fixture();
|
||||
try (MockedStatic<IrisModdedCommands> commands = mockStatic(IrisModdedCommands.class);
|
||||
MockedStatic<IrisContext> context = mockStatic(IrisContext.class)) {
|
||||
fixture.context(context);
|
||||
fixture.teleport();
|
||||
commands.verify(() -> IrisModdedCommands.fail(eq(fixture.source), anyString()));
|
||||
commands.verify(() -> IrisModdedCommands.ok(eq(fixture.source), anyString()), never());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worldChangeCancelsBeforeCaveLookupOrTeleport() throws Exception {
|
||||
Fixture fixture = new Fixture();
|
||||
when(fixture.player.inWorld(fixture.world)).thenReturn(false);
|
||||
try (MockedStatic<IrisModdedCommands> commands = mockStatic(IrisModdedCommands.class)) {
|
||||
fixture.teleport();
|
||||
verifyNoInteractions(fixture.locator);
|
||||
verify(fixture.player, never()).teleport(any(), anyDouble(), anyDouble(), anyDouble());
|
||||
commands.verify(() -> IrisModdedCommands.fail(eq(fixture.source), anyString()));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class Fixture {
|
||||
private final NativeCommandSource source = mock(NativeCommandSource.class);
|
||||
private final NativeWorld world = mock(NativeWorld.class);
|
||||
private final NativeProtocolPlayer player = mock(NativeProtocolPlayer.class);
|
||||
private final Engine engine = mock(Engine.class);
|
||||
private final BiomeLocator locator = mock(BiomeLocator.class);
|
||||
|
||||
private Fixture() throws Exception {
|
||||
when(player.connected()).thenReturn(true);
|
||||
when(player.inWorld(world)).thenReturn(true);
|
||||
when(engine.acquireGenerationLease("modded_locator_teleport")).thenReturn(mock(GenerationSessionLease.class));
|
||||
SubterrainPosition target = new SubterrainPosition(8, -40, 8);
|
||||
when(locator.position(engine, new Position2(0, 0))).thenReturn(target);
|
||||
when(locator.landing(engine, world, target, Optional.empty())).thenReturn(new SubterrainPosition(8, -42, 8));
|
||||
}
|
||||
|
||||
private void context(MockedStatic<IrisContext> context) {
|
||||
context.when(() -> IrisContext.open(eq(engine), anyLong(), any())).thenReturn(mock(IrisContext.Scope.class));
|
||||
}
|
||||
|
||||
private void teleport() {
|
||||
ModdedLocateCommands.teleportToLocateResult(source, world, engine, player, "biome deep", locator,
|
||||
new Position2(0, 0), Optional.of(new ModdedLocateCommands.CaveDestination(
|
||||
new SubterrainPosition(8, -40, 8), Optional.empty())));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user