diff --git a/src/main/java/emu/nebula/data/GameData.java b/src/main/java/emu/nebula/data/GameData.java index b30b715..25559cb 100644 --- a/src/main/java/emu/nebula/data/GameData.java +++ b/src/main/java/emu/nebula/data/GameData.java @@ -155,6 +155,9 @@ public class GameData { // ===== Activity ===== @Getter private static DataTable ActivityDataTable = new DataTable<>(); + + // Activity: Login Reward + @Getter private static DataTable LoginRewardGroupControlDataTable = new DataTable<>(); // Activity: Tower Defense @Getter private static DataTable TowerDefenseLevelDataTable = new DataTable<>(); diff --git a/src/main/java/emu/nebula/data/resources/LoginRewardGroupControlDef.java b/src/main/java/emu/nebula/data/resources/LoginRewardGroupControlDef.java new file mode 100644 index 0000000..83fd8d8 --- /dev/null +++ b/src/main/java/emu/nebula/data/resources/LoginRewardGroupControlDef.java @@ -0,0 +1,36 @@ +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 = "LoginRewardGroup.json") +public class LoginRewardGroupControlDef extends BaseDef { + private int Id; + + private int RewardId1; + private int Qty1; + private int RewardId2; + private int Qty2; + + private transient ItemParamMap rewards; + + @Override + public int getId() { + return Id; + } + + @Override + public void onLoad() { + this.rewards = new ItemParamMap(); + + if (this.RewardId1 > 0) { + this.rewards.add(this.RewardId1, this.Qty1); + } + if (this.RewardId2 > 0) { + this.rewards.add(this.RewardId2, this.Qty2); + } + } +} diff --git a/src/main/java/emu/nebula/game/activity/ActivityManager.java b/src/main/java/emu/nebula/game/activity/ActivityManager.java index 72d6398..efd283c 100644 --- a/src/main/java/emu/nebula/game/activity/ActivityManager.java +++ b/src/main/java/emu/nebula/game/activity/ActivityManager.java @@ -111,6 +111,7 @@ public class ActivityManager extends PlayerManager implements GameDatabaseObject // TODO improve activity creation GameActivity activity = switch (data.getType()) { + case LoginReward -> new LoginRewardActivity(this, data); case TowerDefense -> new TowerDefenseActivity(this, data); case Trial -> new TrialActivity(this, data); case Levels -> new LevelsActivity(this, data); @@ -122,6 +123,14 @@ public class ActivityManager extends PlayerManager implements GameDatabaseObject return activity; } + + // Events + + public synchronized void onLogin() { + for (var activity : this.getActivities().values()) { + activity.onLogin(); + } + } // Database diff --git a/src/main/java/emu/nebula/game/activity/ActivityModule.java b/src/main/java/emu/nebula/game/activity/ActivityModule.java index 77e029f..5600903 100644 --- a/src/main/java/emu/nebula/game/activity/ActivityModule.java +++ b/src/main/java/emu/nebula/game/activity/ActivityModule.java @@ -18,7 +18,8 @@ public class ActivityModule extends GameContextModule { // TODO make an activity json file to read activity ids from // Trial activities - this.activities.add(700104); + this.activities.add(700105); + this.activities.add(700106); this.activities.add(700107); this.activities.add(700108); @@ -35,6 +36,10 @@ public class ActivityModule extends GameContextModule { this.activities.add(2010103); this.activities.add(2010104); + // Christmas 2025 login events + this.activities.add(301011); + this.activities.add(301012); + // Trekker versus this.activities.add(600001); } diff --git a/src/main/java/emu/nebula/game/activity/GameActivity.java b/src/main/java/emu/nebula/game/activity/GameActivity.java index 082ed1c..63d6afa 100644 --- a/src/main/java/emu/nebula/game/activity/GameActivity.java +++ b/src/main/java/emu/nebula/game/activity/GameActivity.java @@ -41,6 +41,12 @@ public abstract class GameActivity { ); } + // Events + + public void onLogin() { + + } + // Proto public Activity toProto() { diff --git a/src/main/java/emu/nebula/game/activity/type/LoginRewardActivity.java b/src/main/java/emu/nebula/game/activity/type/LoginRewardActivity.java new file mode 100644 index 0000000..30624d3 --- /dev/null +++ b/src/main/java/emu/nebula/game/activity/type/LoginRewardActivity.java @@ -0,0 +1,101 @@ +package emu.nebula.game.activity.type; + +import dev.morphia.annotations.Entity; +import emu.nebula.data.GameData; +import emu.nebula.data.resources.ActivityDef; +import emu.nebula.game.activity.ActivityManager; +import emu.nebula.game.activity.GameActivity; +import emu.nebula.game.inventory.ItemParamMap; +import emu.nebula.game.player.PlayerChangeInfo; +import emu.nebula.proto.ActivityDetail.ActivityMsg; + +import lombok.Getter; + +@Getter +@Entity +public class LoginRewardActivity extends GameActivity { + private int actual; // Received rewards + private int receive; // Rewards level that we can claim + + private boolean complete; + private long lastEpochDay; + + @Deprecated // Morphia only + public LoginRewardActivity() { + + } + + public LoginRewardActivity(ActivityManager manager, ActivityDef data) { + super(manager, data); + } + + public PlayerChangeInfo claim() { + // Create change info + var change = new PlayerChangeInfo(); + + // Sanity check + if (this.getActual() >= this.getReceive()) { + return change; + } + + // Get rewards + var rewards = new ItemParamMap(); + + for (int i = this.getActual() + 1; i <= this.getReceive(); i++) { + int rewardId = (this.getId() * 100) + i; + var data = GameData.getLoginRewardGroupControlDataTable().get(rewardId); + + if (data == null) { + continue; + } + + rewards.add(data.getRewards()); + } + + // Give rewards to player + this.getPlayer().getInventory().addItems(rewards, change); + + // Update claimed and save to database + this.actual = this.receive; + this.save(); + + // Complete + return change; + } + + @Override + public void onLogin() { + // Check if epoch day has changed + if (this.getPlayer().getLastEpochDay() <= this.lastEpochDay || this.isComplete()) { + return; + } + + // Get next reward + int nextReceive = this.receive + 1; + int rewardId = (this.getId() * 100) + nextReceive; + var data = GameData.getLoginRewardGroupControlDataTable().get(rewardId); + + if (data != null) { + this.receive = nextReceive; + } else { + this.complete = true; // Set "complete" flag so we dont need to save to database/do a recheck every login + } + + // Unlock next reward + this.lastEpochDay = this.getPlayer().getLastEpochDay(); + + // Save + this.save(); + } + + // Proto + + @Override + public void encodeActivityMsg(ActivityMsg msg) { + msg.getMutableLogin() + .setActivityId(this.getId()) + .setActual(this.getActual()) + .setReceive(this.getReceive()); + } + +} diff --git a/src/main/java/emu/nebula/game/player/Player.java b/src/main/java/emu/nebula/game/player/Player.java index d10eba5..d440d57 100644 --- a/src/main/java/emu/nebula/game/player/Player.java +++ b/src/main/java/emu/nebula/game/player/Player.java @@ -804,6 +804,9 @@ public class Player implements GameDatabaseObject { // Fix any broken honor ids this.checkBrokenHonor(); + // Update activities + this.getActivityManager().onLogin(); + // Update last login time this.lastLogin = System.currentTimeMillis(); Nebula.getGameDatabase().update(this, this.getUid(), "lastLogin", this.getLastLogin()); diff --git a/src/main/java/emu/nebula/server/handlers/HandlerActivityLoginRewardReceiveReq.java b/src/main/java/emu/nebula/server/handlers/HandlerActivityLoginRewardReceiveReq.java new file mode 100644 index 0000000..356a32a --- /dev/null +++ b/src/main/java/emu/nebula/server/handlers/HandlerActivityLoginRewardReceiveReq.java @@ -0,0 +1,36 @@ +package emu.nebula.server.handlers; + +import emu.nebula.net.NetHandler; +import emu.nebula.net.NetMsgId; +import emu.nebula.proto.Public.UI32; +import emu.nebula.net.HandlerId; +import emu.nebula.game.activity.type.LoginRewardActivity; +import emu.nebula.net.GameSession; + +@HandlerId(NetMsgId.activity_login_reward_receive_req) +public class HandlerActivityLoginRewardReceiveReq extends NetHandler { + + @Override + public byte[] handle(GameSession session, byte[] message) throws Exception { + // Parse request + var req = UI32.parseFrom(message); + + // Get activity + var activity = session.getPlayer().getActivityManager().getActivity(LoginRewardActivity.class, req.getValue()); + + if (activity == null) { + return session.encodeMsg(NetMsgId.activity_login_reward_receive_failed_ack); + } + + // Claim any rewards + var change = activity.claim(); + + if (change == null) { + return session.encodeMsg(NetMsgId.activity_login_reward_receive_failed_ack); + } + + // Encode and send + return session.encodeMsg(NetMsgId.activity_login_reward_receive_succeed_ack, change.toProto()); + } + +}