fix(workspace): do not fire signals from physics thread as lua has to always be executed from main thread
This commit is contained in:
parent
0ded4ac7fb
commit
dca5c483c4
3 changed files with 45 additions and 10 deletions
|
@ -29,26 +29,28 @@ Workspace::~Workspace() {
|
||||||
PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {}
|
PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {}
|
||||||
|
|
||||||
void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) {
|
void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) {
|
||||||
|
workspace->contactQueueLock.lock();
|
||||||
for (size_t i = 0; i < data.getNbContactPairs(); i++) {
|
for (size_t i = 0; i < data.getNbContactPairs(); i++) {
|
||||||
auto pair = data.getContactPair(i);
|
auto pair = data.getContactPair(i);
|
||||||
auto type = pair.getEventType();
|
auto type = pair.getEventType();
|
||||||
if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue;
|
if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue;
|
||||||
|
|
||||||
auto part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStay)
|
||||||
auto part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
continue;
|
||||||
|
|
||||||
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart) {
|
ContactItem contact;
|
||||||
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
|
contact.part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
||||||
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
|
contact.part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
||||||
} else if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactExit) {
|
contact.action = type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart ? ContactItem::CONTACTITEM_TOUCHED : ContactItem::CONTACTITEM_TOUCHENDED;
|
||||||
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
|
|
||||||
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
workspace->contactQueue.push(contact);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
workspace->contactQueueLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PhysicsEventListener::onTrigger(const rp::OverlapCallback::CallbackData& data) {
|
void PhysicsEventListener::onTrigger(const rp::OverlapCallback::CallbackData& data) {
|
||||||
for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
workspace->contactQueueLock.lock();
|
||||||
|
for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
||||||
auto pair = data.getOverlappingPair(i);
|
auto pair = data.getOverlappingPair(i);
|
||||||
auto type = pair.getEventType();
|
auto type = pair.getEventType();
|
||||||
if (type == rp::OverlapCallback::OverlapPair::EventType::OverlapStay) continue;
|
if (type == rp::OverlapCallback::OverlapPair::EventType::OverlapStay) continue;
|
||||||
|
@ -64,6 +66,7 @@ for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
||||||
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
workspace->contactQueueLock.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Workspace::InitService() {
|
void Workspace::InitService() {
|
||||||
|
@ -143,6 +146,22 @@ void Workspace::updatePartPhysics(std::shared_ptr<Part> part) {
|
||||||
part->rigidBody->setUserData(&*part);
|
part->rigidBody->setUserData(&*part);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Workspace::ProcessContactEvents() {
|
||||||
|
contactQueueLock.lock();
|
||||||
|
while (!contactQueue.empty()) {
|
||||||
|
ContactItem& contact = contactQueue.front();
|
||||||
|
contactQueue.pop();
|
||||||
|
if (contact.action == ContactItem::CONTACTITEM_TOUCHED) {
|
||||||
|
contact.part0->Touched->Fire({ (Variant)InstanceRef(contact.part1) });
|
||||||
|
contact.part1->Touched->Fire({ (Variant)InstanceRef(contact.part0) });
|
||||||
|
} else if (contact.action == ContactItem::CONTACTITEM_TOUCHENDED) {
|
||||||
|
contact.part0->TouchEnded->Fire({ (Variant)InstanceRef(contact.part1) });
|
||||||
|
contact.part1->TouchEnded->Fire({ (Variant)InstanceRef(contact.part0) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contactQueueLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void Workspace::SyncPartPhysics(std::shared_ptr<Part> part) {
|
void Workspace::SyncPartPhysics(std::shared_ptr<Part> part) {
|
||||||
if (globalPhysicsLock.try_lock()) {
|
if (globalPhysicsLock.try_lock()) {
|
||||||
updatePartPhysics(part);
|
updatePartPhysics(part);
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <queue>
|
||||||
#include <reactphysics3d/body/RigidBody.h>
|
#include <reactphysics3d/body/RigidBody.h>
|
||||||
#include <reactphysics3d/engine/EventListener.h>
|
#include <reactphysics3d/engine/EventListener.h>
|
||||||
#include <reactphysics3d/engine/PhysicsCommon.h>
|
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||||
|
@ -52,6 +53,15 @@ struct QueueItem {
|
||||||
} action;
|
} action;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ContactItem {
|
||||||
|
std::shared_ptr<Part> part0;
|
||||||
|
std::shared_ptr<Part> part1;
|
||||||
|
enum {
|
||||||
|
CONTACTITEM_TOUCHED,
|
||||||
|
CONTACTITEM_TOUCHENDED,
|
||||||
|
} action;
|
||||||
|
};
|
||||||
|
|
||||||
class Workspace;
|
class Workspace;
|
||||||
class PhysicsEventListener : public rp::EventListener {
|
class PhysicsEventListener : public rp::EventListener {
|
||||||
friend Workspace;
|
friend Workspace;
|
||||||
|
@ -66,8 +76,12 @@ class PhysicsEventListener : public rp::EventListener {
|
||||||
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||||
AUTOGEN_PREAMBLE
|
AUTOGEN_PREAMBLE
|
||||||
|
|
||||||
|
friend PhysicsEventListener;
|
||||||
|
|
||||||
std::list<std::shared_ptr<Part>> simulatedBodies;
|
std::list<std::shared_ptr<Part>> simulatedBodies;
|
||||||
std::list<QueueItem> bodyQueue;
|
std::list<QueueItem> bodyQueue;
|
||||||
|
std::queue<ContactItem> contactQueue;
|
||||||
|
std::mutex contactQueueLock;
|
||||||
rp::PhysicsWorld* physicsWorld;
|
rp::PhysicsWorld* physicsWorld;
|
||||||
static rp::PhysicsCommon* physicsCommon;
|
static rp::PhysicsCommon* physicsCommon;
|
||||||
PhysicsEventListener physicsEventListener;
|
PhysicsEventListener physicsEventListener;
|
||||||
|
@ -97,6 +111,7 @@ public:
|
||||||
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
||||||
void DestroyJoint(rp::Joint* joint);
|
void DestroyJoint(rp::Joint* joint);
|
||||||
|
|
||||||
|
void ProcessContactEvents();
|
||||||
void PhysicsStep(float deltaTime);
|
void PhysicsStep(float deltaTime);
|
||||||
std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF);
|
std::optional<const RaycastResult> CastRayNearest(glm::vec3 point, glm::vec3 rotation, float maxLength, std::optional<RaycastFilter> filter = std::nullopt, unsigned short categoryMaskBits = 0xFFFF);
|
||||||
};
|
};
|
|
@ -140,6 +140,7 @@ void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
||||||
placeWidget->repaint();
|
placeWidget->repaint();
|
||||||
placeWidget->updateCycle();
|
placeWidget->updateCycle();
|
||||||
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
||||||
|
gDataModel->GetService<Workspace>()->ProcessContactEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue