Moved the register to MS function to a variable, added Giants enums, implemented plugin system

This commit is contained in:
Amazed 2019-01-23 10:28:23 +01:00
parent 3fd1ea47b3
commit d594e38be5
8 changed files with 129 additions and 45 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
maps/*.gck

View File

@ -30,9 +30,10 @@ class Netserver:
gameserverthread = threading.Thread(target=self.handle_packets)
gameserverthread.start()
#ms = MasterServer(self.server)
#statsserverthread = threading.Thread(target=ms.register_and_run)
#statsserverthread.start()
if self.server.register_with_ms:
ms = MasterServer(self.server)
ms.register()
gameserverthread.join()
#statsserverthread.join()
@ -74,7 +75,7 @@ class Netserver:
er.ApplicationInstanceGUID = self.guid
er.ApplicationGUID = eq.ApplicationGUID
er.ApplicationReservedData = b'\xff' # Map ID
er.ApplicationReservedData += b'\x00\x04\x00'
er.ApplicationReservedData += b'\x00\x04\x00' # game type and teams
er.ApplicationReservedData += b'\xd9\x05' # game version
er.ApplicationReservedData += b'\x02\x92\x05\x00\x01\x00\x00\x00\x00\x00' # Unknown
er.ApplicationReservedData += b'\x9c\x53\xf4\xde' # Seems to be a checksum of current map

View File

@ -0,0 +1,25 @@
class Teams:
MvM = 0x00
MvMvM = 0x01
RvR = 0x02
MvR = 0x03
MvRvK = 0x04
MvK = 0x05
RvK = 0x06
TeamB = 0x07
Crash = 0x5a
class GameTypes:
TeamDeathmatch = 0x00
TeamDeathmatchWithFullBase = 0x01
CaptureSmartie = 0x02
CaptureSmartieWithFullBase = 0x03
BaseBuildDeathmatch = 0x04
BaseBuildCaptureSmartie = 0x05
DefendBase = 0x06
DefendBaseCaptureSmartie = 0x07
GTypeStone = 0x08
GTypeWood = 0x09
Crash = 0x0a
GTypeNull = 0x0c

View File

@ -1,11 +1,24 @@
class Map:
def __init__(self, mapname="Unknown mapname"):
self.mapname = mapname
self.checksum = None
import os
def load_map(self, mapname):
self.checksum = Map.checksum(mapname)
class Map:
def __init__(self, mappath):
self.mappath = mappath
self.checksum = None
self.mapname = "Unknown map"
self.load_map(mappath)
def load_map(self, mappath):
if not os.path.exists("maps/"+mappath):
raise Exception("Map not found: "+mappath)
if not mappath.endswith(".gck"):
raise Exception("Server only supports GCK maps")
self.mapname = mappath.split(".gck")[0]
self.checksum = Map.checksum(mappath)
@staticmethod
def checksum(mapname):
# TODO
return 1

View File

@ -1,5 +1,6 @@
import socket
from dpnet.packet import Packet
import threading
class MasterServer:
@ -9,22 +10,27 @@ class MasterServer:
self.masterserverip = "gckms.no-ip.org"
self.masterserverport = 27900
def register(self):
statsserverthread = threading.Thread(target=self.register_and_run)
statsserverthread.start()
statsserverthread.join()
def register_and_run(self):
self.socket.bind((self.server.listen_ip, 8911))
print("Listening to " + self.server.listen_ip + ":" + str(8911))
print("Registering to Master Server")
self.register()
self._register()
self.keepalive()
self.handle_packets()
def register(self):
def _register(self):
packet = Packet()
packet.write("019711".encode("ascii"))
packet.write(("0"+str(self.server.listen_port)).encode("ascii"))
self.socket.sendto(packet.getvalue(), (self.masterserverip, self.masterserverport))
def keepalive(self):
packet = Packet()
packet.write("119711".encode("ascii"))
packet.write(("1"+str(self.server.listen_port)).encode("ascii"))
self.socket.sendto(packet.getvalue(), (self.masterserverip, self.masterserverport))
def handle_packets(self):

0
plugins/__init__.py Normal file
View File

14
plugins/greetings.py Normal file
View File

@ -0,0 +1,14 @@
class Greetings:
def __init__(self, server):
self.server = server
def on_player_join(self, player):
self.server.broadcast_message("Welcome "+player.name+"!")
def on_map_change(self, newmap):
self.server.broadcast_message("You are now playing on "+newmap.mapname)
def setup(server):
plugin = Greetings(server)
server.add_plugin(plugin)

View File

@ -2,8 +2,14 @@ from giants.map import Map
from giants.player import Player
from dpnet.netserver import Netserver
from dpnet.session import Session
from dpnet.DFrame import DFrame
import socket
import importlib
import os
from giants import Teams, GameTypes
from utils.logger import setup_logger
import traceback
logger = setup_logger(__name__)
class Server:
@ -14,51 +20,69 @@ class Server:
fake_session.ip = "127.0.0.1"
fake_session.port = 3333
self.players = [Player("Amazed4", fake_session)]
self.currentmap = kwargs.get("map", Map("wow rly"))
self.currentmap = kwargs.get("map", Map("Three Way Island - Canyons.gck"))
self.maxplayers = kwargs.get("maxplayers", 20)
self.name = kwargs.get("name", "Default Server Name")
self.accept_new_players = True
self.register_with_ms = False
self.register_with_ms = kwargs.get("register", False)
self.teams = kwargs.get("teams", Teams.MvM)
self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase)
self._plugins = []
# events
self._on_new_player = []
self._on_new_map = []
def new_player(self, player):
def add_player(self, player):
self.players.append(player)
for func in self._on_new_player:
func(player)
self._broadcast_event("on_player_join", player)
def change_map(self, mapname):
for func in self._on_new_map:
func(mapname)
def add_plugin(self, plugin):
self._plugins.append(plugin)
def on_new_player(self, func):
self._on_new_player.append(func)
return func
def change_map(self, mappath):
try:
self.currentmap = Map(mappath)
self._broadcast_event("on_map_change", self.currentmap)
except Exception:
logger.error("Could not change map")
def _broadcast_event(self, event, *args):
logger.debug("Broadcasting event "+event)
for plugin in self._plugins:
if hasattr(plugin, event):
func = getattr(plugin, event)
if callable(func):
try:
func(args)
except Exception:
logger.error("Could not call plugin function: "+plugin.__name__+"."+event)
traceback.print_exc()
def load_plugins(self):
plugins = os.listdir("plugins")
for plugin in plugins:
if os.path.isdir("plugins/"+plugin) or plugin == "__init__.py":
continue
if not plugin.endswith(".py"):
continue
pluginname = plugin.split(".py")[0]
try:
module = importlib.import_module("plugins."+pluginname)
if hasattr(module, "setup"):
setup = getattr(module, "setup")
if callable(setup):
logger.info("Loading plugin "+module.__name__)
module.setup(self)
except Exception:
logger.warn("Could not load plugin "+plugin)
traceback.print_exc()
def broadcast_message(self, text):
for player in self.players:
player.session.send_gamedata(b'\x35\x80\x81'+text.encode("ascii")+b'\x00\x00')
def on_new_map(self, func):
self._on_new_map.append(func)
return func
def run(self):
self.load_plugins()
return Netserver(self).run()
if __name__ == '__main__':
server = Server(name="giantsd", map=Map("expect crashes"), maxplayers=10)
@server.on_new_player
def new_player(player):
#print("A NEW PLAYER HAS JOINED: %s" % player)
pass
@server.on_new_map
def new_map(mapname):
pass
server = Server(name="giantsd", maxplayers=10, register=False)
server.run() # blocking