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,25 +29,27 @@ Workspace::~Workspace() {
|
|||
PhysicsEventListener::PhysicsEventListener(Workspace* parent) : workspace(parent) {}
|
||||
|
||||
void PhysicsEventListener::onContact(const rp::CollisionCallback::CallbackData& data) {
|
||||
workspace->contactQueueLock.lock();
|
||||
for (size_t i = 0; i < data.getNbContactPairs(); i++) {
|
||||
auto pair = data.getContactPair(i);
|
||||
auto type = pair.getEventType();
|
||||
if (type == rp::CollisionCallback::ContactPair::EventType::ContactStay) continue;
|
||||
|
||||
auto part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
||||
auto part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
||||
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStay)
|
||||
continue;
|
||||
|
||||
if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart) {
|
||||
part0->Touched->Fire({ (Variant)InstanceRef(part1) });
|
||||
part1->Touched->Fire({ (Variant)InstanceRef(part0) });
|
||||
} else if (type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactExit) {
|
||||
part0->TouchEnded->Fire({ (Variant)InstanceRef(part1) });
|
||||
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||
}
|
||||
ContactItem contact;
|
||||
contact.part0 = reinterpret_cast<Part*>(pair.getBody1()->getUserData())->shared<Part>();
|
||||
contact.part1 = reinterpret_cast<Part*>(pair.getBody2()->getUserData())->shared<Part>();
|
||||
contact.action = type == reactphysics3d::CollisionCallback::ContactPair::EventType::ContactStart ? ContactItem::CONTACTITEM_TOUCHED : ContactItem::CONTACTITEM_TOUCHENDED;
|
||||
|
||||
workspace->contactQueue.push(contact);
|
||||
}
|
||||
workspace->contactQueueLock.unlock();
|
||||
}
|
||||
|
||||
void PhysicsEventListener::onTrigger(const rp::OverlapCallback::CallbackData& data) {
|
||||
workspace->contactQueueLock.lock();
|
||||
for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
||||
auto pair = data.getOverlappingPair(i);
|
||||
auto type = pair.getEventType();
|
||||
|
@ -64,6 +66,7 @@ for (size_t i = 0; i < data.getNbOverlappingPairs(); i++) {
|
|||
part1->TouchEnded->Fire({ (Variant)InstanceRef(part0) });
|
||||
}
|
||||
}
|
||||
workspace->contactQueueLock.unlock();
|
||||
}
|
||||
|
||||
void Workspace::InitService() {
|
||||
|
@ -143,6 +146,22 @@ void Workspace::updatePartPhysics(std::shared_ptr<Part> 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) {
|
||||
if (globalPhysicsLock.try_lock()) {
|
||||
updatePartPhysics(part);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <reactphysics3d/body/RigidBody.h>
|
||||
#include <reactphysics3d/engine/EventListener.h>
|
||||
#include <reactphysics3d/engine/PhysicsCommon.h>
|
||||
|
@ -52,6 +53,15 @@ struct QueueItem {
|
|||
} action;
|
||||
};
|
||||
|
||||
struct ContactItem {
|
||||
std::shared_ptr<Part> part0;
|
||||
std::shared_ptr<Part> part1;
|
||||
enum {
|
||||
CONTACTITEM_TOUCHED,
|
||||
CONTACTITEM_TOUCHENDED,
|
||||
} action;
|
||||
};
|
||||
|
||||
class Workspace;
|
||||
class PhysicsEventListener : public rp::EventListener {
|
||||
friend Workspace;
|
||||
|
@ -66,8 +76,12 @@ class PhysicsEventListener : public rp::EventListener {
|
|||
class DEF_INST_SERVICE_(explorer_icon="workspace") Workspace : public Service {
|
||||
AUTOGEN_PREAMBLE
|
||||
|
||||
friend PhysicsEventListener;
|
||||
|
||||
std::list<std::shared_ptr<Part>> simulatedBodies;
|
||||
std::list<QueueItem> bodyQueue;
|
||||
std::queue<ContactItem> contactQueue;
|
||||
std::mutex contactQueueLock;
|
||||
rp::PhysicsWorld* physicsWorld;
|
||||
static rp::PhysicsCommon* physicsCommon;
|
||||
PhysicsEventListener physicsEventListener;
|
||||
|
@ -97,6 +111,7 @@ public:
|
|||
rp::Joint* CreateJoint(const rp::JointInfo& jointInfo);
|
||||
void DestroyJoint(rp::Joint* joint);
|
||||
|
||||
void ProcessContactEvents();
|
||||
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);
|
||||
};
|
|
@ -140,6 +140,7 @@ void PlaceDocument::timerEvent(QTimerEvent* evt) {
|
|||
placeWidget->repaint();
|
||||
placeWidget->updateCycle();
|
||||
gDataModel->GetService<ScriptContext>()->RunSleepingThreads();
|
||||
gDataModel->GetService<Workspace>()->ProcessContactEvents();
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue