NPC Plugin rewrite.

Plugin-level data can be stored in DB
This commit is contained in:
simon 2018-12-21 14:00:18 -05:00
parent 70eeb1442d
commit 94b8ef5395
22 changed files with 391 additions and 245 deletions

View File

@ -67,7 +67,7 @@ public class CubotComPort extends CubotHardwareModule {
} else if (a == COMPORT_FRONT_PORT_OUT) {
if (cubot.spendEnergy(20)) {
if (cubot.spendEnergy(5)) {
//Get object directly in front of the Cubot
Point frontTile = cubot.getFrontTile();
//Todo will have to add getGameObjectsBlockingAt to enable Factory

View File

@ -7,8 +7,6 @@ import org.bson.Document;
import org.bson.types.ObjectId;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
/**
* Game objects that regularly creates NonPlayerCharacters
@ -27,35 +25,17 @@ public class Factory extends Structure implements Updatable {
*/
private static final int NPC_CREATION_COOLDOWN = NonPlayerCharacter.LIFETIME / MAX_NPC_COUNT;
/**
* List of associated NonPlayerCharacters
*/
private ArrayList<NonPlayerCharacter> npcs = new ArrayList<>();
/**
* Number of ticks to wait until the Factory can spawn a new NPC
*/
private int cooldown = 0;
/**
* Temporary NPC objectId array. The Factory links the NPCs to itself when initialised,
* at the first call of update().
*/
private Object[] tmpNpcArray = new Object[0];
/**
* Factory are uninitialised until the first update() call
*/
private boolean initialised = false;
public Factory() {
super(2, 2);
}
public Factory(Document document) {
super(document, 2, 2);
tmpNpcArray = ((ArrayList) document.get("npcs")).toArray();
}
@Override
@ -70,66 +50,29 @@ public class Factory extends Structure implements Updatable {
@Override
public void update() {
if (!initialised) {
Settlement settlement = NpcPlugin.settlementMap.get(getWorld().getId());
initialised = true;
if (cooldown == 0) {
if (settlement.getNpcs().size() < MAX_NPC_COUNT) {
Point p = getAdjacentTile();
for (Object id : tmpNpcArray) {
if (p != null) {
NonPlayerCharacter npc = new HarvesterNPC();
npc.setWorld(getWorld());
npc.setObjectId(new ObjectId());
npc.setX(p.x);
npc.setY(p.y);
getWorld().addObject(npc);
getWorld().incUpdatable();
NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((ObjectId) id);
if (npc != null) {
npc.setFactory(this);
npcs.add(npc);
settlement.addNpc(npc);
}
}
tmpNpcArray = null;
cooldown += NPC_CREATION_COOLDOWN;
} else {
if (cooldown == 0) {
if (npcs.size() < MAX_NPC_COUNT) {
Point p = getAdjacentTile();
if (p != null) {
NonPlayerCharacter npc = new HarvesterNPC();
npc.setWorld(getWorld());
npc.setObjectId(new ObjectId());
npc.setX(p.x);
npc.setY(p.y);
getWorld().addObject(npc);
getWorld().incUpdatable();
npc.setFactory(this);
npcs.add(npc);
}
}
cooldown += NPC_CREATION_COOLDOWN;
} else {
cooldown--;
}
cooldown--;
}
}
@Override
public Document mongoSerialise() {
Document dbObject = super.mongoSerialise();
List<ObjectId> tmpNpcArray = new ArrayList<>(npcs.size());
for (NonPlayerCharacter npc : npcs) {
tmpNpcArray.add(npc.getObjectId());
}
dbObject.put("npcs", tmpNpcArray);
return dbObject;
}
ArrayList<NonPlayerCharacter> getNpcs() {
return npcs;
}
}

View File

@ -33,7 +33,7 @@ public class HarvesterNPC extends NonPlayerCharacter {
super.update();
if (getFactory() != null) {
if (getSettlement() != null) {
if (getTask().checkCompleted()) {
setTask(new HarvestTask());
@ -54,8 +54,8 @@ public class HarvesterNPC extends NonPlayerCharacter {
getWorld().decUpdatable();
if (getFactory() != null && getFactory().getNpcs() != null) {
getFactory().getNpcs().remove(this);
if (getSettlement() != null && getSettlement().getNpcs() != null) {
getSettlement().getNpcs().remove(this);
}
GameServer.INSTANCE.getEventDispatcher().dispatch(new ObjectDeathEvent(this));

View File

@ -41,10 +41,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
*/
private Action lastAction = Action.IDLE;
/**
* Factory that created this NPC
*/
private Factory factory;
private Settlement settlement;
/**
* If set to true, the NPC will be destroyed next tick if it is
@ -93,8 +90,8 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
age++;
//Destroy NPCs that are not linked with a Factory
if (factory == null) {
//Destroy NPCs that are not linked with a Settlement
if (settlement == null) {
if (selfDestroyNextTick) {
setDead(true);
}
@ -147,7 +144,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
if (direction == Direction.NORTH) {
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(),
getWorld().getX(), getWorld().getY() - 1) <= MAX_FACTORY_DISTANCE) {
if (!moveTo(8, 0, 0)) {
setDirection(Direction.NORTH);
@ -159,7 +156,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
}
} else if (direction == Direction.EAST) {
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(),
getWorld().getX() + 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) {
if (!moveTo(15, 7, 0)) {
setDirection(Direction.EAST);
@ -170,7 +167,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
return false;
}
} else if (direction == Direction.SOUTH) {
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(),
getWorld().getX(), getWorld().getY() + 1) <= MAX_FACTORY_DISTANCE) {
if (!moveTo(8, 15, 0)) {
setDirection(Direction.SOUTH);
@ -181,7 +178,7 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
return false;
}
} else if (direction == Direction.WEST) {
if (Util.manhattanDist(factory.getWorld().getX(), factory.getWorld().getY(),
if (Util.manhattanDist(settlement.getWorld().getX(), settlement.getWorld().getY(),
getWorld().getX() - 1, getWorld().getY()) <= MAX_FACTORY_DISTANCE) {
if (!moveTo(0, 7, 0)) {
setDirection(Direction.WEST);
@ -254,16 +251,15 @@ public abstract class NonPlayerCharacter extends GameObject implements Updatable
return lastAction;
}
public Factory getFactory() {
return factory;
}
public void setFactory(Factory factory) {
this.factory = factory;
}
public int getAge() {
return age;
}
public Settlement getSettlement() {
return settlement;
}
public void setSettlement(Settlement settlement) {
this.settlement = settlement;
}
}

View File

@ -11,15 +11,14 @@ import net.simon987.server.ServerConfiguration;
import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.ServerPlugin;
import org.bson.Document;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class NpcPlugin extends ServerPlugin {
/**
* Radio tower cache
*/
private static ArrayList<RadioTower> radioTowers;
public static Map<String, Settlement> settlementMap;
@Override
public void init(GameServer gameServer) {
@ -46,13 +45,35 @@ public class NpcPlugin extends ServerPlugin {
registry.registerTile(TileVaultFloor.ID, TileVaultFloor.class);
registry.registerTile(TileVaultWall.ID, TileVaultWall.class);
radioTowers = new ArrayList<>(32);
settlementMap = new ConcurrentHashMap<>();
LogManager.LOGGER.info("(NPC Plugin) Initialised NPC plugin");
}
public static ArrayList<RadioTower> getRadioTowers() {
return radioTowers;
@Override
public Document mongoSerialise() {
Document document = super.mongoSerialise();
Document settlements = new Document();
for (String world : settlementMap.keySet()) {
settlements.put(world, settlementMap.get(world).mongoSerialise());
}
document.put("settlement_map", settlements);
return document;
}
@Override
public void load(Document document) {
super.load(document);
Document settlements = (Document) document.get("settlement_map");
for (String world : settlements.keySet()) {
settlementMap.put(world, new Settlement((Document) settlements.get(world)));
}
LogManager.LOGGER.fine(String.format("(%s) Loaded %d settlements", name, settlementMap.size()));
}
}

View File

@ -8,6 +8,7 @@ import net.simon987.server.game.objects.ControllableUnit;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
public class RadioReceiverHardware extends HardwareModule {
@ -39,12 +40,14 @@ public class RadioReceiverHardware extends HardwareModule {
//Find the nearest Radio Tower and query it
cubot.setAction(Action.LISTENING);
ArrayList<char[]> messages = new ArrayList<>(6);
List<char[]> messages = new ArrayList<>(6);
ArrayList<RadioTower> towers = new ArrayList<>(NpcPlugin.getRadioTowers()); //Avoid ConcurrentModificationException
for (RadioTower tower : towers) {
if (Util.manhattanDist(tower.getWorld().getX(), tower.getWorld().getY(), cubot.getWorld().getX(),
cubot.getWorld().getY()) <= RadioTower.MAX_RANGE) {
for (String world : NpcPlugin.settlementMap.keySet()) {
RadioTower tower = NpcPlugin.settlementMap.get(world).getRadioTower();
if (tower != null && Util.manhattanDist(
tower.getWorld().getX(), tower.getWorld().getY(),
cubot.getWorld().getX(), cubot.getWorld().getY()) <= RadioTower.MAX_RANGE) {
//Tower is in range
messages.addAll(tower.getMessages());
}

View File

@ -24,7 +24,6 @@ public class RadioTower extends Structure implements MessageReceiver, Updatable
public RadioTower(Document document) {
super(document, 1, 1);
NpcPlugin.getRadioTowers().add(this);
}
@Override

View File

@ -0,0 +1,219 @@
package net.simon987.npcplugin;
import net.simon987.server.GameServer;
import net.simon987.server.game.world.TilePlain;
import net.simon987.server.game.world.World;
import net.simon987.server.game.world.WorldGenerationException;
import net.simon987.server.io.MongoSerializable;
import org.bson.Document;
import org.bson.types.ObjectId;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
public class Settlement implements MongoSerializable {
private Factory factory = null;
private RadioTower radioTower = null;
private VaultDoor vaultDoor = null;
private World world;
private DifficultyLevel difficultyLevel;
private List<NonPlayerCharacter> npcs = new ArrayList<>();
private char[] password;
public Settlement(Document document) {
world = GameServer.INSTANCE.getGameUniverse().getWorld(document.getString("world"), false);
ObjectId radioTowerId = document.getObjectId("radio_tower");
if (radioTowerId != null) {
radioTower = (RadioTower) GameServer.INSTANCE.getGameUniverse().getObject(radioTowerId);
}
ObjectId vaultDoorId = document.getObjectId("vault_door");
if (vaultDoorId != null) {
vaultDoor = (VaultDoor) GameServer.INSTANCE.getGameUniverse().getObject(vaultDoorId);
}
ObjectId factoryId = document.getObjectId("factory");
factory = (Factory) GameServer.INSTANCE.getGameUniverse().getObject(factoryId);
difficultyLevel = DifficultyLevel.values()[document.getInteger("difficulty_level")];
Object[] npcArray = ((ArrayList) document.get("npcs")).toArray();
for (Object id : npcArray) {
NonPlayerCharacter npc = (NonPlayerCharacter) GameServer.INSTANCE.getGameUniverse().getObject((ObjectId) id);
if (npc != null) {
addNpc(npc);
}
}
password = document.getString("password").toCharArray();
}
public Settlement(World world) throws WorldGenerationException {
System.out.println("SETTLING");
this.world = world;
this.difficultyLevel = DifficultyLevel.NORMAL; //TODO randomize ?
outerLoopFactory:
for (int x = 2; x < 12; x++) {
for (int y = 2; y < 12; y++) {
if ((!world.isTileBlocked(x, y) && !world.isTileBlocked(x + 1, y) &&
!world.isTileBlocked(x, y + 1) && !world.isTileBlocked(x + 1, y + 1))) {
Factory factory = new Factory();
factory.setWorld(world);
factory.setObjectId(new ObjectId());
factory.setX(x);
factory.setY(y);
if (factory.getAdjacentTile() == null) {
//Factory has no non-blocked adjacent tiles
continue;
}
world.addObject(factory);
world.incUpdatable();
this.factory = factory;
break outerLoopFactory;
}
}
}
if (factory == null) {
throw new WorldGenerationException("Could not place Factory");
}
//Also spawn a radio tower in the same World
Point p = world.getRandomTileWithAdjacent(8, TilePlain.ID);
if (p != null) {
while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0) {
p = world.getRandomPassableTile();
if (p == null) {
//World is full
return;
}
}
RadioTower radioTower = new RadioTower();
radioTower.setWorld(world);
radioTower.setObjectId(new ObjectId());
radioTower.setX(p.x);
radioTower.setY(p.y);
if (radioTower.getAdjacentTile() != null) {
//Radio Tower has adjacent tiles
world.addObject(radioTower);
world.incUpdatable(); //In case the Factory couldn't be spawned.
this.radioTower = radioTower;
}
}
//Also spawn a Vault in the same World
p = world.getRandomPassableTile();
if (p != null) {
VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ?
vaultDoor.setWorld(world);
int counter = 700;
while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0
|| vaultDoor.getAdjacentTileCount(true) < 8) {
p = world.getRandomPassableTile();
if (p == null) {
//World is full
return;
}
vaultDoor.setX(p.x);
vaultDoor.setY(p.y);
counter--;
if (counter <= 0) {
//Reached maximum amount of retries
return;
}
}
vaultDoor.setObjectId(new ObjectId());
world.addObject(vaultDoor);
world.incUpdatable(); //In case the Factory & Radio Tower couldn't be spawned.
vaultDoor.setWorld(world);
vaultDoor.initialize();
this.vaultDoor = vaultDoor;
}
}
public void addNpc(NonPlayerCharacter npc) {
npcs.add(npc);
npc.setSettlement(this);
}
@Override
public Document mongoSerialise() {
Document document = new Document();
document.put("world", world.getId());
if (radioTower != null) {
document.put("radio_tower", radioTower.getObjectId());
}
if (vaultDoor != null) {
document.put("vault_door", vaultDoor.getObjectId());
}
document.put("factory", factory.getObjectId());
document.put("difficulty_level", difficultyLevel.ordinal());
document.put("password", "1234567"); //todo
List<ObjectId> npcArray = new ArrayList<>(npcs.size());
for (NonPlayerCharacter npc : npcs) {
npcArray.add(npc.getObjectId());
}
document.put("npcs", npcArray);
return document;
}
public enum DifficultyLevel {
NORMAL(0);
public int cypherId;
DifficultyLevel(int cypherId) {
this.cypherId = cypherId;
}
}
public Factory getFactory() {
return factory;
}
public RadioTower getRadioTower() {
return radioTower;
}
public VaultDoor getVaultDoor() {
return vaultDoor;
}
public World getWorld() {
return world;
}
public List<NonPlayerCharacter> getNpcs() {
return npcs;
}
}

View File

@ -29,7 +29,7 @@ public class VaultDimension {
public VaultDimension(VaultDoor vaultDoor) {
name = "v" + vaultDoor.getObjectId() + "-";
name = "v" + vaultDoor.getObjectId();
/*
* Creates a group of vault worlds and pieces them together with openings.

View File

@ -1,17 +1,14 @@
package net.simon987.npcplugin.event;
import net.simon987.npcplugin.Factory;
import net.simon987.npcplugin.NpcPlugin;
import net.simon987.npcplugin.RadioTower;
import net.simon987.npcplugin.VaultDoor;
import net.simon987.npcplugin.Settlement;
import net.simon987.server.event.GameEvent;
import net.simon987.server.event.GameEventListener;
import net.simon987.server.event.WorldGenerationEvent;
import net.simon987.server.game.world.TilePlain;
import net.simon987.server.game.world.World;
import org.bson.types.ObjectId;
import net.simon987.server.game.world.WorldGenerationException;
import net.simon987.server.logging.LogManager;
import java.awt.*;
import java.util.Random;
public class WorldCreationListener implements GameEventListener {
@ -37,105 +34,13 @@ public class WorldCreationListener implements GameEventListener {
if (random.nextInt(FACTORY_SPAWN_RATE) == 0) {
World world = ((WorldGenerationEvent) event).getWorld();
World world = (World) event.getSource();
outerLoopFactory:
for (int x = 2; x < 12; x++) {
for (int y = 2; y < 12; y++) {
if ((!world.isTileBlocked(x, y) && !world.isTileBlocked(x + 1, y) &&
!world.isTileBlocked(x, y + 1) && !world.isTileBlocked(x + 1, y + 1))) {
Factory factory = new Factory();
factory.setWorld(world);
factory.setObjectId(new ObjectId());
factory.setX(x);
factory.setY(y);
if (factory.getAdjacentTile() == null) {
//Factory has no non-blocked adjacent tiles
continue;
}
world.addObject(factory);
world.incUpdatable();
// LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() +
// ") (" + x + ", " + y + ")");
break outerLoopFactory;
}
}
}
//Also spawn a radio tower in the same World
Point p = world.getRandomTileWithAdjacent(8, TilePlain.ID);
if (p != null) {
while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0) {
p = world.getRandomPassableTile();
if (p == null) {
//World is full
return;
}
}
RadioTower radioTower = new RadioTower();
radioTower.setWorld(world);
radioTower.setObjectId(new ObjectId());
radioTower.setX(p.x);
radioTower.setY(p.y);
if (radioTower.getAdjacentTile() != null) {
//Radio Tower has adjacent tiles
world.addObject(radioTower);
world.incUpdatable(); //In case the Factory couldn't be spawned.
NpcPlugin.getRadioTowers().add(radioTower);
// LogManager.LOGGER.info("Spawned RadioTower at (" + world.getX() + ", " + world.getY() +
// ") (" + p.x + ", " + p.y + ")");
}
}
//Also spawn a Vault in the same World
p = world.getRandomPassableTile();
if (p != null) {
VaultDoor vaultDoor = new VaultDoor(0); //todo cypherId ?
vaultDoor.setWorld(world);
int counter = 700;
while (p.x == 0 || p.x == world.getWorldSize() - 1 || p.y == world.getWorldSize() - 1 || p.y == 0
|| vaultDoor.getAdjacentTileCount(true) < 8) {
p = world.getRandomPassableTile();
if (p == null) {
//World is full
return;
}
vaultDoor.setX(p.x);
vaultDoor.setY(p.y);
counter--;
if (counter <= 0) {
//Reached maximum amount of retries
return;
}
}
vaultDoor.setObjectId(new ObjectId());
world.addObject(vaultDoor);
world.incUpdatable(); //In case the Factory & Radio Tower couldn't be spawned.
vaultDoor.setWorld(world);
vaultDoor.initialize();
// LogManager.LOGGER.info("Spawned Vault Door at (" + world.getX() + ", " + world.getY() +
// ") (" + p.x + ", " + p.y + ")");
try {
NpcPlugin.settlementMap.put(world.getId(), new Settlement(world));
} catch (WorldGenerationException e) {
LogManager.LOGGER.fine(String.format("Exception during settlement generation: %s.",
e.getMessage()));
}
}
}

View File

@ -73,9 +73,6 @@ public class WorldUtils {
}
}
// LogManager.LOGGER.info("Generated " + biomassBlobs.size() + " biomassBlobs for World (" + world.getX() + ',' +
// world.getY() + ')');
return biomassBlobs;
}
}

View File

@ -7,7 +7,6 @@ import net.simon987.server.event.GameEventListener;
import net.simon987.server.event.ObjectDeathEvent;
import net.simon987.server.game.objects.GameObject;
import net.simon987.server.game.world.World;
import net.simon987.server.logging.LogManager;
import org.bson.types.ObjectId;
/**
@ -41,8 +40,6 @@ public class ObjectDeathListener implements GameEventListener {
dyingHarvesterNPC.getX(), dyingHarvesterNPC.getY(), dyingHarvesterNPC.getWorld());
//Add it to the world game objects
dyingHarvesterNPC.getWorld().addObject(newBiomassBlob);
LogManager.LOGGER.fine("Spawned biomass at (" + newBiomassBlob.getX() +
", " + newBiomassBlob.getY() + ")");
}
}
}

View File

@ -18,6 +18,7 @@ import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.game.world.*;
import net.simon987.server.logging.LogManager;
import net.simon987.server.plugin.PluginManager;
import net.simon987.server.plugin.ServerPlugin;
import net.simon987.server.user.User;
import net.simon987.server.user.UserManager;
import net.simon987.server.user.UserStatsHelper;
@ -221,11 +222,18 @@ public class GameServer implements Runnable {
universe.addUser(user);
}
//Load misc server info
//Load server & plugin data
cursor = server.find().iterator();
if (cursor.hasNext()) {
Document serverObj = cursor.next();
gameUniverse.setTime((long) serverObj.get("time"));
Document plugins = (Document) serverObj.get("plugins");
for (String pluginName : plugins.keySet()) {
ServerPlugin plugin = pluginManager.getPluginByName(pluginName);
plugin.load((Document) plugins.get(pluginName));
}
}
LogManager.LOGGER.info("Done loading! W:" + GameServer.INSTANCE.getGameUniverse().getWorldCount() +
@ -267,6 +275,13 @@ public class GameServer implements Runnable {
Document serverObj = new Document();
serverObj.put("time", gameUniverse.getTime());
Document plugins = new Document();
for (ServerPlugin plugin : pluginManager.getPlugins()) {
plugins.put(plugin.getName(), plugin.mongoSerialise());
}
serverObj.put("plugins", plugins);
//A constant id ensures only one entry is kept and updated, instead of a new entry created every save.
server.replaceOne(new Document("_id", "serverinfo"), serverObj, updateOptions);

View File

@ -115,6 +115,14 @@ public class GameUniverse {
}
}
public World getWorld(String id, boolean createNew) {
String[] tokens = id.split("-");
return getWorld(Integer.decode(tokens[1]), Integer.decode(tokens[2]),
createNew, tokens[0]);
}
public World getLoadedWorld(int x, int y, String dimension) {
// Wrapping coordinates around cyclically
x %= maxWidth;

View File

@ -159,30 +159,30 @@ public abstract class GameObject implements JSONSerializable, MongoSerializable
int count = 0;
if (!getWorld().isTileBlocked(getX() + 1, getY())) {
if (getWorld().getTileMap().isInBounds(x + 1, y) && !getWorld().isTileBlocked(x + 1, y)) {
count++;
}
if (!getWorld().isTileBlocked(getX(), getY() + 1)) {
if (getWorld().getTileMap().isInBounds(x, y + 1) && !getWorld().isTileBlocked(x, y + 1)) {
count++;
}
if (!getWorld().isTileBlocked(getX() - 1, getY())) {
if (getWorld().getTileMap().isInBounds(x - 1, y) && !getWorld().isTileBlocked(x - 1, y)) {
count++;
}
if (!getWorld().isTileBlocked(getX(), getY() - 1)) {
if (getWorld().getTileMap().isInBounds(x, y - 1) && !getWorld().isTileBlocked(x, y - 1)) {
count++;
}
if (diagonals) {
if (!getWorld().isTileBlocked(getX() + 1, getY() + 1)) {
if (getWorld().getTileMap().isInBounds(x + 1, y + 1) && !getWorld().isTileBlocked(x + 1, y + 1)) {
count++;
}
if (!getWorld().isTileBlocked(getX() - 1, getY() + 1)) {
if (getWorld().getTileMap().isInBounds(x - 1, y + 1) && !getWorld().isTileBlocked(x - 1, y + 1)) {
count++;
}
if (!getWorld().isTileBlocked(getX() + 1, getY() - 1)) {
if (getWorld().getTileMap().isInBounds(x + 1, y - 1) && !getWorld().isTileBlocked(x + 1, y - 1)) {
count++;
}
if (!getWorld().isTileBlocked(getX() - 1, getY() - 1)) {
if (getWorld().getTileMap().isInBounds(x - 1, y - 1) && !getWorld().isTileBlocked(x - 1, y - 1)) {
count++;
}
}

View File

@ -5,6 +5,7 @@ import net.simon987.server.GameServer;
import net.simon987.server.game.objects.GameRegistry;
import net.simon987.server.io.JSONSerializable;
import net.simon987.server.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
@ -87,7 +88,8 @@ public class TileMap implements JSONSerializable, MongoSerializable {
*/
public int getTileIdAt(int x, int y) {
try {
return tiles[x][y].getId();
Tile tile = tiles[x][y];
return tile == null ? -1 : tile.getId();
} catch (ArrayIndexOutOfBoundsException e) {
return -1;
}
@ -101,13 +103,18 @@ public class TileMap implements JSONSerializable, MongoSerializable {
* @return the tile id at the specified position, null if out of bounds
*/
public Tile getTileAt(int x, int y) {
try {
if (isInBounds(x, y)) {
return tiles[x][y];
} catch (ArrayIndexOutOfBoundsException e) {
} else {
LogManager.LOGGER.warning(String.format("ArrayIndexOutOfBoundsException in TileMap::getTileAt(%d, %d)", x, y));
Thread.dumpStack();
return null;
}
}
public boolean isInBounds(int x, int y) {
return x >= 0 && x < width && y >= 0 && y < width;
}
public int getWidth() {

View File

@ -76,7 +76,7 @@ public class World implements MongoSerializable {
* @return long
*/
public static String idFromCoordinates(int x, int y, String dimension) {
return dimension + "0x" + Integer.toHexString(x) + "-" + "0x" + Integer.toHexString(y);
return dimension + "-0x" + Integer.toHexString(x) + "-" + "0x" + Integer.toHexString(y);
}
/**
@ -425,28 +425,28 @@ public class World implements MongoSerializable {
if (rTile != null) {
int adjacentTiles = 0;
if (!isTileBlocked(rTile.x, rTile.y - 1)) {
if (tileMap.isInBounds(rTile.x, rTile.y - 1) && !isTileBlocked(rTile.x, rTile.y - 1)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x + 1, rTile.y)) {
if (tileMap.isInBounds(rTile.x + 1, rTile.y) && !isTileBlocked(rTile.x + 1, rTile.y)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x, rTile.y + 1)) {
if (tileMap.isInBounds(rTile.x, rTile.y + 1) && !isTileBlocked(rTile.x, rTile.y + 1)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x - 1, rTile.y)) {
if (tileMap.isInBounds(rTile.x - 1, rTile.y) && !isTileBlocked(rTile.x - 1, rTile.y)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x + 1, rTile.y + 1)) {
if (tileMap.isInBounds(rTile.x + 1, rTile.y + 1) && !isTileBlocked(rTile.x + 1, rTile.y + 1)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x - 1, rTile.y + 1)) {
if (tileMap.isInBounds(rTile.x - 1, rTile.y + 1) && !isTileBlocked(rTile.x - 1, rTile.y + 1)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x + 1, rTile.y - 1)) {
if (tileMap.isInBounds(rTile.x + 1, rTile.y - 1) && !isTileBlocked(rTile.x + 1, rTile.y - 1)) {
adjacentTiles++;
}
if (!isTileBlocked(rTile.x - 1, rTile.y - 1)) {
if (tileMap.isInBounds(rTile.x - 1, rTile.y - 1) && !isTileBlocked(rTile.x - 1, rTile.y - 1)) {
adjacentTiles++;
}

View File

@ -0,0 +1,7 @@
package net.simon987.server.game.world;
public class WorldGenerationException extends Exception {
public WorldGenerationException(String message) {
super(message);
}
}

View File

@ -38,6 +38,8 @@ public class WorldGenerator {
private int minCopperCount;
private int maxCopperCount;
private String dimension;
private static final int DEFAULT_WORLD_SIZE = 16;
/**
@ -48,6 +50,8 @@ public class WorldGenerator {
public WorldGenerator(ServerConfiguration config) {
dimension = config.getString("new_user_dimension");
centerPointCountMin = config.getInt("wg_centerPointCountMin");
centerPointCountMax = config.getInt("wg_centerPointCountMax");
wallPlainRatio = config.getInt("wg_wallPlainRatio");
@ -88,9 +92,9 @@ public class WorldGenerator {
/**
* Generates an empty World
*/
private static World generateEmptyWorld(int locX, int locY) {
private static World generateEmptyWorld(int locX, int locY, String dimension) {
return new World(locX, locY, new TileMap(DEFAULT_WORLD_SIZE, DEFAULT_WORLD_SIZE), "w-");
return new World(locX, locY, new TileMap(DEFAULT_WORLD_SIZE, DEFAULT_WORLD_SIZE), dimension);
}
/**
@ -99,7 +103,7 @@ public class WorldGenerator {
public World generateWorld(int locX, int locY) throws CancelledException {
Random random = new Random();
World world = generateEmptyWorld(locX, locY);
World world = generateEmptyWorld(locX, locY, dimension);
centerPointsMap = new HashMap<>(16);

View File

@ -152,6 +152,10 @@ public class PluginManager {
return null;
}
public ServerPlugin getPluginByName(String name) {
return PluginManager.getPluginByName(name, loadedPlugins);
}
private boolean isLoaded(String name) {
return getPluginByName(name, loadedPlugins) != null;
}

View File

@ -2,11 +2,14 @@ package net.simon987.server.plugin;
import net.simon987.server.GameServer;
import net.simon987.server.event.GameEventListener;
import net.simon987.server.io.MongoSerializable;
import net.simon987.server.logging.LogManager;
import org.bson.Document;
import java.util.ArrayList;
import java.util.List;
public abstract class ServerPlugin {
public abstract class ServerPlugin implements MongoSerializable {
/**
* Name of the plugin
@ -49,4 +52,22 @@ public abstract class ServerPlugin {
public List<GameEventListener> getListeners() {
return listeners;
}
@Override
public Document mongoSerialise() {
Document document = new Document();
document.put("version", version);
return document;
}
public void load(Document document) {
LogManager.LOGGER.fine(String.format("(%s) Loading from database", name));
if (!version.equals(document.getString("version"))) {
LogManager.LOGGER.warning(String.format("(%s) Version mismatch with database!" +
" This could cause problems. %s!=%s", name, version, document.getString("version")));
}
}
}

View File

@ -48,7 +48,7 @@ user_timeout=100
#User creation
new_user_worldX=32767
new_user_worldY=32767
new_user_dimension=w-
new_user_dimension=w
# Default user code
new_user_code=; Welcome to Much Assembly required!\n\
; You will find useful information on the game here: https://github.com/simon987/Much-Assembly-Required/wiki\n\