diff --git a/src/main/java/emu/grasscutter/data/GameData.java b/src/main/java/emu/grasscutter/data/GameData.java index ed5c469bb..a87e0e168 100644 --- a/src/main/java/emu/grasscutter/data/GameData.java +++ b/src/main/java/emu/grasscutter/data/GameData.java @@ -75,6 +75,7 @@ public class GameData { private static final Int2ObjectMap shopGoodsDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap combineDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap rewardPreviewDataMap = new Int2ObjectOpenHashMap<>(); + private static final Int2ObjectMap gatherDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap towerFloorDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap towerLevelDataMap = new Int2ObjectOpenHashMap<>(); private static final Int2ObjectMap towerScheduleDataMap = new Int2ObjectOpenHashMap<>(); @@ -347,4 +348,8 @@ public class GameData { public static Int2ObjectMap getQuestDataMap() { return questDataMap; } + + public static Int2ObjectMap getGatherDataMap() { + return gatherDataMap; + } } diff --git a/src/main/java/emu/grasscutter/data/def/GatherData.java b/src/main/java/emu/grasscutter/data/def/GatherData.java new file mode 100644 index 000000000..c80442378 --- /dev/null +++ b/src/main/java/emu/grasscutter/data/def/GatherData.java @@ -0,0 +1,49 @@ +package emu.grasscutter.data.def; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; + +@ResourceType(name = "GatherExcelConfigData.json") +public class GatherData extends GameResource { + private int PointType; + private int Id; + private int GadgetId; + private int ItemId; + private int Cd; // Probably hours + private boolean IsForbidGuest; + private boolean InitDisableInteract; + + @Override + public int getId() { + return this.PointType; + } + + public int getGatherId() { + return Id; + } + + public int getGadgetId() { + return GadgetId; + } + + public int getItemId() { + return ItemId; + } + + public int getCd() { + return Cd; + } + + public boolean isForbidGuest() { + return IsForbidGuest; + } + + public boolean initDisableInteract() { + return InitDisableInteract; + } + + @Override + public void onLoad() { + + } +} diff --git a/src/main/java/emu/grasscutter/data/def/SceneData.java b/src/main/java/emu/grasscutter/data/def/SceneData.java index cd1510e1d..955291cff 100644 --- a/src/main/java/emu/grasscutter/data/def/SceneData.java +++ b/src/main/java/emu/grasscutter/data/def/SceneData.java @@ -12,7 +12,6 @@ public class SceneData extends GameResource { private SceneType Type; private String ScriptData; - @Override public int getId() { return this.Id; diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index 640f93f22..af1d2c68c 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -5,8 +5,13 @@ import java.util.List; import emu.grasscutter.data.GameData; import emu.grasscutter.data.def.GadgetData; +import emu.grasscutter.game.entity.gadget.GadgetContent; +import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; +import emu.grasscutter.game.entity.gadget.GadgetRewardStatue; +import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityType; +import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.World; @@ -39,7 +44,8 @@ public class EntityGadget extends EntityBaseGadget { private int gadgetId; private int state; - private IntSet worktopOptions; + private int pointType; + private GadgetContent content; public EntityGadget(Scene scene, int gadgetId, Position pos) { super(scene); @@ -50,19 +56,22 @@ public class EntityGadget extends EntityBaseGadget { this.rot = new Position(); } + public EntityGadget(Scene scene, int gadgetId, Position pos, GadgetContent content) { + this(scene, gadgetId, pos); + this.content = content; + } + public GadgetData getGadgetData() { return data; } @Override public Position getPosition() { - // TODO Auto-generated method stub return this.pos; } @Override public Position getRotation() { - // TODO Auto-generated method stub return this.rot; } @@ -82,27 +91,42 @@ public class EntityGadget extends EntityBaseGadget { this.state = state; } - public IntSet getWorktopOptions() { - return worktopOptions; + public int getPointType() { + return pointType; + } + + public void setPointType(int pointType) { + this.pointType = pointType; + } + + public GadgetContent getContent() { + return content; + } + + @Deprecated // Dont use! + public void setContent(GadgetContent content) { + this.content = this.content == null ? content : this.content; } - public void addWorktopOptions(int[] options) { - if (this.worktopOptions == null) { - this.worktopOptions = new IntOpenHashSet(); - } - Arrays.stream(options).forEach(this.worktopOptions::add); - } - - public void removeWorktopOption(int option) { - if (this.worktopOptions == null) { + // TODO refactor + public void buildContent() { + if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) { return; } - this.worktopOptions.remove(option); + + EntityType type = getGadgetData().getType(); + GadgetContent content = switch (type) { + case GatherPoint -> new GadgetGatherPoint(this); + case Worktop -> new GadgetWorktop(this); + case RewardStatue -> new GadgetRewardStatue(this); + default -> null; + }; + + this.content = content; } @Override public Int2FloatOpenHashMap getFightProperties() { - // TODO Auto-generated method stub return null; } @@ -143,11 +167,8 @@ public class EntityGadget extends EntityBaseGadget { .setIsEnableInteract(true) .setAuthorityPeerId(this.getScene().getWorld().getHostPeerId()); - if (this.getGadgetData().getType() == EntityType.Worktop && this.getWorktopOptions() != null) { - WorktopInfo worktop = WorktopInfo.newBuilder() - .addAllOptionList(this.getWorktopOptions()) - .build(); - gadgetInfo.setWorktop(worktop); + if (this.getContent() != null) { + this.getContent().onBuildProto(gadgetInfo); } entityInfo.setGadget(gadgetInfo); diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetContent.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetContent.java new file mode 100644 index 000000000..d35663f60 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetContent.java @@ -0,0 +1,21 @@ +package emu.grasscutter.game.entity.gadget; + +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; + +public abstract class GadgetContent { + private final EntityGadget gadget; + + public GadgetContent(EntityGadget gadget) { + this.gadget = gadget; + } + + public EntityGadget getGadget() { + return gadget; + } + + public abstract boolean onInteract(Player player); + + public abstract void onBuildProto(SceneGadgetInfo.Builder gadgetInfo); +} diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetGatherPoint.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetGatherPoint.java new file mode 100644 index 000000000..0b3f3b6f9 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetGatherPoint.java @@ -0,0 +1,44 @@ +package emu.grasscutter.game.entity.gadget; + +import emu.grasscutter.data.GameData; +import emu.grasscutter.data.def.GatherData; +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.net.proto.GatherGadgetInfoOuterClass.GatherGadgetInfo; +import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; + +public class GadgetGatherPoint extends GadgetContent { + private GatherData gatherData; + + public GadgetGatherPoint(EntityGadget gadget) { + super(gadget); + this.gatherData = GameData.getGatherDataMap().get(gadget.getPointType()); + } + + public GatherData getGatherData() { + return gatherData; + } + + public int getItemId() { + return getGatherData().getItemId(); + } + + public boolean onInteract(Player player) { + GameItem item = new GameItem(gatherData.getItemId(), 1); + + player.getInventory().addItem(item, ActionReason.Gather); + + return true; + } + + public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) { + GatherGadgetInfo gatherGadgetInfo = GatherGadgetInfo.newBuilder() + .setItemId(this.getItemId()) + .setIsForbidGuest(this.getGatherData().isForbidGuest()) + .build(); + + gadgetInfo.setGatherGadget(gatherGadgetInfo); + } +} diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java new file mode 100644 index 000000000..8412c8b9f --- /dev/null +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetRewardStatue.java @@ -0,0 +1,28 @@ +package emu.grasscutter.game.entity.gadget; + +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; +import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; +import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; + +public class GadgetRewardStatue extends GadgetContent { + + public GadgetRewardStatue(EntityGadget gadget) { + super(gadget); + } + + public boolean onInteract(Player player) { + if (player.getScene().getChallenge() != null) { + player.getScene().getChallenge().getStatueDrops(player); + } + + player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_OPEN_STATUE)); + + return false; + } + + public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) { + + } +} diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetWorktop.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetWorktop.java new file mode 100644 index 000000000..fa7966189 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetWorktop.java @@ -0,0 +1,52 @@ +package emu.grasscutter.game.entity.gadget; + +import java.util.Arrays; + +import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; +import emu.grasscutter.net.proto.WorktopInfoOuterClass.WorktopInfo; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; + +public class GadgetWorktop extends GadgetContent { + private IntSet worktopOptions; + + public GadgetWorktop(EntityGadget gadget) { + super(gadget); + } + + public IntSet getWorktopOptions() { + return worktopOptions; + } + + public void addWorktopOptions(int[] options) { + if (this.worktopOptions == null) { + this.worktopOptions = new IntOpenHashSet(); + } + Arrays.stream(options).forEach(this.worktopOptions::add); + } + + public void removeWorktopOption(int option) { + if (this.worktopOptions == null) { + return; + } + this.worktopOptions.remove(option); + } + + public boolean onInteract(Player player) { + return false; + } + + public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) { + if (this.worktopOptions == null) { + return; + } + + WorktopInfo worktop = WorktopInfo.newBuilder() + .addAllOptionList(this.getWorktopOptions()) + .build(); + + gadgetInfo.setWorktop(worktop); + } +} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index aa4a0b59f..0ec0f3d1d 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -917,22 +917,20 @@ public class Player { else this.getScene().broadcastPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_PICK_ITEM)); } - } else if (entity instanceof EntityGadget) { - EntityGadget gadget = (EntityGadget) entity; + } else if (entity instanceof EntityGadget gadget) { + if (gadget.getContent() == null) { + return; + } - if (gadget.getGadgetData().getType() == EntityType.RewardStatue) { - if (scene.getChallenge() != null) { - scene.getChallenge().getStatueDrops(this); - } - - this.sendPacket(new PacketGadgetInteractRsp(gadget, InteractType.INTERACT_OPEN_STATUE)); + boolean shouldDelete = gadget.getContent().onInteract(this); + + if (shouldDelete) { + entity.getScene().removeEntity(entity); } } else { // Delete directly entity.getScene().removeEntity(entity); } - - return; } public void onPause() { diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 1c382fc74..c53ad0b21 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -23,6 +23,7 @@ import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.scripts.SceneIndexManager; import emu.grasscutter.scripts.SceneScriptManager; import emu.grasscutter.scripts.data.SceneBlock; +import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.server.packet.send.PacketAvatarSkillInfoNotify; import emu.grasscutter.server.packet.send.PacketDungeonChallengeFinishNotify; @@ -577,7 +578,15 @@ public class Scene { if (group.init_config == null) { continue; } + + // Load garbages + List garbageGadgets = group.getGarbageGadgets(); + + if (garbageGadgets != null) { + garbageGadgets.forEach(g -> scriptManager.createGadgets(group.id, group.block_id, g)); + } + // Load suites int suite = group.init_config.suite; if (suite == 0) { diff --git a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java index d57cb9ab5..99755a18f 100644 --- a/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java +++ b/src/main/java/emu/grasscutter/scripts/SceneScriptManager.java @@ -362,6 +362,8 @@ public class SceneScriptManager { entity.setGroupId(groupId); entity.getRotation().set(g.rot); entity.setState(g.state); + entity.setPointType(g.point_type); + entity.buildContent(); return entity; } diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLib.java b/src/main/java/emu/grasscutter/scripts/ScriptLib.java index e82df384d..f436df321 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLib.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLib.java @@ -4,6 +4,7 @@ import emu.grasscutter.game.dungeons.DungeonChallenge; import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneRegion; import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify; @@ -83,21 +84,22 @@ public class ScriptLib { public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) { logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}", groupId,configId,options); + Optional entity = getSceneScriptManager().getScene().getEntities().values().stream() .filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst(); - if (entity.isEmpty()) { - return 1; - } - - if (!(entity.get() instanceof EntityGadget)) { - return 1; - } - - EntityGadget gadget = (EntityGadget) entity.get(); - gadget.addWorktopOptions(options); + if (entity.isEmpty() || !(entity.get() instanceof EntityGadget gadget)) { + return 1; + } + + if (!(gadget.getContent() instanceof GadgetWorktop worktop)) { + return 1; + } + + worktop.addWorktopOptions(options); getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget)); + return 0; } @@ -107,18 +109,17 @@ public class ScriptLib { Optional entity = getSceneScriptManager().getScene().getEntities().values().stream() .filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst(); - if (entity.isEmpty()) { + if (entity.isEmpty() || !(entity.get() instanceof EntityGadget gadget)) { + return 1; + } + + if (!(gadget.getContent() instanceof GadgetWorktop worktop)) { return 1; } - if (!(entity.get() instanceof EntityGadget)) { - return 1; - } - - EntityGadget gadget = (EntityGadget) entity.get(); - gadget.removeWorktopOption(option); - + worktop.removeWorktopOption(option); getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget)); + return 0; } diff --git a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java index 049dbce32..6795de575 100644 --- a/src/main/java/emu/grasscutter/scripts/ScriptLoader.java +++ b/src/main/java/emu/grasscutter/scripts/ScriptLoader.java @@ -95,7 +95,7 @@ public class ScriptLoader { return sc.get(); } - Grasscutter.getLogger().info("Loaded Script" + path); + Grasscutter.getLogger().info("Loading script " + path); File file = new File(path); @@ -106,7 +106,7 @@ public class ScriptLoader { scriptsCache.put(path, new SoftReference<>(script)); return script; } catch (Exception e) { - Grasscutter.getLogger().error("Loaded Script {} failed!", path, e); + Grasscutter.getLogger().error("Loading script {} failed!", path, e); return null; } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneBusiness.java b/src/main/java/emu/grasscutter/scripts/data/SceneBusiness.java new file mode 100644 index 000000000..f03011e09 --- /dev/null +++ b/src/main/java/emu/grasscutter/scripts/data/SceneBusiness.java @@ -0,0 +1,10 @@ +package emu.grasscutter.scripts.data; + +import lombok.Setter; +import lombok.ToString; + +@ToString +@Setter +public class SceneBusiness { + public int type; +} diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java index 8b3e452fd..bdf3d55ba 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGadget.java @@ -8,4 +8,5 @@ import lombok.ToString; public class SceneGadget extends SceneObject{ public int gadget_id; public int state; + public int point_type; } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGarbage.java b/src/main/java/emu/grasscutter/scripts/data/SceneGarbage.java new file mode 100644 index 000000000..19f98984e --- /dev/null +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGarbage.java @@ -0,0 +1,12 @@ +package emu.grasscutter.scripts.data; + +import java.util.List; + +import lombok.Setter; +import lombok.ToString; + +@ToString +@Setter +public class SceneGarbage { + public List gadgets; +} diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index 08766b763..0cef08627 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -26,21 +26,20 @@ public class SceneGroup { public int refresh_id; public Position pos; - /** - * ConfigId - Monster - */ - public Map monsters; - /** - * ConfigId - Gadget - */ - public Map gadgets; + public Map monsters; // + public Map gadgets; // + public List triggers; public List regions; public List suites; + public List variables; + + public SceneBusiness business; + public SceneGarbage garbages; public SceneInitConfig init_config; - public List variables; private transient boolean loaded; // Not an actual variable in the scripts either + private transient CompiledScript script; public boolean isLoaded() { return loaded; @@ -49,8 +48,14 @@ public class SceneGroup { public void setLoaded(boolean loaded) { this.loaded = loaded; } - - private transient CompiledScript script; // Not an actual variable in the scripts either + + public int getBusinessType() { + return this.business == null ? 0 : this.business.type; + } + + public List getGarbageGadgets() { + return this.garbages == null ? null : this.garbages.gadgets; + } public CompiledScript getScript() { return script; @@ -75,6 +80,7 @@ public class SceneGroup { } this.script = cs; + // Eval script try { cs.eval(bindings); @@ -90,15 +96,16 @@ public class SceneGroup { triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, bindings.get("triggers")); triggers.forEach(t -> t.currentGroup = this); - + suites = ScriptLoader.getSerializer().toList(SceneSuite.class, bindings.get("suites")); regions = ScriptLoader.getSerializer().toList(SceneRegion.class, bindings.get("regions")); + garbages = ScriptLoader.getSerializer().toObject(SceneGarbage.class, bindings.get("garbages")); init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, bindings.get("init_config")); // Add variables to suite variables = ScriptLoader.getSerializer().toList(SceneVar.class, bindings.get("variables")); - // Add monsters to suite + // Add monsters and gadgets to suite for (SceneSuite suite : suites) { suite.sceneMonsters = new ArrayList<>( suite.monsters.stream() @@ -118,6 +125,7 @@ public class SceneGroup { } catch (ScriptException e) { Grasscutter.getLogger().error("Error loading group " + id + " in scene " + sceneId, e); } + Grasscutter.getLogger().info("group {} in scene {} is loaded successfully.", id, sceneId); return this; } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketWorktopOptionNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketWorktopOptionNotify.java index 14648a618..ade64cf09 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketWorktopOptionNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketWorktopOptionNotify.java @@ -1,6 +1,7 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.game.entity.EntityGadget; +import emu.grasscutter.game.entity.gadget.GadgetWorktop; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.WorktopOptionNotifyOuterClass.WorktopOptionNotify; @@ -13,8 +14,8 @@ public class PacketWorktopOptionNotify extends BasePacket { WorktopOptionNotify.Builder proto = WorktopOptionNotify.newBuilder() .setGadgetEntityId(gadget.getId()); - if (gadget.getWorktopOptions() != null) { - proto.addAllOptionList(gadget.getWorktopOptions()); + if (gadget.getContent() instanceof GadgetWorktop worktop) { + proto.addAllOptionList(worktop.getWorktopOptions()); } this.setData(proto);