Merge pull request 'Chunithm Fixes and Maintenance for all!' (#46) from EmmyHeart/artemis:develop into develop

Reviewed-on: https://gitea.tendokyu.moe/Hay1tsme/artemis/pulls/46
This commit is contained in:
Midorica
2023-10-17 17:00:08 +00:00
11 changed files with 180 additions and 122 deletions

View File

@@ -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": []},
}
}

View File

@@ -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,

View File

@@ -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
}
}

View File

@@ -201,9 +201,9 @@ 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()
return result.fetchall()

View File

@@ -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)

View File

@@ -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",

View File

@@ -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",