diff options
| author | 2023-12-15 09:11:47 +0800 | |
|---|---|---|
| committer | 2023-12-15 09:11:47 +0800 | |
| commit | be8de118db913711eb72ae5187d26e54a0055727 (patch) | |
| tree | 96cd6c012dafa3f4015e54edef90df5eaaab0ddb /src/infini | |
| parent | 9b2d27ba1d91a0d5531bc9c0d52c3887a2dfb2aa (diff) | |
| download | infini-be8de118db913711eb72ae5187d26e54a0055727.tar.gz infini-be8de118db913711eb72ae5187d26e54a0055727.zip | |
refactor(docs): optmst `docs` dir & `deps`
Diffstat (limited to 'src/infini')
| -rw-r--r-- | src/infini/__init__.py | 6 | ||||
| -rw-r--r-- | src/infini/cli.py | 45 | ||||
| -rw-r--r-- | src/infini/consts/__init__.py | 0 | ||||
| -rw-r--r-- | src/infini/consts/templates.py | 69 | ||||
| -rw-r--r-- | src/infini/event.py | 43 | ||||
| -rw-r--r-- | src/infini/exceptions.py | 6 | ||||
| -rw-r--r-- | src/infini/logging.py | 40 | ||||
| -rw-r--r-- | src/infini/manager.py | 18 | ||||
| -rw-r--r-- | src/infini/rule.py | 75 | ||||
| -rw-r--r-- | src/infini/settings.py | 1 | ||||
| -rw-r--r-- | src/infini/typing.py | 41 |
11 files changed, 344 insertions, 0 deletions
diff --git a/src/infini/__init__.py b/src/infini/__init__.py new file mode 100644 index 00000000..9c88b4f9 --- /dev/null +++ b/src/infini/__init__.py @@ -0,0 +1,6 @@ +from infini.cli import Cli +from infini.rule import Rule, Result, Dice +from infini.typing import Config as ConfigTyping +from infini.event import Event + +__all__ = ["Rule", "Cli", "Result", "Dice", "Event", "ConfigTyping"] diff --git a/src/infini/cli.py b/src/infini/cli.py new file mode 100644 index 00000000..e372b4b4 --- /dev/null +++ b/src/infini/cli.py @@ -0,0 +1,45 @@ +from pathlib import Path +from .consts import templates +from .logging import logger + +import argparse +import os +import sys +import importlib + + +class Cli: + def parse_args(self, argv: list[str] | None = None): + parser = argparse.ArgumentParser(description="HydroRoll 命令行工具") + + parser.add_argument("--new", action="store_true", help="创建一个 HydroRoll 规则包模板") + parser.add_argument("--run", action="store_true", help="运行 HydroRoll 规则包") + parser.add_argument("--gui", action="store_true", help="显示弹窗") + parser.add_argument("--path", help="指定路径") + + args = parser.parse_args(argv if argv else sys.argv[1:]) + + if args.gui: + logger.critical("选项[--gui]尚未被支持!") + sys.exit(1) + + path = Path(args.path).resolve() if args.path else Path(os.getcwd()).resolve() + if args.new and args.run: + logger.error("无法确定的指令要求: 你同时指定了new与run指令。") + sys.exit(1) + + if args.new: + if path.exists(): + logger.error("指定的文件夹已经存在!") + sys.exit(1) + + path.mkdir(parents=True, exist_ok=True) + (path / "rule.py").write_text(templates.RULE, encoding="utf-8") + (path / "event.py").write_text(templates.EVENT, encoding="utf-8") + (path / "dice.py").write_text(templates.DICE, encoding="utf-8") + + logger.success("HydroRoll 规则包模板已创建!") + + if args.run: + sys.path.append(str(path)) + importlib.import_module("event") diff --git a/src/infini/consts/__init__.py b/src/infini/consts/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/src/infini/consts/__init__.py diff --git a/src/infini/consts/templates.py b/src/infini/consts/templates.py new file mode 100644 index 00000000..e2edc2d6 --- /dev/null +++ b/src/infini/consts/templates.py @@ -0,0 +1,69 @@ +RULE = """from infini import Rule, Result, Dice + + +class MyRule(Rule): + \"\"\"自设规则包\"\"\" + + name = "MyRule" + priority: int = 0 + + def __init__(self) -> None: + \"\"\"初始化你的规则包\"\"\" + + def check(self, dice: Dice) -> Result: + \"\"\"声明规则包检定方式\"\"\" + return Result("myevent.event1", True) +""" + +EVENT = """from infini import Event + +__events__ = ["MyEvent"] + + +class MyEvent(Event): + name = "event1" + output = "检定成功!" +""" + +DICE = """from infini import Dice + +import random +import re + + +class BaseDice(Dice): + \"\"\"多面骰\"\"\" + + def __init__(self, roll_string: str = "") -> None: + self.roll_string = roll_string + self.parse() + + def parse(self) -> "Dice": + self.dices = [] + split = re.split(r"[dD]", self.roll_string) + + if split[0]: + self.a = int(split[0]) + else: + self.a = 1 + + if split[1]: + self.b = int(split[1]) + else: + self.b = 100 + + self.db = f"{self.a}D{self.b}" + self.dices += [f"D{self.b}"] * self.a + return self + + def roll(self) -> int: + self.results = [] + + for _ in range(self.a): + result = random.randint(1, self.b) + + self.results.append(result) + + self.outcome = sum(self.results) + return self.outcome +""" diff --git a/src/infini/event.py b/src/infini/event.py new file mode 100644 index 00000000..9ce34bd9 --- /dev/null +++ b/src/infini/event.py @@ -0,0 +1,43 @@ +from .typing import Dict +from .logging import logger + +import re + +__all__ = ["Event", "events"] + + +class Events: + """事件集合""" + + _events: Dict[str, str] = {} + + def regist(self, name: str, output: str) -> None: + self._events[name.lower()] = output + + def process(self, name: str, **kwargs) -> str: + if string := self._events.get(name.lower()): + return self._format(string, **kwargs) + logger.warning(f"事件[{name.lower()}]不存在,将返回空字符串!") + return "" + + def _format(self, string: str, **kwargs): + pattern = r"{(.*?)}" + values = re.findall(pattern, string) + for value in values: + kwarg = kwargs.get(value) + value = kwarg if kwarg else "" + string = re.sub(pattern, value, string) + return string + + +class Event: + """事件基类""" + + name: str + output: str + + def __init_subclass__(cls) -> None: + events.regist(cls.name, cls.output) + + +events = Events() diff --git a/src/infini/exceptions.py b/src/infini/exceptions.py new file mode 100644 index 00000000..62c88fa1 --- /dev/null +++ b/src/infini/exceptions.py @@ -0,0 +1,6 @@ +class HydroError(Exception): + """HydroRoll 异常基类""" + + +class RuleLoadError(HydroError): + """规则导入错误""" diff --git a/src/infini/logging.py b/src/infini/logging.py new file mode 100644 index 00000000..a1458ef4 --- /dev/null +++ b/src/infini/logging.py @@ -0,0 +1,40 @@ +"""infini 日志。 + +infini 使用 [loguru](https://github.com/Delgan/loguru) 来记录日志信息。 +自定义 logger 请参考 [loguru](https://github.com/Delgan/loguru) 文档。 +""" +from datetime import datetime +from multilogging import multilogger +from pathlib import Path +from .settings import DEBUG + + +__all__ = ["logger", "error_or_exception"] + +logger = multilogger( + name="HydroRoll", payload="Core", level="DEBUG" if DEBUG else "INFO" +) +current_path = Path(__file__).resolve().parent +LOG_PATH = current_path / "logs" +if not LOG_PATH.exists(): + LOG_PATH.mkdir(parents=True, exist_ok=True) +logger.add( + sink=LOG_PATH / (datetime.now().strftime("%Y-%m-%d") + ".log"), + level="INFO", + rotation="10 MB", +) # 每个日志文件最大为 10MB + + +def error_or_exception(message: str, exception: Exception, verbose: bool = True): + # 弃用的方法 + # logger.remove() + # logger.add( + # sys.stderr, + # format="<magenta>{time:YYYY-MM-DD HH:mm:ss.SSS}</magenta> <level>[{level}]</level> > <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>", + # ) + + if verbose: + logger.exception(exception) + logger.critical(message) + else: + logger.critical(f"{message} {exception!r}") diff --git a/src/infini/manager.py b/src/infini/manager.py new file mode 100644 index 00000000..42e79563 --- /dev/null +++ b/src/infini/manager.py @@ -0,0 +1,18 @@ +from .event import Events, events +from .logging import logger +from .typing import Dict + + +class Manager: + """事件处理单元""" + + events: Events + + def __init__(self, _events: Events = None) -> None: + self.events = _events if _events else events + + def roll(self): + ... + + +manager = Manager() diff --git a/src/infini/rule.py b/src/infini/rule.py new file mode 100644 index 00000000..a1f04151 --- /dev/null +++ b/src/infini/rule.py @@ -0,0 +1,75 @@ +from abc import ABCMeta, abstractmethod +from enum import Enum +from .exceptions import HydroError +from .typing import Dict + +__all__ = ["RuleLoadType", "Result", "Dice", "Rule"] + + +class RuleLoadType(Enum): + """The Type Of Rules To Be Loaded""" + + DIR = "dir" + NAME = "name" + FILE = "file" + CLASS = "class" + + +class Result(metaclass=ABCMeta): + """规则检定结果基类""" + + event: str + status: bool + exception: HydroError | None = None + + def __init__(self, event: str, status: bool, exception: HydroError | None) -> None: + self.event = event + self.status = status + self.exception = exception + + def ok(self): + """规则执行期间是否产生异常""" + return isinstance(self.exception, HydroError) + + +class Dice(metaclass=ABCMeta): + """掷骰基类""" + + roll_string: str + db: str + outcome: int + + def __repr__(self) -> str: + return f'<HydroDice "{self.db.upper()}">' + + def __str__(self) -> str: + return self.db.upper() + + def __int__(self) -> int: + return self.outcome + + @abstractmethod + def parse(self) -> "Dice": + """解析传入的掷骰字符串`roll_string`,返回一个`Dice`对象""" + raise NotImplementedError + + @abstractmethod + def roll(self) -> int: + """掷骰方法,返回掷骰结果""" + raise NotImplementedError + + +class Rule(metaclass=ABCMeta): + """规则基类""" + + name: str + dices: Dict[str, str] = {} + priority: int = 0 + + @abstractmethod + def __init__(self) -> None: + raise NotImplementedError + + @abstractmethod + def check(self, dice: Dice) -> Result: + raise NotImplementedError diff --git a/src/infini/settings.py b/src/infini/settings.py new file mode 100644 index 00000000..51c64dd2 --- /dev/null +++ b/src/infini/settings.py @@ -0,0 +1 @@ +DEBUG = True diff --git a/src/infini/typing.py b/src/infini/typing.py new file mode 100644 index 00000000..333a763b --- /dev/null +++ b/src/infini/typing.py @@ -0,0 +1,41 @@ +from pydantic import BaseModel +from typing import ( + Dict as Dict, + TYPE_CHECKING as TYPE_CHECKING, + TypeVar as TypeVar, + Callable as Callable, + NoReturn as NoReturn, + Awaitable as Awaitable, +) + + +class Config(BaseModel): + rule_dir: list = [] + rules: list = [] + + +class DiceConfig(BaseModel): + sides: int + counts: int + init_dice_pool: int + + +class PlayerCard(BaseModel): + name: str + traits: list + + +class Bonus(BaseModel): + level: int + cost: int + + +class WikiPage(BaseModel): + title: str + content: str + tags: list = [] + + +class WikiModel: + class Setting(BaseModel): + desc: str |
