Files
2026-01-26 18:48:28 -05:00

480 lines
19 KiB
Python

import re
from database import (
getDMGFPlaylogbyToken,
getDMGFProfileDetailsbyToken,
getDMGFProfileExtbyToken,
getEacnetProfilebyToken,
getDMGFProfilebyToken,
add_user_DMGF,
manage_user_DMGF,
manage_user_DMGF_Details,
update_DMGF_playlog,
)
from variables.strings.games.gitadora import (
gitadoraNewPlayerData,
gitadoraPlayerData,
gitadoraRegisterData,
gitadoraMusicDB,
gitadoraFullPlayerData,
gitadoraGameStatus,
gitadoraGameEnd,
gitadoraStageResult,
gitadoraMusicItem,
customDataDefault,
favMusicDefault
)
from variables.strings.common import genericError
from variables.protocols import EAC_XML, EAC_RESULT
from time import time
from random import choices
import xmltodict
def clamp_u64(value):
"""Clamp value to valid u64 range"""
try:
val = int(float(value))
return max(0, min(val, 18446744073709551615))
except:
return 0
def knst_cardutil_return(playStyle, userProfile, playerIdentification):
skill = 0
allSkill = 0
if playStyle == "GF":
skill = userProfile.GFskill
allSkill = userProfile.GFallSkill
elif playStyle == "DM":
skill = userProfile.DMskill
allSkill = userProfile.DMallSkill
return gitadoraPlayerData.format(refid=playerIdentification.refid,snsid=playerIdentification.snsid,usercode=userProfile.usercode,skill=skill,allSkill=allSkill).encode()
def gitadoraRelay(module, method, data, playerToken):
print(f"{module} {method}")
playerIdentification = getEacnetProfilebyToken(playerToken)
playStyle = data.get("gametype", {}).get("#text", "U32:J:A") # Default to GF if playstyle is not avalible
match playStyle:
case "U32:J:A":
playStyle = "GF"
case "U32:J:B":
playStyle = "DM"
match module:
case "knst_playablemusic":
match method:
case "get":
return gitadoraMusicDB
case "knst_gameinfo":
match method:
case "get":
return gitadoraGameStatus
case "knst_cardutil":
match method:
case "check":
userProfile = getDMGFProfilebyToken(playerToken)
if userProfile is None:
return gitadoraNewPlayerData
return knst_cardutil_return(playStyle,userProfile,playerIdentification)
case "regist":
newUserCode = ''.join(choices('0123456789ABCDEF', k=10))
userProfile = getDMGFProfilebyToken(playerToken)
userProfileExt = getDMGFProfileExtbyToken(playerToken)
userProfileDetails = getDMGFProfileDetailsbyToken(playerToken)
if userProfile is None:
manage_user_DMGF_Details(playerIdentification.refid,playerToken,[],"")
manage_user_DMGF(playerIdentification.refid,playerToken,"","","","")
newUser = add_user_DMGF(playerIdentification.refid,playerToken,playerIdentification.snsid,newUserCode)
if newUser is not None:
return gitadoraRegisterData.format(refid=playerIdentification.refid,snsid=playerIdentification.snsid,usercode=newUserCode).encode()
else:
print("throwing generic error")
return genericError.format(protocol=EAC_XML,result=EAC_RESULT)
# Something went wrong with the user Registration, and it needs to start over again.
else:
print("Registering new card for user ")
return gitadoraRegisterData.format(refid=playerIdentification.refid,snsid=playerIdentification.snsid,usercode=newUserCode).encode()
case "knst_gametop":
match method:
case "get":
userProfile = getDMGFProfilebyToken(playerToken)
userProfileExt = getDMGFProfileExtbyToken(playerToken)
userProfileDetails = getDMGFProfileDetailsbyToken(playerToken)
stageResult = '<stage_result />'
musiclist = '<musiclist nr="0" />'
playlogs = getDMGFPlaylogbyToken(playerToken, playStyle)
playstyle = customDataDefault
custom = customDataDefault
lastCategory = 0
lastMusicID = -1
lastSeq = 0
dispLevel = 0
cabid = 0
play = 0
playtime = 0
playterm = 0
session_cnt = 0
matching_num = 0
extra_stage = 0
extra_play = 0
extra_clear = 0
encore_play = 0
encore_clear = 0
pencore_play = 0
pencore_clear = 0
max_clear_diff = 0
max_full_diff = 0
max_exce_diff = 0
clear_num = 0
full_num = 0
exce_num = 0
no_num = 0
e_num = 0
d_num = 0
c_num = 0
b_num = 0
a_num = 0
s_num = 0
ss_num = 0
musicFavorites1 = favMusicDefault
musicFavorites2 = favMusicDefault
musicFavorites3 = favMusicDefault
if playlogs and len(playlogs) > 0:
gitadoraMusicDBdict = xmltodict.parse(gitadoraMusicDB.decode())
# Generate stage results
musicItems = {} # Dictionary to store music data grouped by musicid
# Group playlogs by musicid
for playlog in playlogs:
if playlog.musicid not in musicItems:
musicItems[playlog.musicid] = {
'musicid': playlog.musicid,
'sequences': {
1: None, # Guitar Basic
2: None, # Guitar Advanced
3: None, # Guitar Extreme
4: None, # Guitar Master
5: None, # Bass Basic
6: None, # Bass Advanced
7: None, # Bass Extreme
8: None # Bass Master
}
}
# Get current data for this sequence
current_data = musicItems[playlog.musicid]['sequences'][playlog.seq]
# Determine if we should replace the existing data
should_replace = False
if current_data is None:
should_replace = True
else:
# Check importance ladder
if playlog.excellent:
# Replace if current isn't excellent or if both excellent but new perc is higher
if not current_data['excellent'] or (current_data['excellent'] and playlog.perc > current_data['perc']):
should_replace = True
elif playlog.fullcombo:
# Replace if current isn't excellent and isn't fullcombo
if not current_data['excellent'] and not current_data['fullcombo']:
should_replace = True
elif playlog.clear:
# Replace if current isn't excellent, isn't fullcombo, and isn't clear
if not current_data['excellent'] and not current_data['fullcombo'] and not current_data['clear']:
should_replace = True
# Only update if we should replace
if should_replace:
musicItems[playlog.musicid]['sequences'][playlog.seq] = {
'stage_no': playlog.stage_no,
'skill': playlog.skill,
'new_skill': playlog.new_skill,
'clear': playlog.clear,
'auto_clear': playlog.auto_clear,
'fullcombo': playlog.fullcombo,
'excellent': playlog.excellent,
'medal': playlog.medal,
'perc': playlog.perc,
'new_perc': playlog.new_perc,
'rank': playlog.rank,
'score': playlog.score,
'combo': playlog.combo,
'max_combo_perc': playlog.max_combo_perc,
'flags': playlog.flags,
'phrase_combo_perc': playlog.phrase_combo_perc,
'meter': playlog.meter,
'meter_prog': playlog.meter_prog
}
musiclistPrep = ""
musiclistLength = 0
for musicid, data in musicItems.items():
print(musicid)
flagFC = 0
flagEX = 0
flagCLR = 0
# Initialize arrays with correct length and default values
meter = ["0"]*8 # Array of 8 zeros as strings
meterProg = [0]*8 # Array of 8 zeros
mdata = [-1] + [-1]*14 + [0]*2 # 17 elements total
sdataSeq = -1
sdataSkill = -1
best_skill = -1 # Track the best skill
for seq, seqData in data["sequences"].items():
try:
seq = int(seq)
print(f"Processing sequence {seq} with data:", seqData)
if seqData is not None:
# Update skill data if this sequence has a higher skill
if seqData["skill"] > best_skill:
best_skill = seqData["skill"]
sdataSeq = seq
sdataSkill = seqData["skill"]
flagFC += seqData["fullcombo"] * 2**seq
flagEX += seqData["excellent"] * 2**seq
flagCLR += seqData["clear"] * 2**seq
# Safely handle meter values
if seqData["meter"]:
try:
# Clamp meter value to valid u64 range
meter[seq-1] = str(clamp_u64(seqData["meter"]))
except Exception as e:
print(f"Error processing meter for seq {seq}: {e}")
meter[seq-1] = "0"
try:
meterProg[seq-1] = int(seqData["meter_prog"])
except (ValueError, TypeError):
print(f"Invalid meter_prog value for seq {seq}: {seqData['meter_prog']}")
meterProg[seq-1] = 0
# Only set perc/rank if the chart was cleared
if seqData["clear"]:
try:
mdata[seq] = int(seqData.get("perc", -2))
mdata[seq+8] = int(seqData.get("rank", 0))
except (ValueError, TypeError) as e:
print(f"Error processing perc/rank for seq {seq}: {e}")
mdata[seq] = -2
mdata[seq+8] = 0
except Exception as e:
print(f"Error processing sequence {seq}: {e}")
continue
# Format the music item
musiclistPrep += gitadoraMusicItem.format(
musicId=musicid,
flag=f"{flagFC} {flagEX} {flagCLR} 0",
sdata=f"{sdataSeq} {sdataSkill}",
mdata=" ".join(str(x) for x in mdata),
meter=" ".join(meter),
meterProg=" ".join(str(x) for x in meterProg)
)
musiclistLength += 1
musiclist = f'<musiclist nr="{musiclistLength}">{musiclistPrep}</musiclist>'
# constructing the stageResults
stageResults = ""
for playlog in playlogs:
# Find the musicid in the gitadoraMusicDBdict
# Find the matching music entry in the musicinfo list
music_info = None
for music in gitadoraMusicDBdict["eacnet"]["response"]["knst_playablemusic"]["musicinfo"]["music"]:
if music["id"]["#text"] == str(playlog.musicid):
music_info = music
break
stageResults += gitadoraStageResult.format(
dateMs=playlog.date_ms,
stage=playlog.stage_no,
skill=playlog.skill,
musicId=playlog.musicid,
diff=music_info["diff"]["#text"].split()[playlog.seq], # Get difficulty from music_info
seqmode=playlog.seq,
musicTitle=music_info.get("music_title", {}).get("#text", ""),
musicArtist=music_info.get("artist", {}).get("#text", ""),
rightsCredits=music_info.get("right_credit", {}).get("#text", ""),
clearStatus=playlog.clear,
rank=playlog.rank,
perfect=playlog.perfect,
great=playlog.great,
good=playlog.good,
ok=playlog.ok,
miss=playlog.miss,
perfectPerc=playlog.perfect_perc,
greatPerc=playlog.great_perc,
goodPerc=playlog.good_perc,
okPerc=playlog.ok_perc,
missPerc=playlog.miss_perc,
maxCombo=playlog.combo,
maxComboPerc=playlog.max_combo_perc,
score=playlog.score,
flags=playlog.flags,
point=playlog.skill, # Using skill as point
newPoint=playlog.new_skill,
perc=playlog.perc,
newPerc=playlog.new_perc,
meter=playlog.meter,
meterProg=playlog.meter_prog,
beforeMeter=playlog.before_meter,
beforeMeterProg=playlog.before_meter_prog,
isNewMeter=playlog.is_new_meter,
phraseDataNum=playlog.phrase_data_num,
phraseAddr=playlog.phrase_addr,
phraseType=playlog.phrase_type,
phraseStatus=playlog.phrase_status,
phraseEndAddr=playlog.phrase_end_addr,
phraseComboPerc=playlog.phrase_combo_perc
)
if stageResults:
stageResult = f"<stage_result>{stageResults}</stage_result>"
else:
stageResult = "<stage_result />"
if playStyle == "GF":
playstyle = userProfileExt.GFplaystyle
custom = userProfileExt.GFcustom
lastCategory = userProfileExt.GFlastCategory
lastMusicID = userProfileExt.GFlastMusic
lastSeq = userProfileExt.GFlastSeq
dispLevel = userProfileExt.GFdisplayLevel
cabid = userProfileDetails.GFcabid
play = userProfileDetails.GFplay
playtime = userProfileDetails.GFplaytime
playterm = userProfileDetails.GFplayterm
session_cnt = userProfileDetails.GFsession_cnt
matching_num = userProfileDetails.GFmatching_num
extra_stage = userProfileDetails.GFextra_stage
extra_play = userProfileDetails.GFextra_play
extra_clear = userProfileDetails.GFextra_clear
encore_play = userProfileDetails.GFencore_play
encore_clear = userProfileDetails.GFencore_clear
pencore_play = userProfileDetails.GFpencore_play
pencore_clear = userProfileDetails.GFpencore_clear
max_clear_diff = userProfileDetails.GFmax_clear_diff
max_full_diff = userProfileDetails.GFmax_full_diff
max_exce_diff = userProfileDetails.GFmax_exce_diff
clear_num = userProfileDetails.GFclear_num
full_num = userProfileDetails.GFfull_num
exce_num = userProfileDetails.GFexce_num
no_num = userProfileDetails.GFno_num
e_num = userProfileDetails.GFe_num
d_num = userProfileDetails.GFd_num
c_num = userProfileDetails.GFc_num
b_num = userProfileDetails.GFb_num
a_num = userProfileDetails.GFa_num
s_num = userProfileDetails.GFs_num
ss_num = userProfileDetails.GFss_num
musicFavorites1 = userProfileExt.GFmusicFavorites1
musicFavorites2 = userProfileExt.GFmusicFavorites2
musicFavorites3 = userProfileExt.GFmusicFavorites3
elif playStyle == "DM":
playstyle = userProfileExt.DMplaystyle
custom = userProfileExt.DMcustom
lastCategory = userProfileExt.DMlastCategory
lastMusicID = userProfileExt.DMlastMusic
lastSeq = userProfileExt.DMlastSeq
dispLevel = userProfileExt.DMdisplayLevel
cabid = userProfileDetails.DMcabid
play = userProfileDetails.DMplay
playtime = userProfileDetails.DMplaytime
playterm = userProfileDetails.DMplayterm
session_cnt = userProfileDetails.DMsession_cnt
matching_num = userProfileDetails.DMmatching_num
extra_stage = userProfileDetails.DMextra_stage
extra_play = userProfileDetails.DMextra_play
extra_clear = userProfileDetails.DMextra_clear
encore_play = userProfileDetails.DMencore_play
encore_clear = userProfileDetails.DMencore_clear
pencore_play = userProfileDetails.DMpencore_play
pencore_clear = userProfileDetails.DMpencore_clear
max_clear_diff = userProfileDetails.DMmax_clear_diff
max_full_diff = userProfileDetails.DMmax_full_diff
max_exce_diff = userProfileDetails.DMmax_exce_diff
clear_num = userProfileDetails.DMclear_num
full_num = userProfileDetails.DMfull_num
exce_num = userProfileDetails.DMexce_num
no_num = userProfileDetails.DMno_num
e_num = userProfileDetails.DMe_num
d_num = userProfileDetails.DMd_num
c_num = userProfileDetails.DMc_num
b_num = userProfileDetails.DMb_num
a_num = userProfileDetails.DMa_num
s_num = userProfileDetails.DMs_num
ss_num = userProfileDetails.DMss_num
musicFavorites1 = userProfileExt.DMmusicFavorites1
musicFavorites2 = userProfileExt.DMmusicFavorites2
musicFavorites3 = userProfileExt.DMmusicFavorites3
return gitadoraFullPlayerData.format(
refid=playerIdentification.refid,
snsid=playerIdentification.snsid,
usercode=userProfile.usercode,
time=int(time()),
playstyle=playstyle,
custom=custom,
lastCategory=lastCategory,
lastMusicID=lastMusicID,
lastSeq=lastSeq,
dispLevel=dispLevel,
cabid=cabid,
play=play,
playtime=playtime,
playterm=playterm,
session_cnt=session_cnt,
matching_num=matching_num,
extra_stage=extra_stage,
extra_play=extra_play,
extra_clear=extra_clear,
encore_play=encore_play,
encore_clear=encore_clear,
pencore_play=pencore_play,
pencore_clear=pencore_clear,
max_clear_diff=max_clear_diff,
max_full_diff=max_full_diff,
max_exce_diff=max_exce_diff,
clear_num=clear_num,
full_num=full_num,
exce_num=exce_num,
no_num=no_num,
e_num=e_num,
d_num=d_num,
c_num=c_num,
b_num=b_num,
a_num=a_num,
s_num=s_num,
ss_num=ss_num,
musicFavorites1=musicFavorites1,
musicFavorites2=musicFavorites2,
musicFavorites3=musicFavorites3,
stageResult=stageResult,
musicList=musiclist
).encode()
case "knst_gameend":
match method:
case "regist": # game is saved here, every time you complete a song
playerData = data["player"]
customData = playerData["customdata"]
skillData = playerData["skilldata"]
record = playerData["record"]
favoritemusic = playerData["favoritemusic"]
playinfo = playerData["playinfo"]
stage = playerData.get("stage", {})
manage_user_DMGF(playerIdentification.refid,playerToken,customData,favoritemusic,playinfo,playStyle)
manage_user_DMGF_Details(playerIdentification.refid,playerToken,playinfo,playStyle)
if stage:
update_DMGF_playlog(playerIdentification.refid, playerToken, stage,playStyle)
return gitadoraGameEnd
case _: # Backup Case
return b"NoMatches"