aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2024-06-30 08:46:52 +0800
committer简律纯 <i@jyunko.cn>2024-06-30 08:46:52 +0800
commit87f0d8fbc019b65ff942b415b107293a1024fe1d (patch)
tree06c6237d8110658c96109452d2c932fb87fdcbd7
parent23ab264ebe52bd050e02c5c6a009645a252a5ea0 (diff)
downloadHydroRollCore-87f0d8fbc019b65ff942b415b107293a1024fe1d.tar.gz
HydroRollCore-87f0d8fbc019b65ff942b415b107293a1024fe1d.zip
feat(exception): enrich exceptions:: EventException, SkipException, StopException, CoreException, GetEventTimeOut, LoudModuleError
-rw-r--r--examples/COC7/Character.py40
-rw-r--r--examples/COC7/__init__.py79
-rw-r--r--hrc/__init__.py2
-rw-r--r--hrc/dependencies.py118
-rw-r--r--hrc/exceptions.py22
-rw-r--r--hrc/rule/__init__.py16
-rw-r--r--hrc/utils.py8
-rw-r--r--noxfile.py2
8 files changed, 209 insertions, 78 deletions
diff --git a/examples/COC7/Character.py b/examples/COC7/Character.py
index 70b934b..37e2a4e 100644
--- a/examples/COC7/Character.py
+++ b/examples/COC7/Character.py
@@ -10,14 +10,13 @@ from hrc.rule.BaseRule import CharacterCard
@dataclass
class Attributes(CharacterCard.Attribute):
- @property
+
@aliases(["luck", "运气"], ignore_case=True)
def LUK(self) -> Union[str, int, None]: ...
- @property
@aliases(["伤害加值", "DamageBonus"], ignore_case=True)
def DB(self) -> Union[str, int, None]:
- sum = self.STR + self.SIZ
+ sum = self.STR() + self.SIZ()
return (
str(math.ceil((sum - 164) / 80)) + "D6"
if sum > 164
@@ -32,45 +31,38 @@ class Attributes(CharacterCard.Attribute):
else None
)
- @property
@aliases(["年龄", "age"], ignore_case=True)
def AGE(self) -> Union[str, int, None]: ...
- @property
@aliases(["HitPoints", "生命值", "生命"], ignore_case=True)
def HP(self) -> Union[str, int, None]:
return self.MAX_HP
- @property
@aliases(["最大生命值", "HitPointTotal", "总生命值"], ignore_case=True)
def MAX_HP(self) -> Union[str, int, None]:
if hasattr(self, "CON") and hasattr(self, "SIZ"):
- return (self.CON + self.SIZ) // 10
+ return (self.CON() + self.SIZ()) // 10
else:
return None
- @property
@aliases(["理智", "Sanity", "SanityPoint", "理智值", "san值"], ignore_case=True)
def SAN(self) -> Union[str, int, None]:
- return self.POW
+ return self.POW()
- @property
@aliases(["最大理智值", "MaximumSanity"], ignore_case=True)
def MAX_SAN(self) -> Union[str, int, None]:
- return 99 - self.player_card.CM
+ return 99 - self.player_card.CM()
- @property
@aliases(["魔法", "魔法值", "MagicPoints"], ignore_case=True)
def MP(self) -> Union[str, int, None]:
if hasattr(self, "POW"):
- return math.floor(self.POW / 5)
+ return math.floor(self.POW() / 5)
else:
return None
- @property
@aliases(["伤害加值", "DamageBonus"], ignore_case=True)
def DB(self) -> Union[int, str, None]: # noqa: F811
- sum = self.STR + self.SIZ
+ sum = self.STR() + self.SIZ()
return (
str(math.ceil((sum - 164) / 80)) + "D6"
if sum > 164
@@ -85,10 +77,9 @@ class Attributes(CharacterCard.Attribute):
else None
)
- @property
@aliases(["体格", "build"], ignore_case=True)
def BUILD(self) -> Union[str, int, None]:
- sum = self.STR + self.SIZ
+ sum = self.STR() + self.SIZ()
return (
math.ceil((sum - 84) / 80)
if sum > 164
@@ -103,14 +94,13 @@ class Attributes(CharacterCard.Attribute):
else None
)
- @property
@aliases(["移动速度"], ignore_case=True)
def MOV(self) -> Union[str, int, None]:
mov = 8
- siz = self.player_card.SIZ
- str_val = self.player_card.STR
- dex = self.player_card.DEX
- age = self.AGE
+ siz = self.player_card.SIZ()
+ str_val = self.player_card.STR()
+ dex = self.player_card.DEX()
+ age = self.AGE()
if age >= 40:
mov -= math.floor(age / 10 - 3)
@@ -122,24 +112,20 @@ class Attributes(CharacterCard.Attribute):
return mov
- @property
@aliases(["兴趣技能点", "PersonalInterests"], ignore_case=True)
def PI(self) -> Union[str, int, None]:
- return self.player_card.INT * 2
+ return self.player_card.INT() * 2
- @property
@aliases(["闪避", "Dodge"], ignore_case=True)
def DODGE(self) -> Union[str, int, None]:
if hasattr(self.player_card, "DEX"):
return math.floor(self.player_card.DEX / 2)
return None
- @property
@aliases(["锁匠", "开锁", "撬锁", "Locksmith"], ignore_case=True)
def LOCKSMITH(self) -> Union[str, int, None]:
return 1
- @property
@aliases(["动物驯养", "驯兽", "AnimalHandling"], ignore_case=True)
def ANIMAL_HANDLING(self) -> Union[str, int, None]:
return 1
diff --git a/examples/COC7/__init__.py b/examples/COC7/__init__.py
index 01efe57..50db8f4 100644
--- a/examples/COC7/__init__.py
+++ b/examples/COC7/__init__.py
@@ -1,41 +1,52 @@
import math
from hrc import Core, player_card
+from hrc.rule import Rule, BaseRule
+from hrc.dependencies import Depends
+
+from .Character import Attributes
+from .Wiki import Wiki
core = Core()
-@core.event_post_processor_hook
-async def auto_card(_event="T_Event"):
- g = core.session
- pc = player_card
- if g and core.session.gid and g.ac:
- if hasattr(pc.trans, "生命") or hasattr(pc.trans, "理智"):
- core.session.call(
- "set_group_card", pc.gid, f"card#{pc.uid}", await overview_card(pc.char)
- )
-
-
-async def overview_card(pc: player_card):
- max_hp = math.floor((pc.get("CON", 0) + pc.get("SIZ", 0) / 10))
- max_san = math.floor(99 - pc.get("CM", 0))
- mp = pc.get("MP", 0)
- mp_show = (
- " mp" + str(mp) + "/" + str(math.floor(pc.get("POW", 0) / 5))
- if mp and mp != math.floor(pc.get("POW", 0) / 5)
- else ""
- )
- return (
- pc.get("__Name", "")
- + " hp"
- + str(pc.get("HP", max_hp))
- + "/"
- + str(max_hp)
- + " san"
- + str(pc.get("SAN", "?"))
- + "/"
- + str(max_san)
- + mp_show
- + " DEX"
- + str(pc.get("DEX", "?"))
- )
+class COC7(Rule):
+
+ attr: Attributes = Depends() # 必须实现一个继承自 Character.Attribute 的类
+ wiki: Wiki = Depends() # 可选实现一个 Wiki
+
+ @core.event_post_processor_hook
+ async def auto_card(self):
+ if self.session and self.session.gid and self.ac:
+ if hasattr(self.pc.trans, "生命") or hasattr(self.pc.trans, "理智"):
+ self.event.call_back(
+ "set_group_card", self.pc.gid, f"card#{self.pc.uid}", await self.overview_card()
+ )
+
+ async def overview_card(self):
+ max_hp = math.floor((self.pc.get("CON", 0) + self.pc.get("SIZ", 0) / 10))
+ max_san = math.floor(99 - self.pc.get("CM", 0))
+ mp = self.pc.get("MP", 0)
+ mp_show = (
+ " mp" + str(mp) + "/" + str(math.floor(self.pc.get("POW", 0) / 5))
+ if mp and mp != math.floor(self.pc.get("POW", 0) / 5)
+ else ""
+ )
+ return (
+ self.pc.get("__Name", "")
+ + " hp"
+ + str(self.pc.get("HP", max_hp))
+ + "/"
+ + str(max_hp)
+ + " san"
+ + str(self.pc.get("SAN", "?"))
+ + "/"
+ + str(max_san)
+ + mp_show
+ + " DEX"
+ + str(self.pc.get("DEX", "?"))
+ )
+
+
+print(COC7)
+print(COC7.attr) \ No newline at end of file
diff --git a/hrc/__init__.py b/hrc/__init__.py
index ba4efed..29021d3 100644
--- a/hrc/__init__.py
+++ b/hrc/__init__.py
@@ -1,7 +1,7 @@
from .LibCore import * # noqa: F403
from . import rule # noqa: F401
-from . import core # noqa: F401
+from .core import Core # noqa: F401
from . import log # noqa: F401
from . import exceptions # noqa: F401
from . import config # noqa: F401
diff --git a/hrc/dependencies.py b/hrc/dependencies.py
index e69de29..3a662fd 100644
--- a/hrc/dependencies.py
+++ b/hrc/dependencies.py
@@ -0,0 +1,118 @@
+import inspect
+from contextlib import AsyncExitStack, asynccontextmanager, contextmanager
+from typing import (
+ Any,
+ AsyncContextManager,
+ AsyncGenerator,
+ Callable,
+ ContextManager,
+ Dict,
+ Generator,
+ Optional,
+ Type,
+ TypeVar,
+ Union,
+ cast,
+)
+
+from .utils import get_annotations, sync_ctx_manager_wrapper
+
+_T = TypeVar("_T")
+Dependency = Union[
+ # Class
+ Type[Union[_T, AsyncContextManager[_T], ContextManager[_T]]],
+ # GeneratorContextManager
+ Callable[[], AsyncGenerator[_T, None]],
+ Callable[[], Generator[_T, None, None]],
+]
+
+
+__all__ = ["Depends"]
+
+
+class InnerDepends:
+
+ dependency: Optional[Dependency[Any]]
+ use_cache: bool
+
+ def __init__(
+ self, dependency: Optional[Dependency[Any]] = None, *, use_cache: bool = True
+ ) -> None:
+ self.dependency = dependency
+ self.use_cache = use_cache
+
+ def __repr__(self) -> str:
+ attr = getattr(self.dependency, "__name__", type(self.dependency).__name__)
+ cache = "" if self.use_cache else ", use_cache=False"
+ return f"InnerDepends({attr}{cache})"
+
+
+def Depends( # noqa: N802 # pylint: disable=invalid-name
+ dependency: Optional[Dependency[_T]] = None, *, use_cache: bool = True
+) -> _T:
+
+ return InnerDepends(dependency=dependency, use_cache=use_cache) # type: ignore
+
+
+async def solve_dependencies(
+ dependent: Dependency[_T],
+ *,
+ use_cache: bool,
+ stack: AsyncExitStack,
+ dependency_cache: Dict[Dependency[Any], Any],
+) -> _T:
+ if use_cache and dependent in dependency_cache:
+ return dependency_cache[dependent]
+
+ if isinstance(dependent, type):
+ # type of dependent is Type[T]
+ values: Dict[str, Any] = {}
+ ann = get_annotations(dependent)
+ for name, sub_dependent in inspect.getmembers(
+ dependent, lambda x: isinstance(x, InnerDepends)
+ ):
+ assert isinstance(sub_dependent, InnerDepends)
+ if sub_dependent.dependency is None:
+ dependent_ann = ann.get(name, None)
+ if dependent_ann is None:
+ raise TypeError("can not solve dependent")
+ sub_dependent.dependency = dependent_ann
+ values[name] = await solve_dependencies(
+ sub_dependent.dependency,
+ use_cache=sub_dependent.use_cache,
+ stack=stack,
+ dependency_cache=dependency_cache,
+ )
+ depend_obj = cast(
+ Union[_T, AsyncContextManager[_T], ContextManager[_T]],
+ dependent.__new__(dependent), # pyright: ignore[reportGeneralTypeIssues]
+ )
+ for key, value in values.items():
+ setattr(depend_obj, key, value)
+ depend_obj.__init__() # type: ignore[misc] # pylint: disable=unnecessary-dunder-call
+
+ if isinstance(depend_obj, AsyncContextManager):
+ depend = await stack.enter_async_context(
+ depend_obj # pyright: ignore[reportUnknownArgumentType]
+ )
+ elif isinstance(depend_obj, ContextManager):
+ depend = await stack.enter_async_context(
+ sync_ctx_manager_wrapper(
+ depend_obj # pyright: ignore[reportUnknownArgumentType]
+ )
+ )
+ else:
+ depend = depend_obj
+ elif inspect.isasyncgenfunction(dependent):
+ # type of dependent is Callable[[], AsyncGenerator[T, None]]
+ cm = asynccontextmanager(dependent)()
+ depend = cast(_T, await stack.enter_async_context(cm))
+ elif inspect.isgeneratorfunction(dependent):
+ # type of dependent is Callable[[], Generator[T, None, None]]
+ cm = sync_ctx_manager_wrapper(contextmanager(dependent)())
+ depend = cast(_T, await stack.enter_async_context(cm))
+ else:
+ raise TypeError("dependent is not a class or generator function")
+
+ dependency_cache[dependent] = depend
+ return depend \ No newline at end of file
diff --git a/hrc/exceptions.py b/hrc/exceptions.py
index e69de29..c71118f 100644
--- a/hrc/exceptions.py
+++ b/hrc/exceptions.py
@@ -0,0 +1,22 @@
+class EventException(BaseException):
+ ...
+
+
+class SkipException(EventException):
+ ...
+
+
+class StopException(EventException):
+ ...
+
+
+class CoreException(Exception):
+ ... # noqa: N818
+
+
+class GetEventTimeout(CoreException):
+ ...
+
+
+class LoadModuleError(CoreException):
+ ...
diff --git a/hrc/rule/__init__.py b/hrc/rule/__init__.py
index a41c81d..bbd2cfe 100644
--- a/hrc/rule/__init__.py
+++ b/hrc/rule/__init__.py
@@ -155,11 +155,11 @@ class Rule(ABC, Generic[EventT, StateT, ConfigT]):
"""
raise NotImplementedError
-
-def aliases(names, ignore_case=False):
- def decorator(func):
- func._aliases = names
- func._ignore_case = ignore_case
- return func
-
- return decorator
+ @staticmethod
+ def aliases(names, ignore_case=False):
+ def decorator(func):
+ func._aliases = names
+ func._ignore_case = ignore_case
+ return func
+
+ return decorator
diff --git a/hrc/utils.py b/hrc/utils.py
index 480b105..e85cea4 100644
--- a/hrc/utils.py
+++ b/hrc/utils.py
@@ -82,14 +82,6 @@ class ModulePathFinder(MetaPathFinder):
def is_config_class(config_class: Any) -> TypeGuard[Type[ConfigModel]]:
- """Determine whether an object is a configuration class.
-
- Args:
- config_class: The object to be judged.
-
- Returns:
- Returns whether it is a configuration class.
- """
return (
inspect.isclass(config_class)
and issubclass(config_class, ConfigModel)
diff --git a/noxfile.py b/noxfile.py
index d64f210..a574670 100644
--- a/noxfile.py
+++ b/noxfile.py
@@ -15,3 +15,5 @@ def bench(session: nox.Session):
session.env["MATURIN_PEP517_ARGS"] = "--profile=dev"
session.install(".[dev]")
session.run("pytest", "--benchmark-enable")
+
+