forked from hipstercat/giantsd
294 lines
11 KiB
Python
294 lines
11 KiB
Python
from dpnet.packet import Packet
|
|
from giants.map import Map
|
|
from giants.player import Player
|
|
from dpnet.netserver import Netserver
|
|
from dpnet.session import Session
|
|
import socket
|
|
import importlib
|
|
import os
|
|
from giants import Teams, GameTypes, ChatColor, ChatType
|
|
from utils.logger import setup_logger
|
|
import traceback
|
|
import asyncio
|
|
from aioconsole import ainput
|
|
import struct
|
|
from curses import wrapper
|
|
|
|
logger = setup_logger(__name__)
|
|
|
|
|
|
class Server:
|
|
def __init__(self, **kwargs):
|
|
self.listen_ip = kwargs.get("ip", "0.0.0.0")
|
|
self.listen_port = kwargs.get("port", 19711)
|
|
self.register_with_ms = kwargs.get("register", False)
|
|
self.teams = kwargs.get("teams", Teams.MvM)
|
|
self.game_type = kwargs.get("gametype", GameTypes.TeamDeathmatchWithFullBase)
|
|
self.currentmap = kwargs.get("map", Map("Testmap.gck"))
|
|
self.maxplayers = kwargs.get("maxplayers", 20)
|
|
self.name = kwargs.get("name", "Default Server Name")
|
|
|
|
fake_session = Session(self, socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
|
fake_session.ip = "127.0.0.1"
|
|
fake_session.port = 3333
|
|
self.players = [Player("[Server]", fake_session)]
|
|
|
|
fake_player = Session(self, socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
|
fake_player.ip = "127.0.0.1"
|
|
fake_player.port = 3334
|
|
self.players.append(Player("Bot 1", fake_player))
|
|
|
|
fake_player = Session(self, socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
|
fake_player.ip = "127.0.0.1"
|
|
fake_player.port = 3334
|
|
self.players.append(Player("Bot 2", fake_player))
|
|
|
|
fake_player = Session(self, socket.socket(socket.AF_INET, socket.SOCK_DGRAM))
|
|
fake_player.ip = "127.0.0.1"
|
|
fake_player.port = 3334
|
|
self.players.append(Player("Bot 3", fake_player))
|
|
|
|
self.accept_new_players = True
|
|
self.version = 1.497
|
|
self.points_per_kill = 1
|
|
self.points_per_capture = 5
|
|
self.detente_time = 0 # minutes
|
|
self._plugins = []
|
|
self.tempplayers = []
|
|
self.running = True
|
|
self.ticks = 60
|
|
|
|
self._nextid = 118
|
|
|
|
def update(self):
|
|
#logger.debug("Calling update")
|
|
pass
|
|
|
|
async def add_player(self, player):
|
|
self.tempplayers.remove(player)
|
|
self.players.append(player)
|
|
await self.broadcast_event("on_player_join", player)
|
|
|
|
# todo: remove
|
|
def create_temp_player(self, player):
|
|
self.tempplayers.append(player)
|
|
|
|
async def remove_player(self, player):
|
|
self.players.remove(player)
|
|
|
|
def add_plugin(self, plugin):
|
|
self._plugins.append(plugin)
|
|
|
|
async def change_map(self, mappath):
|
|
try:
|
|
self.currentmap = Map(mappath)
|
|
await self.broadcast_event("on_map_change", self.currentmap)
|
|
except Exception:
|
|
logger.error("Could not change map")
|
|
|
|
async 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:
|
|
await func(*args)
|
|
except Exception:
|
|
logger.error("Could not call plugin function: "+plugin.__class__.__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.warning("Could not load plugin "+plugin)
|
|
traceback.print_exc()
|
|
|
|
async def broadcast_message(self, text, color=ChatColor.Orange, type=ChatType.All):
|
|
for player in self.players:
|
|
if player.name == "[Server]":
|
|
continue
|
|
await player.send_message(text, color=color, type=type)
|
|
|
|
async def ask_command(self):
|
|
while True:
|
|
try:
|
|
cmd = await ainput(">")
|
|
logger.debug("Sending game payload %s", cmd)
|
|
for player in self.players:
|
|
if player.name == "[Server]":
|
|
continue
|
|
await player.session.send_gamedata(bytes.fromhex(cmd), acknow=False)
|
|
except:
|
|
traceback.print_exc()
|
|
|
|
async def broadcast_gamedata(self, payload, **kwargs):
|
|
for player in self.players:
|
|
if player.name == "[Server]":
|
|
continue
|
|
await player.session.send_gamedata(payload, **kwargs)
|
|
|
|
async def broadcast_gamedata_except(self, player, payload, **kwargs):
|
|
for pplayer in self.players:
|
|
if pplayer.name == "[Server]" or pplayer == player:
|
|
continue
|
|
await pplayer.session.send_gamedata(payload, **kwargs)
|
|
|
|
async def broadcast_message_except(self, player, text, color=ChatColor.Yellow, type=ChatType.All):
|
|
for pplayer in self.players:
|
|
if pplayer.name == "[Server]" or pplayer == player:
|
|
continue
|
|
await pplayer.send_message(text, color=color, type=type)
|
|
|
|
async def new_object(self, model):
|
|
oid = self._nextid
|
|
p = Packet()
|
|
p.putByte(0x05) # opcode
|
|
p.putByte(0)
|
|
p.putShort(self._nextid)
|
|
p.putByte(0x00)
|
|
p.putULong(model)
|
|
p.putByte(0x00)
|
|
self._nextid += 1
|
|
await self.broadcast_gamedata(p.getvalue())
|
|
return oid
|
|
|
|
async def spawn(self, player, model):
|
|
plix = self.get_player_index(player)
|
|
p = Packet()
|
|
p.putByte(0x05) # opcode
|
|
p.putByte(plix)
|
|
p.putShort(self._nextid)
|
|
p.putByte(0x00)
|
|
p.putULong(model)
|
|
p.putByte(0x00)
|
|
|
|
await self.broadcast_gamedata(p.getvalue(), acknow=False)
|
|
#await self.broadcast_gamedata(bytes.fromhex("05" + plix + struct.pack("<H", self._nextid).hex() + "00" + model + "00000000"), acknow=False)
|
|
|
|
p = Packet()
|
|
p.putByte(0x0a) # opcode
|
|
p.putByte(0x12) # length
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(plix) # player index
|
|
p.putShort(self._nextid) # object id
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x01) # unknown
|
|
p.putULong(model) # model
|
|
p.putFloat(player.x) # player x
|
|
p.putFloat(player.y) # player y
|
|
p.putFloat(player.z) # player z
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # orientation
|
|
p.putULong(0x00) # unknown
|
|
|
|
await self.broadcast_gamedata(p.getvalue(), acknow=False)
|
|
|
|
self._nextid+=1
|
|
|
|
#await self.broadcast_gamedata(bytes.fromhex("0a12000000" + plix + struct.pack("<H", self._nextid).hex() + "0003" + model + "00000000"), acknow=False)
|
|
#await self.broadcast_gamedata(bytes.fromhex("0a32000000" + plix + struct.pack("<B", self._nextid).hex() + "000001" + model + "000000ff00000000000000000000000000000000000000000000000000000000000000000000000a12000000" + plix + struct.pack("<B", self._nextid).hex() + "0000" + model + "020000000000000000"), acknow=False)
|
|
|
|
async def change_model(self, player, model):
|
|
plid = self.get_player_index(player)
|
|
# p = Packet()
|
|
# p.putByte(0x0a) # opcode
|
|
# p.putByte(0x12) # length
|
|
# p.putByte(0x00) # unknown
|
|
# p.putByte(0x00) # unknown
|
|
# p.putByte(0x00) # unknown
|
|
# p.putByte(plid) # player index
|
|
# p.putShort(player.oid) # object id
|
|
# p.putByte(0x00) # unknown
|
|
# p.putByte(0x02) # 4 -> death, 3 -> little move
|
|
# p.putULong(model) # model
|
|
# p.putFloat(player.x) # x
|
|
# p.putFloat(player.y) # y
|
|
# p.putFloat(player.z) # z
|
|
# p.putULong(0x00) # unknown
|
|
# p.putULong(0x00) # unknown
|
|
# p.putULong(0x00) # unknown
|
|
# p.putULong(0x00) # unknown
|
|
# p.putULong(player.o + 30) # orientation
|
|
# p.putULong(0x00) # unknown
|
|
|
|
p = Packet()
|
|
p.putByte(0x0a) # opcode
|
|
p.putByte(0x32) # length
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(plid) # player index
|
|
p.putShort(player.oid) # object id
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x01) # 1 -> stand still, 4 -> death, 3 -> little move
|
|
p.putULong(model) # model
|
|
p.putFloat(0x00) # x
|
|
p.putFloat(player.y) # y
|
|
p.putFloat(player.z) # z
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong(0x00) # unknown
|
|
p.putULong((player.o + 30) % 360) # orientation
|
|
p.putULong(0x00) # unknown
|
|
|
|
p.putByte(0x0a) # opcode
|
|
p.putByte(0x12) # length
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(plid) # player index
|
|
p.putShort(player.oid) # object id
|
|
p.putByte(0x00) # unknown
|
|
p.putByte(0x00) # 1 -> stand still, 4 -> death, 3 -> little move
|
|
p.putULong(model) # model
|
|
p.putULong(0x00)
|
|
p.putByte(0x00)
|
|
p.putByte(0x00)
|
|
|
|
await self.broadcast_gamedata(p.getvalue(), acknow=False)
|
|
#await self.broadcast_gamedata(bytes.fromhex("0a32000000" + plix + struct.pack("<B", objid).hex() + "000001" + model + "000000ff00000000000000000000000000000000000000000000000000000000000000000000000a12000000" + plix + struct.pack("<B", objid).hex() + "0000" + model + "020000000000000000"), acknow=False)
|
|
|
|
def get_player_index(self, player):
|
|
for iplayer in range(len(self.players)):
|
|
if self.players[iplayer] == player:
|
|
return iplayer
|
|
return False
|
|
|
|
def get_player_by_index(self, playerindex):
|
|
return self.players[playerindex]
|
|
|
|
if __name__ == '__main__':
|
|
server = Server(name="giantsd", maxplayers=20, register=False, teams=Teams.MvM, map=Map("Three Way Island - Canyons.gck")) #, map=Map("Three Way Island - Canyons.gck"))
|
|
server.load_plugins()
|
|
|
|
loop = asyncio.get_event_loop()
|
|
listen = loop.create_datagram_endpoint(lambda: Netserver(server), local_addr=(server.listen_ip, server.listen_port))
|
|
transport, protocol = loop.run_until_complete(listen)
|
|
loop.create_task(server.ask_command())
|
|
try:
|
|
loop.run_forever()
|
|
except KeyboardInterrupt:
|
|
pass
|
|
transport.close()
|
|
loop.close()
|