diff --git a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java index 59e50ae70..7b0f3c1dd 100644 --- a/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java +++ b/core/src/main/java/com/volmit/iris/core/commands/CommandDeveloper.java @@ -24,8 +24,11 @@ import com.volmit.iris.core.tools.IrisPackBenchmarking; import com.volmit.iris.core.tools.IrisToolbelt; import com.volmit.iris.core.tools.IrisWorldDump; import com.volmit.iris.engine.framework.Engine; +import com.volmit.iris.engine.framework.EnginePlayer; import com.volmit.iris.engine.object.IrisDimension; import com.volmit.iris.engine.service.EngineStatusSVC; +import com.volmit.iris.util.collection.KList; +import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.decree.DecreeExecutor; import com.volmit.iris.util.decree.DecreeOrigin; import com.volmit.iris.util.decree.annotations.Decree; @@ -198,6 +201,34 @@ public class CommandDeveloper implements DecreeExecutor { } } + @Decree(description = "All players in iris worlds") + public void getPlayers() { + KList IrisWorlds = new KList<>(); + for (World w : Bukkit.getServer().getWorlds()) { + if(IrisToolbelt.isIrisWorld(w)) { + IrisWorlds.add(w); + } + } + + if (sender().isPlayer()) { + sender().sendMessage(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + sender().sendMessage(C.IRIS + "- " + IrisWorld.getName() + C.GRAY + ", " + IrisToolbelt.access(IrisWorld).getEngine().getEnginePlayers().stream().count() + " players"); + for (EnginePlayer player : IrisToolbelt.access(IrisWorld).getEngine().getEnginePlayers()) { + sender().sendMessage(C.DARK_GRAY + "> " + player.getPlayer().getName()); + } + } + } else { + Iris.info(C.BLUE + "Iris Worlds: "); + for (World IrisWorld : IrisWorlds.copy()) { + Iris.info(C.IRIS + "- " + IrisWorld.getName() + C.GRAY + ", " + IrisToolbelt.access(IrisWorld).getEngine().getEnginePlayers().stream().count() + " players"); + for (EnginePlayer player : IrisToolbelt.access(IrisWorld).getEngine().getEnginePlayers()) { + Iris.info(C.DARK_GRAY + "> " + player.getPlayer().getName()); + } + } + } + } + @Decree(description = "Test the compression algorithms") public void compression( @Param(description = "base IrisWorld") World world, diff --git a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java index f1b08a309..f2d2ed82c 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisEngine.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisEngine.java @@ -34,6 +34,7 @@ import com.volmit.iris.engine.object.*; import com.volmit.iris.engine.scripting.EngineExecutionEnvironment; import com.volmit.iris.engine.service.EngineEffectsSVC; import com.volmit.iris.util.atomics.AtomicRollingSequence; +import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; import com.volmit.iris.util.context.ChunkContext; import com.volmit.iris.util.context.IrisContext; @@ -47,6 +48,7 @@ import com.volmit.iris.util.mantle.MantleFlag; import com.volmit.iris.util.math.M; import com.volmit.iris.util.math.RNG; import com.volmit.iris.util.matter.MatterStructurePOI; +import com.volmit.iris.util.mobs.IrisMobPiece; import com.volmit.iris.util.plugin.VolmitSender; import com.volmit.iris.util.scheduling.ChronoLatch; import com.volmit.iris.util.scheduling.J; @@ -62,15 +64,15 @@ import org.bukkit.block.Biome; import org.bukkit.block.data.BlockData; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerChangedWorldEvent; import java.io.File; import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; -import java.util.Collections; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; @@ -106,6 +108,7 @@ public class IrisEngine implements Engine { private EngineMode mode; private EngineExecutionEnvironment execution; private EngineWorldManager worldManager; + private KList players; private volatile int parallelism; private volatile int minHeight; private boolean failing; @@ -119,6 +122,7 @@ public class IrisEngine implements Engine { public IrisEngine(EngineTarget target, boolean studio) { this.studio = studio; this.target = target; + this.players = new KList<>(); getEngineData(); verifySeed(); this.seedManager = new SeedManager(target.getWorld().getRawWorldSeed()); @@ -187,6 +191,23 @@ public class IrisEngine implements Engine { if (effects != null) effects.tickRandomPlayer(); } + @Override + public EnginePlayer getEnginePlayer(UUID uuid) { + return getPlayer(uuid); + } + + @Override + public KList getEnginePlayers() { + return players; + } + + private EnginePlayer getPlayer(UUID uuid) { + for (EnginePlayer player : players) { + if (player.getPlayer().getUniqueId().equals(uuid)) return player; + } + return null; + } + private void prehotload() { worldManager.close(); complex.close(); diff --git a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java index 3482a3456..574b93152 100644 --- a/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java +++ b/core/src/main/java/com/volmit/iris/engine/IrisWorldManager.java @@ -23,6 +23,7 @@ import com.volmit.iris.core.IrisSettings; import com.volmit.iris.core.loader.IrisData; import com.volmit.iris.engine.framework.Engine; import com.volmit.iris.engine.framework.EngineAssignedWorldManager; +import com.volmit.iris.engine.framework.EnginePlayer; import com.volmit.iris.engine.object.*; import com.volmit.iris.util.collection.KList; import com.volmit.iris.util.collection.KMap; @@ -50,14 +51,16 @@ import org.bukkit.World; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockPlaceEvent; +import org.bukkit.event.player.PlayerChangedWorldEvent; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.event.player.PlayerLevelChangeEvent; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.ItemStack; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -181,6 +184,56 @@ public class IrisWorldManager extends EngineAssignedWorldManager { looper.start(); } + @EventHandler + private void on(PlayerChangedWorldEvent event) { + updatePlayers(); + } + + @EventHandler + private void on(PlayerJoinEvent event) { + updatePlayers(); + } + + @EventHandler + private void on(PlayerLevelChangeEvent event) { + updatePlayers(); + } + + public synchronized void updatePlayers() { + // ^ perhaps synchronized isn't the best one to use here + if (!getEngine().getWorld().tryGetRealWorld() || getEngine().isHeadless()) { + return; + } + + var world = getEngine().getWorld().realWorld(); + if (world == null) return; + + Set worldPlayers = new HashSet<>(world.getPlayers()); + + Map enginePlayerMap = new HashMap<>(); + for (EnginePlayer ep : getEngine().getEnginePlayers()) { + enginePlayerMap.put(ep.getOwner(), ep); + } + + Iterator> iterator = enginePlayerMap.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + if (worldPlayers.stream().noneMatch(p -> p.getUniqueId().equals(entry.getKey()))) { + entry.getValue().close(); + iterator.remove(); + getEngine().getEnginePlayers().remove(entry.getValue()); + } + } + + for (Player player : worldPlayers) { + if (!enginePlayerMap.containsKey(player.getUniqueId())) { + EnginePlayer newEnginePlayer = new EnginePlayer(getEngine(), player); + enginePlayerMap.put(player.getUniqueId(), newEnginePlayer); + getEngine().getEnginePlayers().add(newEnginePlayer); + } + } + } + private void discoverChunks() { var mantle = getEngine().getMantle().getMantle(); for (Player i : getEngine().getWorld().realWorld().getPlayers()) { diff --git a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java index 3fe6b7ecc..a49f6756c 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/Engine.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/Engine.java @@ -94,6 +94,8 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat int getBlockUpdatesPerSecond(); + boolean isHeadless(); + void printMetrics(CommandSender sender); EngineMantle getMantle(); @@ -819,6 +821,10 @@ public interface Engine extends DataProvider, Fallible, LootProvider, BlockUpdat int getCacheID(); + EnginePlayer getEnginePlayer(UUID uuid); + + KList getEnginePlayers(); + default IrisBiome getBiomeOrMantle(Location l) { return getBiomeOrMantle(l.getBlockX(), l.getBlockY(), l.getBlockZ()); } diff --git a/core/src/main/java/com/volmit/iris/engine/framework/EnginePlayer.java b/core/src/main/java/com/volmit/iris/engine/framework/EnginePlayer.java index c85d1e6fc..23a0baeca 100644 --- a/core/src/main/java/com/volmit/iris/engine/framework/EnginePlayer.java +++ b/core/src/main/java/com/volmit/iris/engine/framework/EnginePlayer.java @@ -29,6 +29,8 @@ import lombok.Data; import org.bukkit.Location; import org.bukkit.entity.Player; +import java.util.UUID; + @Data public class EnginePlayer { private final Engine engine; @@ -99,4 +101,12 @@ public class EnginePlayer { biome = engine.getBiome(l); region = engine.getRegion(l); } + + public UUID getOwner() { + return player.getUniqueId(); + } + + public void close() { + engine.getEnginePlayers().remove(this); + } } diff --git a/core/src/main/java/com/volmit/iris/engine/service/EngineEffectsSVC.java b/core/src/main/java/com/volmit/iris/engine/service/EngineEffectsSVC.java index 422960f9e..b4bbf8b29 100644 --- a/core/src/main/java/com/volmit/iris/engine/service/EngineEffectsSVC.java +++ b/core/src/main/java/com/volmit/iris/engine/service/EngineEffectsSVC.java @@ -31,7 +31,6 @@ import java.util.UUID; import java.util.concurrent.Semaphore; public class EngineEffectsSVC extends IrisEngineService { - private KMap players; private Semaphore limit; public EngineEffectsSVC(Engine engine) { @@ -40,58 +39,34 @@ public class EngineEffectsSVC extends IrisEngineService { @Override public void onEnable(boolean hotload) { - players = new KMap<>(); limit = new Semaphore(1); } @Override public void onDisable(boolean hotload) { - players = null; limit = null; } - public void updatePlayerMap() { - List pr = engine.getWorld().getPlayers(); - - if (pr == null) { - return; - } - - for (Player i : pr) { - boolean pcc = players.containsKey(i.getUniqueId()); - if (!pcc) { - players.put(i.getUniqueId(), new EnginePlayer(engine, i)); - } - } - - for (UUID i : players.k()) { - if (!pr.contains(players.get(i).getPlayer())) { - players.remove(i); - } - } - } public void tickRandomPlayer() { if (limit.tryAcquire()) { if (M.r(0.02)) { - updatePlayerMap(); limit.release(); return; } - if (players.isEmpty()) { + if (engine.getEnginePlayers().isEmpty()) { limit.release(); return; } double limitms = 1.5; - int max = players.size(); + int max = engine.getEnginePlayers().size(); PrecisionStopwatch p = new PrecisionStopwatch(); while (max-- > 0 && M.ms() - p.getMilliseconds() < limitms) { - players.v().getRandom().tick(); + engine.getEnginePlayers().getRandom().tick(); } - limit.release(); } } diff --git a/core/src/main/java/com/volmit/iris/util/mobs/IrisMobPiece.java b/core/src/main/java/com/volmit/iris/util/mobs/IrisMobPiece.java index 42a5735a8..b91a85318 100644 --- a/core/src/main/java/com/volmit/iris/util/mobs/IrisMobPiece.java +++ b/core/src/main/java/com/volmit/iris/util/mobs/IrisMobPiece.java @@ -1,15 +1,9 @@ package com.volmit.iris.util.mobs; -import com.volmit.iris.engine.framework.Engine; -import com.volmit.iris.engine.object.IrisEngineChunkData; -import com.volmit.iris.engine.object.IrisEngineSpawnerCooldown; -import com.volmit.iris.engine.object.IrisEntitySpawn; -import com.volmit.iris.engine.object.IrisPosition; -import com.volmit.iris.engine.service.EngineMobHandlerSVC; +import com.volmit.iris.engine.framework.EnginePlayer; import com.volmit.iris.util.math.M; -import com.volmit.iris.util.math.RNG; -import jakarta.activation.DataHandler; import lombok.Getter; +import org.bukkit.World; import org.bukkit.entity.Player; import java.util.Collections; @@ -20,11 +14,14 @@ import java.util.UUID; public class IrisMobPiece { @Getter private final Player player; + private double energyPiece; + private final World world; private IrisMobDataHandler dataHandler; private long lastRanPlayer; public IrisMobPiece(Player player, IrisMobDataHandler dh) { this.player = player; + this.world = player.getWorld(); this.dataHandler = dh; } @@ -58,12 +55,12 @@ public class IrisMobPiece { * Ticks the current player * @param energy the energy given for the tick */ - public void tick(int energy) { + public void tick(double energy) { lastRanPlayer = M.ms(); + this.energyPiece += energy; } - public UUID getOwner() { return player.getUniqueId(); }