mirror of
https://github.com/kuitoi/kuitoi-Server.git
synced 2026-02-16 02:20:52 +00:00
[~] 0.4.5 > 0.4.6
[+] Recreate config (if empty) [+] Hidden config [!] FIX rl [!] Update getting loop [-] core_player_set_id [~] Update copyrights [~] Minor
This commit is contained in:
@@ -19,7 +19,7 @@ class Client:
|
||||
def __init__(self, reader, writer, core):
|
||||
self.__reader = reader
|
||||
self.__writer = writer
|
||||
self.__Core = core
|
||||
self._core = core
|
||||
self.__alive = True
|
||||
self.__packets_queue = []
|
||||
self.__tasks = []
|
||||
@@ -38,7 +38,7 @@ class Client:
|
||||
self._identifiers = []
|
||||
self._cars = [None] * 21 # Max 20 cars per player + 1 snowman
|
||||
self._focus_car = -1
|
||||
self._snowman = {"id": -1, "packet": ""}
|
||||
self._unicycle = {"id": -1, "packet": ""}
|
||||
self._connect_time = 0
|
||||
self._last_position = {}
|
||||
self._lock = Lock()
|
||||
@@ -155,7 +155,7 @@ class Client:
|
||||
|
||||
if to_all:
|
||||
code = chr(data[0])
|
||||
for client in self.__Core.clients:
|
||||
for client in self._core.clients:
|
||||
if not client or (client is self and not to_self):
|
||||
continue
|
||||
if not to_udp or code in ['V', 'W', 'Y', 'E']:
|
||||
@@ -174,8 +174,7 @@ class Client:
|
||||
data = b"ABG:" + zlib.compress(data, level=zlib.Z_BEST_COMPRESSION)
|
||||
|
||||
if to_udp:
|
||||
udp_sock = self._udp_sock[0]
|
||||
udp_addr = self._udp_sock[1]
|
||||
udp_sock, udp_addr = self._udp_sock
|
||||
# self.log.debug(f'[UDP] len: {len(data)}; send: {data!r}')
|
||||
if udp_sock and udp_addr:
|
||||
try:
|
||||
@@ -297,7 +296,7 @@ class Client:
|
||||
file = data[1:].decode(config.enc)
|
||||
self.log.info(i18n.client_mod_request.format(repr(file)))
|
||||
size = -1
|
||||
for mod in self.__Core.mods_list:
|
||||
for mod in self._core.mods_list:
|
||||
if type(mod) == int:
|
||||
continue
|
||||
if mod.get('path') == file:
|
||||
@@ -318,9 +317,9 @@ class Client:
|
||||
await self.kick("Missing download socket")
|
||||
return
|
||||
if config.Options['use_queue']:
|
||||
while self.__Core.lock_upload:
|
||||
while self._core.lock_upload:
|
||||
await asyncio.sleep(.2)
|
||||
self.__Core.lock_upload = True
|
||||
self._core.lock_upload = True
|
||||
speed = config.Options["speed_limit"]
|
||||
if speed:
|
||||
speed = speed / 2
|
||||
@@ -332,8 +331,8 @@ class Client:
|
||||
]
|
||||
sl0, sl1 = await asyncio.gather(*uploads)
|
||||
tr = (time.monotonic() - t) or 0.0001
|
||||
if self.__Core.lock_upload:
|
||||
self.__Core.lock_upload = False
|
||||
if self._core.lock_upload:
|
||||
self._core.lock_upload = False
|
||||
msg = i18n.client_mod_sent.format(round(size / MB, 3), math.ceil(size / tr / MB), int(tr))
|
||||
if speed:
|
||||
msg += i18n.client_mod_sent_limit.format(int(speed * 2))
|
||||
@@ -349,7 +348,7 @@ class Client:
|
||||
elif data.startswith(b"SR"):
|
||||
path_list = ''
|
||||
size_list = ''
|
||||
for mod in self.__Core.mods_list:
|
||||
for mod in self._core.mods_list:
|
||||
if type(mod) == int:
|
||||
continue
|
||||
path_list += f"{mod['path']};"
|
||||
@@ -391,7 +390,7 @@ class Client:
|
||||
car_data = data[2:]
|
||||
car_id = next((i for i, car in enumerate(self._cars) if car is None), len(self._cars))
|
||||
cars_count = len(self._cars) - self._cars.count(None)
|
||||
if self._snowman['id'] != -1:
|
||||
if self._unicycle['id'] != -1:
|
||||
cars_count -= 1 # -1 for unicycle
|
||||
self.log.debug(f"car_id={car_id}, cars_count={cars_count}")
|
||||
car_json = {}
|
||||
@@ -416,12 +415,12 @@ class Client:
|
||||
snowman = car_json.get("jbm") == "unicycle"
|
||||
if allow and config.Game['cars'] > cars_count or (snowman and allow_snowman) or over_spawn:
|
||||
if snowman:
|
||||
unicycle_id = self._snowman['id']
|
||||
unicycle_id = self._unicycle['id']
|
||||
if unicycle_id != -1:
|
||||
self.log.debug(f"Delete old unicycle: unicycle_id={unicycle_id}")
|
||||
self.log.debug(f"Delete old unicycle: car_id={unicycle_id}")
|
||||
self._cars[unicycle_id] = None
|
||||
await self._send(f"Od:{self.cid}-{unicycle_id}", to_all=True, to_self=True)
|
||||
self._snowman = {"id": car_id, "packet": pkt}
|
||||
self._unicycle = {"id": car_id, "packet": pkt}
|
||||
self.log.debug(f"Unicycle spawn accepted: car_id={car_id}")
|
||||
else:
|
||||
self.log.debug(f"Car spawn accepted: car_id={car_id}")
|
||||
@@ -469,8 +468,8 @@ class Client:
|
||||
car = self._cars[car_id]
|
||||
if car['snowman']:
|
||||
self.log.debug(f"Snowman found")
|
||||
unicycle_id = self._snowman['id']
|
||||
self._snowman['id'] = -1
|
||||
unicycle_id = self._unicycle['id']
|
||||
self._unicycle['id'] = -1
|
||||
self._cars[unicycle_id] = None
|
||||
self._cars[car_id] = None
|
||||
await self._send(f"Od:{self.cid}-{car_id}", to_all=True, to_self=True)
|
||||
@@ -482,7 +481,7 @@ class Client:
|
||||
async def _edit_car(self, raw_data, data):
|
||||
cid, car_id = self._get_cid_vid(raw_data)
|
||||
if car_id != -1 and self._cars[car_id]:
|
||||
client = self.__Core.get_client(cid=cid)
|
||||
client = self._core.get_client(cid=cid)
|
||||
if client:
|
||||
car = client._cars[car_id]
|
||||
new_car_json = {}
|
||||
@@ -506,8 +505,8 @@ class Client:
|
||||
|
||||
if cid == self.cid or allow or admin_allow:
|
||||
if car['snowman']:
|
||||
unicycle_id = self._snowman['id']
|
||||
self._snowman['id'] = -1
|
||||
unicycle_id = self._unicycle['id']
|
||||
self._unicycle['id'] = -1
|
||||
self.log.debug(f"Delete snowman")
|
||||
await self._send(f"Od:{self.cid}-{unicycle_id}", to_all=True, to_self=True)
|
||||
self._cars[unicycle_id] = None
|
||||
@@ -593,7 +592,7 @@ class Client:
|
||||
await self._send(f"Sn{self.nick}", to_all=True) # I don't know for what it
|
||||
await self._send(f"J{i18n.game_welcome_message.format(self.nick)}", to_all=True) # Hello message
|
||||
|
||||
for client in self.__Core.clients:
|
||||
for client in self._core.clients:
|
||||
if not client:
|
||||
continue
|
||||
for car in client._cars:
|
||||
@@ -656,20 +655,18 @@ class Client:
|
||||
self.__alive = False
|
||||
return
|
||||
|
||||
# Codes: V W X Y
|
||||
if 89 >= data[0] >= 86:
|
||||
await self._send(data, to_all=True, to_self=False)
|
||||
return
|
||||
|
||||
_bytes = False
|
||||
try:
|
||||
data = data.decode()
|
||||
except UnicodeDecodeError:
|
||||
_bytes = True
|
||||
self.log.error(f"UnicodeDecodeError: {data}")
|
||||
self.log.info("Some things are skipping...")
|
||||
|
||||
# Codes: p, Z in udp_server.py
|
||||
if data[0] in ['V', 'W', 'Y', 'E', 'N']:
|
||||
await self._send(data, to_all=True, to_self=False)
|
||||
return
|
||||
|
||||
# Codes: p, Z, X in udp_server.py
|
||||
match data[0]: # At data[0] code
|
||||
case "H": # Map load, client ready
|
||||
await self._connected_handler()
|
||||
@@ -700,8 +697,8 @@ class Client:
|
||||
ev.call_lua_event(event_name, self.cid, even_data)
|
||||
ev.call_event(event_name, data=even_data, player=self)
|
||||
await ev.call_async_event(event_name, data=even_data, player=self)
|
||||
case "N":
|
||||
await self._send(data, to_all=True, to_self=False)
|
||||
case _:
|
||||
self.log.warning(f"TCP [{self.cid}] Unknown code: {data[0]}; {data}")
|
||||
|
||||
async def _looper(self):
|
||||
ev.call_lua_event("onPlayerConnecting", self.cid)
|
||||
@@ -728,7 +725,7 @@ class Client:
|
||||
await asyncio.sleep(0.3)
|
||||
self.__alive = False
|
||||
if (self.cid > 0 or self.nick is not None) and \
|
||||
self.__Core.clients_by_nick.get(self.nick):
|
||||
self._core.clients_by_nick.get(self.nick):
|
||||
for i, car in enumerate(self._cars):
|
||||
if not car:
|
||||
continue
|
||||
@@ -746,9 +743,9 @@ class Client:
|
||||
round((time.monotonic() - self._connect_time) / 60, 2)
|
||||
)
|
||||
)
|
||||
self.__Core.clients[self.cid] = None
|
||||
del self.__Core.clients_by_id[self.cid]
|
||||
del self.__Core.clients_by_nick[self.nick]
|
||||
self._core.clients[self.cid] = None
|
||||
del self._core.clients_by_id[self.cid]
|
||||
del self._core.clients_by_nick[self.nick]
|
||||
else:
|
||||
self.log.debug(f"Removing client; Closing connection...")
|
||||
try:
|
||||
|
||||
@@ -25,7 +25,7 @@ class Client:
|
||||
self._log = utils.get_logger("client(id: )")
|
||||
self._addr: Tuple[str, int] = writer.get_extra_info("sockname")
|
||||
self._loop = asyncio.get_event_loop()
|
||||
self.__Core: Core = core
|
||||
self._core: Core = core
|
||||
self._cid: int = -1
|
||||
self._key: str = None
|
||||
self.nick: str = None
|
||||
@@ -37,7 +37,7 @@ class Client:
|
||||
self._focus_car = -1
|
||||
self._identifiers = []
|
||||
self._cars: List[Union[Dict[str, Union[str, bool, Dict[str, Union[str, List[int], float]]]], None]] = []
|
||||
self._snowman: Dict[str, Union[int, str]] = {"id": -1, "packet": ""}
|
||||
self._unicycle: Dict[str, Union[int, str]] = {"id": -1, "packet": ""}
|
||||
self._last_position = {}
|
||||
self._lock = Lock()
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
__title__ = 'KuiToi-Server'
|
||||
__description__ = 'BeamingDrive Multiplayer server compatible with BeamMP clients.'
|
||||
__url__ = 'https://github.com/kuitoi/kuitoi-Server'
|
||||
__version__ = '0.4.5'
|
||||
__build__ = 2303 # Я это считаю лог файлами
|
||||
__version__ = '0.4.6'
|
||||
__build__ = 2421 # Я это считаю лог файлами
|
||||
__author__ = 'SantaSpeen'
|
||||
__author_email__ = 'admin@kuitoi.su'
|
||||
__license__ = "FPA"
|
||||
__copyright__ = 'Copyright 2023 © SantaSpeen (Maxim Khomutov)'
|
||||
__copyright__ = 'Copyright 2024 © SantaSpeen (Maxim Khomutov)'
|
||||
|
||||
import asyncio
|
||||
import builtins
|
||||
@@ -43,7 +43,7 @@ config_path = "kuitoi.yml"
|
||||
if args.config:
|
||||
config_path = args.config
|
||||
config_provider = ConfigProvider(config_path)
|
||||
config = config_provider.open_config()
|
||||
config = config_provider.read()
|
||||
builtins.config = config
|
||||
config.enc = config.Options['encoding']
|
||||
if config.Options['debug'] is True:
|
||||
@@ -60,6 +60,7 @@ ml.builtins_hook()
|
||||
log.debug("Initializing EventsSystem...")
|
||||
ev = EventsSystem()
|
||||
ev.builtins_hook()
|
||||
ev.register("get_version", lambda _: {"version": __version__, "build": __build__})
|
||||
|
||||
log.info(i18n.hello)
|
||||
log.info(i18n.config_path.format(config_path))
|
||||
@@ -68,7 +69,7 @@ log.debug("Initializing BeamMP Server system...")
|
||||
# Key handler..
|
||||
if not config.Auth['private'] and not config.Auth['key']:
|
||||
log.warn(i18n.auth_need_key)
|
||||
url = "https://beammp.com/k/keys"
|
||||
url = "https://keymaster.beammp.com/login"
|
||||
if shortcuts.yes_no_dialog(
|
||||
title='BeamMP Server Key',
|
||||
text=i18n.GUI_need_key_message,
|
||||
@@ -90,7 +91,7 @@ if not config.Auth['private'] and not config.Auth['key']:
|
||||
text=i18n.GUI_enter_key_message,
|
||||
ok_text=i18n.GUI_ok,
|
||||
cancel_text=i18n.GUI_cancel).run()
|
||||
config_provider.save_config()
|
||||
config_provider.save()
|
||||
if not config.Auth['private'] and not config.Auth['key']:
|
||||
log.error(i18n.auth_empty_key)
|
||||
log.info(i18n.stop)
|
||||
|
||||
@@ -27,7 +27,8 @@ class Core:
|
||||
|
||||
def __init__(self):
|
||||
self.log = utils.get_logger("core")
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(self.loop)
|
||||
self.start_time = time.monotonic()
|
||||
self.run = False
|
||||
self.direct = False
|
||||
@@ -47,7 +48,7 @@ class Core:
|
||||
self.lock_upload = False
|
||||
|
||||
self.client_major_version = "2.0"
|
||||
self.BeamMP_version = "3.4.1" # 20.07.2023
|
||||
self.BeamMP_version = "3.4.1" # 16.07.2024
|
||||
|
||||
ev.register("_get_BeamMP_version", lambda x: tuple([int(i) for i in self.BeamMP_version.split(".")]))
|
||||
ev.register("_get_player", lambda x: self.get_client(**x['kwargs']))
|
||||
@@ -103,6 +104,7 @@ class Core:
|
||||
return out
|
||||
|
||||
async def check_alive(self):
|
||||
self.log.debug("Starting alive checker.")
|
||||
maxp = config.Game['players']
|
||||
try:
|
||||
while self.run:
|
||||
@@ -138,6 +140,8 @@ class Core:
|
||||
uvserver.run()
|
||||
|
||||
async def stop_me(self):
|
||||
if not config.WebAPI['enabled']:
|
||||
return
|
||||
while webapp.data_run[0]:
|
||||
await asyncio.sleep(1)
|
||||
self.run = False
|
||||
@@ -145,31 +149,44 @@ class Core:
|
||||
|
||||
# noinspection SpellCheckingInspection,PyPep8Naming
|
||||
async def heartbeat(self, test=False):
|
||||
if config.Auth["private"] or self.direct:
|
||||
if test:
|
||||
self.log.info(i18n.core_direct_mode)
|
||||
self.direct = True
|
||||
return
|
||||
try:
|
||||
self.log.debug("Starting heartbeat.")
|
||||
if config.Auth["private"] or self.direct:
|
||||
if test:
|
||||
self.log.info(i18n.core_direct_mode)
|
||||
self.direct = True
|
||||
return
|
||||
|
||||
BEAM_backend = ["backend.beammp.com", "backup1.beammp.com", "backup2.beammp.com"]
|
||||
modlist = ""
|
||||
for mod in self.mods_list:
|
||||
if type(mod) == int:
|
||||
continue
|
||||
modlist += f"/{os.path.basename(mod['path'])};"
|
||||
modstotalsize = self.mods_list[0]
|
||||
modstotal = len(self.mods_list) - 1
|
||||
while self.run:
|
||||
try:
|
||||
data = {"uuid": config.Auth["key"], "players": len(self.clients_by_id),
|
||||
"maxplayers": config.Game["players"], "port": config.Server["server_port"],
|
||||
"map": f"/levels/{config.Game['map']}/info.json", "private": config.Auth['private'],
|
||||
"version": self.BeamMP_version, "clientversion": self.client_major_version,
|
||||
"name": config.Server["name"], "modlist": modlist, "modstotalsize": modstotalsize,
|
||||
"modstotal": modstotal, "playerslist": "", "desc": config.Server['description'], "pass": False}
|
||||
BEAM_backend = ["backend.beammp.com", "backup1.beammp.com", "backup2.beammp.com"]
|
||||
_map = config.Game['map'] if "/" in config.Game['map'] else f"/levels/{config.Game['map']}/info.json"
|
||||
tags = config.Server['tags'].replace(", ", ";").replace(",", ";")
|
||||
if tags and tags[-1:] != ";":
|
||||
tags += ";"
|
||||
modlist = "".join(f"/{os.path.basename(mod['path'])};" for mod in self.mods_list[1:])
|
||||
modstotalsize = self.mods_list[0]
|
||||
modstotal = len(self.mods_list) - 1
|
||||
while self.run:
|
||||
playerslist = "".join(f"{client.nick};" for client in self.clients if client and client.alive)
|
||||
data = {
|
||||
"uuid": config.Auth["key"],
|
||||
"players": len(self.clients_by_id),
|
||||
"maxplayers": config.Game["players"],
|
||||
"port": config.Server["server_port"],
|
||||
"map": _map,
|
||||
"private": config.Auth['private'],
|
||||
"version": self.BeamMP_version,
|
||||
"clientversion": self.client_major_version,
|
||||
"name": config.Server["name"],
|
||||
"tags": tags,
|
||||
"guests": not config.Auth["private"],
|
||||
"modlist": modlist,
|
||||
"modstotalsize": modstotalsize,
|
||||
"modstotal": modstotal,
|
||||
"playerslist": playerslist,
|
||||
"desc": config.Server['description'],
|
||||
"pass": False
|
||||
}
|
||||
|
||||
# Sentry?
|
||||
ok = False
|
||||
body = {}
|
||||
for server_url in BEAM_backend:
|
||||
url = "https://" + server_url + "/heartbeat"
|
||||
@@ -177,14 +194,15 @@ class Core:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.post(url, data=data, headers={"api-v": "2"}) as response:
|
||||
code = response.status
|
||||
# text = await response.text()
|
||||
# self.log.debug(f"[HB] res={text}")
|
||||
body = await response.json()
|
||||
ok = True
|
||||
break
|
||||
except Exception as e:
|
||||
self.log.debug(f"Auth: Error `{e}` while auth with `{server_url}`")
|
||||
continue
|
||||
|
||||
if ok:
|
||||
if body:
|
||||
if not (body.get("status") is not None and
|
||||
body.get("code") is not None and
|
||||
body.get("msg") is not None):
|
||||
@@ -216,11 +234,11 @@ class Core:
|
||||
# raise KeyboardInterrupt
|
||||
|
||||
if test:
|
||||
return ok
|
||||
return bool(body)
|
||||
|
||||
await asyncio.sleep(5)
|
||||
except Exception as e:
|
||||
self.log.error(f"Error in heartbeat: {e}")
|
||||
except Exception as e:
|
||||
self.log.error(f"Error in heartbeat: {e}")
|
||||
|
||||
async def kick_cmd(self, args):
|
||||
if not len(args) > 0:
|
||||
|
||||
@@ -94,9 +94,8 @@ class TCPServer:
|
||||
await client.kick(i18n.core_player_kick_server_full)
|
||||
return False, client
|
||||
else:
|
||||
self.log.info(i18n.core_identifying_okay)
|
||||
await self.Core.insert_client(client)
|
||||
client.log.info(i18n.core_player_set_id.format(client.pid))
|
||||
client.log.info(i18n.core_identifying_okay)
|
||||
|
||||
return True, client
|
||||
|
||||
@@ -137,7 +136,8 @@ class TCPServer:
|
||||
try:
|
||||
ip = writer.get_extra_info('peername')[0]
|
||||
if self.rl.is_banned(ip):
|
||||
self.rl.notify(ip, writer)
|
||||
await self.rl.notify(ip, writer)
|
||||
writer.close()
|
||||
break
|
||||
data = await reader.read(1)
|
||||
if not data:
|
||||
|
||||
@@ -18,7 +18,7 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
super().__init__()
|
||||
self.log = utils.get_logger("UDPServer")
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.Core = core
|
||||
self._core = core
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.run = False
|
||||
@@ -33,8 +33,10 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
code = data[2:3].decode()
|
||||
data = data[2:].decode()
|
||||
|
||||
client = self.Core.get_client(cid=cid)
|
||||
client = self._core.get_client(cid=cid)
|
||||
if client:
|
||||
if not client.alive:
|
||||
self.log.debug(f"{client.nick}:{cid} still sending UDP data: {data}")
|
||||
match code:
|
||||
case "p": # Ping packet
|
||||
ev.call_event("onSentPing")
|
||||
@@ -45,24 +47,26 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
self.log.debug(f"Set UDP Sock for CID: {cid}")
|
||||
ev.call_event("onChangePosition", data=data)
|
||||
sub = data.find("{", 1)
|
||||
last_pos_data = data[sub:]
|
||||
last_pos = data[sub:]
|
||||
try:
|
||||
last_pos = json.loads(last_pos_data)
|
||||
client._last_position = last_pos
|
||||
_, car_id = client._get_cid_vid(data)
|
||||
client._cars[car_id]['pos'] = last_pos
|
||||
if client._cars[car_id]:
|
||||
last_pos = json.loads(last_pos)
|
||||
client._last_position = last_pos
|
||||
client._cars[car_id]['pos'] = last_pos
|
||||
except Exception as e:
|
||||
self.log.debug(f"Cannot parse position packet: {e}")
|
||||
self.log.debug(f"data: {data}, sup: {sub}")
|
||||
self.log.debug(f"last_pos_data: {last_pos_data}")
|
||||
self.log.warning(f"Cannot parse position packet: {e}")
|
||||
self.log.debug(f"data: '{data}', sup: {sub}")
|
||||
self.log.debug(f"last_pos ({type(last_pos)}): {last_pos}")
|
||||
await client._send(data, to_all=True, to_self=False, to_udp=True)
|
||||
case "X":
|
||||
await client._send(data, to_all=True, to_self=False, to_udp=True)
|
||||
case _:
|
||||
self.log.debug(f"[{cid}] Unknown code: {code}")
|
||||
self.log.warning(f" UDP [{cid}] Unknown code: {code}; {data}")
|
||||
else:
|
||||
self.log.debug(f"[{cid}] Client not found.")
|
||||
|
||||
except Exception as e:
|
||||
|
||||
self.log.error(f"Error handle_datagram: {e}")
|
||||
|
||||
def datagram_received(self, *args, **kwargs):
|
||||
@@ -81,14 +85,14 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
|
||||
async def _start(self):
|
||||
self.log.debug("Starting UDP server.")
|
||||
while self.Core.run:
|
||||
while self._core.run:
|
||||
try:
|
||||
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
d = UDPServer
|
||||
self.transport, p = await self.loop.create_datagram_endpoint(
|
||||
lambda: d(self.Core),
|
||||
lambda: d(self._core),
|
||||
local_addr=(self.host, self.port)
|
||||
)
|
||||
d.transport = self.transport
|
||||
|
||||
@@ -18,7 +18,7 @@ class UDPServer(asyncio.DatagramTransport):
|
||||
def __init__(self, core: Core, host=None, port=None, transport=None):
|
||||
self.log = utils.get_logger("UDPServer")
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.Core = core
|
||||
self._core = core
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.run = False
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import copy
|
||||
# Developed by KuiToi Dev
|
||||
# File modules.ConfigProvider
|
||||
# Written by: SantaSpeen
|
||||
@@ -16,12 +16,12 @@ class Config:
|
||||
def __init__(self, auth=None, game=None, server=None, rcon=None, options=None, web=None):
|
||||
self.Auth = auth or {"key": None, "private": True}
|
||||
self.Game = game or {"map": "gridmap_v2", "players": 8, "cars": 1}
|
||||
self.Server = server or {"name": "KuiToi-Server", "description": "Welcome to KuiToi Server!",
|
||||
self.Server = server or {"name": "KuiToi-Server", "description": "Welcome to KuiToi Server!", "tags": "Freroam",
|
||||
"server_ip": "0.0.0.0", "server_port": 30814}
|
||||
self.Options = options or {"language": "en", "speed_limit": 0, "use_queue": False,
|
||||
"use_lua": False, "log_chat": True}
|
||||
self.RCON = rcon or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 10383,
|
||||
"password": secrets.token_hex(16)}
|
||||
self.Options = options or {"language": "en", "encoding": "utf-8", "speed_limit": 0, "use_queue": False,
|
||||
"debug": False, "use_lua": False, "log_chat": True}
|
||||
"password": secrets.token_hex(6)}
|
||||
self.WebAPI = web or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 8433,
|
||||
"access_token": secrets.token_hex(16)}
|
||||
|
||||
@@ -36,7 +36,7 @@ class ConfigProvider:
|
||||
self.config_path = config_path
|
||||
self.config = Config()
|
||||
|
||||
def open_config(self):
|
||||
def read(self, _again=False):
|
||||
if not os.path.exists(self.config_path):
|
||||
with open(self.config_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(self.config, f)
|
||||
@@ -47,9 +47,26 @@ class ConfigProvider:
|
||||
print("You have errors in the YAML syntax.")
|
||||
print("Stopping server.")
|
||||
exit(1)
|
||||
if not self.config:
|
||||
if _again:
|
||||
print("Error: empty configuration.")
|
||||
exit(1)
|
||||
print("Empty config?..")
|
||||
os.remove(self.config_path)
|
||||
self.config = Config()
|
||||
return self.read(True)
|
||||
|
||||
if not self.config.Options.get("debug"):
|
||||
self.config.Options['debug'] = False
|
||||
if not self.config.Options.get("encoding"):
|
||||
self.config.Options['encoding'] = "utf-8"
|
||||
|
||||
return self.config
|
||||
|
||||
def save_config(self):
|
||||
def save(self):
|
||||
_config = copy.deepcopy(self.config)
|
||||
del _config.enc
|
||||
del _config.Options['debug']
|
||||
del _config.Options['encoding']
|
||||
with open(self.config_path, "w", encoding="utf-8") as f:
|
||||
yaml.dump(self.config, f)
|
||||
yaml.dump(_config, f)
|
||||
|
||||
@@ -40,6 +40,7 @@ class RateLimiter:
|
||||
if len(x) == 2:
|
||||
ip = x[1]
|
||||
if ip in _banned_ips:
|
||||
self._notified[ip] = False
|
||||
self._calls[ip].clear()
|
||||
self._banned_until[ip] = datetime.now()
|
||||
return f"{ip} removed from banlist."
|
||||
@@ -52,6 +53,7 @@ class RateLimiter:
|
||||
sec = x[2]
|
||||
if not sec.isdigit():
|
||||
return f"{sec!r} is not digit."
|
||||
self._notified[ip] = False
|
||||
self._calls[ip].clear()
|
||||
self._banned_until[ip] = datetime.now() + timedelta(seconds=int(sec))
|
||||
return f"{ip} banned until {self._banned_until[ip]}"
|
||||
@@ -69,7 +71,6 @@ class RateLimiter:
|
||||
try:
|
||||
writer.write(b'\x0b\x00\x00\x00Eip banned.')
|
||||
await writer.drain()
|
||||
writer.close()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@@ -45,7 +45,6 @@ class i18n:
|
||||
core_player_kick_stale: str
|
||||
core_player_kick_no_allowed_default_reason: str
|
||||
core_player_kick_server_full: str
|
||||
core_player_set_id: str
|
||||
core_identifying_okay: str
|
||||
|
||||
# In-game phrases
|
||||
@@ -110,5 +109,4 @@ class i18n:
|
||||
# Command: exit
|
||||
man_message_exit: str
|
||||
help_message_exit: str
|
||||
|
||||
```
|
||||
@@ -41,7 +41,6 @@
|
||||
"core_player_kick_stale": "过时的客户端。(由新连接替换)",
|
||||
"core_player_kick_no_allowed_default_reason": "您不受欢迎。拒绝访问。",
|
||||
"core_player_kick_server_full": "服务器已满。",
|
||||
"core_player_set_id": "玩家设置ID {}",
|
||||
"core_identifying_okay": "成功登录。",
|
||||
|
||||
"": "游戏内短语",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"core_player_kick_stale": "Stale client. (Replaced by new connection)",
|
||||
"core_player_kick_no_allowed_default_reason": "You are not welcome on this server. Access denied.",
|
||||
"core_player_kick_server_full": "Server is full.",
|
||||
"core_player_set_id": "Player set ID {}",
|
||||
"core_identifying_okay": "Successful login.",
|
||||
|
||||
"": "In-game phrases",
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
"core_player_kick_stale": "Устаревший клиент. (Заменено новым подключением)",
|
||||
"core_player_kick_no_allowed_default_reason": "Вам не рады на этом сервере. Вход запрещён.",
|
||||
"core_player_kick_server_full": "Сервер полон.",
|
||||
"core_player_set_id": "Игрок получил ID {}",
|
||||
"core_identifying_okay": "Успешный вход.",
|
||||
|
||||
"": "In-game phrases",
|
||||
|
||||
Reference in New Issue
Block a user