Add signature to mjSpec and mjModel and use it to perform safe bind to mjModel and mjData.
PiperOrigin-RevId: 740378879 Change-Id: If14b326942529494f172e7aedcae30195798b458
This commit is contained in:
committed by
Copybara-Service
parent
c931565fdc
commit
157b074116
@@ -414,6 +414,9 @@ struct mjData_ {
|
|||||||
|
|
||||||
// thread pool pointer
|
// thread pool pointer
|
||||||
uintptr_t threadpool;
|
uintptr_t threadpool;
|
||||||
|
|
||||||
|
// compilation signature
|
||||||
|
uint64_t signature; // also held by the mjSpec that compiled the model
|
||||||
};
|
};
|
||||||
typedef struct mjData_ mjData;
|
typedef struct mjData_ mjData;
|
||||||
typedef enum mjtDisableBit_ { // disable default feature bitflags
|
typedef enum mjtDisableBit_ { // disable default feature bitflags
|
||||||
@@ -1451,6 +1454,9 @@ struct mjModel_ {
|
|||||||
|
|
||||||
// paths
|
// paths
|
||||||
char* paths; // paths to assets, 0-terminated (npaths x 1)
|
char* paths; // paths to assets, 0-terminated (npaths x 1)
|
||||||
|
|
||||||
|
// compilation signature
|
||||||
|
uint64_t signature; // also held by the mjSpec that compiled this model
|
||||||
};
|
};
|
||||||
typedef struct mjModel_ mjModel;
|
typedef struct mjModel_ mjModel;
|
||||||
struct mjResource_ {
|
struct mjResource_ {
|
||||||
@@ -1713,6 +1719,7 @@ typedef enum mjtOrientation_ { // type of orientation specifier
|
|||||||
} mjtOrientation;
|
} mjtOrientation;
|
||||||
typedef struct mjsElement_ { // element type, do not modify
|
typedef struct mjsElement_ { // element type, do not modify
|
||||||
mjtObj elemtype; // element type
|
mjtObj elemtype; // element type
|
||||||
|
uint64_t signature; // compilation signature
|
||||||
} mjsElement;
|
} mjsElement;
|
||||||
typedef struct mjsCompiler_ { // compiler options
|
typedef struct mjsCompiler_ { // compiler options
|
||||||
mjtByte autolimits; // infer "limited" attribute based on range
|
mjtByte autolimits; // infer "limited" attribute based on range
|
||||||
|
|||||||
@@ -442,6 +442,9 @@ struct mjData_ {
|
|||||||
|
|
||||||
// thread pool pointer
|
// thread pool pointer
|
||||||
uintptr_t threadpool;
|
uintptr_t threadpool;
|
||||||
|
|
||||||
|
// compilation signature
|
||||||
|
uint64_t signature; // also held by the mjSpec that compiled the model
|
||||||
};
|
};
|
||||||
typedef struct mjData_ mjData;
|
typedef struct mjData_ mjData;
|
||||||
|
|
||||||
|
|||||||
@@ -1155,6 +1155,9 @@ struct mjModel_ {
|
|||||||
|
|
||||||
// paths
|
// paths
|
||||||
char* paths; // paths to assets, 0-terminated (npaths x 1)
|
char* paths; // paths to assets, 0-terminated (npaths x 1)
|
||||||
|
|
||||||
|
// compilation signature
|
||||||
|
uint64_t signature; // also held by the mjSpec that compiled this model
|
||||||
};
|
};
|
||||||
typedef struct mjModel_ mjModel;
|
typedef struct mjModel_ mjModel;
|
||||||
|
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
// this is a C-API
|
// this is a C-API
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -119,6 +120,7 @@ typedef enum mjtOrientation_ { // type of orientation specifier
|
|||||||
|
|
||||||
typedef struct mjsElement_ { // element type, do not modify
|
typedef struct mjsElement_ { // element type, do not modify
|
||||||
mjtObj elemtype; // element type
|
mjtObj elemtype; // element type
|
||||||
|
uint64_t signature; // compilation signature
|
||||||
} mjsElement;
|
} mjsElement;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -613,12 +613,27 @@ def generate_find() -> None:
|
|||||||
print(code)
|
print(code)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_signature() -> None:
|
||||||
|
"""Generate signature functions."""
|
||||||
|
for key, _, _, _, _ in SPECS:
|
||||||
|
elem = key.removeprefix('mjs')
|
||||||
|
titlecase = 'Mjs' + elem
|
||||||
|
code = f"""\n
|
||||||
|
{key}.def_property_readonly("signature",
|
||||||
|
[](raw::{titlecase}& self) -> uint64_t {{
|
||||||
|
return mjs_getSpec(self.element)->element->signature;
|
||||||
|
}});
|
||||||
|
"""
|
||||||
|
print(code)
|
||||||
|
|
||||||
|
|
||||||
def main(argv: Sequence[str]) -> None:
|
def main(argv: Sequence[str]) -> None:
|
||||||
if len(argv) > 1:
|
if len(argv) > 1:
|
||||||
raise app.UsageError('Too many command-line arguments.')
|
raise app.UsageError('Too many command-line arguments.')
|
||||||
generate()
|
generate()
|
||||||
generate_add()
|
generate_add()
|
||||||
generate_find()
|
generate_find()
|
||||||
|
generate_signature()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -4454,6 +4454,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
doc='paths to assets, 0-terminated',
|
doc='paths to assets, 0-terminated',
|
||||||
array_extent=('npaths',),
|
array_extent=('npaths',),
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='signature',
|
||||||
|
type=ValueType(name='uint64_t'),
|
||||||
|
doc='also held by the mjSpec that compiled this model',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
('mjThreadPool',
|
('mjThreadPool',
|
||||||
@@ -6037,6 +6042,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='uintptr_t'),
|
type=ValueType(name='uintptr_t'),
|
||||||
doc='thread pool pointer',
|
doc='thread pool pointer',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='signature',
|
||||||
|
type=ValueType(name='uint64_t'),
|
||||||
|
doc='also held by the mjSpec that compiled the model',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
('mjvPerturb',
|
('mjvPerturb',
|
||||||
@@ -9044,6 +9054,11 @@ STRUCTS: Mapping[str, StructDecl] = dict([
|
|||||||
type=ValueType(name='mjtObj'),
|
type=ValueType(name='mjtObj'),
|
||||||
doc='element type',
|
doc='element type',
|
||||||
),
|
),
|
||||||
|
StructFieldDecl(
|
||||||
|
name='signature',
|
||||||
|
type=ValueType(name='uint64_t'),
|
||||||
|
doc='compilation signature',
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
('mjsCompiler',
|
('mjsCompiler',
|
||||||
|
|||||||
@@ -1153,6 +1153,13 @@ class SpecsTest(absltest.TestCase):
|
|||||||
AttributeError, "object has no attribute 'invalid'"
|
AttributeError, "object has no attribute 'invalid'"
|
||||||
):
|
):
|
||||||
print(mj_model.bind(joints).invalid)
|
print(mj_model.bind(joints).invalid)
|
||||||
|
invalid_spec = mujoco.MjSpec()
|
||||||
|
invalid_spec.worldbody.add_body(name='main')
|
||||||
|
with self.assertRaisesRegex(
|
||||||
|
ValueError,
|
||||||
|
'The mjSpec does not match mjModel. Please recompile the mjSpec.',
|
||||||
|
):
|
||||||
|
print(mj_model.bind(invalid_spec.body('main')))
|
||||||
|
|
||||||
def test_incorrect_hfield_size(self):
|
def test_incorrect_hfield_size(self):
|
||||||
nrow = 300
|
nrow = 300
|
||||||
|
|||||||
@@ -1710,6 +1710,10 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
// Return the full bytes array of concatenated paths
|
// Return the full bytes array of concatenated paths
|
||||||
return m.paths_bytes;
|
return m.paths_bytes;
|
||||||
});
|
});
|
||||||
|
mjModel.def_property_readonly(
|
||||||
|
"signature", [](const MjModelWrapper& m) -> const uint64_t& {
|
||||||
|
return m.get()->signature;
|
||||||
|
});
|
||||||
|
|
||||||
#define XGROUP(MjModelGroupedViews, field, nfield, FIELD_XMACROS) \
|
#define XGROUP(MjModelGroupedViews, field, nfield, FIELD_XMACROS) \
|
||||||
mjModel.def( \
|
mjModel.def( \
|
||||||
@@ -1730,7 +1734,13 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
mjModel.def( \
|
mjModel.def( \
|
||||||
"bind_scalar", \
|
"bind_scalar", \
|
||||||
[](MjModelWrapper& m, spectype& spec) -> auto& { \
|
[](MjModelWrapper& m, spectype& spec) -> auto& { \
|
||||||
return m.indexer().field##_by_name(mjs_getString(spec.name)); \
|
if (mjs_getSpec(spec.element)->element->signature != \
|
||||||
|
m.get()->signature) { \
|
||||||
|
throw py::value_error( \
|
||||||
|
"The mjSpec does not match mjModel. Please recompile " \
|
||||||
|
"the mjSpec."); \
|
||||||
|
} \
|
||||||
|
return m.indexer().field(mjs_getId(spec.element)); \
|
||||||
}, \
|
}, \
|
||||||
py::return_value_policy::reference_internal, \
|
py::return_value_policy::reference_internal, \
|
||||||
py::arg_v("spec", py::none()));
|
py::arg_v("spec", py::none()));
|
||||||
@@ -2018,6 +2028,10 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
std::istringstream input(b, std::ios::in | std::ios::binary);
|
std::istringstream input(b, std::ios::in | std::ios::binary);
|
||||||
return MjDataWrapper::Deserialize(input);
|
return MjDataWrapper::Deserialize(input);
|
||||||
}));
|
}));
|
||||||
|
mjData.def_property_readonly(
|
||||||
|
"signature", [](const MjDataWrapper& d) -> uint64_t {
|
||||||
|
return d.get()->signature;
|
||||||
|
});
|
||||||
|
|
||||||
#define X(type, var) \
|
#define X(type, var) \
|
||||||
mjData.def_property( \
|
mjData.def_property( \
|
||||||
@@ -2076,7 +2090,13 @@ This is useful for example when the MJB is not available as a file on disk.)"));
|
|||||||
mjData.def( \
|
mjData.def( \
|
||||||
"bind_scalar", \
|
"bind_scalar", \
|
||||||
[](MjDataWrapper& d, spectype& spec) -> auto& { \
|
[](MjDataWrapper& d, spectype& spec) -> auto& { \
|
||||||
return d.indexer().field##_by_name(mjs_getString(spec.name)); \
|
if (mjs_getSpec(spec.element)->element->signature != \
|
||||||
|
d.get()->signature) { \
|
||||||
|
throw py::value_error( \
|
||||||
|
"The mjSpec does not match mjData. Please recompile "\
|
||||||
|
"the mjSpec."); \
|
||||||
|
} \
|
||||||
|
return d.indexer().field(mjs_getId(spec.element)); \
|
||||||
}, \
|
}, \
|
||||||
py::return_value_policy::reference_internal, \
|
py::return_value_policy::reference_internal, \
|
||||||
py::arg_v("spec", py::none()));
|
py::arg_v("spec", py::none()));
|
||||||
|
|||||||
@@ -2014,6 +2014,9 @@ static void _resetData(const mjModel* m, mjData* d, unsigned char debug_value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy signature from model
|
||||||
|
d->signature = m->signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -403,12 +403,14 @@ bool mjCFlexcomp::Make(mjsBody* body, char* error, int error_sz) {
|
|||||||
mjCFlex* flex = model->AddFlex();
|
mjCFlex* flex = model->AddFlex();
|
||||||
mjsFlex* pf = &flex->spec;
|
mjsFlex* pf = &flex->spec;
|
||||||
int id = flex->id;
|
int id = flex->id;
|
||||||
|
int uid = flex->uid;
|
||||||
|
|
||||||
*flex = def.Flex();
|
*flex = def.Flex();
|
||||||
flex->PointToLocal();
|
flex->PointToLocal();
|
||||||
|
|
||||||
flex->model = model;
|
flex->model = model;
|
||||||
flex->id = id;
|
flex->id = id;
|
||||||
|
flex->uid = uid;
|
||||||
mjs_setString(pf->name, name.c_str());
|
mjs_setString(pf->name, name.c_str());
|
||||||
mjs_setInt(pf->elem, element.data(), element.size());
|
mjs_setInt(pf->elem, element.data(), element.size());
|
||||||
mjs_setFloat(pf->texcoord, texcoord.data(), texcoord.size());
|
mjs_setFloat(pf->texcoord, texcoord.data(), texcoord.size());
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ mjCModel::mjCModel() {
|
|||||||
world->mass = 0;
|
world->mass = 0;
|
||||||
mjuu_zerovec(world->inertia, 3);
|
mjuu_zerovec(world->inertia, 3);
|
||||||
world->id = 0;
|
world->id = 0;
|
||||||
|
world->uid = GetUid();
|
||||||
world->parent = nullptr;
|
world->parent = nullptr;
|
||||||
world->weldid = 0;
|
world->weldid = 0;
|
||||||
world->name = "world";
|
world->name = "world";
|
||||||
@@ -213,6 +214,9 @@ mjCModel::mjCModel() {
|
|||||||
|
|
||||||
// the source spec is the model itself, overwritten in the copy constructor
|
// the source spec is the model itself, overwritten in the copy constructor
|
||||||
source_spec_ = &spec;
|
source_spec_ = &spec;
|
||||||
|
|
||||||
|
// set the signature
|
||||||
|
spec.element->signature = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -289,6 +293,7 @@ void mjCModel::CopyList(std::vector<T*>& dest,
|
|||||||
// copy the element from the other model to this model
|
// copy the element from the other model to this model
|
||||||
if (deepcopy_) {
|
if (deepcopy_) {
|
||||||
source[i]->ForgetKeyframes();
|
source[i]->ForgetKeyframes();
|
||||||
|
candidate->uid = GetUid();
|
||||||
} else {
|
} else {
|
||||||
candidate->AddRef();
|
candidate->AddRef();
|
||||||
}
|
}
|
||||||
@@ -499,6 +504,9 @@ mjCModel& mjCModel::operator+=(const mjCModel& other) {
|
|||||||
nq = nv = na = nu = nmocap = 0;
|
nq = nv = na = nu = nmocap = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update signature before we reset the tree lists
|
||||||
|
spec.element->signature = Signature();
|
||||||
|
|
||||||
PointToLocal();
|
PointToLocal();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
@@ -633,6 +641,9 @@ mjCModel& mjCModel::operator-=(const mjCBody& subtree) {
|
|||||||
RemoveFromList(sensors_, oldmodel);
|
RemoveFromList(sensors_, oldmodel);
|
||||||
RemovePlugins();
|
RemovePlugins();
|
||||||
|
|
||||||
|
// update signature before we reset the tree lists
|
||||||
|
spec.element->signature = Signature();
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -803,6 +814,9 @@ void mjCModel::DeleteElement(mjsElement* el) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update signature before we reset the tree lists
|
||||||
|
spec.element->signature = Signature();
|
||||||
|
|
||||||
ResetTreeLists(); // in case of a nested delete
|
ResetTreeLists(); // in case of a nested delete
|
||||||
MakeTreeLists();
|
MakeTreeLists();
|
||||||
ProcessLists(/*checkrepeat=*/false);
|
ProcessLists(/*checkrepeat=*/false);
|
||||||
@@ -1019,7 +1033,9 @@ template <class T>
|
|||||||
T* mjCModel::AddObject(vector<T*>& list, string type) {
|
T* mjCModel::AddObject(vector<T*>& list, string type) {
|
||||||
T* obj = new T(this);
|
T* obj = new T(this);
|
||||||
obj->id = (int)list.size();
|
obj->id = (int)list.size();
|
||||||
|
obj->uid = GetUid();
|
||||||
list.push_back(obj);
|
list.push_back(obj);
|
||||||
|
spec.element->signature = Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1030,7 +1046,9 @@ T* mjCModel::AddObjectDefault(vector<T*>& list, string type, mjCDef* def) {
|
|||||||
T* obj = new T(this, def ? def : defaults_[0]);
|
T* obj = new T(this, def ? def : defaults_[0]);
|
||||||
obj->id = (int)list.size();
|
obj->id = (int)list.size();
|
||||||
obj->classname = def ? def->name : "main";
|
obj->classname = def ? def->name : "main";
|
||||||
|
obj->uid = GetUid();
|
||||||
list.push_back(obj);
|
list.push_back(obj);
|
||||||
|
spec.element->signature = Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4572,6 +4590,28 @@ void mjCModel::TryCompile(mjModel*& m, mjData*& d, const mjVFS* vfs) {
|
|||||||
mju::strcpy_arr(errInfo.message, warningtext);
|
mju::strcpy_arr(errInfo.message, warningtext);
|
||||||
errInfo.warning = true;
|
errInfo.warning = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save signature
|
||||||
|
m->signature = Signature();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t mjCModel::Signature() {
|
||||||
|
std::string uid_str;
|
||||||
|
for (int i = 0; i < mjNOBJECT; ++i) {
|
||||||
|
if (i == mjOBJ_XBODY || i == mjOBJ_UNKNOWN || i == mjOBJ_DOF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (object_lists_[i] == nullptr) {
|
||||||
|
throw mjCError(0, "object list %s is null", std::to_string(i).c_str());
|
||||||
|
}
|
||||||
|
uid_str += '|';
|
||||||
|
for (mjCBase* object : *object_lists_[i]) {
|
||||||
|
uid_str += std::to_string(object->uid) + " ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mj_hashString(uid_str.c_str(), UINT64_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#define MUJOCO_SRC_USER_USER_MODEL_H_
|
#define MUJOCO_SRC_USER_USER_MODEL_H_
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -324,6 +325,9 @@ class mjCModel : public mjCModel_, private mjSpec {
|
|||||||
// set attached flag
|
// set attached flag
|
||||||
void SetAttached(bool deepcopy) { attached_ |= !deepcopy; }
|
void SetAttached(bool deepcopy) { attached_ |= !deepcopy; }
|
||||||
|
|
||||||
|
// get new uid
|
||||||
|
int GetUid() { return uid_count_++; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// settings for each defaults class
|
// settings for each defaults class
|
||||||
std::vector<mjCDef*> defaults_;
|
std::vector<mjCDef*> defaults_;
|
||||||
@@ -440,11 +444,14 @@ class mjCModel : public mjCModel_, private mjSpec {
|
|||||||
void MarkPluginInstance(std::unordered_map<std::string, bool>& instances,
|
void MarkPluginInstance(std::unordered_map<std::string, bool>& instances,
|
||||||
const std::vector<T*>& list);
|
const std::vector<T*>& list);
|
||||||
|
|
||||||
|
// generate a signature for the model
|
||||||
|
uint64_t Signature();
|
||||||
|
|
||||||
mjListKeyMap ids; // map from object names to ids
|
mjListKeyMap ids; // map from object names to ids
|
||||||
mjCError errInfo; // last error info
|
mjCError errInfo; // last error info
|
||||||
std::vector<mjKeyInfo> key_pending_; // attached keyframes
|
std::vector<mjKeyInfo> key_pending_; // attached keyframes
|
||||||
bool deepcopy_; // copy objects when attaching
|
bool deepcopy_; // copy objects when attaching
|
||||||
bool attached_ = false; // true if model is attached to a parent model
|
bool attached_ = false; // true if model is attached to a parent model
|
||||||
|
int uid_count_ = 0; // unique id count for all objects
|
||||||
};
|
};
|
||||||
#endif // MUJOCO_SRC_USER_USER_MODEL_H_
|
#endif // MUJOCO_SRC_USER_USER_MODEL_H_
|
||||||
|
|||||||
@@ -837,6 +837,7 @@ mjCBody::mjCBody(mjCModel* _model) {
|
|||||||
|
|
||||||
mjCBody::mjCBody(const mjCBody& other, mjCModel* _model) {
|
mjCBody::mjCBody(const mjCBody& other, mjCModel* _model) {
|
||||||
model = _model;
|
model = _model;
|
||||||
|
uid = model->GetUid();
|
||||||
mjSpec* origin = model->FindSpec(other.compiler);
|
mjSpec* origin = model->FindSpec(other.compiler);
|
||||||
compiler = origin ? &origin->compiler : &model->spec.compiler;
|
compiler = origin ? &origin->compiler : &model->spec.compiler;
|
||||||
*this = other;
|
*this = other;
|
||||||
@@ -930,6 +931,7 @@ mjCBody& mjCBody::operator+=(const mjCFrame& other) {
|
|||||||
frames.back()->frame = other.frame;
|
frames.back()->frame = other.frame;
|
||||||
if (model->deepcopy_) {
|
if (model->deepcopy_) {
|
||||||
frames.back()->NameSpace(other_model);
|
frames.back()->NameSpace(other_model);
|
||||||
|
frames.back()->uid = model->GetUid();
|
||||||
} else {
|
} else {
|
||||||
frames.back()->AddRef();
|
frames.back()->AddRef();
|
||||||
}
|
}
|
||||||
@@ -1022,6 +1024,8 @@ void mjCBody::CopyList(std::vector<T*>& dst, const std::vector<T*>& src,
|
|||||||
// increment refcount if shallow copy is made
|
// increment refcount if shallow copy is made
|
||||||
if (!model->deepcopy_) {
|
if (!model->deepcopy_) {
|
||||||
dst.back()->AddRef();
|
dst.back()->AddRef();
|
||||||
|
} else {
|
||||||
|
dst.back()->uid = model->GetUid();
|
||||||
}
|
}
|
||||||
|
|
||||||
// set namespace
|
// set namespace
|
||||||
@@ -1237,6 +1241,10 @@ mjCBody* mjCBody::AddBody(mjCDef* _def) {
|
|||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
obj->parent = this;
|
obj->parent = this;
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1248,6 +1256,10 @@ mjCFrame* mjCBody::AddFrame(mjCFrame* _frame) {
|
|||||||
frames.push_back(obj);
|
frames.push_back(obj);
|
||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1268,6 +1280,10 @@ mjCJoint* mjCBody::AddFreeJoint() {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1287,6 +1303,10 @@ mjCJoint* mjCBody::AddJoint(mjCDef* _def) {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1306,6 +1326,10 @@ mjCGeom* mjCBody::AddGeom(mjCDef* _def) {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1325,6 +1349,10 @@ mjCSite* mjCBody::AddSite(mjCDef* _def) {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1344,6 +1372,10 @@ mjCCamera* mjCBody::AddCamera(mjCDef* _def) {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1363,6 +1395,10 @@ mjCLight* mjCBody::AddLight(mjCDef* _def) {
|
|||||||
model->ResetTreeLists();
|
model->ResetTreeLists();
|
||||||
model->MakeTreeLists();
|
model->MakeTreeLists();
|
||||||
|
|
||||||
|
|
||||||
|
// update signature
|
||||||
|
obj->uid = model->GetUid();
|
||||||
|
model->spec.element->signature = model->Signature();
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ class mjCBoundingVolumeHierarchy : public mjCBoundingVolumeHierarchy_ {
|
|||||||
class mjCBase_ : public mjsElement {
|
class mjCBase_ : public mjsElement {
|
||||||
public:
|
public:
|
||||||
int id; // object id
|
int id; // object id
|
||||||
|
int uid; // unique identifier
|
||||||
std::string name; // object name
|
std::string name; // object name
|
||||||
std::string classname; // defaults class name
|
std::string classname; // defaults class name
|
||||||
std::string info; // error message info set by the user
|
std::string info; // error message info set by the user
|
||||||
|
|||||||
@@ -5008,6 +5008,7 @@ public unsafe struct mjData_ {
|
|||||||
public double* efc_force;
|
public double* efc_force;
|
||||||
public int* efc_state;
|
public int* efc_state;
|
||||||
public UIntPtr threadpool;
|
public UIntPtr threadpool;
|
||||||
|
public UInt64 signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@@ -5672,6 +5673,7 @@ public unsafe struct mjModel_ {
|
|||||||
public char* names;
|
public char* names;
|
||||||
public int* names_map;
|
public int* names_map;
|
||||||
public char* paths;
|
public char* paths;
|
||||||
|
public UInt64 signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
|||||||
Reference in New Issue
Block a user