Overte C++ Documentation
SimulationOwner.h
1 //
2 // SimulationOwner.h
3 // libraries/entities/src
4 //
5 // Created by Andrew Meadows on 2015.06.19
6 // Copyright 2015 High Fidelity, Inc.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi_SimulationOwner_h
13 #define hifi_SimulationOwner_h
14 
15 #include <QtCore/QDebug>
16 #include <QtCore/QByteArray>
17 
18 #include <SharedUtil.h>
19 #include <UUID.h>
20 
21 // HighFidelity uses a distributed physics simulation where multiple "participants" simulate portions
22 // of the same domain. Even when portions overlap only one participant is allowed to be the current
23 // authority for any particular object's physical simulation. The authoritative participant is called the
24 // "simulation owner" and its duty is to send "state synchronization" (transform/velocity) updates for an
25 // entity to the entity-server. The entity-server relays updates to other participants who apply them to
26 // their own simulation.
27 //
28 // Participants acquire ownership by sending a "bid" to the entity-server. The bid is a properties update:
29 // { "simulationOwner": { "ownerID" : sessionID, "priority" : priority },
30 // transform/velocity properties
31 // }
32 //
33 // The entity-server is the authority as to who owns what and may reject a bid. The rules for handling a
34 // bid are as follows:
35 //
36 // (1) A bid may be refused for special ownership restrictions, but otherwise...
37 //
38 // (2) A bid at higher priority is accepted
39 //
40 // (3) A bid at equal priority is accepted unless it was received shortly after (within 200msec) of the
41 // last ownership change. This to avoid rapid ownership transitions should multiple participants
42 // bid simultaneously.
43 //
44 // (4) The current owner is the only participant allowed to clear their ownership or adjust priority.
45 //
46 // (5) If an owner does not update the transform or velocities of an owned entity within some period
47 // (5 seconds) then ownership is cleared and the entity's velocities are zeroed. This to handle
48 // the case when an owner drops off the network.
49 //
50 // The priority of a participant's bid depends on how "interested" it is in the entity's motion. The rules
51 // for bidding are as follows:
52 //
53 // (6) A participant (almost) never assumes its bid is accepted by the entity-server. It packs the
54 // simulation owner properties as if they really did change but doesn't actually modify them
55 // locally. Instead it waits to hear back from the entity-server for bid acceptance. If the entity
56 // remains unowned the participant will resend the bid (assuming the bid pakcet was lost). The
57 // exception is when the participant creates a moving entity: it assumes it starts off owning any
58 // moving entities it creates.
59 //
60 // (7) When an entity becomes active in the physics simulation but is not owned the participant will
61 // start a timer and if it is still unowned after expiry (0.5 seconds) the participant will
62 // bid at priority = VOLUNTEER (=2). The entity-server never grants ownership at VOLUNTEER
63 // priority: when a VOLUNTEER bid is accepted the entity-server always promotes the priority to
64 // RECRUIT (=VOLUNTEER + 1); this to avoid a race-condition which might rapidly transition ownership
65 // when multiple participants (with variable ping-times to the server) bid simultaneously for a
66 // recently activated entity.
67 //
68 // (8) When a participant's script changes an entity's transform/velocity the participant will bid at
69 // priority = POKE (=127)
70 //
71 // (9) When an entity collides against MyAvatar the participant will bid at priority = POKE.
72 //
73 // (10) When a participant grabs an entity it will bid at priority = GRAB (=128). This to allow UserA
74 // to whack UserB with a "sword" without losing ownership, since UserB will bid at POKE. If UserB
75 // wants to contest for ownership they must also GRAB it.
76 //
77 // (11) When EntityA, locally owned at priority = N, collides with an unowned EntityB the owner will
78 // also bid for EntityB at priority = N-1 (or VOLUNTEER, whichever is larger).
79 //
80 // (12) When an entity comes to rest and is deactivated in the physics simulation the owner will send
81 // an update to: clear their ownerhsip, set priority to zero, and set the entity's velocities to
82 // zero. As per a normal bid, the owner does NOT assume its ownership has been cleared until
83 // it hears back from the entity-server. Thus, if the packet is lost the owner will re-send after
84 // expiry.
85 //
86 // (13) When an entity is still active but the owner no longer wants to own it, the owner will drop its
87 // priority to YIELD (=1, below VOLUNTEER) thereby signalling to other participants to bid for it.
88 //
89 // (14) When an entity's ownership priority drops to YIELD (=1, below VOLUNTEER) other participants may
90 // bid for it immediately at VOLUNTEER.
91 //
92 /* These declarations temporarily moved to SimulationFlags.h while we unravel some spaghetti dependencies.
93  * The intent is to move them back here once the dust settles.
94 const uint8_t YIELD_SIMULATION_PRIORITY = 1;
95 const uint8_t VOLUNTEER_SIMULATION_PRIORITY = YIELD_SIMULATION_PRIORITY + 1;
96 const uint8_t RECRUIT_SIMULATION_PRIORITY = VOLUNTEER_SIMULATION_PRIORITY + 1;
97 
98 // When poking objects with scripts an observer will bid at SCRIPT_EDIT priority.
99 const uint8_t SCRIPT_GRAB_SIMULATION_PRIORITY = 128;
100 const uint8_t SCRIPT_POKE_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY - 1;
101 
102 // PERSONAL priority (needs a better name) is the level at which a simulation observer owns its own avatar
103 // which really just means: things that collide with it will be bid at a priority level one lower
104 const uint8_t PERSONAL_SIMULATION_PRIORITY = SCRIPT_GRAB_SIMULATION_PRIORITY;
105 const uint8_t AVATAR_ENTITY_SIMULATION_PRIORITY = PERSONAL_SIMULATION_PRIORITY;
106 */
107 
108 
109 class SimulationOwner {
110 public:
111  static const int NUM_BYTES_ENCODED;
112 
113  SimulationOwner();
114  SimulationOwner(const QUuid& id, uint8_t priority);
115  SimulationOwner(const SimulationOwner &) = default;
116 
117  const QUuid& getID() const { return _id; }
118  const uint64_t& getExpiry() const { return _expiry; }
119  uint8_t getPriority() const { return _priority; }
120 
121  QByteArray toByteArray() const;
122  bool fromByteArray(const QByteArray& data);
123 
124  void clear();
125 
126  void setPriority(uint8_t priority);
127 
128  // return true if id is changed
129  bool setID(const QUuid& id);
130  bool set(const QUuid& id, uint8_t priority);
131  bool set(const SimulationOwner& owner);
132 
133  bool isNull() const { return _id.isNull(); }
134  bool matchesValidID(const QUuid& id) const { return _id == id && !_id.isNull(); }
135 
136  void updateExpiry();
137  bool hasExpired() const { return usecTimestampNow() > _expiry; }
138 
139  void clearCurrentOwner();
140 
141  bool operator>=(uint8_t priority) const { return _priority >= priority; }
142  bool operator==(const SimulationOwner& other) { return (_id == other._id && _priority == other._priority); }
143 
144  bool operator!=(const SimulationOwner& other);
145  SimulationOwner& operator=(const SimulationOwner& other);
146 
147  friend QDebug& operator<<(QDebug& d, const SimulationOwner& simOwner);
148 
149  // debug
150  static void test();
151 
152 private:
153  QUuid _id; // owner
154  uint64_t _expiry; // time when ownership can transition at equal priority
155  uint8_t _priority; // priority of current owner
156 };
157 
158 
159 
160 #endif // hifi_SimulationOwner_h