mirror of
https://github.com/573dev/gfdm-server.git
synced 2026-10-24 00:52:39 -05:00
526 lines
23 KiB
Python
526 lines
23 KiB
Python
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.model.user import PlayData, User, UserData
|
|
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 = itob(int(root.find("clear").text))
|
|
self.auto_clear = itob(int(root.find("auto_clear").text))
|
|
self.score = int(root.find("score").text)
|
|
self.flags = int(root.find("flags").text)
|
|
self.fullcombo = itob(int(root.find("fullcombo").text))
|
|
self.excellent = itob(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()
|
|
|
|
# Save player data
|
|
playerinfo = self.player.playerinfo
|
|
user = User.from_refid(playerinfo.refid)
|
|
if user is not None:
|
|
user_data = UserData.from_userid(user.userid)
|
|
|
|
if user_data is None:
|
|
raise Exception("user data shouldn't be none here")
|
|
|
|
user_data.style = playerinfo.styles
|
|
user_data.style_2 = playerinfo.styles_2
|
|
user_data.secret_music = playerinfo.secret_music
|
|
user_data.secret_chara = playerinfo.secret_chara
|
|
user_data.perfect = playerinfo.perfect
|
|
user_data.great = playerinfo.great
|
|
user_data.good = playerinfo.good
|
|
user_data.poor = playerinfo.poor
|
|
user_data.miss = playerinfo.miss
|
|
user_data.time = playerinfo.time
|
|
db.session.commit()
|
|
else:
|
|
raise Exception("This user doesn't exist")
|
|
|
|
# Save playdata
|
|
for idx, data in enumerate(self.player.playdata):
|
|
musicid = self.modedata.stages[idx].musicid
|
|
play_data = PlayData(
|
|
userid=user.userid,
|
|
no=data.no,
|
|
musicid=musicid,
|
|
seqmode=data.seqmode,
|
|
clear=data.clear,
|
|
auto_clear=data.auto_clear,
|
|
score=data.score,
|
|
flags=data.flags,
|
|
fullcombo=data.fullcombo,
|
|
excellent=data.excellent,
|
|
combo=data.combo,
|
|
skill_point=data.skill_point,
|
|
skill_perc=data.skill_perc,
|
|
result_rank=data.result_rank,
|
|
difficulty=data.difficulty,
|
|
combo_rate=data.combo_rate,
|
|
perfect_rate=data.perfect_rate,
|
|
)
|
|
db.session.add(play_data)
|
|
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)
|