mirror of
https://github.com/573dev/gfdm-server.git
synced 2026-07-18 16:32:41 -05:00
Classes for all requests data
- A more generic class loader depending on request url, baed on method and module to avoid big if trees. Better separation of data classes as well imo.
This commit is contained in:
parent
186fd3c139
commit
a46b0210eb
|
|
@ -1,24 +1,4 @@
|
|||
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
|
||||
from v8_server.eamuse.services.package import Package
|
||||
from v8_server.eamuse.services.pcbevent import PCBEvent
|
||||
from v8_server.eamuse.services.pcbtracker import PCBTracker
|
||||
from v8_server.eamuse.services.services import ServiceRequest, Services, ServiceType
|
||||
|
||||
|
||||
__all__ = [
|
||||
"CardMng",
|
||||
"DLStatus",
|
||||
"Facility",
|
||||
"Local",
|
||||
"Message",
|
||||
"PCBEvent",
|
||||
"PCBTracker",
|
||||
"Package",
|
||||
"ServiceRequest",
|
||||
"ServiceType",
|
||||
"Services",
|
||||
]
|
||||
__all__ = ["ServiceRequest", "ServiceType", "Services"]
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server import db
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
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
|
||||
from v8_server.model.user import Card, RefID, User, UserAccount
|
||||
from v8_server.utils.convert import bool_to_int as btoi, int_to_bool as itob
|
||||
|
||||
|
||||
class CardStatus(object):
|
||||
|
|
@ -19,38 +21,40 @@ class CardStatus(object):
|
|||
INVALID_PIN = 116
|
||||
|
||||
|
||||
class CardMng(object):
|
||||
class Inquire(object):
|
||||
"""
|
||||
Handle the CardMng (Card Manage) request.
|
||||
Handle the CardMng Inquire request.
|
||||
|
||||
This is for supporting eAmuse card interaction.
|
||||
Given the Card ID, determine if we have a brand new user or a returning one.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardmng
|
||||
cardid="E00401007F7AD7A4"
|
||||
cardtype="1"
|
||||
method="inquire"
|
||||
model="HCV:J:A:A"
|
||||
update="1"
|
||||
/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# Methods
|
||||
INQUIRE = "inquire"
|
||||
GETREFID = "getrefid"
|
||||
AUTHPASS = "authpass"
|
||||
BINDMODEL = "bindmodel"
|
||||
GETKEEPSPAN = "getkeepspan"
|
||||
GETDATALIST = "getdatalist"
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.cardid = get_xml_attrib(req.xml[0], "cardid")
|
||||
self.cardtype = int(get_xml_attrib(req.xml[0], "cardtype"))
|
||||
self.update = int(get_xml_attrib(req.xml[0], "update"))
|
||||
|
||||
@classmethod
|
||||
def inquire(cls, req: ServiceRequest):
|
||||
# Model doesn't always exist in the request, unsure what it's used for
|
||||
model_value = get_xml_attrib(req.xml[0], "model")
|
||||
self.model = model_value if model_value != "None" else None
|
||||
|
||||
def response(self) -> etree:
|
||||
"""
|
||||
Handle a Card Manage Inquire Request
|
||||
|
||||
Either the given card id is a brand new user, or a returning user.
|
||||
|
||||
Modifyable XML Text Replacements:
|
||||
refid: The RefID.refid value for an existing user
|
||||
newflag: Set to true for a new user, else 0
|
||||
binded: Set to true if the user has a profile/account, else 0
|
||||
status: See CardMng status consts at the top of this class
|
||||
"""
|
||||
|
||||
# Grab the card id
|
||||
cardid = get_xml_attrib(req.xml[0], "cardid")
|
||||
|
||||
# New unregistered user
|
||||
args: Dict[str, Any] = {
|
||||
"newflag": 1,
|
||||
|
|
@ -69,7 +73,7 @@ class CardMng(object):
|
|||
}
|
||||
|
||||
# We have a returning user
|
||||
if (user := User.from_cardid(cardid)) is not None:
|
||||
if (user := User.from_cardid(self.cardid)) is not None:
|
||||
refid = RefID.from_userid(user.userid)
|
||||
bound = UserAccount.from_userid(user.userid) is not None
|
||||
|
||||
|
|
@ -89,19 +93,44 @@ class CardMng(object):
|
|||
"cardmng", "inquire", args, drop_attributes=drop_attributes
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def getrefid(cls, req: ServiceRequest):
|
||||
# Grab the card id and pin
|
||||
cardid = get_xml_attrib(req.xml[0], "cardid")
|
||||
pin = get_xml_attrib(req.xml[0], "passwd")
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'CardMng.Inquire<cardid = "{self.cardid}", cardtype = {self.cardtype}, '
|
||||
f'update = {self.update}, model = "{self.model}">'
|
||||
)
|
||||
|
||||
|
||||
class Getrefid(object):
|
||||
"""
|
||||
Handle the CardMng Getrefid request.
|
||||
|
||||
Given the Card ID, password, etc, generate a new RefID for the user and return it
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardmng
|
||||
cardid="E00401007F7AD7A4"
|
||||
cardtype="1"
|
||||
method="getrefid"
|
||||
newflag="0"
|
||||
passwd="1234"
|
||||
/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.cardid = get_xml_attrib(req.xml[0], "cardid")
|
||||
self.cardtype = int(get_xml_attrib(req.xml[0], "cardtype"))
|
||||
self.newflag = itob(int(get_xml_attrib(req.xml[0], "newflag")))
|
||||
self.passwd = get_xml_attrib(req.xml[0], "passwd")
|
||||
|
||||
def response(self) -> etree:
|
||||
# Create a new user object with the given pin
|
||||
user = User(pin=pin)
|
||||
user = User(pin=self.passwd)
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
|
||||
# Create the card, tie it to the user account
|
||||
card = Card(cardid=cardid, userid=user.userid)
|
||||
card = Card(cardid=self.cardid, userid=user.userid)
|
||||
db.session.add(card)
|
||||
db.session.commit()
|
||||
|
||||
|
|
@ -110,42 +139,79 @@ class CardMng(object):
|
|||
|
||||
return load_xml_template("cardmng", "getrefid", {"refid": refid.refid})
|
||||
|
||||
@classmethod
|
||||
def authpass(cls, req: ServiceRequest):
|
||||
""""""
|
||||
# Grab the refid and pin
|
||||
refid_str = get_xml_attrib(req.xml[0], "refid")
|
||||
pin = get_xml_attrib(req.xml[0], "pass")
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'CardMng.Getrefid<cardid = "{self.cardid}", cardtype = {self.cardtype}, '
|
||||
f'newflag = {self.newflag}, passwd = "{self.passwd}">'
|
||||
)
|
||||
|
||||
|
||||
class Authpass(object):
|
||||
"""
|
||||
Handle the CardMng Authpass request.
|
||||
|
||||
Given the RefID, and password, verify that the password given is correct for that
|
||||
user
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardmng method="authpass" pass="1234" refid="E9D2DD02072F05C5"/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.passwd = get_xml_attrib(req.xml[0], "pass")
|
||||
self.refid = get_xml_attrib(req.xml[0], "refid")
|
||||
|
||||
def response(self) -> etree:
|
||||
# Grab the refid
|
||||
refid = db.session.query(RefID).filter(RefID.refid == refid_str).one_or_none()
|
||||
refid = db.session.query(RefID).filter(RefID.refid == self.refid).one_or_none()
|
||||
|
||||
if refid is None:
|
||||
raise Exception("RefID Is None Here!")
|
||||
|
||||
# Check if the pin is valid for the user
|
||||
user = refid.user
|
||||
status = CardStatus.SUCCESS if user.pin == pin else CardStatus.INVALID_PIN
|
||||
status = (
|
||||
CardStatus.SUCCESS if user.pin == self.passwd else CardStatus.INVALID_PIN
|
||||
)
|
||||
|
||||
return load_xml_template("cardmng", "authpass", {"status": status})
|
||||
|
||||
@classmethod
|
||||
def bindmodel(cls, req: ServiceRequest):
|
||||
""""""
|
||||
# Grab the refid
|
||||
refid_str = get_xml_attrib(req.xml[0], "refid")
|
||||
refid = db.session.query(RefID).filter(RefID.refid == refid_str).one_or_none()
|
||||
def __repr__(self) -> str:
|
||||
return f'CardMng.Authpass<passwd = "{self.passwd}", refid = "{self.refid}">'
|
||||
|
||||
|
||||
class Bindmodel(object):
|
||||
"""
|
||||
Handle the CardMng Bindmodel request.
|
||||
|
||||
Given the RefID, and a newflag, bind the user to the current game.
|
||||
|
||||
XXX: Partially unsure what this actually needs to do
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardmng method="bindmodel" newflag="0" refid="A01D0C781F132DBC"/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.refid = get_xml_attrib(req.xml[0], "refid")
|
||||
self.newflag = itob(int(get_xml_attrib(req.xml[0], "newflag")))
|
||||
|
||||
def response(self) -> etree:
|
||||
refid = db.session.query(RefID).filter(RefID.refid == self.refid).one_or_none()
|
||||
|
||||
if refid is None:
|
||||
raise Exception("RefID is None Here!")
|
||||
|
||||
# Just bind some garbage here for now
|
||||
profile = Profile(refid=refid.refid, data={"data": "something"})
|
||||
db.session.add(profile)
|
||||
db.session.commit()
|
||||
|
||||
return load_xml_template("cardmng", "bindmodel", {"refid": refid.refid})
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'CardMng.Bindmodel<refid = "{self.refid}", newflag = {self.newflag}>'
|
||||
|
||||
|
||||
# TODO: figure out if these are actually used or not
|
||||
'''
|
||||
@classmethod
|
||||
def getkeepspan(cls):
|
||||
"""
|
||||
|
|
@ -161,3 +227,4 @@ class CardMng(object):
|
|||
Unclear what this method does, return a dummy response
|
||||
"""
|
||||
return load_xml_template("cardmng", "cardmng")
|
||||
'''
|
||||
|
|
|
|||
161
v8_server/eamuse/services/cardutil.py
Normal file
161
v8_server/eamuse/services/cardutil.py
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
import logging
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server import db
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
from v8_server.model.user import User, UserAccount
|
||||
from v8_server.utils.convert import int_to_bool as itob
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Card(object):
|
||||
"""
|
||||
Cardutil.Check.Card object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.no = int(get_xml_attrib(root, "no"))
|
||||
self.refid = root.find("refid").text
|
||||
self.uid = root.find("uid").text
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Card<no = {self.no}, refid = "{self.refid}", uid = "{self.uid}">'
|
||||
|
||||
|
||||
class CheckStatus(object):
|
||||
"""
|
||||
Status values for the Cardutil.Check response
|
||||
"""
|
||||
|
||||
NEW_USER = 0
|
||||
UNKNOWN = 1 # XXX: Unsure if this is used anywhere for anything
|
||||
EXISTING_USER = 2
|
||||
|
||||
|
||||
class Check(object):
|
||||
"""
|
||||
Handle the Cardutil.Check request.
|
||||
|
||||
Checks to see if the card belongs to a new user or an existing registered user.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardutil method="check">
|
||||
<card no="1">
|
||||
<refid __type="str">E9D2DD02072F05C5</refid>
|
||||
<uid __type="str">E00401007F7AD7A4</uid>
|
||||
</card>
|
||||
</cardutil>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.card = Card(req.xml[0].find("card"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Cardutil.Check<card = {self.card}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
user = User.from_refid(self.card.refid)
|
||||
|
||||
new_user = (
|
||||
user is None or (account := UserAccount.from_userid(user.userid)) is None
|
||||
)
|
||||
|
||||
# New User
|
||||
args: Dict[str, Any] = {"state": CheckStatus.NEW_USER}
|
||||
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": CheckStatus.EXISTING_USER,
|
||||
"name": account.name,
|
||||
"chara": account.chara,
|
||||
}
|
||||
drop_children = None
|
||||
|
||||
return load_xml_template("cardutil", "check", args, drop_children=drop_children)
|
||||
|
||||
|
||||
class Data(object):
|
||||
"""
|
||||
Cardutil.Regist.Data object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.no = int(get_xml_attrib(root, "no"))
|
||||
self.refid = root.find("refid").text
|
||||
self.name = root.find("name").text
|
||||
self.chara = int(root.find("chara").text)
|
||||
self.uid = root.find("uid").text
|
||||
self.cabid = int(root.find("cabid").text)
|
||||
self.is_succession = itob(int(root.find("is_succession")))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Data<no = {self.no}, refid = "{self.refid}", name = "{self.name}", '
|
||||
f'chara = {self.chara}, uid = "{self.uid}", cabid = {self.cabid}, '
|
||||
f"is_succession = {self.is_succession}>"
|
||||
)
|
||||
|
||||
|
||||
class Regist(object):
|
||||
"""
|
||||
Handle the Cardutil Regist request.
|
||||
|
||||
Register the data for a new user.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<cardutil method="regist">
|
||||
<data no="1">
|
||||
<refid __type="str">E9D2DD02072F05C5</refid>
|
||||
<name __type="str">AAAA</name>
|
||||
<chara __type="u8">0</chara>
|
||||
<uid __type="str">E00401007F7AD7A4</uid>
|
||||
<cabid __type="u32">1</cabid>
|
||||
<is_succession __type="s8">0</is_succession>
|
||||
</data>
|
||||
</cardutil>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.data = Data(req.xml[0].find("data"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Cardutil.Regist<data = {self.data}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
user = User.from_refid(self.data.refid)
|
||||
if user is None:
|
||||
raise Exception("This user should theoretically exist here")
|
||||
if user.card.cardid != self.data.uid:
|
||||
raise Exception(
|
||||
f"Card ID is incorrect: {user.card.cardid} != {self.data.uid}"
|
||||
)
|
||||
|
||||
user_account = UserAccount(
|
||||
userid=user.userid,
|
||||
name=self.data.name,
|
||||
chara=self.data.chara,
|
||||
is_succession=self.data.is_succession,
|
||||
)
|
||||
db.session.add(user_account)
|
||||
db.session.commit()
|
||||
|
||||
return load_xml_template("cardutil", "regist")
|
||||
82
v8_server/eamuse/services/customize.py
Normal file
82
v8_server/eamuse/services/customize.py
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Get(object):
|
||||
"""
|
||||
Customize.Regist.Player.Syogodata.Get object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.syogo = [int(x.text) for x in root.findall("syogo")]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Get<syogo = {self.syogo}>"
|
||||
|
||||
|
||||
class Syogodata(object):
|
||||
"""
|
||||
Customize.Regist.Player.Syogodata object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.get = Get(root.find("get"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Syogodata<get = {self.get}>"
|
||||
|
||||
|
||||
class Player(object):
|
||||
"""
|
||||
Customize.Regist.Player object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.no = int(get_xml_attrib(root, "no"))
|
||||
self.refid = root.find("refid").text
|
||||
self.syogodata = Syogodata(root.find("syogodata"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Player<no = {self.no}, refid = "{self.refid}", '
|
||||
f"syogodata = {self.syogodata}>"
|
||||
)
|
||||
|
||||
|
||||
class Regist(object):
|
||||
"""
|
||||
Handle the Customize Regist request.
|
||||
|
||||
Possibly just used to save some customizations for the user after the game ends.
|
||||
Such as giving the user a new title.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<customize method="regist">
|
||||
<player no="1">
|
||||
<refid __type="str">E9D2DD02072F05C5</refid>
|
||||
<syogodata>
|
||||
<get>
|
||||
<syogo __type="s16">4</syogo>
|
||||
<syogo __type="s16">0</syogo>
|
||||
</get>
|
||||
</syogodata>
|
||||
</player>
|
||||
</customize>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.players = [Player(x) for x in req.xml[0].findall("player")]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Customize.Regist<players = {self.players}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
return load_xml_template("customize", "regist")
|
||||
72
v8_server/eamuse/services/demodata.py
Normal file
72
v8_server/eamuse/services/demodata.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
from v8_server.model.song import HitChart
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Shop(object):
|
||||
"""
|
||||
Demodata.Get.Shop object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.locationid = root.find("locationid").text
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Shop<locationid = "{self.locationid}">'
|
||||
|
||||
|
||||
class Get(object):
|
||||
"""
|
||||
Handle the Demodata Get request.
|
||||
|
||||
Return demo data for the hitchart, etc.
|
||||
|
||||
<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>
|
||||
"""
|
||||
|
||||
DT_FMT = "%Y-%m-%d %H:%M:%S%z"
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.shop = Shop(req.xml[0].find("shop"))
|
||||
self.hitchart_nr = int(req.xml[0].find("hitchart_nr").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Demodata.Get<shop = {self.shop}, hitchart_nr = {self.hitchart_nr}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
rank_items = HitChart.get_ranking(self.hitchart_nr)
|
||||
|
||||
# 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": self.hitchart_nr,
|
||||
"start": datetime.now().strftime(self.DT_FMT),
|
||||
"end": datetime.now().strftime(self.DT_FMT),
|
||||
"hitchart_data": hitchart_xml_str,
|
||||
"division": 14,
|
||||
"message": "SenPi's Kickass DrumMania V8 Machine",
|
||||
}
|
||||
|
||||
return load_xml_template("demodata", "get", args)
|
||||
|
|
@ -1,16 +1,27 @@
|
|||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
|
||||
|
||||
class DLStatus(object):
|
||||
class Progress(object):
|
||||
"""
|
||||
Handle the DLStatus request.
|
||||
Handle the DLStatus Progress request.
|
||||
|
||||
It is unknown as to what this does.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<dlstatus method="progress">
|
||||
<progress __type="s32">0</progress>
|
||||
</dlstatus>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# Methods
|
||||
PROGRESS = "progress"
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.progress_value = int(req.xml[0].find("progress").text)
|
||||
|
||||
@classmethod
|
||||
def progress(cls):
|
||||
def progress(self) -> etree:
|
||||
return load_xml_template("dlstatus", "progress")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"DLStatus.Progress<progress = {self.progress_value}>"
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
|
||||
|
||||
class Facility(object):
|
||||
class Get(object):
|
||||
"""
|
||||
Handle the Facility request.
|
||||
Handle the Facility Get request.
|
||||
|
||||
The only method of note is the "get" method. This method expects to return a bunch
|
||||
of information about the arcade this cabinet is in, as well as some settings for
|
||||
URLs and the name of the cab.
|
||||
This method expects to return a bunch of information about the arcade this cabinet
|
||||
is in, as well as some settings for URLs and the name of the Arcade.
|
||||
|
||||
Example:
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<facility encoding="SHIFT_JIS" method="get"/>
|
||||
</call>
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<facility encoding="SHIFT_JIS" method="get"/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# Methods
|
||||
GET = "get"
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.encoding = get_xml_attrib(req.xml[0], "encoding")
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
def response(self) -> etree:
|
||||
# TODO: The facility data should be read in from a config file instead of being
|
||||
# hard coded here
|
||||
|
||||
|
|
@ -30,3 +30,6 @@ class Facility(object):
|
|||
"name": "SenPi Arcade",
|
||||
}
|
||||
return load_xml_template("facility", "get", args)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Facility.Get<encoding = "{self.encoding}">'
|
||||
|
|
|
|||
476
v8_server/eamuse/services/gameend.py
Normal file
476
v8_server/eamuse/services/gameend.py
Normal file
|
|
@ -0,0 +1,476 @@
|
|||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server import db
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
from v8_server.model.song import HitChart
|
||||
from v8_server.utils.convert import int_to_bool as itob
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Gamemode(object):
|
||||
"""
|
||||
Gameend.Regist.Gamemode object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.mode = get_xml_attrib(root, "mode")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Gamemode<mode = "{self.mode}">'
|
||||
|
||||
|
||||
class Shop(object):
|
||||
"""
|
||||
Gameend.Regist.Shop object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.cabid = int(root.find("cabid").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Shop<cabid = {self.cabid}>"
|
||||
|
||||
|
||||
class Hitchart(object):
|
||||
"""
|
||||
Gameend.Regist.Hitchart object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.musicids = [int(x.text) for x in root.findall("musicid")]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Hitchart<musicids = {self.musicids}>"
|
||||
|
||||
|
||||
class Stage(object):
|
||||
"""
|
||||
Gameend.Regist.Modedata.Stage object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.no = int(root.find("no").text)
|
||||
self.musicid = int(root.find("musicid").text)
|
||||
self.newmusic = itob(int(root.find("newmusic").text))
|
||||
self.longmusic = itob(int(root.find("longmusic").text))
|
||||
self.kind = int(root.find("kind").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Stage<no = {self.no}, musicid = {self.musicid}, "
|
||||
f"newmusic = {self.newmusic}, longmusic = {self.longmusic}, "
|
||||
f"kind = {self.kind}>"
|
||||
)
|
||||
|
||||
|
||||
class Modedata(object):
|
||||
"""
|
||||
Gameend.Regist.Modedata object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.mode = get_xml_attrib(root, "mode")
|
||||
self.stages = [Stage(x) for x in root.findall("stage")]
|
||||
self.session = int(root.find("session").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Modedata<mode = "{self.mode}", stages = {self.stages}, '
|
||||
f"session = {self.session}>"
|
||||
)
|
||||
|
||||
|
||||
class Info(object):
|
||||
"""
|
||||
Gameend.Regist.Player.Playerinfo.Info object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.mode = int(root.find("mode").text)
|
||||
self.boss = int(root.find("boss").text)
|
||||
self.battle_aniv = int(root.find("battle_aniv").text) # Possible Bool?
|
||||
self.free_music = int(root.find("free_music").text)
|
||||
self.free_chara = int(root.find("free_chara").text)
|
||||
self.event = int(root.find("event").text)
|
||||
self.battle_event = int(root.find("battle_event").text)
|
||||
self.champ = int(root.find("champ").text)
|
||||
self.item = int(root.find("item").text)
|
||||
self.quest = int(root.find("quest").text)
|
||||
self.campaign = int(root.find("campaign").text)
|
||||
self.gdp = int(root.find("gdp").text)
|
||||
self.v7 = int(root.find("v7").text) # Possible Bool?
|
||||
self.champ_result = [int(x) for x in root.find("champ_result").text.split()]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Info<mode = {self.mode}, boss = {self.boss}, "
|
||||
f"battle_aniv = {self.battle_aniv}, free_music = {self.free_music}, "
|
||||
f"free_chara = {self.free_chara}, event = {self.event}, "
|
||||
f"battle_event = {self.battle_event}, champ = {self.champ}, "
|
||||
f"item = {self.item}, quest = {self.quest}, campaign = {self.campaign}, "
|
||||
f"gdp = {self.gdp}, v7 = {self.v7}, champ_result = {self.champ_result}>"
|
||||
)
|
||||
|
||||
|
||||
class Customize(object):
|
||||
"""
|
||||
Gameend.Regist.Player.Playerinfo.Customize object
|
||||
|
||||
This is potentially the mod (speed mods, dark, auto bass, etc) data
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.shutter = int(root.find("shutter").text)
|
||||
self.info_level = int(root.find("info_level").text)
|
||||
self.name_disp = int(root.find("name_disp").text) # Possible Bool?
|
||||
self.auto = int(root.find("auto").text)
|
||||
self.random = int(root.find("random").text)
|
||||
self.judge_logo = int(root.find("judge_logo").text)
|
||||
self.skin = int(root.find("skin").text)
|
||||
self.movie = int(root.find("movie").text)
|
||||
self.attack_effect = int(root.find("attack_effect").text)
|
||||
self.layout = int(root.find("layout").text)
|
||||
self.target_skill = int(root.find("target_skill").text)
|
||||
self.comparison = int(root.find("comparison").text)
|
||||
self.meter_custom = [int(x) for x in root.find("meter_custom").text.split()]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Customize<shutter = {self.shutter}, info_level = {self.info_level}, "
|
||||
f"name_disp = {self.name_disp}, auto = {self.auto}, "
|
||||
f"random = {self.random}, judge_logo = {self.judge_logo}, "
|
||||
f"skin = {self.skin}, movie = {self.movie}, "
|
||||
f"attack_effect = {self.attack_effect}, layout = {self.layout}, "
|
||||
f"target_skill = {self.target_skill}, comparison = {self.comparison}, "
|
||||
f"meter_custom = {self.meter_custom}>"
|
||||
)
|
||||
|
||||
|
||||
class Playerinfo(object):
|
||||
"""
|
||||
Gameend.Regist.Player.Playerinfo object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.refid = root.find("refid").text
|
||||
self.gdp = int(root.find("gdp").text)
|
||||
self.bad_play_kind = int(root.find("bad_play_kind").text)
|
||||
self.total_skill_point = int(root.find("total_skill_point").text)
|
||||
self.styles = int(root.find("styles").text)
|
||||
self.styles_2 = int(root.find("styles_2").text)
|
||||
self.secret_music = [int(x) for x in root.find("secret_music").text.split()]
|
||||
self.chara = int(root.find("chara").text)
|
||||
self.secret_chara = int(root.find("secret_chara").text)
|
||||
self.syogo = [int(x) for x in root.find("syogo").text.split()]
|
||||
self.shutter_list = int(root.find("shutter_list").text)
|
||||
self.judge_logo_list = int(root.find("judge_logo_list").text)
|
||||
self.skin_list = int(root.find("skin_list").text)
|
||||
self.movie_list = int(root.find("movie_list").text)
|
||||
self.attack_effect_list = int(root.find("attack_effect_list").text)
|
||||
self.idle_screen = int(root.find("idle_screen").text)
|
||||
self.chance_point = int(root.find("chance_point").text)
|
||||
self.failed_cnt = int(root.find("failed_cnt").text)
|
||||
self.perfect = int(root.find("perfect").text)
|
||||
self.great = int(root.find("great").text)
|
||||
self.good = int(root.find("good").text)
|
||||
self.poor = int(root.find("poor").text)
|
||||
self.miss = int(root.find("miss").text)
|
||||
self.time = int(root.find("time").text)
|
||||
self.exc_clear_num = int(root.find("exc_clear_num").text)
|
||||
self.full_clear_num = int(root.find("full_clear_num").text)
|
||||
self.max_clear_difficulty = int(root.find("max_clear_difficulty").text)
|
||||
self.max_fullcombo_difficulty = int(root.find("max_fullcombo_difficulty").text)
|
||||
self.max_excellent_difficulty = int(root.find("max_excellent_difficulty").text)
|
||||
self.champ_group = int(root.find("champ_group").text)
|
||||
self.champ_kind = int(root.find("champ_kind").text)
|
||||
self.musicid = [int(x) for x in root.find("musicid").text.split()]
|
||||
self.object_musicid = [int(x) for x in root.find("object_musicid").text.split()]
|
||||
self.seqmode = [int(x) for x in root.find("seqmode").text.split()]
|
||||
self.flags = [int(x) for x in root.find("flags").text.split()]
|
||||
self.score = [int(x) for x in root.find("score").text.split()]
|
||||
self.point = [int(x) for x in root.find("point").text.split()]
|
||||
self.info = Info(root.find("info"))
|
||||
self.customize = Customize(root.find("customize"))
|
||||
# There seems to be another `perfect` here for some reason
|
||||
self.bp = int(root.find("bp").text)
|
||||
self.reserv_item_list = [
|
||||
int(x) for x in root.find("reserv_item_list").text.split()
|
||||
]
|
||||
self.rival_id_1 = root.find("rival_id_1").text
|
||||
self.rival_id_2 = root.find("rival_id_2").text
|
||||
self.rival_id_3 = root.find("rival_id_3").text
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Playerinfo<refid = "{self.refid}", gdp = {self.gdp}, '
|
||||
f"bad_play_kind = {self.bad_play_kind}, "
|
||||
f"total_skill_point = {self.total_skill_point}, "
|
||||
f"styles = {self.styles}, styles_2 = {self.styles_2}, "
|
||||
f"secret_music = {self.secret_music}, chara = {self.chara}, "
|
||||
f"secret_chara = {self.secret_chara}, syogo = {self.syogo}, "
|
||||
f"shutter_list = {self.shutter_list}, "
|
||||
f"judge_logo_list = {self.judge_logo_list}, "
|
||||
f"skin_list = {self.skin_list}, movie_list = {self.movie_list}, "
|
||||
f"attack_effect_list = {self.attack_effect_list}, "
|
||||
f"idle_screen = {self.idle_screen}, "
|
||||
f"chance_point = {self.chance_point}, failed_cnt = {self.failed_cnt}, "
|
||||
f"perfect = {self.perfect}, great = {self.great}, good = {self.good}, "
|
||||
f"poor = {self.poor}, miss = {self.miss}, time = {self.time}, "
|
||||
f"exc_clear_num = {self.exc_clear_num}, "
|
||||
f"full_clear_num = {self.full_clear_num}, "
|
||||
f"max_clear_difficulty = {self.max_clear_difficulty}, "
|
||||
f"max_fullcombo_difficulty = {self.max_fullcombo_difficulty}, "
|
||||
f"max_excellent_difficulty = {self.max_excellent_difficulty}, "
|
||||
f"champ_group = {self.champ_group}, champ_kind = {self.champ_kind}, "
|
||||
f"musicid = {self.musicid}, object_musicid = {self.object_musicid}, "
|
||||
f"seqmode = {self.seqmode}, flags = {self.flags}, "
|
||||
f"score = {self.score}, point = {self.point}, info = {self.info}, "
|
||||
f"customize = {self.customize}, bp = {self.bp}, "
|
||||
f"reserv_item_list = {self.reserv_item_list}, "
|
||||
f'rival_id_1 = "{self.rival_id_1}", rival_id_2 = "{self.rival_id_2}", '
|
||||
f'rival_id_3 = "{self.rival_id_3}">'
|
||||
)
|
||||
|
||||
|
||||
class Playdata(object):
|
||||
"""
|
||||
Gameend.Regist.Player.Playdata object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.no = int(root.find("no").text)
|
||||
self.seqmode = int(root.find("seqmode").text)
|
||||
self.clear = int(root.find("clear").text)
|
||||
self.auto_clear = int(root.find("auto_clear").text)
|
||||
self.score = int(root.find("score").text)
|
||||
self.flags = int(root.find("flags").text)
|
||||
self.fullcombo = int(root.find("fullcombo").text)
|
||||
self.excellent = int(root.find("excellent").text)
|
||||
self.combo = int(root.find("combo").text)
|
||||
self.skill_point = int(root.find("skill_point").text)
|
||||
self.skill_perc = int(root.find("skill_perc").text)
|
||||
self.result_rank = int(root.find("result_rank").text)
|
||||
self.difficulty = int(root.find("difficulty").text)
|
||||
self.combo_rate = int(root.find("combo_rate").text)
|
||||
self.perfect_rate = int(root.find("perfect_rate").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Playdata<no = {self.no}, seqmode = {self.seqmode}, clear = {self.clear}, "
|
||||
f"auto_clear = {self.auto_clear}, score = {self.score}, "
|
||||
f"flag = {self.flags}, fullcombo = {self.fullcombo}, "
|
||||
f"excellent = {self.excellent}, combo = {self.combo}, "
|
||||
f"skill_point = {self.skill_point}, skill_perc = {self.skill_perc}, "
|
||||
f"result_rank = {self.result_rank}, difficulty = {self.difficulty}, "
|
||||
f"combo_rate = {self.combo_rate}, perfect_rate = {self.perfect_rate}>"
|
||||
)
|
||||
|
||||
|
||||
class Player(object):
|
||||
"""
|
||||
Gameend.Regist.Player object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.card = get_xml_attrib(root, "card")
|
||||
self.no = int(get_xml_attrib(root, "no"))
|
||||
self.playerinfo = Playerinfo(root.find("playerinfo"))
|
||||
self.playdata = [Playdata(x) for x in root.findall("playdata")]
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Player<card = "{self.card}", no = {self.no}, '
|
||||
f"playerinfo = {self.playerinfo}, playdata = {self.playdata}>"
|
||||
)
|
||||
|
||||
|
||||
class Regist(object):
|
||||
"""
|
||||
Handle the Gameend Regist request.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<gameend method="regist">
|
||||
<gamemode mode="game_mode"/>
|
||||
<shop>
|
||||
<cabid __type="u32">1</cabid>
|
||||
</shop>
|
||||
<hitchart>
|
||||
<musicid __type="s32">1849</musicid>
|
||||
</hitchart>
|
||||
<modedata mode="standard">
|
||||
<stage>
|
||||
<no __type="u8">1</no>
|
||||
<musicid __type="s32">1849</musicid>
|
||||
<newmusic __type="u8">1</newmusic>
|
||||
<longmusic __type="u8">0</longmusic>
|
||||
<kind __type="u8">0</kind>
|
||||
</stage>
|
||||
<session __type="u8">0</session>
|
||||
</modedata>
|
||||
<player card="use" no="1">
|
||||
<playerinfo>
|
||||
<refid __type="str">E9D2DD02072F05C5</refid>
|
||||
<gdp __type="u32">900</gdp>
|
||||
<bad_play_kind __type="s32">0</bad_play_kind>
|
||||
<total_skill_point __type="s32">0</total_skill_point>
|
||||
<styles __type="u32">2097152</styles>
|
||||
<styles_2 __type="u32">0</styles_2>
|
||||
<secret_music __type="u16" __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
|
||||
</secret_music>
|
||||
<chara __type="u8">0</chara>
|
||||
<secret_chara __type="u32">1824</secret_chara>
|
||||
<syogo __type="s16" __count="2">0 0</syogo>
|
||||
<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>
|
||||
<perfect __type="u32">0</perfect>
|
||||
<great __type="u32">0</great>
|
||||
<good __type="u32">0</good>
|
||||
<poor __type="u32">0</poor>
|
||||
<miss __type="u32">120</miss>
|
||||
<time __type="u32">222</time>
|
||||
<exc_clear_num __type="u32">0</exc_clear_num>
|
||||
<full_clear_num __type="u32">0</full_clear_num>
|
||||
<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>
|
||||
<champ_group __type="u8">0</champ_group>
|
||||
<champ_kind __type="u8">0</champ_kind>
|
||||
<musicid __type="s32" __count="6">0 0 0 0 0 0</musicid>
|
||||
<object_musicid __type="s32" __count="6">
|
||||
0 0 0 0 0 0
|
||||
</object_musicid>
|
||||
<seqmode __type="s8" __count="6">0 0 0 0 0 0</seqmode>
|
||||
<flags __type="u32" __count="6">0 0 0 0 0 0</flags>
|
||||
<score __type="u32" __count="6">0 0 0 0 0 0</score>
|
||||
<point __type="u32" __count="6">0 0 0 0 0 0</point>
|
||||
<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>
|
||||
<champ_result __type="u32" __count="2">0 0</champ_result>
|
||||
</info>
|
||||
<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>
|
||||
<perfect __type="u32">0</perfect>
|
||||
<bp __type="u32">0</bp>
|
||||
<reserv_item_list __type="s16" __count="200">
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
|
||||
</reserv_item_list>
|
||||
<rival_id_1 __type="str"></rival_id_1>
|
||||
<rival_id_2 __type="str"></rival_id_2>
|
||||
<rival_id_3 __type="str"></rival_id_3>
|
||||
</playerinfo>
|
||||
<playdata>
|
||||
<no __type="u8">1</no>
|
||||
<seqmode __type="s8">1</seqmode>
|
||||
<clear __type="u8">0</clear>
|
||||
<auto_clear __type="u8">0</auto_clear>
|
||||
<score __type="u32">0</score>
|
||||
<flags __type="u32">0</flags>
|
||||
<fullcombo __type="u8">0</fullcombo>
|
||||
<excellent __type="u8">0</excellent>
|
||||
<combo __type="u32">0</combo>
|
||||
<skill_point __type="s32">0</skill_point>
|
||||
<skill_perc __type="s32">-1</skill_perc>
|
||||
<result_rank __type="s8">0</result_rank>
|
||||
<difficulty __type="s8">11</difficulty>
|
||||
<combo_rate __type="s8">0</combo_rate>
|
||||
<perfect_rate __type="s8">0</perfect_rate>
|
||||
</playdata>
|
||||
</player>
|
||||
</gameend>
|
||||
</call>
|
||||
"""
|
||||
|
||||
DT_FMT = "%Y-%m-%d %H:%M:%S%z"
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.gamemode = Gamemode(req.xml[0].find("gamemode"))
|
||||
self.shop = Shop(req.xml[0].find("shop"))
|
||||
self.hitchart = Hitchart(req.xml[0].find("hitchart"))
|
||||
self.modedata = Modedata(req.xml[0].find("modedata"))
|
||||
self.player = Player(req.xml[0].find("player"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Gameend.Regist<gamemode = {self.gamemode}, shop = {self.shop}, "
|
||||
f"hitchart = {self.hitchart}, modedata = {self.modedata}, "
|
||||
f"player = {self.player}>"
|
||||
)
|
||||
|
||||
def response(self) -> etree:
|
||||
for musicid in self.hitchart.musicids:
|
||||
hc = HitChart(musicid=musicid, playdate=datetime.now())
|
||||
logger.debug(f"Saving HitChart: {hc}")
|
||||
db.session.add(hc)
|
||||
db.session.commit()
|
||||
|
||||
# Just send back a dummy object for now
|
||||
now_time = datetime.now().strftime(self.DT_FMT)
|
||||
|
||||
# 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": self.gamemode.mode,
|
||||
"player_card": self.player.card,
|
||||
"player_no": self.player.no,
|
||||
"now_time": now_time,
|
||||
"history_rounds": history_rounds,
|
||||
"music_hist_rounds": music_hist_rounds,
|
||||
}
|
||||
|
||||
return load_xml_template("gameend", "regist", args)
|
||||
57
v8_server/eamuse/services/gameinfo.py
Normal file
57
v8_server/eamuse/services/gameinfo.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.utils.crc import calculate_crc8
|
||||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Shop(object):
|
||||
"""
|
||||
Gameinfo.Get.Shop object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.locationid = root.find("locationid").text
|
||||
self.cabid = int(root.find("cabid").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Shop<locationid = {self.locationid}, cabid = {self.cabid}>"
|
||||
|
||||
|
||||
class Get(object):
|
||||
"""
|
||||
Handle the Gameinfo Get request.
|
||||
|
||||
Returns various game data at the start of a game session.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<gameinfo method="get">
|
||||
<shop>
|
||||
<locationid __type="str">CA-123</locationid>
|
||||
<cabid __type="u32">1</cabid>
|
||||
</shop>
|
||||
</gameinfo>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.shop = Shop(req.xml[0].find("shop"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Gameinfo.Get<shop = {self.shop}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
# 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,
|
||||
}
|
||||
return load_xml_template("gameinfo", "get", args)
|
||||
122
v8_server/eamuse/services/gametop.py
Normal file
122
v8_server/eamuse/services/gametop.py
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.utils.crc import calculate_crc8
|
||||
from v8_server.eamuse.xml.utils import fill, get_xml_attrib, load_xml_template
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Request(object):
|
||||
"""
|
||||
Gametop.Get.Player.Request object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.kind = int(root.find("kind").text)
|
||||
self.offset = int(root.find("offset").text)
|
||||
self.music_nr = int(root.find("music_nr").text)
|
||||
self.cabid = int(root.find("cabid").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Request<kind = {self.kind}, offset = {self.offset}, "
|
||||
f"music_nr = {self.music_nr}, cabid = {self.cabid}>"
|
||||
)
|
||||
|
||||
|
||||
class Player(object):
|
||||
"""
|
||||
Gametop.Get.Player object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.card = get_xml_attrib(root, "card")
|
||||
self.no = int(get_xml_attrib(root, "no"))
|
||||
self.refid = root.find("refid").text
|
||||
self.request = Request(root.find("request"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Player<card = "{self.card}", no = {self.no}, refid = "{self.refid}", '
|
||||
f"request = {self.request}>"
|
||||
)
|
||||
|
||||
|
||||
class Get(object):
|
||||
"""
|
||||
Handle the Gametop.Get request.
|
||||
|
||||
This requests saved user data when using eAmuse.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<gametop method="get">
|
||||
<player card="use" no="1">
|
||||
<refid __type="str">E9D2DD02072F05C5</refid>
|
||||
<request>
|
||||
<kind __type="u8">0</kind>
|
||||
<offset __type="u16">0</offset>
|
||||
<music_nr __type="u16">250</music_nr>
|
||||
<cabid __type="u32">1</cabid>
|
||||
</request>
|
||||
</player>
|
||||
</gametop>
|
||||
</call>
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.player = Player(req.xml[0].find("player"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Gametop.Get<player = {self.player}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
# 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,
|
||||
}
|
||||
|
||||
return load_xml_template("gametop", "get", args)
|
||||
|
||||
|
||||
# TODO: We haven't ever received a request for rival data, so we can implement this in
|
||||
# the future
|
||||
"""
|
||||
elif req.method == cls.GAMETOP_GET_RIVAL:
|
||||
response = load_xml_template(
|
||||
"gametop", "get_rival", {"name": "name", "chara": 0}
|
||||
)
|
||||
else:
|
||||
raise Exception(
|
||||
"Not sure how to handle this gametop request. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
"""
|
||||
|
|
@ -1 +0,0 @@
|
|||
# >>libshare-pj.c: xrpc_module_add(aLobby, "lobby", aLobby, &off_100404C4);
|
||||
|
|
@ -1,302 +0,0 @@
|
|||
import logging
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from lxml import etree
|
||||
|
||||
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 fill, get_xml_attrib, load_xml_template
|
||||
from v8_server.model.song import HitChart
|
||||
from v8_server.model.user import User, UserAccount
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Local(object):
|
||||
"""
|
||||
Handle the Local request.
|
||||
|
||||
This request handles most of the game specific requests.
|
||||
"""
|
||||
|
||||
# Methods
|
||||
SHOPINFO = "shopinfo"
|
||||
SHOPINFO_REGIST = "regist"
|
||||
|
||||
DEMODATA = "demodata"
|
||||
DEMODATA_GET = "get"
|
||||
|
||||
CARDUTIL = "cardutil"
|
||||
CARDUTIL_CHECK = "check"
|
||||
CARDUTIL_REGIST = "regist"
|
||||
|
||||
GAMEINFO = "gameinfo"
|
||||
GAMEINFO_GET = "get"
|
||||
|
||||
GAMEEND = "gameend"
|
||||
GAMEEND_REGIST = "regist"
|
||||
|
||||
GAMETOP = "gametop"
|
||||
GAMETOP_GET = "get"
|
||||
GAMETOP_GET_RIVAL = "get_rival"
|
||||
|
||||
CUSTOMIZE = "customize"
|
||||
CUSTOMIZE_REGIST = "regist"
|
||||
|
||||
ASSERT_REPORT = "assert_report"
|
||||
ASSERT_REPORT_REGIST = "regist"
|
||||
|
||||
# Not sure about this one yet
|
||||
INCREMENT = "increment"
|
||||
|
||||
@classmethod
|
||||
def customize(cls, req: ServiceRequest) -> etree:
|
||||
if req.method == cls.CUSTOMIZE_REGIST:
|
||||
response = load_xml_template("customize", "regist")
|
||||
else:
|
||||
raise Exception(
|
||||
"Not sure how to handle this customize request. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def shopinfo(cls, req: ServiceRequest) -> etree:
|
||||
if req.method == cls.SHOPINFO_REGIST:
|
||||
response = load_xml_template("shopinfo", "regist")
|
||||
else:
|
||||
raise Exception(
|
||||
"Not sure how to handle this shopinfo request. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def demodata(cls, req: ServiceRequest) -> etree:
|
||||
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_items = HitChart.get_ranking(hitchart_number)
|
||||
|
||||
# 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. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def cardutil(cls, req: ServiceRequest) -> etree:
|
||||
if req.method == cls.CARDUTIL_CHECK:
|
||||
refid = req.xml[0].find("card/refid").text
|
||||
user = User.from_refid(refid)
|
||||
|
||||
new_user = (
|
||||
user is None
|
||||
or (account := UserAccount.from_userid(user.userid)) is None
|
||||
)
|
||||
|
||||
# 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
|
||||
name = root.find("name").text
|
||||
chara = root.find("chara").text
|
||||
cardid = root.find("uid").text
|
||||
is_succession = root.find("is_succession").text
|
||||
|
||||
user = User.from_refid(refid)
|
||||
if user is None:
|
||||
raise Exception("This user should theoretically exist here")
|
||||
if user.card.cardid != cardid:
|
||||
raise Exception(f"Card ID is incorrect: {user.card.cardid} != {cardid}")
|
||||
|
||||
user_account = UserAccount(
|
||||
userid=user.userid,
|
||||
name=name,
|
||||
chara=int(chara),
|
||||
is_succession=True if is_succession == "1" else False,
|
||||
)
|
||||
db.session.add(user_account)
|
||||
db.session.commit()
|
||||
|
||||
response = load_xml_template("cardutil", "regist")
|
||||
else:
|
||||
raise Exception(
|
||||
"Not sure how to handle this cardutil request. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def gameinfo(cls, req: ServiceRequest) -> etree:
|
||||
if req.method == cls.GAMEINFO_GET:
|
||||
# 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. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def gametop(cls, req: ServiceRequest) -> etree:
|
||||
if req.method == cls.GAMETOP_GET:
|
||||
# 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 = load_xml_template(
|
||||
"gametop", "get_rival", {"name": "name", "chara": 0}
|
||||
)
|
||||
else:
|
||||
raise Exception(
|
||||
"Not sure how to handle this gametop request. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def gameend(cls, req: ServiceRequest) -> etree:
|
||||
"""
|
||||
Handle a GameEnd request.
|
||||
|
||||
For now just save the hitchart data
|
||||
"""
|
||||
dtfmt = "%Y-%m-%d %H:%M:%S%z"
|
||||
|
||||
if req.method == cls.GAMEEND_REGIST:
|
||||
# Grab the hitchart data
|
||||
hc_root = req.xml[0].find("hitchart")
|
||||
|
||||
for mid in hc_root.findall("musicid"):
|
||||
musicid = int(mid.text)
|
||||
hc = HitChart(musicid=musicid, playdate=datetime.now())
|
||||
logger.debug(f"Saving HitChart: {hc}")
|
||||
db.session.add(hc)
|
||||
db.session.commit()
|
||||
|
||||
# Just send back a dummy object for now
|
||||
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")
|
||||
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. "
|
||||
f'method "{req.method}" is unknown for request: {req}'
|
||||
)
|
||||
|
||||
return response
|
||||
|
|
@ -1,21 +1,25 @@
|
|||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
|
||||
|
||||
class Message(object):
|
||||
class Get(object):
|
||||
"""
|
||||
Handle the Message request.
|
||||
Handle the Message Get request.
|
||||
|
||||
It is unknown as to what this does. Possibly it's for operator messages
|
||||
|
||||
Example:
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<message method="get"/>
|
||||
</call>
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<message method="get"/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# Methods
|
||||
GET = "get"
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def get(cls):
|
||||
def response(self) -> etree:
|
||||
return load_xml_template("message", "get")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return "Message.Get<>"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,26 @@
|
|||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
|
||||
|
||||
class Package(object):
|
||||
class List(object):
|
||||
"""
|
||||
Handle the Package request.
|
||||
Handle the Package List request.
|
||||
|
||||
This is for supporting downloading of updates. We do not support this.
|
||||
This is for supporting downloading of updates.
|
||||
We do not support this.
|
||||
|
||||
Example:
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<package method="list" pkgtype="all"/>
|
||||
</call>
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<package method="list" pkgtype="all"/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# Methods
|
||||
LIST = "list"
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.pkgtype = get_xml_attrib(req.xml[0], "pkgtype")
|
||||
|
||||
@classmethod
|
||||
def list(cls):
|
||||
def response(self) -> etree:
|
||||
return load_xml_template("package", "list")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'Package.List<pkgtype="{self.pkgtype}">'
|
||||
|
|
|
|||
|
|
@ -10,16 +10,15 @@ from v8_server.eamuse.xml.utils import load_xml_template
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PCBEventItem(object):
|
||||
class PCBEventPutItem(object):
|
||||
"""
|
||||
Contains the data for a PCBEvent Item
|
||||
|
||||
Example:
|
||||
<item>
|
||||
<name __type="str">K32.mode.std</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992363</time>
|
||||
</item>
|
||||
<item>
|
||||
<name __type="str">K32.mode.std</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992363</time>
|
||||
</item>
|
||||
"""
|
||||
|
||||
DATE_FMT = "%b/%d/%Y-%H:%M:%S"
|
||||
|
|
@ -32,39 +31,28 @@ class PCBEventItem(object):
|
|||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'PCBEventItem<name: "{self.name}", value: {self.value}, '
|
||||
f'PCBEventPutItem<name: "{self.name}", value: {self.value}, '
|
||||
f"time: {self.time.strftime(self.DATE_FMT)}>"
|
||||
)
|
||||
|
||||
|
||||
class PCBEvent(object):
|
||||
class Put(object):
|
||||
"""
|
||||
Handle the PCBEvent request.
|
||||
|
||||
It is unknown as to what this does.
|
||||
|
||||
Example:
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<pcbevent method="put">
|
||||
<time __type="time">1602992385</time>
|
||||
<seq __type="u32">4</seq>
|
||||
<item>
|
||||
<name __type="str">K32.mode.std</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992363</time>
|
||||
</item>
|
||||
<item>
|
||||
<name __type="str">K32.playcnt.t</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992363</time>
|
||||
</item>
|
||||
<item>
|
||||
<name __type="str">game.e</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992371</time>
|
||||
</item>
|
||||
</pcbevent>
|
||||
</call>
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<pcbevent method="put">
|
||||
<time __type="time">1602992385</time>
|
||||
<seq __type="u32">4</seq>
|
||||
<item>
|
||||
<name __type="str">K32.mode.std</name>
|
||||
<value __type="s32">1</value>
|
||||
<time __type="time">1602992363</time>
|
||||
</item>
|
||||
</pcbevent>
|
||||
</call>
|
||||
"""
|
||||
|
||||
DATE_FMT = "%b/%d/%Y-%H:%M:%S"
|
||||
|
|
@ -78,27 +66,16 @@ class PCBEvent(object):
|
|||
|
||||
self.items = []
|
||||
for item in xml_root.findall("item"):
|
||||
self.items.append(PCBEventItem(item))
|
||||
self.items.append(PCBEventPutItem(item))
|
||||
|
||||
# Methods
|
||||
PUT = "put"
|
||||
|
||||
@classmethod
|
||||
def put(cls, req: ServiceRequest):
|
||||
"""
|
||||
Example:
|
||||
<response>
|
||||
<pcbevent expire="600"/>
|
||||
</response>
|
||||
"""
|
||||
# Log the event
|
||||
event = PCBEvent(req)
|
||||
logger.info(event)
|
||||
logger.info(self)
|
||||
|
||||
def response(self) -> etree:
|
||||
return load_xml_template("pcbevent", "put")
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"PCBEvent<time: {self.time.strftime(self.DATE_FMT)}, "
|
||||
f"PCBEvent.Put<time: {self.time.strftime(self.DATE_FMT)}, "
|
||||
f"seq: {self.seq}, items: {self.items}>"
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,28 +1,36 @@
|
|||
from v8_server.eamuse.xml.utils import load_xml_template
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
from v8_server.utils.convert import bool_to_int as btoi
|
||||
|
||||
|
||||
class PCBTracker(object):
|
||||
class Alive(object):
|
||||
"""
|
||||
Handle the PCBTracker request.
|
||||
Handle the PCBTracker Alive request.
|
||||
|
||||
The only method of note is the "alive" method which returns whether PASELI should be
|
||||
active or not for this session.
|
||||
This method which returns whether PASELI should be active or not for this session.
|
||||
|
||||
Example:
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<pcbtracker hardid="010074D435AAD895" method="alive" softid=""/>
|
||||
</call>
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<pcbtracker hardid="010074D435AAD895" method="alive" softid=""/>
|
||||
</call>
|
||||
"""
|
||||
|
||||
# We don't support PASELI on GFDM: V8
|
||||
PASELI_ACTIVE = False
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.hardid = get_xml_attrib(req.xml[0], "hardid")
|
||||
self.softid = get_xml_attrib(req.xml[0], "softid")
|
||||
|
||||
# Methods
|
||||
ALIVE = "alive"
|
||||
# Most likely you'd determine this value from the hardware id?
|
||||
# Right now we don't support paseli
|
||||
self.paseli_active = False
|
||||
|
||||
@classmethod
|
||||
def alive(cls):
|
||||
def response(self) -> etree:
|
||||
return load_xml_template(
|
||||
"pcbtracker", "alive", {"ecenable": btoi(cls.PASELI_ACTIVE)}
|
||||
"pcbtracker", "alive", {"ecenable": btoi(self.paseli_active)}
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'PCBTracker.Alive<hardid="{self.hardid}", softid="{self.softid}", '
|
||||
f"paseli_active = {self.paseli_active}>"
|
||||
)
|
||||
|
|
|
|||
208
v8_server/eamuse/services/shopinfo.py
Normal file
208
v8_server/eamuse/services/shopinfo.py
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
import logging
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from v8_server.eamuse.services.services import ServiceRequest
|
||||
from v8_server.eamuse.xml.utils import get_xml_attrib, load_xml_template
|
||||
from v8_server.utils.convert import int_to_bool as itob
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SoundOptions(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.SoundOptions object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.volume_bgm = int(root.find("volume_bgm").text)
|
||||
self.volume_se_myself = int(root.find("volume_se_myself").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"SoundOptions<volume_bgm = {self.volume_bgm}, "
|
||||
f"volume_se_myself = {self.volume_se_myself}>"
|
||||
)
|
||||
|
||||
|
||||
class StandAlone(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.GameOptions.StandAlone object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.difficulty_standard = int(root.find("difficulty_standard").text)
|
||||
self.max_stage_standard = int(root.find("max_stage_standard").text)
|
||||
self.long_music = int(root.find("long_music").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"StandAlone<difficulty_standard = {self.difficulty_standard}, "
|
||||
f"max_stage_standard = {self.max_stage_standard}, "
|
||||
f"long_music = {self.long_music}>"
|
||||
)
|
||||
|
||||
|
||||
class Session(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.GameOptions.Session object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.game_joining_period = int(root.find("game_joining_period").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Session<game_joining_period = {self.game_joining_period}>"
|
||||
|
||||
|
||||
class GameSettings(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.GameOptions.GameSettings object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.is_shop_close_on = int(root.find("is_shop_close_on").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"GameSettings<is_shop_close_on = {self.is_shop_close_on}>"
|
||||
|
||||
|
||||
class GameOptions(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.GameOptions object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.stand_alone = StandAlone(root.find("stand_alone"))
|
||||
self.session = Session(root.find("session"))
|
||||
self.game_settings = GameSettings(root.find("game_settings"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"GameOptions<stand_alone = {self.stand_alone}, session = {self.session}, "
|
||||
f"game_settings = {self.game_settings}>"
|
||||
)
|
||||
|
||||
|
||||
class CoinOptions(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.CoinOptions object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.coin_slot = int(root.find("coin_slot").text)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"CoinOptions<coin_slot = {self.coin_slot}>"
|
||||
|
||||
|
||||
class Bookkeeping(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode.Bookkeeping object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.enable = itob(int(root.find("enable").text))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Bookkeeping<enable = {self.enable}>"
|
||||
|
||||
|
||||
class Testmode(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop.Testmode object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.send = itob(int(get_xml_attrib(root, "send")))
|
||||
self.sound_options = SoundOptions(root.find("sound_options"))
|
||||
self.game_options = GameOptions(root.find("game_options"))
|
||||
self.coin_options = CoinOptions(root.find("coin_options"))
|
||||
self.bookkeeping = Bookkeeping(root.find("bookkeeping"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f"Testmode<send = {self.send}, sound_options = {self.sound_options}, "
|
||||
f"game_options = {self.game_options}, coin_options = {self.coin_options}, "
|
||||
f"bookkeeping = {self.bookkeeping}>"
|
||||
)
|
||||
|
||||
|
||||
class Shop(object):
|
||||
"""
|
||||
Shopinfo.Regist.Shop object
|
||||
"""
|
||||
|
||||
def __init__(self, root: etree) -> None:
|
||||
self.name = root.find("name").text
|
||||
self.pref = int(root.find("pref").text)
|
||||
self.systemid = root.find("systemid").text
|
||||
self.softwareid = root.find("softwareid").text
|
||||
self.hardwareid = root.find("hardwareid").text
|
||||
self.locationid = root.find("locationid").text
|
||||
self.testmode = Testmode(root.find("testmode"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return (
|
||||
f'Shop<name = "{self.name}", pref = {self.pref}, '
|
||||
f'systemid = "{self.systemid}", softwareid = "{self.softwareid}", '
|
||||
f'hardwareid = "{self.hardwareid}", locationid = "{self.locationid}", '
|
||||
f"testmode = {self.testmode}>"
|
||||
)
|
||||
|
||||
|
||||
class Regist(object):
|
||||
"""
|
||||
Handle the Shopinfo Regist request.
|
||||
|
||||
Possibly just used to register machine info onto the server.
|
||||
|
||||
<call model="K32:J:B:A:2011033000" srcid="00010203040506070809">
|
||||
<shopinfo method="regist">
|
||||
<shop>
|
||||
<name __type="str">あ</name>
|
||||
<pref __type="s8">2</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">7</difficulty_standard>
|
||||
<max_stage_standard __type="u8">1</max_stage_standard>
|
||||
<long_music __type="u8">5</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">1</coin_slot>
|
||||
</coin_options>
|
||||
<bookkeeping>
|
||||
<enable __type="u8">0</enable>
|
||||
</bookkeeping>
|
||||
</testmode>
|
||||
</shop>
|
||||
</shopinfo>
|
||||
</call>
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, req: ServiceRequest) -> None:
|
||||
self.shop = Shop(req.xml[0].find("shop"))
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"Shopinfo.Regist<shop = {self.shop}>"
|
||||
|
||||
def response(self) -> etree:
|
||||
return load_xml_template("shopinfo", "regist")
|
||||
|
|
@ -5,3 +5,12 @@ def bool_to_int(value: bool) -> int:
|
|||
True = 1, False = 0
|
||||
"""
|
||||
return 1 if value else 0
|
||||
|
||||
|
||||
def int_to_bool(value: int) -> bool:
|
||||
"""
|
||||
Convert an integer to a boolean.
|
||||
|
||||
1 = True, 0 = False
|
||||
"""
|
||||
return False if value == 0 else True
|
||||
|
|
|
|||
|
|
@ -1,21 +1,10 @@
|
|||
import importlib
|
||||
from typing import Dict, Tuple
|
||||
|
||||
from flask import request
|
||||
|
||||
from v8_server import app
|
||||
from v8_server.eamuse.services import (
|
||||
CardMng,
|
||||
DLStatus,
|
||||
Facility,
|
||||
Local,
|
||||
Message,
|
||||
Package,
|
||||
PCBEvent,
|
||||
PCBTracker,
|
||||
ServiceRequest,
|
||||
Services,
|
||||
ServiceType,
|
||||
)
|
||||
from v8_server.eamuse.services import ServiceRequest, Services
|
||||
|
||||
|
||||
FlaskResponse = Tuple[bytes, Dict[str, str]]
|
||||
|
|
@ -54,70 +43,27 @@ def service_service(route: int) -> FlaskResponse:
|
|||
# simple as possible
|
||||
req = ServiceRequest(request)
|
||||
|
||||
if route == ServiceType.PCBTRACKER.value:
|
||||
if req.method == PCBTracker.ALIVE:
|
||||
response = PCBTracker.alive()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this PCBTracker Request: {req}")
|
||||
elif route == ServiceType.MESSAGE.value:
|
||||
if req.method == Message.GET:
|
||||
response = Message.get()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this Message Request: {req}")
|
||||
elif route == ServiceType.PCBEVENT.value:
|
||||
if req.method == PCBEvent.PUT:
|
||||
response = PCBEvent.put(req)
|
||||
else:
|
||||
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()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this Package Request: {req}")
|
||||
elif route == ServiceType.FACILITY.value:
|
||||
if req.method == Facility.GET:
|
||||
response = Facility.get()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this Facility Request: {req}")
|
||||
elif route == ServiceType.DLSTATUS.value:
|
||||
if req.method == DLStatus.PROGRESS:
|
||||
response = DLStatus.progress()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this DLStatus Request: {req}")
|
||||
elif route == ServiceType.CARDMNG.value:
|
||||
if req.method == CardMng.INQUIRE:
|
||||
response = CardMng.inquire(req)
|
||||
elif req.method == CardMng.GETREFID:
|
||||
response = CardMng.getrefid(req)
|
||||
elif req.method == CardMng.AUTHPASS:
|
||||
response = CardMng.authpass(req)
|
||||
elif req.method == CardMng.BINDMODEL:
|
||||
response = CardMng.bindmodel(req)
|
||||
elif req.method == CardMng.GETKEEPSPAN:
|
||||
response = CardMng.getkeepspan()
|
||||
elif req.method == CardMng.GETDATALIST:
|
||||
response = CardMng.getdatalist()
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this Cardmng Request: {req}")
|
||||
elif route == ServiceType.LOCAL.value:
|
||||
if req.module == Local.SHOPINFO:
|
||||
response = Local.shopinfo(req)
|
||||
elif req.module == Local.DEMODATA:
|
||||
response = Local.demodata(req)
|
||||
elif req.module == Local.CARDUTIL:
|
||||
response = Local.cardutil(req)
|
||||
elif req.module == Local.GAMEINFO:
|
||||
response = Local.gameinfo(req)
|
||||
elif req.module == Local.GAMEEND:
|
||||
response = Local.gameend(req)
|
||||
elif req.module == Local.GAMETOP:
|
||||
response = Local.gametop(req)
|
||||
elif req.module == Local.CUSTOMIZE:
|
||||
response = Local.customize(req)
|
||||
else:
|
||||
raise Exception(f"Not sure how to handle this Local Request: {req}")
|
||||
if req.method is not None:
|
||||
method = req.method.title().replace("_", "")
|
||||
try:
|
||||
module = importlib.import_module(f"v8_server.eamuse.services.{req.module}")
|
||||
except ModuleNotFoundError:
|
||||
app.logger.error(f"No Module found for request: {req}")
|
||||
raise
|
||||
|
||||
try:
|
||||
cls = getattr(module, method)
|
||||
except AttributeError:
|
||||
app.logger.error(f"No Class found for request: {req}")
|
||||
raise
|
||||
|
||||
inst = cls(req)
|
||||
app.logger.debug(inst)
|
||||
response = inst.response()
|
||||
else:
|
||||
print(route)
|
||||
raise Exception(f"Not sure how to handle this Request: {req}")
|
||||
|
||||
return req.response(response)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user