8#include <simplesquirrel/simplesquirrel.hpp>
19constexpr auto kRopeCreateSchemaId =
"physics:rope3d-create";
22 std::optional<double>
minimum = {}, std::optional<double>
maximum = {},
23 std::string defaultJson = {}) {
30 field.defaultJson = std::move(defaultJson);
37 schema.
id = kRopeCreateSchemaId;
39 schema.
title =
"3D Rope Creation Parameters";
40 schema.
description =
"Validated construction and initial solver settings for Rope3D.";
43 ropeField(
"particleCount", ValueType::Integer,
true, 2, 100000),
44 ropeField(
"startX", ValueType::Number,
true),
45 ropeField(
"startY", ValueType::Number,
true),
46 ropeField(
"startZ", ValueType::Number,
true),
47 ropeField(
"endX", ValueType::Number,
true),
48 ropeField(
"endY", ValueType::Number,
true),
49 ropeField(
"endZ", ValueType::Number,
true),
50 ropeField(
"gravityX", ValueType::Number,
false, {}, {},
"0"),
51 ropeField(
"gravityY", ValueType::Number,
false, {}, {},
"-9.81"),
52 ropeField(
"gravityZ", ValueType::Number,
false, {}, {},
"0"),
53 ropeField(
"stretchCompliance", ValueType::Number,
false, 0, {},
"0"),
54 ropeField(
"distanceConstraintsEnabled", ValueType::Boolean,
false, {}, {},
"true"),
55 ropeField(
"bendCompliance", ValueType::Number,
false, 0, {},
"0.002"),
56 ropeField(
"bendConstraintsEnabled", ValueType::Boolean,
false, {}, {},
"true"),
57 ropeField(
"maxBending", ValueType::Number,
false, 0, 0.5,
"0.025"),
58 ropeField(
"plasticYield", ValueType::Number,
false, 0, 0.5,
"0"),
59 ropeField(
"plasticCreep", ValueType::Number,
false, 0, {},
"0"),
60 ropeField(
"maxCompression", ValueType::Number,
false, 0, 1,
"0"),
61 ropeField(
"damping", ValueType::Number,
false, 0, 1,
"0.01"),
62 ropeField(
"particleMass", ValueType::Number,
false, 0.000001, {},
"0.1"),
63 ropeField(
"radius", ValueType::Number,
false, 0.000001, {},
"0.04"),
64 ropeField(
"collisionFriction", ValueType::Number,
false, 0, 1,
"0"),
65 ropeField(
"collisionRestitution", ValueType::Number,
false, 0, 1,
"0"),
66 ropeField(
"continuousCollision", ValueType::Boolean,
false, {}, {},
"true"),
67 ropeField(
"selfCollision", ValueType::Boolean,
false, {}, {},
"true"),
68 ropeField(
"pinStart", ValueType::Boolean,
false, {}, {},
"false"),
69 ropeField(
"pinEnd", ValueType::Boolean,
false, {}, {},
"false"),
70 ropeField(
"tearingEnabled", ValueType::Boolean,
false, {}, {},
"false"),
71 ropeField(
"tearResistance", ValueType::Number,
false, 0.000001, {},
"1000"),
72 ropeField(
"maxTearsPerStep", ValueType::Integer,
false, 1, 1000,
"1"),
87 throw Exception(
"Rope3D.%s: %s",
operation, diagnostic ? diagnostic->message().c_str() :
"operation failed");
93 throw Exception(
"Rope3D.%s: %s",
operation, diagnostic ? diagnostic->message().c_str() :
"operation failed");
97 if (result.
ok())
return static_cast<std::int64_t
>(result.
value().value);
99 throw Exception(
"Rope3D.%s: %s",
operation, diagnostic ? diagnostic->message().c_str() :
"operation failed");
120 "physics.rope3d.create-schema"));
121 std::string parseError;
123 if (!document.valid())
127 "physics.rope3d.create-schema"));
128 const auto root = document.root();
130 auto rope = std::make_unique<Rope3D>(
root.getInt(
"particleCount"),
root.getFloat(
"startX"),
131 root.getFloat(
"startY"),
root.getFloat(
"startZ"),
root.getFloat(
"endX"),
132 root.getFloat(
"endY"),
root.getFloat(
"endZ"));
133 rope->setGravity(
root.getFloat(
"gravityX", 0.f),
root.getFloat(
"gravityY", -9.81f),
134 root.getFloat(
"gravityZ", 0.f));
135 rope->setStretchCompliance(
root.getFloat(
"stretchCompliance", 0.f));
136 rope->setDistanceConstraintsEnabled(
root.getBool(
"distanceConstraintsEnabled",
true));
137 rope->setBendCompliance(
root.getFloat(
"bendCompliance", 0.002f));
138 rope->setBendConstraintsEnabled(
root.getBool(
"bendConstraintsEnabled",
true));
139 rope->setMaxBending(
root.getFloat(
"maxBending", 0.025f));
140 rope->setPlasticity(
root.getFloat(
"plasticYield", 0.f),
root.getFloat(
"plasticCreep", 0.f));
141 rope->setMaxCompression(
root.getFloat(
"maxCompression", 0.f));
142 rope->setDamping(
root.getFloat(
"damping", 0.01f));
143 rope->setParticleMass(
root.getFloat(
"particleMass", 0.1f));
144 rope->setRadius(
root.getFloat(
"radius", 0.04f));
145 rope->setCollisionFriction(
root.getFloat(
"collisionFriction", 0.f));
146 rope->setCollisionRestitution(
root.getFloat(
"collisionRestitution", 0.f));
147 rope->setContinuousCollision(
root.getBool(
"continuousCollision",
true));
148 rope->setSelfCollision(
root.getBool(
"selfCollision",
true));
149 if (
root.getBool(
"pinStart",
false)) {
150 auto pinned = rope->pin(0);
153 if (
root.getBool(
"pinEnd",
false)) {
154 auto pinned = rope->pin(rope->getParticleCount() - 1);
157 if (
root.getBool(
"tearingEnabled",
false))
158 rope->setTearing(
root.getFloat(
"tearResistance", 1000.f),
root.getInt(
"maxTearsPerStep", 1));
160 }
catch (
const std::exception& exception) {
164 "physics.rope3d.create-schema"));
168Rope3D* Rope::newRope3DFromJsonScript(
const std::string& json) {
169 auto created = newRope3DFromJson(json);
171 const auto* diagnostic =
created.status().primaryDiagnostic();
172 throw Exception(
"Rope.newRope3DFromJson: %s", diagnostic ? diagnostic->message().c_str() :
"creation failed");
175void Rope::expose(ssq::Table& table) {
176 auto cls = table.addClass(
name, Rope::create,
false);
178 auto rope = table.addClass<
Rope3D>(
"Rope3D", std::function<Rope3D*()>([]() ->
Rope3D* {
return nullptr; }),
true);
179 rope.addFunc(
"update", &Rope3D::update);
180 rope.addFunc(
"setGravity", &Rope3D::setGravity);
181 rope.addFunc(
"getGravityX", &Rope3D::getGravityX);
182 rope.addFunc(
"getGravityY", &Rope3D::getGravityY);
183 rope.addFunc(
"getGravityZ", &Rope3D::getGravityZ);
184 rope.addFunc(
"setStretchCompliance", &Rope3D::setStretchCompliance);
185 rope.addFunc(
"setDistanceConstraintsEnabled", &Rope3D::setDistanceConstraintsEnabled);
186 rope.addFunc(
"getDistanceConstraintsEnabled", [](Rope3D* self) {
return self->getDistanceConstraintsEnabled(); });
187 rope.addFunc(
"setBendCompliance", &Rope3D::setBendCompliance);
188 rope.addFunc(
"setBendConstraintsEnabled", &Rope3D::setBendConstraintsEnabled);
189 rope.addFunc(
"getBendConstraintsEnabled", [](Rope3D* self) {
return self->getBendConstraintsEnabled(); });
190 rope.addFunc(
"setMaxBending", &Rope3D::setMaxBending);
191 rope.addFunc(
"getMaxBending", [](Rope3D* self) {
return self->getMaxBending(); });
192 rope.addFunc(
"setPlasticity", &Rope3D::setPlasticity);
193 rope.addFunc(
"getPlasticYield", [](Rope3D* self) {
return self->getPlasticYield(); });
194 rope.addFunc(
"getPlasticCreep", [](Rope3D* self) {
return self->getPlasticCreep(); });
195 rope.addFunc(
"getBendPlasticity", &Rope3D::getBendPlasticity);
196 rope.addFunc(
"setMaxCompression", &Rope3D::setMaxCompression);
197 rope.addFunc(
"setDamping", &Rope3D::setDamping);
198 rope.addFunc(
"getDamping", &Rope3D::getDamping);
199 rope.addFunc(
"setParticleMass", &Rope3D::setParticleMass);
200 rope.addFunc(
"getParticleMass", &Rope3D::getParticleMass);
201 rope.addFunc(
"setRadius", &Rope3D::setRadius);
202 rope.addFunc(
"getRadius", &Rope3D::getRadius);
203 rope.addFunc(
"setCollisionFriction", &Rope3D::setCollisionFriction);
204 rope.addFunc(
"getCollisionFriction", [](Rope3D* self) {
return self->getCollisionFriction(); });
205 rope.addFunc(
"setCollisionRestitution", &Rope3D::setCollisionRestitution);
206 rope.addFunc(
"getCollisionRestitution", [](Rope3D* self) {
return self->getCollisionRestitution(); });
207 rope.addFunc(
"setContinuousCollision", &Rope3D::setContinuousCollision);
208 rope.addFunc(
"getContinuousCollision", [](Rope3D* self) {
return self->getContinuousCollision(); });
209 rope.addFunc(
"setCollideWorld", &Rope3D::setCollideWorld);
210 rope.addFunc(
"getCollideWorld", [](Rope3D* self) {
return self->getCollideWorld(); });
211 rope.addFunc(
"setCollideSdf", &Rope3D::setCollideSdf);
212 rope.addFunc(
"getCollideSdf", [](Rope3D* self) {
return self->getCollideSdf(); });
213 rope.addFunc(
"clearColliders", &Rope3D::clearColliders);
214 rope.addFunc(
"setSelfCollision", &Rope3D::setSelfCollision);
215 rope.addFunc(
"getSelfCollision", &Rope3D::getSelfCollision);
216 rope.addFunc(
"setBounds", &Rope3D::setBounds);
217 rope.addFunc(
"clearBounds", &Rope3D::clearBounds);
218 rope.addFunc(
"isAttached", &Rope3D::isAttached);
219 rope.addFunc(
"applyForce", &Rope3D::applyForce);
220 rope.addFunc(
"getRestLength", &Rope3D::getRestLength);
221 rope.addFunc(
"calculateLength", &Rope3D::calculateLength);
222 rope.addFunc(
"isElementActive", &Rope3D::isElementActive);
223 rope.addFunc(
"getElementForce", &Rope3D::getElementForce);
224 rope.addFunc(
"getTopologyRevision", [](Rope3D* self) {
return self->getTopologyRevision(); });
225 rope.addFunc(
"getLastTornElementCount", [](Rope3D* self) {
return self->getLastTornElementCount(); });
226 rope.addFunc(
"getLastTornElement", &Rope3D::getLastTornElement);
227 rope.addFunc(
"setTearing", &Rope3D::setTearing);
228 rope.addFunc(
"disableTearing", &Rope3D::disableTearing);
229 rope.addFunc(
"getParticleCount", &Rope3D::getParticleCount);
230 rope.addFunc(
"getParticleX", &Rope3D::getParticleX);
231 rope.addFunc(
"getParticleY", &Rope3D::getParticleY);
232 rope.addFunc(
"getParticleZ", &Rope3D::getParticleZ);
233 rope.addFunc(
"getSampleX", &Rope3D::getSampleX);
234 rope.addFunc(
"getSampleY", &Rope3D::getSampleY);
235 rope.addFunc(
"getSampleZ", &Rope3D::getSampleZ);
236 rope.addFunc(
"getSampleTangentX", &Rope3D::getSampleTangentX);
237 rope.addFunc(
"getSampleTangentY", &Rope3D::getSampleTangentY);
238 rope.addFunc(
"getSampleTangentZ", &Rope3D::getSampleTangentZ);
239 rope.addFunc(
"addSphereCollider", [](Rope3D* self,
float x,
float y,
float z,
float radius) {
240 return ropeColliderIdOrThrow(self->addSphereCollider(
x,
y,
z,
radius),
"addSphereCollider");
242 rope.addFunc(
"addPlaneCollider", [](Rope3D* self,
float x,
float y,
float z,
float nx,
float ny,
float nz) {
243 return ropeColliderIdOrThrow(self->addPlaneCollider(
x,
y,
z,
nx,
ny,
nz),
"addPlaneCollider");
245 rope.addFunc(
"moveSphereCollider", [](Rope3D* self, std::int64_t
id,
float x,
float y,
float z) {
246 return ropeColliderChangeOrThrow(
247 self->moveSphereCollider(RopeColliderId{static_cast<std::uint64_t>(id)},
x,
y,
z),
"moveSphereCollider");
249 rope.addFunc(
"removeCollider", [](Rope3D* self, std::int64_t
id) {
250 return ropeColliderChangeOrThrow(self->removeCollider(RopeColliderId{static_cast<std::uint64_t>(id)}),
253 rope.addFunc(
"pin", [](Rope3D* self,
int index) {
return ropeChangeOrThrow(self->pin(
index),
"pin"); });
254 rope.addFunc(
"attach", [](Rope3D* self,
int index,
float x,
float y,
float z) {
255 return ropeChangeOrThrow(self->attach(
index,
x,
y,
z),
"attach");
257 rope.addFunc(
"moveAttachment", [](Rope3D* self,
int index,
float x,
float y,
float z) {
258 return ropeChangeOrThrow(self->moveAttachment(
index,
x,
y,
z),
"moveAttachment");
260 rope.addFunc(
"detach", [](Rope3D* self,
int index) {
return ropeChangeOrThrow(self->detach(
index),
"detach"); });
261 rope.addFunc(
"cut", [](Rope3D* self,
int index) {
return ropeChangeOrThrow(self->cut(
index),
"cut"); });
262 rope.addFunc(
"repair", [](Rope3D* self,
int index) {
return ropeChangeOrThrow(self->repair(
index),
"repair"); });
263 rope.addFunc(
"setRestLength", [](Rope3D* self,
float length) {
264 return ropeChangeOrThrow(self->setRestLength(
length),
"setRestLength");
266 rope.addFunc(
"changeLength", [](Rope3D* self,
float length,
float spacing,
bool fromEnd) {
267 return ropeChangeOrThrow(self->changeLength(
length,
spacing, fromEnd),
"changeLength");
271void Rope::expose(ssq::Class&
cls) {
272 cls.addFunc(
"getName", &Rope::getName);
273 cls.addFunc(
"newRope3D", &Rope::newRope3D);
274 cls.addFunc(
"newRope3DFromJson", &Rope::newRope3DFromJsonScript);
ActionParameterOperation operation
#define Module_IMPL(ModuleName, newExpr)
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
EVENGINE_API_FOUNDATION public API.
Move-only operation result carrying either a value or Status.
static Result success(T value)
Construct a successful result owning value.
const T & value() const &
Borrow the value from a const lvalue after checking success.
bool ok() const noexcept
Whether this result represents a non-failure outcome.
const Status & status() const noexcept
Inspect the structured operation status.
static Result failure(Status status)
Construct a failed result from a structured status.
const Diagnostic * primaryDiagnostic() const noexcept
First diagnostic, or null when no diagnostic was supplied.
static Status success(StatusCode code=StatusCode::Ok)
Construct a successful status with an explicit non-error outcome.
Type type() const
Return the active value type.
static Document parse(const std::string &text, std::string *error=nullptr)
Parse.
Renderer-independent particle rope with XPBD stretch and bend constraints.
Optional physics satellite that owns rope construction, schema, and script bindings.
eve::Result< void > registerRope3DCreateSchema()
Registers physics:rope3d-create@1 for tools and editors.
Rope3D * newRope3D(int particleCount, float startX, float startY, float startZ, float endX, float endY, float endZ)
Creates a straight renderer-independent rope.
eve::Result< Rope3D * > newRope3DFromJson(const std::string &json)
Validates a versioned creation document and transfers the new rope to the caller.
static eve::Result< SchemaRegistrationStatus > registerVersioned(const SchemaDefinition &definition)
Registers a new exact (id, version) entry without replacing it.
static std::vector< ValidationError > validate(const std::string &schemaId, const std::string &json)
Validates JSON text against the highest registered schema version.
static const SchemaDefinition * resolve(const std::string &schemaId, int schemaVersion)
Resolves one exact (schemaId, schemaVersion) pair, or nullptr.
Optional physics backend for vehicle mobility and body attach.
const EditorValue * field(const EditorValue &value, const char *name)
ValueType
JSON-compatible value kinds understood by a schema field.
std::vector< DiagnosticDetail > DiagnosticDetails
Owning collection of diagnostic details with stable insertion order.
Metadata and validation constraints for one object member.
Versioned runtime schema for a JSON object.
std::vector< FieldDefinition > fields
bool additionalProperties