add compatibility server setting

This commit is contained in:
Fabian Dill 2020-07-16 16:57:38 +02:00
parent fe2c743480
commit 1d036c0d3c
3 changed files with 26 additions and 9 deletions

View File

@ -26,7 +26,7 @@ from fuzzywuzzy import process as fuzzy_process
import Items import Items
import Regions import Regions
import Utils import Utils
from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem from Utils import get_item_name_from_id, get_location_name_from_address, ReceivedItem, _version_tuple
from NetUtils import Node, Endpoint from NetUtils import Node, Endpoint
console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups)) console_names = frozenset(set(Items.item_table) | set(Regions.location_table) | set(Items.item_name_groups))
@ -60,8 +60,9 @@ class Client(Endpoint):
class Context(Node): class Context(Node):
def __init__(self, host: str, port: int, password: str, location_check_points: int, hint_cost: int, def __init__(self, host: str, port: int, password: str, location_check_points: int, hint_cost: int,
item_cheat: bool, forfeit_mode: str = "disabled", remaining_mode: str = "disabled", item_cheat: bool, forfeit_mode: str = "disabled", remaining_mode: str = "disabled",
auto_shutdown: typing.SupportsFloat = 0): auto_shutdown: typing.SupportsFloat = 0, compatibility: int = 2):
super(Context, self).__init__() super(Context, self).__init__()
self.compatibility: int = compatibility
self.shutdown_task = None self.shutdown_task = None
self.data_filename = None self.data_filename = None
self.save_filename = None self.save_filename = None
@ -190,8 +191,8 @@ class Context(Node):
self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True) self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True)
self.auto_saver_thread.start() self.auto_saver_thread.start()
import atexit import atexit
atexit.register(self._save) # make sure we save on exit too atexit.register(self._save) # make sure we save on exit too
def get_save(self) -> dict: def get_save(self) -> dict:
d = { d = {
@ -640,7 +641,8 @@ class CommonCommandProcessor(CommandProcessor):
"password": str, "password": str,
"forfeit_mode": str, "forfeit_mode": str,
"item_cheat": bool, "item_cheat": bool,
"auto_save_interval": int} "auto_save_interval": int,
"compatibility": int}
def _cmd_countdown(self, seconds: str = "10") -> bool: def _cmd_countdown(self, seconds: str = "10") -> bool:
"""Start a countdown in seconds""" """Start a countdown in seconds"""
@ -889,7 +891,6 @@ async def process_client_cmd(ctx: Context, client: Client, cmd, args):
errors.add('InvalidPassword') errors.add('InvalidPassword')
if type(args["rom"]) == list: if type(args["rom"]) == list:
args["rom"] = bytes(letter for letter in args["rom"]).decode() args["rom"] = bytes(letter for letter in args["rom"]).decode()
if args['rom'] not in ctx.rom_names: if args['rom'] not in ctx.rom_names:
errors.add('InvalidRom') errors.add('InvalidRom')
else: else:
@ -909,8 +910,12 @@ async def process_client_cmd(ctx: Context, client: Client, cmd, args):
client.name = ctx.player_names[(team, slot)] client.name = ctx.player_names[(team, slot)]
client.team = team client.team = team
client.slot = slot client.slot = slot
if ctx.compatibility == 1 and "Berserker" not in args.get('tags', Client.tags):
errors.add('IncompatibleVersion')
elif ctx.compatibility == 0 and args.get('version', Client.version) != list(_version_tuple):
errors.add('IncompatibleVersion')
if errors: if errors:
logging.info(f"A client connection was refused due to: {errors}")
await ctx.send_msgs(client, [['ConnectionRefused', list(errors)]]) await ctx.send_msgs(client, [['ConnectionRefused', list(errors)]])
else: else:
ctx.client_ids[client.team, client.slot] = args.get("uuid", None) ctx.client_ids[client.team, client.slot] = args.get("uuid", None)
@ -1181,6 +1186,12 @@ def parse_args() -> argparse.Namespace:
parser.add_argument('--use_embedded_options', action="store_true", parser.add_argument('--use_embedded_options', action="store_true",
help='retrieve forfeit, remaining and hint options from the multidata file,' help='retrieve forfeit, remaining and hint options from the multidata file,'
' instead of host.yaml') ' instead of host.yaml')
parser.add_argument('--compatibility', default=defaults["compatibility"], type=int,
help="""
#2 -> recommended for casual/cooperative play, attempt to be compatible with everything across all versions
#1 -> recommended for friendly racing, only allow Berserker's Multiworld, to disallow old /getitem for example
#0 -> recommended for tournaments to force a level playing field, only allow an exact version match
""")
args = parser.parse_args() args = parser.parse_args()
return args return args
@ -1214,7 +1225,8 @@ async def main(args: argparse.Namespace):
logging.basicConfig(format='[%(asctime)s] %(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO)) logging.basicConfig(format='[%(asctime)s] %(message)s', level=getattr(logging, args.loglevel.upper(), logging.INFO))
ctx = Context(args.host, args.port, args.password, args.location_check_points, args.hint_cost, ctx = Context(args.host, args.port, args.password, args.location_check_points, args.hint_cost,
not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode, args.auto_shutdown) not args.disable_item_cheat, args.forfeit_mode, args.remaining_mode, args.auto_shutdown,
args.compatibility)
data_filename = args.multidata data_filename = args.multidata

View File

@ -42,7 +42,7 @@ class DBCommandProcessor(ServerCommandProcessor):
class WebHostContext(Context): class WebHostContext(Context):
def __init__(self): def __init__(self):
super(WebHostContext, self).__init__("", 0, "", 1, 40, True, "enabled", "enabled", 0) super(WebHostContext, self).__init__("", 0, "", 1, 40, True, "enabled", "enabled", 0, 2)
self.main_loop = asyncio.get_running_loop() self.main_loop = asyncio.get_running_loop()
self.video = {} self.video = {}
self.tags = ["Berserker", "WebHost"] self.tags = ["Berserker", "WebHost"]

View File

@ -40,6 +40,11 @@ server_options:
remaining_mode: "goal" remaining_mode: "goal"
# automatically shut down the server after this many seconds without new location checks, 0 to keep running # automatically shut down the server after this many seconds without new location checks, 0 to keep running
auto_shutdown: 0 auto_shutdown: 0
#compatibility handling
#2 -> recommended for casual/cooperative play, attempt to be compatible with everything across all versions
#1 -> recommended for friendly racing, only allow Berserker's Multiworld, to disallow old /getitem for example
#0 -> recommended for tournaments to force a level playing field, only allow an exact version match
compatibility: 2
#options for MultiMystery.py #options for MultiMystery.py
multi_mystery_options: multi_mystery_options:
#teams, however, note that there is currently no way to supply names for teams 2+ through MultiMystery #teams, however, note that there is currently no way to supply names for teams 2+ through MultiMystery