feat: split world and position, added BlockUpdateEvent
This commit is contained in:
parent
e6a1ecc5c4
commit
f920bbc838
6 changed files with 105 additions and 88 deletions
|
@ -3,3 +3,4 @@ from .join_game import JoinGameEvent
|
|||
from .death import DeathEvent
|
||||
from .system import ConnectedEvent, DisconnectedEvent
|
||||
from .connection import PlayerJoinEvent, PlayerLeaveEvent
|
||||
from .block_update import BlockUpdateEvent
|
||||
|
|
13
src/treepuncher/events/block_update.py
Normal file
13
src/treepuncher/events/block_update.py
Normal file
|
@ -0,0 +1,13 @@
|
|||
from aiocraft.mc.definitions import BlockPos
|
||||
|
||||
from .base import BaseEvent
|
||||
|
||||
class BlockUpdateEvent(BaseEvent):
|
||||
SENTINEL = object()
|
||||
|
||||
location : BlockPos
|
||||
state : int
|
||||
|
||||
def __init__(self, location: BlockPos, state: int):
|
||||
self.location = location
|
||||
self.state = state
|
|
@ -4,3 +4,4 @@ from .tablist import GameTablist
|
|||
from .chat import GameChat
|
||||
from .world import GameWorld
|
||||
from .container import GameContainer
|
||||
from .position import GamePosition
|
||||
|
|
53
src/treepuncher/game/position.py
Normal file
53
src/treepuncher/game/position.py
Normal file
|
@ -0,0 +1,53 @@
|
|||
from typing import Optional
|
||||
|
||||
from aiocraft.mc.definitions import BlockPos
|
||||
from aiocraft.mc.proto import PacketPosition, PacketSetPassengers, PacketEntityTeleport, PacketTeleportConfirm
|
||||
|
||||
from ..scaffold import Scaffold
|
||||
|
||||
class GamePosition(Scaffold):
|
||||
position : BlockPos
|
||||
vehicle_id : Optional[int]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.position = BlockPos(0, 0, 0)
|
||||
self.vehicle_id = None
|
||||
|
||||
@self.on_packet(PacketSetPassengers)
|
||||
async def player_enters_vehicle_cb(packet:PacketSetPassengers):
|
||||
if self.vehicle_id is None: # might get mounted on a vehicle
|
||||
for entity_id in packet.passengers:
|
||||
if entity_id == self.entity_id:
|
||||
self.vehicle_id = packet.entityId
|
||||
else: # might get dismounted from vehicle
|
||||
if packet.entityId == self.vehicle_id:
|
||||
if self.entity_id not in packet.passengers:
|
||||
self.vehicle_id = None
|
||||
|
||||
@self.on_packet(PacketEntityTeleport)
|
||||
async def entity_rubberband_cb(packet:PacketEntityTeleport):
|
||||
if self.vehicle_id is None:
|
||||
return
|
||||
if self.vehicle_id != packet.entityId:
|
||||
return
|
||||
self.position = BlockPos(packet.x, packet.y, packet.z)
|
||||
self.logger.info(
|
||||
"Position synchronized : (x:%.0f,y:%.0f,z:%.0f) (vehicle)",
|
||||
self.position.x, self.position.y, self.position.z
|
||||
)
|
||||
|
||||
@self.on_packet(PacketPosition)
|
||||
async def player_rubberband_cb(packet:PacketPosition):
|
||||
self.position = BlockPos(packet.x, packet.y, packet.z)
|
||||
self.logger.info(
|
||||
"Position synchronized : (x:%.0f,y:%.0f,z:%.0f)",
|
||||
self.position.x, self.position.y, self.position.z
|
||||
)
|
||||
await self.dispatcher.write(
|
||||
PacketTeleportConfirm(
|
||||
self.dispatcher.proto,
|
||||
teleportId=packet.teleportId
|
||||
)
|
||||
)
|
|
@ -1,98 +1,27 @@
|
|||
import json
|
||||
|
||||
from time import time
|
||||
from typing import Optional
|
||||
|
||||
from aiocraft.mc.definitions import BlockPos
|
||||
from aiocraft.mc.proto.play.clientbound import (
|
||||
PacketPosition, PacketMapChunk, PacketBlockChange, PacketMultiBlockChange, PacketSetPassengers,
|
||||
PacketEntityTeleport, PacketRelEntityMove
|
||||
)
|
||||
from aiocraft.mc.proto.play.serverbound import PacketTeleportConfirm, PacketSteerVehicle
|
||||
from aiocraft.mc.proto import PacketMapChunk, PacketBlockChange, PacketMultiBlockChange
|
||||
from aiocraft.mc.types import twos_comp
|
||||
|
||||
from aiocraft import Chunk, World # TODO these imports will hopefully change!
|
||||
|
||||
from ..scaffold import Scaffold
|
||||
from ..events import BlockUpdateEvent
|
||||
|
||||
class GameWorld(Scaffold):
|
||||
position : BlockPos
|
||||
vehicle_id : Optional[int]
|
||||
world : World
|
||||
|
||||
_last_steer_vehicle : float
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
self.position = BlockPos(0, 0, 0)
|
||||
self.vehicle_id = None
|
||||
self._last_steer_vehicle = time()
|
||||
self.world = World()
|
||||
|
||||
@self.on_packet(PacketSetPassengers)
|
||||
async def player_enters_vehicle_cb(packet:PacketSetPassengers):
|
||||
if self.vehicle_id is None: # might get mounted on a vehicle
|
||||
for entity_id in packet.passengers:
|
||||
if entity_id == self.entity_id:
|
||||
self.vehicle_id = packet.entityId
|
||||
else: # might get dismounted from vehicle
|
||||
if packet.entityId == self.vehicle_id:
|
||||
if self.entity_id not in packet.passengers:
|
||||
self.vehicle_id = None
|
||||
|
||||
@self.on_packet(PacketEntityTeleport)
|
||||
async def entity_rubberband_cb(packet:PacketEntityTeleport):
|
||||
if self.vehicle_id is None:
|
||||
return
|
||||
if self.vehicle_id != packet.entityId:
|
||||
return
|
||||
self.position = BlockPos(packet.x, packet.y, packet.z)
|
||||
self.logger.info(
|
||||
"Position synchronized : (x:%.0f,y:%.0f,z:%.0f) (vehicle)",
|
||||
self.position.x, self.position.y, self.position.z
|
||||
)
|
||||
|
||||
@self.on_packet(PacketRelEntityMove)
|
||||
async def entity_relative_move_cb(packet:PacketRelEntityMove):
|
||||
if self.vehicle_id is None:
|
||||
return
|
||||
if self.vehicle_id != packet.entityId:
|
||||
return
|
||||
self.position = BlockPos(
|
||||
self.position.x + packet.dX,
|
||||
self.position.y + packet.dY,
|
||||
self.position.z + packet.dZ
|
||||
)
|
||||
self.logger.debug(
|
||||
"Position synchronized : (x:%.0f,y:%.0f,z:%.0f) (relMove vehicle)",
|
||||
self.position.x, self.position.y, self.position.z
|
||||
)
|
||||
if time() - self._last_steer_vehicle >= 5:
|
||||
self._last_steer_vehicle = time()
|
||||
await self.dispatcher.write(
|
||||
PacketSteerVehicle(
|
||||
self.dispatcher.proto,
|
||||
forward=0,
|
||||
sideways=0,
|
||||
jump=0
|
||||
)
|
||||
)
|
||||
|
||||
@self.on_packet(PacketPosition)
|
||||
async def player_rubberband_cb(packet:PacketPosition):
|
||||
self.position = BlockPos(packet.x, packet.y, packet.z)
|
||||
self.logger.info(
|
||||
"Position synchronized : (x:%.0f,y:%.0f,z:%.0f)",
|
||||
self.position.x, self.position.y, self.position.z
|
||||
)
|
||||
await self.dispatcher.write(
|
||||
PacketTeleportConfirm(
|
||||
self.dispatcher.proto,
|
||||
teleportId=packet.teleportId
|
||||
)
|
||||
)
|
||||
|
||||
if self.cfg.getboolean("process_world", fallback=False):
|
||||
self.world = World()
|
||||
# Since this might require more resources, allow to disable it
|
||||
if not self.cfg.getboolean("process_world", fallback=True):
|
||||
return
|
||||
|
||||
if self.proto == 340: # Chunk parsing is only implemented for 1.12
|
||||
@self.on_packet(PacketMapChunk)
|
||||
async def map_chunk_cb(packet:PacketMapChunk):
|
||||
assert isinstance(packet.bitMap, int)
|
||||
|
@ -100,15 +29,34 @@ class GameWorld(Scaffold):
|
|||
c.read(packet.chunkData)
|
||||
self.world.put(c, packet.x, packet.z, not packet.groundUp)
|
||||
|
||||
@self.on_packet(PacketBlockChange)
|
||||
async def block_change_cb(packet:PacketBlockChange):
|
||||
self.world.put_block(packet.location[0], packet.location[1], packet.location[2], packet.type)
|
||||
@self.on_packet(PacketBlockChange)
|
||||
async def block_change_cb(packet:PacketBlockChange):
|
||||
self.world.put_block(packet.location[0], packet.location[1], packet.location[2], packet.type)
|
||||
pos = BlockPos(packet.location[0], packet.location[1], packet.location[2])
|
||||
await self.run_callbacks(BlockUpdateEvent, BlockUpdateEvent(pos, packet.type))
|
||||
|
||||
@self.on_packet(PacketMultiBlockChange)
|
||||
async def multi_block_change_cb(packet:PacketMultiBlockChange):
|
||||
@self.on_packet(PacketMultiBlockChange)
|
||||
async def multi_block_change_cb(packet:PacketMultiBlockChange):
|
||||
if self.proto < 751:
|
||||
chunk_x_off = packet.chunkX * 16
|
||||
chunk_z_off = packet.chunkZ * 16
|
||||
for entry in packet.records:
|
||||
x_off = (entry['horizontalPos'] >> 4 ) & 15
|
||||
z_off = entry['horizontalPos'] & 15
|
||||
self.world.put_block(x_off + chunk_x_off, entry['y'], z_off + chunk_z_off, entry['blockId'])
|
||||
pos = BlockPos(x_off + chunk_x_off, entry['y'], z_off + chunk_z_off)
|
||||
self.world.put_block(pos.x,pos.y, pos.z, entry['blockId'])
|
||||
await self.run_callbacks(BlockUpdateEvent, BlockUpdateEvent(pos, entry['blockId']))
|
||||
elif self.proto < 760:
|
||||
x = twos_comp((packet.chunkCoordinates >> 42) & 0x3FFFFF, 22)
|
||||
z = twos_comp((packet.chunkCoordinates >> 20) & 0x3FFFFF, 22)
|
||||
y = twos_comp((packet.chunkCoordinates ) & 0xFFFFF , 20)
|
||||
for loc in packet.records:
|
||||
state = loc >> 12
|
||||
dx = ((loc & 0x0FFF) >> 8 ) & 0x0F
|
||||
dz = ((loc & 0x0FFF) >> 4 ) & 0x0F
|
||||
dy = ((loc & 0x0FFF) ) & 0x0F
|
||||
pos = BlockPos(16*x + dx, 16*y + dy, 16*z + dz)
|
||||
self.world.put_block(pos.x, pos.y, pos.z, state)
|
||||
await self.run_callbacks(BlockUpdateEvent, BlockUpdateEvent(pos, state))
|
||||
else:
|
||||
self.logger.error("Cannot process MultiBlockChange for protocol %d", self.proto)
|
||||
|
|
|
@ -15,7 +15,7 @@ from aiocraft.mc.auth import AuthInterface, AuthException, MojangAuthenticator,
|
|||
from aiocraft.mc.auth.microsoft import InvalidStateError
|
||||
|
||||
from .storage import StorageDriver, SystemState, AuthenticatorState
|
||||
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld, GameContainer
|
||||
from .game import GameState, GameChat, GameInventory, GameTablist, GameWorld, GameContainer, GamePosition
|
||||
from .addon import Addon
|
||||
from .notifier import Notifier, Provider
|
||||
|
||||
|
@ -34,6 +34,7 @@ class Treepuncher(
|
|||
GameInventory,
|
||||
GameContainer,
|
||||
GameTablist,
|
||||
GamePosition,
|
||||
GameWorld
|
||||
):
|
||||
name: str
|
||||
|
@ -222,7 +223,7 @@ class Treepuncher(
|
|||
|
||||
except AuthException as e:
|
||||
self.logger.error("Auth exception : [%s|%d] %s (%s)", e.endpoint, e.code, e.data, e.kwargs)
|
||||
except InvalidStateError as e:
|
||||
except InvalidStateError:
|
||||
self.logger.error("Invalid authenticator state")
|
||||
if isinstance(self.authenticator, MicrosoftAuthenticator):
|
||||
self.logger.info("Obtain an auth code by visiting %s", self.authenticator.url())
|
||||
|
|
Loading…
Reference in a new issue