Compare commits

...

3 Commits

13 changed files with 150 additions and 51 deletions

View File

@ -0,0 +1,3 @@
ALTER TABLE mai2_item_card
CHANGE COLUMN startDate startDate TIMESTAMP DEFAULT "2018-01-01 00:00:00.0",
CHANGE COLUMN endDate endDate TIMESTAMP DEFAULT "2038-01-01 00:00:00.0";

View File

@ -0,0 +1,3 @@
ALTER TABLE mai2_item_card
CHANGE COLUMN startDate startDate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
CHANGE COLUMN endDate endDate TIMESTAMP NOT NULL;

View File

@ -253,13 +253,13 @@ python dbutils.py --game SDDT upgrade
| Version ID | Version Name | | Version ID | Version Name |
|------------|-----------------| |------------|-----------------|
| 0 | Card Maker 1.34 | | 0 | Card Maker 1.30 |
| 1 | Card Maker 1.35 | | 1 | Card Maker 1.35 |
### Support status ### Support status
* Card Maker 1.34: * Card Maker 1.30:
* CHUNITHM NEW!!: Yes * CHUNITHM NEW!!: Yes
* maimai DX UNiVERSE: Yes * maimai DX UNiVERSE: Yes
* O.N.G.E.K.I. Bright: Yes * O.N.G.E.K.I. Bright: Yes
@ -285,19 +285,46 @@ python read.py --series SDED --version <version ID> --binfolder titles/cm/cm_dat
python read.py --series SDDT --version <version ID> --binfolder /path/to/game/folder --optfolder /path/to/game/option/folder python read.py --series SDDT --version <version ID> --binfolder /path/to/game/folder --optfolder /path/to/game/option/folder
``` ```
Also make sure to import all maimai and Chunithm data as well: Also make sure to import all maimai DX and CHUNITHM data as well:
```shell ```shell
python read.py --series SDED --version <version ID> --binfolder /path/to/cardmaker/CardMaker_Data python read.py --series SDED --version <version ID> --binfolder /path/to/cardmaker/CardMaker_Data
``` ```
The importer for Card Maker will import all required Gachas (Banners) and cards (for maimai/Chunithm) and the hardcoded The importer for Card Maker will import all required Gachas (Banners) and cards (for maimai DX/CHUNITHM) and the hardcoded
Cards for each Gacha (O.N.G.E.K.I. only). Cards for each Gacha (O.N.G.E.K.I. only).
**NOTE: Without executing the importer Card Maker WILL NOT work!** **NOTE: Without executing the importer Card Maker WILL NOT work!**
### O.N.G.E.K.I. Gachas ### Config setup
Make sure to update your `config/cardmaker.yaml` with the correct version for each game. To get the current version required to run a specific game, open every opt (Axxx) folder descending until you find all three folders:
- `MU3`: O.N.G.E.K.I.
- `MAI`: maimai DX
- `CHU`: CHUNITHM
Inside each folder is a `DataConfig.xml` file, for example:
`MU3/DataConfig.xml`:
```xml
<cardMakerVersion>
<major>1</major>
<minor>35</minor>
<release>3</release>
</cardMakerVersion>
```
Now update your `config/cardmaker.yaml` with the correct version number, for example:
```yaml
version:
1: # Card Maker 1.35
ongeki: 1.35.03
```
### O.N.G.E.K.I.
Gacha "無料ガチャ" can only pull from the free cards with the following probabilities: 94%: R, 5% SR and 1% chance of Gacha "無料ガチャ" can only pull from the free cards with the following probabilities: 94%: R, 5% SR and 1% chance of
getting an SSR card getting an SSR card
@ -310,20 +337,24 @@ and 3% chance of getting an SSR card
All other (limited) gachas can pull from every card added to ongeki_static_cards but with the promoted cards All other (limited) gachas can pull from every card added to ongeki_static_cards but with the promoted cards
(click on the green button under the banner) having a 10 times higher chance to get pulled (click on the green button under the banner) having a 10 times higher chance to get pulled
### Chunithm Gachas ### CHUNITHM
All cards in Chunithm (basically just the characters) have the same rarity to it just pulls randomly from all cards All cards in CHUNITHM (basically just the characters) have the same rarity to it just pulls randomly from all cards
from a given gacha but made sure you cannot pull the same card twice in the same 5 times gacha roll. from a given gacha but made sure you cannot pull the same card twice in the same 5 times gacha roll.
### maimai DX
Printed maimai DX cards: Freedom (`cardTypeId=6`) or Gold Pass (`cardTypeId=4`) can now be selected during the login process. You can only have ONE Freedom and ONE Gold Pass active at a given time. The cards will expire after 15 days.
Thanks GetzeAvenue for the `selectedCardList` rarity hint!
### Notes ### Notes
Card Maker 1.34 will only load an O.N.G.E.K.I. Bright profile (1.30). Card Maker 1.35 will only load an O.N.G.E.K.I. Card Maker 1.30-1.34 will only load an O.N.G.E.K.I. Bright profile (1.30). Card Maker 1.35+ will only load an O.N.G.E.K.I.
Bright Memory profile (1.35). Bright Memory profile (1.35).
The gachas inside the `ongeki.yaml` will make sure only the right gacha ids for the right CM version will be loaded. The gachas inside the `config/ongeki.yaml` will make sure only the right gacha ids for the right CM version will be loaded.
Gacha IDs up to 1140 will be loaded for CM 1.34 and all gachas will be loaded for CM 1.35. Gacha IDs up to 1140 will be loaded for CM 1.34 and all gachas will be loaded for CM 1.35.
**NOTE: There is currently no way to load/use the (printed) maimai DX cards!**
## WACCA ## WACCA
### SDFE ### SDFE

