diff options
| author | 2024-06-30 08:46:52 +0800 | |
|---|---|---|
| committer | 2024-06-30 08:46:52 +0800 | |
| commit | 87f0d8fbc019b65ff942b415b107293a1024fe1d (patch) | |
| tree | 06c6237d8110658c96109452d2c932fb87fdcbd7 | |
| parent | 23ab264ebe52bd050e02c5c6a009645a252a5ea0 (diff) | |
| download | HydroRollCore-87f0d8fbc019b65ff942b415b107293a1024fe1d.tar.gz HydroRollCore-87f0d8fbc019b65ff942b415b107293a1024fe1d.zip | |
feat(exception): enrich exceptions:: EventException, SkipException, StopException, CoreException, GetEventTimeOut, LoudModuleError
| -rw-r--r-- | examples/COC7/Character.py | 40 | ||||
| -rw-r--r-- | examples/COC7/__init__.py | 79 | ||||
| -rw-r--r-- | hrc/__init__.py | 2 | ||||
| -rw-r--r-- | hrc/dependencies.py | 118 | ||||
| -rw-r--r-- | hrc/exceptions.py | 22 | ||||
| -rw-r--r-- | hrc/rule/__init__.py | 16 | ||||
| -rw-r--r-- | hrc/utils.py | 8 | ||||
| -rw-r--r-- | noxfile.py | 2 |
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) @@ -15,3 +15,5 @@ def bench(session: nox.Session): session.env["MATURIN_PEP517_ARGS"] = "--profile=dev" session.install(".[dev]") session.run("pytest", "--benchmark-enable") + + |
