feat(service): added JointsService

This commit is contained in:
maelstrom 2025-04-17 23:38:33 +02:00
parent 0da4d6d67f
commit 86c6890ca1
8 changed files with 102 additions and 24 deletions

View file

@ -42,7 +42,7 @@ public:
bool isSuccess() { return std::holds_alternative<success_state>(value); }
bool isError() { return std::holds_alternative<error_state>(value); }
std::optional<T_Result> success() { return isSuccess() ? std::get<success_state>(value).success : std::nullopt; }
std::optional<T_Result> success() { return isSuccess() ? std::make_optional(std::get<success_state>(value).success) : std::nullopt; }
std::optional<std::variant<T_Errors...>> error() { return isError() ? std::make_optional(std::get<error_state>(value).error) : std::nullopt; }
void logError(Logger::LogLevel logLevel = Logger::LogLevel::ERROR) {

View file

@ -49,7 +49,7 @@ public:
template <typename T>
result<std::shared_ptr<T>, NoSuchService> GetService(std::string name) {
if (services.count(name) != 0)
return services[name];
return std::dynamic_pointer_cast<T>(services[name]);
// TODO: Replace this with a result return type
if (!INSTANCE_MAP[name] || (INSTANCE_MAP[name]->flags ^ (INSTANCE_NOTCREATABLE | INSTANCE_SERVICE)) != 0) {
@ -59,13 +59,13 @@ public:
services[name] = std::dynamic_pointer_cast<Service>(INSTANCE_MAP[name]->constructor());
AddChild(std::dynamic_pointer_cast<Instance>(services[name]));
return services[name];
return std::dynamic_pointer_cast<T>(services[name]);
}
template <typename T>
std::optional<std::shared_ptr<T>> FindService() {
if (services.count(name) != 0)
return services[name];
return std::dynamic_pointer_cast<T>(services[name]);
return std::nullopt;
}

View file

@ -0,0 +1,23 @@
#include "jointsservice.h"
const InstanceType JointsService::TYPE = {
.super = &Instance::TYPE,
.className = "JointsService",
.constructor = &JointsService::Create,
.flags = INSTANCE_NOTCREATABLE | INSTANCE_SERVICE,
};
const InstanceType* JointsService::GetClass() {
return &TYPE;
}
JointsService::JointsService(): Service(&TYPE) {
}
JointsService::~JointsService() = default;
void JointsService::InitService() {
if (initialized) return;
initialized = true;
}

View file

@ -0,0 +1,18 @@
#pragma once
#include "objects/base/service.h"
class JointsService : public Service {
protected:
void InitService() override;
bool initialized = false;
public:
const static InstanceType TYPE;
JointsService();
~JointsService();
static inline std::shared_ptr<Instance> Create() { return std::make_shared<JointsService>(); };
virtual const InstanceType* GetClass() override;
};

View file

@ -1,4 +1,5 @@
#include "meta.h"
#include "objects/jointsservice.h"
#include "objects/part.h"
#include "objects/snap.h"
#include "objects/workspace.h"
@ -9,4 +10,5 @@ std::map<std::string, const InstanceType*> INSTANCE_MAP = {
{ "Workspace", &Workspace::TYPE },
{ "DataModel", &DataModel::TYPE },
{ "Snap", &Snap::TYPE },
{ "JointsService", &JointsService::TYPE },
};

View file

@ -3,6 +3,8 @@
#include "datatypes/cframe.h"
#include "datatypes/ref.h"
#include "datatypes/vector.h"
#include "objects/datamodel.h"
#include "objects/jointsservice.h"
#include "workspace.h"
#include "part.h"
#include <memory>
@ -50,43 +52,67 @@ Snap::Snap(): Instance(&TYPE) {
Snap::~Snap() {
}
void Snap::OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) {
// Remove the existing joint if it does
if (this->joint && oldWorkspace) {
oldWorkspace.value()->physicsWorld->destroyJoint(this->joint);
void Snap::OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) {
// If the old workspace existed, and the new one differs, delete the current joint
if (this->joint && !this->oldWorkspace.expired() && (!workspace() || workspace().value() != this->oldWorkspace.lock())) {
// printf("Broke joint - Removed from workspace\n");
oldJointWorkspace.lock()->physicsWorld->destroyJoint(this->joint);
this->joint = nullptr;
}
buildJoint();
}
// If the previous parent was JointsService, and now it isn't, delete the joint
if (this->joint && !oldParent.expired() && oldParent.lock()->GetClass() == &JointsService::TYPE && (!GetParent() || GetParent() != oldParent.lock())) {
// printf("Broke joint - Removed from JointsService\n");
oldJointWorkspace.lock()->physicsWorld->destroyJoint(this->joint);
this->joint = nullptr;
}
void Snap::OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) {
if (!this->joint) return;
// If the new workspace exists, and the old one differs, create the joint
if (!this->joint && workspace() && (oldWorkspace.expired() || oldWorkspace.lock() != workspace().value())) {
// printf("Made joint - Added to workspace\n");
buildJoint();
}
oldWorkspace->physicsWorld->destroyJoint(this->joint);
this->joint = nullptr;
// If the new parent is JointsService and the previous wasn't, then create the joint
if (!this->joint && GetParent() && GetParent().value()->GetClass() == &JointsService::TYPE && (oldParent.expired() || GetParent() != oldParent.lock())) {
// printf("Made joint - Added to JointsService\n");
buildJoint();
}
this->oldParent = !GetParent() ? std::weak_ptr<Instance>() : GetParent().value();
this->oldWorkspace = !workspace() ? std::weak_ptr<Workspace>() : workspace().value();
this->oldJointWorkspace = !jointWorkspace() ? std::weak_ptr<Workspace>() : jointWorkspace().value();
}
void Snap::onUpdated(std::string property) {
// We are not in the workspace, so we don't really care what values are currently set
if (!workspace()) return;
if (!jointWorkspace()) return;
// Workspace cannot have changed, so if the joint currently exists, it is in the present one
if (this->joint)
workspace().value()->physicsWorld->destroyJoint(this->joint);
jointWorkspace().value()->physicsWorld->destroyJoint(this->joint);
buildJoint();
}
void Snap::buildJoint() {
if (part0.expired() || part1.expired() || !workspace()) return;
if (part0.expired() || part1.expired() || !jointWorkspace()) return;
// Update Part1's rotation and cframe prior to creating the joint as reactphysics3d locks rotation based on how it
// used to be rather than specifying an anchor rotation, so whatever.
Data::CFrame newFrame = part0.lock()->cframe * (c1.Inverse() * c0);
part1.lock()->cframe = newFrame;
workspace().value()->SyncPartPhysics(part1.lock());
jointWorkspace().value()->SyncPartPhysics(part1.lock());
rp::FixedJointInfo jointInfo(part0.lock()->rigidBody, part1.lock()->rigidBody, (c0.Inverse() * c1).Position());
this->joint = dynamic_cast<rp::FixedJoint*>(workspace().value()->physicsWorld->createJoint(jointInfo));
this->joint = dynamic_cast<rp::FixedJoint*>(jointWorkspace().value()->physicsWorld->createJoint(jointInfo));
}
std::optional<std::shared_ptr<Workspace>> Snap::jointWorkspace() {
if (workspace()) return workspace();
if (GetParent() && GetParent().value()->GetClass() == &JointsService::TYPE)
return std::dynamic_pointer_cast<DataModel>(GetParent().value()->GetParent().value())->GetService<Workspace>("Workspace");
return {};
}

View file

@ -5,13 +5,20 @@
#include <optional>
class Part;
class Workspace;
class Snap : public Instance {
rp::FixedJoint* joint = nullptr;
protected:
void OnWorkspaceAdded(std::optional<std::shared_ptr<Workspace>> oldWorkspace, std::shared_ptr<Workspace> newWorkspace) override;
void OnWorkspaceRemoved(std::shared_ptr<Workspace> oldWorkspace) override;
std::weak_ptr<Instance> oldParent;
// The actual workspace the joint is a part of
std::weak_ptr<Workspace> oldWorkspace;
// The pseudo-workspace the joint is a part of (including if parented to JointsService)
std::weak_ptr<Workspace> oldJointWorkspace;
protected:
void OnAncestryChanged(std::optional<std::shared_ptr<Instance>>, std::optional<std::shared_ptr<Instance>>) override;
std::optional<std::shared_ptr<Workspace>> jointWorkspace();
void onUpdated(std::string property);
void buildJoint();
void breakJoint();

View file

@ -2,6 +2,7 @@
#include "./ui_mainwindow.h"
#include "common.h"
#include "logger.h"
#include "objects/jointsservice.h"
#include "objects/snap.h"
#include <map>
#include <memory>
@ -169,7 +170,8 @@ MainWindow::MainWindow(QWidget *parent)
snap->c0 = part1->cframe;
snap->c1 = part0->cframe;
gWorkspace()->AddChild(snap);
// gWorkspace()->AddChild(snap);
gDataModel->GetService<JointsService>("JointsService").expect()->AddChild(snap);
}
void MainWindow::closeEvent(QCloseEvent* evt) {