View File

@ -1,3 +1,13 @@
server: server:
enable: True enable: True
loglevel: "info" loglevel: "info"
version:
0:
ongeki: 1.30.01
chuni: 2.00.00
maimai: 1.20.00
1:
ongeki: 1.35.03
chuni: 2.10.00
maimai: 1.30.00

View File

@ -17,7 +17,7 @@ Games listed below have been tested and confirmed working. Only game versions ol
+ All versions + All versions
+ Card Maker + Card Maker
+ 1.34 + 1.30
+ 1.35 + 1.35
+ O.N.G.E.K.I. + O.N.G.E.K.I.

View File

@ -23,19 +23,40 @@ class CardMakerBase:
self.game = CardMakerConstants.GAME_CODE self.game = CardMakerConstants.GAME_CODE
self.version = CardMakerConstants.VER_CARD_MAKER self.version = CardMakerConstants.VER_CARD_MAKER
@staticmethod
def _parse_int_ver(version: str) -> str:
return version.replace(".", "")[:3]
def handle_get_game_connect_api_request(self, data: Dict) -> Dict: def handle_get_game_connect_api_request(self, data: Dict) -> Dict:
if self.core_cfg.server.is_develop: if self.core_cfg.server.is_develop:
uri = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}" uri = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}"
else: else:
uri = f"http://{self.core_cfg.title.hostname}" uri = f"http://{self.core_cfg.title.hostname}"
# CHUNITHM = 0, maimai = 1, ONGEKI = 2 # grab the dict with all games version numbers from user config
games_ver = self.game_cfg.version.version(self.version)
return { return {
"length": 3, "length": 3,
"gameConnectList": [ "gameConnectList": [
{"modelKind": 0, "type": 1, "titleUri": f"{uri}/SDHD/200/"}, # CHUNITHM
{"modelKind": 1, "type": 1, "titleUri": f"{uri}/SDEZ/120/"}, {
{"modelKind": 2, "type": 1, "titleUri": f"{uri}/SDDT/130/"}, "modelKind": 0,
"type": 1,
"titleUri": f"{uri}/SDHD/{self._parse_int_ver(games_ver['chuni'])}/",
},
# maimai DX
{
"modelKind": 1,
"type": 1,
"titleUri": f"{uri}/SDEZ/{self._parse_int_ver(games_ver['maimai'])}/",
},
# ONGEKI
{
"modelKind": 2,
"type": 1,
"titleUri": f"{uri}/SDDT/{self._parse_int_ver(games_ver['ongeki'])}/",
},
], ],
} }
@ -47,12 +68,15 @@ class CardMakerBase:
datetime.now() + timedelta(hours=4), self.date_time_format datetime.now() + timedelta(hours=4), self.date_time_format
) )
# grab the dict with all games version numbers from user config
games_ver = self.game_cfg.version.version(self.version)
return { return {
"gameSetting": { "gameSetting": {
"dataVersion": "1.30.00", "dataVersion": "1.30.00",
"ongekiCmVersion": "1.30.01", "ongekiCmVersion": games_ver["ongeki"],
"chuniCmVersion": "2.00.00", "chuniCmVersion": games_ver["chuni"],
"maimaiCmVersion": "1.20.00", "maimaiCmVersion": games_ver["maimai"],
"requestInterval": 10, "requestInterval": 10,
"rebootStartTime": reboot_start, "rebootStartTime": reboot_start,
"rebootEndTime": reboot_end, "rebootEndTime": reboot_end,

View File

@ -1,8 +1,4 @@
from datetime import date, datetime, timedelta from typing import Dict
from typing import Any, Dict, List
import json
import logging
from enum import Enum
from core.config import CoreConfig from core.config import CoreConfig
from core.data.cache import cached from core.data.cache import cached
@ -16,23 +12,7 @@ class CardMaker135(CardMakerBase):
super().__init__(core_cfg, game_cfg) super().__init__(core_cfg, game_cfg)
self.version = CardMakerConstants.VER_CARD_MAKER_135 self.version = CardMakerConstants.VER_CARD_MAKER_135
def handle_get_game_connect_api_request(self, data: Dict) -> Dict:
ret = super().handle_get_game_connect_api_request(data)
if self.core_cfg.server.is_develop:
uri = f"http://{self.core_cfg.title.hostname}:{self.core_cfg.title.port}"
else:
uri = f"http://{self.core_cfg.title.hostname}"
ret["gameConnectList"][0]["titleUri"] = f"{uri}/SDHD/205/"
ret["gameConnectList"][1]["titleUri"] = f"{uri}/SDEZ/125/"
ret["gameConnectList"][2]["titleUri"] = f"{uri}/SDDT/135/"
return ret
def handle_get_game_setting_api_request(self, data: Dict) -> Dict: def handle_get_game_setting_api_request(self, data: Dict) -> Dict:
ret = super().handle_get_game_setting_api_request(data) ret = super().handle_get_game_setting_api_request(data)
ret["gameSetting"]["dataVersion"] = "1.35.00" ret["gameSetting"]["dataVersion"] = "1.35.00"
ret["gameSetting"]["ongekiCmVersion"] = "1.35.03"
ret["gameSetting"]["chuniCmVersion"] = "2.05.00"
ret["gameSetting"]["maimaiCmVersion"] = "1.25.00"
return ret return ret

View File

@ -1,3 +1,4 @@
from typing import Dict
from core.config import CoreConfig from core.config import CoreConfig
@ -20,6 +21,21 @@ class CardMakerServerConfig:
) )
class CardMakerVersionConfig:
def __init__(self, parent_config: "CardMakerConfig") -> None:
self.__config = parent_config
def version(self, version: int) -> Dict:
"""
in the form of:
1: {"ongeki": 1.30.01, "chuni": 2.00.00, "maimai": 1.20.00}
"""
return CoreConfig.get_config_field(
self.__config, "cardmaker", "version", default={}
)[version]
class CardMakerConfig(dict): class CardMakerConfig(dict):
def __init__(self) -> None: def __init__(self) -> None:
self.server = CardMakerServerConfig(self) self.server = CardMakerServerConfig(self)
self.version = CardMakerVersionConfig(self)

View File

@ -6,7 +6,7 @@ class CardMakerConstants:
VER_CARD_MAKER = 0 VER_CARD_MAKER = 0
VER_CARD_MAKER_135 = 1 VER_CARD_MAKER_135 = 1
VERSION_NAMES = ("Card Maker 1.34", "Card Maker 1.35") VERSION_NAMES = ("Card Maker 1.30", "Card Maker 1.35")
@classmethod @classmethod
def game_ver_to_string(cls, ver: int): def game_ver_to_string(cls, ver: int):

View File

@ -30,7 +30,7 @@ class CardMakerServlet:
self.versions = [ self.versions = [
CardMakerBase(core_cfg, self.game_cfg), CardMakerBase(core_cfg, self.game_cfg),
CardMaker135(core_cfg, self.game_cfg), CardMaker135(core_cfg, self.game_cfg)
] ]
self.logger = logging.getLogger("cardmaker") self.logger = logging.getLogger("cardmaker")
@ -89,7 +89,7 @@ class CardMakerServlet:
if version >= 130 and version < 135: # Card Maker if version >= 130 and version < 135: # Card Maker
internal_ver = CardMakerConstants.VER_CARD_MAKER internal_ver = CardMakerConstants.VER_CARD_MAKER
elif version >= 135 and version < 136: # Card Maker 1.35 elif version >= 135 and version < 140: # Card Maker 1.35
internal_ver = CardMakerConstants.VER_CARD_MAKER_135 internal_ver = CardMakerConstants.VER_CARD_MAKER_135
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:

View File

@ -7,4 +7,4 @@ index = Mai2Servlet
database = Mai2Data database = Mai2Data
reader = Mai2Reader reader = Mai2Reader
game_codes = [Mai2Constants.GAME_CODE] game_codes = [Mai2Constants.GAME_CODE]
current_schema_version = 4 current_schema_version = 5

View File

@ -39,8 +39,8 @@ card = Table(
Column("cardTypeId", Integer, nullable=False), Column("cardTypeId", Integer, nullable=False),
Column("charaId", Integer, nullable=False), Column("charaId", Integer, nullable=False),
Column("mapId", Integer, nullable=False), Column("mapId", Integer, nullable=False),
Column("startDate", TIMESTAMP, server_default="2018-01-01 00:00:00.0"), Column("startDate", TIMESTAMP, nullable=False, server_default=func.now()),
Column("endDate", TIMESTAMP, server_default="2038-01-01 00:00:00.0"), Column("endDate", TIMESTAMP, nullable=False),
UniqueConstraint("user", "cardId", "cardTypeId", name="mai2_item_card_uk"), UniqueConstraint("user", "cardId", "cardTypeId", name="mai2_item_card_uk"),
mysql_charset="utf8mb4", mysql_charset="utf8mb4",
) )
@ -444,6 +444,8 @@ class Mai2ItemData(BaseData):
card_kind: int, card_kind: int,
chara_id: int, chara_id: int,
map_id: int, map_id: int,
start_date: datetime,
end_date: datetime,
) -> Optional[Row]: ) -> Optional[Row]:
sql = insert(card).values( sql = insert(card).values(
user=user_id, user=user_id,
@ -451,9 +453,13 @@ class Mai2ItemData(BaseData):
cardTypeId=card_kind, cardTypeId=card_kind,
charaId=chara_id, charaId=chara_id,
mapId=map_id, mapId=map_id,
startDate=start_date,
endDate=end_date,
) )
conflict = sql.on_duplicate_key_update(charaId=chara_id, mapId=map_id) conflict = sql.on_duplicate_key_update(
charaId=chara_id, mapId=map_id, startDate=start_date, endDate=end_date
)
result = self.execute(conflict) result = self.execute(conflict)
if result is None: if result is None:

