fix(physics): prevent double-joining

This commit is contained in:
maelstrom 2025-04-23 15:15:58 +02:00
parent e35c895233
commit 587629fcdd
3 changed files with 30 additions and 7 deletions

View file

@ -259,6 +259,26 @@ SurfaceType Part::surfaceFromFace(NormalId face) {
return SurfaceSmooth; // Unreachable
}
bool Part::checkJointContinuinty(std::shared_ptr<Part> otherPart) {
// Make sure that the two parts don't depend on one another
if (shared<Part>() == otherPart) return false;
for (auto joint : primaryJoints) {
if (joint.expired() || joint.lock()->part1.expired()) continue;
if (!joint.lock()->part1.lock()->checkJointContinuinty(otherPart))
return false;
}
for (auto joint : secondaryJoints) {
if (joint.expired() || joint.lock()->part0.expired()) continue;
if (!joint.lock()->part0.lock()->checkJointContinuinty(otherPart))
return false;
}
return true;
}
void Part::MakeJoints() {
// Algorithm: Find nearby parts
// Make sure parts are not dependant on each other (via primary/secondaryJoints)
@ -290,6 +310,7 @@ void Part::MakeJoints() {
float dot = myWorldNormal.Dot(otherWorldNormal);
if (dot > -0.99) continue; // Surface is pointing opposite to ours
if (abs(surfacePointLocalToMyFrame.Z()) > 0.05) continue; // Surfaces are within 0.05 studs of one another
if (!checkJointContinuinty(otherPart)) continue;
SurfaceType mySurface = surfaceFromFace(faceFromNormal(myFace));
SurfaceType otherSurface = surfaceFromFace(faceFromNormal(otherFace));
@ -307,7 +328,7 @@ void Part::MakeJoints() {
dataModel().value()->GetService<JointsService>()->AddChild(joint);
joint->UpdateProperty("Part0");
printf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str());
Logger::debugf("Made joint between %s and %s!\n", name.c_str(), otherPart->name.c_str());
}
}
}

View file

@ -37,6 +37,7 @@ protected:
void untrackJoint(std::shared_ptr<Snap>);
SurfaceType surfaceFromFace(NormalId);
bool checkJointContinuinty(std::shared_ptr<Part>);
friend Snap;

View file

@ -368,18 +368,18 @@ void MainWindow::connectActionHandlers() {
connect(ui->actionSave, &QAction::triggered, this, [&]() {
std::optional<std::string> path;
if (!gDataModel->HasFile())
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + gDataModel->name));
if (!gDataModel->HasFile() && (!path || path == "")) return;
if (!editModeDataModel->HasFile())
path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save " + editModeDataModel->name));
if (!editModeDataModel->HasFile() && (!path || path == "")) return;
gDataModel->SaveToFile(path);
editModeDataModel->SaveToFile(path);
});
connect(ui->actionSaveAs, &QAction::triggered, this, [&]() {
std::optional<std::string> path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save as " + gDataModel->name));
std::optional<std::string> path = openFileDialog("Openblocks Level (*.obl)", ".obl", QFileDialog::AcceptSave, QString::fromStdString("Save as " + editModeDataModel->name));
if (!path || path == "") return;
gDataModel->SaveToFile(path);
editModeDataModel->SaveToFile(path);
});
connect(ui->actionOpen, &QAction::triggered, this, [&]() {
@ -391,6 +391,7 @@ void MainWindow::connectActionHandlers() {
// simulationInit();
std::shared_ptr<DataModel> newModel = DataModel::LoadFromFile(path.value());
editModeDataModel = newModel;
gDataModel = newModel;
newModel->Init();
ui->explorerView->updateRoot(newModel);