forked from Hay1tsme/artemis
Initial Card Maker ONGEKI support
This commit is contained in:
15
titles/cm/__init__.py
Normal file
15
titles/cm/__init__.py
Normal file
@ -0,0 +1,15 @@
|
||||
from titles.cm.index import CardMakerServlet
|
||||
from titles.cm.const import CardMakerConstants
|
||||
from titles.cm.read import CardMakerReader
|
||||
|
||||
index = CardMakerServlet
|
||||
reader = CardMakerReader
|
||||
|
||||
use_default_title = True
|
||||
include_protocol = True
|
||||
title_secure = False
|
||||
game_codes = [CardMakerConstants.GAME_CODE]
|
||||
trailing_slash = True
|
||||
use_default_host = True
|
||||
|
||||
current_schema_version = 1
|
84
titles/cm/base.py
Normal file
84
titles/cm/base.py
Normal file
@ -0,0 +1,84 @@
|
||||
from datetime import date, datetime, timedelta
|
||||
from typing import Any, Dict, List
|
||||
import json
|
||||
import logging
|
||||
from enum import Enum
|
||||
|
||||
from core.config import CoreConfig
|
||||
from core.data.cache import cached
|
||||
from titles.cm.const import CardMakerConstants
|
||||
from titles.cm.config import CardMakerConfig
|
||||
|
||||
|
||||
class CardMakerBase():
|
||||
def __init__(self, core_cfg: CoreConfig, game_cfg: CardMakerConfig) -> None:
|
||||
self.core_cfg = core_cfg
|
||||
self.game_cfg = game_cfg
|
||||
self.date_time_format = "%Y-%m-%d %H:%M:%S"
|
||||
self.date_time_format_ext = "%Y-%m-%d %H:%M:%S.%f" # needs to be lopped off at [:-5]
|
||||
self.date_time_format_short = "%Y-%m-%d"
|
||||
self.logger = logging.getLogger("cardmaker")
|
||||
self.game = CardMakerConstants.GAME_CODE
|
||||
self.version = CardMakerConstants.VER_CARD_MAKER
|
||||
|
||||
def handle_get_game_connect_api_request(self, data: Dict) -> Dict:
|
||||
uri = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}"
|
||||
|
||||
# CHUNITHM = 0, maimai = 1, ONGEKI = 2
|
||||
return {
|
||||
"length": 3,
|
||||
"gameConnectList": [
|
||||
{
|
||||
"modelKind": 0,
|
||||
"type": 1,
|
||||
"titleUri": f"{uri}/SDHD/200/"
|
||||
},
|
||||
{
|
||||
"modelKind": 1,
|
||||
"type": 1,
|
||||
"titleUri": f"{uri}/SDEZ/120/"
|
||||
},
|
||||
{
|
||||
"modelKind": 2,
|
||||
"type": 1,
|
||||
"titleUri": f"{uri}/SDDT/130/"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
|
||||
reboot_start = date.strftime(datetime.now() + timedelta(hours=3), self.date_time_format)
|
||||
reboot_end = date.strftime(datetime.now() + timedelta(hours=4), self.date_time_format)
|
||||
|
||||
return {
|
||||
"gameSetting": {
|
||||
"dataVersion": "1.30.00",
|
||||
"ongekiCmVersion": "1.30.01",
|
||||
"chuniCmVersion": "2.00.00",
|
||||
"maimaiCmVersion": "1.20.00",
|
||||
"requestInterval": 10,
|
||||
"rebootStartTime": reboot_start,
|
||||
"rebootEndTime": reboot_end,
|
||||
"maxCountCharacter": 100,
|
||||
"maxCountItem": 100,
|
||||
"maxCountCard": 100,
|
||||
"watermark": False,
|
||||
"isMaintenance": False,
|
||||
"isBackgroundDistribute": False
|
||||
},
|
||||
"isDumpUpload": False,
|
||||
"isAou": False
|
||||
}
|
||||
|
||||
def handle_get_client_bookkeeping_api_request(self, data: Dict) -> Dict:
|
||||
return {
|
||||
"placeId": data["placeId"],
|
||||
"length": 0,
|
||||
"clientBookkeepingList": []
|
||||
}
|
||||
|
||||
def handle_upsert_client_setting_api_request(self, data: Dict) -> Dict:
|
||||
return {"returnCode": 1, "apiName": "UpsertClientSettingApi"}
|
||||
|
||||
def handle_upsert_client_bookkeeping_api_request(self, data: Dict) -> Dict:
|
||||
return {"returnCode": 1, "apiName": "UpsertClientBookkeepingApi"}
|
1616
titles/cm/cm_data/MU3/static_cards.csv
Normal file
1616
titles/cm/cm_data/MU3/static_cards.csv
Normal file
File diff suppressed because it is too large
Load Diff
336
titles/cm/cm_data/MU3/static_gacha_cards.csv
Normal file
336
titles/cm/cm_data/MU3/static_gacha_cards.csv
Normal file
@ -0,0 +1,336 @@
|
||||
"gachaId","cardId","rarity","weight","isPickup","isSelect"
|
||||
1070,100984,4,1,0,1
|
||||
1070,100997,3,2,0,1
|
||||
1070,100998,3,2,0,1
|
||||
1070,101020,2,3,0,1
|
||||
1070,101021,2,3,0,1
|
||||
1070,101022,2,3,0,1
|
||||
1067,100982,4,1,0,0
|
||||
1067,100983,4,1,0,0
|
||||
1067,100996,3,2,0,0
|
||||
1068,100075,2,3,0,0
|
||||
1068,100182,2,3,0,0
|
||||
1068,100348,2,3,0,0
|
||||
1068,100232,2,3,0,0
|
||||
1068,100417,2,3,0,0
|
||||
1068,100755,2,3,0,0
|
||||
1068,100077,3,2,0,0
|
||||
1068,100271,3,2,0,0
|
||||
1068,100425,3,2,0,0
|
||||
1068,100758,3,2,0,0
|
||||
1068,101000,3,2,0,0
|
||||
1068,100284,4,1,0,0
|
||||
1068,100767,4,1,0,0
|
||||
1068,101293,4,1,0,0
|
||||
1069,100069,2,3,0,0
|
||||
1069,100183,2,3,0,0
|
||||
1069,100349,2,3,0,0
|
||||
1069,100233,2,3,0,0
|
||||
1069,100416,2,3,0,0
|
||||
1069,100071,3,2,0,0
|
||||
1069,100272,3,2,0,0
|
||||
1069,100427,3,2,0,0
|
||||
1069,100805,3,2,0,0
|
||||
1069,101300,3,2,0,0
|
||||
1069,100285,4,1,0,0
|
||||
1069,100768,4,1,0,0
|
||||
1069,100988,4,1,0,0
|
||||
1071,100275,4,1,0,0
|
||||
1071,100437,4,1,0,0
|
||||
1071,100780,4,1,0,0
|
||||
1071,100006,3,2,0,0
|
||||
1071,100007,3,2,0,0
|
||||
1071,100249,3,2,0,0
|
||||
1071,100262,3,2,0,0
|
||||
1071,100418,3,2,0,0
|
||||
1071,100003,2,3,0,0
|
||||
1071,100004,2,3,0,0
|
||||
1071,100173,2,3,0,0
|
||||
1071,100223,2,3,0,0
|
||||
1071,100339,2,3,0,0
|
||||
1071,100692,2,3,0,0
|
||||
1072,100017,4,1,0,0
|
||||
1072,100276,4,1,0,0
|
||||
1072,100760,4,1,0,0
|
||||
1072,100015,3,2,0,0
|
||||
1072,100016,3,2,0,0
|
||||
1072,100250,3,2,0,0
|
||||
1072,100263,3,2,0,0
|
||||
1072,100423,3,2,0,0
|
||||
1072,100765,3,2,0,0
|
||||
1072,100012,2,3,0,0
|
||||
1072,100013,2,3,0,0
|
||||
1072,100174,2,3,0,0
|
||||
1072,100224,2,3,0,0
|
||||
1072,100340,2,3,0,0
|
||||
1072,100693,2,3,0,0
|
||||
1073,100026,4,1,0,0
|
||||
1073,100277,4,1,0,0
|
||||
1073,100761,4,1,0,0
|
||||
1073,100024,3,2,0,0
|
||||
1073,100025,3,2,0,0
|
||||
1073,100251,3,2,0,0
|
||||
1073,100264,3,2,0,0
|
||||
1073,100430,3,2,0,0
|
||||
1073,100021,2,3,0,0
|
||||
1073,100022,2,3,0,0
|
||||
1073,100175,2,3,0,0
|
||||
1073,100225,2,3,0,0
|
||||
1073,100341,2,3,0,0
|
||||
1073,100694,2,3,0,0
|
||||
1011,100454,4,1,0,0
|
||||
1011,100980,4,1,0,0
|
||||
1011,101553,4,1,0,0
|
||||
1011,100253,3,1,0,0
|
||||
1011,100241,3,1,0,0
|
||||
1011,100240,3,1,0,0
|
||||
1011,100239,3,1,0,0
|
||||
1011,100238,3,1,0,0
|
||||
1011,100237,3,1,0,0
|
||||
1011,100236,3,1,0,0
|
||||
1011,100261,3,1,0,0
|
||||
1011,100246,3,1,0,0
|
||||
1011,100245,3,1,0,0
|
||||
1011,100242,3,1,0,0
|
||||
1011,100243,3,1,0,0
|
||||
1011,100254,3,1,0,0
|
||||
1011,100338,3,1,0,0
|
||||
1011,100337,3,1,0,0
|
||||
1011,100336,3,1,0,0
|
||||
1011,100248,3,1,0,0
|
||||
1011,100247,3,1,0,0
|
||||
1011,100244,3,1,0,0
|
||||
1011,100259,3,1,0,0
|
||||
1011,100257,3,1,0,0
|
||||
1011,100258,3,1,0,0
|
||||
1011,100636,3,1,0,0
|
||||
1011,100634,3,1,0,0
|
||||
1011,100255,3,1,0,0
|
||||
1011,100256,3,1,0,0
|
||||
1011,100252,3,1,0,0
|
||||
1011,100638,3,1,0,0
|
||||
1011,100639,3,1,0,0
|
||||
1011,100637,3,1,0,0
|
||||
1011,100772,3,1,0,0
|
||||
1011,100667,3,1,0,0
|
||||
1011,100666,3,1,0,0
|
||||
1011,100665,3,1,0,0
|
||||
1011,100643,3,1,0,0
|
||||
1011,100640,3,1,0,0
|
||||
1011,100641,3,1,0,0
|
||||
1011,100642,3,1,0,0
|
||||
1011,100688,3,1,0,0
|
||||
1011,100645,3,1,0,0
|
||||
1011,100646,3,1,0,0
|
||||
1011,100644,3,1,0,0
|
||||
1012,100644,3,1,0,0
|
||||
1012,100646,3,1,0,0
|
||||
1012,100645,3,1,0,0
|
||||
1012,100688,3,1,0,0
|
||||
1012,100642,3,1,0,0
|
||||
1012,100641,3,1,0,0
|
||||
1012,100640,3,1,0,0
|
||||
1012,100643,3,1,0,0
|
||||
1012,100665,3,1,0,0
|
||||
1012,100666,3,1,0,0
|
||||
1012,100667,3,1,0,0
|
||||
1012,100634,3,1,0,0
|
||||
1012,100636,3,1,0,0
|
||||
1012,100772,3,1,0,0
|
||||
1012,100638,3,1,0,0
|
||||
1012,100637,3,1,0,0
|
||||
1012,100639,3,1,0,0
|
||||
1012,100252,3,1,0,0
|
||||
1012,100256,3,1,0,0
|
||||
1012,100255,3,1,0,0
|
||||
1012,100258,3,1,0,0
|
||||
1012,100257,3,1,0,0
|
||||
1012,100259,3,1,0,0
|
||||
1012,100244,3,1,0,0
|
||||
1012,100247,3,1,0,0
|
||||
1012,100248,3,1,0,0
|
||||
1012,100336,3,1,0,0
|
||||
1012,100337,3,1,0,0
|
||||
1012,100338,3,1,0,0
|
||||
1012,100254,3,1,0,0
|
||||
1012,100243,3,1,0,0
|
||||
1012,100242,3,1,0,0
|
||||
1012,100245,3,1,0,0
|
||||
1012,100246,3,1,0,0
|
||||
1012,100261,3,1,0,0
|
||||
1012,100236,3,1,0,0
|
||||
1012,100237,3,1,0,0
|
||||
1012,100238,3,1,0,0
|
||||
1012,100239,3,1,0,0
|
||||
1012,100240,3,1,0,0
|
||||
1012,100241,3,1,0,0
|
||||
1012,100253,3,1,0,0
|
||||
1012,100454,4,1,0,0
|
||||
1012,100980,4,1,0,0
|
||||
1012,101553,4,1,0,0
|
||||
1074,100985,4,1,0,0
|
||||
1074,100999,3,1,0,0
|
||||
1074,101000,3,1,0,0
|
||||
1074,101023,2,1,0,0
|
||||
1074,101024,2,1,0,0
|
||||
1075,100060,4,1,0,0
|
||||
1075,100434,4,1,0,0
|
||||
1075,100059,3,1,0,0
|
||||
1075,100268,3,1,0,0
|
||||
1075,100420,3,1,0,0
|
||||
1075,100763,3,1,0,0
|
||||
1075,101003,3,1,0,0
|
||||
1075,100057,2,1,0,0
|
||||
1075,100179,2,1,0,0
|
||||
1075,100229,2,1,0,0
|
||||
1075,100345,2,1,0,0
|
||||
1075,100415,2,1,0,0
|
||||
1076,100054,4,1,0,0
|
||||
1076,100282,4,1,0,0
|
||||
1076,100726,4,1,0,0
|
||||
1076,100053,3,1,0,0
|
||||
1076,100269,3,1,0,0
|
||||
1076,100422,3,1,0,0
|
||||
1076,100757,3,1,0,0
|
||||
1076,100051,2,1,0,0
|
||||
1076,100180,2,1,0,0
|
||||
1076,100230,2,1,0,0
|
||||
1076,100346,2,1,0,0
|
||||
1076,100414,2,1,0,0
|
||||
1077,100984,4,1,0,1
|
||||
1077,100997,3,1,0,1
|
||||
1077,100998,3,1,0,1
|
||||
1077,100986,4,1,0,1
|
||||
1077,101001,3,1,0,1
|
||||
1077,101002,3,1,0,1
|
||||
1077,101025,2,1,0,1
|
||||
1077,101026,2,1,0,1
|
||||
1077,101027,2,1,0,1
|
||||
1081,100987,4,1,0,0
|
||||
1081,100988,4,1,0,0
|
||||
1081,101003,3,1,0,0
|
||||
1085,100008,4,1,0,1
|
||||
1085,100017,4,1,0,1
|
||||
1085,100026,4,1,0,1
|
||||
1085,100034,4,1,0,1
|
||||
1085,100041,4,1,0,1
|
||||
1085,100048,4,1,0,1
|
||||
1085,100054,4,1,0,1
|
||||
1085,100060,4,1,0,1
|
||||
1085,100066,4,1,0,1
|
||||
1085,100078,4,1,0,1
|
||||
1085,100072,4,1,0,1
|
||||
1085,100084,4,1,0,1
|
||||
1085,100090,4,1,0,1
|
||||
1085,100282,4,1,0,1
|
||||
1085,100285,4,1,0,1
|
||||
1085,100284,4,1,0,1
|
||||
1085,100286,4,1,0,1
|
||||
1085,100280,4,1,0,1
|
||||
1085,100276,4,1,0,1
|
||||
1085,100277,4,1,0,1
|
||||
1085,100275,4,1,0,1
|
||||
1085,100278,4,1,0,1
|
||||
1085,100431,4,1,0,1
|
||||
1085,100407,4,1,0,1
|
||||
1085,100432,4,1,0,1
|
||||
1085,100433,4,1,0,1
|
||||
1085,100434,4,1,0,1
|
||||
1085,100435,4,1,0,1
|
||||
1085,100436,4,1,0,1
|
||||
1085,100437,4,1,0,1
|
||||
1085,100438,4,1,0,1
|
||||
1085,100439,4,1,0,1
|
||||
1085,100760,4,1,0,1
|
||||
1085,100761,4,1,0,1
|
||||
1085,100779,4,1,0,1
|
||||
1085,100767,4,1,0,1
|
||||
1085,100780,4,1,0,1
|
||||
1085,100784,4,1,0,1
|
||||
1085,100768,4,1,0,1
|
||||
1085,100725,4,1,0,1
|
||||
1085,100726,4,1,0,1
|
||||
1085,100984,4,1,0,1
|
||||
1085,100985,4,1,0,1
|
||||
1085,100987,4,1,0,1
|
||||
1085,100988,4,1,0,1
|
||||
1085,100986,4,1,0,1
|
||||
1085,100989,4,1,0,1
|
||||
1085,100982,4,1,0,1
|
||||
1085,100983,4,1,0,1
|
||||
1085,100787,4,1,0,1
|
||||
1085,101293,4,1,0,1
|
||||
1085,101294,4,1,0,1
|
||||
1085,101295,4,1,0,1
|
||||
1085,101296,4,1,0,1
|
||||
1085,101297,4,1,0,1
|
||||
1085,101320,4,1,0,1
|
||||
1085,101567,4,1,0,1
|
||||
1085,101592,4,1,0,1
|
||||
1085,101593,4,1,0,1
|
||||
1085,101594,4,1,0,1
|
||||
1085,101595,4,1,0,1
|
||||
1089,100989,4,1,0,0
|
||||
1089,101004,3,1,0,0
|
||||
1089,101005,3,1,0,0
|
||||
1104,101293,4,1,0,0
|
||||
1104,101294,4,1,0,0
|
||||
1104,101298,3,1,0,0
|
||||
1111,100008,4,1,0,1
|
||||
1111,100017,4,1,0,1
|
||||
1111,100026,4,1,0,1
|
||||
1111,100034,4,1,0,1
|
||||
1111,100041,4,1,0,1
|
||||
1111,100048,4,1,0,1
|
||||
1111,100054,4,1,0,1
|
||||
1111,100060,4,1,0,1
|
||||
1111,100066,4,1,0,1
|
||||
1111,100078,4,1,0,1
|
||||
1111,100072,4,1,0,1
|
||||
1111,100084,4,1,0,1
|
||||
1111,100090,4,1,0,1
|
||||
1111,100282,4,1,0,1
|
||||
1111,100285,4,1,0,1
|
||||
1111,100284,4,1,0,1
|
||||
1111,100286,4,1,0,1
|
||||
1111,100280,4,1,0,1
|
||||
1111,100276,4,1,0,1
|
||||
1111,100277,4,1,0,1
|
||||
1111,100275,4,1,0,1
|
||||
1111,100278,4,1,0,1
|
||||
1111,100431,4,1,0,1
|
||||
1111,100407,4,1,0,1
|
||||
1111,100432,4,1,0,1
|
||||
1111,100433,4,1,0,1
|
||||
1111,100434,4,1,1,1
|
||||
1111,100435,4,1,1,1
|
||||
1111,100436,4,1,0,1
|
||||
1111,100437,4,1,0,1
|
||||
1111,100438,4,1,0,1
|
||||
1111,100439,4,1,0,1
|
||||
1111,100760,4,1,1,1
|
||||
1111,100761,4,1,0,1
|
||||
1111,100779,4,1,0,1
|
||||
1111,100767,4,1,0,1
|
||||
1111,100780,4,1,1,1
|
||||
1111,100784,4,1,1,1
|
||||
1111,100768,4,1,0,1
|
||||
1111,100725,4,1,1,1
|
||||
1111,100726,4,1,1,1
|
||||
1111,100985,4,1,1,1
|
||||
1111,100988,4,1,1,1
|
||||
1111,100989,4,1,1,1
|
||||
1111,100982,4,1,1,1
|
||||
1111,100983,4,1,1,1
|
||||
1111,101293,4,1,1,1
|
||||
1111,101294,4,1,1,1
|
||||
1111,101295,4,1,1,1
|
||||
1111,101320,4,1,1,1
|
||||
1135,101567,4,1,0,0
|
||||
1135,101592,4,1,0,0
|
||||
1135,101594,4,1,0,0
|
||||
1135,101595,4,1,0,0
|
||||
1135,101566,3,1,0,0
|
||||
1135,101602,3,1,0,0
|
||||
1135,101603,3,1,0,0
|
||||
1135,101619,2,1,0,0
|
|
104
titles/cm/cm_data/MU3/static_gachas.csv
Normal file
104
titles/cm/cm_data/MU3/static_gachas.csv
Normal file
@ -0,0 +1,104 @@
|
||||
"version","gachaId","gachaName","type","kind","isCeiling","maxSelectPoint","ceilingCnt","changeRateCnt1","changeRateCnt2"
|
||||
6,1011,"無料ガチャ",0,3,0,0,10,0,0
|
||||
6,1012,"無料ガチャ(SR確定)",0,3,0,0,10,0,0
|
||||
6,1043,"レギュラーガチャ",0,0,0,0,10,0,0
|
||||
6,1067,"例えるなら大人のパッションフルーツ
|
||||
リゾートプールガチャ",0,1,0,0,10,0,0
|
||||
6,1068,"柏木 咲姫
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1069,"井之原 小星
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1070,"目指すは優勝!
|
||||
炎の体育祭リミテッドガチャ",0,1,1,110,10,0,0
|
||||
6,1071,"星咲 あかり
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1072,"藤沢 柚子
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1073,"三角 葵
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1074,"おくれてきた
|
||||
Halloweenガチャ",0,1,0,0,10,0,0
|
||||
6,1075,"早乙女 彩華
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1076,"桜井 春菜
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1077,"ふわふわすぺーす
|
||||
お仕事体験リミテッドガチャ",0,1,1,110,10,0,0
|
||||
6,1078,"高瀬 梨緒
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1079,"結城 莉玖
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1080,"藍原 椿
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1081,"今夜はおうちでパーティ☆
|
||||
メリクリガチャ",0,1,0,0,10,0,0
|
||||
6,1082,"日向 千夏
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1083,"柏木 美亜
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1084,"東雲 つむぎ
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1085,"謹賀新年
|
||||
福袋ガチャ",0,0,1,33,10,0,0
|
||||
6,1086,"逢坂 茜
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1087,"珠洲島 有栖
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1088,"九條 楓
|
||||
ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1089,"冬の魔法
|
||||
スーパーウルトラウィンターガチャ",0,1,0,0,10,0,0
|
||||
6,1093,"高瀬 梨緒ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1094,"結城 莉玖ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1095,"藍原 椿ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1096,"早乙女 彩華ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1097,"桜井 春菜ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1098,"逢坂 茜ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1099,"九條 楓ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1100,"珠洲島 有栖ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1101,"LEAF属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1102,"AQUA属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1103,"FIRE属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1104,"夜明け前の双星ガチャ",0,1,0,0,10,0,0
|
||||
6,1105,"謎の洞窟 黄金は実在した!!ガチャ",0,1,0,0,10,0,0
|
||||
6,1106,"スウィートブライダルリミテッドガチャ",0,1,0,0,10,0,0
|
||||
6,1107,"忘れられない、愛(ピュア)とロックがここにある。ガチャ",0,1,0,0,10,0,0
|
||||
6,1108,"メルティ夜ふかしガチャ",0,1,0,0,10,0,0
|
||||
6,1109,"絵本の国のシューターズガチャ",0,1,0,0,10,0,0
|
||||
6,1110,"オンゲキ R.E.D. PLUS 大感謝祭ガチャ",0,1,0,0,10,0,0
|
||||
6,1111,"オンゲキ 3rd Anniversaryガチャ",0,1,1,33,10,0,0
|
||||
6,1113,"柏木 咲姫ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1114,"井之原 小星ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1115,"星咲 あかりピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1116,"藤沢 柚子ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1117,"三角 葵ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1118,"日向 千夏ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1119,"柏木 美亜ピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1120,"東雲 つむぎピックアップガチャ",0,2,0,0,10,0,0
|
||||
6,1121,"LEAF属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1122,"FIRE属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1123,"AQUA属性オンリーガチャ",0,2,0,0,10,0,0
|
||||
6,1125,"Let`s SHOOT!ガチャ",0,1,0,0,10,0,0
|
||||
6,1126,"ぽかぽか""温""ゲキ!いい湯だな リミテッドガチャ",0,1,0,0,10,0,0
|
||||
6,1127,"聖夜に煌めく イルミネーションガチャ",0,1,0,0,10,0,0
|
||||
6,1128,"bitter chocolate kiss ガチャ",0,1,0,0,10,0,0
|
||||
6,1134,"謹賀新年福袋ガチャ",0,1,0,0,10,0,0
|
||||
6,1135,"オンゲキ bright 大感謝祭ガチャ",0,1,0,0,10,0,0
|
||||
7,1140,"カラフルアンブレラガチャ",0,0,0,0,10,0,0
|
||||
7,1141,"It's Showtime!ワンダフルサーカスガチャ",0,0,0,0,10,0,0
|
||||
7,1147,"R.B.P. ピックアップガチャ",0,0,0,0,10,0,0
|
||||
7,1148,"皇城 セツナ ピックアップガチャ",0,0,0,0,10,0,0
|
||||
7,1149,"ASTERISM ピックアップガチャ",0,0,0,0,10,0,0
|
||||
7,1153,"Memories of O.N.G.E.K.I.打ち上げガチャ",0,0,0,0,10,0,0
|
||||
7,1156,"bright memory振り返りガチャ",0,0,0,0,10,0,0
|
||||
7,1158,"レギュラーガチャ",0,0,0,100,0,0,0
|
||||
7,1159,"オンゲキ&オンゲキ PLUS ピックアップガチャ",0,2,0,100,0,0,0
|
||||
7,1160,"SUMMER & SUMMER PLUS ピックアップガチャ",0,2,0,100,0,0,0
|
||||
7,1161,"R.E.D. & R.E.D. PLUS ピックアップガチャ",0,2,0,100,0,0,0
|
||||
7,1162,"bright & bright MEMORY ピックアップガチャ",0,2,0,100,0,0,0
|
||||
7,1163,"4周年記念!! 4rd Anniversaryセレクトガチャ",0,1,0,100,0,0,0
|
||||
7,1164,"2023謹賀新年福袋ガチャ",0,1,0,100,0,0,0
|
||||
7,1165,"5周年記念!! 5rd Anniversaryセレクトガチャ",0,1,0,100,0,0,0
|
||||
7,1166,"2024謹賀新年福袋ガチャ",0,1,0,100,0,0,0
|
||||
7,1167,"6周年記念!! 6rd Anniversaryセレクトガチャ",0,1,0,100,0,0,0
|
||||
7,1168,"2025謹賀新年福袋ガチャ",0,1,0,100,0,0,0
|
|
19
titles/cm/config.py
Normal file
19
titles/cm/config.py
Normal file
@ -0,0 +1,19 @@
|
||||
from core.config import CoreConfig
|
||||
|
||||
|
||||
class CardMakerServerConfig():
|
||||
def __init__(self, parent_config: "CardMakerConfig") -> None:
|
||||
self.__config = parent_config
|
||||
|
||||
@property
|
||||
def enable(self) -> bool:
|
||||
return CoreConfig.get_config_field(self.__config, 'cardmaker', 'server', 'enable', default=True)
|
||||
|
||||
@property
|
||||
def loglevel(self) -> int:
|
||||
return CoreConfig.str_to_loglevel(CoreConfig.get_config_field(self.__config, 'cardmaker', 'server', 'loglevel', default="info"))
|
||||
|
||||
|
||||
class CardMakerConfig(dict):
|
||||
def __init__(self) -> None:
|
||||
self.server = CardMakerServerConfig(self)
|
10
titles/cm/const.py
Normal file
10
titles/cm/const.py
Normal file
@ -0,0 +1,10 @@
|
||||
class CardMakerConstants():
|
||||
GAME_CODE = "SDED"
|
||||
|
||||
VER_CARD_MAKER = 0
|
||||
|
||||
VERSION_NAMES = ["Card Maker 1.34"]
|
||||
|
||||
@classmethod
|
||||
def game_ver_to_string(cls, ver: int):
|
||||
return cls.VERSION_NAMES[ver]
|
91
titles/cm/index.py
Normal file
91
titles/cm/index.py
Normal file
@ -0,0 +1,91 @@
|
||||
from twisted.web.http import Request
|
||||
import json
|
||||
import inflection
|
||||
import yaml
|
||||
import string
|
||||
import logging
|
||||
import coloredlogs
|
||||
import zlib
|
||||
from logging.handlers import TimedRotatingFileHandler
|
||||
|
||||
from core.config import CoreConfig
|
||||
from titles.cm.config import CardMakerConfig
|
||||
from titles.cm.const import CardMakerConstants
|
||||
from titles.cm.base import CardMakerBase
|
||||
|
||||
|
||||
class CardMakerServlet():
|
||||
def __init__(self, core_cfg: CoreConfig, cfg_dir: str) -> None:
|
||||
self.core_cfg = core_cfg
|
||||
self.game_cfg = CardMakerConfig()
|
||||
self.game_cfg.update(yaml.safe_load(open(f"{cfg_dir}/cardmaker.yaml")))
|
||||
|
||||
self.versions = [
|
||||
CardMakerBase(core_cfg, self.game_cfg)
|
||||
]
|
||||
|
||||
self.logger = logging.getLogger("cardmaker")
|
||||
log_fmt_str = "[%(asctime)s] Card Maker | %(levelname)s | %(message)s"
|
||||
log_fmt = logging.Formatter(log_fmt_str)
|
||||
fileHandler = TimedRotatingFileHandler("{0}/{1}.log".format(self.core_cfg.server.log_dir, "cardmaker"), encoding='utf8',
|
||||
when="d", backupCount=10)
|
||||
|
||||
fileHandler.setFormatter(log_fmt)
|
||||
|
||||
consoleHandler = logging.StreamHandler()
|
||||
consoleHandler.setFormatter(log_fmt)
|
||||
|
||||
self.logger.addHandler(fileHandler)
|
||||
self.logger.addHandler(consoleHandler)
|
||||
|
||||
self.logger.setLevel(self.game_cfg.server.loglevel)
|
||||
coloredlogs.install(level=self.game_cfg.server.loglevel, logger=self.logger, fmt=log_fmt_str)
|
||||
|
||||
def render_POST(self, request: Request, version: int, url_path: str) -> bytes:
|
||||
req_raw = request.content.getvalue()
|
||||
url_split = url_path.split("/")
|
||||
internal_ver = 0
|
||||
endpoint = url_split[len(url_split) - 1]
|
||||
|
||||
print(f"version: {version}")
|
||||
|
||||
if version >= 130 and version < 135: # Card Maker
|
||||
internal_ver = CardMakerConstants.VER_CARD_MAKER
|
||||
|
||||
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
|
||||
# doing encrypted. The likelyhood of false positives is low but
|
||||
# technically not 0
|
||||
self.logger.error("Encryption not supported at this time")
|
||||
|
||||
try:
|
||||
unzip = zlib.decompress(req_raw)
|
||||
|
||||
except zlib.error as e:
|
||||
self.logger.error(f"Failed to decompress v{version} {endpoint} request -> {e}")
|
||||
return zlib.compress("{\"stat\": \"0\"}".encode("utf-8"))
|
||||
|
||||
req_data = json.loads(unzip)
|
||||
|
||||
self.logger.info(f"v{version} {endpoint} request - {req_data}")
|
||||
|
||||
func_to_find = "handle_" + inflection.underscore(endpoint) + "_request"
|
||||
|
||||
try:
|
||||
handler = getattr(self.versions[internal_ver], func_to_find)
|
||||
resp = handler(req_data)
|
||||
|
||||
except AttributeError as e:
|
||||
self.logger.warning(f"Unhandled v{version} request {endpoint} - {e}")
|
||||
return zlib.compress("{\"stat\": \"0\"}".encode("utf-8"))
|
||||
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error handling v{version} method {endpoint} - {e}")
|
||||
return zlib.compress("{\"stat\": \"0\"}".encode("utf-8"))
|
||||
|
||||
if resp is None:
|
||||
resp = {'returnCode': 1}
|
||||
|
||||
self.logger.info(f"Response {resp}")
|
||||
|
||||
return zlib.compress(json.dumps(resp, ensure_ascii=False).encode("utf-8"))
|
199
titles/cm/read.py
Normal file
199
titles/cm/read.py
Normal file
@ -0,0 +1,199 @@
|
||||
from decimal import Decimal
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import csv
|
||||
import xml.etree.ElementTree as ET
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
from read import BaseReader
|
||||
from core.config import CoreConfig
|
||||
from titles.ongeki.database import OngekiData
|
||||
from titles.cm.const import CardMakerConstants
|
||||
from titles.ongeki.const import OngekiConstants
|
||||
from titles.ongeki.config import OngekiConfig
|
||||
|
||||
|
||||
class CardMakerReader(BaseReader):
|
||||
def __init__(self, config: CoreConfig, version: int, bin_dir: Optional[str],
|
||||
opt_dir: Optional[str], extra: Optional[str]) -> None:
|
||||
super().__init__(config, version, bin_dir, opt_dir, extra)
|
||||
self.ongeki_data = OngekiData(config)
|
||||
|
||||
try:
|
||||
self.logger.info(
|
||||
f"Start importer for {CardMakerConstants.game_ver_to_string(version)}")
|
||||
except IndexError:
|
||||
self.logger.error(f"Invalid ongeki version {version}")
|
||||
exit(1)
|
||||
|
||||
def read(self) -> None:
|
||||
static_datas = {
|
||||
"static_cards.csv": "read_ongeki_card_csv",
|
||||
"static_gachas.csv": "read_ongeki_gacha_csv",
|
||||
"static_gacha_cards.csv": "read_ongeki_gacha_card_csv"
|
||||
}
|
||||
|
||||
if self.bin_dir is not None:
|
||||
for file, func in static_datas.items():
|
||||
if os.path.exists(f"{self.bin_dir}/MU3/{file}"):
|
||||
read_csv = getattr(CardMakerReader, func)
|
||||
read_csv(self, f"{self.bin_dir}/MU3/{file}")
|
||||
else:
|
||||
self.logger.warn(f"Couldn't find {file} file in {self.bin_dir}, skipping")
|
||||
|
||||
if self.opt_dir is not None:
|
||||
dir = self.get_data_directories(self.opt_dir)
|
||||
|
||||
# ONGEKI (MU3) cnnot easily access the bin data(A000.pac)
|
||||
# so only opt_dir will work for now
|
||||
self.read_gacha(f"{dir}/MU3/gacha")
|
||||
self.read_card(f"{dir}/MU3/card")
|
||||
|
||||
def read_ongeki_card_csv(self, file_path: str) -> None:
|
||||
self.logger.info(f"Reading cards from {file_path}...")
|
||||
|
||||
with open(file_path, encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
self.ongeki_data.static.put_card(
|
||||
row["version"],
|
||||
row["cardId"],
|
||||
name=row["name"],
|
||||
charaId=row["charaId"],
|
||||
nickName=row["nickName"] if row["nickName"] != "" else None,
|
||||
school=row["school"],
|
||||
attribute=row["attribute"],
|
||||
gakunen=row["gakunen"],
|
||||
rarity=row["rarity"],
|
||||
levelParam=row["levelParam"],
|
||||
skillId=row["skillId"],
|
||||
choKaikaSkillId=row["choKaikaSkillId"],
|
||||
cardNumber=row["cardNumber"] if row["cardNumber"] != "" else None
|
||||
)
|
||||
|
||||
self.logger.info(f"Added card {row['cardId']}")
|
||||
|
||||
def read_ongeki_gacha_csv(self, file_path: str) -> None:
|
||||
self.logger.info(f"Reading gachas from {file_path}...")
|
||||
|
||||
with open(file_path, encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
self.ongeki_data.static.put_gacha(
|
||||
row["version"],
|
||||
row["gachaId"],
|
||||
row["gachaName"],
|
||||
row["kind"],
|
||||
type=row["type"],
|
||||
isCeiling=True if row["isCeiling"] == "1" else False,
|
||||
maxSelectPoint=row["maxSelectPoint"],
|
||||
ceilingCnt=row["ceilingCnt"],
|
||||
changeRateCnt1=row["changeRateCnt1"],
|
||||
changeRateCnt2=row["changeRateCnt2"]
|
||||
)
|
||||
|
||||
self.logger.info(f"Added gacha {row['gachaId']}")
|
||||
|
||||
def read_ongeki_gacha_card_csv(self, file_path: str) -> None:
|
||||
self.logger.info(f"Reading gacha cards from {file_path}...")
|
||||
|
||||
with open(file_path, encoding="utf-8") as f:
|
||||
reader = csv.DictReader(f)
|
||||
for row in reader:
|
||||
self.ongeki_data.static.put_gacha_card(
|
||||
row["gachaId"],
|
||||
row["cardId"],
|
||||
rarity=row["rarity"],
|
||||
weight=row["weight"],
|
||||
isPickup=True if row["isPickup"] == "1" else False,
|
||||
isSelect=True if row["isSelect"] == "1" else False
|
||||
)
|
||||
|
||||
self.logger.info(f"Added card {row['cardId']} to gacha")
|
||||
|
||||
def read_ongeki_card(self, base_dir: str) -> None:
|
||||
self.logger.info(f"Reading cards from {base_dir}...")
|
||||
|
||||
version_ids = {
|
||||
'1000': OngekiConstants.VER_ONGEKI,
|
||||
'1005': OngekiConstants.VER_ONGEKI_PLUS,
|
||||
'1010': OngekiConstants.VER_ONGEKI_SUMMER,
|
||||
'1015': OngekiConstants.VER_ONGEKI_SUMMER_PLUS,
|
||||
'1020': OngekiConstants.VER_ONGEKI_RED,
|
||||
'1025': OngekiConstants.VER_ONGEKI_RED_PLUS,
|
||||
'1030': OngekiConstants.VER_ONGEKI_BRIGHT,
|
||||
'1035': OngekiConstants.VER_ONGEKI_BRIGHT_MEMORY
|
||||
}
|
||||
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
for dir in dirs:
|
||||
if os.path.exists(f"{root}/{dir}/Card.xml"):
|
||||
with open(f"{root}/{dir}/Card.xml", "r", encoding="utf-8") as f:
|
||||
troot = ET.fromstring(f.read())
|
||||
|
||||
card_id = int(troot.find('Name').find('id').text)
|
||||
name = troot.find('Name').find('str').text
|
||||
chara_id = int(troot.find('CharaID').find('id').text)
|
||||
nick_name = troot.find('NickName').text
|
||||
school = troot.find('School').find('str').text
|
||||
attribute = troot.find('Attribute').text
|
||||
gakunen = troot.find('Gakunen').find('str').text
|
||||
rarity = OngekiConstants.RARITY_TYPES[
|
||||
troot.find('Rarity').text].value
|
||||
|
||||
level_param = []
|
||||
for lvl in troot.find('LevelParam').findall('int'):
|
||||
level_param.append(lvl.text)
|
||||
|
||||
skill_id = int(troot.find('SkillID').find('id').text)
|
||||
cho_kai_ka_skill_id = int(troot.find('ChoKaikaSkillID').find('id').text)
|
||||
|
||||
version = version_ids[
|
||||
troot.find('VersionID').find('id').text]
|
||||
card_number = troot.find('CardNumberString').text
|
||||
|
||||
self.ongeki_data.static.put_card(
|
||||
version,
|
||||
card_id,
|
||||
name=name,
|
||||
charaId=chara_id,
|
||||
nickName=nick_name,
|
||||
school=school,
|
||||
attribute=attribute,
|
||||
gakunen=gakunen,
|
||||
rarity=rarity,
|
||||
levelParam=','.join(level_param),
|
||||
skillId=skill_id,
|
||||
choKaikaSkillId=cho_kai_ka_skill_id,
|
||||
cardNumber=card_number
|
||||
)
|
||||
self.logger.info(f"Added card {card_id}")
|
||||
|
||||
def read_ongeki_gacha(self, base_dir: str) -> None:
|
||||
self.logger.info(f"Reading gachas from {base_dir}...")
|
||||
|
||||
# assuming some GachaKinds based on the GachaType
|
||||
type_to_kind = {
|
||||
"Normal": "Normal",
|
||||
"Pickup": "Pickup",
|
||||
"RecoverFiveShotFlag": "BonusRestored",
|
||||
"Free": "Free",
|
||||
"FreeSR": "Free"
|
||||
}
|
||||
|
||||
for root, dirs, files in os.walk(base_dir):
|
||||
for dir in dirs:
|
||||
if os.path.exists(f"{root}/{dir}/Gacha.xml"):
|
||||
with open(f"{root}/{dir}/Gacha.xml", "r", encoding="utf-8") as f:
|
||||
troot = ET.fromstring(f.read())
|
||||
|
||||
name = troot.find('Name').find('str').text
|
||||
id = int(troot.find('Name').find('id').text)
|
||||
|
||||
gacha_kind = OngekiConstants.CM_GACHA_KINDS[
|
||||
type_to_kind[troot.find('Type').text]].value
|
||||
|
||||
self.ongeki_data.static.put_gacha(
|
||||
self.version, id, name, gacha_kind)
|
||||
self.logger.info(f"Added gacha {id}")
|
Reference in New Issue
Block a user