Implement character archive story rewards

This commit is contained in:
Melledy
2026-08-17 21:23:39 -07:00
parent b40edc90bb
commit 28afb10691
4 changed files with 113 additions and 1 deletions
@@ -13,6 +13,7 @@ public class GameData {
@Getter private static DataTable<CharacterUpgradeDef> CharacterUpgradeDataTable = new DataTable<>(); @Getter private static DataTable<CharacterUpgradeDef> CharacterUpgradeDataTable = new DataTable<>();
@Getter private static DataTable<CharItemExpDef> CharItemExpDataTable = new DataTable<>(); @Getter private static DataTable<CharItemExpDef> CharItemExpDataTable = new DataTable<>();
@Getter private static DataTable<CharacterSkinDef> CharacterSkinDataTable = new DataTable<>(); @Getter private static DataTable<CharacterSkinDef> CharacterSkinDataTable = new DataTable<>();
@Getter private static DataTable<CharacterArchiveDef> CharacterArchiveDataTable = new DataTable<>();
@Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>(); @Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>();
@Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>(); @Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>();
@@ -0,0 +1,23 @@
package emu.nebula.data.resources;
import emu.nebula.data.BaseDef;
import emu.nebula.data.ResourceType;
import lombok.Getter;
@Getter
@ResourceType(name = "CharacterArchive.json")
public class CharacterArchiveDef extends BaseDef {
private int Id;
private int ArchType;
private int CharacterId;
private int UnlockAffinityLevel;
private int ArchReward;
private int ArchRewardQuantity;
@Override
public int getId() {
return Id;
}
}
@@ -15,6 +15,7 @@ import dev.morphia.annotations.PreLoad;
import emu.nebula.GameConstants; import emu.nebula.GameConstants;
import emu.nebula.Nebula; import emu.nebula.Nebula;
import emu.nebula.data.GameData; import emu.nebula.data.GameData;
import emu.nebula.data.resources.CharacterArchiveDef;
import emu.nebula.data.resources.CharacterDef; import emu.nebula.data.resources.CharacterDef;
import emu.nebula.data.resources.TalentGroupDef; import emu.nebula.data.resources.TalentGroupDef;
import emu.nebula.database.GameDatabaseObject; import emu.nebula.database.GameDatabaseObject;
@@ -65,13 +66,20 @@ public class GameCharacter implements GameDatabaseObject {
private int skin; private int skin;
private int[] skills; private int[] skills;
private Bitset talents; private Bitset talents;
private IntSet plots;
private long createTime; private long createTime;
// Archive stories
private IntSet archives;
// Affinity stories (Memory recollection)
private IntSet plots;
// Gems
private int gemPresetIndex; private int gemPresetIndex;
private List<CharacterGemPreset> gemPresets; private List<CharacterGemPreset> gemPresets;
private CharacterGemSlot[] gemSlots; private CharacterGemSlot[] gemSlots;
// Phone/Heartlink
private CharacterContact contact; private CharacterContact contact;
@Deprecated // Morphia only! @Deprecated // Morphia only!
@@ -532,6 +540,36 @@ public class GameCharacter implements GameDatabaseObject {
return change; return change;
} }
public PlayerChangeInfo recvArchiveReward(CharacterArchiveDef archive) {
// Sanity check to prevent players from recving rewards over and over again from the same archive
if (this.getArchives() != null && this.getArchives().contains(archive.getId())) {
return null;
}
// Sanity check to make sure we can complete this archive
if (archive.getUnlockAffinityLevel() > this.getAffinityLevel()) {
return null;
}
// Make sure archive has rewards
if (archive.getArchReward() == 0) {
return null;
}
// Complete archive
if (this.archives == null) {
this.archives = new IntOpenHashSet();
}
this.getArchives().add(archive.getId());
// Update to database
this.save();
// Add items
return this.getPlayer().getInventory().addItem(archive.getArchReward(), archive.getArchRewardQuantity());
}
// Gems // Gems
public boolean hasGemPreset(int index) { public boolean hasGemPreset(int index) {
@@ -955,6 +993,11 @@ public class GameCharacter implements GameDatabaseObject {
this.getPlots().forEach(proto::addPlots); this.getPlots().forEach(proto::addPlots);
} }
// Encode archives
if (this.getArchives() != null) {
this.getArchives().forEach(proto::addArchiveRewardIds);
}
// Finish // Finish
return proto; return proto;
} }
@@ -0,0 +1,45 @@
package emu.nebula.server.handlers;
import emu.nebula.net.NetHandler;
import emu.nebula.net.NetMsgId;
import emu.nebula.proto.CharArchive.CharArchiveRewardReceiveReq;
import emu.nebula.net.HandlerId;
import emu.nebula.data.GameData;
import emu.nebula.net.GameSession;
@HandlerId(NetMsgId.char_archive_reward_receive_req)
public class HandlerCharArchiveRewardReceiveReq extends NetHandler {
@Override
public byte[] handle(GameSession session, byte[] message) throws Exception {
// Parse request
var req = CharArchiveRewardReceiveReq.parseFrom(message);
// Get archive
var archive = GameData.getCharacterArchiveDataTable().get(req.getArchiveId());
if (archive == null) {
// Archive not found
return session.encodeMsg(NetMsgId.char_archive_reward_receive_failed_ack);
}
// Get character
var character = session.getPlayer().getCharacters().getCharacterById(archive.getCharacterId());
if (character == null) {
// Character not found
return session.encodeMsg(NetMsgId.char_archive_reward_receive_failed_ack);
}
// Get archive reward
var change = character.recvArchiveReward(archive);
if (change == null) {
return session.encodeMsg(NetMsgId.char_archive_reward_receive_failed_ack);
}
// Encode reward and send
return session.encodeMsg(NetMsgId.char_archive_reward_receive_succeed_ack, change.toProto());
}
}