Add object inventory helpers to region object manager
This commit is contained in:
@@ -226,7 +226,7 @@ class InventoryModel(InventoryBase):
|
||||
return model
|
||||
|
||||
@classmethod
|
||||
def from_llsd(cls, llsd_val: List[Dict], flavor: str = "legacy") -> InventoryModel:
|
||||
def from_llsd(cls, llsd_val: List[Dict], flavor: str = "legacy") -> Self:
|
||||
model = cls()
|
||||
for obj_dict in llsd_val:
|
||||
obj = None
|
||||
@@ -565,7 +565,7 @@ class InventoryCategory(InventoryContainerBase):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy"):
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy") -> Self:
|
||||
if flavor == "ais" and "type" not in inv_dict:
|
||||
inv_dict = inv_dict.copy()
|
||||
inv_dict["type"] = AssetType.CATEGORY
|
||||
@@ -691,7 +691,7 @@ class InventoryItem(InventoryNodeBase):
|
||||
return val
|
||||
|
||||
@classmethod
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy"):
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy") -> Self:
|
||||
if flavor == "ais" and "linked_id" in inv_dict:
|
||||
# Links get represented differently than other items for whatever reason.
|
||||
# This is incredibly annoying, under *NIX there's nothing really special about symlinks.
|
||||
|
||||
@@ -174,7 +174,7 @@ class SchemaBase(abc.ABC):
|
||||
return fields_dict
|
||||
|
||||
@classmethod
|
||||
def from_str(cls, text: str):
|
||||
def from_str(cls, text: str) -> Self:
|
||||
return cls.from_reader(StringIO(text))
|
||||
|
||||
@classmethod
|
||||
@@ -183,11 +183,11 @@ class SchemaBase(abc.ABC):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls, data: bytes):
|
||||
def from_bytes(cls, data: bytes) -> Self:
|
||||
return cls.from_str(data.decode("utf8"))
|
||||
|
||||
@classmethod
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy"):
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy") -> Self:
|
||||
fields = cls._get_fields_dict(llsd_flavor=flavor)
|
||||
obj_dict = {}
|
||||
try:
|
||||
@@ -262,5 +262,5 @@ class SchemaBase(abc.ABC):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
def _obj_from_dict(cls, obj_dict: Dict):
|
||||
def _obj_from_dict(cls, obj_dict: Dict) -> Self:
|
||||
return cls(**obj_dict) # type: ignore
|
||||
|
||||
@@ -15,6 +15,7 @@ from typing import *
|
||||
|
||||
from hippolyzer.lib.base.datatypes import UUID, Vector3
|
||||
from hippolyzer.lib.base.helpers import proxify
|
||||
from hippolyzer.lib.base.inventory import InventoryItem, InventoryModel
|
||||
from hippolyzer.lib.base.message.message import Block, Message
|
||||
from hippolyzer.lib.base.message.message_handler import MessageHandler
|
||||
from hippolyzer.lib.base.message.msgtypes import PacketFlags
|
||||
@@ -27,7 +28,7 @@ from hippolyzer.lib.base.objects import (
|
||||
)
|
||||
from hippolyzer.lib.base.settings import Settings
|
||||
from hippolyzer.lib.client.namecache import NameCache, NameCacheEntry
|
||||
from hippolyzer.lib.base.templates import PCode, ObjectStateSerializer
|
||||
from hippolyzer.lib.base.templates import PCode, ObjectStateSerializer, XferFilePath
|
||||
from hippolyzer.lib.base import llsd
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -217,6 +218,38 @@ class ClientObjectManager:
|
||||
for entry in entries:
|
||||
self.state.materials[UUID(bytes=entry["ID"])] = entry["Material"]
|
||||
|
||||
async def request_object_inv(self, obj: Object) -> List[InventoryItem]:
|
||||
if "RequestTaskInventory" in self._region.cap_urls:
|
||||
return await self.request_object_inv_via_cap(obj)
|
||||
else:
|
||||
return await self.request_object_inv_via_xfer(obj)
|
||||
|
||||
async def request_object_inv_via_cap(self, obj: Object) -> List[InventoryItem]:
|
||||
async with self._region.caps_client.get("RequestTaskInventory", params={"task_id": obj.FullID}) as resp:
|
||||
resp.raise_for_status()
|
||||
return [InventoryItem.from_llsd(x) for x in (await resp.read_llsd())["contents"]]
|
||||
|
||||
async def request_object_inv_via_xfer(self, obj: Object) -> List[InventoryItem]:
|
||||
session = self._region.session()
|
||||
with self._region.message_handler.subscribe_async(
|
||||
('ReplyTaskInventory',), predicate=lambda x: x["InventoryData"]["TaskID"] == obj.FullID
|
||||
) as get_msg:
|
||||
await self._region.circuit.send_reliable(Message(
|
||||
'RequestTaskInventory',
|
||||
# If no session is passed in we'll use the active session when the coro was created
|
||||
Block('AgentData', AgentID=session.agent_id, SessionID=session.id),
|
||||
Block('InventoryData', LocalID=obj.LocalID),
|
||||
))
|
||||
|
||||
inv_message = await asyncio.wait_for(get_msg(), timeout=5.0)
|
||||
|
||||
# Xfer doesn't need to be immediately awaited, multiple signals can be waited on.
|
||||
xfer = await self._region.xfer_manager.request(
|
||||
file_name=inv_message["InventoryData"]["Filename"], file_path=XferFilePath.CACHE)
|
||||
|
||||
inv_model = InventoryModel.from_bytes(xfer.reassemble_chunks())
|
||||
return list(inv_model.all_items)
|
||||
|
||||
|
||||
class ObjectEvent:
|
||||
__slots__ = ("object", "updated", "update_type")
|
||||
|
||||
@@ -17,6 +17,7 @@ from hippolyzer.lib.base.message.message_handler import MessageHandler
|
||||
from hippolyzer.lib.base.network.caps_client import CapsClient
|
||||
from hippolyzer.lib.base.network.transport import ADDR_TUPLE
|
||||
from hippolyzer.lib.base.objects import handle_to_global_pos
|
||||
from hippolyzer.lib.base.xfer_manager import XferManager
|
||||
|
||||
from hippolyzer.lib.client.object_manager import ClientObjectManager, ClientWorldObjectManager
|
||||
|
||||
@@ -27,6 +28,7 @@ class BaseClientRegion(ConnectionHolder, abc.ABC):
|
||||
# Actually a weakref
|
||||
session: Callable[[], BaseClientSession]
|
||||
objects: ClientObjectManager
|
||||
xfer_manager: XferManager
|
||||
caps_client: CapsClient
|
||||
cap_urls: multidict.MultiDict[str]
|
||||
circuit_addr: ADDR_TUPLE
|
||||
|
||||
Reference in New Issue
Block a user