brought features out of aiocraft, added game managers

This commit is contained in:
əlemi 2022-03-08 01:38:14 +01:00
parent b41f2f6074
commit 88bfadd8cd
No known key found for this signature in database
GPG key ID: BBCBFE5D7244634E
7 changed files with 77 additions and 50 deletions

View file

@ -1,3 +1,4 @@
from .chat import ChatEvent from .chat import ChatEvent
from .join_game import JoinGameEvent from .join_game import JoinGameEvent
from .death import DeathEvent from .death import DeathEvent
from .system import ConnectedEvent, DisconnectedEvent

View file

@ -1,25 +1,19 @@
from typing import Union from typing import Union
from aiocraft.client import MinecraftClient
from aiocraft.mc.proto.play.clientbound import PacketChat as PacketChatMessage from aiocraft.mc.proto.play.clientbound import PacketChat as PacketChatMessage
from aiocraft.mc.proto.play.serverbound import PacketChat from aiocraft.mc.proto.play.serverbound import PacketChat
from ..events.chat import ChatEvent, MessageType from ..events.chat import ChatEvent, MessageType
from ..scaffold import Scaffold
class GameChat(MinecraftClient): class GameChat(Scaffold):
def on_chat(self, msg_type:Union[str, MessageType] = None): def __init__(self, *args, **kwargs):
if isinstance(msg_type, str): super().__init__(*args, **kwargs)
msg_type = MessageType(msg_type)
def wrapper(fun):
async def process_chat_packet(packet:PacketChatMessage):
msg = ChatEvent(packet.message)
if not msg_type or msg.type == msg_type:
return await fun(msg)
self.register(PacketChatMessage, process_chat_packet)
return fun
return wrapper
@self.on_packet(PacketChatMessage)
async def chat_event_callback(packet:PacketChatMessage):
self.run_callbacks(ChatEvent, ChatEvent(packet.message))
async def chat(self, message:str, whisper:str=None, wait:bool=False): async def chat(self, message:str, whisper:str=None, wait:bool=False):
if whisper: if whisper:
@ -32,5 +26,3 @@ class GameChat(MinecraftClient):
wait=wait wait=wait
) )
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

View file

@ -1,11 +1,12 @@
from typing import List from typing import List
from aiocraft.client import MinecraftClient
from aiocraft.mc.definitions import Item from aiocraft.mc.definitions import Item
from aiocraft.mc.proto.play.clientbound import PacketSetSlot, PacketHeldItemSlot as PacketHeldItemChange from aiocraft.mc.proto.play.clientbound import PacketSetSlot, PacketHeldItemSlot as PacketHeldItemChange
from aiocraft.mc.proto.play.serverbound import PacketHeldItemSlot from aiocraft.mc.proto.play.serverbound import PacketHeldItemSlot
class GameInventory(MinecraftClient): from ..scaffold import Scaffold
class GameInventory(Scaffold):
slot : int slot : int
inventory : List[Item] inventory : List[Item]
# TODO inventory # TODO inventory

View file

@ -2,13 +2,14 @@ import asyncio
import datetime import datetime
import functools import functools
from aiocraft.client import MinecraftClient #from aiocraft.client import MinecraftClient
from aiocraft.mc.definitions import Gamemode, Dimension, Difficulty from aiocraft.mc.definitions import Gamemode, Dimension, Difficulty
from aiocraft.mc.proto import PacketRespawn, PacketLogin, PacketUpdateHealth, PacketExperience, PacketSettings, PacketClientCommand from aiocraft.mc.proto import PacketRespawn, PacketLogin, PacketUpdateHealth, PacketExperience, PacketSettings, PacketClientCommand
from ..events import JoinGameEvent, DeathEvent from ..events import JoinGameEvent, DeathEvent, ConnectedEvent, DisconnectedEvent
from ..scaffold import Scaffold
class GameState(MinecraftClient): class GameState(Scaffold):
hp : float hp : float
food : float food : float
xp : float xp : float
@ -26,24 +27,6 @@ class GameState(MinecraftClient):
difficulty : Difficulty difficulty : Difficulty
join_time : datetime.datetime join_time : datetime.datetime
def on_death(self):
def decorator(fun):
@functools.wraps(fun)
async def wrapper():
event = DeathEvent()
return await fun(event)
return self.register(DeathEvent.SENTINEL, wrapper)
return decorator
def on_joined_world(self):
def decorator(fun):
@functools.wraps(fun)
async def wrapper():
event = JoinGameEvent()
return await fun(event)
return self.register(JoinGameEvent.SENTINEL, wrapper)
return decorator
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@ -58,8 +41,8 @@ class GameState(MinecraftClient):
self.xp = 0.0 self.xp = 0.0
self.lvl = 0 self.lvl = 0
@self.on_disconnected() @self.on(DisconnectedEvent)
async def disconnected_cb(): async def disconnected_cb(_):
self.in_game = False self.in_game = False
@self.on_packet(PacketRespawn) @self.on_packet(PacketRespawn)

View file

