diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index 24598a652..627b41103 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -34,6 +34,10 @@ public abstract class GameEntity { return this.id; } + public int getEntityType() { + return getId() >> 24; + } + public World getWorld() { return this.getScene().getWorld(); } diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index ee6b9a6a9..6ef810fbf 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -508,6 +508,7 @@ public class Scene { } group.triggers.forEach(getScriptManager()::registerTrigger); + group.regions.forEach(getScriptManager()::registerRegion); } // Spawn gadgets AFTER triggers are added @@ -526,6 +527,7 @@ public class Scene { for (SceneGroup group : block.groups) { group.triggers.forEach(getScriptManager()::deregisterTrigger); + group.regions.forEach(getScriptManager()::deregisterRegion); } } diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index 58e3b3b8a..f2f892de3 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -35,6 +35,7 @@ import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneInitConfig; import emu.grasscutter.scripts.data.SceneMonster; +import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.scripts.data.SceneSuite; import emu.grasscutter.scripts.data.SceneTrigger; import emu.grasscutter.scripts.data.SceneVar; @@ -51,14 +52,17 @@ public class SceneScriptManager { private Bindings bindings; private SceneConfig config; private List blocks; - private Int2ObjectOpenHashMap> triggers; private boolean isInit; + private final Int2ObjectOpenHashMap> triggers; + private final Int2ObjectOpenHashMap regions; + public SceneScriptManager(Scene scene) { this.scene = scene; this.scriptLib = new ScriptLib(this); this.scriptLibLua = CoerceJavaToLua.coerce(this.scriptLib); this.triggers = new Int2ObjectOpenHashMap<>(); + this.regions = new Int2ObjectOpenHashMap<>(); this.variables = new HashMap<>(); // TEMPORARY @@ -110,6 +114,18 @@ public class SceneScriptManager { getTriggersByEvent(trigger.event).remove(trigger); } + public SceneRegion getRegionById(int id) { + return regions.get(id); + } + + public void registerRegion(SceneRegion region) { + regions.put(region.config_id, region); + } + + public void deregisterRegion(SceneRegion region) { + regions.remove(region.config_id); + } + // TODO optimize public SceneGroup getGroupById(int groupId) { for (SceneBlock block : this.getScene().getLoadedBlocks()) { @@ -210,6 +226,7 @@ public class SceneScriptManager { group.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, bindings.get("gadgets")); group.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")); group.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites")); + group.regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions")); group.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config")); // Add variables to suite @@ -234,11 +251,27 @@ public class SceneScriptManager { } public void onTick() { - checkTriggers(); + checkRegions(); } - public void checkTriggers() { + public void checkRegions() { + if (this.regions.size() == 0) { + return; + } + + for (SceneRegion region : this.regions.values()) { + getScene().getEntities().values() + .stream() + .filter(e -> e.getEntityType() <= 2 && region.contains(e.getPosition())) + .forEach(region::addEntity); + if (region.hasNewEntities()) { + // This is not how it works, source_eid should be region entity id, but we dont have an entity for regions yet + callEvent(EventType.EVENT_ENTER_REGION, new ScriptArgs(region.config_id).setSourceEntityId(region.config_id)); + + region.resetNewEntities(); + } + } } public void spawnGadgetsInGroup(SceneGroup group) { diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index 57cd73dd3..5dfe644be 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -17,6 +17,7 @@ import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneMonster; +import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.scripts.data.ScriptArgs; import emu.grasscutter.server.packet.send.PacketGadgetStateNotify; import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify; @@ -184,6 +185,19 @@ public class ScriptLib { return 0; } + public int GetRegionEntityCount(LuaTable table) { + int regionId = table.get("region_eid").toint(); + int entityType = table.get("entity_type").toint(); + + SceneRegion region = this.getSceneScriptManager().getRegionById(regionId); + + if (region == null) { + return 0; + } + + return (int) region.getEntities().intStream().filter(e -> e >> 24 == entityType).count(); + } + public void PrintContextLog(String msg) { Grasscutter.getLogger().info("[LUA] " + msg); } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index d72d02d53..a13db7b68 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -14,6 +14,7 @@ public class SceneGroup { public List monsters; public List gadgets; public List triggers; + public List regions; public List suites; public SceneInitConfig init_config; diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java new file mode 100644 index 000000000..dac164d0e --- /dev/null +++ b/src/main/java/emu/grasscutter/scripts/data/SceneRegion.java @@ -0,0 +1,57 @@ +package emu.grasscutter.scripts.data; + +import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.scripts.constants.ScriptRegionShape; +import emu.grasscutter.utils.Position; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class SceneRegion { + public int config_id; + public int shape; + public Position pos; + public Position size; + + private boolean hasNewEntities; + private final IntSet entities; // Ids of entities inside this region + + public SceneRegion() { + this.entities = new IntOpenHashSet(); + } + + public IntSet getEntities() { + return entities; + } + + public void addEntity(GameEntity entity) { + if (this.getEntities().contains(entity.getId())) { + return; + } + this.getEntities().add(entity.getId()); + this.hasNewEntities = true; + } + + public void removeEntity(GameEntity entity) { + this.getEntities().remove(entity.getId()); + } + + public boolean contains(Position p) { + switch (shape) { + case ScriptRegionShape.CUBIC: + return (Math.abs(pos.getX() - p.getX()) <= size.getX()) && + (Math.abs(pos.getZ() - p.getZ()) <= size.getZ()); + case ScriptRegionShape.SPHERE: + return false; + } + + return false; + } + + public boolean hasNewEntities() { + return hasNewEntities; + } + + public void resetNewEntities() { + hasNewEntities = false; + } +} diff --git a/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java b/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java index 3073f7322..a1f183b63 100644 --- a/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java +++ b/src/main/java/emu/grasscutter/scripts/data/ScriptArgs.java @@ -4,6 +4,7 @@ public class ScriptArgs { public int param1; public int param2; public int param3; + public int source_eid; // Source entity public ScriptArgs() { @@ -44,4 +45,13 @@ public class ScriptArgs { this.param3 = param3; return this; } + + public int getSourceEntityId() { + return source_eid; + } + + public ScriptArgs setSourceEntityId(int source_eid) { + this.source_eid = source_eid; + return this; + } }