aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--BerryClient/__init__.py1
-rw-r--r--BerryClient/__main__.py13
-rw-r--r--BerryClient/addons/msg.py9
-rw-r--r--BerryClient/addons/reload.py5
-rw-r--r--BerryClient/commands.py50
-rw-r--r--BerryClient/core.py76
-rw-r--r--BerryClient/events.py66
-rw-r--r--BerryClient/logging.py12
-rw-r--r--LICENSE22
-rw-r--r--MANIFEST.in3
-rw-r--r--README.md22
-rw-r--r--requirements.txt2
-rwxr-xr-xsetup.py47
14 files changed, 332 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d1c24fb
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+env
+dist
+__pycache__
+*.egg-info
diff --git a/BerryClient/__init__.py b/BerryClient/__init__.py
new file mode 100644
index 0000000..3aa0d7b
--- /dev/null
+++ b/BerryClient/__init__.py
@@ -0,0 +1 @@
+__version__ = "0.0.0" \ No newline at end of file
diff --git a/BerryClient/__main__.py b/BerryClient/__main__.py
new file mode 100644
index 0000000..05b6ce5
--- /dev/null
+++ b/BerryClient/__main__.py
@@ -0,0 +1,13 @@
+import click
+
+from BerryClient.core import BerryCore
+
+@click.group()
+def main():
+ pass
+
+@main.command()
+def run():
+
+ ins = BerryCore()
+ ins.run()
diff --git a/BerryClient/addons/msg.py b/BerryClient/addons/msg.py
new file mode 100644
index 0000000..61edabd
--- /dev/null
+++ b/BerryClient/addons/msg.py
@@ -0,0 +1,9 @@
+import logging
+
+from BerryClient.commands import command
+
+log = logging.getLogger(__name__)
+
+@command()
+def msg(core, *content):
+ log.info(" ".join(content))
diff --git a/BerryClient/addons/reload.py b/BerryClient/addons/reload.py
new file mode 100644
index 0000000..958bb2b
--- /dev/null
+++ b/BerryClient/addons/reload.py
@@ -0,0 +1,5 @@
+from BerryClient.commands import command
+
+@command(name="reload")
+def _reload(core):
+ core.reload()
diff --git a/BerryClient/commands.py b/BerryClient/commands.py
new file mode 100644
index 0000000..532c0a2
--- /dev/null
+++ b/BerryClient/commands.py
@@ -0,0 +1,50 @@
+import logging
+
+from BerryClient.events import on_chat_post
+
+log = logging.getLogger(__name__)
+
+PREFIX = "#"
+COMMANDS = {}
+
+def command(name=None):
+ def decorator(func):
+ func_name = name or func.__name__
+
+ def wrapper(core, *args):
+ try:
+ retval = func(core, *args)
+ if retval:
+ core.postToChat(f"[{func_name}] {retval}")
+ except Exception as e:
+ log.exception(e)
+
+
+ description = None
+ if func.__doc__:
+ description = func.__doc__.strip().split("\n")[0]
+
+ COMMANDS[func_name] = {
+ "func": wrapper,
+ "description": description
+ }
+
+ return decorator
+
+@on_chat_post()
+def process_post(core, post) -> bool:
+ if not post.message.startswith(PREFIX):
+ return False
+
+ full_command = post.message[len(PREFIX):].split()
+ command = full_command[0]
+ args = full_command[1:]
+
+ try:
+ COMMANDS[command]["func"](core, *args)
+ return True
+ except KeyError:
+ pass
+
+ return False
+
diff --git a/BerryClient/core.py b/BerryClient/core.py
new file mode 100644
index 0000000..5f59e1b
--- /dev/null
+++ b/BerryClient/core.py
@@ -0,0 +1,76 @@
+import sys
+import logging
+from importlib import import_module, reload
+
+from mcpi import minecraft
+from BerryClient.events import process_events
+from BerryClient.logging import MinecraftChatHandler
+
+log = logging.getLogger()
+
+class BerryCore:
+
+ ADDONS = [
+ "BerryClient.addons.msg",
+ "BerryClient.addons.reload"
+ ]
+ ADDON_MODULES = {}
+
+ def __init__(self, address: str = "localhost", port: int = 4711):
+ self.instance = minecraft.Minecraft.create(address, port)
+ self.running = False
+
+ self.__setupLogging()
+ self.__loadAddons()
+
+ def __setupLogging(self):
+ root_logger = logging.getLogger()
+ root_logger.setLevel(logging.DEBUG)
+
+ formatter = logging.Formatter(
+ "[{levelname}][{name}]: {message}", style="{"
+ )
+
+ mc_handler = MinecraftChatHandler(self.instance)
+ mc_handler.setFormatter(formatter)
+ root_logger.addHandler(mc_handler)
+
+ if not sys.stdout.closed:
+ stdout_handler = logging.StreamHandler(sys.stdout)
+ stdout_handler.setFormatter(formatter)
+
+ root_logger.addHandler(stdout_handler)
+
+ def __loadAddons(self):
+ for addon in self.ADDONS:
+ self.ADDON_MODULES[addon] = import_module(addon)
+ log.info(f"Loaded {addon}")
+
+ def __reloadAddons(self):
+ for addon in self.ADDONS:
+ try:
+ self.ADDON_MODULES[addon] = reload(self.ADDON_MODULES[addon])
+ log.info(f"Reloaded {addon}")
+ except KeyError:
+ self.ADDON_MODULES[addon] = import_module(addon)
+ log.info(f"Loaded {addon}")
+
+
+ def __getattr__(self, attr):
+ if self.instance:
+ return getattr(self.instance, attr)
+
+ return AttributeError("No instance running")
+
+ def reload(self):
+ self.__reloadAddons()
+
+ def stop(self):
+ self.running = False
+
+ def run(self):
+ self.running = True
+
+ while self.running:
+ process_events(self)
+
diff --git a/BerryClient/events.py b/BerryClient/events.py
new file mode 100644
index 0000000..c01b6ee
--- /dev/null
+++ b/BerryClient/events.py
@@ -0,0 +1,66 @@
+import logging
+
+from mcpi.connection import RequestError
+from mcpi.event import BlockEvent, ChatEvent
+
+log = logging.getLogger(__name__)
+
+BLOCK_CALLBACKS = []
+def on_block_hit():
+ def decorator(func):
+ def wrapper(core: "BerryCore", event: BlockEvent) -> bool:
+ return func(core, event)
+
+ BLOCK_CALLBACKS.append(wrapper)
+
+ return decorator
+
+CHAT_CALLBACKS = []
+def on_chat_post():
+ def decorator(func):
+ def wrapper(core: "BerryCore", event: ChatEvent) -> bool:
+ return func(core, event)
+
+ CHAT_CALLBACKS.append(wrapper)
+
+ return decorator
+
+PLAYER_MOVEMENT_CALLBACKS = []
+def on_player_movement():
+ def decorator(func):
+ def wrapper(core: "BerryCore", playerId: int, old_pos, new_pos) -> bool:
+ return func(core, playerId, old_pos, new_pos)
+
+ PLAYER_MOVEMENT_CALLBACKS.append(wrapper)
+
+ return decorator
+
+PLAYER_POSITIONS = {}
+def process_events(core: "BerryCore"):
+
+ for hit in core.events.pollBlockHits():
+ for callback in BLOCK_CALLBACKS:
+ if callback(block, hit):
+ break
+
+ for post in core.events.pollChatPosts():
+ for callback in CHAT_CALLBACKS:
+ if callback(core, post):
+ break
+
+ OLD_POSITIONS = PLAYER_POSITIONS.copy()
+ try:
+ playerEntityIds = core.getPlayerEntityIds()
+ except RequestError:
+ playerEntityIds = []
+
+ for playerId in playerEntityIds:
+ PLAYER_POSITIONS[playerId] = core.entity.getPos(playerId)
+
+ if (playerId in OLD_POSITIONS
+ and OLD_POSITIONS[playerId] != PLAYER_POSITIONS[playerId]):
+
+ for callback in PLAYER_MOVEMENT_CALLBACKS:
+ if callback(core, playerId,
+ OLD_POSITIONS[playerId], PLAYER_POSITIONS[playerId]):
+ break
diff --git a/BerryClient/logging.py b/BerryClient/logging.py
new file mode 100644
index 0000000..60aad3d
--- /dev/null
+++ b/BerryClient/logging.py
@@ -0,0 +1,12 @@
+import logging
+
+class MinecraftChatHandler(logging.Handler):
+ def __init__(self, mc, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ self.mc = mc
+
+ def emit(self, record):
+ msg = self.format(record)
+
+ for line in msg.split("\n"):
+ self.mc.postToChat(line) \ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..1b5a336
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) 2022 Jan Drögehoff
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..bb910eb
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,3 @@
+include README.md
+include LICENSE
+include requirements.txt
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..a8c167c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,22 @@
+# unixreg
+
+## why
+While working on porting a python application to Linux I came across many uses of winreg that could not easily be ported over.
+
+Instead of reworking the system I decided to implement a bandaid solution that deals with it transparently.
+
+## how to use
+Update your winreg imports with this
+
+```py
+try:
+ import winreg
+except ImportError:
+ import unixreg as winreg
+```
+
+simply importing unixreg should be enough though, winreg is imported if found
+
+## license
+this project is licensed under the [MIT License](LICENSE)
+feel free to do whatever you want with it
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..b60bc31
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,2 @@
+mcpi
+click
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..3367110
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+import setuptools
+import re
+
+with open('requirements.txt') as f:
+ requirements = f.read().splitlines()
+
+version = None
+with open('BerryClient/__init__.py') as f:
+ version = re.search(r'^__version__\s*=\s*[\'"]([^\'"]*)[\'"]', f.read(), re.MULTILINE).group(1)
+
+if version is None:
+ raise RuntimeError('version is not set')
+
+with open("README.md", "r") as fh:
+ long_description = fh.read()
+
+
+setuptools.setup(
+ name="BerryClient",
+ version=version,
+ author="Jan Drögehoff",
+ author_email="jandroegehoff@gmail.com",
+ long_description=long_description,
+ long_description_content_type="text/markdown",
+ url="https://github.com/Jan200101/BerryClient",
+ packages=["BerryClient"],
+ license="MIT",
+ install_requires=requirements,
+ include_package_data=True,
+ classifiers=[
+ "Development Status :: 3 - Alpha",
+
+ "Programming Language :: Python :: 3",
+
+ "License :: OSI Approved :: MIT License",
+
+ "Operating System :: POSIX",
+ "Operating System :: POSIX :: Linux",
+ ],
+ python_requires=">=3.6",
+ entry_points={
+ 'console_scripts': [
+ 'BerryClient=BerryClient.__main__:main',
+ ],
+ },
+)