From adf5295e2b92669080ba8bf6529995997ab652e0 Mon Sep 17 00:00:00 2001 From: Salad Dais Date: Tue, 9 Jan 2024 13:41:37 +0000 Subject: [PATCH] Add start of ProxyParcelManager --- hippolyzer/lib/client/parcel_manager.py | 54 +++++++++++++++++++++---- hippolyzer/lib/proxy/parcel_manager.py | 18 +++++++++ hippolyzer/lib/proxy/region.py | 2 + 3 files changed, 67 insertions(+), 7 deletions(-) diff --git a/hippolyzer/lib/client/parcel_manager.py b/hippolyzer/lib/client/parcel_manager.py index 44baaf6..59c0f1d 100644 --- a/hippolyzer/lib/client/parcel_manager.py +++ b/hippolyzer/lib/client/parcel_manager.py @@ -1,5 +1,6 @@ import asyncio import dataclasses +import logging from typing import * import numpy as np @@ -10,6 +11,9 @@ from hippolyzer.lib.base.templates import ParcelGridFlags, ParcelFlags from hippolyzer.lib.client.state import BaseClientRegion +LOG = logging.getLogger(__name__) + + @dataclasses.dataclass class Parcel: local_id: int @@ -57,7 +61,8 @@ class ParcelManager: self._parcels_dirty = False if new_overlay_data != self.overlay.data[:]: # If the raw data doesn't match, then we have to parse again - self.overlay.data = new_overlay_data + new_data = np.frombuffer(new_overlay_data, dtype=np.uint8).reshape(self.overlay.shape) + np.copyto(self.overlay, new_data) self._parse_overlay() # We could optimize this by just marking specific squares dirty # if the parcel indices have changed between parses, but I don't care @@ -194,13 +199,30 @@ class ParcelManager: )) self._next_seq += 1 - parcel_props = await parcel_props_fut - data_block = parcel_props["ParcelData"][0] - # Parcel indices are one-indexed, convert to zero-indexed. - parcel_idx = self.parcel_indices[self._pos_to_grid_coords(pos)] - 1 - assert len(self.parcels) > parcel_idx + return self._process_parcel_properties(await parcel_props_fut, pos) - self.parcels[parcel_idx] = parcel = Parcel( + def _process_parcel_properties(self, parcel_props: Message, pos: Optional[Vector2] = None) -> Parcel: + data_block = parcel_props["ParcelData"][0] + grid_coord = None + # Parcel indices are one-indexed, convert to zero-indexed. + if pos is not None: + # We have a pos, figure out where in the grid we should look for the parcel index + grid_coord = self._pos_to_grid_coords(pos) + else: + # Need to look at the parcel bitmap to figure out a valid grid coord. + # This is a boolean array where each bit says whether the parcel occupies that grid. + parcel_bitmap = data_block.deserialize_var("Bitmap") + + for y in range(self.GRIDS_PER_EDGE): + for x in range(self.GRIDS_PER_EDGE): + if parcel_bitmap[y, x]: + # This is the first grid the parcel occupies per the bitmap + grid_coord = y, x + break + if grid_coord: + break + + parcel = Parcel( local_id=data_block["LocalID"], name=data_block["Name"], flags=ParcelFlags(data_block["ParcelFlags"]), @@ -208,4 +230,22 @@ class ParcelManager: # Parcel UUID isn't in this response :/ ) + # I guess the bitmap _could_ be empty, but probably not. + if grid_coord is not None: + parcel_idx = self.parcel_indices[grid_coord] - 1 + if len(self.parcels) > parcel_idx >= 0: + # Okay, parcels list is sane, place the parcel in there. + self.parcels[parcel_idx] = parcel + else: + LOG.warning(f"Received ParcelProperties with incomplete overlay for {grid_coord!r}") + return parcel + + async def get_parcel_at(self, pos: Vector2, request_if_missing: bool = True) -> Optional[Parcel]: + grid_coord = self._pos_to_grid_coords(pos) + parcel = None + if parcel_idx := self.parcel_indices[grid_coord]: + parcel = self.parcels[parcel_idx - 1] + if request_if_missing and parcel is None: + return await self.request_parcel_properties(pos) + return None diff --git a/hippolyzer/lib/proxy/parcel_manager.py b/hippolyzer/lib/proxy/parcel_manager.py index e69de29..1d346a1 100644 --- a/hippolyzer/lib/proxy/parcel_manager.py +++ b/hippolyzer/lib/proxy/parcel_manager.py @@ -0,0 +1,18 @@ +from typing import * + +from hippolyzer.lib.base.helpers import proxify +from hippolyzer.lib.base.message.message import Message +from hippolyzer.lib.client.parcel_manager import ParcelManager +if TYPE_CHECKING: + from hippolyzer.lib.proxy.region import ProxiedRegion + + +class ProxyParcelManager(ParcelManager): + def __init__(self, region: "ProxiedRegion"): + super().__init__(proxify(region)) + # Handle ParcelProperties messages that we didn't specifically ask for + self._region.message_handler.subscribe("ParcelProperties", self._handle_parcel_properties) + + def _handle_parcel_properties(self, msg: Message): + self._process_parcel_properties(msg) + return None diff --git a/hippolyzer/lib/proxy/region.py b/hippolyzer/lib/proxy/region.py index 85e9458..e0062c4 100644 --- a/hippolyzer/lib/proxy/region.py +++ b/hippolyzer/lib/proxy/region.py @@ -21,6 +21,7 @@ from hippolyzer.lib.proxy.object_manager import ProxyObjectManager from hippolyzer.lib.base.transfer_manager import TransferManager from hippolyzer.lib.base.xfer_manager import XferManager from hippolyzer.lib.proxy.asset_uploader import ProxyAssetUploader +from hippolyzer.lib.proxy.parcel_manager import ProxyParcelManager if TYPE_CHECKING: from hippolyzer.lib.proxy.sessions import Session @@ -67,6 +68,7 @@ class ProxiedRegion(BaseClientRegion): self.xfer_manager = XferManager(proxify(self), self.session().secure_session_id) self.transfer_manager = TransferManager(proxify(self), session.agent_id, session.id) self.asset_uploader = ProxyAssetUploader(proxify(self)) + self.parcel_manager = ProxyParcelManager(proxify(self)) self._recalc_caps() @property