@ -3,11 +3,13 @@ import datetime
from typing import Dict, List from typing import Dict, List
from aiocraft.client import MinecraftClient
from aiocraft.mc.definitions import Item from aiocraft.mc.definitions import Item
from aiocraft.mc.proto import PacketPlayerInfo from aiocraft.mc.proto import PacketPlayerInfo
class GameTablist(MinecraftClient): from ..scaffold import Scaffold
from ..events import ConnectedEvent
class GameTablist(Scaffold):
tablist : Dict[uuid.UUID, dict] tablist : Dict[uuid.UUID, dict]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -15,8 +17,8 @@ class GameTablist(MinecraftClient):
self.tablist = {} self.tablist = {}
@self.on_connected() @self.on(ConnectedEvent)
async def connected_cb(): async def connected_cb(_):
self.tablist.clear() self.tablist.clear()
@self.on_packet(PacketPlayerInfo) @self.on_packet(PacketPlayerInfo)

View file

@ -3,11 +3,13 @@ import datetime
from typing import Dict, List from typing import Dict, List
from aiocraft.client import MinecraftClient
from aiocraft.mc.definitions import BlockPos from aiocraft.mc.definitions import BlockPos
from aiocraft.mc.proto import PacketPosition, PacketTeleportConfirm from aiocraft.mc.proto import PacketPosition, PacketTeleportConfirm
class GameWorld(MinecraftClient): from ..scaffold import Scaffold
from ..events import ConnectedEvent
class GameWorld(Scaffold):
position : BlockPos position : BlockPos
# TODO world # TODO world
@ -16,8 +18,8 @@ class GameWorld(MinecraftClient):
self.position = BlockPos(0, 0, 0) self.position = BlockPos(0, 0, 0)
@self.on_connected() @self.on(ConnectedEvent)
async def connected_cb(): async def connected_cb(_):
self.tablist.clear() self.tablist.clear()
@self.on_packet(PacketPosition) @self.on_packet(PacketPosition)

View file

@ -14,11 +14,19 @@ from configparser import ConfigParser
from apscheduler.schedulers.asyncio import AsyncIOScheduler from apscheduler.schedulers.asyncio import AsyncIOScheduler
from aiocraft.client import MinecraftClient from aiocraft.client import MinecraftClient
from aiocraft.util import helpers
from aiocraft.mc.packet import Packet from aiocraft.mc.packet import Packet
from aiocraft.mc.definitions import ConnectionState
from aiocraft.mc.proto import PacketSetCompression, PacketKickDisconnect
from aiocraft.mc.proto.play.clientbound import PacketKeepAlive
from aiocraft.mc.proto.play.serverbound import PacketKeepAlive as PacketKeepAliveResponse
from .scaffold import Scaffold
from .events import ConnectedEvent, DisconnectedEvent
from .storage import Storage, SystemState from .storage import Storage, SystemState
from .notifier import Notifier from .notifier import Notifier
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld
from .traits import CallbacksHolder, Runnable
REMOVE_COLOR_FORMATS = re.compile(r"§[0-9a-z]") REMOVE_COLOR_FORMATS = re.compile(r"§[0-9a-z]")
@ -87,6 +95,8 @@ class Treepuncher(
modules : List[Addon] modules : List[Addon]
ctx : Dict[Any, Any] ctx : Dict[Any, Any]
_processing : bool
def __init__(self, name:str, *args, config_file:str=None, notifier:Notifier=None, **kwargs): def __init__(self, name:str, *args, config_file:str=None, notifier:Notifier=None, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.ctx = dict() self.ctx = dict()
@ -133,19 +143,55 @@ class Treepuncher(
self.storage._set_state(state) self.storage._set_state(state)
async def start(self): async def start(self):
# if self.started: # TODO readd check
# return
await super().start()
await self.notifier.initialize() await self.notifier.initialize()
for m in self.modules: for m in self.modules:
await m.initialize() await m.initialize()
await super().start() self._processing = True
self._worker = asyncio.get_event_loop().create_task(self._work())
self.scheduler.resume() self.scheduler.resume()
self._logger.info("Treepuncher started")
async def stop(self, force:bool=False): async def stop(self, force:bool=False):
self._processing = False
self.scheduler.pause() self.scheduler.pause()
await super().stop(force=force) if self.dispatcher.connected:
await self.dispatcher.disconnect(block=not force)
if not force:
await self._worker
await self.join_callbacks()
for m in self.modules: for m in self.modules:
await m.cleanup() await m.cleanup()
await self.notifier.cleanup() await self.notifier.cleanup()
await super().stop()
self._logger.info("Treepuncher stopped")
def install(self, module:Type[Addon]) -> Type[Addon]: def install(self, module:Type[Addon]) -> Type[Addon]:
self.modules.append(module(self)) self.modules.append(module(self))
return module return module
async def _work(self):
try:
server_data = await self.info(host=self.host, port=self.port)
except Exception:
return self._logger.exception("exception while pinging server")
while self._processing:
try:
await self.join(
host=self.host,
port=self.port,
proto=server_data['version']['protocol'],
packet_whitelist=self.callback_keys(filter=Packet),
)
except ConnectionRefusedError:
self._logger.error("Server rejected connection")
except OSError as e:
self._logger.error("Connection error : %s", str(e))
except Exception:
self._logger.exception("Unhandled exception")
break
await asyncio.sleep(5) # TODO setting
if self._processing:
await self.stop(force=True)