mirror of
https://github.com/kuitoi/kuitoi-Server.git
synced 2025-08-18 00:35:36 +00:00
Compare commits
No commits in common. "719e705bab6faff4b373aecb2925a6e1f665a578" and "7466f987ac55ecec87c36ce7da02c1589eebce28" have entirely different histories.
719e705bab
...
7466f987ac
@ -8,5 +8,4 @@ pydantic~=2.0.2
|
|||||||
click~=8.1.4
|
click~=8.1.4
|
||||||
lupa~=2.0
|
lupa~=2.0
|
||||||
toml~=0.10.2
|
toml~=0.10.2
|
||||||
colorama~=0.4.6
|
colorama~=0.4.6
|
||||||
cryptography~=41.0.2
|
|
@ -561,7 +561,7 @@ class Client:
|
|||||||
await ev.call_async_event("onPlayerJoin", player=self)
|
await ev.call_async_event("onPlayerJoin", player=self)
|
||||||
|
|
||||||
await self._send(f"Sn{self.nick}", to_all=True) # I don't know for what it
|
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
|
await self._send(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:
|
if not client:
|
||||||
|
@ -270,9 +270,6 @@ class Core:
|
|||||||
tasks = []
|
tasks = []
|
||||||
# self.udp.start,
|
# self.udp.start,
|
||||||
f_tasks = [self.tcp.start, self.udp._start, console.start, self.stop_me, self.heartbeat, self.check_alive]
|
f_tasks = [self.tcp.start, self.udp._start, console.start, self.stop_me, self.heartbeat, self.check_alive]
|
||||||
if config.RCON['enabled']:
|
|
||||||
rcon = console.rcon(config.RCON['password'], config.RCON['server_ip'], config.RCON['server_port'])
|
|
||||||
f_tasks.append(rcon.start)
|
|
||||||
for task in f_tasks:
|
for task in f_tasks:
|
||||||
tasks.append(asyncio.create_task(task()))
|
tasks.append(asyncio.create_task(task()))
|
||||||
t = asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
|
t = asyncio.wait(tasks, return_when=asyncio.FIRST_EXCEPTION)
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
from typing import Dict
|
import secrets
|
||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
Auth: Dict[str, object]
|
def __init__(self, auth=None, game=None, server=None, options=None, web=None):
|
||||||
Game: Dict[str, object]
|
self.Auth = auth or {"key": None, "private": True}
|
||||||
Server: Dict[str, object]
|
self.Game = game or {"map": "gridmap_v2", "players": 8, "max_cars": 1}
|
||||||
RCON: Dict[str, object]
|
self.Server = server or {"name": "KuiToi-Server", "description": "Welcome to KuiToi Server!",
|
||||||
Options: Dict[str, object]
|
"server_ip": "0.0.0.0", "server_port": 30814}
|
||||||
WebAPI: Dict[str, object]
|
self.Options = options or {"language": "en", "encoding": "utf8", "speed_limit": 0, "use_queue": False,
|
||||||
enc: str | None
|
"debug": False}
|
||||||
|
self.WebAPI = web or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 8433,
|
||||||
|
"secret_key": secrets.token_hex(16)}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server)
|
return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server)
|
||||||
class config (Config): ...
|
class config (Config): ...
|
||||||
|
@ -12,17 +12,15 @@ import yaml
|
|||||||
|
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
def __init__(self, auth=None, game=None, server=None, rcon=None, options=None, web=None):
|
def __init__(self, auth=None, game=None, server=None, options=None, web=None):
|
||||||
self.Auth = auth or {"key": None, "private": True}
|
self.Auth = auth or {"key": None, "private": True}
|
||||||
self.Game = game or {"map": "gridmap_v2", "players": 8, "max_cars": 1}
|
self.Game = game or {"map": "gridmap_v2", "players": 8, "max_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!",
|
||||||
"server_ip": "0.0.0.0", "server_port": 30814}
|
"server_ip": "0.0.0.0", "server_port": 30814}
|
||||||
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,
|
self.Options = options or {"language": "en", "encoding": "utf-8", "speed_limit": 0, "use_queue": False,
|
||||||
"debug": False, "use_lua": False, "log_chat": True}
|
"debug": False, "use_lua": False, "log_chat": True}
|
||||||
self.WebAPI = web or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 8433,
|
self.WebAPI = web or {"enabled": False, "server_ip": "127.0.0.1", "server_port": 8433,
|
||||||
"access_token": secrets.token_hex(16)}
|
"secret_key": secrets.token_hex(16)}
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server)
|
return "%s(Auth=%r, Game=%r, Server=%r)" % (self.__class__.__name__, self.Auth, self.Game, self.Server)
|
||||||
|
@ -1,92 +0,0 @@
|
|||||||
import hashlib
|
|
||||||
import os
|
|
||||||
from base64 import b64decode, b64encode
|
|
||||||
|
|
||||||
from cryptography.hazmat.primitives import padding
|
|
||||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
||||||
|
|
||||||
from core import get_logger
|
|
||||||
|
|
||||||
"""
|
|
||||||
shared key: SHA256 of "password"
|
|
||||||
<header>: "\x00\x00\x00\x00" (Byte order: Little Endian) - like you use
|
|
||||||
<iv>: A set of random bytes packed in base64 (New for each message)
|
|
||||||
-> To server
|
|
||||||
<- From server
|
|
||||||
|
|
||||||
Open TCP connection /
|
|
||||||
| -> "<iv>:hello" Without header, immediately with AES encryption (shared key)
|
|
||||||
| *Decrypt and some processes*
|
|
||||||
| Fail /
|
|
||||||
| | <- ":E:Bad key" | ":E:Error Message" Without header, without AES encryption
|
|
||||||
| | tcp.close() # End
|
|
||||||
| Success /
|
|
||||||
| | <- "<iv>:hello" with header, with AES encryption
|
|
||||||
| | (Next, everywhere with header, with AES encryption)
|
|
||||||
| -> "<iv>:<header>Cs:ver"
|
|
||||||
| <- "<iv>:<header>Os:KuiToi 0.4.3 | "<iv>:<header>Os:BeamMP 3.2.0"
|
|
||||||
| # Prints server and they version
|
|
||||||
| -> "<iv>:<header>Cs:commands"
|
|
||||||
| <- "<iv>:<header>Os:stop,help,plugins" | "<iv>:<header>Os:SKIP" For an autocomplete; "SKIP" For no autocomplete;
|
|
||||||
| *Ready to handle commands*
|
|
||||||
| -> "<iv>:<header>C:help"
|
|
||||||
| <- "<iv>:<header>O:stop: very cool stop\nhelp: Yayayayoy"
|
|
||||||
| -> "<iv>:<header>C:...."
|
|
||||||
| <- "<iv>:<header>O:...."
|
|
||||||
| -> "<iv>:<header>C:exit"
|
|
||||||
| tcp.close()
|
|
||||||
|
|
||||||
Codes:
|
|
||||||
* "hello" - Hello message
|
|
||||||
* "E:error_message" - Send RCON error
|
|
||||||
* "C:command" - Receive command
|
|
||||||
* "Cs:" - Receive system command
|
|
||||||
* "O:output" - Send command output
|
|
||||||
* "Os:" - Send system output
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class RCONSystem:
|
|
||||||
console = None
|
|
||||||
|
|
||||||
def __init__(self, key, host, port):
|
|
||||||
self.log = get_logger("RCON")
|
|
||||||
self.key = key
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
|
|
||||||
def encrypt(self, message, key):
|
|
||||||
self.log.debug(f"Encrypt message: {message}")
|
|
||||||
key = hashlib.sha256(key).digest()
|
|
||||||
iv = os.urandom(16)
|
|
||||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
|
|
||||||
encryptor = cipher.encryptor()
|
|
||||||
padder = padding.PKCS7(algorithms.AES.block_size).padder()
|
|
||||||
padded_data = padder.update(message.encode('utf-8')) + padder.finalize()
|
|
||||||
encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
|
|
||||||
encoded_data = b64encode(encrypted_data)
|
|
||||||
encoded_iv = b64encode(iv)
|
|
||||||
return encoded_iv + b":" + encoded_data
|
|
||||||
|
|
||||||
def decrypt(self, ciphertext, key):
|
|
||||||
self.log.debug(f"Dencrypt message: {ciphertext}")
|
|
||||||
key = hashlib.sha256(key).digest()
|
|
||||||
encoded_iv, encoded_data = ciphertext.split(":")
|
|
||||||
iv = b64decode(encoded_iv)
|
|
||||||
encrypted_data = b64decode(encoded_data)
|
|
||||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
|
|
||||||
decryptor = cipher.decryptor()
|
|
||||||
unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
|
|
||||||
decrypted_data = decryptor.update(encrypted_data) + decryptor.finalize()
|
|
||||||
unpadded_data = unpadder.update(decrypted_data) + unpadder.finalize()
|
|
||||||
return unpadded_data.decode('utf-8')
|
|
||||||
|
|
||||||
async def handle_client(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def start(self):
|
|
||||||
self.log.info("TODO: RCON")
|
|
||||||
|
|
||||||
async def stop(self):
|
|
||||||
pass
|
|
@ -1,34 +1,36 @@
|
|||||||
from logging import Logger
|
class Console(object):
|
||||||
from typing import AnyStr
|
|
||||||
|
|
||||||
from core import get_logger
|
def __init__(self,
|
||||||
|
prompt_in: str = ">",
|
||||||
|
prompt_out: str = "]:",
|
||||||
|
not_found: str = "Command \"%s\" not found in alias.") -> None: ...
|
||||||
|
|
||||||
|
def __getitem__(self, item): ...
|
||||||
|
@property
|
||||||
|
def alias(self) -> dict: ...
|
||||||
|
def add(self, key: str, func: function) -> dict: ...
|
||||||
|
def log(self, s: str, r='\r') -> None: ...
|
||||||
|
def write(self, s: str, r='\r') -> None: ...
|
||||||
|
def __lshift__(self, s: AnyStr) -> None: ...
|
||||||
|
def logger_hook(self) -> None: ...
|
||||||
|
def builtins_hook(self) -> None: ...
|
||||||
|
async def start(self) -> None: ...
|
||||||
|
|
||||||
class RCONSystem:
|
class console(object):
|
||||||
console = None
|
|
||||||
|
|
||||||
def __init__(self, key, host, port):
|
|
||||||
self.log = get_logger("RCON")
|
|
||||||
self.key = key
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
|
|
||||||
async def start(self): ...
|
|
||||||
async def stop(self): ...
|
|
||||||
|
|
||||||
class console:
|
|
||||||
rcon: RCONSystem = RCONSystem
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def alias() -> dict: ...
|
def alias() -> dict: ...
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def add_command(key: str, func, man: str = None, desc: str = None, custom_completer: dict = None) -> dict: ...
|
def add_command(key: str, func: function) -> dict: ...
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def start() -> None: ...
|
async def start() -> None: ...
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def builtins_hook() -> None: ...
|
def builtins_hook() -> None: ...
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def logger_hook() -> None: ...
|
def logger_hook() -> None: ...
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def log(s: str) -> None: ...
|
def log(s: str) -> None: ...
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -18,7 +18,6 @@ from prompt_toolkit.output.win32 import NoConsoleScreenBufferError
|
|||||||
from prompt_toolkit.patch_stdout import patch_stdout
|
from prompt_toolkit.patch_stdout import patch_stdout
|
||||||
|
|
||||||
from core import get_logger
|
from core import get_logger
|
||||||
from modules.ConsoleSystem import RCON
|
|
||||||
|
|
||||||
|
|
||||||
class Console:
|
class Console:
|
||||||
@ -46,9 +45,6 @@ class Console:
|
|||||||
self.add_command("help", self.__create_help_message, i18n.man_message_help, i18n.help_message_help,
|
self.add_command("help", self.__create_help_message, i18n.man_message_help, i18n.help_message_help,
|
||||||
custom_completer={"help": {"--raw": None}})
|
custom_completer={"help": {"--raw": None}})
|
||||||
self.completer = NestedCompleter.from_nested_dict(self.__alias)
|
self.completer = NestedCompleter.from_nested_dict(self.__alias)
|
||||||
rcon = RCON
|
|
||||||
rcon.console = self
|
|
||||||
self.rcon = rcon
|
|
||||||
|
|
||||||
def __debug(self, *x):
|
def __debug(self, *x):
|
||||||
self.__logger.debug(f"{x}")
|
self.__logger.debug(f"{x}")
|
||||||
|
@ -580,10 +580,13 @@ class LuaPluginsLoader:
|
|||||||
|
|
||||||
def load(self):
|
def load(self):
|
||||||
self.log.debug("Loading Lua plugins...")
|
self.log.debug("Loading Lua plugins...")
|
||||||
self.log.info(i18n.plugins_lua_enabled)
|
# TODO: i18n
|
||||||
self.log.warning(i18n.plugins_lua_nuances_warning)
|
self.log.info("You have enabled support for Lua plugins.")
|
||||||
self.log.warning(i18n.plugins_lua_legacy_config_create_warning)
|
self.log.warning("There are some nuances to working with KuiToi. "
|
||||||
self.log.info(i18n.plugins_lua_legacy_config_create)
|
"If you have a proposal for their solution, and it is related to KuiToi, "
|
||||||
|
"please contact the developer.")
|
||||||
|
self.log.warning("Some BeamMP plugins require a correctly configured ServerConfig.toml file to function.")
|
||||||
|
self.log.info("Creating it.")
|
||||||
data = {
|
data = {
|
||||||
"info": "ServerConfig.toml is created solely for backward compatibility support. "
|
"info": "ServerConfig.toml is created solely for backward compatibility support. "
|
||||||
"This file will be updated every time the program is launched.",
|
"This file will be updated every time the program is launched.",
|
||||||
@ -671,6 +674,6 @@ class LuaPluginsLoader:
|
|||||||
self.log.debug("Unloading lua plugins")
|
self.log.debug("Unloading lua plugins")
|
||||||
for name, data in self.lua_plugins.items():
|
for name, data in self.lua_plugins.items():
|
||||||
if data['ok']:
|
if data['ok']:
|
||||||
self.log.info(i18n.plugins_lua_unload.format(name))
|
self.log.info(f"Unloading lua plugin: {name}")
|
||||||
for _, timer in data['lua'].globals().MP._event_timers.items():
|
for _, timer in data['lua'].globals().MP._event_timers.items():
|
||||||
timer.stop()
|
timer.stop()
|
||||||
|
@ -131,21 +131,21 @@ class PluginsLoader:
|
|||||||
try:
|
try:
|
||||||
is_func = inspect.isfunction
|
is_func = inspect.isfunction
|
||||||
if not is_func(plugin.load):
|
if not is_func(plugin.load):
|
||||||
self.log.error(i18n.plugins_not_found_load)
|
self.log.error('Function "def load():" not found.')
|
||||||
ok = False
|
ok = False
|
||||||
if not is_func(plugin.start):
|
if not is_func(plugin.start):
|
||||||
self.log.error(i18n.plugins_not_found_start)
|
self.log.error('Function "def start():" not found.')
|
||||||
ok = False
|
ok = False
|
||||||
if not is_func(plugin.unload):
|
if not is_func(plugin.unload):
|
||||||
self.log.error(i18n.plugins_not_found_unload)
|
self.log.error('Function "def unload():" not found.')
|
||||||
ok = False
|
ok = False
|
||||||
if type(plugin.kt) != KuiToi:
|
if type(plugin.kt) != KuiToi:
|
||||||
self.log.error(i18n.plugins_kt_invalid)
|
self.log.error(f'Attribute "kt" isn\'t KuiToi class. Plugin file: "{file_path}"')
|
||||||
ok = False
|
ok = False
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
ok = False
|
ok = False
|
||||||
if not ok:
|
if not ok:
|
||||||
self.log.error(i18n.plugins_invalid.format(file_path))
|
self.log.error(f'Plugin file: "{file_path}" is not a valid KuiToi plugin.')
|
||||||
return
|
return
|
||||||
|
|
||||||
pl_name = plugin.kt.name
|
pl_name = plugin.kt.name
|
||||||
@ -185,8 +185,9 @@ class PluginsLoader:
|
|||||||
self.loaded_str += f"{pl_name}:ok, "
|
self.loaded_str += f"{pl_name}:ok, "
|
||||||
self.log.debug(f"Plugin loaded: {file}. Settings: {self.plugins[pl_name]}")
|
self.log.debug(f"Plugin loaded: {file}. Settings: {self.plugins[pl_name]}")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
# TODO: i18n
|
||||||
self.loaded_str += f"{file}:no, "
|
self.loaded_str += f"{file}:no, "
|
||||||
self.log.error(i18n.plugins_error_loading.format(file, f"{e}"))
|
self.log.error(f"Error while loading plugin: {file}; Error: {e}")
|
||||||
self.log.exception(e)
|
self.log.exception(e)
|
||||||
|
|
||||||
async def start(self, _):
|
async def start(self, _):
|
||||||
|
@ -57,25 +57,6 @@
|
|||||||
"client_event_invalid_data": "从事件返回的数据无效:{}",
|
"client_event_invalid_data": "从事件返回的数据无效:{}",
|
||||||
"client_player_disconnected": "离开服务器。游戏时间:{}分钟。",
|
"client_player_disconnected": "离开服务器。游戏时间:{}分钟。",
|
||||||
|
|
||||||
"": "Events system",
|
|
||||||
|
|
||||||
"": "插件加载器",
|
|
||||||
|
|
||||||
"plugins_not_found_load": "未找到\"def load():\"函数。",
|
|
||||||
"plugins_not_found_start": "未找到\"def start():\"函数。",
|
|
||||||
"plugins_not_found_unload": "未找到\"def unload():\"函数。",
|
|
||||||
"plugins_kt_invalid": "“kt”变量不属于KuiToi类。",
|
|
||||||
"plugins_invalid": "无法在KuiToi中运行插件\"{}\"。",
|
|
||||||
"plugins_error_loading": "加载插件{}时出错:{}",
|
|
||||||
|
|
||||||
"": "Lua插件加载器",
|
|
||||||
|
|
||||||
"plugins_lua_enabled": "您已启用Lua插件支持。",
|
|
||||||
"plugins_lua_nuances_warning": "在使用KuiToi时有一些细微差别。如果您有关于解决方案的建议,并且它与KuiToi相关,请联系开发人员。",
|
|
||||||
"plugins_lua_legacy_config_create_warning": "一些BeamMP插件需要一个正确配置的ServerConfig.toml文件才能正常运行。",
|
|
||||||
"plugins_lua_legacy_config_create": "正在创建。",
|
|
||||||
"plugins_lua_unload": "停止Lua插件:{}",
|
|
||||||
|
|
||||||
"": "命令:man",
|
"": "命令:man",
|
||||||
"man_message_man": "man - 显示COMMAND的帮助页面。\n用法:man COMMAND",
|
"man_message_man": "man - 显示COMMAND的帮助页面。\n用法:man COMMAND",
|
||||||
"help_message_man": "显示COMMAND的帮助页面。",
|
"help_message_man": "显示COMMAND的帮助页面。",
|
||||||
|
@ -57,25 +57,6 @@
|
|||||||
"client_event_invalid_data": "Invalid data returned from event: {}",
|
"client_event_invalid_data": "Invalid data returned from event: {}",
|
||||||
"client_player_disconnected": "Left the server. Playtime: {} min",
|
"client_player_disconnected": "Left the server. Playtime: {} min",
|
||||||
|
|
||||||
"": "Events system",
|
|
||||||
|
|
||||||
"": "Plugins loader",
|
|
||||||
|
|
||||||
"plugins_not_found_load": "Function \"def load():\" not found.",
|
|
||||||
"plugins_not_found_start": "Function \"def start():\" not found.",
|
|
||||||
"plugins_not_found_unload": "Function \"def unload():\" not found.",
|
|
||||||
"plugins_kt_invalid": "\"kt\" variable does not belong to the KuiToi class.",
|
|
||||||
"plugins_invalid": "Plugin \"{}\" cannot be run in KuiToi.",
|
|
||||||
"plugins_error_loading": "An error occurred while loading the plugin {}: {}",
|
|
||||||
|
|
||||||
"": "Lua plugins loader",
|
|
||||||
|
|
||||||
"plugins_lua_enabled": "You have enabled Lua plugin support.",
|
|
||||||
"plugins_lua_nuances_warning": "There are some nuances when working with Kuiti. If you have a suggestion for their solution, and it is related to KuiToi, please contact the developer.",
|
|
||||||
"plugins_lua_legacy_config_create_warning": "Some BeamMP plugins require a properly configured ServerConfig.toml file to function.",
|
|
||||||
"plugins_lua_legacy_config_create": "Creating it.",
|
|
||||||
"plugins_lua_unload": "Stopping Lua plugin: {}",
|
|
||||||
|
|
||||||
"": "Command: man",
|
"": "Command: man",
|
||||||
"man_message_man": "man - Shows the help page for COMMAND.\nUsage: man COMMAND",
|
"man_message_man": "man - Shows the help page for COMMAND.\nUsage: man COMMAND",
|
||||||
"help_message_man": "Shows the help page for COMMAND.",
|
"help_message_man": "Shows the help page for COMMAND.",
|
||||||
|
@ -57,25 +57,6 @@
|
|||||||
"client_event_invalid_data": "Из ивента вернулись не верные данные: {}",
|
"client_event_invalid_data": "Из ивента вернулись не верные данные: {}",
|
||||||
"client_player_disconnected": "Вышел с сервера. Время игры: {} мин",
|
"client_player_disconnected": "Вышел с сервера. Время игры: {} мин",
|
||||||
|
|
||||||
"": "Events system",
|
|
||||||
|
|
||||||
"": "Plugins loader",
|
|
||||||
|
|
||||||
"plugins_not_found_load": "Функция \"def load():\" не найдена.",
|
|
||||||
"plugins_not_found_start": "Функция \"def start():\" не найдена.",
|
|
||||||
"plugins_not_found_unload": "Функция \"def unload():\" не найдена.",
|
|
||||||
"plugins_kt_invalid": "Переменная \"kt\" не принадлежит классу KuiToi.",
|
|
||||||
"plugins_invalid": "Плагин: \"{}\" - не может быть запущен в KuiToi.",
|
|
||||||
"plugins_error_loading": "Произошла ошибка при загрузке плагина {}: {}",
|
|
||||||
|
|
||||||
"": "Lua plugins loader",
|
|
||||||
|
|
||||||
"plugins_lua_enabled": "Вы включили поддержку плагинов Lua.",
|
|
||||||
"plugins_lua_nuances_warning": "В работе с Kuiti есть некоторые нюансы. Если у вас есть предложение по их решению, и оно связано с KuiToi, пожалуйста, свяжитесь с разработчиком.",
|
|
||||||
"plugins_lua_legacy_config_create_warning": "Для работы некоторых плагинов BeamMP требуется правильно настроенный файл ServerConfig.toml.",
|
|
||||||
"plugins_lua_legacy_config_create": "Создаю его.",
|
|
||||||
"plugins_lua_unload": "Останавливаю Lua плагин: {}",
|
|
||||||
|
|
||||||
"": "Command: man",
|
"": "Command: man",
|
||||||
"man_message_man": "man - Показывает страничку помощи для COMMAND.\nИспользование: man COMMAND",
|
"man_message_man": "man - Показывает страничку помощи для COMMAND.\nИспользование: man COMMAND",
|
||||||
"help_message_man": "Показывает страничку помощи для COMMAND.",
|
"help_message_man": "Показывает страничку помощи для COMMAND.",
|
||||||
|
@ -60,27 +60,6 @@ class i18n:
|
|||||||
client_event_invalid_data: str
|
client_event_invalid_data: str
|
||||||
client_player_disconnected: str
|
client_player_disconnected: str
|
||||||
|
|
||||||
# Events system
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Plugins loader
|
|
||||||
|
|
||||||
plugins_not_found_load: str
|
|
||||||
plugins_not_found_start: str
|
|
||||||
plugins_not_found_unload: str
|
|
||||||
plugins_kt_invalid: str
|
|
||||||
plugins_invalid: str
|
|
||||||
plugins_error_loading: str
|
|
||||||
|
|
||||||
# Lua plugins loader
|
|
||||||
|
|
||||||
plugins_lua_enabled: str
|
|
||||||
plugins_lua_nuances_warning: str
|
|
||||||
plugins_lua_legacy_config_create_warning: str
|
|
||||||
plugins_lua_legacy_config_create: str
|
|
||||||
plugins_lua_unload: str
|
|
||||||
|
|
||||||
# Command: man
|
# Command: man
|
||||||
man_message_man: str
|
man_message_man: str
|
||||||
help_message_man: str
|
help_message_man: str
|
||||||
|
Loading…
x
Reference in New Issue
Block a user