forked from Hay1tsme/artemis
develop #4
@ -1,6 +1,10 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to.
|
Documenting updates to ARTEMiS, to be updated every time the master branch is pushed to.
|
||||||
|
|
||||||
|
## 20240620
|
||||||
|
### CHUNITHM
|
||||||
|
+ CHUNITHM LUMINOUS support
|
||||||
|
|
||||||
## 20240530
|
## 20240530
|
||||||
### DIVA
|
### DIVA
|
||||||
+ Fix reader for when dificulty is not a int
|
+ Fix reader for when dificulty is not a int
|
||||||
|
87
core/data/alembic/versions/b23f985100ba_chunithm_luminous.py
Normal file
87
core/data/alembic/versions/b23f985100ba_chunithm_luminous.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
"""CHUNITHM LUMINOUS
|
||||||
|
|
||||||
|
Revision ID: b23f985100ba
|
||||||
|
Revises: 3657efefc5a4
|
||||||
|
Create Date: 2024-06-20 08:08:08.759261
|
||||||
|
|
||||||
|
"""
|
||||||
|
from alembic import op
|
||||||
|
from sqlalchemy import Column, Integer, Boolean, UniqueConstraint
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = 'b23f985100ba'
|
||||||
|
down_revision = '3657efefc5a4'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
"chuni_profile_net_battle",
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column("user", Integer, nullable=False),
|
||||||
|
Column("isRankUpChallengeFailed", Boolean),
|
||||||
|
Column("highestBattleRankId", Integer),
|
||||||
|
Column("battleIconId", Integer),
|
||||||
|
Column("battleIconNum", Integer),
|
||||||
|
Column("avatarEffectPoint", Integer),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
op.create_foreign_key(
|
||||||
|
None,
|
||||||
|
"chuni_profile_net_battle",
|
||||||
|
"aime_user",
|
||||||
|
["user"],
|
||||||
|
["id"],
|
||||||
|
ondelete="cascade",
|
||||||
|
onupdate="cascade",
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"chuni_item_cmission",
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column("user", Integer, nullable=False),
|
||||||
|
Column("missionId", Integer, nullable=False),
|
||||||
|
Column("point", Integer),
|
||||||
|
UniqueConstraint("user", "missionId", name="chuni_item_cmission_uk"),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
op.create_foreign_key(
|
||||||
|
None,
|
||||||
|
"chuni_item_cmission",
|
||||||
|
"aime_user",
|
||||||
|
["user"],
|
||||||
|
["id"],
|
||||||
|
ondelete="cascade",
|
||||||
|
onupdate="cascade",
|
||||||
|
)
|
||||||
|
|
||||||
|
op.create_table(
|
||||||
|
"chuni_item_cmission_progress",
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column("user", Integer, nullable=False),
|
||||||
|
Column("missionId", Integer, nullable=False),
|
||||||
|
Column("order", Integer),
|
||||||
|
Column("stage", Integer),
|
||||||
|
Column("progress", Integer),
|
||||||
|
UniqueConstraint(
|
||||||
|
"user", "missionId", "order", name="chuni_item_cmission_progress_uk"
|
||||||
|
),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
op.create_foreign_key(
|
||||||
|
None,
|
||||||
|
"chuni_item_cmission_progress",
|
||||||
|
"aime_user",
|
||||||
|
["user"],
|
||||||
|
["id"],
|
||||||
|
ondelete="cascade",
|
||||||
|
onupdate="cascade",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table("chuni_profile_net_battle")
|
||||||
|
op.drop_table("chuni_item_cmission")
|
||||||
|
op.drop_table("chuni_item_cmission_progress")
|
@ -109,7 +109,7 @@ class BaseData:
|
|||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
async def get_event_log(self, entries: int = 100) -> Optional[List[Row]]:
|
async def get_event_log(self, entries: int = 100) -> Optional[List[Row]]:
|
||||||
sql = event_log.select().limit(entries)
|
sql = event_log.select().order_by(event_log.c.id.desc()).limit(entries)
|
||||||
result = await self.execute(sql)
|
result = await self.execute(sql)
|
||||||
|
|
||||||
if result is None:
|
if result is None:
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Severity</th>
|
<th>Severity</th>
|
||||||
|
<th>Timestamp</th>
|
||||||
<th>System</th>
|
<th>System</th>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>User</th>
|
<th>User</th>
|
||||||
@ -19,7 +20,7 @@
|
|||||||
</thead>
|
</thead>
|
||||||
{% if events is not defined or events|length == 0 %}
|
{% if events is not defined or events|length == 0 %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="10" style="text-align:center"><i>No Events</i></td>
|
<td colspan="11" style="text-align:center"><i>No Events</i></td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</table>
|
</table>
|
||||||
@ -66,7 +67,11 @@ function update_tbl() {
|
|||||||
|
|
||||||
for (var i = 0; i < per_page; i++) {
|
for (var i = 0; i < per_page; i++) {
|
||||||
let off = (page * per_page) + i;
|
let off = (page * per_page) + i;
|
||||||
if (off >= TBL_DATA.length ) {
|
if (off >= TBL_DATA.length) {
|
||||||
|
if (page != 0) {
|
||||||
|
document.getElementById("btn_next").disabled = true;
|
||||||
|
document.getElementById("btn_prev").disabled = false;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,56 +104,59 @@ function update_tbl() {
|
|||||||
row.classList.add("table-primary");
|
row.classList.add("table-primary");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var cell_ts = row.insertCell(1);
|
||||||
|
cell_ts.innerHTML = data.when_logged;
|
||||||
|
|
||||||
var cell_mod = row.insertCell(1);
|
var cell_mod = row.insertCell(2);
|
||||||
cell_mod.innerHTML = data.system;
|
cell_mod.innerHTML = data.system;
|
||||||
|
|
||||||
var cell_name = row.insertCell(2);
|
var cell_name = row.insertCell(3);
|
||||||
cell_name.innerHTML = data.type;
|
cell_name.innerHTML = data.type;
|
||||||
|
|
||||||
var cell_usr = row.insertCell(3);
|
var cell_usr = row.insertCell(4);
|
||||||
if (data.user == 'NONE') {
|
if (data.user == 'NONE') {
|
||||||
cell_usr.innerHTML = "---";
|
cell_usr.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_usr.innerHTML = "<a href=\"/user/" + data.user + "\">" + data.user + "</a>";
|
cell_usr.innerHTML = "<a href=\"/user/" + data.user + "\">" + data.user + "</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_arcade = row.insertCell(4);
|
var cell_arcade = row.insertCell(5);
|
||||||
if (data.arcade == 'NONE') {
|
if (data.arcade == 'NONE') {
|
||||||
cell_arcade.innerHTML = "---";
|
cell_arcade.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_arcade.innerHTML = "<a href=\"/shop/" + data.arcade + "\">" + data.arcade + "</a>";
|
cell_arcade.innerHTML = "<a href=\"/shop/" + data.arcade + "\">" + data.arcade + "</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_machine = row.insertCell(5);
|
var cell_machine = row.insertCell(6);
|
||||||
if (data.arcade == 'NONE') {
|
if (data.arcade == 'NONE') {
|
||||||
cell_machine.innerHTML = "---";
|
cell_machine.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_machine.innerHTML = "<a href=\"/cab/" + data.machine + "\">" + data.machine + "</a>";
|
cell_machine.innerHTML = "<a href=\"/cab/" + data.machine + "\">" + data.machine + "</a>";
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_game = row.insertCell(6);
|
var cell_game = row.insertCell(7);
|
||||||
if (data.game == 'NONE') {
|
if (data.game == 'NONE') {
|
||||||
cell_game.innerHTML = "---";
|
cell_game.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_game.innerHTML = data.game;
|
cell_game.innerHTML = data.game;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_version = row.insertCell(7);
|
var cell_version = row.insertCell(8);
|
||||||
if (data.version == 'NONE') {
|
if (data.version == 'NONE') {
|
||||||
cell_version.innerHTML = "---";
|
cell_version.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_version.innerHTML = data.version;
|
cell_version.innerHTML = data.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_msg = row.insertCell(8);
|
var cell_msg = row.insertCell(9);
|
||||||
if (data.message == '') {
|
if (data.message == '') {
|
||||||
cell_msg.innerHTML = "---";
|
cell_msg.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
cell_msg.innerHTML = data.message;
|
cell_msg.innerHTML = data.message;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cell_deets = row.insertCell(9);
|
var cell_deets = row.insertCell(10);
|
||||||
if (data.details == '{}') {
|
if (data.details == '{}') {
|
||||||
cell_deets.innerHTML = "---";
|
cell_deets.innerHTML = "---";
|
||||||
} else {
|
} else {
|
||||||
@ -160,9 +168,11 @@ function update_tbl() {
|
|||||||
|
|
||||||
function chg_page(num) {
|
function chg_page(num) {
|
||||||
var max_page = TBL_DATA.length / per_page;
|
var max_page = TBL_DATA.length / per_page;
|
||||||
|
console.log(max_page);
|
||||||
page = page + num;
|
page = page + num;
|
||||||
|
|
||||||
if (page > max_page) {
|
|
||||||
|
if (page > max_page && max_page >= 1) {
|
||||||
page = max_page;
|
page = max_page;
|
||||||
document.getElementById("btn_next").disabled = true;
|
document.getElementById("btn_next").disabled = true;
|
||||||
document.getElementById("btn_prev").disabled = false;
|
document.getElementById("btn_prev").disabled = false;
|
||||||
@ -172,6 +182,12 @@ function chg_page(num) {
|
|||||||
document.getElementById("btn_next").disabled = false;
|
document.getElementById("btn_next").disabled = false;
|
||||||
document.getElementById("btn_prev").disabled = true;
|
document.getElementById("btn_prev").disabled = true;
|
||||||
return;
|
return;
|
||||||
|
} else if (page == 0) {
|
||||||
|
document.getElementById("btn_next").disabled = false;
|
||||||
|
document.getElementById("btn_prev").disabled = true;
|
||||||
|
} else {
|
||||||
|
document.getElementById("btn_next").disabled = false;
|
||||||
|
document.getElementById("btn_prev").disabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_tbl();
|
update_tbl();
|
||||||
|
@ -63,6 +63,7 @@ Games listed below have been tested and confirmed working.
|
|||||||
| 12 | CHUNITHM NEW PLUS!! |
|
| 12 | CHUNITHM NEW PLUS!! |
|
||||||
| 13 | CHUNITHM SUN |
|
| 13 | CHUNITHM SUN |
|
||||||
| 14 | CHUNITHM SUN PLUS |
|
| 14 | CHUNITHM SUN PLUS |
|
||||||
|
| 15 | CHUNITHM LUMINOUS |
|
||||||
|
|
||||||
|
|
||||||
### Importer
|
### Importer
|
||||||
|
@ -22,6 +22,9 @@ version:
|
|||||||
14:
|
14:
|
||||||
rom: 2.15.00
|
rom: 2.15.00
|
||||||
data: 2.15.00
|
data: 2.15.00
|
||||||
|
15:
|
||||||
|
rom: 2.20.00
|
||||||
|
data: 2.20.00
|
||||||
|
|
||||||
crypto:
|
crypto:
|
||||||
encrypted_only: False
|
encrypted_only: False
|
||||||
|
@ -941,6 +941,31 @@ class ChuniBase:
|
|||||||
rating_type,
|
rating_type,
|
||||||
upsert[rating_type],
|
upsert[rating_type],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# added in LUMINOUS
|
||||||
|
if "userCMissionList" in upsert:
|
||||||
|
for cmission in upsert["userCMissionList"]:
|
||||||
|
mission_id = cmission["missionId"]
|
||||||
|
|
||||||
|
await self.data.item.put_cmission(
|
||||||
|
user_id,
|
||||||
|
{
|
||||||
|
"missionId": mission_id,
|
||||||
|
"point": cmission["point"],
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
for progress in cmission["userCMissionProgressList"]:
|
||||||
|
await self.data.item.put_cmission_progress(user_id, mission_id, progress)
|
||||||
|
|
||||||
|
if "userNetBattleData" in upsert:
|
||||||
|
net_battle = upsert["userNetBattleData"][0]
|
||||||
|
|
||||||
|
# fix the boolean
|
||||||
|
net_battle["isRankUpChallengeFailed"] = (
|
||||||
|
False if net_battle["isRankUpChallengeFailed"] == "false" else True
|
||||||
|
)
|
||||||
|
await self.data.profile.put_net_battle(user_id, net_battle)
|
||||||
|
|
||||||
return {"returnCode": "1"}
|
return {"returnCode": "1"}
|
||||||
|
|
||||||
@ -969,4 +994,4 @@ class ChuniBase:
|
|||||||
return {
|
return {
|
||||||
"userId": data["userId"],
|
"userId": data["userId"],
|
||||||
"userNetBattleData": {"recentNBSelectMusicList": []},
|
"userNetBattleData": {"recentNBSelectMusicList": []},
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class ChuniConstants:
|
class ChuniConstants:
|
||||||
GAME_CODE = "SDBT"
|
GAME_CODE = "SDBT"
|
||||||
GAME_CODE_NEW = "SDHD"
|
GAME_CODE_NEW = "SDHD"
|
||||||
@ -20,6 +23,7 @@ class ChuniConstants:
|
|||||||
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
|
||||||
VERSION_NAMES = [
|
VERSION_NAMES = [
|
||||||
"CHUNITHM",
|
"CHUNITHM",
|
||||||
"CHUNITHM PLUS",
|
"CHUNITHM PLUS",
|
||||||
@ -35,9 +39,21 @@ class ChuniConstants:
|
|||||||
"CHUNITHM NEW!!",
|
"CHUNITHM NEW!!",
|
||||||
"CHUNITHM NEW PLUS!!",
|
"CHUNITHM NEW PLUS!!",
|
||||||
"CHUNITHM SUN",
|
"CHUNITHM SUN",
|
||||||
"CHUNITHM SUN PLUS"
|
"CHUNITHM SUN PLUS",
|
||||||
|
"CHUNITHM LUMINOUS",
|
||||||
]
|
]
|
||||||
|
|
||||||
@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]
|
||||||
|
|
||||||
|
|
||||||
|
class MapAreaConditionType(Enum):
|
||||||
|
UNLOCKED = "0"
|
||||||
|
MAP_AREA_CLEARED = "2"
|
||||||
|
TROPHY_OBTAINED = "3"
|
||||||
|
|
||||||
|
|
||||||
|
class MapAreaConditionLogicalOperator(Enum):
|
||||||
|
OR = "0"
|
||||||
|
AND = "1"
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from starlette.requests import Request
|
from starlette.requests import Request
|
||||||
from starlette.routing import Route
|
from starlette.routing import Route
|
||||||
from starlette.responses import Response
|
from starlette.responses import Response
|
||||||
import logging, coloredlogs
|
import logging
|
||||||
|
import coloredlogs
|
||||||
from logging.handlers import TimedRotatingFileHandler
|
from logging.handlers import TimedRotatingFileHandler
|
||||||
import zlib
|
import zlib
|
||||||
import yaml
|
import yaml
|
||||||
@ -34,6 +35,7 @@ from .new import ChuniNew
|
|||||||
from .newplus import ChuniNewPlus
|
from .newplus import ChuniNewPlus
|
||||||
from .sun import ChuniSun
|
from .sun import ChuniSun
|
||||||
from .sunplus import ChuniSunPlus
|
from .sunplus import ChuniSunPlus
|
||||||
|
from .luminous import ChuniLuminous
|
||||||
|
|
||||||
class ChuniServlet(BaseServlet):
|
class ChuniServlet(BaseServlet):
|
||||||
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
||||||
@ -61,6 +63,7 @@ class ChuniServlet(BaseServlet):
|
|||||||
ChuniNewPlus,
|
ChuniNewPlus,
|
||||||
ChuniSun,
|
ChuniSun,
|
||||||
ChuniSunPlus,
|
ChuniSunPlus,
|
||||||
|
ChuniLuminous,
|
||||||
]
|
]
|
||||||
|
|
||||||
self.logger = logging.getLogger("chuni")
|
self.logger = logging.getLogger("chuni")
|
||||||
@ -103,7 +106,9 @@ class ChuniServlet(BaseServlet):
|
|||||||
for method in method_list:
|
for method in method_list:
|
||||||
method_fixed = inflection.camelize(method)[6:-7]
|
method_fixed = inflection.camelize(method)[6:-7]
|
||||||
# number of iterations was changed to 70 in SUN and then to 36
|
# number of iterations was changed to 70 in SUN and then to 36
|
||||||
if version == ChuniConstants.VER_CHUNITHM_SUN_PLUS:
|
if version == ChuniConstants.VER_CHUNITHM_LUMINOUS:
|
||||||
|
iter_count = 8
|
||||||
|
elif version == ChuniConstants.VER_CHUNITHM_SUN_PLUS:
|
||||||
iter_count = 36
|
iter_count = 36
|
||||||
elif version == ChuniConstants.VER_CHUNITHM_SUN:
|
elif version == ChuniConstants.VER_CHUNITHM_SUN:
|
||||||
iter_count = 70
|
iter_count = 70
|
||||||
@ -195,8 +200,10 @@ class ChuniServlet(BaseServlet):
|
|||||||
internal_ver = ChuniConstants.VER_CHUNITHM_NEW_PLUS
|
internal_ver = ChuniConstants.VER_CHUNITHM_NEW_PLUS
|
||||||
elif version >= 210 and version < 215: # SUN
|
elif version >= 210 and version < 215: # SUN
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_SUN
|
internal_ver = ChuniConstants.VER_CHUNITHM_SUN
|
||||||
elif version >= 215: # SUN PLUS
|
elif version >= 215 and version < 220: # SUN PLUS
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_SUN_PLUS
|
internal_ver = ChuniConstants.VER_CHUNITHM_SUN_PLUS
|
||||||
|
elif version >= 220: # 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 < 110: # SUPERSTAR / SUPERSTAR PLUS
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE # SUPERSTAR / SUPERSTAR PLUS worked fine with it
|
internal_ver = ChuniConstants.VER_CHUNITHM_PARADISE # SUPERSTAR / SUPERSTAR PLUS worked fine with it
|
||||||
@ -206,8 +213,10 @@ class ChuniServlet(BaseServlet):
|
|||||||
internal_ver = ChuniConstants.VER_CHUNITHM_NEW_PLUS
|
internal_ver = ChuniConstants.VER_CHUNITHM_NEW_PLUS
|
||||||
elif version >= 120 and version < 125: # SUN
|
elif version >= 120 and version < 125: # SUN
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_SUN
|
internal_ver = ChuniConstants.VER_CHUNITHM_SUN
|
||||||
elif version >= 125: # SUN PLUS
|
elif version >= 125 and version < 130: # SUN PLUS
|
||||||
internal_ver = ChuniConstants.VER_CHUNITHM_SUN_PLUS
|
internal_ver = ChuniConstants.VER_CHUNITHM_SUN_PLUS
|
||||||
|
elif version >= 130: # LUMINOUS
|
||||||
|
internal_ver = ChuniConstants.VER_CHUNITHM_LUMINOUS
|
||||||
|
|
||||||
if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32:
|
if all(c in string.hexdigits for c in endpoint) and len(endpoint) == 32:
|
||||||
# If we get a 32 character long hex string, it's a hash and we're
|
# If we get a 32 character long hex string, it's a hash and we're
|
||||||
@ -295,7 +304,7 @@ class ChuniServlet(BaseServlet):
|
|||||||
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
|
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
|
||||||
return Response(zlib.compress(b'{"stat": "0"}'))
|
return Response(zlib.compress(b'{"stat": "0"}'))
|
||||||
|
|
||||||
if resp == None:
|
if resp is None:
|
||||||
resp = {"returnCode": 1}
|
resp = {"returnCode": 1}
|
||||||
|
|
||||||
self.logger.debug(f"Response {resp}")
|
self.logger.debug(f"Response {resp}")
|
||||||
@ -313,4 +322,4 @@ class ChuniServlet(BaseServlet):
|
|||||||
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][1]),
|
bytes.fromhex(self.game_cfg.crypto.keys[internal_ver][1]),
|
||||||
)
|
)
|
||||||
|
|
||||||
return Response(crypt.encrypt(padded))
|
return Response(crypt.encrypt(padded))
|
||||||
|
244
titles/chuni/luminous.py
Normal file
244
titles/chuni/luminous.py
Normal file
@ -0,0 +1,244 @@
|
|||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
from core.config import CoreConfig
|
||||||
|
from titles.chuni.sunplus import ChuniSunPlus
|
||||||
|
from titles.chuni.const import ChuniConstants, MapAreaConditionLogicalOperator, MapAreaConditionType
|
||||||
|
from titles.chuni.config import ChuniConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ChuniLuminous(ChuniSunPlus):
|
||||||
|
def __init__(self, core_cfg: CoreConfig, game_cfg: ChuniConfig) -> None:
|
||||||
|
super().__init__(core_cfg, game_cfg)
|
||||||
|
self.version = ChuniConstants.VER_CHUNITHM_LUMINOUS
|
||||||
|
|
||||||
|
async def handle_cm_get_user_preview_api_request(self, data: Dict) -> Dict:
|
||||||
|
user_data = await super().handle_cm_get_user_preview_api_request(data)
|
||||||
|
|
||||||
|
# Does CARD MAKER 1.35 work this far up?
|
||||||
|
user_data["lastDataVersion"] = "2.20.00"
|
||||||
|
return user_data
|
||||||
|
|
||||||
|
async def handle_get_user_c_mission_api_request(self, data: Dict) -> Dict:
|
||||||
|
user_id = data["userId"]
|
||||||
|
mission_id = data["missionId"]
|
||||||
|
|
||||||
|
progress_list = []
|
||||||
|
point = 0
|
||||||
|
|
||||||
|
mission_data = await self.data.item.get_cmission(user_id, mission_id)
|
||||||
|
progress_data = await self.data.item.get_cmission_progress(user_id, mission_id)
|
||||||
|
|
||||||
|
if mission_data and progress_data:
|
||||||
|
point = mission_data["point"]
|
||||||
|
|
||||||
|
for progress in progress_data:
|
||||||
|
progress_list.append(
|
||||||
|
{
|
||||||
|
"order": progress["order"],
|
||||||
|
"stage": progress["stage"],
|
||||||
|
"progress": progress["progress"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"userId": user_id,
|
||||||
|
"missionId": mission_id,
|
||||||
|
"point": point,
|
||||||
|
"userCMissionProgressList": progress_list,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def handle_get_user_net_battle_ranking_info_api_request(self, data: Dict) -> Dict:
|
||||||
|
user_id = data["userId"]
|
||||||
|
|
||||||
|
net_battle = {}
|
||||||
|
net_battle_data = await self.data.profile.get_net_battle(user_id)
|
||||||
|
|
||||||
|
if net_battle_data:
|
||||||
|
net_battle = {
|
||||||
|
"isRankUpChallengeFailed": net_battle_data["isRankUpChallengeFailed"],
|
||||||
|
"highestBattleRankId": net_battle_data["highestBattleRankId"],
|
||||||
|
"battleIconId": net_battle_data["battleIconId"],
|
||||||
|
"battleIconNum": net_battle_data["battleIconNum"],
|
||||||
|
"avatarEffectPoint": net_battle_data["avatarEffectPoint"],
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"userId": user_id,
|
||||||
|
"userNetBattleData": net_battle,
|
||||||
|
}
|
||||||
|
|
||||||
|
async def handle_get_game_map_area_condition_api_request(self, data: Dict) -> Dict:
|
||||||
|
# There is no game data for this, everything is server side.
|
||||||
|
# TODO: Figure out conditions for 1UM1N0US ep.111
|
||||||
|
return {
|
||||||
|
"length": "7",
|
||||||
|
"gameMapAreaConditionList": [
|
||||||
|
# Secret AREA: MUSIC GAME
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206201", # BlythE ULTIMA
|
||||||
|
"length": "1",
|
||||||
|
# Obtain the trophy "MISSION in progress", which is only available
|
||||||
|
# when running the first CHUNITHM mission
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6832",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2024-01-25 02:00:00.0",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206202", # PRIVATE SERVICE ULTIMA
|
||||||
|
"length": "1",
|
||||||
|
# Obtain the trophy "MISSION in progress", which is only available
|
||||||
|
# when running the first CHUNITHM mission
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6832",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2024-01-25 02:00:00.0",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206203", # New York Back Raise
|
||||||
|
"length": "1",
|
||||||
|
# SS NightTheater's EXPERT chart and get the title
|
||||||
|
# "今宵、劇場に映し出される景色とは――――。"
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6833",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206204", # Spasmodic
|
||||||
|
"length": "2",
|
||||||
|
# - Get 1 miss on Random (any difficulty) and get the title "当たり待ち"
|
||||||
|
# - Get 1 miss on 花たちに希望を (any difficulty) and get the title "花たちに希望を"
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6834",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6835",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206205", # ΩΩPARTS
|
||||||
|
"length": "2",
|
||||||
|
# - S Sage EXPERT to get the title "マターリ進行キボンヌ"
|
||||||
|
# - Equip this title and play cab-to-cab with another person with this title
|
||||||
|
# to get "マターリしようよ"
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6836",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6837",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2024-01-25 02:00:00.0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206206", # Blow My Mind
|
||||||
|
"length": "1",
|
||||||
|
# SS on CHAOS EXPERT, Hydra EXPERT, Surive EXPERT and Jakarta PROGRESSION EXPERT
|
||||||
|
# to get the title "Can you hear me?"
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.TROPHY_OBTAINED.value,
|
||||||
|
"conditionId": "6838",
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mapAreaId": "2206207", # VALLIS-NERIA
|
||||||
|
"length": "6",
|
||||||
|
# Finish the 6 other areas
|
||||||
|
"mapAreaConditionList": [
|
||||||
|
{
|
||||||
|
"type": MapAreaConditionType.MAP_AREA_CLEARED.value,
|
||||||
|
"conditionId": str(x),
|
||||||
|
"logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
"startDate": "2023-12-14 07:00:00.0",
|
||||||
|
"endDate": "2099-12-31 00:00:00.0",
|
||||||
|
}
|
||||||
|
for x in range(2206201, 2206207)
|
||||||
|
],
|
||||||
|
},
|
||||||
|
# {
|
||||||
|
# "mapAreaId": "3229301", # Mystic Rainbow of LUMINOUS Area 1
|
||||||
|
# "length": "1",
|
||||||
|
# # Unlocks when any of the mainline LUMINOUS maps are completed?
|
||||||
|
# "mapAreaConditionList": [
|
||||||
|
# # TODO
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "mapAreaId": "3229302", # Mystic Rainbow of LUMINOUS Area 2
|
||||||
|
# "length": "5",
|
||||||
|
# # Unlocks when LUMINOUS ep. I is completed
|
||||||
|
# "mapAreaConditionList": [
|
||||||
|
# {
|
||||||
|
# "type": MapAreaConditionType.MAP_AREA_CLEARED.value,
|
||||||
|
# "conditionId": str(x),
|
||||||
|
# "logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
# "startDate": "2023-12-14 07:00:00.0",
|
||||||
|
# "endDate": "2099-12-31 00:00:00.0",
|
||||||
|
# }
|
||||||
|
# for x in range(3220101, 3220106)
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "mapAreaId": "3229303", # Mystic Rainbow of LUMINOUS Area 3
|
||||||
|
# "length": "5",
|
||||||
|
# # Unlocks when LUMINOUS ep. II is completed
|
||||||
|
# "mapAreaConditionList": [
|
||||||
|
# {
|
||||||
|
# "type": MapAreaConditionType.MAP_AREA_CLEARED.value,
|
||||||
|
# "conditionId": str(x),
|
||||||
|
# "logicalOpe": MapAreaConditionLogicalOperator.AND.value,
|
||||||
|
# "startDate": "2023-12-14 07:00:00.0",
|
||||||
|
# "endDate": "2099-12-31 00:00:00.0",
|
||||||
|
# }
|
||||||
|
# for x in range(3220201, 3220206)
|
||||||
|
# ]
|
||||||
|
# },
|
||||||
|
# {
|
||||||
|
# "mapAreaId": "3229304", # Mystic Rainbow of LUMINOUS Area 4
|
||||||
|
# "length": "5",
|
||||||
|
# # Unlocks when LUMINOUS ep. III is completed
|
||||||
|
# "mapAreaConditionList": [
|
||||||
|
|
||||||
|
# ]
|
||||||
|
# }
|
||||||
|
],
|
||||||
|
}
|
@ -32,6 +32,8 @@ class ChuniNew(ChuniBase):
|
|||||||
return "210"
|
return "210"
|
||||||
if self.version == ChuniConstants.VER_CHUNITHM_SUN_PLUS:
|
if self.version == ChuniConstants.VER_CHUNITHM_SUN_PLUS:
|
||||||
return "215"
|
return "215"
|
||||||
|
if self.version == ChuniConstants.VER_CHUNITHM_LUMINOUS:
|
||||||
|
return "220"
|
||||||
|
|
||||||
async def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
async def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
||||||
# use UTC time and convert it to JST time by adding +9
|
# use UTC time and convert it to JST time by adding +9
|
||||||
|
@ -243,6 +243,36 @@ matching = Table(
|
|||||||
mysql_charset="utf8mb4",
|
mysql_charset="utf8mb4",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
cmission = Table(
|
||||||
|
"chuni_item_cmission",
|
||||||
|
metadata,
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column(
|
||||||
|
"user",
|
||||||
|
ForeignKey("aime_user.id", ondelete="cascade", onupdate="cascade"),
|
||||||
|
nullable=False,
|
||||||
|
),
|
||||||
|
Column("missionId", Integer, nullable=False),
|
||||||
|
Column("point", Integer),
|
||||||
|
UniqueConstraint("user", "missionId", name="chuni_item_cmission_uk"),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
|
||||||
|
cmission_progress = Table(
|
||||||
|
"chuni_item_cmission_progress",
|
||||||
|
metadata,
|
||||||
|
Column("id", Integer, primary_key=True, nullable=False),
|
||||||
|
Column("user", ForeignKey("aime_user.id", ondelete="cascade"), nullable=False),
|
||||||
|
Column("missionId", Integer, nullable=False),
|
||||||
|
Column("order", Integer),
|
||||||
|
Column("stage", Integer),
|
||||||
|
Column("progress", Integer),
|
||||||
|
UniqueConstraint(
|
||||||
|
"user", "missionId", "order", name="chuni_item_cmission_progress_uk"
|
||||||
|
),
|
||||||
|
mysql_charset="utf8mb4",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChuniItemData(BaseData):
|
class ChuniItemData(BaseData):
|
||||||
async def get_oldest_free_matching(self, version: int) -> Optional[Row]:
|
async def get_oldest_free_matching(self, version: int) -> Optional[Row]:
|
||||||
@ -594,3 +624,66 @@ class ChuniItemData(BaseData):
|
|||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
return result.lastrowid
|
return result.lastrowid
|
||||||
|
|
||||||
|
async def put_cmission_progress(
|
||||||
|
self, user_id: int, mission_id: int, progress_data: Dict
|
||||||
|
) -> Optional[int]:
|
||||||
|
progress_data["user"] = user_id
|
||||||
|
progress_data["missionId"] = mission_id
|
||||||
|
|
||||||
|
sql = insert(cmission_progress).values(**progress_data)
|
||||||
|
conflict = sql.on_duplicate_key_update(**progress_data)
|
||||||
|
result = await self.execute(conflict)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.lastrowid
|
||||||
|
|
||||||
|
async def get_cmission_progress(
|
||||||
|
self, user_id: int, mission_id: int
|
||||||
|
) -> Optional[List[Row]]:
|
||||||
|
sql = cmission_progress.select(
|
||||||
|
and_(
|
||||||
|
cmission_progress.c.user == user_id,
|
||||||
|
cmission_progress.c.missionId == mission_id,
|
||||||
|
)
|
||||||
|
).order_by(cmission_progress.c.order.asc())
|
||||||
|
result = await self.execute(sql)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.fetchall()
|
||||||
|
|
||||||
|
async def get_cmission(self, user_id: int, mission_id: int) -> Optional[Row]:
|
||||||
|
sql = cmission.select(
|
||||||
|
and_(cmission.c.user == user_id, cmission.c.missionId == mission_id)
|
||||||
|
)
|
||||||
|
result = await self.execute(sql)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.fetchone()
|
||||||
|
|
||||||
|
async def put_cmission(self, user_id: int, mission_data: Dict) -> Optional[int]:
|
||||||
|
mission_data["user"] = user_id
|
||||||
|
|
||||||
|
sql = insert(cmission).values(**mission_data)
|
||||||
|
conflict = sql.on_duplicate_key_update(**mission_data)
|
||||||
|
result = await self.execute(conflict)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.lastrowid
|
||||||
|
|
||||||
|
async def get_cmissions(self, user_id: int) -> Optional[List[Row]]:
|
||||||
|
sql = cmission.select(cmission.c.user == user_id)
|
||||||
|
result = await self.execute(sql)
|
||||||
|
|
||||||
|
if result is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return result.fetchall()
|
||||||
|
@ -216,16 +216,20 @@ class OngekiServlet(BaseServlet):
|
|||||||
)
|
)
|
||||||
return Response(zlib.compress(b'{"stat": "0"}'))
|
return Response(zlib.compress(b'{"stat": "0"}'))
|
||||||
|
|
||||||
try:
|
if version < 105:
|
||||||
unzip = zlib.decompress(req_raw)
|
# O.N.G.E.K.I base don't use zlib
|
||||||
|
req_data = json.loads(req_raw)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
unzip = zlib.decompress(req_raw)
|
||||||
|
|
||||||
|
except zlib.error as e:
|
||||||
|
self.logger.error(
|
||||||
|
f"Failed to decompress v{version} {endpoint} request -> {e}"
|
||||||
|
)
|
||||||
|
return Response(zlib.compress(b'{"stat": "0"}'))
|
||||||
|
|
||||||
except zlib.error as e:
|
req_data = json.loads(unzip)
|
||||||
self.logger.error(
|
|
||||||
f"Failed to decompress v{version} {endpoint} request -> {e}"
|
|
||||||
)
|
|
||||||
return Response(zlib.compress(b'{"stat": "0"}'))
|
|
||||||
|
|
||||||
req_data = json.loads(unzip)
|
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"v{version} {endpoint} request from {client_ip}"
|
f"v{version} {endpoint} request from {client_ip}"
|
||||||
@ -251,9 +255,12 @@ class OngekiServlet(BaseServlet):
|
|||||||
|
|
||||||
self.logger.debug(f"Response {resp}")
|
self.logger.debug(f"Response {resp}")
|
||||||
|
|
||||||
zipped = zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))
|
resp_raw = json.dumps(resp, ensure_ascii=False).encode("utf-8")
|
||||||
|
zipped = zlib.compress(resp_raw)
|
||||||
|
|
||||||
if not encrtped or version < 120:
|
if not encrtped or version < 120:
|
||||||
|
if version < 105:
|
||||||
|
return Response(resp_raw)
|
||||||
return Response(zipped)
|
return Response(zipped)
|
||||||
|
|
||||||
padded = pad(zipped, 16)
|
padded = pad(zipped, 16)
|
||||||
|
@ -226,7 +226,7 @@ class PokkenBase:
|
|||||||
load_usr.rankmatch_success = profile_dict.get("rankmatch_success", 0)
|
load_usr.rankmatch_success = profile_dict.get("rankmatch_success", 0)
|
||||||
load_usr.beat_num = profile_dict.get("beat_num", 0)
|
load_usr.beat_num = profile_dict.get("beat_num", 0)
|
||||||
load_usr.title_text_id = profile_dict.get("title_text_id", 2)
|
load_usr.title_text_id = profile_dict.get("title_text_id", 2)
|
||||||
load_usr.title_plate_id = profile_dict.get("title_plate_id", 1)
|
load_usr.title_plate_id = profile_dict.get("title_plate_id", 31)
|
||||||
load_usr.title_decoration_id = profile_dict.get("title_decoration_id", 1)
|
load_usr.title_decoration_id = profile_dict.get("title_decoration_id", 1)
|
||||||
load_usr.navi_trainer = profile_dict.get("navi_trainer", 0)
|
load_usr.navi_trainer = profile_dict.get("navi_trainer", 0)
|
||||||
load_usr.navi_version_id = profile_dict.get("navi_version_id", 0)
|
load_usr.navi_version_id = profile_dict.get("navi_version_id", 0)
|
||||||
|
@ -833,14 +833,14 @@ class WaccaBase:
|
|||||||
# TODO: Coop and vs data
|
# TODO: Coop and vs data
|
||||||
async def handle_user_music_updateCoop_request(self, data: Dict) -> Dict:
|
async def handle_user_music_updateCoop_request(self, data: Dict) -> Dict:
|
||||||
coop_info = data["params"][4]
|
coop_info = data["params"][4]
|
||||||
return self.handle_user_music_update_request(data)
|
return await self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
async def handle_user_music_updateVersus_request(self, data: Dict) -> Dict:
|
async def handle_user_music_updateVersus_request(self, data: Dict) -> Dict:
|
||||||
vs_info = data["params"][4]
|
vs_info = data["params"][4]
|
||||||
return self.handle_user_music_update_request(data)
|
return await self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
async def handle_user_music_updateTrial_request(self, data: Dict) -> Dict:
|
async def handle_user_music_updateTrial_request(self, data: Dict) -> Dict:
|
||||||
return self.handle_user_music_update_request(data)
|
return await self.handle_user_music_update_request(data)
|
||||||
|
|
||||||
async def handle_user_mission_update_request(self, data: Dict) -> Dict:
|
async def handle_user_mission_update_request(self, data: Dict) -> Dict:
|
||||||
req = UserMissionUpdateRequest(data)
|
req = UserMissionUpdateRequest(data)
|
||||||
|
Loading…
Reference in New Issue
Block a user