Add ParcelManager to HippoClient

This commit is contained in:
Salad Dais
2024-01-04 21:45:54 +00:00
parent 67db8110a1
commit 9d2087a0fb
4 changed files with 19 additions and 3 deletions

View File

@@ -3,6 +3,7 @@ A simple client that just says hello to people
""" """
import asyncio import asyncio
import pprint
from contextlib import aclosing from contextlib import aclosing
import os import os
@@ -30,6 +31,11 @@ async def amain():
start_location=os.environ.get("HIPPO_START_LOCATION", "last"), start_location=os.environ.get("HIPPO_START_LOCATION", "last"),
) )
print("I'm here") print("I'm here")
# Wait until we have details about parcels and print them
await client.main_region.parcel_manager.parcels_downloaded.wait()
pprint.pprint(client.main_region.parcel_manager.parcels)
await client.send_chat("Hello World!", chat_type=ChatType.SHOUT) await client.send_chat("Hello World!", chat_type=ChatType.SHOUT)
client.session.message_handler.subscribe("ChatFromSimulator", _respond_to_chat) client.session.message_handler.subscribe("ChatFromSimulator", _respond_to_chat)
# Example of how to work with caps # Example of how to work with caps

View File

@@ -29,6 +29,7 @@ from hippolyzer.lib.base.xfer_manager import XferManager
from hippolyzer.lib.client.asset_uploader import AssetUploader from hippolyzer.lib.client.asset_uploader import AssetUploader
from hippolyzer.lib.client.inventory_manager import InventoryManager from hippolyzer.lib.client.inventory_manager import InventoryManager
from hippolyzer.lib.client.object_manager import ClientObjectManager, ClientWorldObjectManager from hippolyzer.lib.client.object_manager import ClientObjectManager, ClientWorldObjectManager
from hippolyzer.lib.client.parcel_manager import ParcelManager
from hippolyzer.lib.client.state import BaseClientSession, BaseClientRegion, BaseClientSessionManager from hippolyzer.lib.client.state import BaseClientSession, BaseClientRegion, BaseClientSessionManager
@@ -47,6 +48,8 @@ class ClientSettings(Settings):
USER_AGENT: str = SettingDescriptor(f"Hippolyzer/v{version('hippolyzer')}") USER_AGENT: str = SettingDescriptor(f"Hippolyzer/v{version('hippolyzer')}")
SEND_AGENT_UPDATES: bool = SettingDescriptor(True) SEND_AGENT_UPDATES: bool = SettingDescriptor(True)
"""Generally you want to send these, lots of things will break if you don't send at least one.""" """Generally you want to send these, lots of things will break if you don't send at least one."""
AUTO_REQUEST_PARCELS: bool = SettingDescriptor(True)
"""Automatically request all parcel details when connecting to a region"""
class HippoCapsClient(CapsClient): class HippoCapsClient(CapsClient):
@@ -121,6 +124,7 @@ class HippoClientRegion(BaseClientRegion):
self.xfer_manager = XferManager(proxify(self), self.session().secure_session_id) self.xfer_manager = XferManager(proxify(self), self.session().secure_session_id)
self.transfer_manager = TransferManager(proxify(self), session.agent_id, session.id) self.transfer_manager = TransferManager(proxify(self), session.agent_id, session.id)
self.asset_uploader = AssetUploader(proxify(self)) self.asset_uploader = AssetUploader(proxify(self))
self.parcel_manager = ParcelManager(proxify(self))
self.objects = ClientObjectManager(self) self.objects = ClientObjectManager(self)
self._llsd_serializer = LLSDMessageSerializer() self._llsd_serializer = LLSDMessageSerializer()
self._eq_task: Optional[asyncio.Task] = None self._eq_task: Optional[asyncio.Task] = None
@@ -226,6 +230,9 @@ class HippoClientRegion(BaseClientRegion):
self.update_caps(await seed_resp.read_llsd()) self.update_caps(await seed_resp.read_llsd())
self._eq_task = asyncio.create_task(self._poll_event_queue()) self._eq_task = asyncio.create_task(self._poll_event_queue())
if self.session().session_manager.settings.AUTO_REQUEST_PARCELS:
_ = asyncio.create_task(self.parcel_manager.request_dirty_parcels())
except Exception as e: except Exception as e:
# Let consumers who were `await`ing the connected signal know there was an error # Let consumers who were `await`ing the connected signal know there was an error
if not self.connected.done(): if not self.connected.done():

View File

@@ -138,12 +138,13 @@ class ParcelManager:
# Append the grid to the neighbour testing queue # Append the grid to the neighbour testing queue
neighbor_test_queue.append(new_pos) neighbor_test_queue.append(new_pos)
async def request_parcels_if_dirty(self) -> Tuple[Parcel, ...]: async def request_dirty_parcels(self) -> Tuple[Parcel, ...]:
if self._parcels_dirty: if self._parcels_dirty:
return await self.request_all_parcels() return await self.request_all_parcels()
return tuple(self.parcels) return tuple(self.parcels)
async def request_all_parcels(self) -> Tuple[Parcel, ...]: async def request_all_parcels(self) -> Tuple[Parcel, ...]:
await self.overlay_complete.wait()
# Because of how we build up the parcel index map, it's safe for us to # Because of how we build up the parcel index map, it's safe for us to
# do this instead of keeping track of seen IDs in a set or similar # do this instead of keeping track of seen IDs in a set or similar
last_seen_parcel_index = 0 last_seen_parcel_index = 0
@@ -164,9 +165,11 @@ class ParcelManager:
# Wait for all parcel properties to come in # Wait for all parcel properties to come in
await asyncio.gather(*futs) await asyncio.gather(*futs)
self.parcels_downloaded.set() self.parcels_downloaded.set()
self._parcels_dirty = False
return tuple(self.parcels) return tuple(self.parcels)
async def request_parcel_properties(self, pos: Vector2) -> Parcel: async def request_parcel_properties(self, pos: Vector2) -> Parcel:
await self.overlay_complete.wait()
seq_id = self._next_seq seq_id = self._next_seq
# Register a wait on a ParcelProperties matching this seq # Register a wait on a ParcelProperties matching this seq
parcel_props_fut = self._region.message_handler.wait_for( parcel_props_fut = self._region.message_handler.wait_for(
@@ -176,7 +179,7 @@ class ParcelManager:
) )
# We don't care about when we receive an ack, we only care about when we receive the parcel props # We don't care about when we receive an ack, we only care about when we receive the parcel props
_ = self._region.circuit.send_reliable(Message( _ = self._region.circuit.send_reliable(Message(
"RequestParcelProperties", "ParcelPropertiesRequest",
Block("AgentData", AgentID=self._region.session().agent_id, SessionID=self._region.session().id), Block("AgentData", AgentID=self._region.session().agent_id, SessionID=self._region.session().id),
Block( Block(
"ParcelData", "ParcelData",

View File

@@ -253,7 +253,7 @@ class TestParcelOverlay(unittest.IsolatedAsyncioTestCase):
async def test_request_parcel_properties(self): async def test_request_parcel_properties(self):
for msg in self.test_msgs: for msg in self.test_msgs:
self.handler.handle(msg) self.handler.handle(msg)
req_task = asyncio.create_task(self.parcel_manager.request_parcels_if_dirty()) req_task = asyncio.create_task(self.parcel_manager.request_dirty_parcels())
# HACK: Wait for requests to be sent out # HACK: Wait for requests to be sent out
await asyncio.sleep(0.01) await asyncio.sleep(0.01)