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
4848 const QString GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":true}}";
4949 const QString NOT_GRABBABLE_USER_DATA = "{\"grabbableKey\":{\"grabbable\":false}}";
5050
51+static 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+}
79+STATIC_SCRIPT_INITIALIZER(staticScriptInitializer);
80+
5181 EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership) :
5282 _entityTree(nullptr),
5383 _bidOnSimulationOwnership(bidOnSimulationOwnership)
@@ -67,6 +97,146 @@ EntityScriptingInterface::EntityScriptingInterface(bool bidOnSimulationOwnership · 13 unmodified lines
6797 PacketReceiver::makeSourcedListenerReference<EntityScriptingInterface>(this, &EntityScriptingInterface::handleEntityScriptCallMethodPacket));
6898 }
6999
100+void 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+
124+void 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+
70240 void EntityScriptingInterface::queueEntityMessage(PacketType packetType,
71241 EntityItemID entityID, const EntityItemProperties& properties) {
72242 getEntityPacketSender()->queueEditEntityMessage(packetType, _entityTree, entityID, properties);