mirror of
https://github.com/array-in-a-matrix/brainwine.git
synced 2025-04-02 11:11:58 -04:00
Experimental prefab system & structure generation
This commit is contained in:
parent
b11984cb03
commit
3520fe2a44
65 changed files with 1865 additions and 66 deletions
|
@ -10,6 +10,7 @@ import brainwine.gameserver.command.CommandManager;
|
|||
import brainwine.gameserver.entity.player.PlayerManager;
|
||||
import brainwine.gameserver.loot.LootManager;
|
||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
||||
import brainwine.gameserver.prefab.PrefabManager;
|
||||
import brainwine.gameserver.server.NetworkRegistry;
|
||||
import brainwine.gameserver.server.Server;
|
||||
import brainwine.gameserver.zone.ZoneManager;
|
||||
|
@ -23,6 +24,7 @@ public class GameServer {
|
|||
private final Thread handlerThread;
|
||||
private final Queue<Runnable> tasks = new ConcurrentLinkedQueue<>();
|
||||
private final LootManager lootManager;
|
||||
private final PrefabManager prefabManager;
|
||||
private final ZoneManager zoneManager;
|
||||
private final PlayerManager playerManager;
|
||||
private final Server server;
|
||||
|
@ -38,6 +40,7 @@ public class GameServer {
|
|||
GameConfiguration.init();
|
||||
MessagePackHelper.init();
|
||||
lootManager = new LootManager();
|
||||
prefabManager = new PrefabManager();
|
||||
StaticZoneGenerator.init();
|
||||
zoneManager = new ZoneManager();
|
||||
playerManager = new PlayerManager();
|
||||
|
@ -106,6 +109,10 @@ public class GameServer {
|
|||
return lootManager;
|
||||
}
|
||||
|
||||
public PrefabManager getPrefabManager() {
|
||||
return prefabManager;
|
||||
}
|
||||
|
||||
public ZoneManager getZoneManager() {
|
||||
return zoneManager;
|
||||
}
|
||||
|
|
|
@ -13,9 +13,11 @@ import org.apache.logging.log4j.Logger;
|
|||
|
||||
import brainwine.gameserver.command.commands.AdminCommand;
|
||||
import brainwine.gameserver.command.commands.BroadcastCommand;
|
||||
import brainwine.gameserver.command.commands.ExportCommand;
|
||||
import brainwine.gameserver.command.commands.GenerateZoneCommand;
|
||||
import brainwine.gameserver.command.commands.GiveCommand;
|
||||
import brainwine.gameserver.command.commands.HelpCommand;
|
||||
import brainwine.gameserver.command.commands.ImportCommand;
|
||||
import brainwine.gameserver.command.commands.KickCommand;
|
||||
import brainwine.gameserver.command.commands.PlayerIdCommand;
|
||||
import brainwine.gameserver.command.commands.PositionCommand;
|
||||
|
@ -62,6 +64,8 @@ public class CommandManager {
|
|||
registerCommand(new GiveCommand());
|
||||
registerCommand(new GenerateZoneCommand());
|
||||
registerCommand(new SeedCommand());
|
||||
registerCommand(new ExportCommand());
|
||||
registerCommand(new ImportCommand());
|
||||
registerCommand(new PositionCommand());
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
package brainwine.gameserver.command.commands;
|
||||
|
||||
import static brainwine.gameserver.entity.player.NotificationType.ALERT;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import brainwine.gameserver.GameServer;
|
||||
import brainwine.gameserver.command.Command;
|
||||
import brainwine.gameserver.command.CommandExecutor;
|
||||
import brainwine.gameserver.entity.player.Player;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
import brainwine.gameserver.prefab.PrefabManager;
|
||||
import brainwine.gameserver.zone.Zone;
|
||||
|
||||
public class ExportCommand extends Command {
|
||||
|
||||
public static final int SIZE_LIMIT = 10000;
|
||||
|
||||
@Override
|
||||
public void execute(CommandExecutor executor, String[] args) {
|
||||
if(args.length < 5) {
|
||||
executor.notify(String.format("Usage: %s", getUsage(executor)), ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
Zone zone = ((Player)executor).getZone();
|
||||
PrefabManager prefabManager = GameServer.getInstance().getPrefabManager();
|
||||
String name = String.join(" ", Arrays.copyOfRange(args, 4, args.length));
|
||||
|
||||
if(prefabManager.getPrefab(name) != null) {
|
||||
executor.notify("A prefab with that name already exists.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
try {
|
||||
x = Integer.parseInt(args[0]);
|
||||
y = Integer.parseInt(args[1]);
|
||||
width = Integer.parseInt(args[2]);
|
||||
height = Integer.parseInt(args[3]);
|
||||
} catch(NumberFormatException e) {
|
||||
executor.notify("Parameters must be valid numbers.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
if(width < 0 || height < 0) {
|
||||
executor.notify("Width and height must be positive.", ALERT);
|
||||
return;
|
||||
} else if(width * height > SIZE_LIMIT) {
|
||||
executor.notify(String.format("Sorry, your prefab is too large. Max size: %s blocks.", SIZE_LIMIT), ALERT);
|
||||
return;
|
||||
} else if(x < 0 || x + width >= zone.getWidth() || y < 0 || y + height >= zone.getHeight()) {
|
||||
executor.notify("These coordinates are out of bounds.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
Prefab prefab = zone.chop(x, y, width, height);
|
||||
|
||||
if(prefab == null) {
|
||||
executor.notify("Sorry, something went wrong. Please try again.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
executor.notify("Exporting your prefab ...", ALERT);
|
||||
|
||||
try {
|
||||
prefabManager.registerPrefab(name, prefab);
|
||||
executor.notify(String.format("Your prefab '%s' was successfully exported!", name), ALERT);
|
||||
} catch (Exception e) {
|
||||
executor.notify(String.format("An error occured while exporting prefab '%s': %s", name, e.getMessage()), ALERT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "export";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Exports a section of a zone to a prefab file.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage(CommandExecutor executor) {
|
||||
return "/export <x> <y> <width> <height> <name>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExecute(CommandExecutor executor) {
|
||||
return executor instanceof Player && executor.isAdmin();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package brainwine.gameserver.command.commands;
|
||||
|
||||
import static brainwine.gameserver.entity.player.NotificationType.ALERT;
|
||||
|
||||
import brainwine.gameserver.GameServer;
|
||||
import brainwine.gameserver.command.Command;
|
||||
import brainwine.gameserver.command.CommandExecutor;
|
||||
import brainwine.gameserver.entity.player.Player;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
|
||||
public class ImportCommand extends Command {
|
||||
|
||||
@Override
|
||||
public void execute(CommandExecutor executor, String[] args) {
|
||||
if(args.length < 3) {
|
||||
executor.notify(String.format("Usage: %s", getUsage(executor)), ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
try {
|
||||
x = Integer.parseInt(args[1]);
|
||||
y = Integer.parseInt(args[2]);
|
||||
} catch(NumberFormatException e) {
|
||||
executor.notify("X and Y must be valid numbers.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
Prefab prefab = GameServer.getInstance().getPrefabManager().getPrefab(args[0]);
|
||||
|
||||
if(prefab == null) {
|
||||
executor.notify("Sorry, could not find a prefab with that name.", ALERT);
|
||||
return;
|
||||
}
|
||||
|
||||
((Player)executor).getZone().placePrefab(prefab, x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "import";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Places a prefab at the specified location.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsage(CommandExecutor executor) {
|
||||
return "/import <prefab> <x> <y>";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canExecute(CommandExecutor executor) {
|
||||
return executor instanceof Player && executor.isAdmin();
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
import brainwine.gameserver.util.Vector2i;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Item {
|
||||
|
||||
|
@ -36,6 +38,9 @@ public class Item {
|
|||
@JsonProperty("title")
|
||||
private String title;
|
||||
|
||||
@JsonProperty("rotation")
|
||||
private String rotation;
|
||||
|
||||
@JsonProperty("loot_graphic")
|
||||
private LootGraphic lootGraphic = LootGraphic.NONE;
|
||||
|
||||
|
@ -51,6 +56,9 @@ public class Item {
|
|||
@JsonProperty("meta")
|
||||
private MetaType meta = MetaType.NONE;
|
||||
|
||||
@JsonProperty("size")
|
||||
private Vector2i size = new Vector2i(1, 1);
|
||||
|
||||
@JsonProperty("field")
|
||||
private int field;
|
||||
|
||||
|
@ -130,6 +138,10 @@ public class Item {
|
|||
return title;
|
||||
}
|
||||
|
||||
public boolean isMirrorable() {
|
||||
return rotation != null && rotation.equalsIgnoreCase("mirror");
|
||||
}
|
||||
|
||||
public boolean isAir() {
|
||||
return id == 0;
|
||||
}
|
||||
|
@ -166,6 +178,14 @@ public class Item {
|
|||
return meta;
|
||||
}
|
||||
|
||||
public int getBlockWidth() {
|
||||
return size.getX();
|
||||
}
|
||||
|
||||
public int getBlockHeight() {
|
||||
return size.getY();
|
||||
}
|
||||
|
||||
public boolean isDish() {
|
||||
return field > 1;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonEnumDefaultValue;
|
|||
public enum ModType {
|
||||
|
||||
DECAY,
|
||||
ROTATION,
|
||||
|
||||
@JsonEnumDefaultValue
|
||||
NONE;
|
||||
|
|
|
@ -12,17 +12,19 @@ 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.models.AppearanceData;
|
||||
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.AppearanceDataTemplate;
|
||||
import brainwine.gameserver.reflections.ReflectionsHelper;
|
||||
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;
|
||||
|
@ -44,7 +46,9 @@ public class MessagePackHelper {
|
|||
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());
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -29,13 +29,7 @@ public class ChunkTemplate extends AbstractTemplate<Chunk> {
|
|||
packer.write(chunk.getY());
|
||||
packer.write(chunk.getWidth());
|
||||
packer.write(chunk.getHeight());
|
||||
packer.writeArrayBegin(blocks.length * 3);
|
||||
|
||||
for(Block block : blocks) {
|
||||
packer.write(block);
|
||||
}
|
||||
|
||||
packer.writeArrayEnd();
|
||||
packer.write(blocks);
|
||||
packer.writeArrayEnd();
|
||||
}
|
||||
|
||||
|
@ -50,15 +44,13 @@ public class ChunkTemplate extends AbstractTemplate<Chunk> {
|
|||
int y = unpacker.readInt();
|
||||
int width = unpacker.readInt();
|
||||
int height = unpacker.readInt();
|
||||
unpacker.readArrayBegin();
|
||||
int numBlocks = width * height;
|
||||
Block[] blocks = unpacker.read(Block[].class);
|
||||
Chunk chunk = new Chunk(x, y, width, height);
|
||||
|
||||
for(int i = 0; i < numBlocks; i++) {
|
||||
chunk.setBlock(i, unpacker.read(Block.class));
|
||||
for(int i = 0; i < blocks.length; i++) {
|
||||
chunk.setBlock(i, blocks[i]);
|
||||
}
|
||||
|
||||
unpacker.readArrayEnd();
|
||||
unpacker.readArrayEnd();
|
||||
return chunk;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
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;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class CorrespondingReplacement {
|
||||
|
||||
@JsonProperty("key")
|
||||
private Item key;
|
||||
|
||||
@JsonProperty("values")
|
||||
private Map<Item, Item> values = new HashMap<>();
|
||||
|
||||
@JsonCreator
|
||||
private CorrespondingReplacement() {}
|
||||
|
||||
public Item getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public Map<Item, Item> getValues() {
|
||||
return values;
|
||||
}
|
||||
}
|
132
gameserver/src/main/java/brainwine/gameserver/prefab/Prefab.java
Normal file
132
gameserver/src/main/java/brainwine/gameserver/prefab/Prefab.java
Normal file
|
@ -0,0 +1,132 @@
|
|||
package brainwine.gameserver.prefab;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
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.item.Item;
|
||||
import brainwine.gameserver.util.WeightedList;
|
||||
import brainwine.gameserver.zone.Block;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Prefab {
|
||||
|
||||
@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, WeightedList<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<>();
|
||||
|
||||
@JsonIgnore
|
||||
private int width;
|
||||
|
||||
@JsonIgnore
|
||||
private int height;
|
||||
|
||||
@JsonIgnore
|
||||
private Block[] blocks;
|
||||
|
||||
@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) {
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.blocks = blocks;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
private static Prefab fromName(String name) {
|
||||
return GameServer.getInstance().getPrefabManager().getPrefab(name);
|
||||
}
|
||||
|
||||
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<String, Object> getMetadata(int index) {
|
||||
return metadata.get(index);
|
||||
}
|
||||
|
||||
public Map<Integer, Map<String, Object>> getMetadata() {
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public Map<Item, WeightedList<Item>> getReplacements() {
|
||||
return replacements;
|
||||
}
|
||||
|
||||
public Map<Item, CorrespondingReplacement> getCorrespondingReplacements() {
|
||||
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,98 @@
|
|||
package brainwine.gameserver.prefab;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.msgpack.unpacker.BufferUnpacker;
|
||||
import org.reflections.Reflections;
|
||||
import org.reflections.scanners.ResourcesScanner;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
||||
|
||||
public class PrefabManager {
|
||||
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
private final File dataDir = new File("prefabs");
|
||||
private final ObjectMapper mapper = new ObjectMapper();
|
||||
private final Map<String, Prefab> prefabs = new HashMap<>();
|
||||
|
||||
public PrefabManager() {
|
||||
loadPrefabs();
|
||||
}
|
||||
|
||||
private void loadPrefabs() {
|
||||
logger.info("Loading prefabs ...");
|
||||
|
||||
if(!dataDir.exists()) {
|
||||
logger.info("Copying default prefabs ...");
|
||||
dataDir.mkdirs();
|
||||
Reflections reflections = new Reflections("prefabs", new ResourcesScanner());
|
||||
Set<String> fileNames = reflections.getResources(x -> true);
|
||||
|
||||
for(String fileName : fileNames) {
|
||||
File outputFile = new File(fileName);
|
||||
outputFile.getParentFile().mkdirs();
|
||||
|
||||
try {
|
||||
Files.copy(PrefabManager.class.getResourceAsStream(String.format("/%s", fileName)), outputFile.toPath());
|
||||
} catch (IOException e) {
|
||||
logger.error("Could not copy default prefabs", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File[] files = dataDir.listFiles();
|
||||
|
||||
for(File file : files) {
|
||||
if(file.isDirectory()) {
|
||||
loadPrefab(file);
|
||||
}
|
||||
}
|
||||
|
||||
logger.info("Successfully loaded {} prefab(s)", prefabs.size());
|
||||
}
|
||||
|
||||
private void loadPrefab(File file) {
|
||||
String name = file.getName();
|
||||
File configFile = new File(file, "config.json");
|
||||
|
||||
try {
|
||||
Prefab prefab = mapper.readValue(configFile, Prefab.class);
|
||||
BufferUnpacker unpacker = MessagePackHelper.readFile(new File(file, "blocks.cmp"));
|
||||
unpacker.read(prefab);
|
||||
unpacker.close();
|
||||
prefabs.put(name, prefab);
|
||||
} catch(Exception e) {
|
||||
logger.error("Could not load prefab {}:", name, e);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerPrefab(String name, Prefab structure) throws Exception {
|
||||
if(prefabs.containsKey(name)) {
|
||||
logger.warn("Duplicate prefab name: {}", name);
|
||||
return;
|
||||
}
|
||||
|
||||
savePrefab(name, structure);
|
||||
prefabs.put(name, structure);
|
||||
}
|
||||
|
||||
private void savePrefab(String name, Prefab structure) throws Exception {
|
||||
File outputDir = new File(dataDir, name);
|
||||
outputDir.mkdirs();
|
||||
MessagePackHelper.writeToFile(new File(outputDir, "blocks.cmp"), structure);
|
||||
mapper.writerWithDefaultPrettyPrinter().writeValue(new File(outputDir, "config.json"), structure);
|
||||
}
|
||||
|
||||
public Prefab getPrefab(String name) {
|
||||
return prefabs.get(name);
|
||||
}
|
||||
}
|
|
@ -1,18 +1,25 @@
|
|||
package brainwine.gameserver.server.requests;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import brainwine.gameserver.GameServer;
|
||||
import brainwine.gameserver.entity.player.NotificationType;
|
||||
import brainwine.gameserver.entity.player.Player;
|
||||
import brainwine.gameserver.item.Item;
|
||||
import brainwine.gameserver.item.ItemUseType;
|
||||
import brainwine.gameserver.item.Layer;
|
||||
import brainwine.gameserver.loot.Loot;
|
||||
import brainwine.gameserver.loot.LootManager;
|
||||
import brainwine.gameserver.msgpack.models.BlockUseData;
|
||||
import brainwine.gameserver.server.OptionalField;
|
||||
import brainwine.gameserver.server.PlayerRequest;
|
||||
import brainwine.gameserver.util.MapHelper;
|
||||
import brainwine.gameserver.zone.Block;
|
||||
import brainwine.gameserver.zone.MetaBlock;
|
||||
import brainwine.gameserver.zone.Zone;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -33,77 +40,140 @@ public class BlockUseRequest extends PlayerRequest {
|
|||
return;
|
||||
}
|
||||
|
||||
Object[] data = this.data == null ? null : this.data.getData();
|
||||
Block block = zone.getBlock(x, y);
|
||||
MetaBlock metaBlock = zone.getMetaBlock(x, y);
|
||||
Item item = block.getItem(layer);
|
||||
int mod = block.getMod(layer);
|
||||
|
||||
if(data == null) {
|
||||
if(item.hasUse(ItemUseType.CHANGE)) {
|
||||
zone.updateBlock(x, y, layer, item, mod == 0 ? 1 : 0, player);
|
||||
}
|
||||
} else {
|
||||
Object[] data = this.data.getData();
|
||||
item.getUses().forEach((k, v) -> {
|
||||
switch(k) {
|
||||
case DIALOG:
|
||||
case CREATE_DIALOG:
|
||||
// TODO rework dialog system and clean this mess up
|
||||
Map<String, Object> config = (Map<String, Object>)v;
|
||||
String target = MapHelper.getString(config, "target");
|
||||
for(Entry<ItemUseType, Object> entry : item.getUses().entrySet()) {
|
||||
ItemUseType use = entry.getKey();
|
||||
Object value = entry.getValue();
|
||||
|
||||
switch(use) {
|
||||
case DIALOG:
|
||||
case CREATE_DIALOG:
|
||||
if(metaBlock != null && player.getDocumentId().equals(metaBlock.getOwner()) && data != null && value instanceof Map) {
|
||||
Map<String, Object> config = (Map<String, Object>)value;
|
||||
String target = MapHelper.getString(config, "target", "none");
|
||||
|
||||
switch(target) {
|
||||
case "meta":
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
List<Map<String, Object>> sections = MapHelper.getList(config, "sections");
|
||||
int i = 0;
|
||||
|
||||
for(Map<String, Object> section : sections) {
|
||||
metadata.put(MapHelper.getString(section, "input.key"), data[i++]);
|
||||
if(sections != null && data.length == sections.size()) {
|
||||
for(int i = 0; i < sections.size(); i++) {
|
||||
Map<String, Object> section = sections.get(i);
|
||||
String key = MapHelper.getString(section, "input.key");
|
||||
|
||||
if(key != null) {
|
||||
metadata.put(key, data[i]);
|
||||
} else if(MapHelper.getBoolean(section, "input.mod")) {
|
||||
List<Object> options = MapHelper.getList(section, "input.options");
|
||||
|
||||
if(options != null) {
|
||||
mod = options.indexOf(data[i]);
|
||||
mod = mod == -1 ? 0 : mod;
|
||||
mod *= MapHelper.getInt(section, "input.mod_multiple", 1);
|
||||
zone.updateBlock(x, y, layer, item, mod, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO find out what this is for
|
||||
if(use == ItemUseType.CREATE_DIALOG) {
|
||||
metadata.put("cd", true);
|
||||
}
|
||||
|
||||
zone.setMetaBlock(x, y, item, player, metadata);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TELEPORT:
|
||||
if(mod == 1 && data.length == 2 && data[0] instanceof Integer && data[1] instanceof Integer) {
|
||||
int tX = (int)data[0];
|
||||
int tY = (int)data[1];
|
||||
Block targetBlock = zone.getBlock(tX, tY);
|
||||
}
|
||||
break;
|
||||
case CHANGE:
|
||||
zone.updateBlock(x, y, layer, item, mod == 0 ? 1 : 0, player);
|
||||
break;
|
||||
case CONTAINER:
|
||||
if(metaBlock != null) {
|
||||
Map<String, Object> metadata = metaBlock.getMetadata();
|
||||
String specialItem = MapHelper.getString(metadata, "$");
|
||||
|
||||
if(specialItem != null) {
|
||||
String dungeonId = MapHelper.getString(metadata, "@");
|
||||
|
||||
if(targetBlock != null) {
|
||||
Item targetItem = targetBlock.getFrontItem();
|
||||
if(dungeonId != null && item.hasUse(ItemUseType.FIELDABLE) && zone.isDungeonIntact(dungeonId)) {
|
||||
player.alert("This container is secured by protectors in the area.");
|
||||
break;
|
||||
}
|
||||
|
||||
if(specialItem.equals("?")) {
|
||||
metadata.remove("$");
|
||||
LootManager lootManager = GameServer.getInstance().getLootManager();
|
||||
Loot loot = lootManager.getRandomLoot(15, zone.getBiome(), item.getLootCategories()); // TODO level
|
||||
|
||||
if(targetItem.hasUse(ItemUseType.TELEPORT, ItemUseType.ZONE_TELEPORT)) {
|
||||
player.teleport(tX + 1, tY);
|
||||
if(loot == null) {
|
||||
player.alert("How quaint, this container is empty!");
|
||||
} else {
|
||||
player.awardLoot(loot, item.getLootGraphic());
|
||||
}
|
||||
} else {
|
||||
player.alert("Sorry, this container can't be looted right now.");
|
||||
}
|
||||
|
||||
if(mod != 0) {
|
||||
zone.updateBlock(x, y, Layer.FRONT, item, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TELEPORT:
|
||||
if(data != null && mod == 1 && data.length == 2 && data[0] instanceof Integer && data[1] instanceof Integer) {
|
||||
int tX = (int)data[0];
|
||||
int tY = (int)data[1];
|
||||
MetaBlock target = zone.getMetaBlock(tX, tY);
|
||||
|
||||
if(target != null && target.getItem().hasUse(ItemUseType.TELEPORT, ItemUseType.ZONE_TELEPORT)) {
|
||||
player.teleport(tX + 1, tY);
|
||||
}
|
||||
} else if(mod == 0) {
|
||||
zone.updateBlock(x, y, layer, item, 1);
|
||||
player.notify("You repaired a teleporter!", NotificationType.ACCOMPLISHMENT);
|
||||
player.notifyPeers(String.format("%s repaired a teleporter.", player.getName()), NotificationType.SYSTEM);
|
||||
}
|
||||
break;
|
||||
case SWITCH:
|
||||
if(data == null) {
|
||||
if(metaBlock != null) {
|
||||
// TODO timed switches
|
||||
|
||||
zone.updateBlock(x, y, layer, item, mod % 2 == 0 ? mod + 1 : mod - 1, player, null);
|
||||
Map<String, Object> metadata = metaBlock.getMetadata();
|
||||
List<List<Integer>> positions = MapHelper.getList(metadata, ">", Collections.emptyList());
|
||||
|
||||
for(List<Integer> position : positions) {
|
||||
int sX = position.get(0);
|
||||
int sY = position.get(1);
|
||||
Block target = zone.getBlock(sX, sY);
|
||||
|
||||
if(target != null) {
|
||||
Item switchedItem = target.getFrontItem();
|
||||
|
||||
if(switchedItem.hasUse(ItemUseType.SWITCHED)) {
|
||||
if(!(item.getUse(ItemUseType.SWITCHED) instanceof String)) {
|
||||
int switchedMod = target.getFrontMod();
|
||||
zone.updateBlock(sX, sY, Layer.FRONT, switchedItem, switchedMod % 2 == 0 ? switchedMod + 1 : switchedMod - 1, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
else if(data.hasMetadata()) {
|
||||
// TODO
|
||||
Item item = zone.getBlock(x, y).getItem(layer);
|
||||
Map<String, Object> metadata = new HashMap<>();
|
||||
metadata.putAll(data.getMetadata());
|
||||
zone.setMetaBlock(x, y, item, player, metadata);
|
||||
} else if(data.hasPosition()) {
|
||||
int[] position = data.getPosition();
|
||||
int tX = position[0];
|
||||
int tY = position[1];
|
||||
Item item = zone.getBlock(tX, tY).getItem(layer);
|
||||
|
||||
if(item.hasUse(ItemUseType.TELEPORT, ItemUseType.ZONE_TELEPORT)) {
|
||||
player.teleport(tX + 1, tY);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
package brainwine.gameserver.util;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class Vector2i {
|
||||
|
||||
private int x;
|
||||
private int y;
|
||||
|
||||
public Vector2i(int x, int y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@JsonCreator
|
||||
private Vector2i(int[] positions) {
|
||||
if(positions.length == 2) {
|
||||
x = positions[0];
|
||||
y = positions[1];
|
||||
} else {
|
||||
x = 1;
|
||||
y = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public void setX(int x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setY(int y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return y;
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -37,7 +38,9 @@ import brainwine.gameserver.item.ItemRegistry;
|
|||
import brainwine.gameserver.item.ItemUseType;
|
||||
import brainwine.gameserver.item.Layer;
|
||||
import brainwine.gameserver.item.MetaType;
|
||||
import brainwine.gameserver.item.ModType;
|
||||
import brainwine.gameserver.msgpack.MessagePackHelper;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
import brainwine.gameserver.server.Message;
|
||||
import brainwine.gameserver.server.messages.BlockChangeMessage;
|
||||
import brainwine.gameserver.server.messages.BlockMetaMessage;
|
||||
|
@ -248,6 +251,174 @@ public class Zone {
|
|||
return false;
|
||||
}
|
||||
|
||||
public Prefab chop(int x, int y, int width, int height) {
|
||||
if(!areCoordinatesInBounds(x, y) || !areCoordinatesInBounds(x + width, y + height)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Block[] blocks = new Block[width * height];
|
||||
Map<Integer, Map<String, Object>> metadata = new HashMap<>();
|
||||
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
int index = j * width + i;
|
||||
Block block = getBlock(x + i, y + j);
|
||||
blocks[index] = new Block(block.getBaseItem(), block.getBackItem(), block.getBackMod(), block.getFrontItem(), block.getFrontMod(), block.getLiquidItem(), block.getLiquidMod());
|
||||
MetaBlock metaBlock = metaBlocks.get(getBlockIndex(x + i, j + y));
|
||||
|
||||
if(metaBlock != null) {
|
||||
Map<String, Object> data = MapHelper.copy(metaBlock.getMetadata());
|
||||
|
||||
if(!data.isEmpty()) {
|
||||
List<List<Integer>> positions = MapHelper.getList(data, ">", Collections.emptyList());
|
||||
|
||||
for(List<Integer> position : positions) {
|
||||
position.set(0, position.get(0) - x);
|
||||
position.set(1, position.get(1) - y);
|
||||
}
|
||||
|
||||
metadata.put(index, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new Prefab(width, height, blocks, metadata);
|
||||
}
|
||||
|
||||
public void placePrefab(Prefab prefab, int x, int y) {
|
||||
placePrefab(prefab, x, y, new Random());
|
||||
}
|
||||
|
||||
public void placePrefab(Prefab prefab, int x, int y, Random random) {
|
||||
int width = prefab.getWidth();
|
||||
int height = prefab.getHeight();
|
||||
Block[] blocks = prefab.getBlocks();
|
||||
int guardBlocks = 0;
|
||||
String dungeonId = prefab.isDungeon() ? UUID.randomUUID().toString() : null;
|
||||
boolean decay = prefab.hasDecay();
|
||||
boolean mirrored = prefab.isMirrorable() && random.nextBoolean();
|
||||
Map<Item, Item> replacedItems = new HashMap<>();
|
||||
|
||||
// Replacements
|
||||
prefab.getReplacements().forEach((item, list) -> {
|
||||
replacedItems.put(item, list.next(random));
|
||||
});
|
||||
|
||||
// Corresponding replacements
|
||||
prefab.getCorrespondingReplacements().forEach((item, data) -> {
|
||||
Item keyReplacement = replacedItems.get(data.getKey());
|
||||
|
||||
if(keyReplacement != null) {
|
||||
Item replacement = data.getValues().get(keyReplacement);
|
||||
|
||||
if(replacement != null) {
|
||||
replacedItems.put(item, replacement);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for(int i = 0; i < width; i++) {
|
||||
for(int j = 0; j < height; j++) {
|
||||
int index = j * width + (mirrored ? width - 1 - i : i);
|
||||
Block block = blocks[index];
|
||||
Item baseItem = replacedItems.getOrDefault(block.getBaseItem(), block.getBaseItem());
|
||||
Item backItem = replacedItems.getOrDefault(block.getBackItem(), block.getBackItem());
|
||||
Item frontItem = replacedItems.getOrDefault(block.getFrontItem(), block.getFrontItem());
|
||||
Item liquidItem = replacedItems.getOrDefault(block.getLiquidItem(), block.getLiquidItem());
|
||||
int backMod = block.getBackMod();
|
||||
int frontMod = block.getFrontMod();
|
||||
int liquidMod = block.getLiquidMod();
|
||||
|
||||
// Update base item if it isn't empty
|
||||
if(!baseItem.isAir()) {
|
||||
updateBlock(x + i, y + j, Layer.BASE, baseItem);
|
||||
}
|
||||
|
||||
// Update back item if it isn't empty
|
||||
if(!backItem.isAir()) {
|
||||
// Apply decay to back block
|
||||
if(decay && backItem.getMod() == ModType.DECAY && random.nextBoolean()) {
|
||||
backMod = random.nextInt(4) + 1;
|
||||
}
|
||||
|
||||
updateBlock(x + i, y + j, Layer.BACK, backItem, backMod);
|
||||
}
|
||||
|
||||
// Update front item if either the back, front or liquid item isn't empty
|
||||
if(!backItem.isAir() || !frontItem.isAir() || !liquidItem.isAir()) {
|
||||
// Apply mods
|
||||
if(mirrored && frontItem.getMod() == ModType.ROTATION) {
|
||||
// If rotation == mirror, swap mods 0 and 4, otherwise 1 and 3
|
||||
if(frontItem.isMirrorable()) {
|
||||
frontMod = frontMod == 0 ? 4 : frontMod == 4 ? 0 : frontMod;
|
||||
} else {
|
||||
frontMod = frontMod == 1 ? 3 : frontMod == 3 ? 1 : frontMod;
|
||||
}
|
||||
} else if(decay && frontItem.getMod() == ModType.DECAY && random.nextBoolean()) {
|
||||
frontMod = random.nextInt(4) + 1;
|
||||
}
|
||||
|
||||
int offset = mirrored ? -(frontItem.getBlockWidth() - 1) : 0;
|
||||
|
||||
// Clear the block it would normally occupy
|
||||
if(offset != 0) {
|
||||
updateBlock(x + i, y + j, Layer.FRONT, 0);
|
||||
}
|
||||
|
||||
Map<String, Object> metadata = prefab.getMetadata(index);
|
||||
metadata = metadata == null ? new HashMap<>() : MapHelper.copy(metadata);
|
||||
|
||||
// Add dungeon id to guard blocks and containers, and increment guard block count if applicable
|
||||
if(dungeonId != null && frontItem.hasUse(ItemUseType.CONTAINER, ItemUseType.GUARD)) {
|
||||
metadata.put("@", dungeonId);
|
||||
|
||||
if(frontItem.hasUse(ItemUseType.GUARD)) {
|
||||
guardBlocks++;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine lootability for containers
|
||||
if(prefab.hasLoot() && frontItem.hasUse(ItemUseType.CONTAINER)) {
|
||||
// If the container is a "high end" container, make it lootable. Otherwise 10% chance.
|
||||
if(frontItem.hasUse(ItemUseType.FIELDABLE) || random.nextDouble() <= 0.1) {
|
||||
metadata.put("$", "?");
|
||||
frontMod = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Block is linked, offset positions
|
||||
if(metadata.containsKey(">")) {
|
||||
List<List<Integer>> positions = MapHelper.getList(metadata, ">", Collections.emptyList());
|
||||
|
||||
for(List<Integer> position : positions) {
|
||||
int pX = position.get(0);
|
||||
int pY = position.get(1);
|
||||
|
||||
// Create an offset in case the block is bigger than 1x1
|
||||
Item linkedItem = blocks[pY * width + pX].getFrontItem();
|
||||
linkedItem = replacedItems.getOrDefault(linkedItem, linkedItem);
|
||||
int pOffset = -(linkedItem.getBlockWidth() - 1);
|
||||
position.set(0, (mirrored ? width - 1 - pX + pOffset : pX) + x);
|
||||
position.set(1, position.get(1) + y);
|
||||
}
|
||||
}
|
||||
|
||||
updateBlock(x + i + offset, y + j, Layer.FRONT, frontItem, frontMod, null, metadata);
|
||||
}
|
||||
|
||||
// Update liquid item if it isn't empty
|
||||
if(!liquidItem.isAir()) {
|
||||
updateBlock(x + i, y + j, Layer.LIQUID, liquidItem, liquidMod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(guardBlocks > 0) {
|
||||
dungeons.put(dungeonId, guardBlocks);
|
||||
}
|
||||
}
|
||||
|
||||
private void indexDungeons() {
|
||||
List<MetaBlock> guardBlocks = getMetaBlocksWithUse(ItemUseType.GUARD);
|
||||
|
||||
|
|
|
@ -10,6 +10,8 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
|
||||
import brainwine.gameserver.item.Item;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
import brainwine.gameserver.util.Vector2i;
|
||||
import brainwine.gameserver.util.WeightedList;
|
||||
import brainwine.gameserver.zone.gen.models.BaseResourceType;
|
||||
import brainwine.gameserver.zone.gen.models.Deposit;
|
||||
|
@ -28,6 +30,21 @@ public class GeneratorConfig {
|
|||
@JsonProperty("speleothems")
|
||||
private Item[] speleothems = {};
|
||||
|
||||
@JsonProperty("unique_structures")
|
||||
private Prefab[] uniqueStructures = {};
|
||||
|
||||
@JsonProperty("dungeons")
|
||||
private WeightedList<Prefab> dungeons = new WeightedList<>();
|
||||
|
||||
@JsonProperty("spawn_towers")
|
||||
private WeightedList<Prefab> spawnTowers = new WeightedList<>();
|
||||
|
||||
@JsonProperty("dungeon_region")
|
||||
private Vector2i dungeonRegion = new Vector2i(80, 64);
|
||||
|
||||
@JsonProperty("dungeon_chance")
|
||||
private double dungeonRate = 0.25;
|
||||
|
||||
@JsonProperty("stone_variants")
|
||||
private WeightedList<StoneVariant> stoneVariants = new WeightedList<>();
|
||||
|
||||
|
@ -53,6 +70,26 @@ public class GeneratorConfig {
|
|||
return speleothems;
|
||||
}
|
||||
|
||||
public Prefab[] getUniqueStructures() {
|
||||
return uniqueStructures;
|
||||
}
|
||||
|
||||
public WeightedList<Prefab> getDungeons() {
|
||||
return dungeons;
|
||||
}
|
||||
|
||||
public WeightedList<Prefab> getSpawnTowers() {
|
||||
return spawnTowers;
|
||||
}
|
||||
|
||||
public Vector2i getDungeonRegion() {
|
||||
return dungeonRegion;
|
||||
}
|
||||
|
||||
public double getDungeonRate() {
|
||||
return dungeonRate;
|
||||
}
|
||||
|
||||
public WeightedList<StoneVariant> getStoneVariants() {
|
||||
return stoneVariants;
|
||||
}
|
||||
|
|
|
@ -1,18 +1,24 @@
|
|||
package brainwine.gameserver.zone.gen;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Random;
|
||||
|
||||
import brainwine.gameserver.item.Item;
|
||||
import brainwine.gameserver.item.Layer;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
import brainwine.gameserver.zone.Chunk;
|
||||
import brainwine.gameserver.zone.Zone;
|
||||
import brainwine.gameserver.zone.gen.models.BlockPosition;
|
||||
import brainwine.gameserver.zone.gen.models.Cave;
|
||||
|
||||
public class GeneratorContext {
|
||||
|
||||
private final List<Cave> caves = new ArrayList<>();
|
||||
private final Map<BlockPosition, Prefab> prefabs = new HashMap<>();
|
||||
private final Zone zone;
|
||||
private final Random random;
|
||||
private final int seed;
|
||||
|
@ -39,6 +45,28 @@ public class GeneratorContext {
|
|||
return caves;
|
||||
}
|
||||
|
||||
public void placePrefab(Prefab prefab, int x, int y) {
|
||||
if(!willPrefabOverlap(prefab, x, y)) {
|
||||
zone.placePrefab(prefab, x, y, random);
|
||||
prefabs.put(new BlockPosition(x, y), prefab);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean willPrefabOverlap(Prefab prefab, int x, int y) {
|
||||
for(Entry<BlockPosition, Prefab> entry : prefabs.entrySet()) {
|
||||
BlockPosition position = entry.getKey();
|
||||
Prefab other = entry.getValue();
|
||||
int x2 = position.getX();
|
||||
int y2 = position.getY();
|
||||
|
||||
if(x + prefab.getWidth() >= x2 && x <= x2 + other.getWidth() && y + prefab.getHeight() >= y2 && y <= y2 + other.getHeight()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateBlock(int x, int y, Layer layer, int item) {
|
||||
updateBlock(x, y, layer, item, 0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
package brainwine.gameserver.zone.gen;
|
||||
|
||||
import brainwine.gameserver.item.Layer;
|
||||
import brainwine.gameserver.prefab.Prefab;
|
||||
import brainwine.gameserver.util.Vector2i;
|
||||
import brainwine.gameserver.util.WeightedList;
|
||||
import brainwine.gameserver.zone.Block;
|
||||
|
||||
public class StructureGenerator implements GeneratorTask {
|
||||
|
||||
private final Prefab[] uniqueStructures;
|
||||
private final WeightedList<Prefab> dungeons;
|
||||
private final WeightedList<Prefab> spawnTowers;
|
||||
private final Vector2i dungeonRegion;
|
||||
private final double dungeonRate;
|
||||
|
||||
public StructureGenerator(GeneratorConfig config) {
|
||||
uniqueStructures = config.getUniqueStructures();
|
||||
dungeons = config.getDungeons();
|
||||
spawnTowers = config.getSpawnTowers();
|
||||
dungeonRegion = config.getDungeonRegion();
|
||||
dungeonRate = config.getDungeonRate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generate(GeneratorContext ctx) {
|
||||
int width = ctx.getWidth();
|
||||
int height = ctx.getHeight();
|
||||
|
||||
for(Prefab structure : uniqueStructures) {
|
||||
int x = ctx.nextInt(width - 2) + 1;
|
||||
int minY = ctx.getZone().getSurface()[x];
|
||||
int y = ctx.nextInt(height - minY - 2) + minY;
|
||||
ctx.placePrefab(structure, x, y);
|
||||
}
|
||||
|
||||
if(!dungeons.isEmpty()) {
|
||||
for(int x = 0; x < width; x += dungeonRegion.getX()) {
|
||||
for(int y = 0; y < height; y += dungeonRegion.getY()) {
|
||||
if(ctx.nextDouble() <= dungeonRate) {
|
||||
Prefab dungeon = dungeons.next(ctx.getRandom());
|
||||
int prefabWidth = dungeon.getWidth();
|
||||
int prefabHeight = dungeon.getHeight();
|
||||
|
||||
if(ctx.isUnderground(x, y) && ctx.isUnderground(x + prefabWidth, y)) {
|
||||
int placeX = x + (prefabWidth >= dungeonRegion.getX() ? x : ctx.nextInt(dungeonRegion.getX() - prefabWidth));
|
||||
placeX = Math.max(1, Math.min(placeX, width - prefabWidth - 1));
|
||||
int placeY = y + (prefabHeight >= dungeonRegion.getY() ? y : ctx.nextInt(dungeonRegion.getY() - prefabHeight));
|
||||
placeY = Math.max(1, Math.min(placeY, height - prefabHeight - 2));
|
||||
ctx.placePrefab(dungeon, placeX, placeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
placeRandomSpawnTower(ctx, (int)(width * 0.2));
|
||||
placeRandomSpawnTower(ctx, (int)(width * 0.5));
|
||||
placeRandomSpawnTower(ctx, (int)(width * 0.8));
|
||||
}
|
||||
|
||||
private void placeRandomSpawnTower(GeneratorContext ctx, int x) {
|
||||
int surface = ctx.getZone().getSurface()[x];
|
||||
|
||||
if(!spawnTowers.isEmpty()) {
|
||||
Prefab spawnTower = spawnTowers.next(ctx.getRandom());
|
||||
int height = spawnTower.getHeight();
|
||||
int y = surface - height;
|
||||
ctx.placePrefab(spawnTower, x, y);
|
||||
generateFoundation(ctx, x, y + height, spawnTower.getWidth());
|
||||
} else {
|
||||
ctx.updateBlock(x, surface - 1, Layer.FRONT, 891, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateFoundation(GeneratorContext ctx, int x, int y, int width) {
|
||||
for(int i = x; i < x + width; i++) {
|
||||
int j = y;
|
||||
Block block = null;
|
||||
|
||||
while((block = ctx.getZone().getBlock(i, j)) != null && block.getBaseItem().isAir() && !block.getFrontItem().isWhole()) {
|
||||
ctx.updateBlock(i, j, Layer.BACK, 258);
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ public class ZoneGenerator {
|
|||
private final GeneratorTask terrainGenerator;
|
||||
private final GeneratorTask caveGenerator;
|
||||
private final GeneratorTask decorGenerator;
|
||||
private final GeneratorTask structureGenerator;
|
||||
|
||||
public ZoneGenerator() {
|
||||
this(new GeneratorConfig());
|
||||
|
@ -16,6 +17,7 @@ public class ZoneGenerator {
|
|||
terrainGenerator = new TerrainGenerator(config);
|
||||
caveGenerator = new CaveGenerator(config);
|
||||
decorGenerator = new DecorGenerator(config);
|
||||
structureGenerator = new StructureGenerator(config);
|
||||
}
|
||||
|
||||
public void generate(GeneratorContext ctx) {
|
||||
|
@ -25,7 +27,7 @@ public class ZoneGenerator {
|
|||
terrainGenerator.generate(ctx);
|
||||
caveGenerator.generate(ctx);
|
||||
decorGenerator.generate(ctx);
|
||||
ctx.updateBlock(width / 2, ctx.getZone().getSurface()[width / 2] - 1, Layer.FRONT, 891, 0); // TODO structures
|
||||
structureGenerator.generate(ctx);
|
||||
|
||||
for(int x = 0; x < width; x++) {
|
||||
ctx.updateBlock(x, height - 1, Layer.FRONT, 666, 0);
|
||||
|
|
|
@ -15,6 +15,34 @@
|
|||
"sandstone": 4,
|
||||
"limestone": 2
|
||||
},
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"spawn_towers": [
|
||||
"plain_spawn_tower_1",
|
||||
"plain_spawn_tower_2",
|
||||
"plain_spawn_tower_3",
|
||||
"plain_spawn_tower_4"
|
||||
],
|
||||
"base_resources": {
|
||||
"clay": {
|
||||
"per": 1200
|
||||
|
@ -197,6 +225,29 @@
|
|||
"default": 6,
|
||||
"limestone": 1
|
||||
},
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_chance": 0.333,
|
||||
"base_resources": {
|
||||
"clay": {
|
||||
"per": 1200
|
||||
|
@ -362,6 +413,29 @@
|
|||
"ground/stalagmite-4",
|
||||
"ground/stalagmite-5"
|
||||
],
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_chance": 0.375,
|
||||
"base_resources": {
|
||||
"clay": {
|
||||
"per": 1500
|
||||
|
@ -489,6 +563,29 @@
|
|||
"default": 6,
|
||||
"limestone": 1
|
||||
},
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_chance": 0.4,
|
||||
"base_resources": {
|
||||
"rocks": {
|
||||
"per": 200
|
||||
|
@ -608,6 +705,29 @@
|
|||
"default": 3,
|
||||
"sandstone": 1
|
||||
},
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_chance": 0.333,
|
||||
"base_resources": {
|
||||
"clay": {
|
||||
"per": 800
|
||||
|
@ -748,6 +868,30 @@
|
|||
"default": 17,
|
||||
"limestone": 4
|
||||
},
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_region": [81, 85],
|
||||
"dungeon_chance": 0.4,
|
||||
"base_resources": {
|
||||
"clay": {
|
||||
"per": 1200
|
||||
|
@ -869,6 +1013,30 @@
|
|||
"ground/stalagmite-4",
|
||||
"ground/stalagmite-5"
|
||||
],
|
||||
"unique_structures": [
|
||||
"paint_bunker",
|
||||
"head_bunker"
|
||||
],
|
||||
"dungeons": [
|
||||
"dungeon_large_1",
|
||||
"dungeon_large_2",
|
||||
"dungeon_medium_1",
|
||||
"dungeon_medium_2",
|
||||
"dungeon_medium_3",
|
||||
"dungeon_medium_4",
|
||||
"dungeon_medium_5",
|
||||
"dungeon_medium_6",
|
||||
"dungeon_medium_7",
|
||||
"dungeon_medium_8",
|
||||
"dungeon_medium_9",
|
||||
"dungeon_medium_10",
|
||||
"dungeon_small_1",
|
||||
"dungeon_small_2",
|
||||
"dungeon_small_3",
|
||||
"dungeon_small_4"
|
||||
],
|
||||
"dungeon_region": [81, 81],
|
||||
"dungeon_chance": 0.333,
|
||||
"base_resources": {
|
||||
"rocks": {
|
||||
"per": 100
|
||||
|
|
BIN
gameserver/src/main/resources/prefabs/dungeon_large_1/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/dungeon_large_1/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"2316": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 49, 7 ]]
|
||||
},
|
||||
"2333": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 46, 43 ]]
|
||||
},
|
||||
"1977": {
|
||||
"cd": true,
|
||||
"t": "10",
|
||||
"m": "",
|
||||
">": [[ 11, 39 ]]
|
||||
}
|
||||
}
|
||||
}
|
BIN
gameserver/src/main/resources/prefabs/dungeon_large_2/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/dungeon_large_2/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"2306": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 10, 29 ]]
|
||||
},
|
||||
"416": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 36, 30 ]]
|
||||
},
|
||||
"2977": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 35, 42 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"1017": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 11, 8 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"909": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 21, 28 ]]
|
||||
},
|
||||
"425": {
|
||||
"cd": true,
|
||||
"t": "10",
|
||||
"m": "",
|
||||
">": [[ 3, 22 ]]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
xœí˜;RÃ0†e;T¤á%à
|
||||
”P2i*†ÔÁãa u|<7C>('à.Á²-kWZ=-‡ÏdÈéûW«Õ:·7?W-›uñò%«É~‰Q'–ôùG:œŽlUn»;/ß»µà-ÀÈ˦Ÿ²±y¥†xÜLƈ91ìW.r›#/.ùêÁB+)jçHK2vxröÎcÕ6)›JjK
.b^)p^~€ßðêIç†EÁlìžd£ÝäÓj<C393>ÑÖFÓújÄ¢c+n†àSs•—6<E28094>ƒ!/³á‘ìÞ—a¦=ü8—˜J½ÙpU"roÃÄ@`:iÖbB‘ÃäÕàY2<>˜…Œ×*Ø?FXwæÈªê~hCÃ&†òa?0%GjîN±ó«!x(Lj#5®CŒØù¯rÕêOú—¹º<å‹u%m¨:9r=<3D>@Õš·ÖçíW{‹¶U±ÃEÂÐåÐÖLQÕ›\µ®U|Êð±F(#:BáSÎ\83ÅÚXVòb
¿†‡%LÒ®.ûÍ+yd'öx/V™øhÕEÏ60F-Ißš3Šoë·˜M=gÕ&*å:Ð
oŽð'z¦ó;Ìœs ‘éâ<C3A9>%8ÒÙ*@rЂðÖ“.îïhf"nè®È´k[Î¥ª;¿::ð\¨qÁ¨ÚóÙųè–wÒÍÙ™E™O<>up,`vQeŒ¯ï×z±ayÍKÕ!<´€%¨<0C>lÛ{bȺ/2pGðÔ¬:ã…^àPñ‘}ª€ËRíž™ÿÝõ·$ùcá‹ã™
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"building/roof-brown": [
|
||||
"building/roof",
|
||||
"building/roof-brown"
|
||||
]
|
||||
},
|
||||
"corresponding_replace": {
|
||||
"building/roof-edge": {
|
||||
"key": "building/roof-brown",
|
||||
"values": {
|
||||
"building/roof": "building/roof-brown-edge",
|
||||
"building/roof-brown": "building/roof-edge"
|
||||
}
|
||||
},
|
||||
"building/roof-brown-edge": {
|
||||
"key": "building/roof-brown",
|
||||
"values": {
|
||||
"building/roof": "building/roof-edge",
|
||||
"building/roof-brown": "building/roof-brown-edge"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"1220": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 13, 17 ]]
|
||||
},
|
||||
"328": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 23, 29 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"224": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 30, 32 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"back/wallpaper-2": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"building/fence-iron-1": [
|
||||
"building/fence-iron-1",
|
||||
"building/fence-iron-2"
|
||||
],
|
||||
"building/roof": [
|
||||
"building/roof",
|
||||
"building/roof-brown"
|
||||
]
|
||||
},
|
||||
"corresponding_replace": {
|
||||
"building/roof-edge": {
|
||||
"key": "building/roof",
|
||||
"values": {
|
||||
"building/roof": "building/roof-edge",
|
||||
"building/roof-brown": "building/roof-brown-edge"
|
||||
}
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"711": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 9, 19 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"708": {
|
||||
"cd": true,
|
||||
"t": "10",
|
||||
"m": "",
|
||||
">": [[ 19, 22 ]]
|
||||
},
|
||||
"1289": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 11, 7 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"back/wallpaper-2": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"1117": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 24, 12 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"835": {
|
||||
"cd": true,
|
||||
"t": "10",
|
||||
"m": "",
|
||||
">": [[ 40, 29 ]]
|
||||
},
|
||||
"1241": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 18, 7 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"190": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 15, 17 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,56 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"back/wallpaper-2": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"back/brick-mixed": [
|
||||
"back/brick-mixed",
|
||||
"back/brick-tan",
|
||||
"back/brick-blue"
|
||||
],
|
||||
"ammo/bullets": [
|
||||
"ammo/bullets",
|
||||
"containers/crate-small"
|
||||
],
|
||||
"containers/sack-small": [
|
||||
"containers/sack-small",
|
||||
"building/pitch"
|
||||
]
|
||||
},
|
||||
"metadata": {
|
||||
"886": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 23, 7 ]]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
x<EFBFBD>э<EFBFBD>M<0E>0<10><>6<>xw&ю<>Иє.L<>КвЅё8Ф<38>7№&юЧx<18>ђгbC-<2D>YМ&CвїЭtR<74>ёш1И<31>ўAvБ'OЖнЕ<D0BD>8їF/<04> П<C2A0>И#<23><>RУВycБJ9NvB.њ+%P-8$A>)XL<10>љМф;2MБФВpЪDэЃ$Дw№ј2M<32><4D>ьiШаiч<>с<EFBFBD>{ТпЯ<D0BF><D0AF>вЏ іj)ю}б<><D0B1>*/п2аЕЏИ{ПсмЦЈ"|ѓ@Хй<>.<2E><> чC<D187>и<EFBFBD>PЮB<D0AE>q
|
||||
њk<EFBFBD>ЈmЉ(\ђзК"<22>uВ+<1B>
|
||||
йБЎќЊднXВNљЬW6Ђ<36>\ІЁ5#ѓ<><D193>Q,<2C>є&В#R'йf"Ѓ<>К>a%<25> ;SYLХв<D0A5><D0B2>NQ§<51>jEP+OчзЉъ
|
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
]
|
||||
}
|
||||
}
|
BIN
gameserver/src/main/resources/prefabs/dungeon_small_2/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/dungeon_small_2/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"metadata": {
|
||||
"518": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 7, 11 ]]
|
||||
},
|
||||
"786": {
|
||||
"cd": true,
|
||||
"t": "10",
|
||||
"m": "",
|
||||
">": [[ 21, 11 ]]
|
||||
},
|
||||
"799": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 11, 11 ]]
|
||||
},
|
||||
"633": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 9, 11 ]]
|
||||
}
|
||||
}
|
||||
}
|
BIN
gameserver/src/main/resources/prefabs/dungeon_small_3/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/dungeon_small_3/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true
|
||||
}
|
BIN
gameserver/src/main/resources/prefabs/dungeon_small_4/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/dungeon_small_4/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"dungeon": true,
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
xœ½”A E§L»sጉÛFâ¸4&&Þǘô"®MÆx‘v€)N Êâ
¡Àÿ<C380>–ógs sÑ£°}6:~‡R‹Ì><3E>X—ª5ˆÈÐ¥ª<C2A5>ÒåòlH¥N8“õË0q>J0øQå‰[q5âÜ„Yò»¢zgëWCæÀÂ<C380>Üõ ěΦö6GxâäBfEkžÃxÕÑžÂ
Ü_+úSÜ÷ÎwÒ¥^…X=Vé¿u|P…`!}e<><65>³â‘`p+w GbRÐK¡¦1Gg_?
»`eÂ{¿©=òÁÐbtÖªX?©öÚ<>‹J
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"loot": true,
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"furniture/head-deer": {
|
||||
"furniture/head-predator": 1,
|
||||
"furniture/head-tiger": 3,
|
||||
"furniture/head-fish": 10,
|
||||
"furniture/head-cthulhu": 50,
|
||||
"furniture/head-bear": 80,
|
||||
"furniture/head-deer": 80
|
||||
},
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"building/pitch": [
|
||||
"building/pitch",
|
||||
"containers/crate-small",
|
||||
"ammo/bullets"
|
||||
],
|
||||
"containers/crate-small": [
|
||||
"containers/crate-small",
|
||||
"ammo/bullets"
|
||||
],
|
||||
"containers/sack-small": [
|
||||
"containers/sack-small",
|
||||
"building/pitch",
|
||||
"ammo/bullets"
|
||||
]
|
||||
}
|
||||
}
|
BIN
gameserver/src/main/resources/prefabs/paint_bunker/blocks.cmp
Normal file
BIN
gameserver/src/main/resources/prefabs/paint_bunker/blocks.cmp
Normal file
Binary file not shown.
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"furniture/painting-une-pipe": {
|
||||
"furniture/painting-notch": 1,
|
||||
"furniture/painting-outling": 3,
|
||||
"furniture/solar-system-diorama": 3,
|
||||
"furniture/painting-surfer": 8,
|
||||
"furniture/airship-in-bottle": 8,
|
||||
"furniture/painting-mayflower": 10,
|
||||
"furniture/painting-autumn": 10,
|
||||
"furniture/painting-leapquest": 22,
|
||||
"furniture/painting-digdug": 22,
|
||||
"furniture/painting-alpaca": 30,
|
||||
"furniture/globe": 30,
|
||||
"furniture/painting-northerners": 48,
|
||||
"furniture/painting-smasheroid": 48,
|
||||
"furniture/painting-gashlycrumb": 67,
|
||||
"furniture/painting-son-of-man": 104,
|
||||
"furniture/painting-une-pipe": 600
|
||||
}
|
||||
},
|
||||
"metadata": {
|
||||
"84": {
|
||||
"cd": true,
|
||||
"m": "",
|
||||
">": [[ 14, 5 ]]
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"building/ladder-brass": [
|
||||
"building/ladder-wood",
|
||||
"building/ladder-brass",
|
||||
"building/ladder-rope"
|
||||
],
|
||||
"building/roof-brown": [
|
||||
"building/roof",
|
||||
"building/roof-brown"
|
||||
]
|
||||
},
|
||||
"corresponding_replace": {
|
||||
"building/roof-brown-edge": {
|
||||
"key": "building/roof-brown",
|
||||
"values": {
|
||||
"building/roof": "building/roof-edge",
|
||||
"building/roof-brown": "building/roof-brown-edge"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,32 @@
|
|||
{
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"building/brick-tan": [
|
||||
"building/brick",
|
||||
"building/brick-mixed",
|
||||
"building/brick-tan",
|
||||
"building/brick-blue"
|
||||
],
|
||||
"building/ladder-wood": [
|
||||
"building/ladder-wood",
|
||||
"building/ladder-brass",
|
||||
"building/ladder-rope"
|
||||
],
|
||||
"building/fence-iron-2": [
|
||||
"building/fence-iron-1",
|
||||
"building/fence-iron-2"
|
||||
]
|
||||
},
|
||||
"corresponding_replace": {
|
||||
"back/brick-tan": {
|
||||
"key": "building/brick-tan",
|
||||
"values": {
|
||||
"building/brick": "back/brick",
|
||||
"building/brick-mixed": "back/brick-mixed",
|
||||
"building/brick-tan": "back/brick-tan",
|
||||
"building/brick-blue": "back/brick-blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"back/wallpaper-1": [
|
||||
"back/wallpaper-1",
|
||||
"back/wallpaper-2",
|
||||
"back/wallpaper-3",
|
||||
"back/wallpaper-4",
|
||||
"back/wallpaper-5",
|
||||
"back/wallpaper-6",
|
||||
"back/wallpaper-7",
|
||||
"back/wallpaper-8",
|
||||
"back/wallpaper-9",
|
||||
"back/wallpaper-10",
|
||||
"back/wallpaper-11",
|
||||
"back/wallpaper-12"
|
||||
],
|
||||
"building/brick-tan": [
|
||||
"building/brick",
|
||||
"building/brick-mixed",
|
||||
"building/brick-tan",
|
||||
"building/brick-blue"
|
||||
],
|
||||
"building/ladder-wood": [
|
||||
"building/ladder-wood",
|
||||
"building/ladder-brass",
|
||||
"building/ladder-rope"
|
||||
],
|
||||
"building/fence-iron-2": [
|
||||
"building/fence-iron-1",
|
||||
"building/fence-iron-2"
|
||||
]
|
||||
},
|
||||
"corresponding_replace": {
|
||||
"back/brick-tan": {
|
||||
"key": "building/brick-tan",
|
||||
"values": {
|
||||
"building/brick": "back/brick",
|
||||
"building/brick-mixed": "back/brick-mixed",
|
||||
"building/brick-tan": "back/brick-tan",
|
||||
"building/brick-blue": "back/brick-blue"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"decay": true,
|
||||
"mirrorable": true,
|
||||
"replace": {
|
||||
"building/fence-iron-2": [
|
||||
"building/fence-iron-1",
|
||||
"building/fence-iron-2"
|
||||
],
|
||||
"building/ladder-wood": [
|
||||
"building/ladder-wood",
|
||||
"building/ladder-brass",
|
||||
"building/ladder-rope"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue