Implement login reward activity

This commit is contained in:
Melledy
2025-12-24 21:12:31 -08:00
parent b086851b95
commit 9db0f6aabb
8 changed files with 200 additions and 1 deletions
@@ -155,6 +155,9 @@ public class GameData {
// ===== Activity =====
@Getter private static DataTable<ActivityDef> ActivityDataTable = new DataTable<>();
// Activity: Login Reward
@Getter private static DataTable<LoginRewardGroupControlDef> LoginRewardGroupControlDataTable = new DataTable<>();
// Activity: Tower Defense
@Getter private static DataTable<TowerDefenseLevelDef> TowerDefenseLevelDataTable = new DataTable<>();
@@ -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);
}
}
}
@@ -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
@@ -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);
}
@@ -41,6 +41,12 @@ public abstract class GameActivity {
);
}
// Events
public void onLogin() {
}
// Proto
public Activity toProto() {
@@ -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());
}
}
@@ -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());
@@ -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());
}
}