This repository has been archived by the owner on Jun 9, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ADD - basic skill data parsing functionality
Signed-off-by: RaenonX <[email protected]>
- Loading branch information
0 parents
commit 1b2c776
Showing
54 changed files
with
1,971 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: DL Data Parser - CI Tests | ||
|
||
on: [push] | ||
|
||
jobs: | ||
pytest: | ||
name: Run tests | ||
|
||
runs-on: windows-latest | ||
|
||
continue-on-error: true | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions/setup-python@v2 | ||
|
||
- name: Install required packages | ||
run: | | ||
pip install -r requirements-dev.txt | ||
- name: Run tests | ||
run: | | ||
pytest |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
name: DL Data Parser - CQA | ||
|
||
on: [push] | ||
|
||
jobs: | ||
cqa: | ||
name: CQA | ||
|
||
runs-on: windows-latest | ||
|
||
continue-on-error: true | ||
|
||
steps: | ||
- uses: actions/checkout@v2 | ||
|
||
- uses: actions/setup-python@v2 | ||
|
||
- name: Install required packages | ||
run: | | ||
pip install -r requirements-dev.txt | ||
- name: pydocstyle checks (`dlparse`) | ||
run: | | ||
pydocstyle dlparse --count | ||
- name: pylint checks (`dlparse`) | ||
run: | | ||
pylint dlparse |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Game assets (excluding images) | ||
.data/media/assets/_gluonresources/resources/images | ||
|
||
# Test cache | ||
.pytest_cache | ||
|
||
# IntelliJ project files | ||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
[pydocstyle] | ||
ignore = | ||
# Public method missing docstring - `pylint` will check if there's really missing the docstring | ||
D102, | ||
# Magic method missing docstring - no need for it | ||
D105, | ||
# __init__ missing docstring - optional. add details to class docstring | ||
D107, | ||
# Blank line required before docstring - mutually exclusive to D204 | ||
D203, | ||
# Multi-line docstring summary should start at the first line - mutually exclusive to D213 | ||
D212, | ||
# Section underline is over-indented | ||
D215, | ||
# First line should be in imperative mood | ||
D401, | ||
# First word of the docstring should not be This | ||
D404, | ||
# Section name should end with a newline | ||
D406, | ||
# Missing dashed underline after section | ||
D407, | ||
# Section underline should be in the line following the section’s name | ||
D408, | ||
# Section underline should match the length of its name | ||
D409, | ||
# No blank lines allowed between a section header and its content | ||
D412, | ||
# Missing blank line after last section | ||
D413 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
[BASIC] | ||
|
||
# Reason of the good names: | ||
# - _ | ||
# often used as dummy variable during unpacking | ||
# - T | ||
# often used to for TypeVar | ||
# - f | ||
# often used as a file stream name | ||
# - i, j, k | ||
# often used in for loops | ||
# - s | ||
# often used to represent "string" | ||
# - v | ||
# often used to represent "value" | ||
# - dt, tz | ||
# often used in datetime handling (dt for datetime, tz for timezone) | ||
# - ex | ||
# often used as the var name of exception caught by try..except | ||
# - fn | ||
# often used to represent a function address | ||
|
||
good-names=_,T,f,i,j,k,s,v,dt,ex,fn,tz | ||
|
||
[DESIGN] | ||
|
||
max-args=10 | ||
|
||
[FORMAT] | ||
|
||
max-line-length=119 | ||
|
||
[MESSAGES CONTROL] | ||
|
||
# TODO: `unsubscriptable-object` generates false positives for python 3.9 and pylint==2.6. | ||
# https://github.com/PyCQA/pylint/issues/3882 | ||
# Re-enable it when the issue is fixed. | ||
disable=unsubscriptable-object |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# dragalia-data-parse | ||
|
||
This parses the original Dragalia Lost assets to be the file usable for [DL info website][DL-info]. | ||
|
||
Developed under Python 3.9. | ||
|
||
[DL-info]: http://dl.raenonx.cc | ||
[RaenonX-DL]: https://github.com/RaenonX-DL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Main parser for the Dragalia Lost data.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
"""Various in-asset enums.""" | ||
from .affliction import Affliction |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"""Affliction enums.""" | ||
from enum import IntEnum | ||
|
||
__all__ = ("Affliction",) | ||
|
||
|
||
class Affliction(IntEnum): | ||
"""Affliction enums used in the assets.""" | ||
|
||
NONE = 0 | ||
POISON = 1 | ||
BURN = 2 | ||
FREEZE = 3 | ||
PARALYZE = 4 | ||
BLIND = 5 | ||
STUN = 6 | ||
CURSE = 7 | ||
BOG = 9 | ||
SLEEP = 10 | ||
FROSTBITE = 11 | ||
FLASHBURN = 12 | ||
CRASHWIND = 13 | ||
SHADOWBLIGHT = 14 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"""Error classes to be raised during runtime.""" | ||
from typing import Optional | ||
|
||
__all__ = ("SkillDataNotFound", "ActionDataNotFound") | ||
|
||
|
||
class SkillDataNotFound(ValueError): | ||
"""Error to be raised if the skill data is not found.""" | ||
|
||
def __init__(self, skill_id: int): | ||
super().__init__(f"Skill data of ID `{skill_id}` not found") | ||
|
||
self._skill_id = skill_id | ||
|
||
@property | ||
def skill_id(self): | ||
"""Get the skill ID that causes this error.""" | ||
return self._skill_id | ||
|
||
|
||
class ActionDataNotFound(ValueError): | ||
"""Error to be raised if the action data file is not found.""" | ||
|
||
def __init__(self, action_id: int, skill_id: Optional[int] = None): | ||
super().__init__(f"Action data of action ID `{action_id}` / skill ID `{skill_id}` not found") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
"""Various data models to be output.""" | ||
from .skill import AttackingSkillData |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
"""Models for character skills.""" | ||
from dataclasses import dataclass, field | ||
|
||
from dlparse.mono.asset import HitAttrEntry | ||
|
||
__all__ = ("AttackingSkillData",) | ||
|
||
|
||
@dataclass | ||
class AttackingSkillData: | ||
""" | ||
An attacking skill data. | ||
Both ``hit_count`` and ``mods`` should be sorted by the skill level. | ||
For example, if skill level 1 has 1 hit and 100% mods while skill level 2 has 2 hits and 150% + 200% mods, | ||
``hit_count`` should be ``[1, 2]`` and ``mods`` should be ``[[1.0], [1.5, 2.0]]``. | ||
""" | ||
|
||
hit_count: list[int] | ||
mods: list[list[float]] | ||
|
||
damage_hit_attrs: list[list[HitAttrEntry]] | ||
|
||
total_mod: list[float] = field(init=False) | ||
|
||
def __post_init__(self): | ||
self.total_mod = [sum(mods) for mods in self.mods] | ||
|
||
@property | ||
def hit_count_at_max(self) -> int: | ||
"""Get the skill hit count at the max level.""" | ||
return self.hit_count[-1] | ||
|
||
@property | ||
def total_mod_at_max(self) -> float: | ||
"""Get the total skill modifier at the max level.""" | ||
return self.total_mod[-1] | ||
|
||
@property | ||
def mods_at_max(self) -> list[float]: | ||
"""Get the skill modifiers at the max level.""" | ||
return self.mods[-1] | ||
|
||
@property | ||
def max_available_level(self) -> int: | ||
""" | ||
Get the max available level of a skill. | ||
This max level does **NOT** reflect the actual max level in-game. | ||
To get such, character data is needed. | ||
""" | ||
return len(self.hit_count) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Classes for mono behaviors.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"""Asset classes for mono behavior scripts.""" | ||
from .master import * # noqa | ||
from .player_action import * # noqa |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
"""Base classes for mono behavior scripts.""" | ||
from .master import MasterEntryBase, MasterAssetBase, MasterParserBase | ||
from .player_action import ActionComponentBase, ActionAssetBase, ActionParserBase, ActionComponentDamageDealerMixin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
"""Base asset class.""" | ||
import os | ||
from abc import ABC, abstractmethod | ||
from typing import Type, Optional | ||
|
||
from .parser import ParserBase | ||
|
||
__all__ = ("AssetBase",) | ||
|
||
|
||
class AssetBase(ABC): | ||
"""Base class for the mono behavior assets.""" | ||
|
||
asset_file_name: Optional[str] = None | ||
|
||
def __init__(self, parser_cls: Type[ParserBase], file_path: Optional[str] = None, /, | ||
asset_dir: Optional[str] = None): | ||
file_path = file_path or (asset_dir and os.path.join(asset_dir, self.asset_file_name)) | ||
|
||
if not file_path: | ||
raise ValueError("Either `file_path` or " | ||
"`asset_dir` and `asset_file_name` (class attribute) must be given.") | ||
|
||
self._data = parser_cls.parse_file(file_path) | ||
|
||
def __len__(self): | ||
return len(self._data) | ||
|
||
@abstractmethod | ||
def __iter__(self): | ||
raise NotImplementedError() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
"""Base entry class for mono behavior.""" | ||
from abc import ABC, abstractmethod | ||
from dataclasses import dataclass | ||
from datetime import datetime | ||
from typing import Union, Optional | ||
|
||
__all__ = ("EntryBase",) | ||
|
||
|
||
@dataclass | ||
class EntryBase(ABC): | ||
"""Base class for the entries in the mono behavior assets.""" | ||
|
||
@staticmethod | ||
@abstractmethod | ||
def parse_raw(data: dict[str, Union[str, int, float]]) -> "EntryBase": | ||
"""Parse a raw data entry to be the asset entry class.""" | ||
raise NotImplementedError() | ||
|
||
@staticmethod | ||
def parse_datetime(datetime_str: str) -> Optional[datetime]: | ||
"""Parse ``datetime_str`` to be :class:`datetime` if it's not an empty string.""" | ||
return datetime.strptime(datetime_str, "%Y/%m/%d %H:%M:%S") if datetime_str else None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
"""Base object for the master assets.""" | ||
import json | ||
from abc import ABC | ||
from dataclasses import dataclass | ||
from typing import Type, Optional, Any, Callable, Union | ||
|
||
from .asset import AssetBase | ||
from .entry import EntryBase | ||
from .parser import ParserBase | ||
|
||
__all__ = ("MasterEntryBase", "MasterAssetBase", "MasterParserBase") | ||
|
||
|
||
@dataclass | ||
class MasterEntryBase(EntryBase, ABC): | ||
"""Base class for the entries in the master mono behavior asset.""" | ||
|
||
id: int # pylint: disable=invalid-name | ||
|
||
|
||
class MasterParserBase(ParserBase, ABC): | ||
"""Base parser class for parsing the master asset files.""" | ||
|
||
@staticmethod | ||
def get_entries(file_path: str) -> dict[int, dict]: | ||
"""Get a dict of data entries which value needs to be further parsed.""" | ||
with open(file_path) as f: | ||
data = json.load(f) | ||
|
||
if "dict" not in data: | ||
raise ValueError("Key `dict` not in the data") | ||
data = data["dict"] | ||
|
||
if "entriesValue" not in data: | ||
raise ValueError("Key `dict.entriesValue` not in the data") | ||
if "entriesKey" not in data: | ||
raise ValueError("Key `dict.entriesKey` not in the data") | ||
|
||
entry_keys = filter(lambda key: key != 0, data["entriesKey"]) # Only the entries with key != 0 is valid | ||
entry_values = data["entriesValue"] | ||
|
||
return dict(zip(entry_keys, entry_values)) | ||
|
||
@staticmethod | ||
def parse_file(file_path: str) -> dict[int, Any]: | ||
"""Parse a file as a :class:`dict` which key is the ID of the value.""" | ||
raise NotImplementedError() | ||
|
||
|
||
class MasterAssetBase(AssetBase, ABC): | ||
"""Base class for a master mono behavior asset.""" | ||
|
||
def __init__(self, parser_cls: Type[MasterParserBase], file_path: Optional[str] = None, /, | ||
asset_dir: Optional[str] = None): | ||
super().__init__(parser_cls, file_path, asset_dir=asset_dir) | ||
|
||
def __iter__(self): | ||
return iter(self._data.values()) | ||
|
||
def filter(self, condition: Callable[[MasterEntryBase], bool]) -> list[MasterEntryBase]: | ||
"""Get a list of data which matches the ``condition``.""" | ||
return [data for data in self if condition(data)] | ||
|
||
def get_data_by_id(self, data_id: Union[int, str], default: Optional[MasterEntryBase] = None) \ | ||
-> Optional[MasterEntryBase]: | ||
"""Get a data by its ``data_id``. Returns ``default`` if not found.""" | ||
return self._data.get(data_id, default) |
Oops, something went wrong.