diff --git a/hippolyzer/lib/base/inventory.py b/hippolyzer/lib/base/inventory.py index d0d442e..5a79dfc 100644 --- a/hippolyzer/lib/base/inventory.py +++ b/hippolyzer/lib/base/inventory.py @@ -356,8 +356,20 @@ class InventoryModel(InventoryBase): def __contains__(self, item: UUID): return item in self.nodes - def get(self, item: UUID) -> Optional[InventoryNodeBase]: - return self.nodes.get(item) + def get(self, key: UUID) -> Optional[InventoryNodeBase]: + return self.nodes.get(key) + + def get_category(self, key: UUID) -> InventoryCategory: + node = self.get(key) + if not isinstance(node, InventoryCategory): + raise ValueError(f"{node!r} is not a category") + return node + + def get_item(self, key: UUID) -> InventoryItem: + node = self.get(key) + if not isinstance(node, InventoryItem): + raise ValueError(f"{node!r} is not an item") + return node @dataclasses.dataclass diff --git a/hippolyzer/lib/client/inventory_manager.py b/hippolyzer/lib/client/inventory_manager.py index abddb3f..a869331 100644 --- a/hippolyzer/lib/client/inventory_manager.py +++ b/hippolyzer/lib/client/inventory_manager.py @@ -12,7 +12,7 @@ from hippolyzer.lib.base import llsd from hippolyzer.lib.base.datatypes import UUID from hippolyzer.lib.base.inventory import InventoryModel, InventoryCategory, InventoryItem, InventoryNodeBase from hippolyzer.lib.base.message.message import Message, Block -from hippolyzer.lib.base.templates import AssetType, FolderType, InventoryType +from hippolyzer.lib.base.templates import AssetType, FolderType, InventoryType, Permissions from hippolyzer.lib.client.state import BaseClientSession from hippolyzer.lib.base.templates import WearableType @@ -219,9 +219,8 @@ class InventoryManager: self.model.upsert(InventoryItem.from_llsd(link_llsd, flavor="ais")) for cat_id, version in payload.get("_updated_category_versions", {}).items(): - cat_node: InventoryCategory = self.model.get(cat_id) # type: ignore - if cat_node: - cat_node.version = version + cat_node = self.model.get_category(cat_id) + cat_node.version = version # Get rid of anything we were asked to for node_id in itertools.chain( @@ -261,7 +260,7 @@ class InventoryManager: self, parent: InventoryCategory | UUID, name: str, - type: int = -1, + pref_type: int = AssetType.NONE, cat_id: UUID | None = None ) -> InventoryCategory: parent_id = _get_node_id(parent) @@ -271,13 +270,13 @@ class InventoryManager: { "category_id": cat_id, "name": name, - "type_default": type, + "type_default": pref_type, "parent_id": parent_id } ] } data = await self.make_ais_request("POST", f"/category/{parent_id}", {"tid": UUID.random()}, payload) - return self.model.get(data["_created_categories"][0]) # type: ignore + return self.model.get_category(data["_created_categories"][0]) async def create_item( self, @@ -287,7 +286,7 @@ class InventoryManager: inv_type: InventoryType, wearable_type: WearableType, transaction_id: UUID, - next_mask: int = 0x7FffFFff, + next_mask: int | Permissions = 0x0008e000, description: str = '', ) -> InventoryItem: parent_id = _get_node_id(parent) @@ -316,14 +315,14 @@ class InventoryManager: ) ) msg = await asyncio.wait_for(get_msg(), 5.0) - # Handle this synchronously. - self._handle_update_create_inventory_item(msg) - return self.model.get(msg["InventoryData"]["ItemID"]) # type: ignore + # We assume that _handle_update_create_inventory_item() has already been called internally + # by the time that the `await` returns given asyncio scheduling + return self.model.get_item(msg["InventoryData"]["ItemID"]) async def move(self, node: InventoryNodeBase, new_parent: UUID | InventoryCategory) -> None: # AIS error messages suggest using the MOVE HTTP method instead of setting a new parent - # via PATCH. MOVE is not implemented. Instead, we do what the viewer does and use legacy - # UDP messages for reparenting things + # via PATCH. MOVE is not implemented in AIS. Instead, we do what the viewer does and use + # legacy UDP messages for reparenting things new_parent = _get_node_id(new_parent) msg = Message( diff --git a/hippolyzer/lib/proxy/inventory_manager.py b/hippolyzer/lib/proxy/inventory_manager.py index d7c148c..79acdf3 100644 --- a/hippolyzer/lib/proxy/inventory_manager.py +++ b/hippolyzer/lib/proxy/inventory_manager.py @@ -13,7 +13,7 @@ from hippolyzer.lib.base.datatypes import UUID from hippolyzer.lib.base.inventory import InventoryCategory, InventoryNodeBase from hippolyzer.lib.base.message.message import Message, Block from hippolyzer.lib.base.inventory import InventoryItem -from hippolyzer.lib.base.templates import AssetType, InventoryType, WearableType +from hippolyzer.lib.base.templates import AssetType, InventoryType, WearableType, Permissions from hippolyzer.lib.base.network.transport import Direction if TYPE_CHECKING: @@ -119,10 +119,10 @@ class ProxyInventoryManager(InventoryManager): self, parent: InventoryCategory | UUID, name: str, - type: int = -1, + pref_type: int = AssetType.NONE, cat_id: UUID | None = None ) -> InventoryCategory: - cat = await super().create_folder(parent, name, type, cat_id) + cat = await super().create_folder(parent, name, pref_type, cat_id) await self._session.main_region.circuit.send_reliable(self._craft_update_message(cat)) return cat @@ -134,7 +134,7 @@ class ProxyInventoryManager(InventoryManager): inv_type: InventoryType, wearable_type: WearableType, transaction_id: UUID, - next_mask: int = 0x7FffFFff, + next_mask: int | Permissions = 0x0008e000, description: str = '', ) -> InventoryItem: item = await super().create_item( @@ -175,13 +175,14 @@ class ProxyInventoryManager(InventoryManager): return msg def _craft_update_message(self, node: InventoryNodeBase): - is_folder = True - if isinstance(node, InventoryItem): - is_folder = False - - return Message( + msg = Message( "BulkUpdateInventory", Block("AgentData", AgentID=self._session.agent_id, TransactionID=UUID.random()), - node.to_folder_data() if is_folder else node.to_inventory_data("ItemData"), # type: ignore direction=Direction.IN, ) + + if isinstance(node, InventoryItem): + msg.add_block(node.to_inventory_data("ItemData")) + elif isinstance(node, InventoryCategory): + msg.add_block(node.to_folder_data()) + return msg