LoveLogicAI commited on
Commit
3243c2c
·
verified ·
1 Parent(s): 8272517

world state

Browse files
Files changed (1) hide show
  1. xros_world.py +123 -0
xros_world.py ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """xros_world.py — the core of the DiOS/XROS world-state service.
2
+
3
+ This implements the central claim of the DiOS paper (arXiv:2201.03256):
4
+ the physical-digital world is a *single shared resource* among applications.
5
+ Instead of every app reconstructing its own view of the world, apps read and
6
+ mutate one shared world model.
7
+
8
+ The module is dependency-free (stdlib only) so the store can be unit-tested
9
+ and reused anywhere. Networking lives in xros_server.py.
10
+
11
+ Concepts:
12
+ - WorldObject: a node in the scene graph (an entity in the shared world).
13
+ - WorldState: the registry of objects + an event bus that publishes
14
+ spawn/move/remove events to every subscriber.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import asyncio
20
+ import time
21
+ import uuid
22
+ from dataclasses import dataclass, field, asdict
23
+ from typing import Any, Dict, List, Optional
24
+
25
+
26
+ @dataclass
27
+ class Pose:
28
+ """Position (meters), rotation (quaternion x,y,z,w), scale (unitless)."""
29
+ position: List[float] = field(default_factory=lambda: [0.0, 0.0, 0.0])
30
+ rotation: List[float] = field(default_factory=lambda: [0.0, 0.0, 0.0, 1.0])
31
+ scale: List[float] = field(default_factory=lambda: [1.0, 1.0, 1.0])
32
+
33
+
34
+ @dataclass
35
+ class WorldObject:
36
+ """A single entity in the shared world (a scene-graph node)."""
37
+ id: str
38
+ type: str
39
+ pose: Pose
40
+ properties: Dict[str, Any] = field(default_factory=dict)
41
+ owner: Optional[str] = None
42
+ created_at: float = field(default_factory=time.time)
43
+ updated_at: float = field(default_factory=time.time)
44
+
45
+ def to_dict(self) -> Dict[str, Any]:
46
+ d = asdict(self)
47
+ d["pose"] = asdict(self.pose)
48
+ return d
49
+
50
+
51
+ class WorldState:
52
+ """The shared world: an object registry plus a fan-out event bus.
53
+
54
+ Thread-safety: all mutations are serialized through an asyncio.Lock, and
55
+ events are delivered to per-subscriber asyncio.Queues so a slow client
56
+ never blocks a fast one.
57
+ """
58
+
59
+ def __init__(self) -> None:
60
+ self._objects: Dict[str, WorldObject] = {}
61
+ self._subscribers: List[asyncio.Queue] = []
62
+ self._lock = asyncio.Lock()
63
+
64
+ # ---- mutations -----------------------------------------------------
65
+
66
+ async def spawn(
67
+ self,
68
+ type: str,
69
+ pose: Optional[Pose] = None,
70
+ properties: Optional[Dict[str, Any]] = None,
71
+ owner: Optional[str] = None,
72
+ ) -> WorldObject:
73
+ obj = WorldObject(
74
+ id=uuid.uuid4().hex,
75
+ type=type,
76
+ pose=pose or Pose(),
77
+ properties=properties or {},
78
+ owner=owner,
79
+ )
80
+ async with self._lock:
81
+ self._objects[obj.id] = obj
82
+ await self._publish({"op": "spawn", "object": obj.to_dict()})
83
+ return obj
84
+
85
+ async def move(self, obj_id: str, pose: Pose) -> WorldObject:
86
+ async with self._lock:
87
+ obj = self._objects[obj_id] # KeyError if unknown -> caller handles
88
+ obj.pose = pose
89
+ obj.updated_at = time.time()
90
+ await self._publish({"op": "move", "object": obj.to_dict()})
91
+ return obj
92
+
93
+ async def remove(self, obj_id: str) -> WorldObject:
94
+ async with self._lock:
95
+ obj = self._objects.pop(obj_id) # KeyError if unknown
96
+ await self._publish({"op": "remove", "id": obj_id})
97
+ return obj
98
+
99
+ # ---- reads ---------------------------------------------------------
100
+
101
+ async def snapshot(self) -> List[Dict[str, Any]]:
102
+ async with self._lock:
103
+ return [o.to_dict() for o in self._objects.values()]
104
+
105
+ async def get(self, obj_id: str) -> Optional[WorldObject]:
106
+ async with self._lock:
107
+ return self._objects.get(obj_id)
108
+
109
+ # ---- pub/sub -------------------------------------------------------
110
+
111
+ def subscribe(self) -> asyncio.Queue:
112
+ """Return a queue that will receive every future world event."""
113
+ q: asyncio.Queue = asyncio.Queue()
114
+ self._subscribers.append(q)
115
+ return q
116
+
117
+ def unsubscribe(self, q: asyncio.Queue) -> None:
118
+ if q in self._subscribers:
119
+ self._subscribers.remove(q)
120
+
121
+ async def _publish(self, event: Dict[str, Any]) -> None:
122
+ for q in list(self._subscribers):
123
+ q.put_nowait(event)