mirror of
https://github.com/Melledy/Nebula.git
synced 2025-12-13 04:45:02 +01:00
Implement Heartlink
This commit is contained in:
@@ -28,6 +28,8 @@ public class GameData {
|
||||
@Getter private static DataTable<TalentGroupDef> TalentGroupDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<TalentDef> TalentDataTable = new DataTable<>();
|
||||
|
||||
@Getter private static DataTable<ChatDef> ChatDataTable = new DataTable<>();
|
||||
|
||||
// Discs
|
||||
@Getter private static DataTable<DiscDef> DiscDataTable = new DataTable<>();
|
||||
@Getter private static DataTable<DiscStrengthenDef> DiscStrengthenDataTable = new DataTable<>();
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@@ -21,6 +24,8 @@ public class CharacterDef extends BaseDef {
|
||||
private int FragmentsId;
|
||||
private int TransformQty;
|
||||
|
||||
private transient List<ChatDef> chats;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
@@ -33,4 +38,9 @@ public class CharacterDef extends BaseDef {
|
||||
|
||||
return this.SkillsUpgradeGroup[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
this.chats = new ObjectArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
36
src/main/java/emu/nebula/data/resources/ChatDef.java
Normal file
36
src/main/java/emu/nebula/data/resources/ChatDef.java
Normal file
@@ -0,0 +1,36 @@
|
||||
package emu.nebula.data.resources;
|
||||
|
||||
import emu.nebula.data.BaseDef;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.data.ResourceType;
|
||||
import emu.nebula.data.ResourceType.LoadPriority;
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@ResourceType(name = "Chat.json", loadPriority = LoadPriority.LOW)
|
||||
public class ChatDef extends BaseDef {
|
||||
private int Id;
|
||||
private int AddressBookId;
|
||||
private int PreChatId;
|
||||
|
||||
private int TriggerType;
|
||||
private int TriggerCond;
|
||||
private String TriggerCondParam;
|
||||
|
||||
private int Reward1;
|
||||
private int RewardQty1;
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return Id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
var character = GameData.getCharacterDataTable().get(this.AddressBookId);
|
||||
|
||||
if (character != null) {
|
||||
character.getChats().add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,7 @@ public class Character implements GameDatabaseObject {
|
||||
private int skin;
|
||||
private int[] skills;
|
||||
private Bitset talents;
|
||||
|
||||
private CharacterContact contact;
|
||||
private long createTime;
|
||||
|
||||
@Deprecated // Morphia only!
|
||||
@@ -66,11 +66,13 @@ public class Character implements GameDatabaseObject {
|
||||
this.playerUid = player.getUid();
|
||||
this.charId = data.getId();
|
||||
this.data = data;
|
||||
this.createTime = Nebula.getCurrentTime();
|
||||
|
||||
this.level = 1;
|
||||
this.skin = data.getDefaultSkinId();
|
||||
this.skills = new int[] {1, 1, 1, 1, 1};
|
||||
this.talents = new Bitset();
|
||||
this.createTime = Nebula.getCurrentTime();
|
||||
this.contact = new CharacterContact(this);
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
@@ -78,8 +80,20 @@ public class Character implements GameDatabaseObject {
|
||||
}
|
||||
|
||||
public void setData(CharacterDef data) {
|
||||
if (this.data == null && data.getId() == this.getCharId()) {
|
||||
this.data = data;
|
||||
// Sanity check
|
||||
if (this.data != null || data.getId() != this.getCharId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set data
|
||||
this.data = data;
|
||||
|
||||
// Check contacts
|
||||
if (this.contact == null) {
|
||||
this.contact = new CharacterContact(this);
|
||||
this.save();
|
||||
} else {
|
||||
this.contact.setCharacter(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
49
src/main/java/emu/nebula/game/character/CharacterChat.java
Normal file
49
src/main/java/emu/nebula/game/character/CharacterChat.java
Normal file
@@ -0,0 +1,49 @@
|
||||
package emu.nebula.game.character;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.nebula.data.resources.ChatDef;
|
||||
import emu.nebula.proto.Public.Chat;
|
||||
import lombok.Getter;
|
||||
import us.hebi.quickbuf.RepeatedInt;
|
||||
|
||||
@Getter
|
||||
@Entity(useDiscriminator = false)
|
||||
public class CharacterChat {
|
||||
private int id;
|
||||
private int process;
|
||||
private boolean end;
|
||||
|
||||
private int[] options;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public CharacterChat() {
|
||||
|
||||
}
|
||||
|
||||
public CharacterChat(ChatDef data) {
|
||||
this.id = data.getId();
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public Chat toProto() {
|
||||
var proto = Chat.newInstance()
|
||||
.setId(this.getId())
|
||||
.setProcess(this.getProcess());
|
||||
|
||||
if (this.getOptions() != null) {
|
||||
proto.addAllOptions(this.getOptions());
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
public void report(int process, RepeatedInt options, boolean end) {
|
||||
this.process = process;
|
||||
this.end = end;
|
||||
|
||||
if (options.length() > 0 && options.length() <= 5) {
|
||||
this.options = options.toArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
154
src/main/java/emu/nebula/game/character/CharacterContact.java
Normal file
154
src/main/java/emu/nebula/game/character/CharacterContact.java
Normal file
@@ -0,0 +1,154 @@
|
||||
package emu.nebula.game.character;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.resources.ChatDef;
|
||||
import emu.nebula.game.player.PlayerChangeInfo;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.Public.Contacts;
|
||||
import emu.nebula.proto.Public.UI32;
|
||||
import lombok.Getter;
|
||||
import us.hebi.quickbuf.RepeatedInt;
|
||||
|
||||
@Getter
|
||||
@Entity(useDiscriminator = false)
|
||||
public class CharacterContact {
|
||||
private transient Character character;
|
||||
|
||||
private boolean top;
|
||||
private long triggerTime;
|
||||
private Map<Integer, CharacterChat> chats;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public CharacterContact() {
|
||||
|
||||
}
|
||||
|
||||
public CharacterContact(Character character) {
|
||||
this.character = character;
|
||||
this.chats = new HashMap<>();
|
||||
this.triggerTime = character.getCreateTime();
|
||||
|
||||
// Get starter chat
|
||||
for (var chatData : character.getData().getChats()) {
|
||||
// Skip chats that have a requirement
|
||||
if (chatData.getPreChatId() != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add chat for character
|
||||
var chat = new CharacterChat(chatData);
|
||||
this.getChats().put(chat.getId(), chat);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCharacter(Character character) {
|
||||
this.character = character;
|
||||
}
|
||||
|
||||
public void addNextChat() {
|
||||
// Find next chat data
|
||||
ChatDef nextChatData = null;
|
||||
|
||||
for (var chatData : getCharacter().getData().getChats()) {
|
||||
// Skip chats that we have added
|
||||
if (this.getChats().containsKey(chatData.getId())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nextChatData = chatData;
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip if we cant find any new chat data
|
||||
if (nextChatData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add chat for character
|
||||
var chat = new CharacterChat(nextChatData);
|
||||
this.getChats().put(chat.getId(), chat);
|
||||
|
||||
// Send packet
|
||||
this.getCharacter().getPlayer().addNextPackage(
|
||||
NetMsgId.phone_chat_change_notify,
|
||||
UI32.newInstance().setValue(chat.getId())
|
||||
);
|
||||
}
|
||||
|
||||
public CharacterChat getChatById(int chatId) {
|
||||
return this.getChats().get(chatId);
|
||||
}
|
||||
|
||||
public boolean hasNew() {
|
||||
return this.getChats().values()
|
||||
.stream()
|
||||
.anyMatch(c -> !c.isEnd());
|
||||
}
|
||||
|
||||
public PlayerChangeInfo report(ChatDef chatData, int process, RepeatedInt options, boolean end) {
|
||||
// Get chat
|
||||
var chat = this.getChatById(chatData.getId());
|
||||
if (chat == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Player change info
|
||||
var change = new PlayerChangeInfo();
|
||||
|
||||
// Sanity check
|
||||
if (chat.isEnd()) {
|
||||
return change;
|
||||
}
|
||||
|
||||
// Report
|
||||
chat.report(process, options, end);
|
||||
|
||||
// Set trigger time
|
||||
this.triggerTime = Nebula.getCurrentTime();
|
||||
|
||||
// Add next chat
|
||||
this.addNextChat();
|
||||
|
||||
// TODO save more efficiently
|
||||
this.getCharacter().save();
|
||||
|
||||
// Add rewards
|
||||
if (chat.isEnd()) {
|
||||
getCharacter().getPlayer().getInventory().addItem(
|
||||
chatData.getReward1(),
|
||||
chatData.getRewardQty1(),
|
||||
change
|
||||
);
|
||||
}
|
||||
|
||||
// Success
|
||||
return change.setSuccess(true);
|
||||
}
|
||||
|
||||
public void toggleTop() {
|
||||
// Toggle
|
||||
this.top = !this.top;
|
||||
|
||||
// TODO save more efficiently
|
||||
this.getCharacter().save();
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public Contacts toProto() {
|
||||
var proto = Contacts.newInstance()
|
||||
.setCharId(this.getCharacter().getCharId())
|
||||
.setTop(this.isTop())
|
||||
.setTriggerTime(this.getTriggerTime());
|
||||
|
||||
for (var chat : this.getChats().values()) {
|
||||
proto.addChats(chat.toProto());
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
@@ -70,6 +70,18 @@ public class CharacterStorage extends PlayerManager {
|
||||
return this.getCharacters().values();
|
||||
}
|
||||
|
||||
public int getNewPhoneMessageCount() {
|
||||
int count = 0;
|
||||
|
||||
for (var character : this.getCharacterCollection()) {
|
||||
if (character.getContact().hasNew()) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
public HandbookInfo getCharacterHandbook() {
|
||||
var bitset = new Bitset();
|
||||
|
||||
|
||||
@@ -710,9 +710,12 @@ public class Player implements GameDatabaseObject {
|
||||
proto.addHandbook(this.getCharacters().getCharacterHandbook());
|
||||
proto.addHandbook(this.getCharacters().getDiscHandbook());
|
||||
|
||||
// Phone
|
||||
var phone = proto.getMutablePhone();
|
||||
phone.setNewMessage(this.getCharacters().getNewPhoneMessageCount());
|
||||
|
||||
// Extra
|
||||
proto.getMutableAgent();
|
||||
proto.getMutablePhone();
|
||||
|
||||
return proto;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.PhoneContactsInfo.PhoneContactsInfoResp;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@@ -10,7 +11,15 @@ public class HandlerPhoneContactsInfoReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_info_succeed_ack);
|
||||
// Build response
|
||||
var rsp = PhoneContactsInfoResp.newInstance();
|
||||
|
||||
for (var character : session.getPlayer().getCharacters().getCharacterCollection()) {
|
||||
rsp.addList(character.getContact().toProto());
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_info_succeed_ack, rsp);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package emu.nebula.server.handlers;
|
||||
|
||||
import emu.nebula.net.NetHandler;
|
||||
import emu.nebula.net.NetMsgId;
|
||||
import emu.nebula.proto.PhoneContactsReport.PhoneContactsReportReq;
|
||||
import emu.nebula.net.HandlerId;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.phone_contacts_report_req)
|
||||
public class HandlerPhoneContactsReportReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = PhoneContactsReportReq.parseFrom(message);
|
||||
|
||||
// Get chat data
|
||||
var data = GameData.getChatDataTable().get(req.getChatId());
|
||||
if (data == null) {
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_report_failed_ack);
|
||||
}
|
||||
|
||||
// Get character
|
||||
var character = session.getPlayer().getCharacters().getCharacterById(data.getAddressBookId());
|
||||
if (character == null) {
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_report_failed_ack);
|
||||
}
|
||||
|
||||
// Handle report
|
||||
var change = character.getContact().report(data, req.getProcess(), req.getOptions(), req.getEnd());
|
||||
|
||||
if (change == null) {
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_report_failed_ack);
|
||||
}
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_report_succeed_ack, change.toProto());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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.net.GameSession;
|
||||
|
||||
@HandlerId(NetMsgId.phone_contacts_top_req)
|
||||
public class HandlerPhoneContactsTopReq extends NetHandler {
|
||||
|
||||
@Override
|
||||
public byte[] handle(GameSession session, byte[] message) throws Exception {
|
||||
// Parse request
|
||||
var req = UI32.parseFrom(message);
|
||||
|
||||
// Get character
|
||||
var character = session.getPlayer().getCharacters().getCharacterById(req.getValue());
|
||||
if (character == null) {
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_top_failed_ack);
|
||||
}
|
||||
|
||||
// Toggle chat status
|
||||
character.getContact().toggleTop();
|
||||
|
||||
// Encode and send
|
||||
return session.encodeMsg(NetMsgId.phone_contacts_top_succeed_ack);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user