1
0
mirror of synced 2024-11-27 23:50:47 +01:00

fix issues and verify lint

This commit is contained in:
Shinrin Ouja Moriking 2024-04-01 00:10:37 -06:00
parent 2b6ce21084
commit cd587b19c3
12 changed files with 243 additions and 140 deletions

View File

@ -1,9 +1,7 @@
from typing import Optional
from typing_extensions import Final from typing_extensions import Final
from bemani.backend.base import Base from bemani.backend.base import Base
from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler from bemani.backend.core import CoreHandler, CardManagerHandler, PASELIHandler
from bemani.common import GameConstants, ValidatedDict from bemani.common import GameConstants
from bemani.protocol import Node
class HelloPopnBase(CoreHandler, CardManagerHandler, PASELIHandler, Base): class HelloPopnBase(CoreHandler, CardManagerHandler, PASELIHandler, Base):

View File

@ -8,6 +8,7 @@ from bemani.common import ValidatedDict, VersionConstants, Profile
from bemani.data import Score from bemani.data import Score
from bemani.protocol import Node from bemani.protocol import Node
class HelloPopnMusic( class HelloPopnMusic(
EventLogHandler, EventLogHandler,
HelloPopnBase, HelloPopnBase,
@ -16,14 +17,11 @@ class HelloPopnMusic(
version = VersionConstants.HELLO_POPN_MUSIC version = VersionConstants.HELLO_POPN_MUSIC
@classmethod @classmethod
def get_settings(cls) -> Dict[str, Any]: def get_settings(cls) -> Dict[str, Any]:
""" """
Return all of our front-end modifiably settings. Return all of our front-end modifiably settings.
""" """
return { return {
"ints": [
],
'bools': [ 'bools': [
{ {
'name': 'Force Song Unlock', 'name': 'Force Song Unlock',
@ -55,7 +53,7 @@ class HelloPopnMusic(
return root return root
def handle_game_new_request(self, request: Node) -> Node: def handle_game_new_request(self, request: Node) -> Node:
#profile creation # profile creation
root = Node.void('game') root = Node.void('game')
userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid'))
@ -79,10 +77,9 @@ class HelloPopnMusic(
return root return root
def handle_game_load_request(self, request: Node) -> Node: def handle_game_load_request(self, request: Node) -> Node:
#Load profile values # Load profile values
root = Node.void('game') root = Node.void('game')
userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid'))
profile = self.get_profile(userid) profile = self.get_profile(userid)
@ -90,7 +87,7 @@ class HelloPopnMusic(
game_config = self.get_game_config() game_config = self.get_game_config()
force_unlock_songs = game_config.get_bool("force_unlock_songs") force_unlock_songs = game_config.get_bool("force_unlock_songs")
#if we send all chara love as max, all songs will be unlocked # if we send all chara love as max, all songs will be unlocked
if force_unlock_songs: if force_unlock_songs:
for n in range(12): for n in range(12):
chara = Node.void('chara') chara = Node.void('chara')
@ -98,7 +95,7 @@ class HelloPopnMusic(
chara.set_attribute('love', "5") chara.set_attribute('love', "5")
root.add_child(chara) root.add_child(chara)
else: else:
#load chara love progress # load chara love progress
for achievement in achievements: for achievement in achievements:
if achievement.type == 'toki_love': if achievement.type == 'toki_love':
chara = Node.void('chara') chara = Node.void('chara')
@ -106,7 +103,6 @@ class HelloPopnMusic(
chara.set_attribute('love', achievement.data.get_str('love')) chara.set_attribute('love', achievement.data.get_str('love'))
root.add_child(chara) root.add_child(chara)
last = Node.void('last') last = Node.void('last')
root.add_child(last) root.add_child(last)
last.set_attribute('chara', profile.get_str('chara')) last.set_attribute('chara', profile.get_str('chara'))
@ -119,7 +115,7 @@ class HelloPopnMusic(
return root return root
def handle_game_load_m_request(self, request: Node) -> Node: def handle_game_load_m_request(self, request: Node) -> Node:
#Load scores # Load scores
userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid'))
scores = self.data.remote.music.get_scores(self.game, self.version, userid) scores = self.data.remote.music.get_scores(self.game, self.version, userid)
@ -152,7 +148,7 @@ class HelloPopnMusic(
return root return root
def handle_game_save_request(self, request: Node) -> Node: def handle_game_save_request(self, request: Node) -> Node:
#Save profile data # Save profile data
root = Node.void('game') root = Node.void('game')
userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid')) userid = self.data.remote.user.from_refid(self.game, self.version, request.attribute('refid'))
@ -169,35 +165,32 @@ class HelloPopnMusic(
self.put_profile(userid, newprofile) self.put_profile(userid, newprofile)
game_config = self.get_game_config() game_config = self.get_game_config()
force_unlock_songs = game_config.get_bool("force_unlock_songs") force_unlock_songs = game_config.get_bool("force_unlock_songs")
#if we were on force unlock mode, achievements will not be modified # if we were on force unlock mode, achievements will not be modified
if force_unlock_songs is False: if force_unlock_songs is False:
achievements = self.data.local.user.get_achievements(self.game, self.version, userid) achievements = self.data.local.user.get_achievements(self.game, self.version, userid)
love = last.attribute('love') chara = int(last.attribute('chara'))
for achievement in achievements: for achievement in achievements:
if achievement.type == 'toki_love' and achievement.id == int(last.attribute('chara')): if achievement.type == 'toki_love' and achievement.id == chara:
love = str(int(achievement.data["love"]) + 1) love = int(achievement.data["love"])
if achievement.data["love"] == "5": if love > 5:
love = "5"
self.data.local.user.put_achievement( self.data.local.user.put_achievement(
self.game, self.game,
self.version, self.version,
userid, userid,
int(last.attribute('chara')), chara,
'toki_love', 'toki_love',
{ {
'love': love, 'love': str(love + 1),
}, },
) )
break
return root return root
def handle_game_save_m_request(self, request: Node) -> Node: def handle_game_save_m_request(self, request: Node) -> Node:
#Score saving # Score saving
clear_type = int(request.attribute('clear_type')) clear_type = int(request.attribute('clear_type'))
level = int(request.attribute('level')) level = int(request.attribute('level'))
@ -207,7 +200,7 @@ class HelloPopnMusic(
userid = self.data.remote.user.from_refid(self.game, self.version, refid) userid = self.data.remote.user.from_refid(self.game, self.version, refid)
#pull old score # Pull old score
oldscore = self.data.local.music.get_score( oldscore = self.data.local.music.get_score(
self.game, self.game,
self.version, self.version,
@ -228,14 +221,13 @@ class HelloPopnMusic(
points = max(oldscore.points, points) points = max(oldscore.points, points)
scoredata = oldscore.data scoredata = oldscore.data
#Clear type # Clear type
scoredata.replace_int('clear_type', max(scoredata.get_int('clear_type'), clear_type)) scoredata.replace_int('clear_type', max(scoredata.get_int('clear_type'), clear_type))
history.replace_int('clear_type', clear_type) history.replace_int('clear_type', clear_type)
# Look up where this score was earned # Look up where this score was earned
lid = self.get_machine_id() lid = self.get_machine_id()
# Write the new score back # Write the new score back
self.data.local.music.put_score( self.data.local.music.put_score(
self.game, self.game,

View File

@ -1,6 +1,6 @@
import base64 import random
import time import time
from typing import Optional from typing import Any, Dict, Optional
from bemani.client.base import BaseClient from bemani.client.base import BaseClient
from bemani.protocol import Node from bemani.protocol import Node
@ -8,9 +8,7 @@ from bemani.protocol import Node
class HelloPopnMuiscClient(BaseClient): class HelloPopnMuiscClient(BaseClient):
NAME = "" def verify_game_shop(self) -> None:
def verify_game_shop(self)->None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -46,8 +44,7 @@ class HelloPopnMuiscClient(BaseClient):
# Verify that response is correct # Verify that response is correct
self.assert_path(resp, "response/game/@status") self.assert_path(resp, "response/game/@status")
def verify_game_common(self) -> None:
def verify_game_common(self)->None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -57,9 +54,14 @@ class HelloPopnMuiscClient(BaseClient):
resp = self.exchange("", call) resp = self.exchange("", call)
# Verify that response is correct # Verify that response is correct
#self.__verify_profile(resp) self.assert_path(resp, "response/game/@status")
self.assert_path(resp, "response/game/flag/@id")
self.assert_path(resp, "response/game/flag/@s1")
self.assert_path(resp, "response/game/flag/@s2")
self.assert_path(resp, "response/game/flag/@t")
self.assert_path(resp, "response/game/cnt_music")
def verify_game_new(self, loc: str, refid: str)->None: def verify_game_new(self, loc: str, refid: str) -> None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -74,7 +76,7 @@ class HelloPopnMuiscClient(BaseClient):
# Verify that response is correct # Verify that response is correct
self.assert_path(resp, "response/game/@status") self.assert_path(resp, "response/game/@status")
def verify_game_load(self, refid: str)->None: def verify_game_load(self, refid: str) -> None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -91,7 +93,7 @@ class HelloPopnMuiscClient(BaseClient):
self.assert_path(resp, "response/game/last/@music_id") self.assert_path(resp, "response/game/last/@music_id")
self.assert_path(resp, "response/game/last/@style") self.assert_path(resp, "response/game/last/@style")
def verify_game_load_m(self, refid: str)->None: def verify_game_load_m(self, refid: str) -> None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -105,26 +107,51 @@ class HelloPopnMuiscClient(BaseClient):
# Verify that response is correct # Verify that response is correct
self.assert_path(resp, "response/game/@status") self.assert_path(resp, "response/game/@status")
def verify_game_save_m(self, refid: str)->None: # Grab scores
scores: Dict[int, Dict[int, int]] = {}
clears: Dict[int, Dict[int, int]] = {}
for child in resp.child("game").children:
if child.name != "music":
continue
score_data = child.child("style").child("level")
musicid = child.attribute("music_id")
chart = score_data.attribute("id")
score = score_data.attribute("score")
clear_type = score_data.attribute("clear_type")
if musicid not in scores:
scores[musicid] = {}
if musicid not in clears:
clears[musicid] = {}
scores[musicid][chart] = score
clears[musicid][chart] = clear_type
return {
"scores": scores,
"clears": clears,
}
def verify_game_save_m(self, refid: str, score: Dict[str, Any]) -> None:
call = self.call_node() call = self.call_node()
# Construct node
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
game.set_attribute("clear_type", "2") game.set_attribute("clear_type", score["clear_type"])
game.set_attribute("level", "1") game.set_attribute("level", score["chart"])
game.set_attribute("method", "save_m") game.set_attribute("method", "save_m")
game.set_attribute("music_id", "1") game.set_attribute("music_id", score["id"])
game.set_attribute("refid", refid) game.set_attribute("refid", refid)
game.set_attribute("score", "736000") game.set_attribute("score", score["score"])
game.set_attribute("style", "0") game.set_attribute("style", "0")
game.set_attribute("ver", "0") game.set_attribute("ver", "0")
# Swap with server # Swap with server
resp = self.exchange("", call) resp = self.exchange("", call)
# Verify that response is correct
self.assert_path(resp, "response/game/@status") self.assert_path(resp, "response/game/@status")
def verify_game_save(self, loc: str , refid: str)->None: def verify_game_save(self, loc: str , refid: str) -> None:
call = self.call_node() call = self.call_node()
game = Node.void("game") game = Node.void("game")
call.add_child(game) call.add_child(game)
@ -146,7 +173,6 @@ class HelloPopnMuiscClient(BaseClient):
# Verify that response is correct # Verify that response is correct
self.assert_path(resp, "response/game/@status") self.assert_path(resp, "response/game/@status")
def verify(self, cardid: Optional[str]) -> None: def verify(self, cardid: Optional[str]) -> None:
# Verify boot sequence is okay # Verify boot sequence is okay
self.verify_services_get( self.verify_services_get(
@ -190,8 +216,8 @@ class HelloPopnMuiscClient(BaseClient):
raise Exception(f'Invalid refid \'{ref_id}\' returned when registering card') raise Exception(f'Invalid refid \'{ref_id}\' returned when registering card')
if ref_id != self.verify_cardmng_inquire(card, msg_type='new', paseli_enabled=paseli_enabled): if ref_id != self.verify_cardmng_inquire(card, msg_type='new', paseli_enabled=paseli_enabled):
raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card')
#New profile creation # New profile creation
self.verify_game_new(location,ref_id) self.verify_game_new(location, ref_id)
else: else:
print("Skipping new card checks for existing card") print("Skipping new card checks for existing card")
ref_id = self.verify_cardmng_inquire(card, msg_type='query', paseli_enabled=paseli_enabled) ref_id = self.verify_cardmng_inquire(card, msg_type='query', paseli_enabled=paseli_enabled)
@ -204,8 +230,99 @@ class HelloPopnMuiscClient(BaseClient):
raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card') raise Exception(f'Invalid refid \'{ref_id}\' returned when querying card')
self.verify_game_load(ref_id) self.verify_game_load(ref_id)
self.verify_game_load_m(ref_id) self.verify_game_load_m(ref_id)
self.verify_game_save_m(ref_id) if cardid is None:
self.verify_game_save(location,ref_id) # verify score saving
for phase in [1, 2]:
if phase == 1:
dummyscores = [
# An okay score on a chart
{
"id": "1",
"chart": "1",
"clear_type": "1",
"score": "813144",
},
# A good score on an easier chart of the same song
{
"id": "1",
"chart": "0",
"clear_type": "4",
"score": "1000000",
},
# A bad score on a hard chart
{
"id": "35",
"chart": "2",
"clear_type": "1",
"score": "590523",
},
# A terrible score on an easy chart
{
"id": "28",
"chart": "0",
"clear_type": "1",
"score": "1",
},
]
# Random score to add in
songid = str(random.randint(1, 35))
chartid = str(random.randint(0, 2))
clear_type = str(random.randint(1, 4))
score = str(random.randint(0, 1000000))
dummyscores.append(
{
"id": songid,
"chart": chartid,
"clear_type": clear_type,
"score": score,
}
)
if phase == 2:
dummyscores = [
# A better score on the same chart
{
"id": "1",
"chart": "1",
"clear_type": "3",
"score": "950144",
},
# A worse score on another same chart
{
"id": "1",
"chart": "0",
"clear_type": "1",
"score": "672381",
"expected_score": "1000000",
"expected_clear": "4",
},
]
for dummyscore in dummyscores:
self.verify_game_save_m(ref_id, dummyscore)
# Sleep so we don't end up putting in score history on the same second
time.sleep(1)
scores = self.verify_game_load_m(ref_id)
for expected in dummyscores:
newscore = scores["scores"][expected["id"]][expected["chart"]]
newclear = scores["clears"][expected["id"]][expected["chart"]]
if "expected_score" in expected:
expected_score = expected["expected_score"]
else:
expected_score = expected["score"]
if "expected_clear" in expected:
expected_clear = expected["expected_clear"]
else:
expected_clear = expected["clear_type"]
if newscore != expected_score:
raise Exception(
f'Expected a score of \'{expected_score}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got score \'{newscore}\''
)
if newclear != expected_clear:
raise Exception(
f'Expected a medal of \'{expected_clear}\' for song \'{expected["id"]}\' chart \'{expected["chart"]}\' but got medal \'{newclear}\''
)
else:
print("Skipping score checks for existing card")
self.verify_game_save(location, ref_id)

View File

@ -1,19 +1,12 @@
from bemani.data import Config, Data from bemani.data import Config, Data
from flask_caching import Cache from bemani.common import cache
from bemani.frontend.app import app
from bemani.frontend.hellopopn.hellopopn import HelloPopnMusicFrontend from bemani.frontend.hellopopn.hellopopn import HelloPopnMusicFrontend
class HelloPopnMusicCache: class HelloPopnMusicCache:
@classmethod @classmethod
def preload(cls, data: Data, config: Config) -> None: def preload(cls, data: Data, config: Config) -> None:
cache = Cache(
app,
config={
"CACHE_TYPE": "filesystem",
"CACHE_DIR": config.cache_dir,
},
)
frontend = HelloPopnMusicFrontend(data, config, cache) frontend = HelloPopnMusicFrontend(data, config, cache)
frontend.get_all_songs(force_db_load=True) frontend.get_all_songs(force_db_load=True)

View File

@ -1,5 +1,4 @@
import re import re
from flask import Blueprint
from bemani.frontend.templates import templates_location from bemani.frontend.templates import templates_location
from bemani.frontend.static import static_location from bemani.frontend.static import static_location
from bemani.data import UserID from bemani.data import UserID
@ -29,7 +28,6 @@ def viewnetworkscores() -> Response:
if len(network_scores["attempts"]) > 10: if len(network_scores["attempts"]) > 10:
network_scores["attempts"] = frontend.round_to_ten(network_scores["attempts"]) network_scores["attempts"] = frontend.round_to_ten(network_scores["attempts"])
return render_react( return render_react(
"Global Hello Pop'n Music Scores", "Global Hello Pop'n Music Scores",
"hpnm/scores.react.js", "hpnm/scores.react.js",
@ -47,6 +45,7 @@ def viewnetworkscores() -> Response:
}, },
) )
@hpnm_pages.route("/scores/list") @hpnm_pages.route("/scores/list")
@jsonify @jsonify
@loginrequired @loginrequired
@ -54,6 +53,7 @@ def listnetworkscores() -> Dict[str, Any]:
frontend = HelloPopnMusicFrontend(g.data, g.config, g.cache) frontend = HelloPopnMusicFrontend(g.data, g.config, g.cache)
return frontend.get_network_scores() return frontend.get_network_scores()
@hpnm_pages.route('/scores/<int:userid>') @hpnm_pages.route('/scores/<int:userid>')
@loginrequired @loginrequired
def viewscores(userid: UserID) -> Response: def viewscores(userid: UserID) -> Response:
@ -61,7 +61,7 @@ def viewscores(userid: UserID) -> Response:
info = frontend.get_latest_player_info([userid]).get(userid) info = frontend.get_latest_player_info([userid]).get(userid)
if info is None: if info is None:
abort(404) abort(404)
scores = frontend.get_scores(userid,limit=100) scores = frontend.get_scores(userid, limit=100)
if len(scores) > 10: if len(scores) > 10:
scores = frontend.round_to_ten(scores) scores = frontend.round_to_ten(scores)
@ -83,6 +83,7 @@ def viewscores(userid: UserID) -> Response:
}, },
) )
@hpnm_pages.route("/scores/<int:userid>/list") @hpnm_pages.route("/scores/<int:userid>/list")
@jsonify @jsonify
@loginrequired @loginrequired
@ -93,6 +94,7 @@ def listscores(userid: UserID) -> Dict[str, Any]:
"players": {}, "players": {},
} }
@hpnm_pages.route("/topscores/<int:musicid>") @hpnm_pages.route("/topscores/<int:musicid>")
@loginrequired @loginrequired
def viewtopscores(musicid: int) -> Response: def viewtopscores(musicid: int) -> Response:
@ -161,6 +163,7 @@ def viewplayers() -> Response:
}, },
) )
@hpnm_pages.route('/players/list') @hpnm_pages.route('/players/list')
@jsonify @jsonify
@loginrequired @loginrequired
@ -208,6 +211,7 @@ def listplayer(userid: UserID) -> Dict[str, Any]:
"player": info, "player": info,
} }
@hpnm_pages.route("/options") @hpnm_pages.route("/options")
@loginrequired @loginrequired
def viewsettings() -> Response: def viewsettings() -> Response:
@ -270,6 +274,7 @@ def updatename() -> Dict[str, Any]:
"name": name, "name": name,
} }
@hpnm_pages.route("/records") @hpnm_pages.route("/records")
@loginrequired @loginrequired
def viewnetworkrecords() -> Response: def viewnetworkrecords() -> Response:

View File

@ -1,11 +1,11 @@
import copy
from typing import Any, Dict, Iterator, List, Tuple from typing import Any, Dict, Iterator, List, Tuple
from flask_caching import Cache # type: ignore from flask_caching import Cache # type: ignore
from bemani.backend.hellopopn import HelloPopnFactory,HelloPopnBase from bemani.backend.hellopopn import HelloPopnFactory, HelloPopnBase
from bemani.common import Profile, ValidatedDict, GameConstants from bemani.common import Profile, ValidatedDict, GameConstants
from bemani.data import Data,UserID,Attempt, Song from bemani.data import Data, UserID, Attempt, Song
from bemani.frontend.base import FrontendBase from bemani.frontend.base import FrontendBase
class HelloPopnMusicFrontend(FrontendBase): class HelloPopnMusicFrontend(FrontendBase):
game = GameConstants.HELLO_POPN game = GameConstants.HELLO_POPN

View File

@ -16,7 +16,6 @@ from bemani.common import GameConstants, cache
from bemani.data import Config, Data from bemani.data import Config, Data
def load_config(filename: str, config: Config) -> None: def load_config(filename: str, config: Config) -> None:
config.update(yaml.safe_load(open(filename))) config.update(yaml.safe_load(open(filename)))
config["database"]["engine"] = Data.create_engine(config) config["database"]["engine"] = Data.create_engine(config)

View File

@ -4591,9 +4591,9 @@ class ImportHelloPopn(ImportBase):
'artist': song.artist, 'artist': song.artist,
'genre': song.genre, 'genre': song.genre,
'difficulty': { 'difficulty': {
'easy': 0, 'easy': 1,
'normal': 1, 'normal': 10,
'hard': 2, 'hard': 100,
}, },
'category': self.version 'category': self.version
} }
@ -4602,10 +4602,9 @@ class ImportHelloPopn(ImportBase):
# Reassemble the data # Reassemble the data
reassembled_songs = [val for _, val in lut.items()] reassembled_songs = [val for _, val in lut.items()]
return reassembled_songs return reassembled_songs
def import_music_db(self, songs: List[Dict[str, Any]],version: int) -> None: def import_music_db(self, songs: List[Dict[str, Any]], version: int) -> None:
if self.version is None: if self.version is None:
raise Exception('Can\'t import database for \'all\' version!') raise Exception('Can\'t import database for \'all\' version!')
@ -5391,7 +5390,7 @@ def main() -> None:
'No TSV provided and no remote server specified! Please ' + 'No TSV provided and no remote server specified! Please ' +
'provide either a --tsv or a --server and --token option!' 'provide either a --tsv or a --server and --token option!'
) )
hellopopn.import_music_db(songs,args.version) hellopopn.import_music_db(songs, args.version)
hellopopn.close() hellopopn.close()
else: else: