XML Template refactor

This commit is contained in:
573dev 2020-11-09 08:51:28 -06:00
parent 1d009a8db1
commit 186fd3c139
33 changed files with 715 additions and 764 deletions

View File

@ -826,13 +826,13 @@ class CardCipher:
out = [0] * 8
CardCipher.__from_int(
out, CardCipher.__operatorA(0x00, CardCipher.__to_int(inp))
out, CardCipher.__operator_a(0x00, CardCipher.__to_int(inp))
)
CardCipher.__from_int(
out, CardCipher.__operatorB(0x20, CardCipher.__to_int(out))
out, CardCipher.__operator_b(0x20, CardCipher.__to_int(out))
)
CardCipher.__from_int(
out, CardCipher.__operatorA(0x40, CardCipher.__to_int(out))
out, CardCipher.__operator_a(0x40, CardCipher.__to_int(out))
)
return bytes(out)
@ -848,35 +848,35 @@ class CardCipher:
out = [0] * 8
CardCipher.__from_int(
out, CardCipher.__operatorB(0x40, CardCipher.__to_int(inp))
out, CardCipher.__operator_b(0x40, CardCipher.__to_int(inp))
)
CardCipher.__from_int(
out, CardCipher.__operatorA(0x20, CardCipher.__to_int(out))
out, CardCipher.__operator_a(0x20, CardCipher.__to_int(out))
)
CardCipher.__from_int(
out, CardCipher.__operatorB(0x00, CardCipher.__to_int(out))
out, CardCipher.__operator_b(0x00, CardCipher.__to_int(out))
)
return bytes(out)
@staticmethod
def __to_int(data: List[int]) -> int:
inX = (
in_x = (
(data[0] & 0xFF)
| ((data[1] & 0xFF) << 8)
| ((data[2] & 0xFF) << 16)
| ((data[3] & 0xFF) << 24)
)
inY = (
in_y = (
(data[4] & 0xFF)
| ((data[5] & 0xFF) << 8)
| ((data[6] & 0xFF) << 16)
| ((data[7] & 0xFF) << 24)
)
v7 = ((((inX ^ (inY >> 4)) & 0xF0F0F0F) << 4) ^ inY) & 0xFFFFFFFF
v8 = (((inX ^ (inY >> 4)) & 0xF0F0F0F) ^ inX) & 0xFFFFFFFF
v7 = ((((in_x ^ (in_y >> 4)) & 0xF0F0F0F) << 4) ^ in_y) & 0xFFFFFFFF
v8 = (((in_x ^ (in_y >> 4)) & 0xF0F0F0F) ^ in_x) & 0xFFFFFFFF
v9 = ((v7 ^ (v8 >> 16))) & 0x0000FFFF
v10 = (((v7 ^ (v8 >> 16)) << 16) ^ v8) & 0xFFFFFFFF
@ -921,20 +921,20 @@ class CardCipher:
v34 = (v32 ^ v30) & 0xFFFFFFFF
v35 = (v33 ^ (v34 >> 4)) & 0xF0F0F0F
outY = ((v35 << 4) ^ v34) & 0xFFFFFFFF
outX = (v35 ^ v33) & 0xFFFFFFFF
out_y = ((v35 << 4) ^ v34) & 0xFFFFFFFF
out_x = (v35 ^ v33) & 0xFFFFFFFF
data[0] = outX & 0xFF
data[1] = (outX >> 8) & 0xFF
data[2] = (outX >> 16) & 0xFF
data[3] = (outX >> 24) & 0xFF
data[4] = outY & 0xFF
data[5] = (outY >> 8) & 0xFF
data[6] = (outY >> 16) & 0xFF
data[7] = (outY >> 24) & 0xFF
data[0] = out_x & 0xFF
data[1] = (out_x >> 8) & 0xFF
data[2] = (out_x >> 16) & 0xFF
data[3] = (out_x >> 24) & 0xFF
data[4] = out_y & 0xFF
data[5] = (out_y >> 8) & 0xFF
data[6] = (out_y >> 16) & 0xFF
data[7] = (out_y >> 24) & 0xFF
@staticmethod
def __operatorA(off: int, state: int) -> int:
def __operator_a(off: int, state: int) -> int:
v3 = (state >> 32) & 0xFFFFFFFF
v4 = state & 0xFFFFFFFF
@ -968,7 +968,7 @@ class CardCipher:
return ((v3 & 0xFFFFFFFF) << 32) | (v4 & 0xFFFFFFFF)
@staticmethod
def __operatorB(off: int, state: int) -> int:
def __operator_b(off: int, state: int) -> int:
v3 = (state >> 32) & 0xFFFFFFFF
v4 = state & 0xFFFFFFFF

View File

@ -1,10 +1,8 @@
from typing import Any, Dict, List, Optional
from v8_server import db
from v8_server.eamuse.services.services import ServiceRequest
from v8_server.eamuse.xml.utils import (
drop_attributes,
get_xml_attrib,
load_xml_template,
)
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
from v8_server.model.user import Card, Profile, RefID, User, UserAccount
from v8_server.utils.convert import bool_to_int as btoi
@ -53,19 +51,25 @@ class CardMng(object):
# Grab the card id
cardid = get_xml_attrib(req.xml[0], "cardid")
# Default result for a new unregistered user
args = {
"refid": "",
# New unregistered user
args: Dict[str, Any] = {
"newflag": 1,
"binded": 0,
"status": CardStatus.NOT_REGISTERED,
}
# Check if a user with this card id already exists
user = User.from_cardid(cardid)
drop_attributes: Optional[Dict[str, List[str]]] = {
"cardmng": [
"refid",
"dataid",
"expired",
"exflag",
"useridflag",
"extidflag",
]
}
# We have a returning user
if user is not None:
if (user := User.from_cardid(cardid)) is not None:
refid = RefID.from_userid(user.userid)
bound = UserAccount.from_userid(user.userid) is not None
@ -73,22 +77,17 @@ class CardMng(object):
# TODO: better exception?
raise Exception("RefID Should not be None here!")
args["refid"] = refid.refid
args["newflag"] = 0
args["binded"] = btoi(bound)
args["status"] = CardStatus.SUCCESS
args = {
"refid": refid.refid,
"newflag": 0,
"binded": btoi(bound),
"status": CardStatus.SUCCESS,
}
drop_attributes = None
result = load_xml_template("cardmng", "inquire", args)
# If we have a brand new user, we can remove unnecessary xml attributes from the
# cardmng node
if user is None:
drop_attributes(
result.find("cardmng"),
["refid", "dataid", "expired", "exflag", "useridflag", "extidflag"],
)
return result
return load_xml_template(
"cardmng", "inquire", args, drop_attributes=drop_attributes
)
@classmethod
def getrefid(cls, req: ServiceRequest):

View File

@ -1,4 +1,4 @@
from lxml.builder import E
from v8_server.eamuse.xml.utils import load_xml_template
class DLStatus(object):
@ -6,10 +6,6 @@ class DLStatus(object):
Handle the DLStatus request.
It is unknown as to what this does.
Example:
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
</call>
"""
# Methods
@ -17,10 +13,4 @@ class DLStatus(object):
@classmethod
def progress(cls):
"""
Example:
<response>
<dlstatus expire="600"/>
</response>
"""
return E.response(E.dlstatus({"expire": "600"}))
return load_xml_template("dlstatus", "progress")

View File

@ -1,6 +1,4 @@
from lxml.builder import E
from v8_server.eamuse.xml.utils import XMLBinTypes as T, e_type
from v8_server.eamuse.xml.utils import load_xml_template
class Facility(object):
@ -22,92 +20,13 @@ class Facility(object):
@classmethod
def get(cls):
"""
Example:
<response>
<facility expire="600">
<location>
<id>US-123</id>
<country>US</country>
<region>.</region>
<name>H</name>
<type __type="u8">0</type>
</location>
<line>
<id>.</id>
<class __type="u8">0</class>
</line>
<portfw>
<globalip __type="ip4" __count="1">127.0.0.1</globalip>
<globalport __type="u16">80</globalport>
<privateport __type="u16">80</privateport>
</portfw>
<public>
<flag __type="u8">1</flag>
<name>.</name>
<latitude>0</latitude>
<longitude>0</longitude>
</public>
<share>
<eacoin>
<notchamount __type="s32">3000</notchamount>
<notchcount __type="s32">3</notchcount>
<supplylimit __type="s32">10000</supplylimit>
</eacoin>
<eapass>
<valid __type="u16">365</valid>
</eapass>
<url>
<eapass>www.ea-pass.konami.net</eapass>
<arcadefan>www.konami.jp/am</arcadefan>
<konaminetdx>http://am.573.jp</konaminetdx>
<konamiid>http://id.konami.net</konamiid>
<eagate>http://eagate.573.jp</eagate>
</url>
</share>
</facility>
</response>
"""
# TODO: The facility data should be read in from a config file instead of being
# hard coded here
return E.response(
E.facility(
E.location(
E.id("CA-123"),
E.country("CA"),
E.region("MB"),
E.name("SenPi Arcade"),
E.type("0", e_type(T.u8)),
),
E.line(E.id("."), E("class", "0", e_type(T.u8))),
E.portfw(
E.globalip("127.0.0.1", e_type(T.ip4, count=1)),
E.globalport("80", e_type(T.u16)),
E.privateport("80", e_type(T.u16)),
),
E.public(
E.flag("1", e_type(T.u8)),
E.name("Gotem"),
E.latitude("0"),
E.longitude("0"),
),
E.share(
E.eacoin(
E.notchamount("3000", e_type(T.s32)),
E.notchcount("3", e_type(T.s32)),
E.supplylimit("10000", e_type(T.s32)),
),
E.eapass(E.valid("365", e_type(T.u16))),
E.url(
E.eapass("www.ea-pass.konami.net"),
E.arcadefan("www.konami.jp/am"),
E.konaminetdx("http://am.573.jp"),
E.konamiid("http://id.konami.net"),
E.eagate("http://eagate.573.jp"),
),
),
{"expire": "600"},
)
)
args = {
"id": "CA-123",
"country": "CA",
"region": "MB",
"name": "SenPi Arcade",
}
return load_xml_template("facility", "get", args)

View File

@ -1,13 +1,13 @@
import logging
from datetime import datetime
from typing import Any, Dict, List, Optional
from lxml import etree
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.xml.utils import XMLBinTypes as T, e_type, fill, get_xml_attrib
from v8_server.eamuse.xml.utils import fill, get_xml_attrib, load_xml_template
from v8_server.model.song import HitChart
from v8_server.model.user import User, UserAccount
@ -39,9 +39,6 @@ class Local(object):
GAMEEND = "gameend"
GAMEEND_REGIST = "regist"
GAMEINFO = "gameinfo"
GAMEINFO_GET = "get"
GAMETOP = "gametop"
GAMETOP_GET = "get"
GAMETOP_GET_RIVAL = "get_rival"
@ -58,7 +55,7 @@ class Local(object):
@classmethod
def customize(cls, req: ServiceRequest) -> etree:
if req.method == cls.CUSTOMIZE_REGIST:
response = E.response(E.customize(E.player({"no": "1", "state": "2"})))
response = load_xml_template("customize", "regist")
else:
raise Exception(
"Not sure how to handle this customize request. "
@ -69,76 +66,8 @@ class Local(object):
@classmethod
def shopinfo(cls, req: ServiceRequest) -> etree:
"""
Handle the shopinfo request
Example Request:
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
<shopinfo method="regist">
<shop>
<name __type="str"></name>
<pref __type="s8">31</pref>
<systemid __type="str">00010203040506070809</systemid>
<softwareid __type="str">012112345679</softwareid>
<hardwareid __type="str">010074D435AAD895</hardwareid>
<locationid __type="str">CA-123</locationid>
<testmode send="1">
<sound_options>
<volume_bgm __type="u8">20</volume_bgm>
<volume_se_myself __type="u8">20</volume_se_myself>
</sound_options>
<game_options>
<stand_alone>
<difficulty_standard __type="u8">
3
</difficulty_standard>
<max_stage_standard __type="u8">
3
</max_stage_standard>
<long_music __type="u8">3</long_music>
</stand_alone>
<session>
<game_joining_period __type="u8">
15
</game_joining_period>
</session>
<game_settings>
<is_shop_close_on __type="u8">0</is_shop_close_on>
</game_settings>
</game_options>
<coin_options>
<coin_slot __type="u8">8</coin_slot>
</coin_options>
<bookkeeping>
<enable __type="u8">0</enable>
</bookkeeping>
</testmode>
</shop>
</shopinfo>
</call>
Example Response:
<response>
<shopinfo>
<data>
<cabid __type="u32">1</cabid>
<locationid>nowhere</locationid>
<is_send __type="u8">1</is_send>
</data>
</shopinfo>
</response>
"""
if req.method == cls.SHOPINFO_REGIST:
response = E.response(
E.shopinfo(
E.data(
E.cabid("1", e_type(T.u32)),
E.locationid("nowhere"),
E.is_send("1", e_type(T.u8)),
)
)
)
response = load_xml_template("shopinfo", "regist")
else:
raise Exception(
"Not sure how to handle this shopinfo request. "
@ -149,63 +78,31 @@ class Local(object):
@classmethod
def demodata(cls, req: ServiceRequest) -> etree:
"""
Handle the demodata request.
Potentially this is just some initial demo data for initial boot/factory reset
After this data, the game might keep track of all this stuff itself.
# Example Request:
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
<demodata method="get">
<shop>
<locationid __type="str">CA-123</locationid>
</shop>
<hitchart_nr __type="u16">100</hitchart_nr>
</demodata>
</call>
# Example Response:
<response>
<demodata expire="600"/>
</response>
"""
dtfmt = "%Y-%m-%d %H:%M:%S%z"
if req.method == cls.DEMODATA_GET:
hitchart_number = int(req.xml[0].find("hitchart_nr").text)
rank_data = HitChart.get_ranking(hitchart_number)
rank_items = HitChart.get_ranking(hitchart_number)
response = E.response(
E.demodata(
E.mode("0", e_type(T.u8)), # Unknown what mode we need
E.hitchart(
E.start(datetime.now().strftime(dtfmt)),
E.end(datetime.now().strftime(dtfmt)),
*[
E.data(
E.musicid(str(x), e_type(T.s32)),
E.last1("0", e_type(T.s32)),
)
for x in rank_data
],
{"nr": str(hitchart_number)},
),
E.bossdata( # No idea what this stuff means
E.division("14", e_type(T.u8)), # Shows up as "Extra Lv X"
E.border("0 0 0 0 0 0 0 0 0", e_type(T.u8, count=9)),
E.extra_border("90", e_type(T.u8)),
E.bsc_encore_border("92", e_type(T.u8)),
E.adv_encore_border("93", e_type(T.u8)),
E.ext_encore_border("94", e_type(T.u8)),
E.bsc_premium_border("95", e_type(T.u8)),
E.adv_premium_border("95", e_type(T.u8)),
E.ext_premium_border("95", e_type(T.u8)),
),
E.info(E.message("SenPi's Kickass Machine")),
E.assert_report_state("0", e_type(T.u8)),
)
)
# Generate all hitchart data xml
hitchart_xml_str = ""
for rank_item in rank_items:
hitchart_xml_str += etree.tostring(
load_xml_template(
"demodata", "get.data", {"musicid": rank_item, "last1": 0}
)
).decode("UTF-8")
args = {
"hitchart_nr": hitchart_number,
"start": datetime.now().strftime(dtfmt),
"end": datetime.now().strftime(dtfmt),
"hitchart_data": hitchart_xml_str,
"division": 14,
"message": "SenPi's Kickass DrumMania V8 Machine",
}
response = load_xml_template("demodata", "get", args)
else:
raise Exception(
"Not sure how to handle this demodata request. "
@ -216,59 +113,41 @@ class Local(object):
@classmethod
def cardutil(cls, req: ServiceRequest) -> etree:
"""
Handle the Cardutil request.
# Example Request:
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
<cardutil method="check">
<card no="1">
<refid __type="str">ADE0FE0B14AEAEFC</refid>
<uid __type="str">E0040100DE52896C</uid>
</card>
</cardutil>
</call>
# Example Response:
<response>
<cardutil>
<card no="1" state="0">
<kind __type="s8">0</kind>
</card>
</cardutil>
</response>
"""
# TODO: Figure out what this thing actually needs to send back
if req.method == cls.CARDUTIL_CHECK:
refid = req.xml[0].find("card/refid").text
user = User.from_refid(refid)
if (
new_user = (
user is None
or (account := UserAccount.from_userid(user.userid)) is None
):
response = E.response(
E.cardutil(
E.card(E.kind("0", e_type(T.s8)), {"no": "1", "state": "0"})
)
)
else:
response = E.response(
E.cardutil(
E.card(
E.kind("0", e_type(T.s8)),
E.name(account.name),
E.gdp("0", e_type(T.u32)),
E.skill("0", e_type(T.s32)),
E.all_skill("0", e_type(T.s32)),
E.chara(str(account.chara), e_type(T.u8)),
E.syogo(fill(2), e_type(T.s16, count=2)),
E.penalty("0", e_type(T.u8)),
{"no": "1", "state": "2"},
)
)
)
)
# New User
args: Dict[str, Any] = {"state": 0}
drop_children: Optional[Dict[str, List[str]]] = {
"cardutil/card": [
"name",
"gdp",
"skill",
"all_skill",
"chara",
"syogo",
"penalty",
],
}
# Existing User
if not new_user and account is not None:
args = {
"state": 2,
"name": account.name,
"chara": account.chara,
}
drop_children = None
response = load_xml_template(
"cardutil", "check", args, drop_children=drop_children
)
elif req.method == cls.CARDUTIL_REGIST:
root = req.xml[0].find("data")
refid = root.find("refid").text
@ -292,7 +171,7 @@ class Local(object):
db.session.add(user_account)
db.session.commit()
response = E.response(E.cardutil())
response = load_xml_template("cardutil", "regist")
else:
raise Exception(
"Not sure how to handle this cardutil request. "
@ -303,67 +182,16 @@ class Local(object):
@classmethod
def gameinfo(cls, req: ServiceRequest) -> etree:
"""
Handle a Gameinfo request.
Currently unsure how to handle this, so we just return a dummy object.
# Example Request:
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
<gameinfo method="get">
<shop>
<locationid __type="str">US-123</locationid>
<cabid __type="u32">1</cabid>
</shop>
</gameinfo>
</call>
Example Response:
<response>
<gameinfo expire="600"/>
</response>
"""
if req.method == cls.GAMEINFO_GET:
response = E.response(
E.gameinfo(
E.mode("0", e_type(T.u8)),
E.free_music("262143", e_type(T.u32)),
E.key(E.musicid("-1", e_type(T.s32))),
E.limit_gdp("40000", e_type(T.u32)),
E.free_chara("1824", e_type(T.u32)),
E.tag(str(calculate_crc8(str(262143 + 1824))), e_type(T.u8)),
E.bossdata(
E.division("14", e_type(T.u8)), # Shows up as "Extra Lv X"
E.border("0 0 0 0 0 0 0 0 0", e_type(T.u8, count=9)),
E.extra_border("90", e_type(T.u8)),
E.bsc_encore_border("92", e_type(T.u8)),
E.adv_encore_border("93", e_type(T.u8)),
E.ext_encore_border("94", e_type(T.u8)),
E.bsc_premium_border("95", e_type(T.u8)),
E.adv_premium_border("95", e_type(T.u8)),
E.ext_premium_border("95", e_type(T.u8)),
),
E.battledata(
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(fill(26), e_type(T.u32, count=26)),
*[
E(f"play_{x}", fill(32), e_type(T.u32, count=32))
for x in range(0, 13)
],
*[
E(f"clear_{x}", fill(32), e_type(T.u32, count=32))
for x in range(0, 13)
],
),
E.campaign(E.campaign("0", e_type(T.u8))),
)
)
# tag is the crc8 checksum of free_music and free_chara
# I also don't actually know what these free_music/chara values mean
args = {
"free_music": 262143,
"free_chara": 1824,
"tag": calculate_crc8(str(262143 + 1824)),
"division": 14,
}
response = load_xml_template("gameinfo", "get", args)
else:
raise Exception(
"Not sure how to handle this gameinfo request. "
@ -374,213 +202,39 @@ 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:
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"},
)
)
# Generate history rounds (blank for now)
history_rounds = ""
for _ in range(0, 10):
history_rounds += etree.tostring(
load_xml_template("gametop", "get.history.round")
).decode("UTF-8")
music_hist_rounds = ""
for _ in range(0, 20):
music_hist_rounds += etree.tostring(
load_xml_template("gametop", "get.music_hist.round")
).decode("UTF-8")
secret_music = fill(32)
secret_chara = 0
tag = calculate_crc8(
str(sum(int(x) for x in secret_music.split()) + secret_chara)
)
args = {
"secret_music": secret_music,
"style": 2097152,
"secret_chara": secret_chara,
"tag": tag,
"history_rounds": history_rounds,
"music_hist_rounds": music_hist_rounds,
}
response = load_xml_template("gametop", "get", args)
elif req.method == cls.GAMETOP_GET_RIVAL:
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"},
)
)
response = load_xml_template(
"gametop", "get_rival", {"name": "name", "chara": 0}
)
else:
raise Exception(
@ -611,126 +265,34 @@ class Local(object):
db.session.commit()
# Just send back a dummy object for now
gamemode = get_xml_attrib(req.xml[0].find("gamemode"), "game_mode")
gamemode = get_xml_attrib(req.xml[0].find("gamemode"), "mode")
card = get_xml_attrib(req.xml[0].find("player"), "card")
no = get_xml_attrib(req.xml[0].find("player"), "no")
response = E.response(
E.gameend(
E.gamemode({"mode": gamemode}),
E.player(
E.skill(
E.point("0", e_type(T.s32)),
E.rank("1", e_type(T.u32)),
E.total_nr("1", e_type(T.u32)),
E.all_point("0", e_type(T.s32)),
E.all_rank("1", e_type(T.u32)),
E.all_total_nr("1", e_type(T.u32)),
),
E.registered_other_num("0", e_type(T.u32)),
E.xg_play_cnt("0", e_type(T.u32)),
E.play_cnt("0", e_type(T.u32)),
E.sess_cnt("0", e_type(T.u32)),
E.encore_play("0", e_type(T.u32)),
E.premium_play("0", e_type(T.u32)),
E.now_time(datetime.now().strftime(dtfmt)),
E.kikan_event("0", e_type(T.u32)),
E.vip_rensyo("0", e_type(T.u16)),
E.all_play_mode("0", e_type(T.u8)),
E.play_shop_num("0", e_type(T.u8)),
E.judge_perfect("0", e_type(T.u32)),
E.is_v5_goodplayer("0", e_type(T.u8)),
E.max_clear_difficulty("0", e_type(T.s8)),
E.max_fullcombo_difficulty("0", e_type(T.s8)),
E.max_excellent_difficulty("0", e_type(T.s8)),
E.rival_data(),
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.type_normal("0", e_type(T.u32)),
E.type_perfect("0", e_type(T.u32)),
E.type_combo("0", e_type(T.u32)),
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.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.area_draw_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.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.championship(E.playable(fill(4), e_type(T.s32, count=4))),
{"card": card, "no": no},
),
)
)
now_time = datetime.now().strftime(dtfmt)
# Generate history rounds (blank for now)
history_rounds = ""
for _ in range(0, 10):
history_rounds += etree.tostring(
load_xml_template("gameend", "regist.history.round")
).decode("UTF-8")
music_hist_rounds = ""
for _ in range(0, 20):
music_hist_rounds += etree.tostring(
load_xml_template("gameend", "regist.music_hist.round")
).decode("UTF-8")
args = {
"gamemode": gamemode,
"player_card": card,
"player_no": no,
"now_time": now_time,
"history_rounds": history_rounds,
"music_hist_rounds": music_hist_rounds,
}
response = load_xml_template("gameend", "regist", args)
else:
raise Exception(
"Not sure how to handle this gameend request. "

View File

@ -1,4 +1,4 @@
from lxml.builder import E
from v8_server.eamuse.xml.utils import load_xml_template
class Message(object):
@ -18,10 +18,4 @@ class Message(object):
@classmethod
def get(cls):
"""
Example:
<response>
<message expire="600"/>
</response>
"""
return E.response(E.message({"expire": "600"}))
return load_xml_template("message", "get")

View File

@ -1,7 +1,4 @@
from lxml.builder import E
from v8_server.eamuse.services.services import ServiceRequest
from v8_server.eamuse.xml.utils import get_xml_attrib
from v8_server.eamuse.xml.utils import load_xml_template
class Package(object):
@ -19,26 +16,6 @@ class Package(object):
# Methods
LIST = "list"
# PKGTypes
PKGTYPE_ALL = "all"
@classmethod
def list(cls, req: ServiceRequest):
"""
Example:
<response>
<package expire="600"/>
</response>
"""
# Grab the pkgtype in case we ever need it
pkgtype = get_xml_attrib(req.xml[0], "pkgtype")
if pkgtype == cls.PKGTYPE_ALL:
response = E.response(E.package({"expire": "600"}))
else:
raise Exception(
"Not sure how to handle this package request. "
f'pkgtype "{pkgtype}" is unknown for request: {req}'
)
return response
def list(cls):
return load_xml_template("package", "list")

View File

@ -2,9 +2,9 @@ import logging
from datetime import datetime
from lxml import etree
from lxml.builder import E
from v8_server.eamuse.services.services import ServiceRequest
from v8_server.eamuse.xml.utils import load_xml_template
logger = logging.getLogger(__name__)
@ -95,7 +95,7 @@ class PCBEvent(object):
event = PCBEvent(req)
logger.info(event)
return E.response(E.pcbevent({"expire": "600"}))
return load_xml_template("pcbevent", "put")
def __repr__(self) -> str:
return (

View File

@ -1,4 +1,5 @@
from lxml.builder import E
from v8_server.eamuse.xml.utils import load_xml_template
from v8_server.utils.convert import bool_to_int as btoi
class PCBTracker(object):
@ -22,17 +23,6 @@ class PCBTracker(object):
@classmethod
def alive(cls):
"""
Example (if Paseli is not active):
<response>
<pcbtracker ecenable="0"/>
</response>
Potentially if Paseli is active, the response might look like so:
<response>
<pcbtracker time="" limit="" ecenable="1" eclimit=""/>
</response>
I am unsure what the `time`, `limit`, and `eclimit` responses would be.
"""
return E.response(E.pcbtracker({"ecenable": "1" if cls.PASELI_ACTIVE else "0"}))
return load_xml_template(
"pcbtracker", "alive", {"ecenable": btoi(cls.PASELI_ACTIVE)}
)

View File

@ -119,6 +119,9 @@ class ServiceRequest(object):
# Log dir for the requests
LOG_DIR = LOG_PATH / "requests"
# Static Request ID
REQUEST_ID = 0
def __init__(self, request: Request) -> None:
# Save the request so we can refer back to it
self._request = request
@ -211,6 +214,9 @@ class ServiceRequest(object):
rlogger.debug(f"Response:\n{xml_bytes.decode(self.ENCODING)}")
# Update the Static Request ID
ServiceRequest.REQUEST_ID += 1
return xml_bin, headers
def _get_encryption_data(self) -> Tuple[str, bytes]:
@ -233,7 +239,10 @@ class ServiceRequest(object):
# Write out the data
date = datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
filepath = self.LOG_DIR / f"eamuse_{date}_{uid}_{kind}.xml"
filepath = (
self.LOG_DIR
/ f"eamuse_{date}_{uid}_{ServiceRequest.REQUEST_ID:04d}_{kind}.xml"
)
with filepath.open("wb") as f:
logging.debug(f"Writing File: {filepath}")
f.write(data)

View File

@ -0,0 +1,14 @@
<response>
<cardutil>
<card no="1" state="{state}">
<kind __type="s8">0</kind>
<name __type="str">{name}</name>
<gdp __type="u32">0</gdp>
<skill __type="s32">0</skill>
<all_skill __type="s32">0</all_skill>
<chara __type="u8">{chara}</chara>
<syogo __type="s16" __count="2">0 0</syogo>
<penalty __type="u8">0</penalty>
</card>
</cardutil>
</response>

View File

@ -0,0 +1,3 @@
<response>
<cardutil/>
</response>

View File

@ -0,0 +1,5 @@
<response>
<customize>
<player no="1" state="2"/>
</customize>
</response>

View File

@ -0,0 +1,4 @@
<data>
<musicid __type="s32">{musicid}</musicid>
<last1 __type="s32">{last1}</last1>
</data>

View File

@ -0,0 +1,25 @@
<response>
<demodata>
<mode __type="u8">0</mode>
<hitchart nr="{hitchart_nr}">
<start __type="str">{start}</start>
<end __type="str">{end}</end>
{hitchart_data}
</hitchart>
<bossdata>
<division __type="u8">{division}</division>
<border __type="u8" __count="9">0 0 0 0 0 0 0 0 0</border>
<extra_border __type="u8">90</extra_border>
<bsc_encore_border __type="u8">92</bsc_encore_border>
<adv_encore_border __type="u8">93</adv_encore_border>
<ext_encore_border __type="u8">94</ext_encore_border>
<bsc_premium_border __type="u8">95</bsc_premium_border>
<adv_premium_border __type="u8">95</adv_premium_border>
<ext_premium_border __type="u8">95</ext_premium_border>
</bossdata>
<info>
<message __type="str">{message}</message>
</info>
<assert_report_state __type="u8">0</assert_report_state>
</demodata>
</response>

View File

@ -0,0 +1,3 @@
<response>
<dlstatus/>
</response>

View File

@ -0,0 +1,43 @@
<response>
<facility expire="600">
<location>
<id>{id}</id>
<country>{country}</country>
<region>{region}</region>
<name>{name}</name>
<type __type="u8">0</type>
</location>
<line>
<id>.</id>
<class __type="u8">0</class>
</line>
<portfw>
<globalip __type="ip4" __count="1">127.0.0.1</globalip>
<globalport __type="u16">80</globalport>
<privateport __type="u16">80</privateport>
</portfw>
<public>
<flag __type="u8">1</flag>
<name>{name}</name>
<latitude>0</latitude>
<longitude>0</longitude>
</public>
<share>
<eacoin>
<notchamount __type="s32">3000</notchamount>
<notchcount __type="s32">3</notchcount>
<supplylimit __type="s32">10000</supplylimit>
</eacoin>
<eapass>
<valid __type="u16">365</valid>
</eapass>
<url>
<eapass>www.ea-pass.konami.net</eapass>
<arcadefan>www.konami.jp/am</arcadefan>
<konaminetdx>http://am.573.jp</konaminetdx>
<konamiid>http://id.konami.net</konamiid>
<eagate>http://eagate.573.jp</eagate>
</url>
</share>
</facility>
</response>

View File

@ -0,0 +1,20 @@
<round before="0">
<defeat_class __type="s8">0</defeat_class>
<rival_type __type="s8">0</rival_type>
<name __type="str">0</name>
<shopname __type="str">0</shopname>
<chara_icon __type="u8">0</chara_icon>
<pref __type="u8">0</pref>
<skill __type="s32">0</skill>
<battle_rate __type="s32">0</battle_rate>
<syogo __type="s16" __count="2">0 0</syogo>
<result __type="s8">0</result>
<seqmode __type="s8" __count="2">0 0</seqmode>
<score_type __type="s8" __count="2">0 0</score_type>
<musicid __type="s32" __count="2">0 0</musicid>
<flags __type="u32" __count="2">0 0</flags>
<score_diff __type="s32" __count="2">0 0</score_diff>
<item __type="s16" __count="2">0 0</item>
<select_type __type="s8" __count="2">0 0</select_type>
<gold_star_hist __type="u8">0</gold_star_hist>
</round>

View File

@ -0,0 +1,7 @@
<round before="0">
<point __type="s16">0</point>
<my_select_musicid __type="s32">0</my_select_musicid>
<my_select_result __type="s8">0</my_select_result>
<rival_select_musicid __type="s32">0</rival_select_musicid>
<rival_select_result __type="s8">0</rival_select_result>
</round>

View File

@ -0,0 +1,85 @@
<response>
<gameend>
<gamemode mode="{gamemode}"/>
<player card="{player_card}" no="{player_no}">
<skill>
<point __type="s32">0</point>
<rank __type="u32">1</rank>
<total_nr __type="u32">1</total_nr>
<all_point __type="s32">0</all_point>
<all_rank __type="u32">1</all_rank>
<all_total_nr __type="u32">1</all_total_nr>
</skill>
<registered_other_num __type="u32">0</registered_other_num>
<xg_play_cnt __type="u32">0</xg_play_cnt>
<play_cnt __type="u32">0</play_cnt>
<sess_cnt __type="u32">0</sess_cnt>
<encore_play __type="u32">0</encore_play>
<premium_play __type="u32">0</premium_play>
<now_time>{now_time}</now_time>
<kikan_event __type="u32">0</kikan_event>
<vip_rensyo __type="u16">0</vip_rensyo>
<all_play_mode __type="u8">0</all_play_mode>
<play_shop_num __type="u8">0</play_shop_num>
<judge_perfect __type="u32">0</judge_perfect>
<is_v5_goodplayer __type="u8">0</is_v5_goodplayer>
<max_clear_difficulty __type="s8">0</max_clear_difficulty>
<max_fullcombo_difficulty __type="s8">0</max_fullcombo_difficulty>
<max_excellent_difficulty __type="s8">0</max_excellent_difficulty>
<rival_data/>
<battledata>
<bp __type="u32">0</bp>
<battle_rate __type="s32">0</battle_rate>
<battle_class __type="u8">0</battle_class>
<point __type="s16">0</point>
<rensyo __type="u16">0</rensyo>
<win __type="u32">0</win>
<lose __type="u32">0</lose>
<score_type __type="u8">0</score_type>
<strategy_item __type="s16">0</strategy_item>
<production_item __type="s16">0</production_item>
<draw __type="u32">0</draw>
<max_class __type="u8">0</max_class>
<max_rensyo __type="u16">0</max_rensyo>
<vip_rensyo __type="u16">0</vip_rensyo>
<max_defeat_skill __type="s32">0</max_defeat_skill>
<max_defeat_battle_rate __type="s32">0</max_defeat_battle_rate>
<gold_star __type="u32">0</gold_star>
<random_select __type="u32">0</random_select>
<type_normal __type="u32">0</type_normal>
<type_perfect __type="u32">0</type_perfect>
<type_combo __type="u32">0</type_combo>
<battle_aniv>
<get>
<category_ver __type="u16" __count="11">0 0 0 0 0 0 0 0 0 0 0</category_ver>
<category_genre __type="u16" __count="11">0 0 0 0 0 0 0 0 0 0 0</category_genre>
</get>
</battle_aniv>
<area_id_list __type="u8" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_id_list>
<area_win_list __type="u32" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_win_list>
<area_lose_list __type="u32" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_lose_list>
<area_draw_list __type="u32" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_draw_list>
<perfect __type="u32">0</perfect>
<great __type="u32">0</great>
<good __type="u32">0</good>
<poor __type="u32">0</poor>
<miss __type="u32">0</miss>
<history>
{history_rounds}
</history>
<music_hist>
{music_hist_rounds}
</music_hist>
</battledata>
<quest>
<quest_rank __type="u8">0</quest_rank>
<star __type="u32">0</star>
<fan __type="u64">0</fan>
<qdata __type="u32" __count="39">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</qdata>
</quest>
<championship>
<playable __type="s32" __count="4">0 0 0 0</playable>
</championship>
</player>
</gameend>
</response>

View File

@ -0,0 +1,62 @@
<response>
<gameinfo>
<mode __type="u8">0</mode>
<free_music __type="u32">{free_music}</free_music>
<key>
<musicid __type="s32">-1</musicid>
</key>
<limit_gdp __type="u32">40000</limit_gdp>
<free_chara __type="u32">{free_chara}</free_chara>
<tag __type="u8">{tag}</tag>
<bossdata>
<division __type="u8">{division}</division>
<border __type="u8" __count="9">0 0 0 0 0 0 0 0 0</border>
<extra_border __type="u8">90</extra_border>
<bsc_encore_border __type="u8">92</bsc_encore_border>
<adv_encore_border __type="u8">93</adv_encore_border>
<ext_encore_border __type="u8">94</ext_encore_border>
<bsc_premium_border __type="u8">95</bsc_premium_border>
<adv_premium_border __type="u8">95</adv_premium_border>
<ext_premium_border __type="u8">95</ext_premium_border>
</bossdata>
<battledata>
<battle_music_level __type="u8" __count="13">0 0 0 0 0 0 0 0 0 0 0 0 0</battle_music_level>
<standard_skill __type="s32" __count="13">0 0 0 0 0 0 0 0 0 0 0 0 0</standard_skill>
<border_skill __type="s32" __count="13">0 0 0 0 0 0 0 0 0 0 0 0 0</border_skill>
</battledata>
<quest>
<division __type="u8">0</division>
<border __type="u8">0</border>
<qdata __type="u32" __count="26">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</qdata>
<play_0 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_0>
<play_1 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_1>
<play_2 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_2>
<play_3 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_3>
<play_4 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_4>
<play_5 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_5>
<play_6 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_6>
<play_7 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_7>
<play_8 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_8>
<play_9 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_9>
<play_10 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_10>
<play_11 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_11>
<play_12 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</play_12>
<clear_0 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_0>
<clear_1 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_1>
<clear_2 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_2>
<clear_3 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_3>
<clear_4 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_4>
<clear_5 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_5>
<clear_6 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_6>
<clear_7 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_7>
<clear_8 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_8>
<clear_9 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_9>
<clear_10 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_10>
<clear_11 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_11>
<clear_12 __type="u32" __count="32">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</clear_12>
</quest>
<campaign>
<campaign __type="u8">0</campaign>
</campaign>
</gameinfo>
</response>

View File

@ -0,0 +1,20 @@
<round before="0">
<defeat_class __type="s8">0</defeat_class>
<rival_type __type="s8">0</rival_type>
<name __type="str">0</name>
<shopname __type="str">0</shopname>
<chara_icon __type="u8">0</chara_icon>
<pref __type="u8">0</pref>
<skill __type="s32">0</skill>
<battle_rate __type="s32">0</battle_rate>
<syogo __type="s16" __count="2">0 0</syogo>
<result __type="s8">0</result>
<seqmode __type="s8" __count="2">0 0</seqmode>
<score_type __type="s8" __count="2">0 0</score_type>
<musicid __type="s32" __count="2">0 0</musicid>
<flags __type="u32" __count="2">0 0</flags>
<score_diff __type="s32" __count="2">0 0</score_diff>
<item __type="s16" __count="2">0 0</item>
<select_type __type="s8" __count="2">0 0</select_type>
<gold_star_hist __type="u8">0</gold_star_hist>
</round>

View File

@ -0,0 +1,7 @@
<round before="0">
<point __type="s16">0</point>
<my_select_musicid __type="s32">0</my_select_musicid>
<my_select_result __type="s8">0</my_select_result>
<rival_select_musicid __type="s32">0</rival_select_musicid>
<rival_select_result __type="s8">0</rival_select_result>
</round>

View File

@ -0,0 +1,127 @@
<response>
<gametop>
<player no="1">
<player_type __type="u8">0</player_type>
<my_rival_id __type="str">0</my_rival_id>
<mode __type="u8">0</mode>
<syogo_list __type="s16" __count="200">-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1</syogo_list>
<badge_list __type="s16" __count="200">-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1</badge_list>
<favorite_music __type="s16" __count="20">-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1</favorite_music>
<favorite_music_2 __type="s16" __count="20">-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1</favorite_music_2>
<favorite_music_3 __type="s16" __count="20">-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1</favorite_music_3>
<secret_music __type="u16" __count="32">{secret_music}</secret_music>
<style __type="u32">{style}</style>
<style_2 __type="u32">0</style_2>
<shutter_list __type="u32">0</shutter_list>
<judge_logo_list __type="u32">0</judge_logo_list>
<skin_list __type="u32">0</skin_list>
<movie_list __type="u32">0</movie_list>
<attack_effect_list __type="u32">0</attack_effect_list>
<idle_screen __type="u32">0</idle_screen>
<chance_point __type="s32">0</chance_point>
<failed_cnt __type="s32">0</failed_cnt>
<secret_chara __type="u32">{secret_chara}</secret_chara>
<mode_beginner __type="u16">0</mode_beginner>
<mode_standard __type="u16">0</mode_standard>
<mode_battle_global __type="u16">0</mode_battle_global>
<mode_battle_local __type="u16">0</mode_battle_local>
<mode_quest __type="u16">0</mode_quest>
<v3_skill __type="s32">-1</v3_skill>
<v4_skill __type="s32">-1</v4_skill>
<old_ver_skill __type="s32">-1</old_ver_skill>
<customize>
<shutter __type="u8">0</shutter>
<info_level __type="u8">0</info_level>
<name_disp __type="u8">0</name_disp>
<auto __type="u8">0</auto>
<random __type="u8">0</random>
<judge_logo __type="u32">0</judge_logo>
<skin __type="u32">0</skin>
<movie __type="u32">0</movie>
<attack_effect __type="u32">0</attack_effect>
<layout __type="u8">0</layout>
<target_skill __type="u8">0</target_skill>
<comparison __type="u8">0</comparison>
<meter_custom __type="u8" __count="3">0 0 0</meter_custom>
</customize>
<tag __type="u8">{tag}</tag>
<battledata>
<bp __type="u32">0</bp>
<battle_rate __type="s32">0</battle_rate>
<battle_class __type="u8">0</battle_class>
<point __type="s16">0</point>
<rensyo __type="u16">0</rensyo>
<win __type="u32">0</win>
<lose __type="u32">0</lose>
<score_type __type="u8">0</score_type>
<strategy_item __type="s16">0</strategy_item>
<production_item __type="s16">0</production_item>
<draw __type="u32">0</draw>
<max_class __type="u8">0</max_class>
<max_rensyo __type="u16">0</max_rensyo>
<vip_rensyo __type="u16">0</vip_rensyo>
<max_defeat_skill __type="s32">0</max_defeat_skill>
<max_defeat_battle_rate __type="s32">0</max_defeat_battle_rate>
<gold_star __type="u32">0</gold_star>
<random_select __type="u32">0</random_select>
<enable_bonus_bp __type="u8">0</enable_bonus_bp>
<type_normal __type="u32">0</type_normal>
<type_perfect __type="u32">0</type_perfect>
<type_combo __type="u32">0</type_combo>
<area_id_list __type="u8" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_id_list>
<area_win_list __type="u32" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_win_list>
<area_lose_list __type="u32" __count="60">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</area_lose_list>
<perfect __type="u32">0</perfect>
<great __type="u32">0</great>
<good __type="u32">0</good>
<poor __type="u32">0</poor>
<miss __type="u32">0</miss>
<history>
{history_rounds}
</history>
<music_hist>
{music_hist_rounds}
</music_hist>
</battledata>
<battle_aniv>
<get>
<category_ver __type="u16" __count="11">0 0 0 0 0 0 0 0 0 0 0</category_ver>
<category_genre __type="u16" __count="11">0 0 0 0 0 0 0 0 0 0 0</category_genre>
</get>
</battle_aniv>
<info>
<mode __type="u32">0</mode>
<boss __type="u32">0</boss>
<battle_aniv __type="u32">0</battle_aniv>
<free_music __type="u32">0</free_music>
<free_chara __type="u32">0</free_chara>
<event __type="u32">0</event>
<battle_event __type="u32">0</battle_event>
<champ __type="u32">0</champ>
<item __type="u32">0</item>
<quest __type="u32">0</quest>
<campaign __type="u32">0</campaign>
<gdp __type="u32">0</gdp>
<v7 __type="u32">0</v7>
</info>
<quest>
<quest_rank __type="u8">0</quest_rank>
<star __type="u32">0</star>
<fan __type="u64">0</fan>
<qdata __type="u32" __count="39">0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</qdata>
<test_data __type="u32" __count="12">0 0 0 0 0 0 0 0 0 0 0 0</test_data>
</quest>
<championship>
<playable __type="s32" __count="4">0 0 0 0</playable>
</championship>
<ranking>
<skill_rank __type="s32">0</skill_rank>
</ranking>
<rival_id_1 __type="str" __count="1"></rival_id_1>
<rival_id_2 __type="str" __count="1"></rival_id_2>
<rival_id_3 __type="str" __count="1"></rival_id_3>
<standard nr="0"/>
<finish __type="u8">1</finish>
</player>
</gametop>
</response>

View File

@ -0,0 +1,31 @@
<response>
<gametop>
<player no="1">
<pdata rival_id="0">
<name __type="str">{name}</name>
<chara __type="u8">{chara}</chara>
<skill __type="s32">0</skill>
<syogo __type="s16" __count="2">0 0</syogo>
<info_level __type="u8">0</info_level>
<bdata>
<battle_rate __type="s32">0</battle_rate>
<battle_class __type="u8">0</battle_class>
<point __type="s16">0</point>
<rensyo __type="u16">0</rensyo>
<win __type="u32">0</win>
<lose __type="u32">0</lose>
<draw __type="u32">0</draw>
</bdata>
<quest>
<quest_rank __type="u8">0</quest_rank>
<star __type="u32">0</star>
<fan __type="u64">0</fan>
<qdata __type="u32" __count="13">0 0 0 0 0 0 0 0 0 0 0 0 0</qdata>
<test_data __type="u32" __count="12">0 0 0 0 0 0 0 0 0 0 0 0</test_data>
</quest>
</pdata>
<standard nr="0"/>
<finish __type="u8">1</finish>
</player>
</gametop>
</response>

View File

@ -0,0 +1,3 @@
<response>
<message/>
</response>

View File

@ -0,0 +1,3 @@
<response>
<package/>
</response>

View File

@ -0,0 +1,3 @@
<response>
<pcbevent/>
</response>

View File

@ -0,0 +1,3 @@
<response>
<pcbtracker ecenable="{ecenable}"/>
</response>

View File

@ -0,0 +1,9 @@
<response>
<shopinfo>
<data>
<cabid __type="u32">1</cabid>
<locationid __type="str">nowhere</locationid>
<is_send __type="u8">1</is_send>
</data>
</shopinfo>
</response>

View File

@ -1,4 +1,5 @@
import logging
import re
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, List, Optional
@ -8,9 +9,16 @@ from lxml import etree
logger = logging.getLogger(__name__)
FORMAT_VALUE_RE = re.compile(r"\{(.*)\}")
def load_xml_template(
service: str, method: str, args: Optional[Dict[str, Any]], / # noqa: W504
service: str,
method: str,
args: Optional[Dict[str, Any]] = None,
/,
drop_attributes: Optional[Dict[str, List[str]]] = None,
drop_children: Optional[Dict[str, List[str]]] = None,
) -> etree:
"""
Given a service and a method, load the appropriate XML template and return it
@ -20,6 +28,12 @@ def load_xml_template(
method (str): eAmuse Method Name
args (Dict[str, Any]): Used for formatting the xml string
Keyword Args:
drop_attributes (Optional[Dict[str, List[str]]]) = None: For each xpath str in
the dict key, remove all attributes listed from that node.
drop_children (Optional[Dict[str, List[str]]]) = None: For each xpath str in
the dict key, remove all children nodes listed from that node.
Returns:
etree: Resulting XML etree
"""
@ -32,16 +46,36 @@ def load_xml_template(
raise
if args is not None:
# Put in default args for format strings that we don't have a value for
# in `args`
for value in FORMAT_VALUE_RE.findall(xml_str):
if value not in args:
args[value] = ""
xml_str = xml_str.format(**args)
return etree.fromstring(xml_str.encode("UTF-8"))
xml_root = etree.fromstring(xml_str.encode("UTF-8"))
if drop_attributes is not None:
for xpath, attributes in drop_attributes.items():
drop_attributes_from_node(xml_root.find(xpath), attributes)
if drop_children is not None:
for xpath, children in drop_children.items():
drop_children_from_node(xml_root.find(xpath), children)
return xml_root
def drop_attributes(element: etree, attributes: List[str]) -> None:
def drop_attributes_from_node(element: etree, attributes: List[str]) -> None:
for attribute in attributes:
element.attrib.pop(attribute)
def drop_children_from_node(element: etree, children: List[str]) -> None:
for child in children:
element.remove(element.find(child))
def fill(count: int, value: str = "0") -> str:
return " ".join(value for _ in range(0, count))

View File

@ -4,7 +4,7 @@ import json
import logging
from datetime import datetime
from pathlib import Path
from typing import List, Tuple
from typing import List
from flask_sqlalchemy.model import DefaultMeta
from sqlalchemy import Column, ForeignKey, PrimaryKeyConstraint, event, func, text

View File

@ -71,7 +71,7 @@ def service_service(route: int) -> FlaskResponse:
raise Exception(f"Not sure how to handle this PCBEvent Request: {req}")
elif route == ServiceType.PACKAGE.value:
if req.method == Package.LIST:
response = Package.list(req)
response = Package.list()
else:
raise Exception(f"Not sure how to handle this Package Request: {req}")
elif route == ServiceType.FACILITY.value: