mirror of
https://github.com/VolmitSoftware/Iris.git
synced 2026-10-26 05:50:39 +00:00
Port the v3 map as iris std map
- iris std map opens the v3 map window; noise, palettes, objects, procedural and image maps are views in it - Rivers view draws v4 hydrology, with an empty state when the pack has rivers off - 3D views fall back to software when LWJGL isn't on the classpath; modded jars use the game's LWJGL - FlatLaf and LWJGL join core; v4's separate studio windows are removed
This commit is contained in:
1 parent
2d211cf106
commit
29cca99947
214 files changed
+27582
-4368
No files matched your search
@@ -60,6 +60,7 @@ import art.arcane.iris.integration.MultiverseCoreLink;
|
||||
import art.arcane.iris.platform.bukkit.nms.INMS;
|
||||
import art.arcane.volmlib.nativelib.terrain.ServerShutdownBoundary;
|
||||
import art.arcane.iris.studio.view.BukkitGuiHost;
|
||||
import art.arcane.iris.studio.view.GuiHost;
|
||||
import art.arcane.iris.studio.view.PregeneratorJob;
|
||||
import art.arcane.iris.platform.bukkit.BoardSVC;
|
||||
import art.arcane.iris.command.CommandSVC;
|
||||
@@ -988,6 +989,7 @@ public class Iris extends VolmitPlugin implements Listener, ReloadAware {
|
||||
}
|
||||
|
||||
public void onDisable() {
|
||||
GuiHost.shutdown();
|
||||
preservePendingBlockDrops();
|
||||
papiLifecycleActive = false;
|
||||
if (updateNotifier != null) {
|
||||
|
||||
@@ -21,10 +21,10 @@ package art.arcane.iris.command;
|
||||
import art.arcane.iris.Iris;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.configuration.IrisSettings;
|
||||
import art.arcane.iris.studio.map.MapWindow;
|
||||
import art.arcane.iris.studio.map.NoiseExplorerGUI;
|
||||
import art.arcane.iris.studio.map.PaletteExplorerStart;
|
||||
import art.arcane.iris.studio.view.GuiHost;
|
||||
import art.arcane.iris.studio.view.ImageMapStudioGUI;
|
||||
import art.arcane.iris.studio.view.NoiseExplorerGUI;
|
||||
import art.arcane.iris.studio.view.VisionGUI;
|
||||
import art.arcane.iris.pack.loading.IrisData;
|
||||
import art.arcane.iris.studio.workspace.IrisProject;
|
||||
import art.arcane.iris.studio.workspace.IrisCodeWorkspace;
|
||||
@@ -255,15 +255,19 @@ public class CommandStudio implements DirectorExecutor {
|
||||
long seed
|
||||
) {
|
||||
if (noGUI()) return;
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_NOISE_EXPLORER));
|
||||
|
||||
if (generator == null) {
|
||||
NoiseExplorerGUI.launch();
|
||||
Engine playerEngine = engine();
|
||||
Engine engine = playerEngine != null ? playerEngine : GuiHost.get().findActiveEngine();
|
||||
if (generator != null) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_NOISE_EXPLORER));
|
||||
NoiseExplorerGUI.launchGeneratorKey(engine, generator.getLoadKey(), generator, seed);
|
||||
return;
|
||||
}
|
||||
|
||||
String generatorKey = generator.getLoadKey();
|
||||
NoiseExplorerGUI.launchGeneratorKey(generatorKey, generator, seed);
|
||||
if (engine == null) {
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_YOU_NEED_BE_SPECIFY_IRIS_GENERATED_WORLD));
|
||||
return;
|
||||
}
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_NOISE_EXPLORER));
|
||||
MapWindow.openNoise(playerEngine != null ? mapStartIn(player().getWorld()) : mapStartWithoutWorld(engine));
|
||||
}
|
||||
|
||||
@Director(description = "Open the image-map studio (External GUI)", descriptionKey = "iris.director.commandstudio.director.open_image_map_studio_external_gui", aliases = {"imap"})
|
||||
@@ -279,8 +283,7 @@ public class CommandStudio implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
Engine activeEngine = IrisToolbelt.access(world).getEngine();
|
||||
ImageMapStudioGUI.launch(activeEngine);
|
||||
MapWindow.openImageMaps(mapStartIn(world));
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_IMAGE_MAP_STUDIO));
|
||||
}
|
||||
|
||||
@@ -420,11 +423,27 @@ public class CommandStudio implements DirectorExecutor {
|
||||
return;
|
||||
}
|
||||
|
||||
UUID openerId = sender().isPlayer() ? player().getUniqueId() : null;
|
||||
VisionGUI.launch(IrisToolbelt.access(world).getEngine(), openerId);
|
||||
MapWindow.openMap(mapStartIn(world));
|
||||
sender().sendMessage(IrisLanguage.text(BukkitCommandMessagesExtended.COMMAND_STUDIO_OPENING_MAP));
|
||||
}
|
||||
|
||||
// The map opens where the player stands when they are in that world, otherwise at the world origin.
|
||||
private PaletteExplorerStart mapStartIn(World world) {
|
||||
Location center = sender().isPlayer() && player().getWorld().equals(world) ? player().getLocation() : null;
|
||||
return new PaletteExplorerStart(
|
||||
IrisToolbelt.access(world).getEngine(),
|
||||
world.getUID(),
|
||||
sender().isPlayer() ? player().getUniqueId() : null,
|
||||
null,
|
||||
center == null ? 0D : center.getX(),
|
||||
center == null ? 0D : center.getZ()
|
||||
);
|
||||
}
|
||||
|
||||
private PaletteExplorerStart mapStartWithoutWorld(Engine engine) {
|
||||
return new PaletteExplorerStart(engine, null, sender().isPlayer() ? player().getUniqueId() : null, null, 0D, 0D);
|
||||
}
|
||||
|
||||
@Director(description = "Profiles the performance of a dimension", descriptionKey = "iris.director.commandstudio.director.profiles_performance_dimension", origin = DirectorOrigin.PLAYER)
|
||||
public void profile(
|
||||
@Param(description = "The dimension to profile", descriptionKey = "iris.director.commandstudio.param.dimension_profile", contextual = true, contextualOverride = true, defaultValue = "default", customHandler = DimensionHandler.class)
|
||||
|
||||
+42
-6
@@ -23,6 +23,8 @@ import art.arcane.iris.world.event.IrisEngineHotloadEvent;
|
||||
import art.arcane.iris.world.IrisToolbelt;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.platform.generation.PlatformChunkGenerator;
|
||||
import art.arcane.iris.studio.StudioSVC;
|
||||
import art.arcane.iris.studio.workspace.IrisProject;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.event.EventHandler;
|
||||
@@ -40,16 +42,21 @@ public final class BukkitGuiHost implements GuiHost.Provider {
|
||||
GuiHost.set(new BukkitGuiHost());
|
||||
}
|
||||
|
||||
/**
|
||||
* The engine of the open studio project, which reads the pack folder being edited, or else the first
|
||||
* Iris world. A normal Iris world runs on its own copy of the pack, made when the world was created.
|
||||
*/
|
||||
@Override
|
||||
public Engine findActiveEngine() {
|
||||
Engine studioEngine = findStudioEngine();
|
||||
if (studioEngine != null) {
|
||||
return studioEngine;
|
||||
}
|
||||
try {
|
||||
for (World world : new ArrayList<>(Bukkit.getWorlds())) {
|
||||
try {
|
||||
PlatformChunkGenerator access = IrisToolbelt.access(world);
|
||||
if (access != null && access.getEngine() != null && !access.getEngine().isClosed()) {
|
||||
return access.getEngine();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
Engine engine = engineOf(world);
|
||||
if (engine != null) {
|
||||
return engine;
|
||||
}
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
@@ -57,6 +64,35 @@ public final class BukkitGuiHost implements GuiHost.Provider {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Engine findEngine(UUID worldId) {
|
||||
World world = worldId == null ? null : Bukkit.getWorld(worldId);
|
||||
return world == null ? null : engineOf(world);
|
||||
}
|
||||
|
||||
private static Engine findStudioEngine() {
|
||||
try {
|
||||
StudioSVC studio = Iris.service(StudioSVC.class);
|
||||
IrisProject project = studio == null || !studio.isProjectOpen() ? null : studio.getActiveProject();
|
||||
PlatformChunkGenerator provider = project == null ? null : project.getActiveProvider();
|
||||
Engine engine = provider == null ? null : provider.getEngine();
|
||||
return engine == null || engine.isClosed() ? null : engine;
|
||||
} catch (Throwable ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static Engine engineOf(World world) {
|
||||
try {
|
||||
PlatformChunkGenerator access = IrisToolbelt.access(world);
|
||||
if (access != null && access.getEngine() != null && !access.getEngine().isClosed()) {
|
||||
return access.getEngine();
|
||||
}
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerHotloadHook(Runnable onHotload) {
|
||||
Listener listener = new HotloadListener(onHotload);
|
||||
|
||||
+41
-30
@@ -18,23 +18,19 @@
|
||||
|
||||
package art.arcane.iris.studio.view;
|
||||
|
||||
import art.arcane.volmlib.nativelib.view.WorldMarker;
|
||||
|
||||
import art.arcane.iris.generation.runtime.IrisComplex;
|
||||
import art.arcane.iris.generation.runtime.Engine;
|
||||
import art.arcane.iris.studio.render.RenderType;
|
||||
import art.arcane.iris.world.IrisWorld;
|
||||
import art.arcane.iris.platform.bukkit.BukkitPlatform;
|
||||
import art.arcane.iris.platform.bukkit.BukkitWorldBinding;
|
||||
import art.arcane.iris.spi.IrisLogging;
|
||||
import art.arcane.iris.world.task.J;
|
||||
import art.arcane.volmlib.util.format.Form;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -56,7 +52,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
private final AtomicBoolean playerRefreshQueued = new AtomicBoolean();
|
||||
private final AtomicLong teleportSequence = new AtomicLong();
|
||||
private final AtomicReference<VisionTeleportRequest> latestTeleport = new AtomicReference<>();
|
||||
private volatile List<WorldMarker> playerMarkers = List.of();
|
||||
private volatile List<GuiMarker> playerMarkers = List.of();
|
||||
|
||||
public BukkitVisionOverlay(Engine engine, UUID openerId) {
|
||||
this.engine = engine;
|
||||
@@ -68,7 +64,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
* built by a server thread.
|
||||
*/
|
||||
@Override
|
||||
public List<WorldMarker> players() {
|
||||
public List<GuiMarker> players() {
|
||||
queuePlayerRefresh();
|
||||
return playerMarkers;
|
||||
}
|
||||
@@ -80,10 +76,10 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
|
||||
boolean scheduled = J.runGlobal(() -> {
|
||||
try {
|
||||
List<WorldMarker> markers = new ArrayList<>();
|
||||
List<GuiMarker> markers = new ArrayList<>();
|
||||
for (Player player : BukkitWorldBinding.players(engine.getWorld())) {
|
||||
Location at = player.getLocation();
|
||||
markers.add(WorldMarker.player(player.getName(), at.getX(), at.getZ()));
|
||||
markers.add(GuiMarker.player(player.getName(), at.getX(), at.getZ(), at.getYaw()));
|
||||
}
|
||||
playerMarkers = List.copyOf(markers);
|
||||
} finally {
|
||||
@@ -97,7 +93,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestEntities(Consumer<List<WorldMarker>> sink) {
|
||||
public void requestEntities(Consumer<List<GuiMarker>> sink) {
|
||||
J.runGlobal(() -> {
|
||||
IrisWorld target = engine.getWorld();
|
||||
World world = BukkitWorldBinding.world(target);
|
||||
@@ -118,7 +114,7 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
return;
|
||||
}
|
||||
|
||||
List<WorldMarker> collected = Collections.synchronizedList(new ArrayList<>(living.size()));
|
||||
List<GuiMarker> collected = Collections.synchronizedList(new ArrayList<>(living.size()));
|
||||
AtomicInteger pending = new AtomicInteger(living.size());
|
||||
Runnable complete = () -> {
|
||||
if (pending.decrementAndGet() == 0) {
|
||||
@@ -144,22 +140,22 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
});
|
||||
}
|
||||
|
||||
private WorldMarker marker(LivingEntity entity, Location at) {
|
||||
private GuiMarker marker(LivingEntity entity, Location at) {
|
||||
String label = Form.capitalizeWords(entity.getType().name().toLowerCase(Locale.ROOT).replaceAll("\\Q_\\E", " "));
|
||||
double maxHealth = 0;
|
||||
try {
|
||||
maxHealth = entity.getAttribute(MAX_HEALTH).getValue();
|
||||
} catch (Throwable ignored) {
|
||||
}
|
||||
return WorldMarker.entity(label, at.getX(), at.getY(), at.getZ(), entity.getHealth(), maxHealth);
|
||||
return GuiMarker.entity(label, at.getX(), at.getY(), at.getZ(), entity.getHealth(), maxHealth);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void teleport(double worldX, double worldZ) {
|
||||
VisionTeleportRequest request = new VisionTeleportRequest(
|
||||
teleportSequence.incrementAndGet(),
|
||||
VisionGUI.floorWorldCoordinate(worldX),
|
||||
VisionGUI.floorWorldCoordinate(worldZ));
|
||||
(int) StrictMath.floor(worldX),
|
||||
(int) StrictMath.floor(worldZ));
|
||||
latestTeleport.set(request);
|
||||
startTeleport(request);
|
||||
}
|
||||
@@ -212,6 +208,36 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestOpenerPosition(Consumer<OpenerPosition> sink) {
|
||||
if (openerId == null) {
|
||||
sink.accept(OpenerPosition.OFFLINE);
|
||||
return;
|
||||
}
|
||||
boolean scheduled = J.runGlobal(() -> {
|
||||
Player player = Bukkit.getPlayer(openerId);
|
||||
if (player == null) {
|
||||
sink.accept(OpenerPosition.OFFLINE);
|
||||
return;
|
||||
}
|
||||
World world = BukkitWorldBinding.world(engine.getWorld());
|
||||
if (!J.runEntity(player, () -> sink.accept(positionOf(player, world)))) {
|
||||
sink.accept(OpenerPosition.OFFLINE);
|
||||
}
|
||||
});
|
||||
if (!scheduled) {
|
||||
sink.accept(OpenerPosition.OFFLINE);
|
||||
}
|
||||
}
|
||||
|
||||
private static OpenerPosition positionOf(Player player, World world) {
|
||||
if (world == null || player.getWorld() != world) {
|
||||
return OpenerPosition.IN_OTHER_WORLD;
|
||||
}
|
||||
Location at = player.getLocation();
|
||||
return OpenerPosition.inWorld(at.getX(), at.getY(), at.getZ());
|
||||
}
|
||||
|
||||
private Player selectPlayer(List<Player> players) {
|
||||
if (openerId == null) {
|
||||
return players.isEmpty() ? null : players.get(0);
|
||||
@@ -316,21 +342,6 @@ public final class BukkitVisionOverlay implements GuiOverlay {
|
||||
+ blockX + "," + blockZ + ".", failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String openInEditor(double worldX, double worldZ, RenderType type) {
|
||||
IrisComplex complex = engine.getComplex();
|
||||
File file = switch (type) {
|
||||
case BIOME, LAYER_LOAD, DECORATOR_LOAD, OBJECT_LOAD, HEIGHT, RIVER ->
|
||||
complex.getTrueBiomeStream().get(worldX, worldZ).openInVSCode();
|
||||
case BIOME_LAND -> complex.getLandBiomeStream().get(worldX, worldZ).openInVSCode();
|
||||
case BIOME_SEA -> complex.getSeaBiomeStream().get(worldX, worldZ).openInVSCode();
|
||||
case REGION -> complex.getRegionStream().get(worldX, worldZ).openInVSCode();
|
||||
case CAVE_LAND -> complex.getCaveBiomeStream().get(worldX, worldZ).openInVSCode();
|
||||
default -> null;
|
||||
};
|
||||
return file == null ? null : file.getName();
|
||||
}
|
||||
|
||||
private static final class VisionTeleportRequest {
|
||||
private final long sequence;
|
||||
private final int blockX;
|
||||
|
||||
Reference in new issue
Block a user