public static void Main(string[] args) { //MapData.MapList(); //this has to be packed once all mapdata is gotten. ObjectData.load(); ItemData.load(); //this has to be first because npcDrops use itemData.. i think. NpcData.load(); //first load the npc data. NpcDrop.load(); //second load the npc drops. [order does matter here, as it binds to npcData]. NpcSpawn.load(); //finally you can spawn the npcs. LaddersAndStairs.load(); objectManager = new WorldObjectManager(); groundItemManager = new GroundItemManager(); shopManager = new ShopManager(); minigames = new MinigamesHandler(); grandExchange = new GrandExchange(); clanManager = new ClanManager(); packetHandlers = new PacketHandlers(); loginHandler = new LoginHandler(); registerEvent(new RunEnergyEvent()); registerEvent(new LevelChangeEvent()); registerEvent(new SpecialRestoreEvent()); registerEvent(new SkullCycleEvent()); registerEvent(new AreaVariables()); registerEvent(new AggressiveNpcEvent()); registerEvent(new LowerPotionCyclesEvent()); objectManager.getFarmingPatches().processPatches(); isRunning = true; new Thread(new ThreadStart(Server.eventProcessingThread)).Start(); Console.Title = "RS2 530 C# Server"; // setup the listener try { IPEndPoint ipe = new IPEndPoint(0, Constants.SERVER_PORT); serverListenerSocket = new System.Net.Sockets.Socket(ipe.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp); serverListenerSocket.Bind(ipe); serverListenerSocket.Listen(25); //backlog serverListenerSocket.BeginAccept(new AsyncCallback(acceptCallback), serverListenerSocket); Console.WriteLine("RS2 530 C# server started on port " + Constants.SERVER_PORT); } catch (SocketException ioe) { Misc.WriteError("Error: Unable to startup listener on " + Constants.SERVER_PORT + " - port already in use?"); Misc.WriteError(ioe.Message.ToString()); isRunning = false; } while (isRunning) { // could do game updating stuff in here... // maybe do all the major stuff here in a big loop and just do the packet // sending/receiving in the client subthreads. The actual packet forming code // will reside within here and all created packets are then relayed by the subthreads. // This way we avoid all the sync'in issues // The rough outline could look like: // doPlayers() // updates all player related stuff // doNpcs() // all npc related stuff // doObjects() // doWhatever() curTime = Environment.TickCount; if (curTime - lastInfoTime >= 2000 && !toggledStats) { Console.Title = "RS2 C# Server [Players: " + players.Count + "][Connections: " + connections.Count + "]"; lastInfoTime = curTime; toggledStats = true; } else if (curTime - lastInfoTime >= 4000 && toggledStats) { Console.Title = "RS2 C# Server [Events Running: " + events.Count + "]"; lastInfoTime = curTime; toggledStats = false; } lock (connections) { foreach (Connection c in connections.ToArray()) //these are logged in players. //ThreadPool.QueueUserWorkItem(c.processQueuedPackets); { c.processQueuedPackets(null); } foreach (Connection c in connections.ToArray()) //update server. { if (LoginHandler.removableConnection(c)) { removeConnection(c); } } } lock (players) { foreach (Player p in players) { p.tick(); p.processQueuedHits(); //if (p.getWalkingQueue().hasNextStep() || p.getTeleportTo() != null) p.getWalkingQueue().getNextPlayerMovement(); } } lock (npcs) { foreach (Npc n in npcs) { n.tick(); n.processQueuedHits(); } } lock (players) { foreach (Player p in players) { if (p == null) { continue; } if (p.isActive()) { PlayerUpdate.update(p); NpcUpdate.update(p); //In case the player turns active in the loop below make sure it doesn't clear flags. if (!p.getUpdateFlags().isClearable()) { p.getUpdateFlags().setClearable(true); } } } foreach (Player p in players) { if (p.isActive() && p.getUpdateFlags().isClearable() && p.getUpdateFlags().isUpdateRequired()) { p.getUpdateFlags().clear(); } p.getHits().clear(); if (!p.getConnection().socket.Connected || p.isDisconnected()) { unregister(p); //This must be after PlayerUpdate or chance of messing up playerIndexes for PlayerUpdate } } } lock (npcs) { foreach (Npc n in npcs) { if (n.getUpdateFlags().isUpdateRequired()) { n.getUpdateFlags().clear(); } n.getHits().clear(); } } try { System.Threading.Thread.Sleep(500 - (Environment.TickCount - curTime)); } catch { } } Console.WriteLine("Server has shutdown successfully, press any key to exit console."); //Console.ReadKey(true); Console.ReadLine(); }
public static void gameThread() { while (isRunning) { // could do game updating stuff in here... // maybe do all the major stuff here in a big loop and just do the packet // sending/receiving in the client subthreads. The actual packet forming code // will reside within here and all created packets are then relayed by the subthreads. // This way we avoid all the sync'in issues // The rough outline could look like: // doPlayers() // updates all player related stuff // doNpcs() // all npc related stuff // doObjects() // doWhatever() curTime = Environment.TickCount; if (curTime - lastInfoTime >= 2000 && !toggledStats) { Console.Title = "Runescape 530 C# Server [Players: " + players.Count + "][Connections: " + connections.Count + "]"; lastInfoTime = curTime; toggledStats = true; } else if (curTime - lastInfoTime >= 4000 && toggledStats) { Console.Title = "Runescape 530 C# Server [Events Running: " + events.Count + "]"; lastInfoTime = curTime; toggledStats = false; } lock (connections) { /* * This recieving packets now use the Task for threadpooling, why its better. * If one person decides to send a bunch of tiny packets in max buffer size * Pretty much 5kb packets with a maybe 4k packets per packet it will cause * serious lag problem because it has to process all one user's packets first * before it moves onto processing next player's packets, Task solves this * issue. */ foreach (Connection c in connections) { if (!c.hasRunningThread() && c.hasQueuedPackets()) { c.setRunningThread(true); Task.Factory.StartNew(c.processQueuedPackets); } } foreach (Connection c in connections) //update server. { if (LoginHandler.removableConnection(c)) { removeConnection(c); } } } lock (players) { foreach (Player p in players) { p.tick(); p.processQueuedHits(); //if (p.getWalkingQueue().hasNextStep() || p.getTeleportTo() != null) p.getWalkingQueue().getNextPlayerMovement(); } } lock (npcs) { foreach (Npc n in npcs) { n.tick(); n.processQueuedHits(); } } lock (players) { foreach (Player p in players) { if (p == null) { continue; } if (p.isActive()) { PlayerUpdate.update(p); NpcUpdate.update(p); //In case the player turns active in the loop below make sure it doesn't clear flags. if (!p.getUpdateFlags().isClearable()) { p.getUpdateFlags().setClearable(true); } } } foreach (Player p in players) { if (p.isActive() && p.getUpdateFlags().isClearable() && p.getUpdateFlags().isUpdateRequired()) { p.getUpdateFlags().clear(); } p.getHits().clear(); if (!p.getConnection().socket.Connected || p.isDisconnected()) { unregister(p); //This must be after PlayerUpdate or chance of messing up playerIndexes for PlayerUpdate } } } lock (npcs) { foreach (Npc n in npcs) { if (n.getUpdateFlags().isUpdateRequired()) { n.getUpdateFlags().clear(); } n.getHits().clear(); } } try { System.Threading.Thread.Sleep(500 - (Environment.TickCount - curTime)); } catch { } } Console.WriteLine("Server has shutdown successfully, press any key to exit console."); //Console.ReadKey(true); Console.ReadLine(); }