History

shifting classes around and adding static initializers to resolve dependencies on scripting-engine (and drop dependencies from scripting-engine)

Heather Anderson committed 5 years ago

Commit 665ea521 parent 1f4f45853 files · +457 −404Browse files

Showing the changes to libraries/entities/src/EntityScriptingInterface.cpp (1 of 53 files). Show all

Unified · Split

libraries/entities/src/EntityScriptingInterface.cpp+170−0
@@ -48,6 +48,36 @@ · 47 unmodified lines
48const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";48const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";
49const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";49const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
50 50
51static void staticScriptInitializer(ScriptManager* manager) {
52 auto scriptEngine = manager->engine().data();
53
54 auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
55 entityScriptingInterface->init();
56 auto ifacePtr = entityScriptingInterface.data(); // using this when we don't want to leak a reference
57
58 registerMetaTypes(scriptEngine);
59
60 scriptRegisterMetaType(scriptEngine, EntityPropertyFlagsToScriptValue, EntityPropertyFlagsFromScriptValue);
61 scriptRegisterMetaType(scriptEngine, EntityItemPropertiesToScriptValue, EntityItemPropertiesFromScriptValueHonorReadOnly);
62 scriptRegisterMetaType(scriptEngine, EntityPropertyInfoToScriptValue, EntityPropertyInfoFromScriptValue);
63 scriptRegisterMetaType(scriptEngine, EntityItemIDtoScriptValue, EntityItemIDfromScriptValue);
64 scriptRegisterMetaType(scriptEngine, RayToEntityIntersectionResultToScriptValue, RayToEntityIntersectionResultFromScriptValue);
65
66 scriptEngine->registerGlobalObject("Entities", entityScriptingInterface.data());
67 scriptEngine->registerFunction("Entities", "getMultipleEntityProperties", EntityScriptingInterface::getMultipleEntityProperties);
68
69 // "The return value of QObject::sender() is not valid when the slot is called via a Qt::DirectConnection from a thread
70 // different from this object's thread. Do not use this function in this type of scenario."
71 // so... yay lambdas everywhere to get the sender
72 manager->connect(
73 manager, &ScriptManager::attachDefaultEventHandlers, entityScriptingInterface.data(),
74 [ifacePtr, manager] { ifacePtr->attachDefaultEventHandlers(manager); },
75 Qt::DirectConnection);
76 manager->connect(manager, &ScriptManager::releaseEntityPacketSenderMessages, entityScriptingInterface.data(),
77 &EntityScriptingInterface::releaseEntityPacketSenderMessages, Qt::DirectConnection);
78}
79STATIC_SCRIPT_INITIALIZER(staticScriptInitializer);
80
51EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :81EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
52 _entityTree(nullptr),82 _entityTree(nullptr),
53 _bidOnSimulationOwnership(bidOnSimulationOwnership)83 _bidOnSimulationOwnership(bidOnSimulationOwnership)
@@ -67,6 +97,146 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership · 13 unmodified lines
67 PacketReceiver::makeSourcedListenerReference<EntityScriptingInterface>(this, &EntityScriptingInterface::handleEntityScriptCallMethodPacket));97 PacketReceiver::makeSourcedListenerReference<EntityScriptingInterface>(this, &EntityScriptingInterface::handleEntityScriptCallMethodPacket));
68}98}
69 99
100void EntityScriptingInterface::releaseEntityPacketSenderMessages(bool wait) {
101 EntityEditPacketSender* entityPacketSender = getEntityPacketSender();
102 if (entityPacketSender->serversExist()) {
103 // release the queue of edit entity messages.
104 entityPacketSender->releaseQueuedMessages();
105
106 // since we're in non-threaded mode, call process so that the packets are sent
107 if (!entityPacketSender->isThreaded()) {
108 if (!wait) {
109 entityPacketSender->process();
110 } else {
111 // wait here till the edit packet sender is completely done sending
112 while (entityPacketSender->hasPacketsToSend()) {
113 entityPacketSender->process();
114 QCoreApplication::processEvents();
115 }
116 }
117 } else {
118 // FIXME - do we need to have a similar "wait here" loop for non-threaded packet senders?
119 }
120 }
121}
122
123
124void EntityScriptingInterface::attachDefaultEventHandlers(ScriptManager* manager) {
125 // Connect up ALL the handlers to the global entities object's signals.
126 // (We could go signal by signal, or even handler by handler, but I don't think the efficiency is worth the complexity.)
127
128 // Bug? These handlers are deleted when entityID is deleted, which is nice.
129 // But if they are created by an entity script on a different entity, should they also be deleted when the entity script unloads?
130 // E.g., suppose a bow has an entity script that causes arrows to be created with a potential lifetime greater than the bow,
131 // and that the entity script adds (e.g., collision) handlers to the arrows. Should those handlers fire if the bow is unloaded?
132 // Also, what about when the entity script is REloaded?
133 // For now, we are leaving them around. Changing that would require some non-trivial digging around to find the
134 // handlers that were added while a given currentEntityIdentifier was in place. I don't think this is dangerous. Just perhaps unexpected. -HRS
135 connect(this, &EntityScriptingInterface::deletingEntity, manager,
136 [manager](const EntityItemID& entityID) { manager->removeAllEventHandlers(entityID); });
137
138 // Two common cases of event handler, differing only in argument signature.
139
140 /*@jsdoc
141 * Called when an entity event occurs on an entity as registered with {@link Script.addEventHandler}.
142 * @callback Script~entityEventCallback
143 * @param {Uuid} entityID - The ID of the entity the event has occured on.
144 */
145 using SingleEntityHandler = std::function<void(const EntityItemID&)>;
146 auto makeSingleEntityHandler = [manager](QString eventName) -> SingleEntityHandler {
147 return [manager, eventName](const EntityItemID& entityItemID) {
148 manager->forwardHandlerCall(entityItemID, eventName, { entityItemID.toScriptValue(manager->engine().data()) });
149 };
150 };
151
152 /*@jsdoc
153 * Called when a pointer event occurs on an entity as registered with {@link Script.addEventHandler}.
154 * @callback Script~pointerEventCallback
155 * @param {Uuid} entityID - The ID of the entity the event has occurred on.
156 * @param {PointerEvent} pointerEvent - Details of the event.
157 */
158 using PointerHandler = std::function<void(const EntityItemID&, const PointerEvent&)>;
159 auto makePointerHandler = [manager](QString eventName) -> PointerHandler {
160 return [manager, eventName](const EntityItemID& entityItemID, const PointerEvent& event) {
161 if (!EntityTree::areEntityClicksCaptured()) {
162 ScriptEngine* engine = manager->engine().data();
163 manager->forwardHandlerCall(entityItemID, eventName,
164 { entityItemID.toScriptValue(engine), event.toScriptValue(engine) });
165 }
166 };
167 };
168
169 /*@jsdoc
170 * Called when a collision event occurs on an entity as registered with {@link Script.addEventHandler}.
171 * @callback Script~collisionEventCallback
172 * @param {Uuid} entityA - The ID of one entity in the collision.
173 * @param {Uuid} entityB - The ID of the other entity in the collision.
174 * @param {Collision} collisionEvent - Details of the collision.
175 */
176 using CollisionHandler = std::function<void(const EntityItemID&, const EntityItemID&, const Collision&)>;
177 auto makeCollisionHandler = [manager](QString eventName) -> CollisionHandler {
178 return [manager, eventName](const EntityItemID& idA, const EntityItemID& idB, const Collision& collision) {
179 ScriptEngine* engine = manager->engine().data();
180 manager->forwardHandlerCall(idA, eventName,
181 { idA.toScriptValue(engine), idB.toScriptValue(engine),
182 collisionToScriptValue(engine, collision) });
183 };
184 };
185
186 /*@jsdoc
187 * <p>The name of an entity event. When the entity event occurs, any function that has been registered for that event
188 * via {@link Script.addEventHandler} is called with parameters per the entity event.</p>
189 * <table>
190 * <thead>
191 * <tr><th>Event Name</th><th>Callback Type</th><th>Entity Event</th></tr>
192 * </thead>
193 * <tbody>
194 * <tr><td><code>"enterEntity"</code></td><td>{@link Script~entityEventCallback|entityEventCallback}</td>
195 * <td>{@link Entities.enterEntity}</td></tr>
196 * <tr><td><code>"leaveEntity"</code></td><td>{@link Script~entityEventCallback|entityEventCallback}</td>
197 * <td>{@link Entities.leaveEntity}</td></tr>
198 * <tr><td><code>"mousePressOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
199 * <td>{@link Entities.mousePressOnEntity}</td></tr>
200 * <tr><td><code>"mouseMoveOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
201 * <td>{@link Entities.mouseMoveOnEntity}</td></tr>
202 * <tr><td><code>"mouseReleaseOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
203 * <td>{@link Entities.mouseReleaseOnEntity}</td></tr>
204 * <tr><td><code>"clickDownOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
205 * <td>{@link Entities.clickDownOnEntity}</td></tr>
206 * <tr><td><code>"holdingClickOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
207 * <td>{@link Entities.holdingClickOnEntity}</td></tr>
208 * <tr><td><code>"clickReleaseOnEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
209 * <td>{@link Entities.clickReleaseOnEntity}</td></tr>
210 * <tr><td><code>"hoverEnterEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
211 * <td>{@link Entities.hoverEnterEntity}</td></tr>
212 * <tr><td><code>"hoverOverEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
213 * <td>{@link Entities.hoverOverEntity}</td></tr>
214 * <tr><td><code>"hoverLeaveEntity"</code></td><td>{@link Script~pointerEventCallback|pointerEventCallback}</td>
215 * <td>{@link Entities.hoverLeaveEntity}</td></tr>
216 * <tr><td><code>"collisionWithEntity"</code><td>{@link Script~collisionEventCallback|collisionEventCallback}</td>
217 * </td><td>{@link Entities.collisionWithEntity}</td></tr>
218 * </tbody>
219 * </table>
220 * @typedef {string} Script.EntityEvent
221 */
222 connect(this, &EntityScriptingInterface::enterEntity, manager, makeSingleEntityHandler("enterEntity"));
223 connect(this, &EntityScriptingInterface::leaveEntity, manager, makeSingleEntityHandler("leaveEntity"));
224
225 connect(this, &EntityScriptingInterface::mousePressOnEntity, manager, makePointerHandler("mousePressOnEntity"));
226 connect(this, &EntityScriptingInterface::mouseMoveOnEntity, manager, makePointerHandler("mouseMoveOnEntity"));
227 connect(this, &EntityScriptingInterface::mouseReleaseOnEntity, manager, makePointerHandler("mouseReleaseOnEntity"));
228
229 connect(this, &EntityScriptingInterface::clickDownOnEntity, manager, makePointerHandler("clickDownOnEntity"));
230 connect(this, &EntityScriptingInterface::holdingClickOnEntity, manager, makePointerHandler("holdingClickOnEntity"));
231 connect(this, &EntityScriptingInterface::clickReleaseOnEntity, manager, makePointerHandler("clickReleaseOnEntity"));
232
233 connect(this, &EntityScriptingInterface::hoverEnterEntity, manager, makePointerHandler("hoverEnterEntity"));
234 connect(this, &EntityScriptingInterface::hoverOverEntity, manager, makePointerHandler("hoverOverEntity"));
235 connect(this, &EntityScriptingInterface::hoverLeaveEntity, manager, makePointerHandler("hoverLeaveEntity"));
236
237 connect(this, &EntityScriptingInterface::collisionWithEntity, manager, makeCollisionHandler("collisionWithEntity"));
238}
239
70void EntityScriptingInterface::queueEntityMessage(PacketType packetType,240void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
71 EntityItemID entityID, const EntityItemProperties& properties) {241 EntityItemID entityID, const EntityItemProperties& properties) {
72 getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);242 getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);