diff --git a/src/main/NGECore.java b/src/main/NGECore.java index e6ac7704..60762ced 100644 --- a/src/main/NGECore.java +++ b/src/main/NGECore.java @@ -136,27 +136,27 @@ import engine.servers.PingServer; @SuppressWarnings("unused") public class NGECore { - + private static boolean logUnhandledExceptions = true; - + public static boolean didServerCrash = false; - + private static NGECore instance; - + private Config config = null; private Config options = null; private String motd = ""; private volatile boolean isShuttingDown = false; private long galacticTime = System.currentTimeMillis(); private int galaxyStatus = -1; - + private ConcurrentHashMap clients = new ConcurrentHashMap(); - + // Database - + private DatabaseConnection databaseConnection = null; private DatabaseConnection databaseConnection2 = null; - + // Services public LoginService loginService; public RetroService retroService; @@ -208,59 +208,58 @@ public class NGECore { // public BattlefieldService battlefieldService; public InvasionService invasionService; public AdminService adminService; - + // Login Server public NetworkDispatch loginDispatch; private MINAServer loginServer; - + // Zone Server public NetworkDispatch zoneDispatch; private MINAServer zoneServer; - + // Interactive Jython Console public InteractiveJythonAcceptor jythonAcceptor; private InteractiveJythonServer jythonServer; - + private ObjectDatabase mailODB; private ObjectDatabase guildODB; private ObjectDatabase objectIdODB; private ObjectDatabase duplicateIdODB; + private ObjectDatabase reusableIdODB; private ObjectDatabase chatRoomODB; - - private BusConfiguration eventBusConfig = BusConfiguration.Default(1, - new ThreadPoolExecutor(1, 4, 1, TimeUnit.MINUTES, - new LinkedBlockingQueue())); - + + private BusConfiguration eventBusConfig = BusConfiguration.Default(1, new ThreadPoolExecutor(1, 4, 1, TimeUnit.MINUTES, new LinkedBlockingQueue())); + private ObjectDatabase auctionODB; private ObjectDatabase resourceHistoryODB; private ObjectDatabase swgObjectODB; private ObjectDatabase bountiesODB; private ObjectDatabase cityODB; - + public static boolean PACKET_DEBUG = false; - + public NGECore() { - instance = this; } - + // our entry point public static void main(String[] args) { // With this class, we are overwriting the JVM's way of handling // exceptions that are never caught. Very handy so no try/catch spam for // every method. - if (logUnhandledExceptions) - Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger( - "./logs/uncaught")); - + if (logUnhandledExceptions) { + Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionLogger( "./logs/uncaught")); + } + NGECore core = new NGECore(); - + core.start(); - + do { if (didServerCrash) { core.restart(); } + try { Thread.sleep(1000); } catch (InterruptedException e) { @@ -269,12 +268,12 @@ public class NGECore { } while (true); } - + public void start() { - instance = this; - + final ThreadMonitor deadlockDetector = new ThreadMonitor(); + Thread deadlockMonitor = new Thread(new Runnable() { @Override public void run() { @@ -286,29 +285,37 @@ public class NGECore { } } }); + deadlockMonitor.start(); + config = new Config(); + config.setFilePath("nge.cfg"); + if (!(config.loadConfigFile())) { config = DefaultConfig.getConfig(); } - + DevLogQueuer devLogQueuer = new DevLogQueuer(); CharonPacketLogger packetLogger; - if (PACKET_DEBUG) + + if (PACKET_DEBUG) { packetLogger = new CharonPacketLogger(); + } options = new Config(); + options.setFilePath("options.cfg"); + if (!(options.loadConfigFile())) { System.err.println("Failed to load options.cfg!"); options = DefaultConfig.getConfig(); } - + if (options.getInt("CLEAN.ODB.FOLDERS") > 0) { File baseFolder = new File("./odb"); - + if (baseFolder.isDirectory()) { for (File odbFolder : baseFolder.listFiles()) { if (odbFolder.isDirectory()) { @@ -322,10 +329,10 @@ public class NGECore { } } } - + System.out.println("Cleaned ODB Folders."); } - + try (BufferedReader br = new BufferedReader( new FileReader("./motd.txt"))) { for (String line; (line = br.readLine()) != null;) { @@ -334,14 +341,13 @@ public class NGECore { } catch (IOException e1) { e1.printStackTrace(); } - + // Database databaseConnection = new DatabaseConnection(); - databaseConnection.connect(config.getString("DB.URL"), - config.getString("DB.NAME"), config.getString("DB.USER"), - config.getString("DB.PASS"), "postgresql"); - + databaseConnection.connect(config.getString("DB.URL"), config.getString("DB.NAME"), config.getString("DB.USER"), config.getString("DB.PASS"), "postgresql"); + String db2Url = config.getString("DB2.URL"); + if (db2Url == null || db2Url.matches("^\\s*$")) { databaseConnection2 = null; } else { @@ -350,9 +356,9 @@ public class NGECore { config.getString("DB2.NAME"), config.getString("DB2.USER"), config.getString("DB2.PASS"), "mysql"); } - + setGalaxyStatus(GalaxyStatus.Loading); - + if (options.getInt("CLEAN.CHARACTERS.TABLE") > 0) { try { databaseConnection.preparedStatement("DELETE FROM characters") @@ -360,29 +366,22 @@ public class NGECore { } catch (SQLException e) { e.printStackTrace(); } + System.out.println("Cleared characters table."); } - - swgObjectODB = new ObjectDatabase("swgobjects", true, true, true, - SWGObject.class); + + swgObjectODB = new ObjectDatabase("swgobjects", true, true, true, SWGObject.class); mailODB = new ObjectDatabase("mails", true, true, true, Mail.class); - guildODB = new ObjectDatabase("guild", true, true, true, - GuildObject.class); - objectIdODB = new ObjectDatabase("oids", true, true, true, - ObjectId.class); - duplicateIdODB = new ObjectDatabase("doids", true, true, true, - DuplicateId.class); - chatRoomODB = new ObjectDatabase("chatRooms", true, true, true, - ChatRoom.class); - resourceHistoryODB = new ObjectDatabase("resourcehistory", true, true, - true, GalacticResource.class); - auctionODB = new ObjectDatabase("auction", true, true, true, - AuctionItem.class); - bountiesODB = new ObjectDatabase("bounties", true, true, true, - BountyListItem.class); - cityODB = new ObjectDatabase("cities", true, true, true, - PlayerCity.class); - + guildODB = new ObjectDatabase("guild", true, true, true, GuildObject.class); + objectIdODB = new ObjectDatabase("oids", true, true, true, ObjectId.class); + duplicateIdODB = new ObjectDatabase("doids", true, true, true, DuplicateId.class); + reusableIdODB = new ObjectDatabase("reusableIds", true, true, true, ObjectId.class); + chatRoomODB = new ObjectDatabase("chatRooms", true, true, true, ChatRoom.class); + resourceHistoryODB = new ObjectDatabase("resourcehistory", true, true, true, GalacticResource.class); + auctionODB = new ObjectDatabase("auction", true, true, true, AuctionItem.class); + bountiesODB = new ObjectDatabase("bounties", true, true, true, BountyListItem.class); + cityODB = new ObjectDatabase("cities", true, true, true, PlayerCity.class); + // Services loginService = new LoginService(this); retroService = new RetroService(this); @@ -390,7 +389,7 @@ public class NGECore { characterService = new CharacterService(this); mapService = new MapService(this); travelService = new TravelService(this); - + factionService = new FactionService(this); objectService = new ObjectService(this); terrainService = new TerrainService(this); @@ -418,12 +417,12 @@ public class NGECore { staticService = new StaticService(this); reverseEngineeringService = new ReverseEngineeringService(this); petService = new PetService(this); - + if (options.getInt("LOAD.RESOURCE.SYSTEM") == 1) { surveyService = new SurveyService(this); resourceService = new ResourceService(this); } - + if (config.keyExists("JYTHONCONSOLE.PORT")) { int jythonPort = config.getInt("JYTHONCONSOLE.PORT"); if (jythonPort > 0) { @@ -437,12 +436,13 @@ public class NGECore { jythonServer.start(); } } + spawnService = new SpawnService(this); aiService = new AIService(this); missionService = new MissionService(this); questService = new QuestService(this); invasionService = new InvasionService(this); - + // Ping Server if (config.keyExists("PING.PORT")) if (config.getInt("PING.PORT") != 0) { @@ -459,11 +459,11 @@ public class NGECore { else System.out .println("Warning: pingServer was not launched. Port not specified."); - + // Login Server loginDispatch = new NetworkDispatch(this, false); loginDispatch.addService(loginService); - + if (config.keyExists("LOGIN.PORT")) if (config.getInt("LOGIN.PORT") != 0) { loginServer = new MINAServer(loginDispatch, @@ -475,7 +475,7 @@ public class NGECore { else System.out .println("Warning: loginServer was not launched. Port not specified."); - + // Zone Server zoneDispatch = new NetworkDispatch(this, true); zoneDispatch.addService(retroService); @@ -502,26 +502,24 @@ public class NGECore { zoneDispatch.addService(reverseEngineeringService); zoneDispatch.addService(petService); zoneDispatch.addService(invasionService); - + if (options.getInt("LOAD.RESOURCE.SYSTEM") == 1) { zoneDispatch.addService(surveyService); zoneDispatch.addService(resourceService); } - + if (config.keyExists("ZONE.PORT")) if (config.getInt("ZONE.PORT") != 0) { zoneServer = new MINAServer(zoneDispatch, config.getInt("ZONE.PORT")); zoneServer.start(); } else - System.out - .println("Warning: zoneServer was not launched. Port equals 0."); + System.out.println("Warning: zoneServer was not launched. Port equals 0."); else - System.out - .println("Warning: zoneServer was not launched. Port not specified."); - + System.out.println("Warning: zoneServer was not launched. Port not specified."); + // Start terrainList - + // Original Planets terrainService.addPlanet(1, "tatooine", "terrain/tatooine.trn", true); terrainService.addPlanet(2, "naboo", "terrain/naboo.trn", true); @@ -534,34 +532,29 @@ public class NGECore { terrainService.addPlanet(9, "endor", "terrain/endor.trn", true); terrainService.addPlanet(10, "dathomir", "terrain/dathomir.trn", true); terrainService.addPlanet(11, "mustafar", "terrain/mustafar.trn", true); - terrainService.addPlanet(12, "kashyyyk_main", - "terrain/kashyyyk_main.trn", true); - + terrainService.addPlanet(12, "kashyyyk_main", "terrain/kashyyyk_main.trn", true); + // Dungeon Terrains // TODO: Fix BufferUnderFlow Errors on loaded of dungeon instances. - terrainService.addPlanet(13, "kashyyyk_dead_forest", - "terrain/kashyyyk_dead_forest.trn", false); - terrainService.addPlanet(14, "kashyyyk_hunting", - "terrain/kashyyyk_hunting.trn", false); - terrainService.addPlanet(15, "kashyyyk_north_dungeons", - "terrain/kashyyyk_north_dungeons.trn", false); - terrainService.addPlanet(16, "kashyyyk_rryatt_trail", - "terrain/kashyyyk_rryatt_trail.trn", false); - terrainService.addPlanet(17, "kashyyyk_south_dungeons", - "terrain/kashyyyk_south_dungeons.trn", false); - terrainService.addPlanet(18, "adventure1", "terrain/adventure1.trn", - false); - terrainService.addPlanet(19, "adventure2", "terrain/adventure2.trn", - false); - + terrainService.addPlanet(13, "kashyyyk_dead_forest", "terrain/kashyyyk_dead_forest.trn", false); + terrainService.addPlanet(14, "kashyyyk_hunting", "terrain/kashyyyk_hunting.trn", false); + terrainService.addPlanet(15, "kashyyyk_north_dungeons", "terrain/kashyyyk_north_dungeons.trn", false); + terrainService.addPlanet(16, "kashyyyk_rryatt_trail", "terrain/kashyyyk_rryatt_trail.trn", false); + terrainService.addPlanet(17, "kashyyyk_south_dungeons", "terrain/kashyyyk_south_dungeons.trn", false); + terrainService.addPlanet(18, "adventure1", "terrain/adventure1.trn", false); + terrainService.addPlanet(19, "adventure2", "terrain/adventure2.trn", false); + // Tutorial Terrains terrainService.addPlanet(20, "dungeon1", "terrain/dungeon1.trn", true); - terrainService.addPlanet(21, "tutorial", "terrain/tutorial.trn", false); // 21B - // droid - // scene + terrainService.addPlanet(21, "tutorial", "terrain/tutorial.trn", false); + + // 21B + // droid + // scene + // terrainService.addPlanet(22, "space_npe_falcon_3", // "terrain/space_npe_falcon_3.trn", false); - + // Space Zones // NOTE: Commented out for now until space is implemented. No need to be // loaded into memory when space is not implemented. @@ -608,62 +601,61 @@ public class NGECore { * terrainService.addPlanet(45, "space_yavin4", * "terrain/space_yavin4.trn", true); */ - + // end terrainList - + if (options.getInt("LOAD.RESOURCE.SYSTEM") > 0) { resourceService.loadResources(); } - + chatService.loadChatRooms(); - + spawnService = new SpawnService(this); terrainService.loadClientPois(); - + // Travel Points travelService.loadTravelPoints(); simulationService = new SimulationService(this); - + terrainService.loadSnapShotObjects(); objectService.loadServerTemplates(); objectService.loadObjects(); harvesterService.loadHarvesters(); - + simulationService.insertSnapShotObjects(); simulationService.insertPersistentBuildings(); - + // Zone services that need to be loaded after the above zoneDispatch.addService(simulationService); - + guildService = new GuildService(this); zoneDispatch.addService(guildService); - + gcwService = new GCWService(this); zoneDispatch.addService(gcwService); - + collectionService = new CollectionService(this); zoneDispatch.addService(collectionService); - + tradeService = new TradeService(this); zoneDispatch.addService(tradeService); - + zoneDispatch.addService(skillService); - + instanceService = new InstanceService(this); zoneDispatch.addService(instanceService); - + weatherService = new WeatherService(this); weatherService.loadPlanetSettings(); - + spawnService.loadMobileTemplates(); spawnService.loadLairTemplates(); spawnService.loadLairGroups(); spawnService.loadDynamicGroups(); - ; spawnService.loadSpawnAreas(); - + staticService.spawnStatics(); - + equipmentService.loadBonusSets(); playerCityService.loadCityRankCaps(); @@ -672,130 +664,124 @@ public class NGECore { questService.loadEvents(); retroService.run(); - + browserService = new BrowserService(this); // battlefieldService = new BattlefieldService(this); adminService = new AdminService(this); - + didServerCrash = false; cleanupCreatureODB(); //just in case we crashed previously... System.out.println("Started Server."); setGalaxyStatus(GalaxyStatus.Online); - } - + public void stop() { System.out.println("Stopping Servers and Connections."); databaseConnection.close(); databaseConnection2.close(); } - + public void restart() { stop(); cleanUp(); + try { Thread.sleep(30000); } catch (InterruptedException e) { } + start(); } - + public void initiateShutdown() { - if (isShuttingDown) + if (isShuttingDown) { return; + } + try { for (int minutes = 15; minutes > 1; minutes--) { - chatService - .broadcastGalaxy("The server will be shutting down soon. Please find a safe place to logout. (" - + minutes + " minutes left)"); + chatService.broadcastGalaxy("The server will be shutting down soon. Please find a safe place to logout. (" + minutes + " minutes left)"); Thread.sleep(60000); } + setGalaxyStatus(GalaxyStatus.Locked); - chatService - .broadcastGalaxy("The server will be shutting down soon. Please find a safe place to logout. (" - + 1 + " minutes left)"); + + chatService.broadcastGalaxy("The server will be shutting down soon. Please find a safe place to logout. (" + 1 + " minutes left)"); Thread.sleep(30000); - chatService - .broadcastGalaxy("You will be disconnected in 30 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now."); + chatService.broadcastGalaxy("You will be disconnected in 30 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now."); Thread.sleep(20000); - chatService - .broadcastGalaxy("You will be disconnected in 10 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now."); + chatService.broadcastGalaxy("You will be disconnected in 10 seconds so the server can perform a final save before shutting down. Please find a safe place to logout now."); Thread.sleep(10000); - chatService - .broadcastGalaxy("You will now be disconnected so the server can perform a final save before shutting down."); - + chatService.broadcastGalaxy("You will now be disconnected so the server can perform a final save before shutting down."); + synchronized (getActiveConnectionsMap()) { for (Client client : getActiveConnectionsMap().values()) { client.getSession().close(true); connectionService.disconnect(client); } } - + System.exit(0); - } catch (InterruptedException e) { e.printStackTrace(); } } - + public void initiateStop() { - if (isShuttingDown) + if (isShuttingDown) { return; + } + try { - chatService - .broadcastGalaxy("You will now be disconnected so the server can perform a final save before shutting down."); + chatService.broadcastGalaxy("You will now be disconnected so the server can perform a final save before shutting down."); + Thread.sleep(10000); + synchronized (getActiveConnectionsMap()) { for (Client client : getActiveConnectionsMap().values()) { client.getSession().close(true); connectionService.disconnect(client); } } - + System.exit(0); - } catch (InterruptedException e) { e.printStackTrace(); } } - + public void cleanUp() { System.out.println("Cleaning Up..."); long memoryUsed = Runtime.getRuntime().freeMemory(); System.out.println("Using " + memoryUsed + " bytes of memory."); - config = null; databaseConnection = null; databaseConnection2 = null; cleanupCreatureODB(); Runtime.getRuntime().gc(); - System.out.println("Cleaned Up " - + (Runtime.getRuntime().freeMemory() - memoryUsed) - + " bytes of memory."); + System.out.println("Cleaned Up " + (Runtime.getRuntime().freeMemory() - memoryUsed) + " bytes of memory."); } - + public void setGalaxyStatus(int statusId) { - galaxyStatus = statusId; int galaxyId = config.getInt("GALAXY_ID"); - + try { - PreparedStatement ps = databaseConnection - .preparedStatement("UPDATE \"connectionServers\" SET \"statusId\"=? WHERE \"galaxyId\"=?"); + PreparedStatement ps = databaseConnection.preparedStatement("UPDATE \"connectionServers\" SET \"statusId\"=? WHERE \"galaxyId\"=?"); ps.setInt(1, statusId); ps.setInt(2, galaxyId); ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); } - } - + public int getActiveClients() { int connections = 0; + for (Map.Entry c : clients.entrySet()) { if (c.getValue().getSession() != null) { if (c.getValue().getSession().isConnected()) { @@ -803,22 +789,24 @@ public class NGECore { } } } + return connections; } - + public int getActiveZoneClients() { int connections = 0; + for (Map.Entry c : clients.entrySet()) { if (c.getValue().getSession() != null) { - if (c.getValue().getSession().isConnected() - && c.getValue().getParent() != null) { + if (c.getValue().getSession().isConnected() && c.getValue().getParent() != null) { connections++; } } } + return connections; } - + public void closeODBs() { swgObjectODB.close(); mailODB.close(); @@ -827,10 +815,11 @@ public class NGECore { resourceHistoryODB.close(); objectIdODB.close(); duplicateIdODB.close(); + reusableIdODB.close(); auctionODB.close(); cityODB.close(); } - + public Vector getExcludedDevelopers() { Vector excludedDevelopers = new Vector(); // excludedDevelopers.add("Charon"); @@ -839,138 +828,147 @@ public class NGECore { // without having to change options.cfg all the time return excludedDevelopers; } - + //our lone private function //TODO: we could speed this up if we put all the creature object id's into a list //and then replace the call to playerExists with a function that selects object id's //that are not in the list of object id's - those would be returned and deleted all at once private void cleanupCreatureODB() { ODBCursor cursor = swgObjectODB.getCursor(); - + int deleteCount = 0; - + while (cursor.hasNext()) { Object next = cursor.next(); - if (next == null) + + if (next == null) { continue; + } + SWGObject creature = (SWGObject) next; - if (!characterService.playerExists(creature.getObjectID()) - && creature instanceof CreatureObject) { + + if (!characterService.playerExists(creature.getObjectID()) && creature instanceof CreatureObject) { swgObjectODB.remove(creature.getObjectID()); deleteCount++; } } + cursor.close(); - + System.out.println("Deleted " + Integer.toString(deleteCount) + " creatures."); } /* * ---------- Getter methods for NGECore ---------- */ - + public int getGalaxyStatus() { return galaxyStatus; } - + public Config getConfig() { return config; } - + public String getGalaxyName() { return config.getString("GALAXY_NAME"); } - + public DatabaseConnection getDatabase1() { return databaseConnection; } - + public DatabaseConnection getDatabase2() { return databaseConnection2; } - + public ObjectDatabase getSWGObjectODB() { return swgObjectODB; } - + public ObjectDatabase getMailODB() { return mailODB; } - + public ObjectDatabase getGuildODB() { return guildODB; } - + public ObjectDatabase getObjectIdODB() { return objectIdODB; } - + public ObjectDatabase getDuplicateIdODB() { return duplicateIdODB; } - + + public ObjectDatabase getReusableIdODB() { + return reusableIdODB; + } + public ObjectDatabase getChatRoomODB() { return chatRoomODB; } - + public ObjectDatabase getBountiesODB() { return bountiesODB; } - + public ObjectDatabase getResourceHistoryODB() { return resourceHistoryODB; } - + public ObjectDatabase getAuctionODB() { return auctionODB; } - + public ObjectDatabase getCityODB() { return cityODB; } - + public Client getClient(IoSession session) { return clients.get(session); } - + public ConcurrentHashMap getActiveConnectionsMap() { return clients; } - + public void addClient(IoSession session, Client client) { clients.put(session, client); } - + public void removeClient(IoSession session) { clients.remove(session); } - + // for python scripts public Thread getCurrentThread() { return Thread.currentThread(); } - + public static NGECore getInstance() { return instance; } - + public BusConfiguration getEventBusConfig() { return eventBusConfig; } - + public long getGalacticTime() { return System.currentTimeMillis() - galacticTime; } - + public String getMotd() { return motd; } - + public void setMotd(String motd) { this.motd = motd; } - + public Config getOptions() { return options; } + }