mirror of
https://github.com/simon987/Much-Assembly-Required.git
synced 2025-04-19 10:36:43 +00:00
Fixes #121 + Saner thread safety
This commit is contained in:
parent
59fd620e4a
commit
54b72e89b3
@ -37,7 +37,7 @@ public class UserCreationListener implements GameEventListener {
|
|||||||
|
|
||||||
cubot.setX(point.x);
|
cubot.setX(point.x);
|
||||||
cubot.setY(point.y);
|
cubot.setY(point.y);
|
||||||
cubot.getWorld().getGameObjects().add(cubot);
|
cubot.getWorld().addObject(cubot);
|
||||||
cubot.getWorld().incUpdatable();
|
cubot.getWorld().incUpdatable();
|
||||||
|
|
||||||
cubot.setHeldItem(GameServer.INSTANCE.getConfig().getInt("new_user_item"));
|
cubot.setHeldItem(GameServer.INSTANCE.getConfig().getInt("new_user_item"));
|
||||||
|
@ -74,7 +74,7 @@ public class Factory extends GameObject implements Updatable {
|
|||||||
npc.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
npc.setObjectId(GameServer.INSTANCE.getGameUniverse().getNextObjectId());
|
||||||
npc.setX(p.x);
|
npc.setX(p.x);
|
||||||
npc.setY(p.y);
|
npc.setY(p.y);
|
||||||
getWorld().getGameObjects().add(npc);
|
getWorld().addObject(npc);
|
||||||
getWorld().incUpdatable();
|
getWorld().incUpdatable();
|
||||||
npc.setFactory(this);
|
npc.setFactory(this);
|
||||||
|
|
||||||
|
@ -33,14 +33,9 @@ public class HarvestTask extends NPCTask {
|
|||||||
|
|
||||||
if (pause == 0) {
|
if (pause == 0) {
|
||||||
//Get biomass
|
//Get biomass
|
||||||
ArrayList<GameObject> biomass = new ArrayList<>(10);
|
/* todo replace by some sort of .collect call with object
|
||||||
|
id (See https://github.com/simon987/Much-Assembly-Required/pull/66)*/
|
||||||
for (GameObject object : npc.getWorld().getGameObjects()) {
|
ArrayList<GameObject> biomass = npc.getWorld().findObjects(0x4000);
|
||||||
//Plant MAP_INFO
|
|
||||||
if ((object.getMapInfo() & 0x4000) == 0x4000) {
|
|
||||||
biomass.add(object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Get closest one
|
//Get closest one
|
||||||
int minDist = Integer.MAX_VALUE;
|
int minDist = Integer.MAX_VALUE;
|
||||||
|
@ -53,7 +53,7 @@ public class WorldCreationListener implements GameEventListener {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
world.getGameObjects().add(factory);
|
world.addObject(factory);
|
||||||
world.incUpdatable();
|
world.incUpdatable();
|
||||||
|
|
||||||
LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() +
|
LogManager.LOGGER.info("Spawned Factory at (" + world.getX() + ", " + world.getY() +
|
||||||
@ -84,7 +84,7 @@ public class WorldCreationListener implements GameEventListener {
|
|||||||
|
|
||||||
if (radioTower.getAdjacentTile() != null) {
|
if (radioTower.getAdjacentTile() != null) {
|
||||||
//Radio Tower has adjacent tiles
|
//Radio Tower has adjacent tiles
|
||||||
world.getGameObjects().add(radioTower);
|
world.addObject(radioTower);
|
||||||
world.incUpdatable(); //In case the Factory couldn't be spawned.
|
world.incUpdatable(); //In case the Factory couldn't be spawned.
|
||||||
|
|
||||||
NpcPlugin.getRadioTowers().add(radioTower);
|
NpcPlugin.getRadioTowers().add(radioTower);
|
||||||
|
@ -25,7 +25,9 @@ public class WorldCreationListener implements GameEventListener {
|
|||||||
ArrayList<BiomassBlob> biomassBlobs = WorldUtils.generateBlobs(((WorldGenerationEvent) event).getWorld(),
|
ArrayList<BiomassBlob> biomassBlobs = WorldUtils.generateBlobs(((WorldGenerationEvent) event).getWorld(),
|
||||||
minCount, maxCount, yield);
|
minCount, maxCount, yield);
|
||||||
|
|
||||||
((WorldGenerationEvent) event).getWorld().getGameObjects().addAll(biomassBlobs);
|
for (BiomassBlob blob : biomassBlobs) {
|
||||||
|
((WorldGenerationEvent) event).getWorld().addObject(blob);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,11 @@ public class WorldUpdateListener implements GameEventListener {
|
|||||||
|
|
||||||
private HashMap<World, Long> worldWaitMap = new HashMap<>(200);
|
private HashMap<World, Long> worldWaitMap = new HashMap<>(200);
|
||||||
|
|
||||||
private int minBlobCount;
|
private static int minBlobCount;
|
||||||
private int maxBlobCount;
|
private static int maxBlobCount;
|
||||||
private int blobYield;
|
private static int blobYield;
|
||||||
private int waitTime;
|
private static int waitTime;
|
||||||
private int blobThreshold;
|
private static int blobThreshold;
|
||||||
|
|
||||||
public WorldUpdateListener(ServerConfiguration config) {
|
public WorldUpdateListener(ServerConfiguration config) {
|
||||||
|
|
||||||
@ -45,7 +45,7 @@ public class WorldUpdateListener implements GameEventListener {
|
|||||||
World world = ((WorldUpdateEvent) event).getWorld();
|
World world = ((WorldUpdateEvent) event).getWorld();
|
||||||
|
|
||||||
//If there is less than the respawn threshold,
|
//If there is less than the respawn threshold,
|
||||||
if (world.getGameObjects(BiomassBlob.class).size() < blobThreshold) {
|
if (world.findObjects(BiomassBlob.class).size() < blobThreshold) {
|
||||||
|
|
||||||
//Set a timer for respawn_time ticks
|
//Set a timer for respawn_time ticks
|
||||||
if (!worldWaitMap.containsKey(world) || worldWaitMap.get(world) == 0L) {
|
if (!worldWaitMap.containsKey(world) || worldWaitMap.get(world) == 0L) {
|
||||||
@ -59,7 +59,9 @@ public class WorldUpdateListener implements GameEventListener {
|
|||||||
//If the timer was set less than respawn_time ticks ago, respawn the blobs
|
//If the timer was set less than respawn_time ticks ago, respawn the blobs
|
||||||
ArrayList<BiomassBlob> newBlobs = WorldUtils.generateBlobs(world, minBlobCount,
|
ArrayList<BiomassBlob> newBlobs = WorldUtils.generateBlobs(world, minBlobCount,
|
||||||
maxBlobCount, blobYield);
|
maxBlobCount, blobYield);
|
||||||
world.getGameObjects().addAll(newBlobs);
|
for (BiomassBlob blob : newBlobs) {
|
||||||
|
world.addObject(blob);
|
||||||
|
}
|
||||||
|
|
||||||
//Set the 'waitUntil' time to 0 to indicate that we are not waiting
|
//Set the 'waitUntil' time to 0 to indicate that we are not waiting
|
||||||
worldWaitMap.replace(world, 0L);
|
worldWaitMap.replace(world, 0L);
|
||||||
|
@ -9,7 +9,6 @@ import net.simon987.server.event.TickEvent;
|
|||||||
import net.simon987.server.game.DayNightCycle;
|
import net.simon987.server.game.DayNightCycle;
|
||||||
import net.simon987.server.game.GameUniverse;
|
import net.simon987.server.game.GameUniverse;
|
||||||
import net.simon987.server.game.World;
|
import net.simon987.server.game.World;
|
||||||
import net.simon987.server.io.FileUtils;
|
|
||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import net.simon987.server.plugin.PluginManager;
|
import net.simon987.server.plugin.PluginManager;
|
||||||
import net.simon987.server.user.User;
|
import net.simon987.server.user.User;
|
||||||
@ -17,8 +16,6 @@ import net.simon987.server.webserver.SocketServer;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class GameServer implements Runnable {
|
public class GameServer implements Runnable {
|
||||||
|
|
||||||
@ -131,8 +128,7 @@ public class GameServer implements Runnable {
|
|||||||
|
|
||||||
|
|
||||||
//Process user code
|
//Process user code
|
||||||
ArrayList<User> users_ = new ArrayList<>(gameUniverse.getUsers());
|
for (User user : gameUniverse.getUsers()) {
|
||||||
for (User user : users_) {
|
|
||||||
|
|
||||||
if (user.getCpu() != null) {
|
if (user.getCpu() != null) {
|
||||||
try {
|
try {
|
||||||
@ -152,10 +148,8 @@ public class GameServer implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Process each worlds
|
//Process each worlds
|
||||||
//Avoid concurrent modification
|
|
||||||
ArrayList<World> worlds = new ArrayList<>(gameUniverse.getWorlds());
|
|
||||||
int updatedWorlds = 0;
|
int updatedWorlds = 0;
|
||||||
for (World world : worlds) {
|
for (World world : gameUniverse.getWorlds()) {
|
||||||
if (world.shouldUpdate()) {
|
if (world.shouldUpdate()) {
|
||||||
world.update();
|
world.update();
|
||||||
updatedWorlds++;
|
updatedWorlds++;
|
||||||
@ -167,14 +161,9 @@ public class GameServer implements Runnable {
|
|||||||
save();
|
save();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clean up history files
|
|
||||||
if (gameUniverse.getTime() % config.getInt("clean_interval") == 0) {
|
|
||||||
FileUtils.cleanHistory(config.getInt("history_size"));
|
|
||||||
}
|
|
||||||
|
|
||||||
socketServer.tick();
|
socketServer.tick();
|
||||||
|
|
||||||
LogManager.LOGGER.info("Processed " + gameUniverse.getWorlds().size() + " worlds (" + updatedWorlds +
|
LogManager.LOGGER.info("Processed " + gameUniverse.getWorldCount() + " worlds (" + updatedWorlds +
|
||||||
") updated");
|
") updated");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +192,7 @@ public class GameServer implements Runnable {
|
|||||||
cursor = users.find();
|
cursor = users.find();
|
||||||
while (cursor.hasNext()) {
|
while (cursor.hasNext()) {
|
||||||
try {
|
try {
|
||||||
universe.getUsers().add(User.deserialize(cursor.next()));
|
universe.addUser(User.deserialize(cursor.next()));
|
||||||
} catch (CancelledException e) {
|
} catch (CancelledException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -217,13 +206,13 @@ public class GameServer implements Runnable {
|
|||||||
gameUniverse.setNextObjectId((long) serverObj.get("nextObjectId"));
|
gameUniverse.setNextObjectId((long) serverObj.get("nextObjectId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
LogManager.LOGGER.info("Done loading! W:" + GameServer.INSTANCE.getGameUniverse().getWorlds().size() +
|
LogManager.LOGGER.info("Done loading! W:" + GameServer.INSTANCE.getGameUniverse().getWorldCount() +
|
||||||
" | U:" + GameServer.INSTANCE.getGameUniverse().getUsers().size());
|
" | U:" + GameServer.INSTANCE.getGameUniverse().getUserCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void save() {
|
private void save() {
|
||||||
|
|
||||||
LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorlds().size() + " | U:" + gameUniverse.getUsers().size());
|
LogManager.LOGGER.info("Saving to MongoDB | W:" + gameUniverse.getWorldCount() + " | U:" + gameUniverse.getUserCount());
|
||||||
try{
|
try{
|
||||||
DB db = mongo.getDB("mar");
|
DB db = mongo.getDB("mar");
|
||||||
|
|
||||||
@ -233,31 +222,22 @@ public class GameServer implements Runnable {
|
|||||||
DBCollection users = db.getCollection("user");
|
DBCollection users = db.getCollection("user");
|
||||||
DBCollection server = db.getCollection("server");
|
DBCollection server = db.getCollection("server");
|
||||||
|
|
||||||
List<DBObject> worldDocuments = new ArrayList<>();
|
|
||||||
int perBatch = 35;
|
|
||||||
int insertedWorlds = 0;
|
int insertedWorlds = 0;
|
||||||
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
GameUniverse universe = GameServer.INSTANCE.getGameUniverse();
|
||||||
ArrayList<World> worlds_ = new ArrayList<>(universe.getWorlds());
|
for (World w : universe.getWorlds()) {
|
||||||
for (World w : worlds_) {
|
// LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
||||||
LogManager.LOGGER.fine("Saving world "+w.getId()+" to mongodb");
|
insertedWorlds++;
|
||||||
insertedWorlds++;
|
|
||||||
worlds.save(w.mongoSerialise());
|
worlds.save(w.mongoSerialise());
|
||||||
|
|
||||||
// If the world should unload, it is removed from the Universe after having been saved.
|
// If the world should unload, it is removed from the Universe after having been saved.
|
||||||
if (w.shouldUnload()){
|
if (w.shouldUnload()){
|
||||||
unloaded_worlds++;
|
unloaded_worlds++;
|
||||||
LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
// LogManager.LOGGER.fine("Unloading world "+w.getId()+" from universe");
|
||||||
universe.removeWorld(w);
|
universe.removeWorld(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DBObject> userDocuments = new ArrayList<>();
|
for (User u : GameServer.INSTANCE.getGameUniverse().getUsers()) {
|
||||||
int insertedUsers = 0;
|
|
||||||
ArrayList<User> users_ = new ArrayList<>(GameServer.INSTANCE.getGameUniverse().getUsers());
|
|
||||||
for (User u : users_) {
|
|
||||||
|
|
||||||
insertedUsers++;
|
|
||||||
|
|
||||||
|
|
||||||
if (!u.isGuest()) {
|
if (!u.isGuest()) {
|
||||||
users.save(u.mongoSerialise());
|
users.save(u.mongoSerialise());
|
||||||
|
@ -84,9 +84,9 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (leftWorld != null) {
|
if (leftWorld != null) {
|
||||||
world.getGameObjects().remove(this);
|
world.removeObject(this);
|
||||||
world.decUpdatable();
|
world.decUpdatable();
|
||||||
leftWorld.getGameObjects().add(this);
|
leftWorld.addObject(this);
|
||||||
leftWorld.incUpdatable();
|
leftWorld.incUpdatable();
|
||||||
setWorld(leftWorld);
|
setWorld(leftWorld);
|
||||||
|
|
||||||
@ -103,9 +103,9 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rightWorld != null) {
|
if (rightWorld != null) {
|
||||||
world.getGameObjects().remove(this);
|
world.removeObject(this);
|
||||||
world.decUpdatable();
|
world.decUpdatable();
|
||||||
rightWorld.getGameObjects().add(this);
|
rightWorld.addObject(this);
|
||||||
rightWorld.incUpdatable();
|
rightWorld.incUpdatable();
|
||||||
setWorld(rightWorld);
|
setWorld(rightWorld);
|
||||||
|
|
||||||
@ -123,9 +123,9 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (upWorld != null) {
|
if (upWorld != null) {
|
||||||
world.getGameObjects().remove(this);
|
world.removeObject(this);
|
||||||
world.decUpdatable();
|
world.decUpdatable();
|
||||||
upWorld.getGameObjects().add(this);
|
upWorld.addObject(this);
|
||||||
upWorld.incUpdatable();
|
upWorld.incUpdatable();
|
||||||
setWorld(upWorld);
|
setWorld(upWorld);
|
||||||
|
|
||||||
@ -143,9 +143,9 @@ public abstract class GameObject implements JSONSerialisable, MongoSerialisable
|
|||||||
|
|
||||||
|
|
||||||
if (downWorld != null) {
|
if (downWorld != null) {
|
||||||
world.getGameObjects().remove(this);
|
world.removeObject(this);
|
||||||
world.decUpdatable();
|
world.decUpdatable();
|
||||||
downWorld.getGameObjects().add(this);
|
downWorld.addObject(this);
|
||||||
downWorld.incUpdatable();
|
downWorld.incUpdatable();
|
||||||
setWorld(downWorld);
|
setWorld(downWorld);
|
||||||
|
|
||||||
|
@ -10,16 +10,15 @@ import net.simon987.server.assembly.exception.CancelledException;
|
|||||||
import net.simon987.server.logging.LogManager;
|
import net.simon987.server.logging.LogManager;
|
||||||
import net.simon987.server.user.User;
|
import net.simon987.server.user.User;
|
||||||
|
|
||||||
import java.net.UnknownHostException;
|
import java.util.Collection;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Hashtable;
|
|
||||||
|
|
||||||
public class GameUniverse {
|
public class GameUniverse {
|
||||||
|
|
||||||
//private ArrayList<World> worlds;
|
//private ArrayList<World> worlds;
|
||||||
private Hashtable<String,World> worlds;
|
private ConcurrentHashMap<String, World> worlds;
|
||||||
private ArrayList<User> users;
|
//username:user
|
||||||
|
private ConcurrentHashMap<String, User> users;
|
||||||
private WorldGenerator worldGenerator;
|
private WorldGenerator worldGenerator;
|
||||||
|
|
||||||
private MongoClient mongo = null;
|
private MongoClient mongo = null;
|
||||||
@ -33,9 +32,8 @@ public class GameUniverse {
|
|||||||
|
|
||||||
public GameUniverse(ServerConfiguration config) {
|
public GameUniverse(ServerConfiguration config) {
|
||||||
|
|
||||||
//worlds = new ArrayList<>(32);
|
worlds = new ConcurrentHashMap<>(256);
|
||||||
worlds = new Hashtable<String,World>(32);
|
users = new ConcurrentHashMap<>(16);
|
||||||
users = new ArrayList<>(16);
|
|
||||||
|
|
||||||
worldGenerator = new WorldGenerator(config);
|
worldGenerator = new WorldGenerator(config);
|
||||||
}
|
}
|
||||||
@ -160,7 +158,7 @@ public class GameUniverse {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public World createWorld(int x, int y) {
|
private World createWorld(int x, int y) {
|
||||||
World world = null;
|
World world = null;
|
||||||
try {
|
try {
|
||||||
world = worldGenerator.generateWorld(x, y);
|
world = worldGenerator.generateWorld(x, y);
|
||||||
@ -171,12 +169,7 @@ public class GameUniverse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public User getUser(String username) {
|
public User getUser(String username) {
|
||||||
for (User user : users) {
|
return users.get(username);
|
||||||
if (user.getUsername().equals(username)) {
|
|
||||||
return user;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public User getOrCreateUser(String username, boolean makeControlledUnit) {
|
public User getOrCreateUser(String username, boolean makeControlledUnit) {
|
||||||
@ -213,7 +206,7 @@ public class GameUniverse {
|
|||||||
|
|
||||||
user.setUsername(username);
|
user.setUsername(username);
|
||||||
|
|
||||||
users.add(user);
|
addUser(user);
|
||||||
|
|
||||||
return user;
|
return user;
|
||||||
|
|
||||||
@ -235,12 +228,11 @@ public class GameUniverse {
|
|||||||
*/
|
*/
|
||||||
public GameObject getObject(long id) {
|
public GameObject getObject(long id) {
|
||||||
|
|
||||||
//
|
|
||||||
for (World world : getWorlds()) {
|
for (World world : getWorlds()) {
|
||||||
for (GameObject object : world.getGameObjects()) {
|
GameObject obj = world.findObject(id);
|
||||||
if (object.getObjectId() == id) {
|
|
||||||
return object;
|
if (obj != null) {
|
||||||
}
|
return obj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,12 +245,20 @@ public class GameUniverse {
|
|||||||
time++;
|
time++;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<World> getWorlds() {
|
public Collection<World> getWorlds() {
|
||||||
return new ArrayList<World>(worlds.values());
|
return worlds.values();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<User> getUsers() {
|
public int getWorldCount() {
|
||||||
return users;
|
return worlds.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<User> getUsers() {
|
||||||
|
return users.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getUserCount() {
|
||||||
|
return users.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getNextObjectId() {
|
public long getNextObjectId() {
|
||||||
@ -281,8 +281,12 @@ public class GameUniverse {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addUser(User user) {
|
||||||
|
users.put(user.getUsername(), user);
|
||||||
|
}
|
||||||
|
|
||||||
public void removeUser(User user) {
|
public void removeUser(User user) {
|
||||||
users.remove(user);
|
users.remove(user.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxWidth() {
|
public int getMaxWidth() {
|
||||||
|
@ -3,18 +3,19 @@ package net.simon987.server.game;
|
|||||||
import com.mongodb.BasicDBList;
|
import com.mongodb.BasicDBList;
|
||||||
import com.mongodb.BasicDBObject;
|
import com.mongodb.BasicDBObject;
|
||||||
import com.mongodb.DBObject;
|
import com.mongodb.DBObject;
|
||||||
|
import com.sun.istack.internal.Nullable;
|
||||||
import net.simon987.server.GameServer;
|
import net.simon987.server.GameServer;
|
||||||
import net.simon987.server.event.GameEvent;
|
import net.simon987.server.event.GameEvent;
|
||||||
import net.simon987.server.event.WorldUpdateEvent;
|
import net.simon987.server.event.WorldUpdateEvent;
|
||||||
import net.simon987.server.game.GameUniverse;
|
|
||||||
import net.simon987.server.game.pathfinding.Pathfinder;
|
import net.simon987.server.game.pathfinding.Pathfinder;
|
||||||
import net.simon987.server.io.MongoSerialisable;
|
import net.simon987.server.io.MongoSerialisable;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
import net.simon987.server.logging.LogManager;
|
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public class World implements MongoSerialisable {
|
public class World implements MongoSerialisable {
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ public class World implements MongoSerialisable {
|
|||||||
|
|
||||||
private TileMap tileMap;
|
private TileMap tileMap;
|
||||||
|
|
||||||
private ArrayList<GameObject> gameObjects = new ArrayList<>(16);
|
private ConcurrentHashMap<Long, GameObject> gameObjects = new ConcurrentHashMap<>(8);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If this number is greater than 0, the World will be updated.
|
* If this number is greater than 0, the World will be updated.
|
||||||
@ -91,26 +92,49 @@ public class World implements MongoSerialisable {
|
|||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public ArrayList<GameObject> findObjects(Class clazz) {
|
||||||
* Get all the game objects that are instances of the specified class
|
|
||||||
*/
|
|
||||||
public ArrayList getGameObjects(Class<? extends GameObject> clazz) {
|
|
||||||
|
|
||||||
ArrayList<GameObject> objects = new ArrayList<>(gameObjects.size());
|
ArrayList<GameObject> matchingObjects = new ArrayList<>(2);
|
||||||
|
|
||||||
for (GameObject object : gameObjects) {
|
for (GameObject obj : gameObjects.values()) {
|
||||||
if (object.getClass().equals(clazz)) {
|
|
||||||
objects.add(object);
|
if (obj.getClass().equals(clazz)) {
|
||||||
|
matchingObjects.add(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return objects;
|
return matchingObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArrayList<GameObject> getGameObjects() {
|
|
||||||
return gameObjects;
|
public ArrayList<GameObject> findObjects(int mapInfo) {
|
||||||
|
|
||||||
|
ArrayList<GameObject> matchingObjects = new ArrayList<>(2);
|
||||||
|
|
||||||
|
for (GameObject obj : gameObjects.values()) {
|
||||||
|
if ((obj.getMapInfo() & mapInfo) == mapInfo) {
|
||||||
|
matchingObjects.add(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matchingObjects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addObject(GameObject object) {
|
||||||
|
gameObjects.put(object.getObjectId(), object);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeObject(GameObject object) {
|
||||||
|
gameObjects.remove(object.getObjectId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public GameObject findObject(long objectId) {
|
||||||
|
return gameObjects.get(objectId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update this World and its GameObjects
|
* Update this World and its GameObjects
|
||||||
* <br>
|
* <br>
|
||||||
@ -122,13 +146,11 @@ public class World implements MongoSerialisable {
|
|||||||
GameEvent event = new WorldUpdateEvent(this);
|
GameEvent event = new WorldUpdateEvent(this);
|
||||||
GameServer.INSTANCE.getEventDispatcher().dispatch(event); //Ignore cancellation
|
GameServer.INSTANCE.getEventDispatcher().dispatch(event); //Ignore cancellation
|
||||||
|
|
||||||
ArrayList<GameObject> gameObjects_ = new ArrayList<>(gameObjects);
|
for (GameObject object : gameObjects.values()) {
|
||||||
|
|
||||||
for (GameObject object : gameObjects_) {
|
|
||||||
//Clean up dead objects
|
//Clean up dead objects
|
||||||
if (object.isDead()) {
|
if (object.isDead()) {
|
||||||
object.onDeadCallback();
|
object.onDeadCallback();
|
||||||
gameObjects.remove(object);
|
removeObject(object);
|
||||||
//LogManager.LOGGER.fine("Removed object " + object + " id: " + object.getObjectId());
|
//LogManager.LOGGER.fine("Removed object " + object + " id: " + object.getObjectId());
|
||||||
} else if (object instanceof Updatable) {
|
} else if (object instanceof Updatable) {
|
||||||
((Updatable) object).update();
|
((Updatable) object).update();
|
||||||
@ -142,8 +164,7 @@ public class World implements MongoSerialisable {
|
|||||||
BasicDBObject dbObject = new BasicDBObject();
|
BasicDBObject dbObject = new BasicDBObject();
|
||||||
|
|
||||||
BasicDBList objects = new BasicDBList();
|
BasicDBList objects = new BasicDBList();
|
||||||
ArrayList<GameObject> gameObjects_ = new ArrayList<>(gameObjects);
|
for (GameObject obj : gameObjects.values()) {
|
||||||
for (GameObject obj : gameObjects_) {
|
|
||||||
objects.add(obj.mongoSerialise());
|
objects.add(obj.mongoSerialise());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -215,7 +236,7 @@ public class World implements MongoSerialisable {
|
|||||||
GameObject object = GameObject.deserialize((DBObject) obj);
|
GameObject object = GameObject.deserialize((DBObject) obj);
|
||||||
|
|
||||||
object.setWorld(world);
|
object.setWorld(world);
|
||||||
world.gameObjects.add(object);
|
world.addObject(object);
|
||||||
}
|
}
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
@ -254,7 +275,7 @@ public class World implements MongoSerialisable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Objects
|
//Objects
|
||||||
for (GameObject obj : this.gameObjects) {
|
for (GameObject obj : gameObjects.values()) {
|
||||||
mapInfo[obj.getX()][obj.getY()] |= obj.getMapInfo();
|
mapInfo[obj.getX()][obj.getY()] |= obj.getMapInfo();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -308,17 +329,16 @@ public class World implements MongoSerialisable {
|
|||||||
*/
|
*/
|
||||||
public ArrayList<GameObject> getGameObjectsBlockingAt(int x, int y) {
|
public ArrayList<GameObject> getGameObjectsBlockingAt(int x, int y) {
|
||||||
|
|
||||||
ArrayList<GameObject> gameObjects = new ArrayList<>(2);
|
ArrayList<GameObject> objectsLooking = new ArrayList<>(2);
|
||||||
|
for (GameObject obj : gameObjects.values()) {
|
||||||
for (GameObject obj : this.gameObjects) {
|
|
||||||
|
|
||||||
if (obj.isAt(x, y)) {
|
if (obj.isAt(x, y)) {
|
||||||
gameObjects.add(obj);
|
objectsLooking.add(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gameObjects;
|
return objectsLooking;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -332,17 +352,15 @@ public class World implements MongoSerialisable {
|
|||||||
* @return the list of game objects at a location
|
* @return the list of game objects at a location
|
||||||
*/
|
*/
|
||||||
public ArrayList<GameObject> getGameObjectsAt(int x, int y) {
|
public ArrayList<GameObject> getGameObjectsAt(int x, int y) {
|
||||||
ArrayList<GameObject> gameObjects = new ArrayList<>(2);
|
ArrayList<GameObject> objectsAt = new ArrayList<>(2);
|
||||||
|
for (GameObject obj : gameObjects.values()) {
|
||||||
|
|
||||||
for (GameObject obj : this.gameObjects) {
|
if (obj.isAt(x, y)) {
|
||||||
|
objectsAt.add(obj);
|
||||||
if (obj.getX() == x && obj.getY() == y) {
|
|
||||||
gameObjects.add(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return objectsAt;
|
||||||
return gameObjects;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void incUpdatable() {
|
public void incUpdatable() {
|
||||||
@ -425,4 +443,7 @@ public class World implements MongoSerialisable {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<GameObject> getGameObjects() {
|
||||||
|
return gameObjects.values();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,35 +1,12 @@
|
|||||||
package net.simon987.server.io;
|
package net.simon987.server.io;
|
||||||
|
|
||||||
import net.simon987.server.logging.LogManager;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.zip.ZipEntry;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
|
|
||||||
private static final int BUFFER_SIZE = 1024;
|
|
||||||
private static final String STR_ENCODING = "UTF-8";
|
|
||||||
private static final String DATE_FORMAT = "yyyyMMddHHmmss";
|
private static final String DATE_FORMAT = "yyyyMMddHHmmss";
|
||||||
private static final String FILE_TYPE = ".zip";
|
|
||||||
private static final Path ROOT_DIR;
|
|
||||||
private static final String DIR_NAME = "history";
|
|
||||||
public static final Path DIR_PATH;
|
|
||||||
|
|
||||||
static {
|
|
||||||
ROOT_DIR = Paths.get(".").normalize();
|
|
||||||
DIR_PATH = ROOT_DIR.resolve(DIR_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Private constructor
|
|
||||||
private FileUtils() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new stamp containing the current date and time
|
* Creates a new stamp containing the current date and time
|
||||||
@ -42,143 +19,4 @@ public class FileUtils {
|
|||||||
return f.format(millisToDate);
|
return f.format(millisToDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Created a directory if none exists with the specified name
|
|
||||||
*
|
|
||||||
* @param directory folder to create
|
|
||||||
* @return true is the file exists or create operation is successful
|
|
||||||
*/
|
|
||||||
public static boolean prepDirectory(Path directory) {
|
|
||||||
File file = directory.toFile();
|
|
||||||
|
|
||||||
//If the directory exists or the directory created successfully return true
|
|
||||||
if (file.exists() || file.mkdir()) {
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
System.out.println("Error creating directory: " + file.toString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a file into an array of bytes
|
|
||||||
*
|
|
||||||
* @param path the file to be converted into bytes
|
|
||||||
* @return the byte array of the given file
|
|
||||||
*/
|
|
||||||
public static byte[] bytifyFile(Path path) {
|
|
||||||
byte[] bytes = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
bytes = Files.readAllBytes(path);
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
|
||||||
System.out.println("Failed to extract bytes from: " + path);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Takes in a file that had been converted to a byte[] to be written to a new
|
|
||||||
* zip file
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* contains data in byte array form to be written, typically a file
|
|
||||||
* that has been converted with bytifyFile()
|
|
||||||
* @throws IOException
|
|
||||||
* if an error occurs during the write process
|
|
||||||
*/
|
|
||||||
public static void writeSaveToZip(String name, byte[] data) throws IOException {
|
|
||||||
|
|
||||||
String newFile = DIR_PATH.resolve(getDateTimeStamp() + FILE_TYPE).toString();
|
|
||||||
FileOutputStream output = new FileOutputStream(newFile);
|
|
||||||
ZipOutputStream stream = new ZipOutputStream(output);
|
|
||||||
byte[] buffer = new byte[BUFFER_SIZE];
|
|
||||||
ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
|
|
||||||
|
|
||||||
while ((bais.read(buffer)) > -1) {
|
|
||||||
// File name
|
|
||||||
ZipEntry entry = new ZipEntry(name);
|
|
||||||
// Set to start of next entry in the stream.
|
|
||||||
stream.putNextEntry(entry);
|
|
||||||
// Data to write.
|
|
||||||
stream.write(data);
|
|
||||||
// Close the current entry.
|
|
||||||
stream.closeEntry();
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.close();
|
|
||||||
output.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void cleanHistory(int size) {
|
|
||||||
|
|
||||||
|
|
||||||
File[] files = new File(DIR_PATH.toString()).listFiles();
|
|
||||||
File[] sorted = new File[size];
|
|
||||||
|
|
||||||
File currentFile;
|
|
||||||
boolean changed;
|
|
||||||
|
|
||||||
if (files != null) {
|
|
||||||
for (int i = 0; i < files.length / 2; i++) {
|
|
||||||
currentFile = files[i];
|
|
||||||
files[i] = files[files.length - i - 1];
|
|
||||||
files[files.length - i - 1] = currentFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int f = 0; f < files.length; f++) {
|
|
||||||
changed = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
long dirFile = Long.parseLong(files[f].getName().substring(0, (files[f].getName().length() - 4)));
|
|
||||||
|
|
||||||
if (f < size && sorted[f] == null) {
|
|
||||||
sorted[f] = files[f];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
for (int s = 0; s < sorted.length; s++) {
|
|
||||||
|
|
||||||
long sortedFile = Long.parseLong(sorted[s].getName().substring(0, (sorted[s].getName().length() - 4)));
|
|
||||||
|
|
||||||
if (dirFile > sortedFile) {
|
|
||||||
|
|
||||||
if (s == sorted.length - 1) {
|
|
||||||
sorted[s] = files[f];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
sorted[s] = files[f];
|
|
||||||
}
|
|
||||||
|
|
||||||
changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!changed) {
|
|
||||||
files[f].delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
} catch (NumberFormatException e) {
|
|
||||||
LogManager.LOGGER.info("Non-save file in history directory: " + files[f].getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Converts a byte array into human readable format using the provided encoding
|
|
||||||
*
|
|
||||||
* @param bytes data to be encoded to String
|
|
||||||
* @return a String containing the encoded bytes
|
|
||||||
*/
|
|
||||||
public static String byteArrAsString(byte[] bytes) throws UnsupportedEncodingException {
|
|
||||||
return new String(bytes, STR_ENCODING);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ import net.simon987.server.logging.LogManager;
|
|||||||
import org.json.simple.JSONArray;
|
import org.json.simple.JSONArray;
|
||||||
import org.json.simple.JSONObject;
|
import org.json.simple.JSONObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
public class ObjectsRequestHandler implements MessageHandler {
|
public class ObjectsRequestHandler implements MessageHandler {
|
||||||
|
|
||||||
|
|
||||||
@ -29,13 +27,12 @@ public class ObjectsRequestHandler implements MessageHandler {
|
|||||||
World world = GameServer.INSTANCE.getGameUniverse().getWorld(x, y, false);
|
World world = GameServer.INSTANCE.getGameUniverse().getWorld(x, y, false);
|
||||||
|
|
||||||
if (world != null) {
|
if (world != null) {
|
||||||
ArrayList<GameObject> gameObjects = world.getGameObjects();
|
|
||||||
|
|
||||||
JSONObject response = new JSONObject();
|
JSONObject response = new JSONObject();
|
||||||
JSONArray objects = new JSONArray();
|
JSONArray objects = new JSONArray();
|
||||||
|
|
||||||
|
|
||||||
for (GameObject object : gameObjects) {
|
for (GameObject object : world.getGameObjects()) {
|
||||||
objects.add(object.serialise());
|
objects.add(object.serialise());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@ public class TerrainRequestHandler implements MessageHandler {
|
|||||||
try {
|
try {
|
||||||
world = GameServer.INSTANCE.getGameUniverse().getWorld(
|
world = GameServer.INSTANCE.getGameUniverse().getWorld(
|
||||||
Long.valueOf((long) json.get("x")).intValue(),
|
Long.valueOf((long) json.get("x")).intValue(),
|
||||||
Long.valueOf((long) json.get("y")).intValue(), false);
|
Long.valueOf((long) json.get("y")).intValue(), true);
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
LogManager.LOGGER.severe("FIXME: handle TerrainRequestHandler");
|
LogManager.LOGGER.severe("FIXME: handle TerrainRequestHandler");
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user