forked from Hay1tsme/artemis
develop #11
@ -2,5 +2,5 @@ from .base import ADBBaseRequest, ADBBaseResponse, ADBHeader, ADBHeaderException
|
|||||||
from .base import CompanyCodes, ReaderFwVer, CMD_CODE_GOODBYE, HEADER_SIZE
|
from .base import CompanyCodes, ReaderFwVer, CMD_CODE_GOODBYE, HEADER_SIZE
|
||||||
from .lookup import ADBLookupRequest, ADBLookupResponse, ADBLookupExResponse
|
from .lookup import ADBLookupRequest, ADBLookupResponse, ADBLookupExResponse
|
||||||
from .campaign import ADBCampaignClearRequest, ADBCampaignClearResponse, ADBCampaignResponse, ADBOldCampaignRequest, ADBOldCampaignResponse
|
from .campaign import ADBCampaignClearRequest, ADBCampaignClearResponse, ADBCampaignResponse, ADBOldCampaignRequest, ADBOldCampaignResponse
|
||||||
from .felica import ADBFelicaLookupRequest, ADBFelicaLookupResponse, ADBFelicaLookup2Request, ADBFelicaLookup2Response
|
from .felica import ADBFelicaLookupRequest, ADBFelicaLookupResponse, ADBFelicaLookupExRequest, ADBFelicaLookupExResponse
|
||||||
from .log import ADBLogExRequest, ADBLogRequest, ADBStatusLogRequest, ADBLogExResponse
|
from .log import ADBLogExRequest, ADBLogRequest, ADBStatusLogRequest, ADBLogExResponse
|
||||||
|
@ -35,7 +35,7 @@ class ADBFelicaLookupResponse(ADBBaseResponse):
|
|||||||
|
|
||||||
return self.head.make() + resp_struct
|
return self.head.make() + resp_struct
|
||||||
|
|
||||||
class ADBFelicaLookup2Request(ADBBaseRequest):
|
class ADBFelicaLookupExRequest(ADBBaseRequest):
|
||||||
def __init__(self, data: bytes) -> None:
|
def __init__(self, data: bytes) -> None:
|
||||||
super().__init__(data)
|
super().__init__(data)
|
||||||
self.random = struct.unpack_from("<16s", data, 0x20)[0]
|
self.random = struct.unpack_from("<16s", data, 0x20)[0]
|
||||||
@ -46,7 +46,7 @@ class ADBFelicaLookup2Request(ADBBaseRequest):
|
|||||||
self.company = CompanyCodes(int.from_bytes(company, 'little'))
|
self.company = CompanyCodes(int.from_bytes(company, 'little'))
|
||||||
self.fw_ver = ReaderFwVer.from_byte(fw_ver)
|
self.fw_ver = ReaderFwVer.from_byte(fw_ver)
|
||||||
|
|
||||||
class ADBFelicaLookup2Response(ADBBaseResponse):
|
class ADBFelicaLookupExResponse(ADBBaseResponse):
|
||||||
def __init__(self, user_id: Union[int, None] = None, access_code: Union[str, None] = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x12, length: int = 0x130, status: int = 1) -> None:
|
def __init__(self, user_id: Union[int, None] = None, access_code: Union[str, None] = None, game_id: str = "SXXX", store_id: int = 1, keychip_id: str = "A69E01A8888", code: int = 0x12, length: int = 0x130, status: int = 1) -> None:
|
||||||
super().__init__(code, length, status, game_id, store_id, keychip_id)
|
super().__init__(code, length, status, game_id, store_id, keychip_id)
|
||||||
self.user_id = user_id if user_id is not None else -1
|
self.user_id = user_id if user_id is not None else -1
|
||||||
@ -56,7 +56,7 @@ class ADBFelicaLookup2Response(ADBBaseResponse):
|
|||||||
self.auth_key = [0] * 256
|
self.auth_key = [0] * 256
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookup2Response":
|
def from_req(cls, req: ADBHeader, user_id: Union[int, None] = None, access_code: Union[str, None] = None) -> "ADBFelicaLookupExResponse":
|
||||||
c = cls(user_id, access_code, req.game_id, req.store_id, req.keychip_id)
|
c = cls(user_id, access_code, req.game_id, req.store_id, req.keychip_id)
|
||||||
c.head.protocol_ver = req.protocol_ver
|
c.head.protocol_ver = req.protocol_ver
|
||||||
return c
|
return c
|
||||||
|
@ -176,6 +176,12 @@ class AimedbServlette():
|
|||||||
|
|
||||||
async def handle_lookup(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
async def handle_lookup(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
||||||
req = ADBLookupRequest(data)
|
req = ADBLookupRequest(data)
|
||||||
|
if req.access_code == "00000000000000000000":
|
||||||
|
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||||
|
ret = ADBLookupResponse.from_req(req.head, -1)
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
||||||
is_banned = await self.data.card.get_card_banned(req.access_code)
|
is_banned = await self.data.card.get_card_banned(req.access_code)
|
||||||
is_locked = await self.data.card.get_card_locked(req.access_code)
|
is_locked = await self.data.card.get_card_locked(req.access_code)
|
||||||
@ -201,6 +207,12 @@ class AimedbServlette():
|
|||||||
|
|
||||||
async def handle_lookup_ex(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
async def handle_lookup_ex(self, data: bytes, resp_code: int) -> ADBBaseResponse:
|
||||||
req = ADBLookupRequest(data)
|
req = ADBLookupRequest(data)
|
||||||
|
if req.access_code == "00000000000000000000":
|
||||||
|
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||||
|
ret = ADBLookupExResponse.from_req(req.head, -1)
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
user_id = await self.data.card.get_user_id_from_card(req.access_code)
|
||||||
|
|
||||||
is_banned = await self.data.card.get_card_banned(req.access_code)
|
is_banned = await self.data.card.get_card_banned(req.access_code)
|
||||||
@ -241,6 +253,12 @@ class AimedbServlette():
|
|||||||
"""
|
"""
|
||||||
req = ADBFelicaLookupRequest(data)
|
req = ADBFelicaLookupRequest(data)
|
||||||
idm = req.idm.zfill(16)
|
idm = req.idm.zfill(16)
|
||||||
|
if idm == "0000000000000000":
|
||||||
|
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||||
|
ret = ADBFelicaLookupResponse.from_req(req.head, "00000000000000000000")
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
card = await self.data.card.get_card_by_idm(idm)
|
card = await self.data.card.get_card_by_idm(idm)
|
||||||
if not card:
|
if not card:
|
||||||
ac = self.data.card.to_access_code(idm)
|
ac = self.data.card.to_access_code(idm)
|
||||||
@ -262,6 +280,14 @@ class AimedbServlette():
|
|||||||
because we don't implement felica_lookup properly.
|
because we don't implement felica_lookup properly.
|
||||||
"""
|
"""
|
||||||
req = ADBFelicaLookupRequest(data)
|
req = ADBFelicaLookupRequest(data)
|
||||||
|
idm = req.idm.zfill(16)
|
||||||
|
|
||||||
|
if idm == "0000000000000000":
|
||||||
|
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||||
|
ret = ADBFelicaLookupResponse.from_req(req.head, "00000000000000000000")
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
ac = self.data.card.to_access_code(req.idm)
|
ac = self.data.card.to_access_code(req.idm)
|
||||||
|
|
||||||
if self.config.server.allow_user_registration:
|
if self.config.server.allow_user_registration:
|
||||||
@ -292,9 +318,16 @@ class AimedbServlette():
|
|||||||
return ADBFelicaLookupResponse.from_req(req.head, ac)
|
return ADBFelicaLookupResponse.from_req(req.head, ac)
|
||||||
|
|
||||||
async def handle_felica_lookup_ex(self, data: bytes, resp_code: int) -> bytes:
|
async def handle_felica_lookup_ex(self, data: bytes, resp_code: int) -> bytes:
|
||||||
req = ADBFelicaLookup2Request(data)
|
req = ADBFelicaLookupExRequest(data)
|
||||||
user_id = None
|
user_id = None
|
||||||
idm = req.idm.zfill(16)
|
idm = req.idm.zfill(16)
|
||||||
|
|
||||||
|
if idm == "0000000000000000":
|
||||||
|
self.logger.warn(f"All-zero IDm from {req.head.keychip_id}")
|
||||||
|
ret = ADBFelicaLookupExResponse.from_req(req.head, -1, "00000000000000000000")
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
card = await self.data.card.get_card_by_idm(idm)
|
card = await self.data.card.get_card_by_idm(idm)
|
||||||
if not card:
|
if not card:
|
||||||
access_code = self.data.card.to_access_code(idm)
|
access_code = self.data.card.to_access_code(idm)
|
||||||
@ -314,7 +347,7 @@ class AimedbServlette():
|
|||||||
f"idm {idm} ipm {req.pmm} -> access_code {access_code} user_id {user_id}"
|
f"idm {idm} ipm {req.pmm} -> access_code {access_code} user_id {user_id}"
|
||||||
)
|
)
|
||||||
|
|
||||||
resp = ADBFelicaLookup2Response.from_req(req.head, user_id, access_code)
|
resp = ADBFelicaLookupExResponse.from_req(req.head, user_id, access_code)
|
||||||
|
|
||||||
if user_id > 0:
|
if user_id > 0:
|
||||||
if card['is_banned'] and card['is_locked']:
|
if card['is_banned'] and card['is_locked']:
|
||||||
@ -348,6 +381,12 @@ class AimedbServlette():
|
|||||||
req = ADBLookupRequest(data)
|
req = ADBLookupRequest(data)
|
||||||
user_id = -1
|
user_id = -1
|
||||||
|
|
||||||
|
if req.access_code == "00000000000000000000":
|
||||||
|
self.logger.warn(f"All-zero access code from {req.head.keychip_id}")
|
||||||
|
ret = ADBLookupResponse.from_req(req.head, -1)
|
||||||
|
ret.head.status = ADBStatus.BAN_SYS
|
||||||
|
return ret
|
||||||
|
|
||||||
if self.config.server.allow_user_registration:
|
if self.config.server.allow_user_registration:
|
||||||
user_id = await self.data.user.create_user()
|
user_id = await self.data.user.create_user()
|
||||||
|
|
||||||
|
@ -19,11 +19,13 @@ class ChuniConstants:
|
|||||||
VER_CHUNITHM_CRYSTAL = 8
|
VER_CHUNITHM_CRYSTAL = 8
|
||||||
VER_CHUNITHM_CRYSTAL_PLUS = 9
|
VER_CHUNITHM_CRYSTAL_PLUS = 9
|
||||||
VER_CHUNITHM_PARADISE = 10
|
VER_CHUNITHM_PARADISE = 10
|
||||||
|
|
||||||
VER_CHUNITHM_NEW = 11
|
VER_CHUNITHM_NEW = 11
|
||||||
VER_CHUNITHM_NEW_PLUS = 12
|
VER_CHUNITHM_NEW_PLUS = 12
|
||||||
VER_CHUNITHM_SUN = 13
|
VER_CHUNITHM_SUN = 13
|
||||||
VER_CHUNITHM_SUN_PLUS = 14
|
VER_CHUNITHM_SUN_PLUS = 14
|
||||||
VER_CHUNITHM_LUMINOUS = 15
|
VER_CHUNITHM_LUMINOUS = 15
|
||||||
|
|
||||||
VERSION_NAMES = [
|
VERSION_NAMES = [
|
||||||
"CHUNITHM",
|
"CHUNITHM",
|
||||||
"CHUNITHM PLUS",
|
"CHUNITHM PLUS",
|
||||||
@ -43,6 +45,37 @@ class ChuniConstants:
|
|||||||
"CHUNITHM LUMINOUS",
|
"CHUNITHM LUMINOUS",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
SCORE_RANK_INTERVALS_OLD = [
|
||||||
|
(1007500, "SSS"),
|
||||||
|
(1000000, "SS"),
|
||||||
|
( 975000, "S"),
|
||||||
|
( 950000, "AAA"),
|
||||||
|
( 925000, "AA"),
|
||||||
|
( 900000, "A"),
|
||||||
|
( 800000, "BBB"),
|
||||||
|
( 700000, "BB"),
|
||||||
|
( 600000, "B"),
|
||||||
|
( 500000, "C"),
|
||||||
|
( 0, "D"),
|
||||||
|
]
|
||||||
|
|
||||||
|
SCORE_RANK_INTERVALS_NEW = [
|
||||||
|
(1009000, "SSS+"), # New only
|
||||||
|
(1007500, "SSS"),
|
||||||
|
(1005000, "SS+"), # New only
|
||||||
|
(1000000, "SS"),
|
||||||
|
( 990000, "S+"), # New only
|
||||||
|
( 975000, "S"),
|
||||||
|
( 950000, "AAA"),
|
||||||
|
( 925000, "AA"),
|
||||||
|
( 900000, "A"),
|
||||||
|
( 800000, "BBB"),
|
||||||
|
( 700000, "BB"),
|
||||||
|
( 600000, "B"),
|
||||||
|
( 500000, "C"),
|
||||||
|
( 0, "D"),
|
||||||
|
]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def game_ver_to_string(cls, ver: int):
|
def game_ver_to_string(cls, ver: int):
|
||||||
return cls.VERSION_NAMES[ver]
|
return cls.VERSION_NAMES[ver]
|
||||||
|
@ -13,6 +13,69 @@ from .config import ChuniConfig
|
|||||||
from .const import ChuniConstants
|
from .const import ChuniConstants
|
||||||
|
|
||||||
|
|
||||||
|
def pairwise(iterable):
|
||||||
|
# https://docs.python.org/3/library/itertools.html#itertools.pairwise
|
||||||
|
# but for Python < 3.10. pairwise('ABCDEFG') → AB BC CD DE EF FG
|
||||||
|
iterator = iter(iterable)
|
||||||
|
a = next(iterator, None)
|
||||||
|
for b in iterator:
|
||||||
|
yield a, b
|
||||||
|
a = b
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_song_rank(score: int, game_version: int) -> str:
|
||||||
|
if game_version >= ChuniConstants.VER_CHUNITHM_NEW:
|
||||||
|
intervals = ChuniConstants.SCORE_RANK_INTERVALS_NEW
|
||||||
|
else:
|
||||||
|
intervals = ChuniConstants.SCORE_RANK_INTERVALS_OLD
|
||||||
|
|
||||||
|
for (min_score, rank) in intervals:
|
||||||
|
if score >= min_score:
|
||||||
|
return rank
|
||||||
|
|
||||||
|
return "D"
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_song_rating(score: int, chart_constant: float, game_version: int) -> float:
|
||||||
|
is_new = game_version >= ChuniConstants.VER_CHUNITHM_NEW
|
||||||
|
|
||||||
|
if is_new: # New and later
|
||||||
|
max_score = 1009000
|
||||||
|
max_rating_modifier = 2.15
|
||||||
|
else: # Up to Paradise Lost
|
||||||
|
max_score = 1007500
|
||||||
|
max_rating_modifier = 2.0
|
||||||
|
|
||||||
|
if (score < 500000):
|
||||||
|
return 0.0 # D
|
||||||
|
elif (score >= max_score):
|
||||||
|
return chart_constant + max_rating_modifier # SSS/SSS+
|
||||||
|
|
||||||
|
# Okay, we're doing this the hard way.
|
||||||
|
# Rating goes up linearly between breakpoints listed below.
|
||||||
|
# Pick the score interval in which we are in, then calculate
|
||||||
|
# the position between possible ratings.
|
||||||
|
score_intervals = [
|
||||||
|
( 500000, 0.0), # C
|
||||||
|
( 800000, max(0.0, (chart_constant - 5.0) / 2)), # BBB
|
||||||
|
( 900000, max(0.0, (chart_constant - 5.0))), # A
|
||||||
|
( 925000, max(0.0, (chart_constant - 3.0))), # AA
|
||||||
|
( 975000, chart_constant), # S
|
||||||
|
(1000000, chart_constant + 1.0), # SS
|
||||||
|
(1005000, chart_constant + 1.5), # SS+
|
||||||
|
(1007500, chart_constant + 2.0), # SSS
|
||||||
|
(1009000, chart_constant + max_rating_modifier), # SSS+!
|
||||||
|
]
|
||||||
|
|
||||||
|
for ((lo_score, lo_rating), (hi_score, hi_rating)) in pairwise(score_intervals):
|
||||||
|
if not (lo_score <= score < hi_score):
|
||||||
|
continue
|
||||||
|
|
||||||
|
interval_pos = (score - lo_score) / (hi_score - lo_score)
|
||||||
|
return lo_rating + ((hi_rating - lo_rating) * interval_pos)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ChuniFrontend(FE_Base):
|
class ChuniFrontend(FE_Base):
|
||||||
def __init__(
|
def __init__(
|
||||||
self, cfg: CoreConfig, environment: jinja2.Environment, cfg_dir: str
|
self, cfg: CoreConfig, environment: jinja2.Environment, cfg_dir: str
|
||||||
@ -91,37 +154,27 @@ class ChuniFrontend(FE_Base):
|
|||||||
base_list=[]
|
base_list=[]
|
||||||
if profile and rating:
|
if profile and rating:
|
||||||
song_records = []
|
song_records = []
|
||||||
|
|
||||||
for song in rating:
|
for song in rating:
|
||||||
music_chart = await self.data.static.get_music_chart(usr_sesh.chunithm_version, song.musicId, song.difficultId)
|
music_chart = await self.data.static.get_music_chart(usr_sesh.chunithm_version, song.musicId, song.difficultId)
|
||||||
if music_chart:
|
if not music_chart:
|
||||||
if (song.score < 800000):
|
continue
|
||||||
song_rating = 0
|
|
||||||
elif (song.score >= 800000 and song.score < 900000):
|
rank = calculate_song_rank(song.score, profile.version)
|
||||||
song_rating = music_chart.level / 2 - 5
|
rating = calculate_song_rating(song.score, music_chart.level, profile.version)
|
||||||
elif (song.score >= 900000 and song.score < 925000):
|
|
||||||
song_rating = music_chart.level - 5
|
song_rating = int(rating * 10 ** 2) / 10 ** 2
|
||||||
elif (song.score >= 925000 and song.score < 975000):
|
song_records.append({
|
||||||
song_rating = music_chart.level - 3
|
"difficultId": song.difficultId,
|
||||||
elif (song.score >= 975000 and song.score < 1000000):
|
"musicId": song.musicId,
|
||||||
song_rating = (song.score - 975000) / 2500 * 0.1 + music_chart.level
|
"title": music_chart.title,
|
||||||
elif (song.score >= 1000000 and song.score < 1005000):
|
"level": music_chart.level,
|
||||||
song_rating = (song.score - 1000000) / 1000 * 0.1 + 1 + music_chart.level
|
"score": song.score,
|
||||||
elif (song.score >= 1005000 and song.score < 1007500):
|
"type": song.type,
|
||||||
song_rating = (song.score - 1005000) / 500 * 0.1 + 1.5 + music_chart.level
|
"rank": rank,
|
||||||
elif (song.score >= 1007500 and song.score < 1009000):
|
"song_rating": song_rating,
|
||||||
song_rating = (song.score - 1007500) / 100 * 0.01 + 2 + music_chart.level
|
})
|
||||||
elif (song.score >= 1009000):
|
|
||||||
song_rating = 2.15 + music_chart.level
|
|
||||||
song_rating = int(song_rating * 10 ** 2) / 10 ** 2
|
|
||||||
song_records.append({
|
|
||||||
"difficultId": song.difficultId,
|
|
||||||
"musicId": song.musicId,
|
|
||||||
"title": music_chart.title,
|
|
||||||
"level": music_chart.level,
|
|
||||||
"score": song.score,
|
|
||||||
"type": song.type,
|
|
||||||
"song_rating": song_rating,
|
|
||||||
})
|
|
||||||
hot_list = [obj for obj in song_records if obj["type"] == "userRatingBaseHotList"]
|
hot_list = [obj for obj in song_records if obj["type"] == "userRatingBaseHotList"]
|
||||||
base_list = [obj for obj in song_records if obj["type"] == "userRatingBaseList"]
|
base_list = [obj for obj in song_records if obj["type"] == "userRatingBaseList"]
|
||||||
return Response(template.render(
|
return Response(template.render(
|
||||||
|
@ -94,14 +94,19 @@ class ChuniServlet(BaseServlet):
|
|||||||
|
|
||||||
known_iter_counts = {
|
known_iter_counts = {
|
||||||
ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS: 67,
|
ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS: 67,
|
||||||
|
f"{ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS}_int": 25, # SUPERSTAR
|
||||||
ChuniConstants.VER_CHUNITHM_PARADISE: 44,
|
ChuniConstants.VER_CHUNITHM_PARADISE: 44,
|
||||||
f"{ChuniConstants.VER_CHUNITHM_PARADISE}_int": 25,
|
f"{ChuniConstants.VER_CHUNITHM_PARADISE}_int": 51, # SUPERSTAR PLUS
|
||||||
ChuniConstants.VER_CHUNITHM_NEW: 54,
|
ChuniConstants.VER_CHUNITHM_NEW: 54,
|
||||||
f"{ChuniConstants.VER_CHUNITHM_NEW}_int": 49,
|
f"{ChuniConstants.VER_CHUNITHM_NEW}_int": 49,
|
||||||
ChuniConstants.VER_CHUNITHM_NEW_PLUS: 25,
|
ChuniConstants.VER_CHUNITHM_NEW_PLUS: 25,
|
||||||
|
f"{ChuniConstants.VER_CHUNITHM_NEW_PLUS}_int": 31,
|
||||||
ChuniConstants.VER_CHUNITHM_SUN: 70,
|
ChuniConstants.VER_CHUNITHM_SUN: 70,
|
||||||
|
f"{ChuniConstants.VER_CHUNITHM_SUN}_int": 35,
|
||||||
ChuniConstants.VER_CHUNITHM_SUN_PLUS: 36,
|
ChuniConstants.VER_CHUNITHM_SUN_PLUS: 36,
|
||||||
|
f"{ChuniConstants.VER_CHUNITHM_SUN_PLUS}_int": 36,
|
||||||
ChuniConstants.VER_CHUNITHM_LUMINOUS: 8,
|
ChuniConstants.VER_CHUNITHM_LUMINOUS: 8,
|
||||||
|
f"{ChuniConstants.VER_CHUNITHM_LUMINOUS}_int": 8,
|
||||||
}
|
}
|
||||||
|
|
||||||
for version, keys in self.game_cfg.crypto.keys.items():
|
for version, keys in self.game_cfg.crypto.keys.items():
|
||||||
@ -233,8 +238,10 @@ class ChuniServlet(BaseServlet):
|
|||||||
elif version >= 220: # LUMINOUS
|
elif version >= 220: # LUMINOUS
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_LUMINOUS
|
internal_ver = ChuniConstants.VER_CHUNITHM_LUMINOUS
|
||||||
elif game_code == "SDGS": # Int
|
elif game_code == "SDGS": # Int
|
||||||
if version < 110: # SUPERSTAR / SUPERSTAR PLUS
|
if version < 105: # SUPERSTAR
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE # SUPERSTAR / SUPERSTAR PLUS worked fine with it
|
internal_ver = ChuniConstants.VER_CHUNITHM_CRYSTAL_PLUS
|
||||||
|
elif version >= 105 and version < 110: # SUPERSTAR PLUS *Cursed but needed due to different encryption key
|
||||||
|
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE
|
||||||
elif version >= 110 and version < 115: # NEW
|
elif version >= 110 and version < 115: # NEW
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_NEW
|
internal_ver = ChuniConstants.VER_CHUNITHM_NEW
|
||||||
elif version >= 115 and version < 120: # NEW PLUS!!
|
elif version >= 115 and version < 120: # NEW PLUS!!
|
||||||
@ -353,9 +360,9 @@ class ChuniServlet(BaseServlet):
|
|||||||
padded = pad(zipped, 16)
|
padded = pad(zipped, 16)
|
||||||
|
|
||||||
crypt = AES.new(
|
crypt = AES.new(
|
||||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][0]),
|
bytes.fromhex(self.game_cfg.crypto.keys[crypto_cfg_key][0]),
|
||||||
AES.MODE_CBC,
|
AES.MODE_CBC,
|
||||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][1]),
|
bytes.fromhex(self.game_cfg.crypto.keys[crypto_cfg_key][1]),
|
||||||
)
|
)
|
||||||
|
|
||||||
return Response(crypt.encrypt(padded))
|
return Response(crypt.encrypt(padded))
|
||||||
|
@ -17,3 +17,13 @@ class ChuniSun(ChuniNewPlus):
|
|||||||
# hardcode lastDataVersion for CardMaker 1.35 A032
|
# hardcode lastDataVersion for CardMaker 1.35 A032
|
||||||
user_data["lastDataVersion"] = "2.10.00"
|
user_data["lastDataVersion"] = "2.10.00"
|
||||||
return user_data
|
return user_data
|
||||||
|
|
||||||
|
#SDGS Exclusive
|
||||||
|
async def handle_get_user_cto_c_play_api_request(self, data: Dict) -> Dict:
|
||||||
|
return {
|
||||||
|
"userId": data["userId"],
|
||||||
|
"orderBy": "0",
|
||||||
|
"count": "0",
|
||||||
|
#game request c2c play history while login but seem unused(?)
|
||||||
|
"userCtoCPlayList": [],
|
||||||
|
}
|
@ -18,6 +18,7 @@
|
|||||||
<th>Music</th>
|
<th>Music</th>
|
||||||
<th>Difficulty</th>
|
<th>Difficulty</th>
|
||||||
<th>Score</th>
|
<th>Score</th>
|
||||||
|
<th>Rank</th>
|
||||||
<th>Rating</th>
|
<th>Rating</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for row in hot_list %}
|
{% for row in hot_list %}
|
||||||
@ -28,6 +29,7 @@
|
|||||||
{{ row.level }}
|
{{ row.level }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ row.score }}</td>
|
<td>{{ row.score }}</td>
|
||||||
|
<td>{{ row.rank }}</td>
|
||||||
<td class="{% if row.song_rating >= 16 %}rainbow{% endif %}">
|
<td class="{% if row.song_rating >= 16 %}rainbow{% endif %}">
|
||||||
{{ row.song_rating }}
|
{{ row.song_rating }}
|
||||||
</td>
|
</td>
|
||||||
@ -48,6 +50,7 @@
|
|||||||
<th>Music</th>
|
<th>Music</th>
|
||||||
<th>Difficulty</th>
|
<th>Difficulty</th>
|
||||||
<th>Score</th>
|
<th>Score</th>
|
||||||
|
<th>Rank</th>
|
||||||
<th>Rating</th>
|
<th>Rating</th>
|
||||||
</tr>
|
</tr>
|
||||||
{% for row in base_list %}
|
{% for row in base_list %}
|
||||||
@ -58,6 +61,7 @@
|
|||||||
{{ row.level }}
|
{{ row.level }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ row.score }}</td>
|
<td>{{ row.score }}</td>
|
||||||
|
<td>{{ row.rank }}</td>
|
||||||
<td class="{% if row.song_rating >= 16 %}rainbow{% endif %}">
|
<td class="{% if row.song_rating >= 16 %}rainbow{% endif %}">
|
||||||
{{ row.song_rating }}
|
{{ row.song_rating }}
|
||||||
</td>
|
</td>
|
||||||
|
Loading…
Reference in New Issue
Block a user