From c78c6a7492434d8a9993de161cf226ea69a29512 Mon Sep 17 00:00:00 2001 From: Melledy <121644117+Melledy@users.noreply.github.com> Date: Mon, 24 Nov 2025 03:07:47 -0800 Subject: [PATCH] Implement trekker affinity story --- src/main/java/emu/nebula/data/GameData.java | 1 + .../emu/nebula/data/resources/PlotDef.java | 31 ++++++++++++ .../nebula/game/character/GameCharacter.java | 42 ++++++++++++++++ .../handlers/HandlerPlotRewardReceiveReq.java | 48 +++++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 src/main/java/emu/nebula/data/resources/PlotDef.java create mode 100644 src/main/java/emu/nebula/server/handlers/HandlerPlotRewardReceiveReq.java diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index 0154e07..7610f86 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -30,6 +30,7 @@ public class GameData { @Getter private static DataTable AffinityLevelDataTable = new DataTable<>(); @Getter private static DataTable AffinityGiftDataTable = new DataTable<>(); + @Getter private static DataTable PlotDataTable = new DataTable<>(); @Getter private static DataTable CharGemDataTable = new DataTable<>(); @Getter private static DataTable CharGemSlotControlDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/PlotDef.java b/src/main/java/emu/nebula/data/resources/PlotDef.java new file mode 100644 index 0000000..88a5680 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/PlotDef.java @@ -0,0 +1,31 @@ +package emu.nebula.data.resources; + +import emu.nebula.data.BaseDef; +import emu.nebula.data.ResourceType; +import emu.nebula.game.inventory.ItemParamMap; +import lombok.Getter; + +@Getter +@ResourceType(name = "Plot.json") +public class PlotDef extends BaseDef { + private int Id; + private int Char; + private int UnlockAffinityLevel; + private String Rewards; + + private transient ItemParamMap rewards; + + @Override + public int getId() { + return this.Id; + } + + public ItemParamMap getRewards() { + return this.rewards; + } + + @Override + public void onLoad() { + this.rewards = ItemParamMap.fromJsonString(this.Rewards); + } +} diff --git a/src/main/java/emu/nebula/game/character/GameCharacter.java b/src/main/java/emu/nebula/game/character/GameCharacter.java index 7d13cd2..66837e8 100644 --- a/src/main/java/emu/nebula/game/character/GameCharacter.java +++ b/src/main/java/emu/nebula/game/character/GameCharacter.java @@ -35,6 +35,7 @@ import emu.nebula.util.Bitset; import emu.nebula.util.CustomIntArray; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; import lombok.Getter; import us.hebi.quickbuf.RepeatedInt; @@ -58,6 +59,7 @@ public class GameCharacter implements GameDatabaseObject { private int skin; private int[] skills; private Bitset talents; + private IntSet plots; private long createTime; private int gemPresetIndex; @@ -461,6 +463,40 @@ public class GameCharacter implements GameDatabaseObject { return change; } + public PlayerChangeInfo recvPlotReward(int plotId) { + // Create change info + var change = new PlayerChangeInfo(); + + // Sanity check to prevent players from recving rewards over and over again from the same plot + if (this.getPlots() != null && this.getPlots().contains(plotId)) { + return change; + } + + // Get data + var plot = GameData.getPlotDataTable().get(plotId); + + // Sanity check to make sure we can complete this plot quest + if (plot == null || plot.getChar() != this.getCharId() || plot.getUnlockAffinityLevel() > this.getAffinityLevel()) { + return change; + } + + // Complete plot + if (this.plots == null) { + this.plots = new IntOpenHashSet(); + } + + this.getPlots().add(plotId); + + // Update to database + this.save(); + + // Add items + this.getPlayer().getInventory().addItems(plot.getRewards(), change); + + // Success + return change; + } + // Gems public boolean hasGemPreset(int index) { @@ -782,6 +818,12 @@ public class GameCharacter implements GameDatabaseObject { // Affinity quests proto.getMutableAffinityQuests(); + // Encode plots + if (this.getPlots() != null) { + this.getPlots().forEach(proto::addPlots); + } + + // Finish return proto; } diff --git a/src/main/java/emu/nebula/server/handlers/HandlerPlotRewardReceiveReq.java b/src/main/java/emu/nebula/server/handlers/HandlerPlotRewardReceiveReq.java new file mode 100644 index 0000000..f8a0497 --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerPlotRewardReceiveReq.java @@ -0,0 +1,48 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.Public.ChangeInfo; +import emu.nebula.proto.Public.UI32; +import emu.nebula.net.HandlerId; +import emu.nebula.data.GameData; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.plot_reward_receive_req) +public class HandlerPlotRewardReceiveReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = UI32.parseFrom(message); + + // Get plot data + var plot = GameData.getPlotDataTable().get(req.getValue()); + + if (plot == null) { + // Send empty packet to prevent the client from crashing + return session.encodeMsg(NetMsgId.plot_reward_receive_succeed_ack, ChangeInfo.newInstance()); + } + + // Get character + var character = session.getPlayer().getCharacters().getCharacterById(plot.getChar()); + + if (character == null) { + // Send empty packet to prevent the client from crashing + return session.encodeMsg(NetMsgId.plot_reward_receive_succeed_ack, ChangeInfo.newInstance()); + } + + // Complete plot + var change = character.recvPlotReward(plot.getId()); + + if (change == null) { + // Should never happen + // Send empty packet to prevent the client from crashing + return session.encodeMsg(NetMsgId.plot_reward_receive_succeed_ack, ChangeInfo.newInstance()); + } + + // Encode and send + return session.encodeMsg(NetMsgId.plot_reward_receive_succeed_ack, change.toProto()); + } + +}