From ab63f58f9ebcfc122857354292fe3440bf6f203c Mon Sep 17 00:00:00 2001 From: 573dev <> Date: Wed, 4 Nov 2020 12:35:10 -0600 Subject: [PATCH] Gametop is working for the most part --- v8_server/eamuse/services/__init__.py | 2 + v8_server/eamuse/services/dlstatus.py | 26 +++ v8_server/eamuse/services/local.py | 225 ++++++++++++++++++++++++-- v8_server/eamuse/utils/xml.py | 5 + v8_server/view/index.py | 21 ++- 5 files changed, 262 insertions(+), 17 deletions(-) create mode 100644 v8_server/eamuse/services/dlstatus.py diff --git a/v8_server/eamuse/services/__init__.py b/v8_server/eamuse/services/__init__.py index f46bcb6..0941157 100644 --- a/v8_server/eamuse/services/__init__.py +++ b/v8_server/eamuse/services/__init__.py @@ -1,4 +1,5 @@ from v8_server.eamuse.services.cardmng import CardMng +from v8_server.eamuse.services.dlstatus import DLStatus from v8_server.eamuse.services.facility import Facility from v8_server.eamuse.services.local import Local from v8_server.eamuse.services.message import Message @@ -10,6 +11,7 @@ from v8_server.eamuse.services.services import ServiceRequest, Services, Service __all__ = [ "CardMng", + "DLStatus", "Facility", "Local", "Message", diff --git a/v8_server/eamuse/services/dlstatus.py b/v8_server/eamuse/services/dlstatus.py new file mode 100644 index 0000000..8bcb128 --- /dev/null +++ b/v8_server/eamuse/services/dlstatus.py @@ -0,0 +1,26 @@ +from lxml.builder import E + + +class DLStatus(object): + """ + Handle the DLStatus request. + + It is unknown as to what this does. + + Example: + + + """ + + # Methods + PROGRESS = "progress" + + @classmethod + def progress(cls): + """ + Example: + + + + """ + return E.response(E.dlstatus({"expire": "600"})) diff --git a/v8_server/eamuse/services/local.py b/v8_server/eamuse/services/local.py index 8ba1bd3..d2c5ec1 100644 --- a/v8_server/eamuse/services/local.py +++ b/v8_server/eamuse/services/local.py @@ -7,7 +7,7 @@ from lxml.builder import E from v8_server import db from v8_server.eamuse.services.services import ServiceRequest from v8_server.eamuse.utils.crc import calculate_crc8 -from v8_server.eamuse.utils.xml import XMLBinTypes as T, e_type +from v8_server.eamuse.utils.xml import XMLBinTypes as T, e_type, fill from v8_server.model.song import HitChart from v8_server.model.user import User, UserAccount @@ -307,22 +307,20 @@ class Local(object): E.ext_premium_border("95", e_type(T.u8)), ), E.battledata( - E.battle_music_level( - " ".join("0" * 13), e_type(T.u8, count=13) - ), - E.standard_skill(" ".join("0" * 13), e_type(T.s32, count=13)), - E.border_skill(" ".join("0" * 13), e_type(T.s32, count=13)), + E.battle_music_level(fill(13), e_type(T.u8, count=13)), + E.standard_skill(fill(13), e_type(T.s32, count=13)), + E.border_skill(fill(13), e_type(T.s32, count=13)), ), E.quest( E.division("0", e_type(T.u8)), E.border("0", e_type(T.u8)), - E.qdata(" ".join("0" * 26), e_type(T.u32, count=26)), + E.qdata(fill(26), e_type(T.u32, count=26)), *[ - E(f"play_{x}", " ".join("0" * 32), e_type(T.u32, count=32)) + E(f"play_{x}", fill(32), e_type(T.u32, count=32)) for x in range(0, 13) ], *[ - E(f"clear_{x}", " ".join("0" * 32), e_type(T.u32, count=32)) + E(f"clear_{x}", fill(32), e_type(T.u32, count=32)) for x in range(0, 13) ], ), @@ -339,18 +337,221 @@ class Local(object): @classmethod def gametop(cls, req: ServiceRequest) -> etree: + refid = req.xml[0].find("player/refid").text + # kind = int(req.xml[0].find("player/request/kind").text) + # offset = int(req.xml[0].find("player/request/offset").text) + # music_nr = int(req.xml[0].find("player/request/music_nr").text) + + user = User.from_refid(refid) + if user is None: + raise Exception(f"GameTop asking for invalid user with refid: {refid}") + account = user.user_account if req.method == cls.GAMETOP_GET: - pass + response = E.response( + E.gametop( + E.player( + E.player_type("0", e_type(T.u8)), + E.my_rival_id("0"), + E.mode("0", e_type(T.u8)), + E.syogo_list(fill(200, value="-1"), e_type(T.s16, count=200)), + E.badge_list(fill(200, value="-1"), e_type(T.s16, count=200)), + E.favorite_music(fill(20, value="-1"), e_type(T.s16, count=20)), + E.favorite_music_2( + fill(20, value="-1"), e_type(T.s16, count=20) + ), + E.favorite_music_3( + fill(20, value="-1"), e_type(T.s16, count=20) + ), + E.secret_music(fill(32), e_type(T.u16, count=32)), + E.style("2097152", e_type(T.u32)), + E.style_2("0", e_type(T.u32)), + E.shutter_list("0", e_type(T.u32)), + E.judge_logo_list("0", e_type(T.u32)), + E.skin_list("0", e_type(T.u32)), + E.movie_list("0", e_type(T.u32)), + E.attack_effect_list("0", e_type(T.u32)), + E.idle_screen("0", e_type(T.u32)), + E.chance_point("0", e_type(T.s32)), + E.failed_cnt("0", e_type(T.s32)), + E.secret_chara("0", e_type(T.u32)), + E.mode_beginner("0", e_type(T.u16)), + E.mode_standard("0", e_type(T.u16)), + E.mode_battle_global("0", e_type(T.u16)), + E.mode_battle_local("0", e_type(T.u16)), + E.mode_quest("0", e_type(T.u16)), + E.v3_skill("-1", e_type(T.s32)), + E.v4_skill("-1", e_type(T.s32)), + E.old_ver_skill("-1", e_type(T.s32)), + E.customize( + E.shutter("0", e_type(T.u8)), + E.info_level("0", e_type(T.u8)), + E.name_disp("0", e_type(T.u8)), + E.auto("0", e_type(T.u8)), + E.random("0", e_type(T.u8)), + E.judge_logo("0", e_type(T.u32)), + E.skin("0", e_type(T.u32)), + E.movie("0", e_type(T.u32)), + E.attack_effect("0", e_type(T.u32)), + E.layout("0", e_type(T.u8)), + E.target_skill("0", e_type(T.u8)), + E.comparison("0", e_type(T.u8)), + E.meter_custom(fill(3), e_type(T.u8, count=3)), + ), + E.tag(str(calculate_crc8("0")), e_type(T.u8)), + E.battledata( + E.bp("0", e_type(T.u32)), + E.battle_rate("0", e_type(T.s32)), + E.battle_class("0", e_type(T.u8)), + E.point("0", e_type(T.s16)), + E.rensyo("0", e_type(T.u16)), + E.win("0", e_type(T.u32)), + E.lose("0", e_type(T.u32)), + E.score_type("0", e_type(T.u8)), + E.strategy_item("0", e_type(T.s16)), + E.production_item("0", e_type(T.s16)), + E.draw("0", e_type(T.u32)), + E.max_class("0", e_type(T.u8)), + E.max_rensyo("0", e_type(T.u16)), + E.vip_rensyo("0", e_type(T.u16)), + E.max_defeat_skill("0", e_type(T.s32)), + E.max_defeat_battle_rate("0", e_type(T.s32)), + E.gold_star("0", e_type(T.u32)), + E.random_select("0", e_type(T.u32)), + E.enable_bonus_bp("0", e_type(T.u8)), + E.type_normal("0", e_type(T.u32)), + E.type_perfect("0", e_type(T.u32)), + E.type_combo("0", e_type(T.u32)), + E.area_id_list(fill(60), e_type(T.u8, count=60)), + E.area_win_list(fill(60), e_type(T.u32, count=60)), + E.area_lose_list(fill(60), e_type(T.u32, count=60)), + E.perfect("0", e_type(T.u32)), + E.great("0", e_type(T.u32)), + E.good("0", e_type(T.u32)), + E.poor("0", e_type(T.u32)), + E.miss("0", e_type(T.u32)), + E.history( + *[ + E.round( + E.defeat_class("0", e_type(T.s8)), + E.rival_type("0", e_type(T.s8)), + E.name("0"), + E.shopname("0"), + E.chara_icon("0", e_type(T.u8)), + E.pref("0", e_type(T.u8)), + E.skill("0", e_type(T.s32)), + E.battle_rate("0", e_type(T.s32)), + E.syogo(fill(2), e_type(T.s16, count=2)), + E.result("0", e_type(T.s8)), + E.seqmode(fill(2), e_type(T.s8, count=2)), + E.score_type(fill(2), e_type(T.s8, count=2)), + E.musicid(fill(2), e_type(T.s32, count=2)), + E.flags(fill(2), e_type(T.u32, count=2)), + E.score_diff(fill(2), e_type(T.s32, count=2)), + E.item(fill(2), e_type(T.s16, count=2)), + E.select_type(fill(2), e_type(T.s8, count=2)), + E.gold_star_hist("0", e_type(T.u8)), + {"before": "0"}, + ) + for _ in range(0, 10) + ], + ), + E.music_hist( + *[ + E.round( + E.point("0", e_type(T.s16)), + E.my_select_musicid("0", e_type(T.s32)), + E.my_select_result("0", e_type(T.s8)), + E.rival_select_musicid("0", e_type(T.s32)), + E.rival_select_result("0", e_type(T.s8)), + {"before": "0"}, + ) + for _ in range(0, 20) + ], + ), + ), + E.battle_aniv( + E.get( + E.category_ver(fill(11), e_type(T.u16, count=11)), + E.category_genre(fill(11), e_type(T.u16, count=11)), + ), + ), + E.info( + E.mode("0", e_type(T.u32)), + E.boss("0", e_type(T.u32)), + E.battle_aniv("0", e_type(T.u32)), + E.free_music("0", e_type(T.u32)), + E.free_chara("0", e_type(T.u32)), + E.event("0", e_type(T.u32)), + E.battle_event("0", e_type(T.u32)), + E.champ("0", e_type(T.u32)), + E.item("0", e_type(T.u32)), + E.quest("0", e_type(T.u32)), + E.campaign("0", e_type(T.u32)), + E.gdp("0", e_type(T.u32)), + E.v7("0", e_type(T.u32)), + ), + E.quest( + E.quest_rank("0", e_type(T.u8)), + E.star("0", e_type(T.u32)), + E.fan("0", e_type(T.u64)), + E.qdata(fill(39), e_type(T.u32, count=39)), + E.test_data(fill(12), e_type(T.u32, count=12)), + ), + E.championship(E.playable(fill(4), e_type(T.s32, count=4))), + E.ranking( + E.skill_rank("0", e_type(T.s32)), + ), + E.rival_id_1("", e_type(T.str, count=1)), + E.rival_id_2("", e_type(T.str, count=1)), + E.rival_id_3("", e_type(T.str, count=1)), + E.standard({"nr": "0"}), + E.finish("1", e_type(T.u8)), + {"no": "1"}, + ) + ) + ) elif req.method == cls.GAMETOP_GET_RIVAL: - pass + response = E.response( + E.gametop( + E.player( + E.pdata( + E.name(account.name), + E.chara(str(account.chara), e_type(T.u8)), + E.skill("0", e_type(T.s32)), + E.syogo(fill(2), e_type(T.s16, count=2)), + E.info_level("0", e_type(T.u8)), + E.bdata( + E.battle_rate("0", e_type(T.s32)), + E.battle_class("0", e_type(T.u8)), + E.point("0", e_type(T.s16)), + E.rensyo("0", e_type(T.u16)), + E.win("0", e_type(T.u32)), + E.lose("0", e_type(T.u32)), + E.draw("0", e_type(T.u32)), + ), + E.quest( + E.quest_rank("0", e_type(T.u8)), + E.star("0", e_type(T.u32)), + E.fan("0", e_type(T.u64)), + E.qdata(fill(13), e_type(T.u32, count=13)), + E.test_data(fill(12), e_type(T.u32, count=12)), + ), + {"rival_id": "0"}, + ), + E.standard({"nr": "0"}), + E.finish("1", e_type(T.u8)), + {"no": "1"}, + ) + ) + ) else: raise Exception( "Not sure how to handle this gametop request. " f'method "{req.method}" is unknown for request: {req}' ) - return request + return response @classmethod def gameend(cls, req: ServiceRequest) -> etree: diff --git a/v8_server/eamuse/utils/xml.py b/v8_server/eamuse/utils/xml.py index 99bca84..c49b64a 100644 --- a/v8_server/eamuse/utils/xml.py +++ b/v8_server/eamuse/utils/xml.py @@ -4,6 +4,10 @@ from typing import Dict, Optional from lxml import etree +def fill(count: int, value: str = "0") -> str: + return " ".join(value for _ in range(0, count)) + + class XMLBinTypes(object): s8 = "s8" u8 = "u8" @@ -15,6 +19,7 @@ class XMLBinTypes(object): u64 = "u64" ip4 = "ip4" time = "time" + str = "str" def e_type(_type, count: Optional[int] = None) -> Dict[str, str]: diff --git a/v8_server/view/index.py b/v8_server/view/index.py index 532e76d..7106c0a 100644 --- a/v8_server/view/index.py +++ b/v8_server/view/index.py @@ -1,12 +1,11 @@ -import random from typing import Dict, Tuple from flask import request -from sqlalchemy.orm.exc import MultipleResultsFound from v8_server import app from v8_server.eamuse.services import ( CardMng, + DLStatus, Facility, Local, Message, @@ -17,8 +16,6 @@ from v8_server.eamuse.services import ( Services, ServiceType, ) -from v8_server.eamuse.utils.xml import get_xml_attrib -from v8_server.model.user import Card, ExtID, Profile, RefID, User FlaskResponse = Tuple[bytes, Dict[str, str]] @@ -111,8 +108,20 @@ def facility_service() -> FlaskResponse: return req.response(response) +@Services.route(ServiceType.DLSTATUS) +def dlstatus_service() -> FlaskResponse: + req = ServiceRequest(request) + + if req.method == DLStatus.PROGRESS: + response = DLStatus.progress() + else: + raise Exception(f"Not sure how to handle this DLStatus Request: {req}") + + return req.response(response) + + @Services.route(ServiceType.CARDMNG) -def cardmng() -> Tuple[bytes, Dict[str, str]]: +def cardmng_service() -> FlaskResponse: req = ServiceRequest(request) if req.method == CardMng.INQUIRE: @@ -147,6 +156,8 @@ def local_service() -> FlaskResponse: response = Local.gameinfo(req) elif req.module == Local.GAMEEND: response = Local.gameend(req) + elif req.module == Local.GAMETOP: + response = Local.gametop(req) else: raise Exception(f"Not sure how to handle this Local Request: {req}") return req.response(response)