mirror of
https://github.com/array-in-a-matrix/brainwine.git
synced 2025-04-02 11:11:58 -04:00
Update MessagePack & binary serialization through Jackson
This commit is contained in:
parent
9f13408c84
commit
83b0b24a30
66 changed files with 799 additions and 1287 deletions
|
@ -10,8 +10,8 @@ repositories {
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'org.apache.logging.log4j:log4j-api:2.15.0'
|
implementation 'org.apache.logging.log4j:log4j-api:2.15.0'
|
||||||
implementation 'org.apache.logging.log4j:log4j-core:2.15.0'
|
implementation 'org.apache.logging.log4j:log4j-core:2.15.0'
|
||||||
implementation 'org.msgpack:msgpack:0.6.12'
|
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.4'
|
||||||
implementation 'com.fasterxml.jackson.core:jackson-databind:2.12.1'
|
implementation 'org.msgpack:jackson-dataformat-msgpack:0.9.0'
|
||||||
implementation 'org.yaml:snakeyaml:1.27'
|
implementation 'org.yaml:snakeyaml:1.27'
|
||||||
implementation 'org.reflections:reflections:0.9.12'
|
implementation 'org.reflections:reflections:0.9.12'
|
||||||
implementation 'io.netty:netty-all:4.1.58.Final'
|
implementation 'io.netty:netty-all:4.1.58.Final'
|
||||||
|
|
|
@ -9,7 +9,6 @@ import org.apache.logging.log4j.Logger;
|
||||||
import brainwine.gameserver.command.CommandManager;
|
import brainwine.gameserver.command.CommandManager;
|
||||||
import brainwine.gameserver.entity.player.PlayerManager;
|
import brainwine.gameserver.entity.player.PlayerManager;
|
||||||
import brainwine.gameserver.loot.LootManager;
|
import brainwine.gameserver.loot.LootManager;
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
|
||||||
import brainwine.gameserver.prefab.PrefabManager;
|
import brainwine.gameserver.prefab.PrefabManager;
|
||||||
import brainwine.gameserver.server.NetworkRegistry;
|
import brainwine.gameserver.server.NetworkRegistry;
|
||||||
import brainwine.gameserver.server.Server;
|
import brainwine.gameserver.server.Server;
|
||||||
|
@ -38,7 +37,6 @@ public class GameServer {
|
||||||
logger.info("Starting GameServer ...");
|
logger.info("Starting GameServer ...");
|
||||||
CommandManager.init();
|
CommandManager.init();
|
||||||
GameConfiguration.init();
|
GameConfiguration.init();
|
||||||
MessagePackHelper.init();
|
|
||||||
lootManager = new LootManager();
|
lootManager = new LootManager();
|
||||||
prefabManager = new PrefabManager();
|
prefabManager = new PrefabManager();
|
||||||
StaticZoneGenerator.init();
|
StaticZoneGenerator.init();
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class ExportCommand extends Command {
|
||||||
executor.notify("Exporting your prefab ...", ALERT);
|
executor.notify("Exporting your prefab ...", ALERT);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
prefabManager.registerPrefab(name, prefab);
|
prefabManager.addPrefab(name, prefab);
|
||||||
executor.notify(String.format("Your prefab '%s' was successfully exported!", name), ALERT);
|
executor.notify(String.format("Your prefab '%s' was successfully exported!", name), ALERT);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
executor.notify(String.format("An error occured while exporting prefab '%s': %s", name, e.getMessage()), ALERT);
|
executor.notify(String.format("An error occured while exporting prefab '%s': %s", name, e.getMessage()), ALERT);
|
||||||
|
|
|
@ -13,7 +13,7 @@ public abstract class ConfigurableDialog implements DialogComponent {
|
||||||
private final Map<String, Object> config = new HashMap<>();
|
private final Map<String, Object> config = new HashMap<>();
|
||||||
|
|
||||||
public abstract void init();
|
public abstract void init();
|
||||||
public abstract void handleResponse(Player player, String[] input);
|
public abstract void handleResponse(Player player, Object[] input);
|
||||||
|
|
||||||
protected void addSection(DialogSection section) {
|
protected void addSection(DialogSection section) {
|
||||||
List<Map<String, Object>> sections = (List<Map<String, Object>>)config.getOrDefault("sections", new ArrayList<>());
|
List<Map<String, Object>> sections = (List<Map<String, Object>>)config.getOrDefault("sections", new ArrayList<>());
|
||||||
|
|
|
@ -37,14 +37,15 @@ public class RegistrationDialog extends ConfigurableDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void handleResponse(Player player, String[] input) {
|
public void handleResponse(Player player, Object[] input) {
|
||||||
if(input.length != 2) {
|
if(input.length != 2) {
|
||||||
player.alert("Incorrect number of parameters.");
|
player.alert("Incorrect number of parameters.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String email = input[0];
|
// TODO toString() for now, dialog system will be worked anyway.
|
||||||
String password = input[1];
|
String email = input[0].toString();
|
||||||
|
String password = input[1].toString();
|
||||||
|
|
||||||
if(email.length() > maxEmailLength || !emailPattern.matcher(email).matches()) {
|
if(email.length() > maxEmailLength || !emailPattern.matcher(email).matches()) {
|
||||||
player.alert("Please enter a valid e-mail address.");
|
player.alert("Please enter a valid e-mail address.");
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package brainwine.gameserver.entity;
|
package brainwine.gameserver.entity;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum EntityStatus {
|
public enum EntityStatus {
|
||||||
|
|
||||||
EXITING,
|
EXITING,
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package brainwine.gameserver.entity;
|
package brainwine.gameserver.entity;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum EntityType {
|
public enum EntityType {
|
||||||
|
|
||||||
PLAYER(0),
|
PLAYER(0),
|
||||||
|
@ -17,7 +15,7 @@ public enum EntityType {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package brainwine.gameserver.entity;
|
package brainwine.gameserver.entity;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.DefaultEnumValue;
|
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum FacingDirection {
|
public enum FacingDirection {
|
||||||
|
|
||||||
@DefaultEnumValue
|
@JsonEnumDefaultValue
|
||||||
WEST(-1),
|
WEST(-1),
|
||||||
EAST(1);
|
EAST(1);
|
||||||
|
|
||||||
|
@ -17,7 +15,7 @@ public enum FacingDirection {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package brainwine.gameserver.entity.player;
|
package brainwine.gameserver.entity.player;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum ChatType {
|
public enum ChatType {
|
||||||
|
|
||||||
CHAT("c"),
|
CHAT("c"),
|
||||||
|
@ -17,7 +15,7 @@ public enum ChatType {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package brainwine.gameserver.entity.player;
|
package brainwine.gameserver.entity.player;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum ContainerType {
|
public enum ContainerType {
|
||||||
|
|
||||||
INVENTORY("i"),
|
INVENTORY("i"),
|
||||||
|
@ -16,7 +14,7 @@ public enum ContainerType {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,6 @@ package brainwine.gameserver.entity.player;
|
||||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum KarmaLevel {
|
public enum KarmaLevel {
|
||||||
|
|
||||||
GODLY("Godly", 500),
|
GODLY("Godly", 500),
|
||||||
|
@ -28,7 +24,6 @@ public enum KarmaLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonValue
|
@JsonValue
|
||||||
@EnumValue
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package brainwine.gameserver.entity.player;
|
package brainwine.gameserver.entity.player;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum NotificationType {
|
public enum NotificationType {
|
||||||
|
|
||||||
ALERT(1),
|
ALERT(1),
|
||||||
|
@ -25,7 +23,7 @@ public enum NotificationType {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public int getId() {
|
public int getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -318,7 +318,7 @@ public class Player extends Entity implements CommandExecutor {
|
||||||
sendMessage(new DialogMessage(id, dialog));
|
sendMessage(new DialogMessage(id, dialog));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void handleDialogInput(int id, String[] input) {
|
public void handleDialogInput(int id, Object[] input) {
|
||||||
ConfigurableDialog dialog = dialogs.remove(id);
|
ConfigurableDialog dialog = dialogs.remove(id);
|
||||||
|
|
||||||
if(dialog == null) {
|
if(dialog == null) {
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
package brainwine.gameserver.entity.player;
|
package brainwine.gameserver.entity.player;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum Skill {
|
public enum Skill {
|
||||||
|
|
||||||
AGILITY,
|
AGILITY,
|
||||||
|
@ -19,7 +17,7 @@ public enum Skill {
|
||||||
STAMINA,
|
STAMINA,
|
||||||
SURVIVAL;
|
SURVIVAL;
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return toString().toLowerCase();
|
return toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,10 +2,6 @@ package brainwine.gameserver.item;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.DefaultEnumValue;
|
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum Layer {
|
public enum Layer {
|
||||||
|
|
||||||
BASE,
|
BASE,
|
||||||
|
@ -13,7 +9,6 @@ public enum Layer {
|
||||||
FRONT,
|
FRONT,
|
||||||
LIQUID,
|
LIQUID,
|
||||||
|
|
||||||
@DefaultEnumValue
|
|
||||||
@JsonEnumDefaultValue
|
@JsonEnumDefaultValue
|
||||||
NONE;
|
NONE;
|
||||||
}
|
}
|
|
@ -1,11 +1,8 @@
|
||||||
package brainwine.gameserver.item;
|
package brainwine.gameserver.item;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum LootGraphic {
|
public enum LootGraphic {
|
||||||
|
|
||||||
LOOT,
|
LOOT,
|
||||||
|
@ -15,7 +12,7 @@ public enum LootGraphic {
|
||||||
@JsonEnumDefaultValue
|
@JsonEnumDefaultValue
|
||||||
NONE;
|
NONE;
|
||||||
|
|
||||||
@EnumValue
|
@JsonValue
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return toString().toLowerCase();
|
return toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface DefaultEnumValue {}
|
|
|
@ -1,14 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be assigned to a field in an Enumeration.
|
|
||||||
* When packed, the value of the first field with this annotation will be used instead of the ordinal.
|
|
||||||
*/
|
|
||||||
@Target({ElementType.FIELD, ElementType.METHOD})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface EnumValue {}
|
|
|
@ -1,107 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.zip.DataFormatException;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.msgpack.MessagePack;
|
|
||||||
import org.msgpack.packer.BufferPacker;
|
|
||||||
import org.msgpack.unpacker.BufferUnpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.item.Item;
|
|
||||||
import brainwine.gameserver.msgpack.models.AppearanceData;
|
|
||||||
import brainwine.gameserver.msgpack.models.BlockUseData;
|
|
||||||
import brainwine.gameserver.msgpack.models.DialogInputData;
|
|
||||||
import brainwine.gameserver.msgpack.templates.AppearanceDataTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.BlockArrayTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.BlockTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.BlockUseDataTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.ChunkTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.DialogInputDataTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.EnumTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.ItemTemplate;
|
|
||||||
import brainwine.gameserver.msgpack.templates.PrefabTemplate;
|
|
||||||
import brainwine.gameserver.prefab.Prefab;
|
|
||||||
import brainwine.gameserver.util.ReflectionsHelper;
|
|
||||||
import brainwine.gameserver.util.ZipUtils;
|
|
||||||
import brainwine.gameserver.zone.Block;
|
|
||||||
import brainwine.gameserver.zone.Chunk;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Static instance for the MsgPack library.
|
|
||||||
*/
|
|
||||||
public class MessagePackHelper {
|
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
|
||||||
private static final MessagePack messagePack = new MessagePack();
|
|
||||||
|
|
||||||
public static void init() {
|
|
||||||
registerTemplates();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void registerTemplates() {
|
|
||||||
logger.info("Registering MessagePack templates ...");
|
|
||||||
messagePack.register(Item.class, new ItemTemplate());
|
|
||||||
messagePack.register(Block.class, new BlockTemplate());
|
|
||||||
messagePack.register(Block[].class, new BlockArrayTemplate());
|
|
||||||
messagePack.register(Chunk.class, new ChunkTemplate());
|
|
||||||
messagePack.register(Prefab.class, new PrefabTemplate());
|
|
||||||
messagePack.register(BlockUseData.class, new BlockUseDataTemplate());
|
|
||||||
messagePack.register(DialogInputData.class, new DialogInputDataTemplate());
|
|
||||||
messagePack.register(AppearanceData.class, new AppearanceDataTemplate());
|
|
||||||
registerEnumTemplates();
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
|
||||||
private static void registerEnumTemplates() {
|
|
||||||
for(Class<?> clazz : ReflectionsHelper.getTypesAnnotatedWith(RegisterEnum.class)) {
|
|
||||||
messagePack.register(clazz, new EnumTemplate(clazz));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferUnpacker readFile(File file) throws IOException, DataFormatException {
|
|
||||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
|
||||||
bytes = ZipUtils.inflateBytes(bytes);
|
|
||||||
return createBufferUnpacker(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferUnpacker readFiles(File... files) throws IOException, DataFormatException, IndexOutOfBoundsException {
|
|
||||||
byte[] buffer = new byte[Short.MAX_VALUE];
|
|
||||||
int index = 0;
|
|
||||||
|
|
||||||
for(File file : files) {
|
|
||||||
byte[] bytes = Files.readAllBytes(file.toPath());
|
|
||||||
bytes = ZipUtils.inflateBytes(bytes);
|
|
||||||
System.arraycopy(bytes, 0, buffer, index, bytes.length);
|
|
||||||
index += bytes.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = new byte[index];
|
|
||||||
System.arraycopy(buffer, 0, bytes, 0, bytes.length);
|
|
||||||
return createBufferUnpacker(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void writeToFile(File file, Object... objects) throws IOException {
|
|
||||||
BufferPacker packer = createBufferPacker();
|
|
||||||
|
|
||||||
for(Object object : objects) {
|
|
||||||
packer.write(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] bytes = packer.toByteArray();
|
|
||||||
bytes = ZipUtils.deflateBytes(bytes);
|
|
||||||
packer.close();
|
|
||||||
Files.write(file.toPath(), bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferUnpacker createBufferUnpacker(byte[] bytes) {
|
|
||||||
return messagePack.createBufferUnpacker(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BufferPacker createBufferPacker() {
|
|
||||||
return messagePack.createBufferPacker();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enumerations with this annotation will automatically be registered with {@link EnumTemplate}
|
|
||||||
*/
|
|
||||||
@Target({ElementType.TYPE})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface RegisterEnum {}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.models;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extremely lazy, yes...
|
|
||||||
* Lazy, but it does the trick.
|
|
||||||
*/
|
|
||||||
public class AppearanceData extends HashMap<String, Object> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private static final long serialVersionUID = -688912102884421443L;
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.models;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple wrapper to avoid having to force our custom template on object arrays.
|
|
||||||
*/
|
|
||||||
public class BlockUseData {
|
|
||||||
|
|
||||||
private final Object[] data;
|
|
||||||
|
|
||||||
public BlockUseData(Object[] data) {
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object[] getData() {
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.models;
|
|
||||||
|
|
||||||
import brainwine.gameserver.server.requests.DialogRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For {@link DialogRequest}
|
|
||||||
* TODO Figure out more about all this.
|
|
||||||
*/
|
|
||||||
public class DialogInputData {
|
|
||||||
|
|
||||||
private String dialogName;
|
|
||||||
private int dialogId;
|
|
||||||
private String[] inputData;
|
|
||||||
private String action;
|
|
||||||
|
|
||||||
public DialogInputData(String dialogName) {
|
|
||||||
this.dialogName = dialogName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DialogInputData(int dialogId, String[] inputData) {
|
|
||||||
this.dialogId = dialogId;
|
|
||||||
this.inputData = inputData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public DialogInputData(int dialogId, String action) {
|
|
||||||
this.dialogId = dialogId;
|
|
||||||
this.action = action;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isType1() {
|
|
||||||
return dialogName != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isType2() {
|
|
||||||
return dialogId != 0 && inputData != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isType3() {
|
|
||||||
return dialogId != 0 && action != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDialogName() {
|
|
||||||
return dialogName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDialogId() {
|
|
||||||
return dialogId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String[] getInputData() {
|
|
||||||
return inputData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getAction() {
|
|
||||||
return action;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.models.AppearanceData;
|
|
||||||
|
|
||||||
public class AppearanceDataTemplate extends AbstractTemplate<AppearanceData> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, AppearanceData data, boolean required) throws IOException {
|
|
||||||
if(data == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AppearanceData read(Unpacker unpacker, AppearanceData to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unpacker.getNextType() != ValueType.MAP) {
|
|
||||||
throw new MessageTypeException("Invalid data type");
|
|
||||||
}
|
|
||||||
|
|
||||||
AppearanceData data = new AppearanceData();
|
|
||||||
int numEntries = unpacker.readMapBegin();
|
|
||||||
|
|
||||||
for(int i = 0; i < numEntries; i++) {
|
|
||||||
String key = unpacker.readString();
|
|
||||||
Object value = null;
|
|
||||||
|
|
||||||
if(unpacker.getNextType() == ValueType.RAW) {
|
|
||||||
value = unpacker.readString();
|
|
||||||
} else if(unpacker.getNextType() == ValueType.INTEGER) {
|
|
||||||
value = unpacker.readInt();
|
|
||||||
} else {
|
|
||||||
throw new MessageTypeException("Invalid data type");
|
|
||||||
}
|
|
||||||
|
|
||||||
data.put(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readMapEnd();
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.zone.Block;
|
|
||||||
|
|
||||||
public class BlockArrayTemplate extends AbstractTemplate<Block[]> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, Block[] blocks, boolean required) throws IOException {
|
|
||||||
if(blocks == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeArrayBegin(blocks.length * 3);
|
|
||||||
|
|
||||||
for(Block block : blocks) {
|
|
||||||
packer.write(block);
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeArrayEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Block[] read(Unpacker unpacker, Block[] to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block[] blocks = new Block[unpacker.readArrayBegin() / 3];
|
|
||||||
|
|
||||||
for(int i = 0; i < blocks.length; i++) {
|
|
||||||
blocks[i] = unpacker.read(Block.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayEnd();
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,41 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.zone.Block;
|
|
||||||
|
|
||||||
public class BlockTemplate extends AbstractTemplate<Block> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, Block block, boolean required) throws IOException {
|
|
||||||
if(block == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(block.getBaseItem().getId() | (((block.getLiquidItem().getId() & 255) << 8) | ((block.getLiquidMod() & 31) << 16)));
|
|
||||||
packer.write(block.getBackItem().getId() | ((block.getBackMod() & 31) << 16));
|
|
||||||
packer.write(block.getFrontItem().getId() | ((block.getFrontMod() & 31) << 16));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Block read(Unpacker unpacker, Block to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int base = unpacker.readInt();
|
|
||||||
int back = unpacker.readInt();
|
|
||||||
int front = unpacker.readInt();
|
|
||||||
return new Block(base & 15, back & 65535, back >> 16 & 31, front & 65535, front >> 16 & 31, base >> 8 & 255, base >> 16 & 31);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,71 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.models.BlockUseData;
|
|
||||||
|
|
||||||
public class BlockUseDataTemplate extends AbstractTemplate<BlockUseData> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, BlockUseData data, boolean required) throws IOException {
|
|
||||||
if(data == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(data.getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BlockUseData read(Unpacker unpacker, BlockUseData to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unpacker.getNextType() == ValueType.ARRAY) {
|
|
||||||
Object[] data = new Object[unpacker.readArrayBegin()];
|
|
||||||
|
|
||||||
for(int i = 0; i < data.length; i++) {
|
|
||||||
data[i] = readObject(unpacker);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayEnd();
|
|
||||||
return new BlockUseData(data);
|
|
||||||
} else if(unpacker.getNextType() == ValueType.MAP) {
|
|
||||||
Object[] data = new Object[unpacker.readMapBegin()];
|
|
||||||
|
|
||||||
for(int i = 0; i < data.length; i++) {
|
|
||||||
unpacker.readString(); // Key, ignore
|
|
||||||
data[i] = readObject(unpacker);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readMapEnd();
|
|
||||||
return new BlockUseData(data);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MessageTypeException("Invalid data type");
|
|
||||||
}
|
|
||||||
|
|
||||||
private Object readObject(Unpacker unpacker) throws IOException {
|
|
||||||
switch(unpacker.getNextType()) {
|
|
||||||
case RAW:
|
|
||||||
return unpacker.readString();
|
|
||||||
case INTEGER:
|
|
||||||
return unpacker.readInt();
|
|
||||||
case FLOAT:
|
|
||||||
return unpacker.readFloat();
|
|
||||||
default:
|
|
||||||
throw new MessageTypeException("Invalid data type");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,57 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.zone.Block;
|
|
||||||
import brainwine.gameserver.zone.Chunk;
|
|
||||||
|
|
||||||
public class ChunkTemplate extends AbstractTemplate<Chunk> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, Chunk chunk, boolean required) throws IOException {
|
|
||||||
if(chunk == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block[] blocks = chunk.getBlocks();
|
|
||||||
packer.writeArrayBegin(5);
|
|
||||||
packer.write(chunk.getX());
|
|
||||||
packer.write(chunk.getY());
|
|
||||||
packer.write(chunk.getWidth());
|
|
||||||
packer.write(chunk.getHeight());
|
|
||||||
packer.write(blocks);
|
|
||||||
packer.writeArrayEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Chunk read(Unpacker unpacker, Chunk to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayBegin();
|
|
||||||
int x = unpacker.readInt();
|
|
||||||
int y = unpacker.readInt();
|
|
||||||
int width = unpacker.readInt();
|
|
||||||
int height = unpacker.readInt();
|
|
||||||
Block[] blocks = unpacker.read(Block[].class);
|
|
||||||
Chunk chunk = new Chunk(x, y, width, height);
|
|
||||||
|
|
||||||
for(int i = 0; i < blocks.length; i++) {
|
|
||||||
chunk.setBlock(i, blocks[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayEnd();
|
|
||||||
return chunk;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.models.DialogInputData;
|
|
||||||
|
|
||||||
public class DialogInputDataTemplate extends AbstractTemplate<DialogInputData> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, DialogInputData data, boolean required) throws IOException {
|
|
||||||
if(data == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.isType1()) {
|
|
||||||
packer.write(data.getDialogName());
|
|
||||||
} else if(data.isType2()) {
|
|
||||||
packer.write(data.getDialogId());
|
|
||||||
packer.write(data.getInputData());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DialogInputData read(Unpacker unpacker, DialogInputData to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(unpacker.getNextType() == ValueType.RAW) {
|
|
||||||
String dialogName = unpacker.readString();
|
|
||||||
unpacker.readValue(); // TODO find out if this is the action, or just garbage data.
|
|
||||||
return new DialogInputData(dialogName);
|
|
||||||
} else if(unpacker.getNextType() == ValueType.INTEGER) {
|
|
||||||
int id = unpacker.readInt();
|
|
||||||
|
|
||||||
if(unpacker.getNextType() == ValueType.RAW) {
|
|
||||||
return new DialogInputData(id, unpacker.readString());
|
|
||||||
} else if(unpacker.getNextType() == ValueType.ARRAY) {
|
|
||||||
return new DialogInputData(id, unpacker.read(String[].class));
|
|
||||||
}
|
|
||||||
|
|
||||||
int numEntries = unpacker.readMapBegin();
|
|
||||||
String[] input = new String[numEntries];
|
|
||||||
|
|
||||||
for(int i = 0; i < numEntries; i++) {
|
|
||||||
unpacker.readString(); // Key, ignore
|
|
||||||
input[i] = unpacker.readString();
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readMapEnd();
|
|
||||||
return new DialogInputData(id, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MessageTypeException("Invalid data type");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.DefaultEnumValue;
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public class EnumTemplate<T> extends AbstractTemplate<T> {
|
|
||||||
|
|
||||||
private final Map<T, Object> ids = new HashMap<>();
|
|
||||||
private final Map<Object, T> values = new HashMap<>();
|
|
||||||
private T defaultValue;
|
|
||||||
|
|
||||||
public EnumTemplate(Class<T> type) {
|
|
||||||
T[] entries = type.getEnumConstants();
|
|
||||||
|
|
||||||
for(Field field : type.getFields()) {
|
|
||||||
if(field.getType() == type && field.isAnnotationPresent(DefaultEnumValue.class)) {
|
|
||||||
try {
|
|
||||||
defaultValue = (T)field.get(type);
|
|
||||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
|
||||||
throw new MessageTypeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(field.isAnnotationPresent(EnumValue.class)) {
|
|
||||||
try {
|
|
||||||
for(T entry : entries) {
|
|
||||||
Object id = field.get(entry);
|
|
||||||
ids.put(entry, id);
|
|
||||||
values.put(id, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} catch (IllegalArgumentException | IllegalAccessException e) {
|
|
||||||
throw new MessageTypeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(Method method : type.getMethods()) {
|
|
||||||
if(method.isAnnotationPresent(EnumValue.class)) {
|
|
||||||
try {
|
|
||||||
for(T entry : entries) {
|
|
||||||
Object id = method.invoke(entry);
|
|
||||||
ids.put(entry, id);
|
|
||||||
values.put(id, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new MessageTypeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < entries.length; i++) {
|
|
||||||
ids.put(entries[i], i);
|
|
||||||
values.put(i, entries[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, T target, boolean required) throws IOException {
|
|
||||||
if(target == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dangerous, might throw an NPE
|
|
||||||
packer.write(ids.get(target));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T read(Unpacker unpacker, T to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
ValueType next = unpacker.getNextType();
|
|
||||||
|
|
||||||
if(next == ValueType.INTEGER) {
|
|
||||||
return values.getOrDefault(unpacker.readInt(), defaultValue);
|
|
||||||
} else if(next == ValueType.RAW) {
|
|
||||||
return values.getOrDefault(unpacker.readString(), defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new MessageTypeException("Unsupported enum id type");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.item.Item;
|
|
||||||
import brainwine.gameserver.item.ItemRegistry;
|
|
||||||
|
|
||||||
public class ItemTemplate extends AbstractTemplate<Item> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, Item item, boolean required) throws IOException {
|
|
||||||
if(item == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(item.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Item read(Unpacker unpacker, Item to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ItemRegistry.getItem(unpacker.readInt());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,50 +0,0 @@
|
||||||
package brainwine.gameserver.msgpack.templates;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.MessageTypeException;
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
import org.msgpack.template.AbstractTemplate;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.prefab.Prefab;
|
|
||||||
import brainwine.gameserver.zone.Block;
|
|
||||||
|
|
||||||
public class PrefabTemplate extends AbstractTemplate<Prefab> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(Packer packer, Prefab prefab, boolean required) throws IOException {
|
|
||||||
if(prefab == null) {
|
|
||||||
if(required) {
|
|
||||||
throw new MessageTypeException("Attempted to write null");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.writeNil();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(prefab.getWidth());
|
|
||||||
packer.write(prefab.getHeight());
|
|
||||||
packer.write(prefab.getBlocks());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Prefab read(Unpacker unpacker, Prefab to, boolean required) throws IOException {
|
|
||||||
if(!required && unpacker.trySkipNil()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
int width = unpacker.readInt();
|
|
||||||
int height = unpacker.readInt();
|
|
||||||
Block[] blocks = unpacker.read(Block[].class);
|
|
||||||
|
|
||||||
if(to != null) {
|
|
||||||
to.setWidth(width);
|
|
||||||
to.setHeight(height);
|
|
||||||
to.setBlocks(blocks);
|
|
||||||
return to;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Prefab(width, height, blocks);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,60 +4,37 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import brainwine.gameserver.GameServer;
|
import brainwine.gameserver.GameServer;
|
||||||
import brainwine.gameserver.item.Item;
|
import brainwine.gameserver.item.Item;
|
||||||
import brainwine.gameserver.util.WeightedMap;
|
import brainwine.gameserver.util.WeightedMap;
|
||||||
import brainwine.gameserver.zone.Block;
|
import brainwine.gameserver.zone.Block;
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
|
||||||
public class Prefab {
|
public class Prefab {
|
||||||
|
|
||||||
@JsonProperty("dungeon")
|
|
||||||
private boolean dungeon;
|
private boolean dungeon;
|
||||||
|
|
||||||
@JsonProperty("ruin")
|
|
||||||
private boolean ruin;
|
private boolean ruin;
|
||||||
|
|
||||||
@JsonProperty("loot")
|
|
||||||
private boolean loot;
|
private boolean loot;
|
||||||
|
|
||||||
@JsonProperty("decay")
|
|
||||||
private boolean decay;
|
private boolean decay;
|
||||||
|
|
||||||
@JsonProperty("mirrorable")
|
|
||||||
private boolean mirrorable;
|
private boolean mirrorable;
|
||||||
|
private int width;
|
||||||
@JsonProperty("replace")
|
private int height;
|
||||||
|
private Block[] blocks;
|
||||||
private Map<Item, WeightedMap<Item>> replacements = new HashMap<>();
|
private Map<Item, WeightedMap<Item>> replacements = new HashMap<>();
|
||||||
|
|
||||||
@JsonProperty("corresponding_replace")
|
|
||||||
private Map<Item, CorrespondingReplacement> correspondingReplacements = new HashMap<>();
|
private Map<Item, CorrespondingReplacement> correspondingReplacements = new HashMap<>();
|
||||||
|
|
||||||
@JsonProperty("metadata")
|
|
||||||
private Map<Integer, Map<String, Object>> metadata = new HashMap<>();
|
private Map<Integer, Map<String, Object>> metadata = new HashMap<>();
|
||||||
|
|
||||||
@JsonIgnore
|
protected Prefab(PrefabConfig config, PrefabBlockData blockData) {
|
||||||
private int width;
|
this(blockData.getWidth(), blockData.getHeight(), blockData.getBlocks(), config.getMetadata());
|
||||||
|
dungeon = config.isDungeon();
|
||||||
@JsonIgnore
|
ruin = config.isRuin();
|
||||||
private int height;
|
loot = config.hasLoot();
|
||||||
|
decay = config.hasDecay();
|
||||||
@JsonIgnore
|
mirrorable = config.isMirrorable();
|
||||||
private Block[] blocks;
|
replacements = config.getReplacements();
|
||||||
|
correspondingReplacements = config.getCorrespondingReplacements();
|
||||||
@JsonCreator
|
|
||||||
private Prefab() {}
|
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public Prefab(int width, int height, Block[] blocks) {
|
|
||||||
this(width, height, blocks, new HashMap<>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
|
||||||
public Prefab(int width, int height, Block[] blocks, Map<Integer, Map<String, Object>> metadata) {
|
public Prefab(int width, int height, Block[] blocks, Map<Integer, Map<String, Object>> metadata) {
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
|
@ -89,6 +66,18 @@ public class Prefab {
|
||||||
public boolean isMirrorable() {
|
public boolean isMirrorable() {
|
||||||
return mirrorable;
|
return mirrorable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] getBlocks() {
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Object> getMetadata(int index) {
|
public Map<String, Object> getMetadata(int index) {
|
||||||
return metadata.get(index);
|
return metadata.get(index);
|
||||||
|
@ -105,28 +94,4 @@ public class Prefab {
|
||||||
public Map<Item, CorrespondingReplacement> getCorrespondingReplacements() {
|
public Map<Item, CorrespondingReplacement> getCorrespondingReplacements() {
|
||||||
return correspondingReplacements;
|
return correspondingReplacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setWidth(int width) {
|
|
||||||
this.width = width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeight(int height) {
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBlocks(Block[] blocks) {
|
|
||||||
this.blocks = blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block[] getBlocks() {
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package brainwine.gameserver.prefab;
|
||||||
|
|
||||||
|
import java.beans.ConstructorProperties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
import brainwine.gameserver.zone.Block;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class PrefabBlockData {
|
||||||
|
|
||||||
|
private int width;
|
||||||
|
private int height;
|
||||||
|
private Block[] blocks;
|
||||||
|
|
||||||
|
protected PrefabBlockData(Prefab prefab) {
|
||||||
|
this(prefab.getWidth(), prefab.getHeight(), prefab.getBlocks());
|
||||||
|
}
|
||||||
|
|
||||||
|
@ConstructorProperties({"width", "height", "blocks"})
|
||||||
|
public PrefabBlockData(int width, int height, Block[] blocks) {
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
this.blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Block[] getBlocks() {
|
||||||
|
return blocks;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package brainwine.gameserver.prefab;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
|
||||||
|
import brainwine.gameserver.item.Item;
|
||||||
|
import brainwine.gameserver.util.WeightedMap;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class PrefabConfig {
|
||||||
|
|
||||||
|
@JsonProperty("dungeon")
|
||||||
|
private boolean dungeon;
|
||||||
|
|
||||||
|
@JsonProperty("ruin")
|
||||||
|
private boolean ruin;
|
||||||
|
|
||||||
|
@JsonProperty("loot")
|
||||||
|
private boolean loot;
|
||||||
|
|
||||||
|
@JsonProperty("decay")
|
||||||
|
private boolean decay;
|
||||||
|
|
||||||
|
@JsonProperty("mirrorable")
|
||||||
|
private boolean mirrorable;
|
||||||
|
|
||||||
|
@JsonProperty("replace")
|
||||||
|
private Map<Item, WeightedMap<Item>> replacements = new HashMap<>();
|
||||||
|
|
||||||
|
@JsonProperty("corresponding_replace")
|
||||||
|
private Map<Item, CorrespondingReplacement> correspondingReplacements = new HashMap<>();
|
||||||
|
|
||||||
|
@JsonProperty("metadata")
|
||||||
|
private Map<Integer, Map<String, Object>> metadata = new HashMap<>();
|
||||||
|
|
||||||
|
@JsonCreator
|
||||||
|
private PrefabConfig() {}
|
||||||
|
|
||||||
|
protected PrefabConfig(Prefab prefab) {
|
||||||
|
dungeon = prefab.isDungeon();
|
||||||
|
ruin = prefab.isRuin();
|
||||||
|
loot = prefab.hasLoot();
|
||||||
|
decay = prefab.hasDecay();
|
||||||
|
mirrorable = prefab.isMirrorable();
|
||||||
|
replacements = prefab.getReplacements();
|
||||||
|
correspondingReplacements = prefab.getCorrespondingReplacements();
|
||||||
|
metadata = prefab.getMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDungeon() {
|
||||||
|
return dungeon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRuin() {
|
||||||
|
return ruin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasLoot() {
|
||||||
|
return loot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDecay() {
|
||||||
|
return decay;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMirrorable() {
|
||||||
|
return mirrorable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Integer, Map<String, Object>> getMetadata() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Item, WeightedMap<Item>> getReplacements() {
|
||||||
|
return replacements;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<Item, CorrespondingReplacement> getCorrespondingReplacements() {
|
||||||
|
return correspondingReplacements;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,24 +9,32 @@ import java.util.Set;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.msgpack.unpacker.BufferUnpacker;
|
import org.msgpack.core.MessagePack;
|
||||||
|
import org.msgpack.core.MessageUnpacker;
|
||||||
|
import org.msgpack.jackson.dataformat.MessagePackFactory;
|
||||||
import org.reflections.Reflections;
|
import org.reflections.Reflections;
|
||||||
import org.reflections.scanners.ResourcesScanner;
|
import org.reflections.scanners.ResourcesScanner;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
|
||||||
|
import brainwine.gameserver.serialization.BlockDeserializer;
|
||||||
|
import brainwine.gameserver.serialization.BlockSerializer;
|
||||||
|
import brainwine.gameserver.util.ZipUtils;
|
||||||
|
import brainwine.gameserver.zone.Block;
|
||||||
import brainwine.shared.JsonHelper;
|
import brainwine.shared.JsonHelper;
|
||||||
|
|
||||||
public class PrefabManager {
|
public class PrefabManager {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
private static final Logger logger = LogManager.getLogger();
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper(new MessagePackFactory())
|
||||||
|
.registerModule(new SimpleModule()
|
||||||
|
.addDeserializer(Block.class, BlockDeserializer.INSTANCE)
|
||||||
|
.addSerializer(BlockSerializer.INSTANCE));
|
||||||
private final File dataDir = new File("prefabs");
|
private final File dataDir = new File("prefabs");
|
||||||
private final Map<String, Prefab> prefabs = new HashMap<>();
|
private final Map<String, Prefab> prefabs = new HashMap<>();
|
||||||
|
|
||||||
public PrefabManager() {
|
public PrefabManager() {
|
||||||
loadPrefabs();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadPrefabs() {
|
|
||||||
logger.info("Loading prefabs ...");
|
logger.info("Loading prefabs ...");
|
||||||
|
|
||||||
if(!dataDir.exists()) {
|
if(!dataDir.exists()) {
|
||||||
|
@ -60,34 +68,49 @@ public class PrefabManager {
|
||||||
|
|
||||||
private void loadPrefab(File file) {
|
private void loadPrefab(File file) {
|
||||||
String name = file.getName();
|
String name = file.getName();
|
||||||
File configFile = new File(file, "config.json");
|
File legacyBlocksFile = new File(file, "blocks.cmp");
|
||||||
|
File blocksFile = new File(file, "blocks.dat");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Prefab prefab = JsonHelper.readValue(configFile, Prefab.class);
|
PrefabBlockData blockData = null;
|
||||||
BufferUnpacker unpacker = MessagePackHelper.readFile(new File(file, "blocks.cmp"));
|
|
||||||
unpacker.read(prefab);
|
if(legacyBlocksFile.exists() && !blocksFile.exists()) {
|
||||||
unpacker.close();
|
logger.info("Updating blocks file for prefab '{}' ...", name);
|
||||||
prefabs.put(name, prefab);
|
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(
|
||||||
|
ZipUtils.inflateBytes(Files.readAllBytes(legacyBlocksFile.toPath())));
|
||||||
|
int width = unpacker.unpackInt();
|
||||||
|
int height = unpacker.unpackInt();
|
||||||
|
Block[] blocks = new Block[unpacker.unpackArrayHeader() / 3];
|
||||||
|
|
||||||
|
for(int i = 0; i < blocks.length; i++) {
|
||||||
|
blocks[i] = new Block(unpacker.unpackInt(), unpacker.unpackInt(), unpacker.unpackInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
blockData = new PrefabBlockData(width, height, blocks);
|
||||||
|
Files.write(blocksFile.toPath(), ZipUtils.deflateBytes(mapper.writeValueAsBytes(blockData)));
|
||||||
|
legacyBlocksFile.delete();
|
||||||
|
} else {
|
||||||
|
blockData = mapper.readValue(ZipUtils.inflateBytes(Files.readAllBytes(blocksFile.toPath())), PrefabBlockData.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
PrefabConfig config = JsonHelper.readValue(new File(file, "config.json"), PrefabConfig.class);
|
||||||
|
prefabs.put(name, new Prefab(config, blockData));
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
logger.error("Could not load prefab {}:", name, e);
|
logger.error("Could not load prefab {}:", name, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void registerPrefab(String name, Prefab structure) throws Exception {
|
public void addPrefab(String name, Prefab prefab) throws Exception {
|
||||||
if(prefabs.containsKey(name)) {
|
if(prefabs.containsKey(name)) {
|
||||||
logger.warn("Duplicate prefab name: {}", name);
|
logger.warn("Duplicate prefab name: {}", name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
savePrefab(name, structure);
|
File prefabDir = new File(dataDir, name);
|
||||||
prefabs.put(name, structure);
|
prefabDir.mkdirs();
|
||||||
}
|
JsonHelper.writeValue(new File(prefabDir, "config.json"), new PrefabConfig(prefab));
|
||||||
|
Files.write(new File(prefabDir, "blocks.dat").toPath(), ZipUtils.deflateBytes(mapper.writeValueAsBytes(new PrefabBlockData(prefab))));
|
||||||
private void savePrefab(String name, Prefab structure) throws Exception {
|
prefabs.put(name, prefab);
|
||||||
File outputDir = new File(dataDir, name);
|
|
||||||
outputDir.mkdirs();
|
|
||||||
MessagePackHelper.writeToFile(new File(outputDir, "blocks.cmp"), structure);
|
|
||||||
JsonHelper.writeValue(new File(outputDir, "config.json"), structure);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Prefab getPrefab(String name) {
|
public Prefab getPrefab(String name) {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package brainwine.gameserver.serialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.zone.Block;
|
||||||
|
|
||||||
|
public class BlockDeserializer extends StdDeserializer<Block> {
|
||||||
|
|
||||||
|
public static final BlockDeserializer INSTANCE = new BlockDeserializer();
|
||||||
|
private static final long serialVersionUID = 4595727432327616509L;
|
||||||
|
|
||||||
|
protected BlockDeserializer() {
|
||||||
|
super(Block.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Block deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
|
||||||
|
int base = parser.getIntValue();
|
||||||
|
int back = parser.nextIntValue(0);
|
||||||
|
int front = parser.nextIntValue(0);
|
||||||
|
return new Block(base, back, front);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
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.ser.std.StdSerializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.zone.Block;
|
||||||
|
|
||||||
|
public class BlockSerializer extends StdSerializer<Block> {
|
||||||
|
|
||||||
|
public static final BlockSerializer INSTANCE = new BlockSerializer();
|
||||||
|
private static final long serialVersionUID = 4060486562629926309L;
|
||||||
|
|
||||||
|
protected BlockSerializer() {
|
||||||
|
super(Block.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Block block, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||||
|
generator.writeNumber(block.getBase());
|
||||||
|
generator.writeNumber(block.getBack());
|
||||||
|
generator.writeNumber(block.getFront());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
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.ser.std.StdSerializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.item.Item;
|
||||||
|
|
||||||
|
public class ItemCodeSerializer extends StdSerializer<Item> {
|
||||||
|
|
||||||
|
public static final ItemCodeSerializer INSTANCE = new ItemCodeSerializer();
|
||||||
|
private static final long serialVersionUID = 8938614385421916365L;
|
||||||
|
|
||||||
|
protected ItemCodeSerializer() {
|
||||||
|
super(Item.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Item item, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||||
|
generator.writeNumber(item.getId());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package brainwine.gameserver.serialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
|
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||||
|
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.server.Message;
|
||||||
|
|
||||||
|
public class MessageSerializer extends StdSerializer<Message> {
|
||||||
|
|
||||||
|
public static final MessageSerializer INSTANCE = new MessageSerializer();
|
||||||
|
private static final long serialVersionUID = 2310652788158728087L;
|
||||||
|
|
||||||
|
protected MessageSerializer() {
|
||||||
|
super(Message.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Message message, JsonGenerator generator, SerializerProvider serializers) throws IOException {
|
||||||
|
Field[] fields = message.getClass().getFields();
|
||||||
|
|
||||||
|
try {
|
||||||
|
if(message.isPrepacked()) {
|
||||||
|
if(fields.length != 1 || !Collection.class.isAssignableFrom(fields[0].getType())) {
|
||||||
|
throw new IOException("Invalid prepacked message.");
|
||||||
|
}
|
||||||
|
|
||||||
|
generator.writeObject(fields[0].get(message));
|
||||||
|
} else {
|
||||||
|
List<Object> fieldValues = new ArrayList<>();
|
||||||
|
|
||||||
|
for(Field field : fields) {
|
||||||
|
fieldValues.add(field.get(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
if(message.isCollection()) {
|
||||||
|
generator.writeObject(Arrays.asList(fieldValues));
|
||||||
|
} else {
|
||||||
|
generator.writeObject(fieldValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(IllegalArgumentException | IllegalAccessException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
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.ser.std.StdSerializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.zone.Chunk;
|
||||||
|
|
||||||
|
public class NetworkChunkSerializer extends StdSerializer<Chunk> {
|
||||||
|
|
||||||
|
public static final NetworkChunkSerializer INSTANCE = new NetworkChunkSerializer();
|
||||||
|
private static final long serialVersionUID = -1573014029866696503L;
|
||||||
|
|
||||||
|
protected NetworkChunkSerializer() {
|
||||||
|
super(Chunk.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serialize(Chunk chunk, JsonGenerator generator, SerializerProvider provider) throws IOException {
|
||||||
|
generator.writeStartArray();
|
||||||
|
generator.writeNumber(chunk.getX());
|
||||||
|
generator.writeNumber(chunk.getY());
|
||||||
|
generator.writeNumber(chunk.getWidth());
|
||||||
|
generator.writeNumber(chunk.getHeight());
|
||||||
|
generator.writeObject(chunk.getBlocks());
|
||||||
|
generator.writeEndArray();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
package brainwine.gameserver.serialization;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.core.JsonToken;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
|
||||||
|
|
||||||
|
import brainwine.gameserver.server.OptionalField;
|
||||||
|
import brainwine.gameserver.server.Request;
|
||||||
|
|
||||||
|
public class RequestDeserializer extends StdDeserializer<Request> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 42527921659694141L;
|
||||||
|
|
||||||
|
public RequestDeserializer(Class<? extends Request> type) {
|
||||||
|
super(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Request deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
|
||||||
|
try {
|
||||||
|
Request request = (Request)_valueClass.newInstance();
|
||||||
|
Field[] fields = request.getClass().getFields();
|
||||||
|
|
||||||
|
if(parser.currentToken() != JsonToken.START_ARRAY) {
|
||||||
|
throw new IOException("Got invalid token, expected START_ARRAY");
|
||||||
|
}
|
||||||
|
|
||||||
|
for(Field field : fields) {
|
||||||
|
boolean required = field.getAnnotation(OptionalField.class) == null;
|
||||||
|
JsonToken token = parser.nextToken();
|
||||||
|
|
||||||
|
if(token == JsonToken.VALUE_NULL) {
|
||||||
|
if(required) {
|
||||||
|
throw new IOException("Value is null, but field is required!");
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
} else if(token == JsonToken.END_ARRAY) {
|
||||||
|
if(required) {
|
||||||
|
throw new IOException("Array is end, but field is required!");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object value = context.findRootValueDeserializer(context.constructType(field.getGenericType())).deserialize(parser, context);
|
||||||
|
field.set(request, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return request;
|
||||||
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
throw new IOException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package brainwine.gameserver.serialization;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.BeanDescription;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationConfig;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier;
|
||||||
|
|
||||||
|
import brainwine.gameserver.server.Request;
|
||||||
|
|
||||||
|
public class RequestDeserializerModifier extends BeanDeserializerModifier {
|
||||||
|
|
||||||
|
public static final RequestDeserializerModifier INSTANCE = new RequestDeserializerModifier();
|
||||||
|
|
||||||
|
private RequestDeserializerModifier() {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
|
||||||
|
Class<?> clazz = beanDesc.getBeanClass();
|
||||||
|
|
||||||
|
if(Request.class.isAssignableFrom(clazz)) {
|
||||||
|
return new RequestDeserializer((Class<? extends Request>)clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deserializer;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,43 +1,10 @@
|
||||||
package brainwine.gameserver.server;
|
package brainwine.gameserver.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.msgpack.packer.Packer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Messages are outgoing packets to the client.
|
* Messages are outgoing packets to the client.
|
||||||
*/
|
*/
|
||||||
public abstract class Message {
|
public abstract class Message {
|
||||||
|
|
||||||
public void pack(Packer packer) throws IOException, IllegalArgumentException, IllegalAccessException {
|
|
||||||
Field[] fields = getClass().getFields();
|
|
||||||
|
|
||||||
if(isPrepacked()) {
|
|
||||||
if(fields.length != 1 || !Collection.class.isAssignableFrom(fields[0].getType())) {
|
|
||||||
throw new IOException("Prepacked messages may only contain 1 field that must be a Collection.");
|
|
||||||
}
|
|
||||||
|
|
||||||
packer.write(fields[0].get(this));
|
|
||||||
} else {
|
|
||||||
List<Object> data = new ArrayList<>();
|
|
||||||
|
|
||||||
for(Field field : fields) {
|
|
||||||
data.add(field.get(this));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(isCollection()) {
|
|
||||||
packer.write(Arrays.asList(data));
|
|
||||||
} else {
|
|
||||||
packer.write(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isJson() {
|
public boolean isJson() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -140,12 +140,8 @@ public class NetworkRegistry {
|
||||||
requests.put(id, type);
|
requests.put(id, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Request instantiateRequest(int id) throws InstantiationException, IllegalAccessException {
|
public static Class<? extends Request> getRequestClass(int id){
|
||||||
if(!requests.containsKey(id)) {
|
return requests.get(id);
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return requests.get(id).newInstance();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void registerMessage(Class<? extends Message> type, int id) {
|
public static void registerMessage(Class<? extends Message> type, int id) {
|
||||||
|
|
|
@ -1,13 +1,6 @@
|
||||||
package brainwine.gameserver.server;
|
package brainwine.gameserver.server;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.server.pipeline.Connection;
|
import brainwine.gameserver.server.pipeline.Connection;
|
||||||
import brainwine.gameserver.server.requests.BlocksIgnoreRequest;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests are incoming packets from the client.
|
* Requests are incoming packets from the client.
|
||||||
|
@ -15,30 +8,4 @@ import brainwine.gameserver.server.requests.BlocksIgnoreRequest;
|
||||||
public abstract class Request {
|
public abstract class Request {
|
||||||
|
|
||||||
public abstract void process(Connection connection);
|
public abstract void process(Connection connection);
|
||||||
|
|
||||||
/**
|
|
||||||
* Can be overriden for custom unpacking rules, as seen in {@link BlocksIgnoreRequest}
|
|
||||||
*/
|
|
||||||
public void unpack(Unpacker unpacker) throws IllegalArgumentException, IllegalAccessException, IOException {
|
|
||||||
unpacker.readArrayBegin();
|
|
||||||
Field[] fields = this.getClass().getFields();
|
|
||||||
|
|
||||||
for(Field field : fields) {
|
|
||||||
try {
|
|
||||||
if(unpacker.getNextType() == ValueType.NIL && field.getAnnotation(OptionalField.class) == null) {
|
|
||||||
throw new IOException("Value is nil, but field is required!");
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
|
||||||
if(field.getAnnotation(OptionalField.class) == null) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
field.set(this, unpacker.read(field.getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayEnd(true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,22 @@ import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.msgpack.core.MessagePack;
|
||||||
|
import org.msgpack.jackson.dataformat.MessagePackFactory;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.MapperFeature;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
|
||||||
|
import brainwine.gameserver.serialization.BlockSerializer;
|
||||||
|
import brainwine.gameserver.serialization.ItemCodeSerializer;
|
||||||
|
import brainwine.gameserver.serialization.MessageSerializer;
|
||||||
|
import brainwine.gameserver.serialization.NetworkChunkSerializer;
|
||||||
|
import brainwine.gameserver.serialization.RequestDeserializerModifier;
|
||||||
import brainwine.gameserver.server.pipeline.Connection;
|
import brainwine.gameserver.server.pipeline.Connection;
|
||||||
import brainwine.gameserver.server.pipeline.MessageEncoder;
|
import brainwine.gameserver.server.pipeline.MessageEncoder;
|
||||||
import brainwine.gameserver.server.pipeline.RequestDecoder;
|
import brainwine.gameserver.server.pipeline.RequestDecoder;
|
||||||
|
@ -32,6 +47,20 @@ public class Server {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
private static final Logger logger = LogManager.getLogger();
|
||||||
private static final ThreadFactory threadFactory = new DefaultThreadFactory("netty");
|
private static final ThreadFactory threadFactory = new DefaultThreadFactory("netty");
|
||||||
|
private static final ObjectMapper mapper = new ObjectMapper(new MessagePackFactory(
|
||||||
|
MessagePack.DEFAULT_PACKER_CONFIG.withStr8FormatSupport(false)))
|
||||||
|
.configure(SerializationFeature.WRITE_ENUMS_USING_INDEX, true)
|
||||||
|
.configure(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE, true)
|
||||||
|
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
|
||||||
|
.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS, true)
|
||||||
|
.registerModule(new SimpleModule()
|
||||||
|
.setDeserializerModifier(RequestDeserializerModifier.INSTANCE)
|
||||||
|
.addSerializer(MessageSerializer.INSTANCE)
|
||||||
|
.addSerializer(BlockSerializer.INSTANCE)
|
||||||
|
.addSerializer(NetworkChunkSerializer.INSTANCE)
|
||||||
|
.addSerializer(ItemCodeSerializer.INSTANCE));
|
||||||
|
private static final ObjectWriter writer = mapper.writer();
|
||||||
|
private static final ObjectReader reader = mapper.reader();
|
||||||
private final List<ChannelFuture> endpoints = new ArrayList<>();
|
private final List<ChannelFuture> endpoints = new ArrayList<>();
|
||||||
private final Class<? extends ServerChannel> channelType;
|
private final Class<? extends ServerChannel> channelType;
|
||||||
private final EventLoopGroup eventLoopGroup;
|
private final EventLoopGroup eventLoopGroup;
|
||||||
|
@ -55,8 +84,8 @@ public class Server {
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
Connection connection = new Connection();
|
Connection connection = new Connection();
|
||||||
channel.pipeline().addLast("framer", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 1, 4, 0, 0, true));
|
channel.pipeline().addLast("framer", new LengthFieldBasedFrameDecoder(ByteOrder.LITTLE_ENDIAN, 1024, 1, 4, 0, 0, true));
|
||||||
channel.pipeline().addLast("encoder", new MessageEncoder(connection));
|
channel.pipeline().addLast("encoder", new MessageEncoder(writer, connection));
|
||||||
channel.pipeline().addLast("decoder", new RequestDecoder());
|
channel.pipeline().addLast("decoder", new RequestDecoder(reader));
|
||||||
channel.pipeline().addLast("handler", connection);
|
channel.pipeline().addLast("handler", connection);
|
||||||
}
|
}
|
||||||
}).bind(port).syncUninterruptibly());
|
}).bind(port).syncUninterruptibly());
|
||||||
|
|
|
@ -5,9 +5,8 @@ import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.msgpack.packer.BufferPacker;
|
import com.fasterxml.jackson.databind.ObjectWriter;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
|
||||||
import brainwine.gameserver.server.Message;
|
import brainwine.gameserver.server.Message;
|
||||||
import brainwine.gameserver.server.NetworkRegistry;
|
import brainwine.gameserver.server.NetworkRegistry;
|
||||||
import brainwine.gameserver.util.ZipUtils;
|
import brainwine.gameserver.util.ZipUtils;
|
||||||
|
@ -18,9 +17,11 @@ import io.netty.handler.codec.MessageToByteEncoder;
|
||||||
|
|
||||||
public class MessageEncoder extends MessageToByteEncoder<Message> {
|
public class MessageEncoder extends MessageToByteEncoder<Message> {
|
||||||
|
|
||||||
|
private final ObjectWriter writer;
|
||||||
private final Connection connection;
|
private final Connection connection;
|
||||||
|
|
||||||
public MessageEncoder(Connection connection) {
|
public MessageEncoder(ObjectWriter writer, Connection connection) {
|
||||||
|
this.writer = writer;
|
||||||
this.connection = connection;
|
this.connection = connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,10 +46,7 @@ public class MessageEncoder extends MessageToByteEncoder<Message> {
|
||||||
|
|
||||||
bytes = JsonHelper.writeValueAsBytes(data);
|
bytes = JsonHelper.writeValueAsBytes(data);
|
||||||
} else {
|
} else {
|
||||||
BufferPacker packer = MessagePackHelper.createBufferPacker();
|
bytes = writer.writeValueAsBytes(in);
|
||||||
in.pack(packer);
|
|
||||||
bytes = packer.toByteArray();
|
|
||||||
packer.close();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(in.isCompressed()) {
|
if(in.isCompressed()) {
|
||||||
|
|
|
@ -3,17 +3,22 @@ package brainwine.gameserver.server.pipeline;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
import com.fasterxml.jackson.databind.ObjectReader;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
|
||||||
import brainwine.gameserver.server.Request;
|
|
||||||
import brainwine.gameserver.server.NetworkRegistry;
|
import brainwine.gameserver.server.NetworkRegistry;
|
||||||
|
import brainwine.gameserver.server.Request;
|
||||||
import io.netty.buffer.ByteBuf;
|
import io.netty.buffer.ByteBuf;
|
||||||
import io.netty.channel.ChannelHandlerContext;
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||||
|
|
||||||
public class RequestDecoder extends MessageToMessageDecoder<ByteBuf> {
|
public class RequestDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||||
|
|
||||||
|
private final ObjectReader reader;
|
||||||
|
|
||||||
|
public RequestDecoder(ObjectReader reader) {
|
||||||
|
this.reader = reader;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
protected void decode(ChannelHandlerContext ctx, ByteBuf buf, List<Object> out) throws Exception {
|
||||||
int id = buf.readByte() & 0xFF;
|
int id = buf.readByte() & 0xFF;
|
||||||
|
@ -23,17 +28,15 @@ public class RequestDecoder extends MessageToMessageDecoder<ByteBuf> {
|
||||||
throw new IOException("Request exceeds max length of 1024 bytes");
|
throw new IOException("Request exceeds max length of 1024 bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
Request request = NetworkRegistry.instantiateRequest(id);
|
Class<? extends Request> type = NetworkRegistry.getRequestClass(id);
|
||||||
|
|
||||||
if(request == null) {
|
if(type == null) {
|
||||||
throw new IOException("Client sent invalid request: " + id);
|
throw new IOException("Client sent invalid request: " + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = new byte[length];
|
byte[] bytes = new byte[length];
|
||||||
buf.readBytes(bytes);
|
buf.readBytes(bytes);
|
||||||
Unpacker unpacker = MessagePackHelper.createBufferUnpacker(bytes);
|
Request request = reader.readValue(bytes, type);
|
||||||
request.unpack(unpacker);
|
|
||||||
unpacker.close();
|
|
||||||
out.add(request);
|
out.add(request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import org.msgpack.type.Value;
|
|
||||||
|
|
||||||
import brainwine.gameserver.GameServer;
|
import brainwine.gameserver.GameServer;
|
||||||
import brainwine.gameserver.server.OptionalField;
|
import brainwine.gameserver.server.OptionalField;
|
||||||
import brainwine.gameserver.server.Request;
|
import brainwine.gameserver.server.Request;
|
||||||
|
@ -14,7 +12,7 @@ public class AuthenticateRequest extends Request {
|
||||||
public String authToken;
|
public String authToken;
|
||||||
|
|
||||||
@OptionalField
|
@OptionalField
|
||||||
public Value details;
|
public Object details;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Connection connection) {
|
public void process(Connection connection) {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import brainwine.gameserver.item.ItemUseType;
|
||||||
import brainwine.gameserver.item.Layer;
|
import brainwine.gameserver.item.Layer;
|
||||||
import brainwine.gameserver.loot.Loot;
|
import brainwine.gameserver.loot.Loot;
|
||||||
import brainwine.gameserver.loot.LootManager;
|
import brainwine.gameserver.loot.LootManager;
|
||||||
import brainwine.gameserver.msgpack.models.BlockUseData;
|
|
||||||
import brainwine.gameserver.server.OptionalField;
|
import brainwine.gameserver.server.OptionalField;
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
import brainwine.gameserver.util.MapHelper;
|
import brainwine.gameserver.util.MapHelper;
|
||||||
|
@ -30,7 +29,7 @@ public class BlockUseRequest extends PlayerRequest {
|
||||||
public Layer layer;
|
public Layer layer;
|
||||||
|
|
||||||
@OptionalField
|
@OptionalField
|
||||||
public BlockUseData data;
|
public Object[] data;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
|
@ -40,7 +39,10 @@ public class BlockUseRequest extends PlayerRequest {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Object[] data = this.data == null ? null : this.data.getData();
|
if(data != null && data.length == 1 && data[0] instanceof Map) {
|
||||||
|
data = ((Map<?, ?>)data[0]).values().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
Block block = zone.getBlock(x, y);
|
Block block = zone.getBlock(x, y);
|
||||||
MetaBlock metaBlock = zone.getMetaBlock(x, y);
|
MetaBlock metaBlock = zone.getMetaBlock(x, y);
|
||||||
Item item = block.getItem(layer);
|
Item item = block.getItem(layer);
|
||||||
|
|
|
@ -1,10 +1,5 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import org.msgpack.type.ValueType;
|
|
||||||
import org.msgpack.unpacker.Unpacker;
|
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
|
|
||||||
|
@ -15,23 +10,6 @@ public class BlocksIgnoreRequest extends PlayerRequest {
|
||||||
|
|
||||||
public int[] chunkIndexes;
|
public int[] chunkIndexes;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unpack(Unpacker unpacker) throws IOException {
|
|
||||||
int length = unpacker.readArrayBegin();
|
|
||||||
|
|
||||||
if(unpacker.getNextType() == ValueType.INTEGER) {
|
|
||||||
chunkIndexes = new int[length];
|
|
||||||
|
|
||||||
for(int i = 0; i < length; i++) {
|
|
||||||
chunkIndexes[i] = unpacker.readInt();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
chunkIndexes = unpacker.read(int[].class);
|
|
||||||
}
|
|
||||||
|
|
||||||
unpacker.readArrayEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -11,7 +11,6 @@ import brainwine.gameserver.entity.player.ColorSlot;
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.item.Item;
|
import brainwine.gameserver.item.Item;
|
||||||
import brainwine.gameserver.item.ItemRegistry;
|
import brainwine.gameserver.item.ItemRegistry;
|
||||||
import brainwine.gameserver.msgpack.models.AppearanceData;
|
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
import brainwine.gameserver.server.messages.DialogMessage;
|
import brainwine.gameserver.server.messages.DialogMessage;
|
||||||
import brainwine.gameserver.util.MapHelper;
|
import brainwine.gameserver.util.MapHelper;
|
||||||
|
@ -22,7 +21,7 @@ import brainwine.gameserver.util.MapHelper;
|
||||||
*/
|
*/
|
||||||
public class ChangeAppearanceRequest extends PlayerRequest {
|
public class ChangeAppearanceRequest extends PlayerRequest {
|
||||||
|
|
||||||
public AppearanceData data;
|
public Map<String, Object> data;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
|
|
|
@ -1,19 +1,28 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.msgpack.models.DialogInputData;
|
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
|
|
||||||
public class DialogRequest extends PlayerRequest {
|
public class DialogRequest extends PlayerRequest {
|
||||||
|
|
||||||
public DialogInputData data;
|
public Object id;
|
||||||
|
public Object[] input;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
if(data.isType1()) {
|
if(input.length == 1 && input[0] instanceof Map) {
|
||||||
|
input = ((Map<?, ?>)input[0]).values().toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(id instanceof String) {
|
||||||
player.alert("Sorry, this action is not implemented yet.");
|
player.alert("Sorry, this action is not implemented yet.");
|
||||||
} else if(data.isType2()) {
|
return;
|
||||||
player.handleDialogInput(data.getDialogId(), data.getInputData());
|
} else if(id instanceof Integer) {
|
||||||
|
if((int)id > 0) {
|
||||||
|
player.handleDialogInput((int)id, input);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import org.msgpack.type.Value;
|
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
|
|
||||||
public class EventRequest extends PlayerRequest {
|
public class EventRequest extends PlayerRequest {
|
||||||
|
|
||||||
public String key;
|
public String key;
|
||||||
public Value value;
|
public Object value;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {}
|
public void process(Player player) {}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import org.msgpack.type.Value;
|
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.item.Item;
|
import brainwine.gameserver.item.Item;
|
||||||
import brainwine.gameserver.server.OptionalField;
|
import brainwine.gameserver.server.OptionalField;
|
||||||
|
@ -19,7 +17,7 @@ public class InventoryUseRequest extends PlayerRequest {
|
||||||
public int status; // 0 = select, 1 = start, 2 = stop
|
public int status; // 0 = select, 1 = start, 2 = stop
|
||||||
|
|
||||||
@OptionalField
|
@OptionalField
|
||||||
public Value details; // array
|
public Object details; // array
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import org.msgpack.type.Value;
|
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
|
|
||||||
public class RespawnRequest extends PlayerRequest {
|
public class RespawnRequest extends PlayerRequest {
|
||||||
|
|
||||||
public Value status;
|
public Object status;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
package brainwine.gameserver.server.requests;
|
package brainwine.gameserver.server.requests;
|
||||||
|
|
||||||
import org.msgpack.type.Value;
|
|
||||||
|
|
||||||
import brainwine.gameserver.entity.player.Player;
|
import brainwine.gameserver.entity.player.Player;
|
||||||
import brainwine.gameserver.server.PlayerRequest;
|
import brainwine.gameserver.server.PlayerRequest;
|
||||||
|
|
||||||
public class StatusRequest extends PlayerRequest {
|
public class StatusRequest extends PlayerRequest {
|
||||||
|
|
||||||
public Value status;
|
public Object status;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Player player) {
|
public void process(Player player) {
|
||||||
|
|
|
@ -4,10 +4,6 @@ import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
import com.fasterxml.jackson.annotation.JsonValue;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.EnumValue;
|
|
||||||
import brainwine.gameserver.msgpack.RegisterEnum;
|
|
||||||
|
|
||||||
@RegisterEnum
|
|
||||||
public enum Biome {
|
public enum Biome {
|
||||||
|
|
||||||
@JsonEnumDefaultValue
|
@JsonEnumDefaultValue
|
||||||
|
@ -20,7 +16,6 @@ public enum Biome {
|
||||||
SPACE;
|
SPACE;
|
||||||
|
|
||||||
@JsonValue
|
@JsonValue
|
||||||
@EnumValue
|
|
||||||
public String getId() {
|
public String getId() {
|
||||||
return toString().toLowerCase();
|
return toString().toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package brainwine.gameserver.zone;
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
|
import java.beans.ConstructorProperties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple & convenient class to store block data.
|
* Simple & convenient class to store block data.
|
||||||
* Outside of allowing zones to be chopped up unto chunks, it doesn't
|
* Outside of allowing zones to be chopped up unto chunks, it doesn't
|
||||||
|
@ -14,12 +18,17 @@ public class Chunk {
|
||||||
private final Block[] blocks;
|
private final Block[] blocks;
|
||||||
private boolean modified;
|
private boolean modified;
|
||||||
|
|
||||||
public Chunk(int x, int y, int width, int height) {
|
@ConstructorProperties({"x", "y", "width", "height", "blocks"})
|
||||||
|
public Chunk(int x, int y, int width, int height, Block[] blocks) {
|
||||||
this.x = x;
|
this.x = x;
|
||||||
this.y = y;
|
this.y = y;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.blocks = new Block[width * height];
|
this.blocks = blocks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk(int x, int y, int width, int height) {
|
||||||
|
this(x, y, width, height, new Block[width * height]);
|
||||||
|
|
||||||
for(int i = 0; i < blocks.length; i++) {
|
for(int i = 0; i < blocks.length; i++) {
|
||||||
blocks[i] = new Block();
|
blocks[i] = new Block();
|
||||||
|
@ -30,6 +39,7 @@ public class Chunk {
|
||||||
this.modified = modified;
|
this.modified = modified;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
public boolean isModified() {
|
public boolean isModified() {
|
||||||
return modified;
|
return modified;
|
||||||
}
|
}
|
||||||
|
@ -50,16 +60,6 @@ public class Chunk {
|
||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setBlock(int x, int y, Block block) {
|
|
||||||
setBlock(getBlockIndex(x % width, y % height), block);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBlock(int index, Block block) {
|
|
||||||
if(isIndexInBounds(index)) {
|
|
||||||
blocks[index] = block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Block getBlock(int x, int y) {
|
public Block getBlock(int x, int y) {
|
||||||
return getBlock(getBlockIndex(x % width, y % height));
|
return getBlock(getBlockIndex(x % width, y % height));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,134 +1,104 @@
|
||||||
package brainwine.gameserver.zone;
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.msgpack.unpacker.Unpacker;
|
import org.msgpack.core.MessagePack;
|
||||||
|
import org.msgpack.core.MessageUnpacker;
|
||||||
|
import org.msgpack.jackson.dataformat.MessagePackFactory;
|
||||||
|
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||||
|
|
||||||
|
import brainwine.gameserver.serialization.BlockDeserializer;
|
||||||
|
import brainwine.gameserver.serialization.BlockSerializer;
|
||||||
import brainwine.gameserver.util.ZipUtils;
|
import brainwine.gameserver.util.ZipUtils;
|
||||||
|
|
||||||
public class ChunkManager {
|
public class ChunkManager {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
private static final Logger logger = LogManager.getLogger();
|
||||||
private static final String headerString = "brainwine blocks file";
|
|
||||||
private static final int latestVersion = 1;
|
|
||||||
private static final int dataOffset = headerString.length() + 4;
|
|
||||||
private static final int allocSize = 2048;
|
private static final int allocSize = 2048;
|
||||||
private static boolean conversionNotified;
|
private static final ObjectMapper mapper = new ObjectMapper(new MessagePackFactory())
|
||||||
|
.registerModule(new SimpleModule()
|
||||||
|
.addDeserializer(Block.class, BlockDeserializer.INSTANCE)
|
||||||
|
.addSerializer(BlockSerializer.INSTANCE));
|
||||||
private final Zone zone;
|
private final Zone zone;
|
||||||
|
private final File blocksFile;
|
||||||
private RandomAccessFile file;
|
private RandomAccessFile file;
|
||||||
|
private int dataOffset;
|
||||||
|
|
||||||
public ChunkManager(Zone zone) {
|
public ChunkManager(Zone zone) {
|
||||||
this.zone = zone;
|
this.zone = zone;
|
||||||
|
blocksFile = new File(zone.getDirectory(), "blocks.dat");
|
||||||
|
File legacyBlocksFile = new File(zone.getDirectory(), "blocks");
|
||||||
|
|
||||||
try {
|
if(!blocksFile.exists() && legacyBlocksFile.exists()) {
|
||||||
if(file == null) {
|
logger.info("Updating blocks file for zone {} ...", zone.getDocumentId());
|
||||||
File blocksFile = new File(zone.getDirectory(), "blocks.dat");
|
DataInputStream inputStream = null;
|
||||||
File legacyBlocksFile = new File(zone.getDirectory(), "blocks");
|
DataOutputStream outputStream = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
inputStream = new DataInputStream(new FileInputStream(legacyBlocksFile));
|
||||||
|
outputStream = new DataOutputStream(new FileOutputStream(blocksFile));
|
||||||
|
int chunkCount = zone.getChunkCount();
|
||||||
|
|
||||||
if(!blocksFile.exists()) {
|
for(int i = 0; i < chunkCount; i++) {
|
||||||
blocksFile.getParentFile().mkdirs();
|
short length = inputStream.readShort();
|
||||||
blocksFile.createNewFile();
|
byte[] chunkBytes = new byte[length];
|
||||||
}
|
inputStream.read(chunkBytes);
|
||||||
|
inputStream.skipBytes(2048 - length - 2);
|
||||||
file = new RandomAccessFile(blocksFile, "rw");
|
chunkBytes = ZipUtils.inflateBytes(chunkBytes);
|
||||||
|
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(chunkBytes);
|
||||||
if(file.length() == 0) {
|
unpacker.unpackArrayHeader();
|
||||||
file.writeUTF(headerString);
|
int x = unpacker.unpackInt();
|
||||||
file.writeInt(latestVersion);
|
int y = unpacker.unpackInt();
|
||||||
|
int width = unpacker.unpackInt();
|
||||||
|
int height = unpacker.unpackInt();
|
||||||
|
Block[] blocks = new Block[unpacker.unpackArrayHeader() / 3];
|
||||||
|
|
||||||
if(legacyBlocksFile.exists()) {
|
for(int j = 0; j < blocks.length; j++) {
|
||||||
if(!conversionNotified) {
|
blocks[j] = new Block(unpacker.unpackInt(), unpacker.unpackInt(), unpacker.unpackInt());
|
||||||
logger.info("One or more block data files need to be converted. This might take a while ...");
|
|
||||||
conversionNotified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
convertLegacyBlocksFile(legacyBlocksFile);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(!file.readUTF().equals(headerString)) {
|
|
||||||
throw new IOException("Invalid header string");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unpacker.close();
|
||||||
|
byte[] bytes = ZipUtils.deflateBytes(mapper.writeValueAsBytes(new Chunk(x, y, width, height, blocks)));
|
||||||
|
outputStream.writeShort(bytes.length);
|
||||||
|
outputStream.write(bytes);
|
||||||
|
outputStream.write(new byte[allocSize - bytes.length - 2]);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
inputStream.close();
|
||||||
logger.error("ChunkManager construction for zone {} failed", zone.getDocumentId(), e);
|
outputStream.close();
|
||||||
}
|
} catch(Exception e) {
|
||||||
}
|
logger.error("Could not update blocks file for zone {}", zone.getDocumentId(), e);
|
||||||
|
|
||||||
private void convertLegacyBlocksFile(File legacyBlocksFile) throws Exception {
|
|
||||||
byte[] bytes = Files.readAllBytes(legacyBlocksFile.toPath());
|
|
||||||
|
|
||||||
for(int i = 0; i < bytes.length; i += 2048) {
|
|
||||||
short length = (short)(((bytes[i] & 0xFF) << 8) + (bytes[i + 1] & 0xFF));
|
|
||||||
byte[] chunkBytes = ZipUtils.inflateBytes(Arrays.copyOfRange(bytes, i + 2, i + 2 + length));
|
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
||||||
DataOutputStream dos = new DataOutputStream(baos);
|
|
||||||
Unpacker unpacker = MessagePackHelper.createBufferUnpacker(chunkBytes);
|
|
||||||
unpacker.readArrayBegin();
|
|
||||||
int x = unpacker.readInt();
|
|
||||||
int y = unpacker.readInt();
|
|
||||||
int width = unpacker.readInt();
|
|
||||||
int height = unpacker.readInt();
|
|
||||||
dos.writeInt(x);
|
|
||||||
dos.writeInt(y);
|
|
||||||
dos.writeInt(width);
|
|
||||||
dos.writeInt(height);
|
|
||||||
unpacker.readArrayBegin();
|
|
||||||
|
|
||||||
for(int j = 0; j < width * height; j++) {
|
|
||||||
dos.writeInt(unpacker.readInt());
|
|
||||||
dos.writeInt(unpacker.readInt());
|
|
||||||
dos.writeInt(unpacker.readInt());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unpacker.close();
|
legacyBlocksFile.delete();
|
||||||
byte[] updatedBytes = ZipUtils.deflateBytes(baos.toByteArray());
|
|
||||||
dos.close();
|
|
||||||
file.seek(dataOffset + zone.getChunkIndex(x, y) * allocSize);
|
|
||||||
file.writeShort(updatedBytes.length);
|
|
||||||
file.write(updatedBytes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Chunk loadChunk(int index) {
|
public Chunk loadChunk(int index) {
|
||||||
Chunk chunk = null;
|
|
||||||
DataInputStream dis = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
if(file == null) {
|
||||||
|
file = new RandomAccessFile(blocksFile, "rw");
|
||||||
|
}
|
||||||
|
|
||||||
file.seek(dataOffset + index * allocSize);
|
file.seek(dataOffset + index * allocSize);
|
||||||
byte[] bytes = new byte[file.readShort()];
|
byte[] bytes = new byte[file.readShort()];
|
||||||
file.read(bytes);
|
file.read(bytes);
|
||||||
|
return mapper.readValue(ZipUtils.inflateBytes(bytes), Chunk.class);
|
||||||
dis = new DataInputStream(new ByteArrayInputStream(ZipUtils.inflateBytes(bytes)));
|
|
||||||
chunk = new Chunk(dis.readInt(), dis.readInt(), dis.readInt(), dis.readInt());
|
|
||||||
|
|
||||||
for(int i = 0; i < zone.getChunkWidth() * zone.getChunkHeight(); i++) {
|
|
||||||
chunk.setBlock(i, new Block(dis.readInt(), dis.readInt(), dis.readInt()));
|
|
||||||
}
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
logger.error("Could not load chunk {} of zone {}", index, zone.getDocumentId(), e);
|
logger.error("Could not load chunk {} of zone {}", index, zone.getDocumentId(), e);
|
||||||
} finally {
|
|
||||||
if(dis != null) {
|
|
||||||
try {
|
|
||||||
dis.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("Resource could not be closed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return chunk;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveModifiedChunks() {
|
public void saveModifiedChunks() {
|
||||||
|
@ -140,38 +110,25 @@ public class ChunkManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveChunk(Chunk chunk) {
|
public void saveChunk(Chunk chunk) {
|
||||||
DataOutputStream dos = null;
|
|
||||||
int index = zone.getChunkIndex(chunk.getX(), chunk.getY());
|
int index = zone.getChunkIndex(chunk.getX(), chunk.getY());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream(allocSize);
|
if(file == null) {
|
||||||
dos = new DataOutputStream(baos);
|
file = new RandomAccessFile(blocksFile, "rw");
|
||||||
dos.writeInt(chunk.getX());
|
}
|
||||||
dos.writeInt(chunk.getY());
|
|
||||||
dos.writeInt(chunk.getWidth());
|
byte[] bytes = ZipUtils.deflateBytes(mapper.writeValueAsBytes(chunk));
|
||||||
dos.writeInt(chunk.getHeight());
|
|
||||||
|
if(bytes.length > allocSize) {
|
||||||
for(Block block : chunk.getBlocks()) {
|
throw new IOException("WARNING: bigger than alloc size: " + bytes.length);
|
||||||
dos.writeInt(block.getBase());
|
|
||||||
dos.writeInt(block.getBack());
|
|
||||||
dos.writeInt(block.getFront());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte[] bytes = ZipUtils.deflateBytes(baos.toByteArray());
|
|
||||||
file.seek(dataOffset + index * allocSize);
|
file.seek(dataOffset + index * allocSize);
|
||||||
file.writeShort(bytes.length);
|
file.writeShort(bytes.length);
|
||||||
file.write(bytes);
|
file.write(bytes);
|
||||||
chunk.setModified(false);
|
chunk.setModified(false);
|
||||||
} catch(Exception e) {
|
} catch (IOException e) {
|
||||||
logger.error("Could not save chunk %s of zone %s", index, zone.getDocumentId(), e);
|
logger.error("Could not save chunk {} of zone {}", index, zone.getDocumentId(), e);
|
||||||
} finally {
|
|
||||||
if(dos != null) {
|
|
||||||
try {
|
|
||||||
dos.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.warn("Resource could not be closed", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
package brainwine.gameserver.zone;
|
|
||||||
|
|
||||||
public enum SizePreset {
|
|
||||||
|
|
||||||
MINI(1000, 400),
|
|
||||||
NORMAL(2000, 800),
|
|
||||||
XL(4000, 1600);
|
|
||||||
|
|
||||||
private final int width;
|
|
||||||
private final int height;
|
|
||||||
|
|
||||||
private SizePreset(int width, int height) {
|
|
||||||
this.width = width;
|
|
||||||
this.height = height;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getWidth() {
|
|
||||||
return width;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getHeight() {
|
|
||||||
return height;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
package brainwine.gameserver.zone;
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
import java.beans.ConstructorProperties;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -19,12 +18,7 @@ import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.msgpack.unpacker.BufferUnpacker;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JacksonInject;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
import com.fasterxml.jackson.annotation.JsonIncludeProperties;
|
|
||||||
import com.fasterxml.jackson.annotation.JsonValue;
|
|
||||||
|
|
||||||
import brainwine.gameserver.GameServer;
|
import brainwine.gameserver.GameServer;
|
||||||
import brainwine.gameserver.entity.Entity;
|
import brainwine.gameserver.entity.Entity;
|
||||||
|
@ -38,7 +32,6 @@ import brainwine.gameserver.item.ItemUseType;
|
||||||
import brainwine.gameserver.item.Layer;
|
import brainwine.gameserver.item.Layer;
|
||||||
import brainwine.gameserver.item.MetaType;
|
import brainwine.gameserver.item.MetaType;
|
||||||
import brainwine.gameserver.item.ModType;
|
import brainwine.gameserver.item.ModType;
|
||||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
|
||||||
import brainwine.gameserver.prefab.Prefab;
|
import brainwine.gameserver.prefab.Prefab;
|
||||||
import brainwine.gameserver.server.Message;
|
import brainwine.gameserver.server.Message;
|
||||||
import brainwine.gameserver.server.messages.BlockChangeMessage;
|
import brainwine.gameserver.server.messages.BlockChangeMessage;
|
||||||
|
@ -52,9 +45,7 @@ import brainwine.gameserver.server.messages.ZoneExploredMessage;
|
||||||
import brainwine.gameserver.server.messages.ZoneStatusMessage;
|
import brainwine.gameserver.server.messages.ZoneStatusMessage;
|
||||||
import brainwine.gameserver.util.MapHelper;
|
import brainwine.gameserver.util.MapHelper;
|
||||||
import brainwine.gameserver.util.MathUtils;
|
import brainwine.gameserver.util.MathUtils;
|
||||||
import brainwine.shared.JsonHelper;
|
|
||||||
|
|
||||||
@JsonIncludeProperties({"name", "biome", "width", "height"})
|
|
||||||
public class Zone {
|
public class Zone {
|
||||||
|
|
||||||
public static final int DEFAULT_CHUNK_WIDTH = 20;
|
public static final int DEFAULT_CHUNK_WIDTH = 20;
|
||||||
|
@ -64,8 +55,8 @@ public class Zone {
|
||||||
private final Biome biome;
|
private final Biome biome;
|
||||||
private final int width;
|
private final int width;
|
||||||
private final int height;
|
private final int height;
|
||||||
private final int chunkWidth;
|
private final int chunkWidth = DEFAULT_CHUNK_WIDTH;
|
||||||
private final int chunkHeight;
|
private final int chunkHeight = DEFAULT_CHUNK_HEIGHT;
|
||||||
private final int numChunksWidth;
|
private final int numChunksWidth;
|
||||||
private final int numChunksHeight;
|
private final int numChunksHeight;
|
||||||
private final int[] surface;
|
private final int[] surface;
|
||||||
|
@ -88,23 +79,19 @@ public class Zone {
|
||||||
private final Map<Integer, MetaBlock> globalMetaBlocks = new HashMap<>();
|
private final Map<Integer, MetaBlock> globalMetaBlocks = new HashMap<>();
|
||||||
private final Map<Integer, MetaBlock> fieldBlocks = new HashMap<>();
|
private final Map<Integer, MetaBlock> fieldBlocks = new HashMap<>();
|
||||||
|
|
||||||
public Zone(String documentId, String name, Biome biome, SizePreset sizePreset) {
|
protected Zone(String documentId, ZoneConfig config, ZoneData data) {
|
||||||
this(documentId, name, biome, sizePreset.getWidth(), sizePreset.getHeight());
|
this(documentId, config.getName(), config.getBiome(), config.getWidth(), config.getHeight());
|
||||||
|
surface = data.getSurface();
|
||||||
|
sunlight = data.getSunlight();
|
||||||
|
chunksExplored = data.getChunksExplored();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ConstructorProperties({"documentId", "name", "biome", "width", "height"})
|
public Zone(String documentId, String name, Biome biome, int width, int height) {
|
||||||
public Zone(@JacksonInject("documentId") String documentId, String name, Biome biome, int width, int height) {
|
|
||||||
this(documentId, name, biome, width, height, DEFAULT_CHUNK_WIDTH, DEFAULT_CHUNK_HEIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Zone(String documentId, String name, Biome biome, int width, int height, int chunkWidth, int chunkHeight) {
|
|
||||||
this.documentId = documentId;
|
this.documentId = documentId;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.biome = biome;
|
this.biome = biome;
|
||||||
this.width = width;
|
this.width = width;
|
||||||
this.height = height;
|
this.height = height;
|
||||||
this.chunkWidth = chunkWidth;
|
|
||||||
this.chunkHeight = chunkHeight;
|
|
||||||
numChunksWidth = width / chunkWidth;
|
numChunksWidth = width / chunkWidth;
|
||||||
numChunksHeight = height / chunkHeight;
|
numChunksHeight = height / chunkHeight;
|
||||||
surface = new int[width];
|
surface = new int[width];
|
||||||
|
@ -139,29 +126,14 @@ public class Zone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lastTick = now;
|
||||||
|
ticks++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void load() throws Exception {
|
public void saveModifiedChunks() {
|
||||||
pendingSunlight.clear();
|
|
||||||
File dataDir = new File("zones", documentId);
|
|
||||||
File shapeFile = new File(dataDir, "shape.cmp");
|
|
||||||
BufferUnpacker unpacker = MessagePackHelper.readFiles(shapeFile);
|
|
||||||
unpacker.read(surface);
|
|
||||||
unpacker.read(sunlight);
|
|
||||||
pendingSunlight.addAll(Arrays.asList(unpacker.read(Integer[].class)));
|
|
||||||
unpacker.read(chunksExplored);
|
|
||||||
setMetaBlocks(JsonHelper.readList(new File(dataDir, "metablocks.json"), MetaBlock.class));
|
|
||||||
indexDungeons();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save() throws Exception {
|
|
||||||
File dataDir = new File("zones", documentId);
|
|
||||||
dataDir.mkdirs();
|
|
||||||
JsonHelper.writeValue(new File(dataDir, "config.json"), this);
|
|
||||||
chunkManager.saveModifiedChunks();
|
chunkManager.saveModifiedChunks();
|
||||||
removeInactiveChunks();
|
removeInactiveChunks();
|
||||||
MessagePackHelper.writeToFile(new File(dataDir, "shape.cmp"), surface, sunlight, pendingSunlight, chunksExplored);
|
|
||||||
JsonHelper.writeValue(new File(dataDir, "metablocks.json"), metaBlocks.values());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -615,6 +587,8 @@ public class Zone {
|
||||||
indexMetaBlock(getBlockIndex(x, y), metaBlock);
|
indexMetaBlock(getBlockIndex(x, y), metaBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indexDungeons();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean ownsMetaBlock(MetaBlock metaBlock, Player player) {
|
private boolean ownsMetaBlock(MetaBlock metaBlock, Player player) {
|
||||||
|
@ -914,16 +888,6 @@ public class Zone {
|
||||||
return numChunksWidth * numChunksHeight;
|
return numChunksWidth * numChunksHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonValue
|
|
||||||
protected Map<String, Object> getJsonConfig() {
|
|
||||||
Map<String, Object> config = new HashMap<>();
|
|
||||||
config.put("name", name);
|
|
||||||
config.put("biome", biome);
|
|
||||||
config.put("width", width);
|
|
||||||
config.put("height", height);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return A {@link Map} containing all the data necessary for use in {@link ConfigurationMessage}.
|
* @return A {@link Map} containing all the data necessary for use in {@link ConfigurationMessage}.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
|
import java.beans.ConstructorProperties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class ZoneConfig {
|
||||||
|
|
||||||
|
private final String name;
|
||||||
|
private final Biome biome;
|
||||||
|
private final int width;
|
||||||
|
private final int height;
|
||||||
|
|
||||||
|
@ConstructorProperties({"name", "biome", "width", "height"})
|
||||||
|
public ZoneConfig(String name, Biome biome, int width, int height) {
|
||||||
|
this.name = name;
|
||||||
|
this.biome = biome;
|
||||||
|
this.width = width;
|
||||||
|
this.height = height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Biome getBiome() {
|
||||||
|
return biome;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
|
import java.beans.ConstructorProperties;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||||
|
|
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
|
public class ZoneData {
|
||||||
|
|
||||||
|
private int[] surface;
|
||||||
|
private int[] sunlight;
|
||||||
|
private int[] pendingSunlight;
|
||||||
|
private boolean[] chunksExplored;
|
||||||
|
|
||||||
|
@ConstructorProperties({"surface", "sunlight", "pending_sunlight", "chunks_explored"})
|
||||||
|
public ZoneData(int[] surface, int[] sunlight, int[] pendingSunlight, boolean[] chunksExplored) {
|
||||||
|
this.surface = surface;
|
||||||
|
this.sunlight = sunlight;
|
||||||
|
this.pendingSunlight = pendingSunlight;
|
||||||
|
this.chunksExplored = chunksExplored;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSurface() {
|
||||||
|
return surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getSunlight() {
|
||||||
|
return sunlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int[] getPendingSunlight() {
|
||||||
|
return pendingSunlight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean[] getChunksExplored() {
|
||||||
|
return chunksExplored;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
package brainwine.gameserver.zone;
|
package brainwine.gameserver.zone;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -13,9 +14,13 @@ import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.msgpack.core.MessagePack;
|
||||||
|
import org.msgpack.core.MessageUnpacker;
|
||||||
|
import org.msgpack.jackson.dataformat.MessagePackFactory;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.InjectableValues;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
|
import brainwine.gameserver.util.ZipUtils;
|
||||||
import brainwine.gameserver.zone.gen.AsyncZoneGenerator;
|
import brainwine.gameserver.zone.gen.AsyncZoneGenerator;
|
||||||
import brainwine.gameserver.zone.gen.StaticZoneGenerator;
|
import brainwine.gameserver.zone.gen.StaticZoneGenerator;
|
||||||
import brainwine.shared.JsonHelper;
|
import brainwine.shared.JsonHelper;
|
||||||
|
@ -24,12 +29,31 @@ public class ZoneManager {
|
||||||
|
|
||||||
private static final Logger logger = LogManager.getLogger();
|
private static final Logger logger = LogManager.getLogger();
|
||||||
private final AsyncZoneGenerator asyncGenerator = new AsyncZoneGenerator(this);
|
private final AsyncZoneGenerator asyncGenerator = new AsyncZoneGenerator(this);
|
||||||
|
private final ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
|
||||||
private final File dataDir = new File("zones");
|
private final File dataDir = new File("zones");
|
||||||
private Map<String, Zone> zones = new HashMap<>();
|
private Map<String, Zone> zones = new HashMap<>();
|
||||||
private Map<String, Zone> zonesByName = new HashMap<>();
|
private Map<String, Zone> zonesByName = new HashMap<>();
|
||||||
|
|
||||||
public ZoneManager() {
|
public ZoneManager() {
|
||||||
loadZones();
|
logger.info("Loading zone data ...");
|
||||||
|
dataDir.mkdirs();
|
||||||
|
|
||||||
|
for(File file : dataDir.listFiles()) {
|
||||||
|
if(file.isDirectory()) {
|
||||||
|
loadZone(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(zones.isEmpty()) {
|
||||||
|
logger.info("No zones were loaded. Generating default zone ...");
|
||||||
|
Zone zone = StaticZoneGenerator.generateZone(Biome.PLAIN, 2000, 800);
|
||||||
|
saveZone(zone);
|
||||||
|
putZone(zone);
|
||||||
|
} else {
|
||||||
|
logger.info("Successfully loaded {} zone(s)", zonesByName.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Starting zone generator thread ...");
|
||||||
asyncGenerator.setDaemon(true);
|
asyncGenerator.setDaemon(true);
|
||||||
asyncGenerator.start();
|
asyncGenerator.start();
|
||||||
}
|
}
|
||||||
|
@ -40,55 +64,78 @@ public class ZoneManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadZone(File file) {
|
||||||
|
String id = file.getName();
|
||||||
|
File dataFile = new File(file, "zone.dat");
|
||||||
|
File shapeFile = new File(file, "shape.cmp");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ZoneData data = null;
|
||||||
|
|
||||||
|
if(shapeFile.exists() && !dataFile.exists()) {
|
||||||
|
MessageUnpacker unpacker = MessagePack.newDefaultUnpacker(ZipUtils.inflateBytes(Files.readAllBytes(shapeFile.toPath())));
|
||||||
|
int[] surface = new int[unpacker.unpackArrayHeader()];
|
||||||
|
|
||||||
|
for(int i = 0; i < surface.length; i++) {
|
||||||
|
surface[i] = unpacker.unpackInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] sunlight = new int[unpacker.unpackArrayHeader()];
|
||||||
|
|
||||||
|
for(int i = 0; i < sunlight.length; i++) {
|
||||||
|
sunlight[i] = unpacker.unpackInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
int[] pendingSunlight = new int[unpacker.unpackArrayHeader()];
|
||||||
|
|
||||||
|
for(int i = 0; i < pendingSunlight.length; i++) {
|
||||||
|
pendingSunlight[i] = unpacker.unpackInt();
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean[] chunksExplored = new boolean[unpacker.unpackArrayHeader()];
|
||||||
|
|
||||||
|
for(int i = 0; i < pendingSunlight.length; i++) {
|
||||||
|
chunksExplored[i] = unpacker.unpackBoolean();
|
||||||
|
}
|
||||||
|
|
||||||
|
data = new ZoneData(surface, sunlight, pendingSunlight, chunksExplored);
|
||||||
|
mapper.writeValue(dataFile, data);
|
||||||
|
shapeFile.delete();
|
||||||
|
} else {
|
||||||
|
data = mapper.readValue(ZipUtils.inflateBytes(Files.readAllBytes(dataFile.toPath())), ZoneData.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZoneConfig config = JsonHelper.readValue(new File(file, "config.json"), ZoneConfig.class);
|
||||||
|
Zone zone = new Zone(id, config, data);
|
||||||
|
zone.setMetaBlocks(JsonHelper.readList(new File(file, "metablocks.json"), MetaBlock.class));
|
||||||
|
putZone(zone);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Zone load failure. id: {}", id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void saveZones() {
|
public void saveZones() {
|
||||||
for(Zone zone : zonesByName.values()) {
|
for(Zone zone : getZones()) {
|
||||||
saveZone(zone);
|
saveZone(zone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveZone(Zone zone) {
|
public void saveZone(Zone zone) {
|
||||||
|
File file = zone.getDirectory();
|
||||||
|
file.mkdirs();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
zone.save();
|
zone.saveModifiedChunks();
|
||||||
|
ZoneConfig config = JsonHelper.readValue(zone, ZoneConfig.class);
|
||||||
|
ZoneData data = JsonHelper.readValue(zone, ZoneData.class);
|
||||||
|
JsonHelper.writeValue(new File(file, "metablocks.json"), zone.getMetaBlocks());
|
||||||
|
JsonHelper.writeValue(new File(file, "config.json"), config);
|
||||||
|
Files.write(new File(file, "zone.dat").toPath(), ZipUtils.deflateBytes(mapper.writeValueAsBytes(data)));
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
logger.error("Zone save failure. id: {}", zone.getDocumentId(), e);
|
logger.error("Zone save failure. id: {}", zone.getDocumentId(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadZones() {
|
|
||||||
logger.info("Loading zone data ...");
|
|
||||||
dataDir.mkdirs();
|
|
||||||
File[] files = dataDir.listFiles();
|
|
||||||
|
|
||||||
if(files.length == 0) {
|
|
||||||
logger.info("Generating default zone ...");
|
|
||||||
Zone zone = StaticZoneGenerator.generateZone(Biome.PLAIN, 2000, 800);
|
|
||||||
saveZone(zone);
|
|
||||||
putZone(zone);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(File file : files) {
|
|
||||||
if(file.isDirectory()) {
|
|
||||||
loadZone(file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Successfully loaded {} zone(s)", zonesByName.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void loadZone(File file) {
|
|
||||||
String id = file.getName();
|
|
||||||
|
|
||||||
try {
|
|
||||||
File configFile = new File(file, "config.json");
|
|
||||||
Zone zone = JsonHelper.readValue(configFile, Zone.class, new InjectableValues.Std().addValue("documentId", id));
|
|
||||||
zone.load();
|
|
||||||
putZone(zone);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.error("Zone load failure. id: {}", id, e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void putZone(Zone zone) {
|
private void putZone(Zone zone) {
|
||||||
String id = zone.getDocumentId();
|
String id = zone.getDocumentId();
|
||||||
String name = zone.getName();
|
String name = zone.getName();
|
||||||
|
|
Loading…
Add table
Reference in a new issue