mirror of
https://github.com/Melledy/Nebula.git
synced 2026-09-20 01:29:54 +02:00
Initial Commit
This commit is contained in:
@@ -0,0 +1,358 @@
|
||||
package emu.nebula.game.player;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import dev.morphia.annotations.Entity;
|
||||
import dev.morphia.annotations.Id;
|
||||
import dev.morphia.annotations.Indexed;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.data.GameData;
|
||||
import emu.nebula.database.GameDatabaseObject;
|
||||
import emu.nebula.game.account.Account;
|
||||
import emu.nebula.game.character.CharacterStorage;
|
||||
import emu.nebula.game.formation.FormationManager;
|
||||
import emu.nebula.game.inventory.Inventory;
|
||||
import emu.nebula.game.mail.Mailbox;
|
||||
import emu.nebula.game.tower.StarTowerManager;
|
||||
import emu.nebula.net.GameSession;
|
||||
import emu.nebula.proto.PlayerData.PlayerInfo;
|
||||
import emu.nebula.proto.Public.NewbieInfo;
|
||||
import emu.nebula.proto.Public.QuestType;
|
||||
import emu.nebula.proto.Public.WorldClass;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
@Entity(value = "players", useDiscriminator = false)
|
||||
public class Player implements GameDatabaseObject {
|
||||
@Id private int uid;
|
||||
@Indexed private String accountUid;
|
||||
|
||||
private transient Account account;
|
||||
private transient Set<GameSession> sessions;
|
||||
|
||||
// Details
|
||||
private String name;
|
||||
private boolean gender;
|
||||
private int headIcon;
|
||||
private int skinId;
|
||||
private int titlePrefix;
|
||||
private int titleSuffix;
|
||||
private int level;
|
||||
private int exp;
|
||||
|
||||
private int energy;
|
||||
|
||||
private IntSet boards;
|
||||
private IntSet titles;
|
||||
|
||||
private long createTime;
|
||||
|
||||
// Managers
|
||||
private final transient CharacterStorage characters;
|
||||
private final transient Inventory inventory;
|
||||
|
||||
// Referenced data
|
||||
private transient FormationManager formations;
|
||||
private transient Mailbox mailbox;
|
||||
private transient StarTowerManager starTowerManager;
|
||||
|
||||
@Deprecated // Morphia only
|
||||
public Player() {
|
||||
this.sessions = new HashSet<>();
|
||||
this.characters = new CharacterStorage(this);
|
||||
this.inventory = new Inventory(this);
|
||||
}
|
||||
|
||||
public Player(Account account, String name, boolean gender) {
|
||||
this();
|
||||
|
||||
// Set uid first
|
||||
if (account.getReservedPlayerUid() > 0) {
|
||||
this.uid = account.getReservedPlayerUid();
|
||||
} else {
|
||||
this.uid = Nebula.getGameDatabase().getNextObjectId(Player.class);
|
||||
}
|
||||
|
||||
// Set basic info
|
||||
this.accountUid = account.getUid();
|
||||
this.name = name;
|
||||
this.gender = gender;
|
||||
this.headIcon = 101;
|
||||
this.skinId = 10301;
|
||||
this.titlePrefix = 1;
|
||||
this.titleSuffix = 2;
|
||||
this.level = 1;
|
||||
this.boards = new IntOpenHashSet();
|
||||
this.titles = new IntOpenHashSet();
|
||||
this.createTime = Nebula.getCurrentTime();
|
||||
|
||||
// Add starter characters
|
||||
this.getCharacters().addCharacter(103);
|
||||
this.getCharacters().addCharacter(112);
|
||||
this.getCharacters().addCharacter(113);
|
||||
|
||||
// Add starter discs
|
||||
this.getCharacters().addDisc(211001);
|
||||
this.getCharacters().addDisc(211005);
|
||||
this.getCharacters().addDisc(211007);
|
||||
this.getCharacters().addDisc(211008);
|
||||
|
||||
// Add titles
|
||||
this.getTitles().add(this.getTitlePrefix());
|
||||
this.getTitles().add(this.getTitleSuffix());
|
||||
|
||||
// Add board ids
|
||||
this.getBoards().add(410301);
|
||||
}
|
||||
|
||||
public Account getAccount() {
|
||||
if (this.account == null) {
|
||||
this.account = Nebula.getAccountDatabase().getObjectByField(Account.class, "_id", this.getAccountUid());
|
||||
}
|
||||
|
||||
return this.account;
|
||||
}
|
||||
|
||||
public void addSession(GameSession session) {
|
||||
synchronized (this.sessions) {
|
||||
this.sessions.add(session);
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSession(GameSession session) {
|
||||
synchronized (this.sessions) {
|
||||
this.sessions.remove(session);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasSessions() {
|
||||
synchronized (this.sessions) {
|
||||
return !this.sessions.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getGender() {
|
||||
return this.gender;
|
||||
}
|
||||
|
||||
public boolean editName(String newName) {
|
||||
// Sanity check
|
||||
if (newName == null || newName.isEmpty() || newName.equals(this.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Limit name length
|
||||
if (newName.length() > 20) {
|
||||
newName = newName.substring(0, 19);
|
||||
}
|
||||
|
||||
// Set name
|
||||
this.name = newName;
|
||||
|
||||
// Update in database
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "name", this.getName());
|
||||
|
||||
// Success
|
||||
return true;
|
||||
}
|
||||
|
||||
public void editGender() {
|
||||
// Set name
|
||||
this.gender = !this.gender;
|
||||
|
||||
// Update in database
|
||||
Nebula.getGameDatabase().update(this, this.getUid(), "gender", this.getGender());
|
||||
}
|
||||
|
||||
public void setNewbieInfo(int groupId, int stepId) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
public int getMaxExp() {
|
||||
var data = GameData.getWorldClassDataTable().get(this.level + 1);
|
||||
return data != null ? data.getExp() : 0;
|
||||
}
|
||||
|
||||
public PlayerChangeInfo addExp(int amount, PlayerChangeInfo changes) {
|
||||
// Check if changes is null
|
||||
if (changes == null) {
|
||||
changes = new PlayerChangeInfo();
|
||||
}
|
||||
|
||||
// Sanity
|
||||
if (amount <= 0) {
|
||||
return changes;
|
||||
}
|
||||
|
||||
// Setup
|
||||
int oldLevel = this.getLevel();
|
||||
int oldExp = this.getExp();
|
||||
int expRequired = this.getMaxExp();
|
||||
|
||||
// Add exp
|
||||
this.exp += amount;
|
||||
|
||||
// Check for level ups
|
||||
while (this.exp >= expRequired && expRequired > 0) {
|
||||
this.level += 1;
|
||||
this.exp -= expRequired;
|
||||
|
||||
expRequired = this.getMaxExp();
|
||||
}
|
||||
|
||||
// Save to database
|
||||
Nebula.getGameDatabase().update(
|
||||
this,
|
||||
this.getUid(),
|
||||
"level",
|
||||
this.getLevel(),
|
||||
"exp",
|
||||
this.getExp()
|
||||
);
|
||||
|
||||
// Calculate changes
|
||||
var proto = WorldClass.newInstance()
|
||||
.setAddClass(this.getLevel() - oldLevel)
|
||||
.setExpChange(this.getExp() - oldExp);
|
||||
|
||||
changes.add(proto);
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
public void sendMessage(String string) {
|
||||
// Empty
|
||||
}
|
||||
|
||||
// Login
|
||||
|
||||
public void onLoad() {
|
||||
// Load from database
|
||||
this.getCharacters().loadFromDatabase();
|
||||
this.getInventory().loadFromDatabase();
|
||||
|
||||
// Load referenced classes
|
||||
this.formations = Nebula.getGameDatabase().getObjectByField(FormationManager.class, "_id", this.getUid());
|
||||
if (this.formations == null) {
|
||||
this.formations = new FormationManager(this);
|
||||
} else {
|
||||
this.formations.setPlayer(this);
|
||||
}
|
||||
|
||||
this.mailbox = Nebula.getGameDatabase().getObjectByField(Mailbox.class, "_id", this.getUid());
|
||||
if (this.mailbox == null) {
|
||||
this.mailbox = new Mailbox(this);
|
||||
}
|
||||
|
||||
this.starTowerManager = Nebula.getGameDatabase().getObjectByField(StarTowerManager.class, "_id", this.getUid());
|
||||
if (this.starTowerManager == null) {
|
||||
this.starTowerManager = new StarTowerManager(this);
|
||||
} else {
|
||||
this.starTowerManager.setPlayer(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public PlayerInfo toProto() {
|
||||
PlayerInfo proto = PlayerInfo.newInstance();
|
||||
|
||||
var acc = proto.getMutableAcc()
|
||||
.setNickName(this.getName())
|
||||
.setGender(this.getGender())
|
||||
.setId(this.getUid())
|
||||
.setHeadIcon(this.getHeadIcon())
|
||||
.setSkinId(this.getSkinId())
|
||||
.setTitlePrefix(this.getTitlePrefix())
|
||||
.setTitleSuffix(this.getTitleSuffix())
|
||||
.setCreateTime(this.getCreateTime());
|
||||
|
||||
proto.getMutableWorldClass()
|
||||
.setStage(3)
|
||||
.setCur(this.getLevel())
|
||||
.setLastExp(this.getExp());
|
||||
|
||||
proto.getMutableEnergy()
|
||||
.getMutableEnergy()
|
||||
.setUpdateTime(Nebula.getCurrentTime())
|
||||
.setNextDuration(60)
|
||||
.setPrimary(240)
|
||||
.setIsPrimary(true);
|
||||
|
||||
// Add characters/discs/res/items
|
||||
for (var character : getCharacters().getCharacterCollection()) {
|
||||
proto.addChars(character.toProto());
|
||||
}
|
||||
|
||||
for (var disc : getCharacters().getDiscCollection()) {
|
||||
proto.addDiscs(disc.toProto());
|
||||
}
|
||||
|
||||
for (var item : getInventory().getItems().values()) {
|
||||
proto.addItems(item.toProto());
|
||||
}
|
||||
|
||||
for (var res : getInventory().getResources().values()) {
|
||||
proto.addRes(res.toProto());
|
||||
}
|
||||
|
||||
// Formations
|
||||
for (var f : this.getFormations().getFormations().values()) {
|
||||
proto.getMutableFormation().addInfo(f.toProto());
|
||||
}
|
||||
|
||||
// Set state
|
||||
var state = proto.getMutableState()
|
||||
.setStorySet(true);
|
||||
|
||||
state.getMutableMail();
|
||||
state.getMutableBattlePass();
|
||||
state.getMutableWorldClassReward();
|
||||
state.getMutableFriendEnergy();
|
||||
state.getMutableMallPackage();
|
||||
state.getMutableAchievement();
|
||||
state.getMutableTravelerDuelQuest()
|
||||
.setType(QuestType.TravelerDuel);
|
||||
state.getMutableTravelerDuelChallengeQuest()
|
||||
.setType(QuestType.TravelerDuelChallenge);
|
||||
state.getMutableStarTower();
|
||||
state.getMutableStarTowerBook();
|
||||
state.getMutableScoreBoss();
|
||||
state.getMutableCharAffinityRewards();
|
||||
|
||||
// Force complete tutorials
|
||||
for (var guide : GameData.getGuideGroupDataTable()) {
|
||||
var info = NewbieInfo.newInstance()
|
||||
.setGroupId(guide.getId())
|
||||
.setStepId(-1);
|
||||
|
||||
acc.addNewbies(info);
|
||||
}
|
||||
|
||||
acc.addNewbies(NewbieInfo.newInstance().setGroupId(GameConstants.INTRO_GUIDE_ID).setStepId(-1));
|
||||
|
||||
//
|
||||
proto.addBoard(410301);
|
||||
proto.setServerTs(Nebula.getCurrentTime());
|
||||
|
||||
// Extra
|
||||
proto.setAchievements(new byte[64]);
|
||||
|
||||
proto.getMutableVampireSurvivorRecord()
|
||||
.getMutableSeason();
|
||||
|
||||
proto.getMutableQuests();
|
||||
proto.getMutableAgent();
|
||||
proto.getMutablePhone();
|
||||
proto.getMutableStory();
|
||||
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package emu.nebula.game.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import emu.nebula.GameConstants;
|
||||
import emu.nebula.proto.AnyOuterClass.Any;
|
||||
import emu.nebula.proto.Public.ChangeInfo;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import us.hebi.quickbuf.ProtoMessage;
|
||||
|
||||
@Getter
|
||||
public class PlayerChangeInfo {
|
||||
private boolean success;
|
||||
private List<Any> list;
|
||||
|
||||
@Setter
|
||||
private Object extraData;
|
||||
|
||||
public PlayerChangeInfo() {
|
||||
this.list = new ArrayList<>();
|
||||
}
|
||||
|
||||
public PlayerChangeInfo setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void add(ProtoMessage<?> proto) {
|
||||
var any = Any.newInstance()
|
||||
.setTypeUrl(GameConstants.PROTO_BASE_TYPE_URL + proto.getClass().getSimpleName())
|
||||
.setValue(proto.toByteArray());
|
||||
|
||||
this.list.add(any);
|
||||
}
|
||||
|
||||
// Proto
|
||||
|
||||
public ChangeInfo toProto() {
|
||||
var proto = ChangeInfo.newInstance();
|
||||
|
||||
for (var any : this.getList()) {
|
||||
proto.addProps(any);
|
||||
}
|
||||
|
||||
return proto;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package emu.nebula.game.player;
|
||||
|
||||
public abstract class PlayerManager {
|
||||
private transient Player player;
|
||||
|
||||
public PlayerManager() {
|
||||
|
||||
}
|
||||
|
||||
public PlayerManager(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return this.player;
|
||||
}
|
||||
|
||||
public void setPlayer(Player player) {
|
||||
if (this.player == null) {
|
||||
this.player = player;
|
||||
}
|
||||
}
|
||||
|
||||
public int getPlayerUid() {
|
||||
return this.getPlayer().getUid();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package emu.nebula.game.player;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import emu.nebula.Nebula;
|
||||
import emu.nebula.game.GameContext;
|
||||
import emu.nebula.game.GameContextModule;
|
||||
import emu.nebula.game.account.Account;
|
||||
import emu.nebula.net.GameSession;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
|
||||
public class PlayerModule extends GameContextModule {
|
||||
private final Int2ObjectMap<Player> cachedPlayers;
|
||||
private final Object2ObjectMap<String, Player> cachedPlayersByAccount;
|
||||
|
||||
public PlayerModule(GameContext gameContext) {
|
||||
super(gameContext);
|
||||
|
||||
this.cachedPlayers = new Int2ObjectOpenHashMap<>();
|
||||
this.cachedPlayersByAccount = new Object2ObjectOpenHashMap<>();
|
||||
}
|
||||
|
||||
public Int2ObjectMap<Player> getCachedPlayers() {
|
||||
return cachedPlayers;
|
||||
}
|
||||
|
||||
private void addToCache(Player player) {
|
||||
this.cachedPlayers.put(player.getUid(), player);
|
||||
this.cachedPlayersByAccount.put(player.getAccountUid(), player);
|
||||
}
|
||||
|
||||
public void removeFromCache(Player player) {
|
||||
this.cachedPlayers.remove(player.getUid());
|
||||
this.cachedPlayersByAccount.remove(player.getAccountUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a player object that has been previously cached. Returns null if the player isnt in the cache.
|
||||
* @param uid User id of the player
|
||||
* @return
|
||||
*/
|
||||
public synchronized Player getCachedPlayerByUid(int uid) {
|
||||
return getCachedPlayers().get(uid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a player object with the given account. Returns null if the player doesnt exist.
|
||||
* @param uid User id of the player
|
||||
* @return
|
||||
*/
|
||||
public synchronized Player getPlayerByAccount(Account account) {
|
||||
// Get player from cache
|
||||
Player player = this.cachedPlayersByAccount.get(account.getUid());
|
||||
|
||||
if (player == null) {
|
||||
// Retrieve player object from database if its not there
|
||||
player = Nebula.getGameDatabase().getObjectByField(Player.class, "accountUid", account.getUid());
|
||||
|
||||
if (player != null) {
|
||||
// Load player
|
||||
player.onLoad();
|
||||
|
||||
// Put in cache
|
||||
this.addToCache(player);
|
||||
}
|
||||
}
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a player with the specified user id.
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public synchronized Player createPlayer(GameSession session, String name, boolean gender) {
|
||||
// Make sure player doesnt already exist
|
||||
if (Nebula.getGameDatabase().checkIfObjectExists(Player.class, "accountUid", session.getAccount().getUid())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Limit name length
|
||||
if (name.length() > 20) {
|
||||
name = name.substring(0, 19);
|
||||
}
|
||||
|
||||
// Create player and save to db
|
||||
var player = new Player(session.getAccount(), name, gender);
|
||||
player.onLoad();
|
||||
player.save();
|
||||
|
||||
// Put in cache
|
||||
this.addToCache(player);
|
||||
|
||||
// Set player for session
|
||||
session.setPlayer(player);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of recent players that have logged on (for followers)
|
||||
* @param player Player that requested this
|
||||
*/
|
||||
public synchronized List<Player> getRandomPlayerList(Player player) {
|
||||
List<Player> list = getCachedPlayers().values().stream().filter(p -> p != player).collect(Collectors.toList());
|
||||
Collections.shuffle(list);
|
||||
return list.stream().limit(15).toList();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user