From 480551f94250b1ebce0d5a359110408f825f4704 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:07:05 +0000 Subject: [PATCH 01/12] Fixed logic error leading to strict IP checking always being enabled --- core/allnet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/allnet.py b/core/allnet.py index 6610c23..b0e1c78 100644 --- a/core/allnet.py +++ b/core/allnet.py @@ -147,7 +147,7 @@ class AllnetServlet: resp_dict = {k: v for k, v in vars(resp).items() if v is not None} return (urllib.parse.unquote(urllib.parse.urlencode(resp_dict)) + "\n").encode("utf-8") - elif not arcade["ip"] or arcade["ip"] is None and self.config.server.strict_ip_checking: + elif (not arcade["ip"] or arcade["ip"] is None) and self.config.server.strict_ip_checking: msg = f"Serial {req.serial} attempted allnet auth from bad IP {req.ip}, but arcade {arcade['id']} has no IP set! (strict checking enabled)." self.data.base.log_event( "allnet", "ALLNET_AUTH_NO_SHOP_IP", logging.ERROR, msg From c78a62de14c7e65abb06845cf07fef5b51e6ebc9 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:09:11 +0000 Subject: [PATCH 02/12] Fixed Rival Music retrieval --- titles/chuni/schema/score.py | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/titles/chuni/schema/score.py b/titles/chuni/schema/score.py index ab26f5f..c31f560 100644 --- a/titles/chuni/schema/score.py +++ b/titles/chuni/schema/score.py @@ -201,9 +201,33 @@ class ChuniScoreData(BaseData): return None return result.lastrowid - def get_rival_music(self, rival_id: int, index: int, max_count: int) -> Optional[List[Dict]]: - sql = select(playlog).where(playlog.c.user == rival_id).limit(max_count).offset(index) + def get_rival_music(self, rival_id: int) -> Optional[List[Dict]]: + sql = select(playlog).where(playlog.c.user == rival_id) result = self.execute(sql) if result is None: return None - return result.fetchall() \ No newline at end of file + return result.fetchall() + def get_rival_music_highest_scores(self, rival_id: int) -> Optional[List[Dict]]: + # Define the subquery to retrieve the highest scoreMax for each level and musicId + subquery = ( + select([ + self.playlog.c.musicId, + self.playlog.c.level, + func.max(self.playlog.c.score) + ]) + .where(self.playlog.c.user == rival_id) + .group_by(self.playlog.c.musicId, self.playlog.c.level) + ) + + # Join the subquery with the playlog table to get the full records + query = select([ + self.playlog, + subquery.scalar() + ]).where(self.playlog.c.user == rival_id) + + result = self.execute(query) + + if result is None: + return None + + return result.fetchall() From d49997f832c02be4eb229c90c48158156d49d386 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:09:53 +0000 Subject: [PATCH 03/12] Team Rank Scaling is dead, long live Team Rank Scaling --- titles/chuni/schema/profile.py | 42 ++++------------------------------ 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/titles/chuni/schema/profile.py b/titles/chuni/schema/profile.py index fa7a4ab..ea70583 100644 --- a/titles/chuni/schema/profile.py +++ b/titles/chuni/schema/profile.py @@ -646,7 +646,7 @@ class ChuniProfileData(BaseData): return None return result.fetchone() - def get_team_rank_actual(self, team_id: int) -> int: + def get_team_rank(self, team_id: int) -> int: # Normal ranking system, likely the one used in the real servers # Query all teams sorted by 'teamPoint' result = self.execute( @@ -663,42 +663,8 @@ class ChuniProfileData(BaseData): # Return the rank if found, or a default rank otherwise return rank if rank is not None else 0 - def get_team_rank(self, team_id: int) -> int: - # Scaled ranking system, designed for smaller instances. - # Query all teams sorted by 'teamPoint' - result = self.execute( - select(team.c.id).order_by(team.c.teamPoint.desc()) - ) - - # Count total number of teams - total_teams = self.execute(select(func.count()).select_from(team)).scalar() - - # Get the rank of the team with the given team_id - rank = None - for i, row in enumerate(result, start=1): - if row.id == team_id: - rank = i - break - - # If the team is not found, return default rank - if rank is None: - return 0 - - # Define rank tiers - tiers = { - 1: range(1, int(total_teams * 0.1) + 1), # Rainbow - 2: range(int(total_teams * 0.1) + 1, int(total_teams * 0.4) + 1), # Gold - 3: range(int(total_teams * 0.4) + 1, int(total_teams * 0.7) + 1), # Silver - 4: range(int(total_teams * 0.7) + 1, total_teams + 1), # Grey - } - - # Assign rank based on tier - for tier_rank, tier_range in tiers.items(): - if rank in tier_range: - return tier_rank - - # Return default rank if not found in any tier - return 0 + # RIP scaled team ranking. Gone, but forgotten + # def get_team_rank_scaled(self, team_id: int) -> int: def update_team(self, team_id: int, team_data: Dict) -> bool: team_data["id"] = team_id @@ -736,4 +702,4 @@ class ChuniProfileData(BaseData): total_play_count += row[0] return { "total_play_count": total_play_count - } \ No newline at end of file + } From 35a7525f74776219e41f579556571233d4d673bd Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:14:11 +0000 Subject: [PATCH 04/12] Removed extraneous function --- titles/chuni/schema/score.py | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/titles/chuni/schema/score.py b/titles/chuni/schema/score.py index c31f560..67cf141 100644 --- a/titles/chuni/schema/score.py +++ b/titles/chuni/schema/score.py @@ -207,27 +207,3 @@ class ChuniScoreData(BaseData): if result is None: return None return result.fetchall() - def get_rival_music_highest_scores(self, rival_id: int) -> Optional[List[Dict]]: - # Define the subquery to retrieve the highest scoreMax for each level and musicId - subquery = ( - select([ - self.playlog.c.musicId, - self.playlog.c.level, - func.max(self.playlog.c.score) - ]) - .where(self.playlog.c.user == rival_id) - .group_by(self.playlog.c.musicId, self.playlog.c.level) - ) - - # Join the subquery with the playlog table to get the full records - query = select([ - self.playlog, - subquery.scalar() - ]).where(self.playlog.c.user == rival_id) - - result = self.execute(query) - - if result is None: - return None - - return result.fetchall() From 3ef40fe85e04484d73319142217bb184db87dd09 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:15:39 +0000 Subject: [PATCH 05/12] Removed Team Rank Scaling and fixed RIval Music Data. Also cleaned up extraneous functions --- titles/chuni/base.py | 106 ++++++++++++++++++++----------------------- 1 file changed, 49 insertions(+), 57 deletions(-) diff --git a/titles/chuni/base.py b/titles/chuni/base.py index 21a6719..775b09b 100644 --- a/titles/chuni/base.py +++ b/titles/chuni/base.py @@ -200,12 +200,30 @@ class ChuniBase: return {"type": data["type"], "length": 0, "gameSaleList": []} def handle_get_game_setting_api_request(self, data: Dict) -> Dict: - reboot_start = datetime.strftime( - datetime.now() - timedelta(hours=4), self.date_time_format - ) - reboot_end = datetime.strftime( - datetime.now() - timedelta(hours=3), self.date_time_format - ) + # if reboot start/end time is not defined use the default behavior of being a few hours ago + if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "": + reboot_start = datetime.strftime( + datetime.utcnow() + timedelta(hours=6), self.date_time_format + ) + reboot_end = datetime.strftime( + datetime.utcnow() + timedelta(hours=7), self.date_time_format + ) + else: + # get current datetime in JST + current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date() + + # parse config start/end times into datetime + reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M") + reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M") + + # offset datetimes with current date/time + reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + + # create strings for use in gameSetting + reboot_start = reboot_start_time.strftime(self.date_time_format) + reboot_end = reboot_end_time.strftime(self.date_time_format) + return { "gameSetting": { "dataVersion": "1.00.00", @@ -385,26 +403,24 @@ class ChuniBase: } def handle_get_user_rival_music_api_request(self, data: Dict) -> Dict: - m = self.data.score.get_rival_music(data["rivalId"], data["nextIndex"], data["maxCount"]) - if m is None: - return {} - + rival_id = data["rivalId"] + next_index = int(data["nextIndex"]) + max_count = int(data["maxCount"]) user_rival_music_list = [] - for music in m: - actual_music_id = self.data.static.get_song(music["musicId"]) - if actual_music_id is None: - music_id = music["musicId"] - else: - music_id = actual_music_id["songId"] + + # Fetch all the rival music entries for the user + all_entries = self.data.score.get_rival_music(rival_id) + + # Process the entries based on max_count and nextIndex + for music in all_entries[next_index:]: + music_id = music["musicId"] level = music["level"] score = music["score"] rank = music["rank"] - # Find the existing entry for the current musicId in the user_rival_music_list + # Create a music entry for the current music_id if it's unique music_entry = next((entry for entry in user_rival_music_list if entry["musicId"] == music_id), None) - if music_entry is None: - # If the entry doesn't exist, create a new entry music_entry = { "musicId": music_id, "length": 0, @@ -412,52 +428,32 @@ class ChuniBase: } user_rival_music_list.append(music_entry) - # Check if the current score is higher than the previous highest score for the level - level_entry = next( - ( - entry - for entry in music_entry["userRivalMusicDetailList"] - if entry["level"] == level - ), - None, - ) - if level_entry is None or score > level_entry["scoreMax"]: - # If the level entry doesn't exist or the score is higher, update or add the entry + # Create a level entry for the current level if it's unique or has a higher score + level_entry = next((entry for entry in music_entry["userRivalMusicDetailList"] if entry["level"] == level), None) + if level_entry is None: level_entry = { "level": level, "scoreMax": score, "scoreRank": rank } + music_entry["userRivalMusicDetailList"].append(level_entry) + elif score > level_entry["scoreMax"]: + level_entry["scoreMax"] = score + level_entry["scoreRank"] = rank - if level_entry not in music_entry["userRivalMusicDetailList"]: - music_entry["userRivalMusicDetailList"].append(level_entry) - + # Calculate the length for each "musicId" by counting the unique levels + for music_entry in user_rival_music_list: music_entry["length"] = len(music_entry["userRivalMusicDetailList"]) + # Prepare the result dictionary with user rival music data result = { "userId": data["userId"], "rivalId": data["rivalId"], - "nextIndex": -1, - "userRivalMusicList": user_rival_music_list + "nextIndex": str(next_index + len(all_entries) if len(all_entries) <= len(user_rival_music_list) else -1), + "userRivalMusicList": user_rival_music_list[:max_count] } return result - def handle_get_user_rival_music_api_requestded(self, data: Dict) -> Dict: - m = self.data.score.get_rival_music(data["rivalId"], data["nextIndex"], data["maxCount"]) - if m is None: - return {} - - userRivalMusicList = [] - for music in m: - self.logger.debug(music["point"]) - - return { - "userId": data["userId"], - "rivalId": data["rivalId"], - "nextIndex": -1 - - } - def handle_get_user_favorite_item_api_request(self, data: Dict) -> Dict: user_fav_item_list = [] @@ -711,11 +707,7 @@ class ChuniBase: if team: team_id = team["id"] team_name = team["teamName"] - # Determine whether to use scaled ranks, or original system - if self.game_cfg.team.rank_scale: - team_rank = self.data.profile.get_team_rank(team["id"]) - else: - team_rank = self.data.profile.get_team_rank_actual(team["id"]) + team_rank = self.data.profile.get_team_rank(team["id"]) # Don't return anything if no team name has been defined for defaults and there is no team set for the player if not profile["teamId"] and team_name == "": @@ -888,4 +880,4 @@ class ChuniBase: return { "userId": data["userId"], "userNetBattleData": {"recentNBSelectMusicList": []}, - } \ No newline at end of file + } From 540d7fc2c2b4fb383f301afdd3b8835132838af6 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:18:23 +0000 Subject: [PATCH 06/12] Added reboot time support --- titles/chuni/new.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/titles/chuni/new.py b/titles/chuni/new.py index 40dee9b..8a658bf 100644 --- a/titles/chuni/new.py +++ b/titles/chuni/new.py @@ -3,6 +3,7 @@ from datetime import datetime, timedelta from random import randint from typing import Dict +import pytz from core.config import CoreConfig from titles.chuni.const import ChuniConstants from titles.chuni.database import ChuniData @@ -31,12 +32,29 @@ class ChuniNew(ChuniBase): match_end = datetime.strftime( datetime.utcnow() + timedelta(hours=16), self.date_time_format ) - reboot_start = datetime.strftime( - datetime.utcnow() + timedelta(hours=6), self.date_time_format - ) - reboot_end = datetime.strftime( - datetime.utcnow() + timedelta(hours=7), self.date_time_format - ) + # if reboot start/end time is not defined use the default behavior of being a few hours ago + if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "": + reboot_start = datetime.strftime( + datetime.utcnow() + timedelta(hours=6), self.date_time_format + ) + reboot_end = datetime.strftime( + datetime.utcnow() + timedelta(hours=7), self.date_time_format + ) + else: + # get current datetime in JST + current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date() + + # parse config start/end times into datetime + reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M") + reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M") + + # offset datetimes with current date/time + reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + + # create strings for use in gameSetting + reboot_start = reboot_start_time.strftime(self.date_time_format) + reboot_end = reboot_end_time.strftime(self.date_time_format) return { "gameSetting": { "isMaintenance": False, From e18b87ee5cb33c8ae5b0d44f2235f3b09eb2e92f Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:20:00 +0000 Subject: [PATCH 07/12] Added reboot time support --- titles/cm/base.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/titles/cm/base.py b/titles/cm/base.py index dae6ecb..587ceb5 100644 --- a/titles/cm/base.py +++ b/titles/cm/base.py @@ -4,6 +4,7 @@ import json import logging from enum import Enum +import pytz from core.config import CoreConfig from core.data.cache import cached from titles.cm.const import CardMakerConstants @@ -61,12 +62,29 @@ class CardMakerBase: } def handle_get_game_setting_api_request(self, data: Dict) -> Dict: - reboot_start = date.strftime( - datetime.now() + timedelta(hours=3), self.date_time_format - ) - reboot_end = date.strftime( - datetime.now() + timedelta(hours=4), self.date_time_format - ) + # if reboot start/end time is not defined use the default behavior of being a few hours ago + if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "": + reboot_start = datetime.strftime( + datetime.utcnow() + timedelta(hours=6), self.date_time_format + ) + reboot_end = datetime.strftime( + datetime.utcnow() + timedelta(hours=7), self.date_time_format + ) + else: + # get current datetime in JST + current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date() + + # parse config start/end times into datetime + reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M") + reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M") + + # offset datetimes with current date/time + reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + + # create strings for use in gameSetting + reboot_start = reboot_start_time.strftime(self.date_time_format) + reboot_end = reboot_end_time.strftime(self.date_time_format) # grab the dict with all games version numbers from user config games_ver = self.game_cfg.version.version(self.version) From 8d289ca0666c6935f1c8d9c63681fbf7660bda19 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:20:37 +0000 Subject: [PATCH 08/12] Added reboot time support --- titles/ongeki/base.py | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/titles/ongeki/base.py b/titles/ongeki/base.py index ccf24f5..c72c086 100644 --- a/titles/ongeki/base.py +++ b/titles/ongeki/base.py @@ -4,6 +4,7 @@ import json import logging from enum import Enum +import pytz from core.config import CoreConfig from core.data.cache import cached from titles.ongeki.const import OngekiConstants @@ -103,12 +104,30 @@ class OngekiBase: self.version = OngekiConstants.VER_ONGEKI def handle_get_game_setting_api_request(self, data: Dict) -> Dict: - reboot_start = date.strftime( - datetime.now() + timedelta(hours=3), self.date_time_format - ) - reboot_end = date.strftime( - datetime.now() + timedelta(hours=4), self.date_time_format - ) + # if reboot start/end time is not defined use the default behavior of being a few hours ago + if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "": + reboot_start = datetime.strftime( + datetime.utcnow() + timedelta(hours=6), self.date_time_format + ) + reboot_end = datetime.strftime( + datetime.utcnow() + timedelta(hours=7), self.date_time_format + ) + else: + # get current datetime in JST + current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date() + + # parse config start/end times into datetime + reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M") + reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M") + + # offset datetimes with current date/time + reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + + # create strings for use in gameSetting + reboot_start = reboot_start_time.strftime(self.date_time_format) + reboot_end = reboot_end_time.strftime(self.date_time_format) + return { "gameSetting": { "dataVersion": "1.00.00", From 9cff321857b809fb97e3313bc9517f2c64bc632c Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:21:07 +0000 Subject: [PATCH 09/12] Added reboot time support --- titles/mai2/base.py | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/titles/mai2/base.py b/titles/mai2/base.py index ad0433f..26677ac 100644 --- a/titles/mai2/base.py +++ b/titles/mai2/base.py @@ -5,6 +5,7 @@ from base64 import b64decode from os import path, stat, remove from PIL import ImageFile +import pytz from core.config import CoreConfig from titles.mai2.const import Mai2Constants from titles.mai2.config import Mai2Config @@ -21,22 +22,47 @@ class Mai2Base: self.can_deliver = False self.can_usbdl = False self.old_server = "" - + if self.core_config.server.is_develop and self.core_config.title.port > 0: self.old_server = f"http://{self.core_config.title.hostname}:{self.core_config.title.port}/SDEY/197/" - + else: self.old_server = f"http://{self.core_config.title.hostname}/SDEY/197/" def handle_get_game_setting_api_request(self, data: Dict): - return { + # if reboot start/end time is not defined use the default behavior of being a few hours ago + if self.core_cfg.title.reboot_start_time == "" or self.core_cfg.title.reboot_end_time == "": + reboot_start = datetime.strftime( + datetime.utcnow() + timedelta(hours=6), self.date_time_format + ) + reboot_end = datetime.strftime( + datetime.utcnow() + timedelta(hours=7), self.date_time_format + ) + else: + # get current datetime in JST + current_jst = datetime.now(pytz.timezone('Asia/Tokyo')).date() + + # parse config start/end times into datetime + reboot_start_time = datetime.strptime(self.core_cfg.title.reboot_start_time, "%H:%M") + reboot_end_time = datetime.strptime(self.core_cfg.title.reboot_end_time, "%H:%M") + + # offset datetimes with current date/time + reboot_start_time = reboot_start_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + reboot_end_time = reboot_end_time.replace(year=current_jst.year, month=current_jst.month, day=current_jst.day, tzinfo=pytz.timezone('Asia/Tokyo')) + + # create strings for use in gameSetting + reboot_start = reboot_start_time.strftime(self.date_time_format) + reboot_end = reboot_end_time.strftime(self.date_time_format) + + + return { "isDevelop": False, "isAouAccession": False, "gameSetting": { "isMaintenance": False, "requestInterval": 1800, - "rebootStartTime": "2020-01-01 07:00:00.0", - "rebootEndTime": "2020-01-01 07:59:59.0", + "rebootStartTime": reboot_start, + "rebootEndTime": reboot_end, "movieUploadLimit": 100, "movieStatus": 1, "movieServerUri": self.old_server + "api/movie" if self.game_config.uploads.movies else "movie", From 4f0a5f60ab67801ef64b62602a9f3ddbb2d161f5 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:22:18 +0000 Subject: [PATCH 10/12] Added config for reboot time support --- core/config.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/config.py b/core/config.py index 14f06f5..3a772f7 100644 --- a/core/config.py +++ b/core/config.py @@ -85,6 +85,18 @@ class TitleConfig: self.__config, "core", "title", "port", default=8080 ) + @property + def reboot_start_time(self) -> str: + return CoreConfig.get_config_field( + self.__config, "core", "title", "reboot_start_time", default="" + ) + + @property + def reboot_end_time(self) -> str: + return CoreConfig.get_config_field( + self.__config, "core", "title", "reboot_end_time", default="" + ) + class DatabaseConfig: def __init__(self, parent_config: "CoreConfig") -> None: From 300cd10abfc6eadd8334a216661aac5f038ff9a1 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:23:56 +0000 Subject: [PATCH 11/12] Updated example config with reboot time You can leave this option out to disable reboot times, and the games will use the prior mechanism of maintenance always being 4~ hours before current time --- example_config/core.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/example_config/core.yaml b/example_config/core.yaml index 76ec5b1..7bf097e 100644 --- a/example_config/core.yaml +++ b/example_config/core.yaml @@ -13,6 +13,9 @@ title: loglevel: "info" hostname: "localhost" port: 8080 + reboot_start_time: "04:00" + reboot_end_time: "05:00" + database: host: "localhost" From 8c114532e83018c4dcd0464a2e42e6bad9609ef4 Mon Sep 17 00:00:00 2001 From: EmmyHeart Date: Mon, 16 Oct 2023 13:30:10 +0000 Subject: [PATCH 12/12] Updated config documentation with IP enforcement and reboot times --- docs/config.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/config.md b/docs/config.md index 18f90eb..9de57f9 100644 --- a/docs/config.md +++ b/docs/config.md @@ -6,11 +6,15 @@ - `name`: Name for the server, used by some games in their default MOTDs. Default `ARTEMiS` - `is_develop`: Flags that the server is a development instance without a proxy standing in front of it. Setting to `False` tells the server not to listen for SSL, because the proxy should be handling all SSL-related things, among other things. Default `True` - `threading`: Flags that `reactor.run` should be called via the `Thread` standard library. May provide a speed boost, but removes the ability to kill the server via `Ctrl + C`. Default: `False` +- `check_arcade_ip`: Checks IPs against the `arcade` table in the database, if one is defined. Default `False` +- `strict_ip_checking`: Rejects clients if there is no IP in the `arcade` table for the respective arcade - `log_dir`: Directory to store logs. Server MUST have read and write permissions to this directory or you will have issues. Default `logs` ## Title - `loglevel`: Logging level for the title server. Default `info` - `hostname`: Hostname that gets sent to clients to tell them where to connect. Games must be able to connect to your server via the hostname or IP you spcify here. Note that most games will reject `localhost` or `127.0.0.1`. Default `localhost` - `port`: Port that the title server will listen for connections on. Set to 0 to use the Allnet handler to reduce the port footprint. Default `8080` +- `reboot_start_time`: 24 hour JST time that clients will see as the start of maintenance period. Leave blank for no maintenance time. Default: "" +- `reboot_end_time`: 24 hour JST time that clients will see as the end of maintenance period. Leave blank for no maintenance time. Default: "" ## Database - `host`: Host of the database. Default `localhost` - `username`: Username of the account the server should connect to the database with. Default `aime`