View File

@ -104,8 +104,12 @@ class Mai2Universe(Mai2Base):
tmp.pop("id") tmp.pop("id")
tmp.pop("user") tmp.pop("user")
tmp["startDate"] = datetime.strftime(tmp["startDate"], "%Y-%m-%d %H:%M:%S") tmp["startDate"] = datetime.strftime(
tmp["endDate"] = datetime.strftime(tmp["endDate"], "%Y-%m-%d %H:%M:%S") tmp["startDate"], Mai2Constants.DATE_TIME_FORMAT
)
tmp["endDate"] = datetime.strftime(
tmp["endDate"], Mai2Constants.DATE_TIME_FORMAT
)
card_list.append(tmp) card_list.append(tmp)
return { return {
@ -154,6 +158,10 @@ class Mai2Universe(Mai2Base):
# set a random card serial number # set a random card serial number
serial_id = "".join([str(randint(0, 9)) for _ in range(20)]) serial_id = "".join([str(randint(0, 9)) for _ in range(20)])
# calculate start and end date of the card
start_date = datetime.utcnow()
end_date = datetime.utcnow() + timedelta(days=15)
user_card = upsert["userCard"] user_card = upsert["userCard"]
self.data.item.put_card( self.data.item.put_card(
user_id, user_id,
@ -161,8 +169,26 @@ class Mai2Universe(Mai2Base):
user_card["cardTypeId"], user_card["cardTypeId"],
user_card["charaId"], user_card["charaId"],
user_card["mapId"], user_card["mapId"],
# add the correct start date and also the end date in 15 days
start_date,
end_date,
) )
# get the profile extend to save the new bought card
extend = self.data.profile.get_profile_extend(user_id, self.version)
if extend:
extend = extend._asdict()
# parse the selectedCardList
# 6 = Freedom Pass, 4 = Gold Pass (cardTypeId)
selected_cards: list = extend["selectedCardList"]
# if no pass is already added, add the corresponding pass
if not user_card["cardTypeId"] in selected_cards:
selected_cards.insert(0, user_card["cardTypeId"])
extend["selectedCardList"] = selected_cards
self.data.profile.put_profile_extend(user_id, self.version, extend)
# properly format userPrintDetail for the database # properly format userPrintDetail for the database
upsert.pop("userCard") upsert.pop("userCard")
upsert.pop("serialId") upsert.pop("serialId")
@ -174,8 +200,8 @@ class Mai2Universe(Mai2Base):
"returnCode": 1, "returnCode": 1,
"orderId": 0, "orderId": 0,
"serialId": serial_id, "serialId": serial_id,
"startDate": "2018-01-01 00:00:00", "startDate": datetime.strftime(start_date, Mai2Constants.DATE_TIME_FORMAT),
"endDate": "2038-01-01 00:00:00", "endDate": datetime.strftime(end_date, Mai2Constants.DATE_TIME_FORMAT),
} }
def handle_cm_upsert_user_printlog_api_request(self, data: Dict) -> Dict: def handle_cm_upsert_user_printlog_api_request(self, data: Dict) -> Dict: