mirror of
https://github.com/array-in-a-matrix/brainwine.git
synced 2025-04-02 11:11:58 -04:00
Better player (de)serialization
This commit is contained in:
parent
e5e6d42f27
commit
b3a35920a5
7 changed files with 242 additions and 110 deletions
|
@ -10,8 +10,10 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
|
|||
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
|
||||
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
|
||||
import brainwine.gameserver.entity.player.Player;
|
||||
import brainwine.gameserver.serialization.AchievementSerializer;
|
||||
import brainwine.gameserver.util.MathUtils;
|
||||
|
||||
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type", defaultImpl = Achievement.class)
|
||||
|
@ -27,6 +29,7 @@ import brainwine.gameserver.util.MathUtils;
|
|||
@Type(name = "DiscoveryAchievement", value = DiscoveryAchievement.class),
|
||||
@Type(name = "Journeyman", value = JourneymanAchievement.class)
|
||||
})
|
||||
@JsonSerialize(using = AchievementSerializer.class)
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public abstract class Achievement {
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
@ -26,11 +25,11 @@ public class Inventory {
|
|||
// TODO clean up, perhaps just merge with inventory somehow.
|
||||
private final ItemContainer hotbar = new ItemContainer(10);
|
||||
private final ItemContainer accessories = new ItemContainer(20);
|
||||
|
||||
@JsonBackReference
|
||||
private Player player;
|
||||
|
||||
public Inventory(Player player) {
|
||||
protected Inventory() {}
|
||||
|
||||
protected Inventory(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
|
@ -49,6 +48,10 @@ public class Inventory {
|
|||
}
|
||||
}
|
||||
|
||||
protected void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void moveItemToContainer(Item item, ContainerType type, int slot) {
|
||||
boolean accessoriesUpdated = false;
|
||||
hotbar.removeItem(item);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package brainwine.gameserver.entity.player;
|
||||
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -13,12 +12,6 @@ import java.util.Set;
|
|||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JacksonInject;
|
||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonManagedReference;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
import brainwine.gameserver.GameConfiguration;
|
||||
import brainwine.gameserver.GameServer;
|
||||
import brainwine.gameserver.achievements.Achievement;
|
||||
|
@ -71,9 +64,6 @@ import brainwine.gameserver.zone.Chunk;
|
|||
import brainwine.gameserver.zone.MetaBlock;
|
||||
import brainwine.gameserver.zone.Zone;
|
||||
|
||||
// TODO re-evaluate how we handle saving/loading this thing..
|
||||
@JsonIncludeProperties({"name", "email", "password_hash", "auth_tokens", "admin", "experience", "skill_points", "karma",
|
||||
"crowns", "inventory", "statistics", "ignored_hints", "achievements", "skills", "equipped_clothing", "equipped_colors", "current_zone"})
|
||||
public class Player extends Entity implements CommandExecutor {
|
||||
|
||||
public static final int MAX_SKILL_LEVEL = 15;
|
||||
|
@ -87,57 +77,22 @@ public class Player extends Entity implements CommandExecutor {
|
|||
public static final float ENTITY_VISIBILITY_RANGE = 40;
|
||||
public static final float BASE_REGEN_AMOUNT = 0.1F;
|
||||
private static int dialogDiscriminator;
|
||||
|
||||
@JacksonInject("documentId")
|
||||
private final String documentId;
|
||||
|
||||
@JsonProperty("email")
|
||||
private String email;
|
||||
|
||||
@JsonProperty("password_hash")
|
||||
private String password;
|
||||
|
||||
@JsonProperty("auth_tokens")
|
||||
private final List<String> authTokens = new ArrayList<>();
|
||||
|
||||
@JsonProperty("admin")
|
||||
private boolean admin;
|
||||
|
||||
@JsonProperty("experience")
|
||||
private int experience;
|
||||
|
||||
@JsonProperty("skill_points")
|
||||
private int skillPoints;
|
||||
|
||||
@JsonProperty("karma")
|
||||
private int karma;
|
||||
|
||||
@JsonProperty("crowns")
|
||||
private int crowns;
|
||||
|
||||
@JsonManagedReference
|
||||
@JsonProperty("inventory")
|
||||
private final Inventory inventory = new Inventory(this);
|
||||
|
||||
@JsonManagedReference
|
||||
@JsonProperty("statistics")
|
||||
private final PlayerStatistics statistics = new PlayerStatistics(this);
|
||||
|
||||
@JsonProperty("ignored_hints")
|
||||
private final Map<String, Float> ignoredHints = new HashMap<String, Float>();
|
||||
|
||||
@JsonProperty("achievements")
|
||||
private final Set<Achievement> achievements = new HashSet<>();
|
||||
|
||||
@JsonProperty("skills")
|
||||
private final Map<Skill, Integer> skills = new HashMap<>();
|
||||
|
||||
@JsonProperty("equipped_clothing")
|
||||
private final Map<ClothingSlot, Item> clothing = new HashMap<>();
|
||||
|
||||
@JsonProperty("equipped_colors")
|
||||
private final Map<ColorSlot, String> colors = new HashMap<>();
|
||||
|
||||
private Inventory inventory;
|
||||
private PlayerStatistics statistics;
|
||||
private List<String> authTokens;
|
||||
private Set<Achievement> achievements;
|
||||
private Map<String, Float> ignoredHints;
|
||||
private Map<Skill, Integer> skills;
|
||||
private Map<ClothingSlot, Item> equippedClothing;
|
||||
private Map<ColorSlot, String> equippedColors;
|
||||
private final Set<Item> wardrobe = new HashSet<>();
|
||||
private final Map<String, Object> settings = new HashMap<>();
|
||||
private final Set<Integer> activeChunks = new HashSet<>();
|
||||
|
@ -154,24 +109,41 @@ public class Player extends Entity implements CommandExecutor {
|
|||
private Zone nextZone;
|
||||
private Connection connection;
|
||||
|
||||
@ConstructorProperties({"documentId", "name", "current_zone"})
|
||||
public Player(@JacksonInject("documentId") String documentId, String name, Zone zone) {
|
||||
protected Player(String documentId, PlayerConfigFile config) {
|
||||
super(config.getCurrentZone());
|
||||
this.documentId = documentId;
|
||||
this.name = config.getName();
|
||||
this.email = config.getEmail();
|
||||
this.password = config.getPasswordHash();
|
||||
this.admin = config.isAdmin();
|
||||
this.experience = config.getExperience();
|
||||
this.skillPoints = config.getSkillPoints();
|
||||
this.karma = config.getKarma();
|
||||
this.crowns = config.getCrowns();
|
||||
this.inventory = config.getInventory();
|
||||
this.statistics = config.getStatistics();
|
||||
this.authTokens = config.getAuthTokens();
|
||||
this.achievements = config.getAchievements();
|
||||
this.ignoredHints = config.getIgnoredHints();
|
||||
this.skills = config.getSkills();
|
||||
this.equippedClothing = config.getEquippedClothing();
|
||||
this.equippedColors = config.getEquippedColors();
|
||||
inventory.setPlayer(this);
|
||||
statistics.setPlayer(this);
|
||||
}
|
||||
|
||||
public Player(String documentId, String name, Zone zone) {
|
||||
super(zone);
|
||||
|
||||
for(Item item : ItemRegistry.getItems()) {
|
||||
if(item.isClothing()) {
|
||||
wardrobe.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.documentId = documentId;
|
||||
this.name = name;
|
||||
settings.put("hotbar_presets", new ArrayList<>());
|
||||
Map<String, Object> test = new HashMap<>();
|
||||
test.put("fg", true);
|
||||
test.put("to", true);
|
||||
test.put("lo", true);
|
||||
settings.put("appearance", test);
|
||||
this.inventory = new Inventory(this);
|
||||
this.statistics = new PlayerStatistics(this);
|
||||
this.authTokens = new ArrayList<>();
|
||||
this.achievements = new HashSet<>();
|
||||
this.ignoredHints = new HashMap<>();
|
||||
this.skills = new HashMap<>();
|
||||
this.equippedClothing = new HashMap<>();
|
||||
this.equippedColors = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -843,7 +815,7 @@ public class Player extends Entity implements CommandExecutor {
|
|||
return;
|
||||
}
|
||||
|
||||
clothing.put(slot, item);
|
||||
equippedClothing.put(slot, item);
|
||||
zone.sendMessage(new EntityChangeMessage(id, getAppearanceConfig()));
|
||||
}
|
||||
|
||||
|
@ -856,17 +828,17 @@ public class Player extends Entity implements CommandExecutor {
|
|||
}
|
||||
|
||||
public Map<ClothingSlot, Item> getEquippedClothing() {
|
||||
return Collections.unmodifiableMap(clothing);
|
||||
return Collections.unmodifiableMap(equippedClothing);
|
||||
}
|
||||
|
||||
public void setColor(ColorSlot slot, String hex) {
|
||||
// TODO check if the string is actually a valid hex color
|
||||
colors.put(slot, hex);
|
||||
equippedColors.put(slot, hex);
|
||||
zone.sendMessage(new EntityChangeMessage(id, getAppearanceConfig()));
|
||||
}
|
||||
|
||||
public Map<ColorSlot, String> getEquippedColors(){
|
||||
return Collections.unmodifiableMap(colors);
|
||||
public Map<ColorSlot, String> getEquippedColors() {
|
||||
return Collections.unmodifiableMap(equippedColors);
|
||||
}
|
||||
|
||||
public void setSkillLevel(Skill skill, int level) {
|
||||
|
@ -1060,36 +1032,14 @@ public class Player extends Entity implements CommandExecutor {
|
|||
return connection != null && connection.isOpen();
|
||||
}
|
||||
|
||||
@JsonValue
|
||||
public Map<String, Object> getJsonValue() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("email", email);
|
||||
map.put("password_hash", password);
|
||||
map.put("auth_tokens", authTokens);
|
||||
map.put("name", name);
|
||||
map.put("admin", admin);
|
||||
map.put("experience", experience);
|
||||
map.put("skill_points", skillPoints);
|
||||
map.put("karma", karma);
|
||||
map.put("crowns", crowns);
|
||||
map.put("current_zone", zone.getDocumentId());
|
||||
map.put("ignored_hints", ignoredHints);
|
||||
map.put("achievements", achievements);
|
||||
map.put("skills", skills);
|
||||
map.put("equipped_colors", colors);
|
||||
map.put("equipped_clothing", clothing);
|
||||
map.put("inventory", inventory);
|
||||
map.put("statistics", statistics);
|
||||
return map;
|
||||
}
|
||||
|
||||
private Map<String, Object> getAppearanceConfig() {
|
||||
Map<String, Object> appearance = new HashMap<>();
|
||||
for(Entry<ClothingSlot, Item> entry : clothing.entrySet()) {
|
||||
|
||||
for(Entry<ClothingSlot, Item> entry : equippedClothing.entrySet()) {
|
||||
appearance.put(entry.getKey().getId(), entry.getValue().getId());
|
||||
}
|
||||
|
||||
for(Entry<ColorSlot, String> entry : colors.entrySet()) {
|
||||
for(Entry<ColorSlot, String> entry : equippedColors.entrySet()) {
|
||||
appearance.put(entry.getKey().getId(), entry.getValue());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
package brainwine.gameserver.entity.player;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.annotation.Nulls;
|
||||
|
||||
import brainwine.gameserver.achievements.Achievement;
|
||||
import brainwine.gameserver.item.Item;
|
||||
import brainwine.gameserver.zone.Zone;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class PlayerConfigFile {
|
||||
|
||||
private String name;
|
||||
private String email;
|
||||
private String passwordHash;
|
||||
private Zone currentZone;
|
||||
private boolean admin;
|
||||
private int experience;
|
||||
private int skillPoints;
|
||||
private int karma;
|
||||
private int crowns;
|
||||
private Inventory inventory = new Inventory();
|
||||
private PlayerStatistics statistics = new PlayerStatistics();
|
||||
private List<String> authTokens = new ArrayList<>();
|
||||
private Set<Achievement> achievements = new HashSet<>();
|
||||
private Map<String, Float> ignoredHints = new HashMap<>();
|
||||
private Map<Skill, Integer> skills = new HashMap<>();
|
||||
private Map<ClothingSlot, Item> equippedClothing = new HashMap<>();
|
||||
private Map<ColorSlot, String> equippedColors = new HashMap<>();
|
||||
|
||||
public PlayerConfigFile(Player player) {
|
||||
this.name = player.getName();
|
||||
this.email = player.getEmail();
|
||||
this.passwordHash = player.getPassword();
|
||||
this.currentZone = player.getZone();
|
||||
this.admin = player.isAdmin();
|
||||
this.experience = player.getExperience();
|
||||
this.skillPoints = player.getSkillPoints();
|
||||
this.karma = player.getKarma();
|
||||
this.crowns = player.getCrowns();
|
||||
this.inventory = player.getInventory();
|
||||
this.statistics = player.getStatistics();
|
||||
this.authTokens = player.getAuthTokens();
|
||||
this.achievements = player.getAchievements();
|
||||
this.ignoredHints = player.getIgnoredHints();
|
||||
this.skills = player.getSkills();
|
||||
this.equippedClothing = player.getEquippedClothing();
|
||||
this.equippedColors = player.getEquippedColors();
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
private PlayerConfigFile() {}
|
||||
|
||||
@JsonSetter(nulls = Nulls.FAIL)
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public String getPasswordHash() {
|
||||
return passwordHash;
|
||||
}
|
||||
|
||||
public Zone getCurrentZone() {
|
||||
return currentZone;
|
||||
}
|
||||
|
||||
public boolean isAdmin() {
|
||||
return admin;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public List<String> getAuthTokens() {
|
||||
return authTokens;
|
||||
}
|
||||
|
||||
public int getExperience() {
|
||||
return experience;
|
||||
}
|
||||
|
||||
public int getSkillPoints() {
|
||||
return skillPoints;
|
||||
}
|
||||
|
||||
public int getKarma() {
|
||||
return karma;
|
||||
}
|
||||
|
||||
public int getCrowns() {
|
||||
return crowns;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP)
|
||||
public Inventory getInventory() {
|
||||
return inventory;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP)
|
||||
public PlayerStatistics getStatistics() {
|
||||
return statistics;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public Set<Achievement> getAchievements() {
|
||||
return achievements;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public Map<String, Float> getIgnoredHints() {
|
||||
return ignoredHints;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public Map<Skill, Integer> getSkills() {
|
||||
return skills;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public Map<ClothingSlot, Item> getEquippedClothing() {
|
||||
return equippedClothing;
|
||||
}
|
||||
|
||||
@JsonSetter(nulls = Nulls.SKIP, contentNulls = Nulls.SKIP)
|
||||
public Map<ColorSlot, String> getEquippedColors() {
|
||||
return equippedColors;
|
||||
}
|
||||
}
|
|
@ -12,8 +12,6 @@ import org.apache.logging.log4j.LogManager;
|
|||
import org.apache.logging.log4j.Logger;
|
||||
import org.mindrot.jbcrypt.BCrypt;
|
||||
|
||||
import com.fasterxml.jackson.databind.InjectableValues;
|
||||
|
||||
import brainwine.gameserver.GameServer;
|
||||
import brainwine.gameserver.server.pipeline.Connection;
|
||||
import brainwine.shared.JsonHelper;
|
||||
|
@ -53,7 +51,8 @@ public class PlayerManager {
|
|||
String id = file.getName().replace(".json", "");
|
||||
|
||||
try {
|
||||
Player player = JsonHelper.readValue(file, Player.class, new InjectableValues.Std().addValue("documentId", id));
|
||||
PlayerConfigFile configFile = JsonHelper.readValue(file, PlayerConfigFile.class);
|
||||
Player player = new Player(id, configFile);
|
||||
|
||||
if(player.getZone() == null) {
|
||||
player.setZone(GameServer.getInstance().getZoneManager().getRandomZone());
|
||||
|
@ -83,7 +82,7 @@ public class PlayerManager {
|
|||
File file = new File("players", player.getDocumentId() + ".json");
|
||||
|
||||
try {
|
||||
JsonHelper.writeValue(file, player);
|
||||
JsonHelper.writeValue(file, new PlayerConfigFile(player));
|
||||
} catch(Exception e) {
|
||||
logger.error("Could not save player id {}", player.getDocumentId(), e);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@ import java.util.Map.Entry;
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect;
|
||||
import com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility;
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
import brainwine.gameserver.achievements.CraftingAchievement;
|
||||
|
@ -39,13 +39,17 @@ public class PlayerStatistics {
|
|||
private int dungeonsRaided;
|
||||
private int deaths;
|
||||
|
||||
@JsonBackReference
|
||||
@JsonIgnore
|
||||
private Player player;
|
||||
|
||||
@JsonCreator
|
||||
private PlayerStatistics() {}
|
||||
protected PlayerStatistics() {}
|
||||
|
||||
public PlayerStatistics(Player player) {
|
||||
protected PlayerStatistics(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
protected void setPlayer(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
package brainwine.gameserver.serialization;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
|
||||
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||
|
||||
import brainwine.gameserver.achievements.Achievement;
|
||||
|
||||
/**
|
||||
* Seriously, Jackson has the stupidest problems sometimes.
|
||||
*/
|
||||
public class AchievementSerializer extends StdSerializer<Achievement> {
|
||||
|
||||
public static final AchievementSerializer INSTANCE = new AchievementSerializer();
|
||||
private static final long serialVersionUID = 7660825036762291561L;
|
||||
|
||||
protected AchievementSerializer() {
|
||||
super(Achievement.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(Achievement achievement, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||
generator.writeString(achievement.getTitle());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWithType(Achievement achievement, JsonGenerator generator, SerializerProvider provider,
|
||||
TypeSerializer typeSerializer) throws IOException {
|
||||
serialize(achievement, generator, provider);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue