add some
This commit is contained in:
parent
b8fe1e237e
commit
42c9da2d25
@ -11,8 +11,8 @@ github: @shenjackyuanjie
|
||||
gitee: @shenjackyuanjie
|
||||
"""
|
||||
|
||||
version = '0.6.2'
|
||||
__version__ = version
|
||||
game_version = '0.6.2'
|
||||
__version__ = game_version
|
||||
|
||||
|
||||
playing = False
|
||||
|
@ -3,6 +3,7 @@
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
# 本文件以 GNU Lesser General Public License v3.0(GNU LGPL v3) 开源协议进行授权 (谢谢狐狸写出这么好的MCDR)
|
||||
|
||||
import functools
|
||||
import inspect
|
||||
|
179
Difficult_Rocket/api/serializer.py
Normal file
179
Difficult_Rocket/api/serializer.py
Normal file
@ -0,0 +1,179 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
# 本文件以 GNU Lesser General Public License v3.0(GNU LGPL v3) 开源协议进行授权 (谢谢狐狸写出这么好的MCDR)
|
||||
# 顺便说一句,我把所有的tab都改成了空格,因为我觉得空格比tab更好看(草,后半句是github copilot自动填充的)
|
||||
|
||||
import copy
|
||||
from abc import ABC
|
||||
from enum import EnumMeta
|
||||
from threading import Lock
|
||||
from typing import Union, TypeVar, List, Dict, Type, get_type_hints, Any
|
||||
|
||||
"""
|
||||
This part of code come from MCDReforged(https://github.com/Fallen-Breath/MCDReforged)
|
||||
Very thanks to Fallen_Breath and other coder who helped MCDR worked better
|
||||
GNU Lesser General Public License v3.0(GNU LGPL v3)
|
||||
(have some changes)
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'serialize',
|
||||
'deserialize',
|
||||
'Serializable'
|
||||
]
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
def _get_type_hints(cls: Type):
|
||||
try:
|
||||
return get_type_hints(cls)
|
||||
except:
|
||||
return get_type_hints(cls, globalns={})
|
||||
|
||||
|
||||
def _get_origin(cls: Type):
|
||||
return getattr(cls, '__origin__', None)
|
||||
|
||||
|
||||
def _get_args(cls: Type) -> tuple:
|
||||
return getattr(cls, '__args__', ())
|
||||
|
||||
|
||||
def serialize(obj) -> Union[None, int, float, str, list, dict]:
|
||||
if type(obj) in (type(None), int, float, str, bool):
|
||||
return obj
|
||||
elif isinstance(obj, list) or isinstance(obj, tuple):
|
||||
return list(map(serialize, obj))
|
||||
elif isinstance(obj, dict):
|
||||
return dict(map(lambda t: (t[0], serialize(t[1])), obj.items()))
|
||||
elif isinstance(obj.__class__, EnumMeta):
|
||||
return obj.name
|
||||
try:
|
||||
attr_dict = vars(obj).copy()
|
||||
# don't serialize protected fields
|
||||
for attr_name in list(attr_dict.keys()):
|
||||
if attr_name.startswith('_'):
|
||||
attr_dict.pop(attr_name)
|
||||
except:
|
||||
raise TypeError('Unsupported input type {}'.format(type(obj))) from None
|
||||
else:
|
||||
return serialize(attr_dict)
|
||||
|
||||
|
||||
_BASIC_CLASSES = (type(None), bool, int, float, str, list, dict)
|
||||
|
||||
|
||||
def deserialize(data, cls: Type[T], *, error_at_missing=False, error_at_redundancy=False) -> T:
|
||||
# in case None instead of NoneType is passed
|
||||
if cls is None:
|
||||
cls = type(None)
|
||||
# if its type is Any, then simply return the data
|
||||
if cls is Any:
|
||||
return data
|
||||
# Union
|
||||
# Unpack Union first since the target class is not confirmed yet
|
||||
elif _get_origin(cls) == Union:
|
||||
for possible_cls in _get_args(cls):
|
||||
try:
|
||||
return deserialize(data, possible_cls, error_at_missing=error_at_missing, error_at_redundancy=error_at_redundancy)
|
||||
except (TypeError, ValueError):
|
||||
pass
|
||||
raise TypeError('Data in type {} cannot match any candidate of target class {}'.format(type(data), cls))
|
||||
# Element (None, int, float, str, list, dict)
|
||||
# For list and dict, since it doesn't have any type hint, we choose to simply return the data
|
||||
elif cls in _BASIC_CLASSES and type(data) is cls:
|
||||
return data
|
||||
# float thing
|
||||
elif cls is float and isinstance(data, int):
|
||||
return float(data)
|
||||
# List
|
||||
elif _get_origin(cls) == List[int].__origin__ and isinstance(data, list):
|
||||
element_type = _get_args(cls)[0]
|
||||
return list(map(lambda e: deserialize(e, element_type, error_at_missing=error_at_missing, error_at_redundancy=error_at_redundancy), data))
|
||||
# Dict
|
||||
elif _get_origin(cls) == Dict[int, int].__origin__ and isinstance(data, dict):
|
||||
key_type = _get_args(cls)[0]
|
||||
val_type = _get_args(cls)[1]
|
||||
instance = {}
|
||||
for key, value in data.items():
|
||||
deserialized_key = deserialize(key, key_type, error_at_missing=error_at_missing, error_at_redundancy=error_at_redundancy)
|
||||
deserialized_value = deserialize(value, val_type, error_at_missing=error_at_missing, error_at_redundancy=error_at_redundancy)
|
||||
instance[deserialized_key] = deserialized_value
|
||||
return instance
|
||||
# Enum
|
||||
elif isinstance(cls, EnumMeta) and isinstance(data, str):
|
||||
return cls[data]
|
||||
# Object
|
||||
elif cls not in _BASIC_CLASSES and isinstance(cls, type) and isinstance(data, dict):
|
||||
try:
|
||||
result = cls()
|
||||
except:
|
||||
raise TypeError('Failed to construct instance of class {}'.format(type(cls)))
|
||||
input_key_set = set(data.keys())
|
||||
for attr_name, attr_type in _get_type_hints(cls).items():
|
||||
if not attr_name.startswith('_'):
|
||||
if attr_name in data:
|
||||
result.__setattr__(attr_name, deserialize(data[attr_name], attr_type, error_at_missing=error_at_missing,
|
||||
error_at_redundancy=error_at_redundancy))
|
||||
input_key_set.remove(attr_name)
|
||||
elif error_at_missing:
|
||||
raise ValueError('Missing attribute {} for class {} in input object {}'.format(attr_name, cls, data))
|
||||
elif hasattr(cls, attr_name):
|
||||
result.__setattr__(attr_name, copy.copy(getattr(cls, attr_name)))
|
||||
if error_at_redundancy and len(input_key_set) > 0:
|
||||
raise ValueError('Redundancy attributes {} for class {} in input object {}'.format(input_key_set, cls, data))
|
||||
if isinstance(result, Serializable):
|
||||
result.on_deserialization()
|
||||
return result
|
||||
else:
|
||||
raise TypeError('Unsupported input type: expected class {} but found data with class {}'.format(cls, type(data)))
|
||||
|
||||
|
||||
class Serializable(ABC):
|
||||
__annotations_cache: dict = None
|
||||
__annotations_lock = Lock()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
for key in kwargs.keys():
|
||||
if key not in self.get_annotations_fields():
|
||||
raise KeyError('Unknown key received in __init__ of class {}: {}'.format(self.__class__, key))
|
||||
vars(self).update(kwargs)
|
||||
|
||||
@classmethod
|
||||
def __get_annotation_dict(cls) -> dict:
|
||||
public_fields = {}
|
||||
for attr_name, attr_type in _get_type_hints(cls).items():
|
||||
if not attr_name.startswith('_'):
|
||||
public_fields[attr_name] = attr_type
|
||||
return public_fields
|
||||
|
||||
@classmethod
|
||||
def get_annotations_fields(cls) -> Dict[str, Type]:
|
||||
with cls.__annotations_lock:
|
||||
if cls.__annotations_cache is None:
|
||||
cls.__annotations_cache = cls.__get_annotation_dict()
|
||||
return cls.__annotations_cache
|
||||
|
||||
def serialize(self) -> dict:
|
||||
return serialize(self)
|
||||
|
||||
@classmethod
|
||||
def deserialize(cls, data: dict, **kwargs):
|
||||
return deserialize(data, cls, **kwargs)
|
||||
|
||||
def update_from(self, data: dict):
|
||||
vars(self).update(vars(self.deserialize(data)))
|
||||
|
||||
@classmethod
|
||||
def get_default(cls):
|
||||
return cls.deserialize({})
|
||||
|
||||
def on_deserialization(self):
|
||||
"""
|
||||
Invoked after being deserialized
|
||||
"""
|
||||
pass
|
@ -11,14 +11,14 @@ github: @shenjackyuanjie
|
||||
gitee: @shenjackyuanjie
|
||||
"""
|
||||
|
||||
from Difficult_Rocket import version
|
||||
from Difficult_Rocket import game_version
|
||||
from Difficult_Rocket.command import line
|
||||
|
||||
|
||||
|
||||
command_tree = {
|
||||
'name': 'DR-root',
|
||||
'version': version,
|
||||
'version': game_version,
|
||||
'information': 'DR这一部分的代码还TM是复制我之前写的屑Census',
|
||||
'commands': {
|
||||
'info': '啊啊啊啊',
|
||||
|
60
Difficult_Rocket/mods/__init__.py
Normal file
60
Difficult_Rocket/mods/__init__.py
Normal file
@ -0,0 +1,60 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
"""
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
github: @shenjackyuanjie
|
||||
gitee: @shenjackyuanjie
|
||||
"""
|
||||
|
||||
from typing import Tuple
|
||||
|
||||
from Difficult_Rocket import game_version
|
||||
from Difficult_Rocket.api.serializer import Serializable
|
||||
|
||||
"""
|
||||
mod系统参数
|
||||
"""
|
||||
MOD_loader_version = "0.0.1" # mod系统版本 版本号遵守semver2.0.0
|
||||
|
||||
|
||||
"""
|
||||
加载mod时会更改的参数
|
||||
这里的只是范例,实际加载时会根据mod配置修改
|
||||
"""
|
||||
|
||||
|
||||
class MODInfo(Serializable):
|
||||
"""
|
||||
加载mod时候的参数
|
||||
"""
|
||||
"""基本信息"""
|
||||
name: str # mod名称
|
||||
version: str # mod版本
|
||||
dependencies: list = [] # mod依赖
|
||||
|
||||
"""作者、描述"""
|
||||
writer: str # 作者
|
||||
description: str = "" # 描述
|
||||
|
||||
"""版本兼容信息"""
|
||||
write_version: str # mod编写版本
|
||||
compatible_version: Tuple[str, str] = (game_version, game_version) # mod兼容版本
|
||||
# 第一个是最低兼容版本,第二个是最高兼容版本
|
||||
# 例如: ("1.0.0", "1.1.0")
|
||||
|
||||
|
||||
MOD_info = MODInfo(
|
||||
name="Difficult_Rocket",
|
||||
version="0.0.1",
|
||||
writer="shenjackyuanjie"
|
||||
)
|
||||
|
||||
"""
|
||||
一些重置用函数
|
||||
"""
|
||||
|
34
Difficult_Rocket/mods/client.py
Normal file
34
Difficult_Rocket/mods/client.py
Normal file
@ -0,0 +1,34 @@
|
||||
# -------------------------------
|
||||
# Difficult Rocket
|
||||
# Copyright © 2021-2022 by shenjackyuanjie
|
||||
# All rights reserved
|
||||
# -------------------------------
|
||||
|
||||
"""
|
||||
writen by shenjackyuanjie
|
||||
mail: 3695888@qq.com
|
||||
github: @shenjackyuanjie
|
||||
gitee: @shenjackyuanjie
|
||||
"""
|
||||
|
||||
"""
|
||||
这里是所有客户端 mod 加载器的装饰器实现
|
||||
可以实现类似
|
||||
|
||||
from Difficult_Rocket.mods.client import KeyBinding
|
||||
|
||||
|
||||
@KeyBinding()
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def KeyBinding(func):
|
||||
"""
|
||||
客户端键盘事件传递装饰器
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
func(*args, **kwargs)
|
||||
|
||||
return wrapper
|
4
docs/howto/client.md
Normal file
4
docs/howto/client.md
Normal file
@ -0,0 +1,4 @@
|
||||
# 设计文档
|
||||
|
||||
20220208
|
||||
|
@ -389,10 +389,10 @@ class VertexList:
|
||||
"""dynamic access to vertex attributes, for backwards compatibility.
|
||||
"""
|
||||
domain = self.domain
|
||||
if self._cache_versions.get(name, None) != domain.version:
|
||||
if self._cache_versions.get(name, None) != domain.game_version:
|
||||
attribute = domain.attribute_names[name]
|
||||
self._caches[name] = attribute.get_region(attribute.buffer, self.start, self.count)
|
||||
self._cache_versions[name] = domain.version
|
||||
self._cache_versions[name] = domain.game_version
|
||||
|
||||
region = self._caches[name]
|
||||
region.invalidate()
|
||||
@ -638,10 +638,10 @@ class IndexedVertexList(VertexList):
|
||||
@property
|
||||
def indices(self):
|
||||
"""Array of index data."""
|
||||
if self._indices_cache_version != self.domain.version:
|
||||
if self._indices_cache_version != self.domain.game_version:
|
||||
domain = self.domain
|
||||
self._indices_cache = domain.get_index_region(self.index_start, self.index_count)
|
||||
self._indices_cache_version = domain.version
|
||||
self._indices_cache_version = domain.game_version
|
||||
|
||||
region = self._indices_cache
|
||||
region.invalidate()
|
||||
|
Loading…
Reference in New Issue
Block a user