Overte C++ Documentation
EntityItemPropertiesMacros.h
1 //
2 // EntityItemPropertiesMacros.h
3 // libraries/entities/src
4 //
5 // Created by Brad Hefta-Gaub on 9/10/14.
6 // Copyright 2014 High Fidelity, Inc.
7 // Copyright 2023 Overte e.V.
8 //
9 // Distributed under the Apache License, Version 2.0.
10 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
11 // SPDX-License-Identifier: Apache-2.0
12 //
13 
14 
15 #ifndef hifi_EntityItemPropertiesMacros_h
16 #define hifi_EntityItemPropertiesMacros_h
17 
18 #include <EntityItemID.h>
19 #include <EntityPropertyFlags.h>
20 #include <RegisteredMetaTypes.h>
21 #include <ScriptEngine.h>
22 #include <ScriptValue.h>
23 #include <ScriptValueUtils.h>
24 #include "Sampler.h"
25 
26 const quint64 UNKNOWN_CREATED_TIME = 0;
27 
28 using vec3Color = glm::vec3;
29 using u8vec3Color = glm::u8vec3;
30 
31 struct EntityPropertyInfo {
32  EntityPropertyInfo(EntityPropertyList propEnum) :
33  propertyEnums(propEnum) {}
34  EntityPropertyInfo(EntityPropertyList propEnum, QVariant min, QVariant max) :
35  propertyEnums(propEnum), minimum(min), maximum(max) {}
36  EntityPropertyInfo() = default;
37  EntityPropertyFlags propertyEnums;
38  QVariant minimum;
39  QVariant maximum;
40 };
41 
42 // For keeping track of who owns an avatar entity so private URLs can't be ripped
43 enum class AvatarEntityOwnership {
44  Nobody,
45  MyAvatar,
46  OtherAvatar,
47 };
48 
49 template <typename T>
50 EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if<!std::is_integral<T>::value>::type* = 0) {
51  return EntityPropertyInfo(p);
52 }
53 
54 template <typename T>
55 EntityPropertyInfo makePropertyInfo(EntityPropertyList p, typename std::enable_if<std::is_integral<T>::value>::type* = 0) {
56  return EntityPropertyInfo(p, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
57 }
58 
59 #define APPEND_ENTITY_PROPERTY(P,V) \
60  if (requestedProperties.getHasProperty(P)) { \
61  LevelDetails propertyLevel = packetData->startLevel(); \
62  successPropertyFits = packetData->appendValue(V); \
63  if (successPropertyFits) { \
64  propertyFlags |= P; \
65  propertiesDidntFit -= P; \
66  propertyCount++; \
67  packetData->endLevel(propertyLevel); \
68  } else { \
69  packetData->discardLevel(propertyLevel); \
70  appendState = OctreeElement::PARTIAL; \
71  } \
72  } else { \
73  propertiesDidntFit -= P; \
74  }
75 
76 #define READ_ENTITY_PROPERTY(P,T,S) \
77  if (propertyFlags.getHasProperty(P)) { \
78  T fromBuffer; \
79  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
80  dataAt += bytes; \
81  bytesRead += bytes; \
82  if (overwriteLocalData) { \
83  S(fromBuffer); \
84  } \
85  somethingChanged = true; \
86  }
87 
88 #define SKIP_ENTITY_PROPERTY(P,T) \
89  if (propertyFlags.getHasProperty(P)) { \
90  T fromBuffer; \
91  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
92  dataAt += bytes; \
93  bytesRead += bytes; \
94  }
95 
96 #define DECODE_GROUP_PROPERTY_HAS_CHANGED(P,N) \
97  if (propertyFlags.getHasProperty(P)) { \
98  set##N##Changed(true); \
99  }
100 
101 
102 #define READ_ENTITY_PROPERTY_TO_PROPERTIES(P,T,O) \
103  if (propertyFlags.getHasProperty(P)) { \
104  T fromBuffer; \
105  int bytes = OctreePacketData::unpackDataFromBytes(dataAt, fromBuffer); \
106  dataAt += bytes; \
107  processedBytes += bytes; \
108  properties.O(fromBuffer); \
109  }
110 
111 #define SET_ENTITY_PROPERTY_FROM_PROPERTIES(P,M) \
112  if (properties._##P##Changed) { \
113  M(properties._##P); \
114  somethingChanged = true; \
115  }
116 
117 #define SET_ENTITY_GROUP_PROPERTY_FROM_PROPERTIES(G,P,p,M) \
118  if (properties.get##G().p##Changed()) { \
119  M(properties.get##G().get##P()); \
120  somethingChanged = true; \
121  }
122 
123 #define SET_ENTITY_PROPERTY_FROM_PROPERTIES_GETTER(C,G,S) \
124  if (properties.C()) { \
125  S(properties.G()); \
126  somethingChanged = true; \
127  }
128 
129 #define COPY_ENTITY_PROPERTY_TO_PROPERTIES(P,M) \
130  properties._##P = M(); \
131  properties._##P##Changed = false;
132 
133 #define COPY_ENTITY_GROUP_PROPERTY_TO_PROPERTIES(G,P,M) \
134  properties.get##G().set##P(M()); \
135  properties.get##G().set##P##Changed(false);
136 
137 #define CHECK_PROPERTY_CHANGE(P,M) \
138  if (_##M##Changed) { \
139  changedProperties += P; \
140  }
141 
142 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec2& v) { return vec2ToScriptValue(e, v); }
143 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ToScriptValue(e, v); }
144 inline ScriptValue vec3Color_convertScriptValue(ScriptEngine* e, const glm::vec3& v) { return vec3ColorToScriptValue(e, v); }
145 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ToScriptValue(e, v); }
146 inline ScriptValue u8vec3Color_convertScriptValue(ScriptEngine* e, const glm::u8vec3& v) { return u8vec3ColorToScriptValue(e, v); }
147 inline ScriptValue convertScriptValue(ScriptEngine* e, float v) { return e->newValue(v); }
148 inline ScriptValue convertScriptValue(ScriptEngine* e, int v) { return e->newValue(v); }
149 inline ScriptValue convertScriptValue(ScriptEngine* e, bool v) { return e->newValue(v); }
150 inline ScriptValue convertScriptValue(ScriptEngine* e, quint16 v) { return e->newValue(v); }
151 inline ScriptValue convertScriptValue(ScriptEngine* e, quint32 v) { return e->newValue(v); }
152 inline ScriptValue convertScriptValue(ScriptEngine* e, quint64 v) { return e->newValue((double)v); }
153 inline ScriptValue convertScriptValue(ScriptEngine* e, const QString& v) { return e->newValue(v); }
154 
155 inline ScriptValue convertScriptValue(ScriptEngine* e, const glm::quat& v) { return quatToScriptValue(e, v); }
156 inline ScriptValue convertScriptValue(ScriptEngine* e, const ScriptValue& v) { return v; }
157 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ToScriptValue(e, v); }
158 inline ScriptValue qVectorVec3Color_convertScriptValue(ScriptEngine* e, const QVector<glm::vec3>& v) {return qVectorVec3ColorToScriptValue(e, v); }
159 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<glm::quat>& v) {return qVectorQuatToScriptValue(e, v); }
160 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<bool>& v) {return qVectorBoolToScriptValue(e, v); }
161 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<float>& v) { return qVectorFloatToScriptValue(e, v); }
162 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QUuid>& v) { return qVectorQUuidToScriptValue(e, v); }
163 inline ScriptValue convertScriptValue(ScriptEngine* e, const QVector<QString>& v) { return qVectorQStringToScriptValue(e, v); }
164 
165 inline ScriptValue convertScriptValue(ScriptEngine* e, const QRect& v) { return qRectToScriptValue(e, v); }
166 
167 inline ScriptValue convertScriptValue(ScriptEngine* e, const QByteArray& v) {
168  QByteArray b64 = v.toBase64();
169  return e->newValue(QString(b64));
170 }
171 
172 inline ScriptValue convertScriptValue(ScriptEngine* e, const EntityItemID& v) { return e->newValue(QUuid(v).toString()); }
173 
174 inline ScriptValue convertScriptValue(ScriptEngine* e, const AACube& v) { return aaCubeToScriptValue(e, v); }
175 
176 inline ScriptValue convertScriptValue(ScriptEngine* e, const Sampler& v) { return samplerToScriptValue(e, v); }
177 
178 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE(X,G,g,P,p) \
179  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
180  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
181  ScriptValue groupProperties = properties.property(#g); \
182  if (!groupProperties.isValid()) { \
183  groupProperties = engine->newObject(); \
184  } \
185  ScriptValue V = convertScriptValue(engine, get##P()); \
186  groupProperties.setProperty(#p, V); \
187  properties.setProperty(#g, groupProperties); \
188  }
189 
190 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_TYPED(X,G,g,P,p,T) \
191  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
192  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
193  ScriptValue groupProperties = properties.property(#g); \
194  if (!groupProperties.isValid()) { \
195  groupProperties = engine->newObject(); \
196  } \
197  ScriptValue V = T##_convertScriptValue(engine, get##P()); \
198  groupProperties.setProperty(#p, V); \
199  properties.setProperty(#g, groupProperties); \
200  }
201 
202 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_GETTER(X,G,g,P,p,M) \
203  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
204  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
205  ScriptValue groupProperties = properties.property(#g); \
206  if (!groupProperties.isValid()) { \
207  groupProperties = engine->newObject(); \
208  } \
209  ScriptValue V = convertScriptValue(engine, M()); \
210  groupProperties.setProperty(#p, V); \
211  properties.setProperty(#g, groupProperties); \
212  }
213 
214 #define COPY_PROPERTY_TO_QSCRIPTVALUE(p,P) \
215  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
216  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
217  ScriptValue V = convertScriptValue(engine, _##P); \
218  properties.setProperty(#P, V); \
219  }
220 
221 #define COPY_PROPERTY_TO_QSCRIPTVALUE_TYPED(p,P,T) \
222  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
223  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
224  ScriptValue V = T##_convertScriptValue(engine, _##P); \
225  properties.setProperty(#P, V); \
226  }
227 
228 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(P, G) \
229  properties.setProperty(#P, G);
230 
231 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, G) \
232  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
233  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
234  ScriptValue V = convertScriptValue(engine, G); \
235  properties.setProperty(#P, V); \
236  }
237 
238 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_TYPED(p, P, G, T) \
239  if ((_desiredProperties.isEmpty() || _desiredProperties.getHasProperty(p)) && \
240  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
241  ScriptValue V = T##_convertScriptValue(engine, G()); \
242  properties.setProperty(#P, V); \
243  }
244 
245 // same as COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER but uses #X instead of #P in the setProperty() step
246 #define COPY_PROXY_PROPERTY_TO_QSCRIPTVALUE_GETTER(p, P, X, G) \
247  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
248  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
249  ScriptValue V = convertScriptValue(engine, G()); \
250  properties.setProperty(#X, V); \
251  }
252 
253 #define COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_ALWAYS(P, G) \
254  if (!skipDefaults || defaultEntityProperties._##P != _##P) { \
255  ScriptValue V = convertScriptValue(engine, G); \
256  properties.setProperty(#P, V); \
257  }
258 
259 #define COPY_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(p, P) \
260  if (((!returnNothingOnEmptyPropertyFlags && _desiredProperties.isEmpty()) || _desiredProperties.getHasProperty(p)) && \
261  (!skipDefaults || defaultEntityProperties._##P != _##P)) { \
262  if ( \
263  ownership == AvatarEntityOwnership::MyAvatar || \
264  (nodeList->getThisNodeCanViewAssetURLs() && ownership != AvatarEntityOwnership::OtherAvatar) \
265  ) { \
266  ScriptValue V = convertScriptValue(engine, _##P); \
267  properties.setProperty(#P, V); \
268  } else { \
269  const QString emptyURL = ""; \
270  ScriptValue V = convertScriptValue(engine, emptyURL); \
271  properties.setProperty(#P, V); \
272  } \
273  }
274 
275 #define COPY_GROUP_PROPERTY_TO_QSCRIPTVALUE_IF_URL_PERMISSION(X, G, g, P, p) \
276  if (((!returnNothingOnEmptyPropertyFlags && desiredProperties.isEmpty()) || desiredProperties.getHasProperty(X)) && \
277  (!skipDefaults || defaultEntityProperties.get##G().get##P() != get##P())) { \
278  if ( \
279  ownership == AvatarEntityOwnership::MyAvatar || \
280  (nodeList->getThisNodeCanViewAssetURLs() && ownership != AvatarEntityOwnership::OtherAvatar) \
281  ) { \
282  ScriptValue groupProperties = properties.property(#g); \
283  if (!groupProperties.isValid()) { \
284  groupProperties = engine->newObject(); \
285  } \
286  ScriptValue V = convertScriptValue(engine, get##P()); \
287  groupProperties.setProperty(#p, V); \
288  properties.setProperty(#g, groupProperties); \
289  } else { \
290  const QString emptyURL = ""; \
291  ScriptValue V = convertScriptValue(engine, emptyURL); \
292  properties.setProperty(#P, V); \
293  } \
294  }
295 
296 typedef QVector<glm::vec3> qVectorVec3;
297 typedef QVector<glm::quat> qVectorQuat;
298 typedef QVector<bool> qVectorBool;
299 typedef QVector<float> qVectorFloat;
300 typedef QVector<QUuid> qVectorQUuid;
301 typedef QVector<QString> qVectorQString;
302 typedef QSet<QString> qSetQString;
303 inline float float_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toFloat(&isValid); }
304 inline quint64 quint64_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toULongLong(&isValid); }
305 inline quint32 quint32_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
306  // Use QString::toUInt() so that isValid is set to false if the number is outside the quint32 range.
307  return v.toString().toUInt(&isValid);
308 }
309 inline quint16 quint16_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
310 inline uint16_t uint16_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
311 inline uint32_t uint32_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
312 inline int int_convertFromScriptValue(const ScriptValue& v, bool& isValid) { return v.toVariant().toInt(&isValid); }
313 inline bool bool_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toBool(); }
314 inline uint8_t uint8_t_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return (uint8_t)(0xff & v.toVariant().toInt(&isValid)); }
315 inline QString QString_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toString().trimmed(); }
316 inline QUuid QUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
317 inline EntityItemID EntityItemID_convertFromScriptValue(const ScriptValue& v, bool& isValid) { isValid = true; return v.toVariant().toUuid(); }
318 
319 inline QByteArray QByteArray_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
320  isValid = true;
321  QString b64 = v.toVariant().toString().trimmed();
322  return QByteArray::fromBase64(b64.toUtf8());
323 }
324 
325 inline glm::vec2 vec2_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
326  isValid = true;
327  glm::vec2 vec2;
328  vec2FromScriptValue(v, vec2);
329  return vec2;
330 }
331 
332 inline glm::vec3 vec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
333  isValid = true;
334  glm::vec3 vec3;
335  vec3FromScriptValue(v, vec3);
336  return vec3;
337 }
338 
339 inline glm::vec3 vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
340  isValid = true;
341  glm::vec3 vec3;
342  vec3FromScriptValue(v, vec3);
343  return vec3;
344 }
345 
346 inline glm::u8vec3 u8vec3Color_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
347  isValid = true;
348  glm::u8vec3 vec3;
349  u8vec3FromScriptValue(v, vec3);
350  return vec3;
351 }
352 
353 inline AACube AACube_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
354  isValid = true;
355  AACube result;
356  aaCubeFromScriptValue(v, result);
357  return result;
358 }
359 
360 inline qVectorFloat qVectorFloat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
361  isValid = true;
362  return qVectorFloatFromScriptValue(v);
363 }
364 
365 inline qVectorVec3 qVectorVec3_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
366  isValid = true;
367  return qVectorVec3FromScriptValue(v);
368 }
369 
370 inline qVectorQuat qVectorQuat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
371  isValid = true;
372  return qVectorQuatFromScriptValue(v);
373 }
374 
375 inline qVectorBool qVectorBool_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
376  isValid = true;
377  return qVectorBoolFromScriptValue(v);
378 }
379 
380 inline qVectorQUuid qVectorQUuid_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
381  isValid = true;
382  return qVectorQUuidFromScriptValue(v);
383 }
384 
385 inline qVectorQString qVectorQString_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
386  isValid = true;
387  return qVectorQStringFromScriptValue(v);
388 }
389 
390 inline glm::quat quat_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
391  isValid = false;
392  ScriptValue x = v.property("x");
393  ScriptValue y = v.property("y");
394  ScriptValue z = v.property("z");
395  ScriptValue w = v.property("w");
396  if (x.isValid() && y.isValid() && z.isValid() && w.isValid()) {
397  glm::quat newValue;
398  newValue.x = x.toVariant().toFloat();
399  newValue.y = y.toVariant().toFloat();
400  newValue.z = z.toVariant().toFloat();
401  newValue.w = w.toVariant().toFloat();
402  isValid = !glm::isnan(newValue.x) &&
403  !glm::isnan(newValue.y) &&
404  !glm::isnan(newValue.z) &&
405  !glm::isnan(newValue.w);
406  if (isValid) {
407  return newValue;
408  }
409  }
410  return glm::quat();
411 }
412 
413 inline QRect QRect_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
414  isValid = true;
415  QRect rect;
416  qRectFromScriptValue(v, rect);
417  return rect;
418 }
419 
420 inline Sampler Sampler_convertFromScriptValue(const ScriptValue& v, bool& isValid) {
421  isValid = true;
422  Sampler sampler;
423  samplerFromScriptValue(v, sampler);
424  return sampler;
425 }
426 
427 #define COPY_PROPERTY_IF_CHANGED(P) \
428 { \
429  if (other._##P##Changed) { \
430  _##P = other._##P; \
431  } \
432 }
433 
434 #define COPY_PROPERTY_FROM_QSCRIPTVALUE(P, T, S) \
435  { \
436  if (namesSet.contains(#P)) { \
437  ScriptValue V = object.property(#P); \
438  if (V.isValid()) { \
439  bool isValid = false; \
440  T newValue = T##_convertFromScriptValue(V, isValid); \
441  if (isValid && (_defaultSettings || newValue != _##P)) { \
442  S(newValue); \
443  } \
444  } \
445  } \
446  }
447 
448 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(P, T, S, G) \
449 { \
450  if (namesSet.contains(#P)) { \
451  ScriptValue V = object.property(#P); \
452  if (V.isValid()) { \
453  bool isValid = false; \
454  T newValue = T##_convertFromScriptValue(V, isValid); \
455  if (isValid && (_defaultSettings || newValue != G())) { \
456  S(newValue); \
457  } \
458  } \
459  } \
460 }
461 
462 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_NOCHECK(P, T, S) \
463 { \
464  if (namesSet.contains(#P)) { \
465  ScriptValue V = object.property(#P); \
466  if (V.isValid()) { \
467  bool isValid = false; \
468  T newValue = T##_convertFromScriptValue(V, isValid); \
469  if (isValid && (_defaultSettings)) { \
470  S(newValue); \
471  } \
472  } \
473  } \
474 }
475 
476 #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE(G, P, T, S) \
477  { \
478  if (namesSet.contains(#G)) { \
479  ScriptValue G = object.property(#G); \
480  if (G.isValid()) { \
481  ScriptValue V = G.property(#P); \
482  if (V.isValid()) { \
483  bool isValid = false; \
484  T newValue = T##_convertFromScriptValue(V, isValid); \
485  if (isValid && (_defaultSettings || newValue != _##P)) { \
486  S(newValue); \
487  } \
488  } \
489  } \
490  } \
491  }
492 
493 #define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \
494  { \
495  if (namesSet.contains(#P)) { \
496  ScriptValue P = object.property(#P); \
497  if (P.isValid()) { \
498  QString newValue = P.toVariant().toString(); \
499  if (_defaultSettings || newValue != get##S##AsString()) { \
500  set##S##FromString(newValue); \
501  } \
502  } \
503  } \
504  }
505 
506 #define COPY_GROUP_PROPERTY_FROM_QSCRIPTVALUE_ENUM(G, P, S) \
507  { \
508  if (namesSet.contains(#G)) { \
509  ScriptValue G = object.property(#G); \
510  if (G.isValid()) { \
511  ScriptValue P = G.property(#P); \
512  if (P.isValid()) { \
513  QString newValue = P.toVariant().toString(); \
514  if (_defaultSettings || newValue != get##S##AsString()) { \
515  set##S##FromString(newValue); \
516  } \
517  } \
518  } \
519  } \
520  }
521 
522 #define DEFINE_PROPERTY_GROUP(N, n, T) \
523  public: \
524  const T& get##N() const { return _##n; } \
525  T& get##N() { return _##n; } \
526  private: \
527  T _##n; \
528  static T _static##N;
529 
530 
531 #define ADD_PROPERTY_TO_MAP(P, n, T) \
532  { \
533  EntityPropertyInfo propertyInfo { makePropertyInfo<T>(P) }; \
534  _propertyInfos[#n] = propertyInfo; \
535  _enumsToPropertyStrings[P] = #n; \
536  }
537 
538 #define ADD_PROPERTY_TO_MAP_WITH_RANGE(P, n, M, X) \
539  { \
540  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \
541  _propertyInfos[#n] = propertyInfo; \
542  _enumsToPropertyStrings[P] = #n; \
543  }
544 
545 #define ADD_GROUP_PROPERTY_TO_MAP(P, g, n) \
546  { \
547  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P); \
548  _propertyInfos[#g "." #n] = propertyInfo; \
549  _propertyInfos[#g].propertyEnums << P; \
550  _enumsToPropertyStrings[P] = #g "." #n; \
551  }
552 
553 #define ADD_GROUP_PROPERTY_TO_MAP_WITH_RANGE(P, g, n, M, X) \
554  { \
555  EntityPropertyInfo propertyInfo = EntityPropertyInfo(P, M, X); \
556  _propertyInfos[#g "." #n] = propertyInfo; \
557  _propertyInfos[#g].propertyEnums << P; \
558  _enumsToPropertyStrings[P] = #g "." #n; \
559  }
560 
561 #define DEFINE_CORE(N, n, T, V) \
562  public: \
563  bool n##Changed() const { return _##n##Changed; } \
564  void set##N##Changed(bool value) { _##n##Changed = value; } \
565  private: \
566  T _##n = V; \
567  bool _##n##Changed { false };
568 
569 #define DEFINE_PROPERTY(N, n, T, V) \
570  public: \
571  T get##N() const { return _##n; } \
572  void set##N(T value) { _##n = value; _##n##Changed = true; } \
573  DEFINE_CORE(N, n, T, V)
574 
575 #define DEFINE_PROPERTY_REF(N, n, T, V) \
576  public: \
577  const T& get##N() const { return _##n; } \
578  void set##N(const T& value) { _##n = value; _##n##Changed = true; } \
579  DEFINE_CORE(N, n, T, V)
580 
581 #define DEFINE_PROPERTY_REF_WITH_SETTER(N, n, T, V) \
582  public: \
583  const T& get##N() const { return _##n; } \
584  void set##N(const T& value); \
585  DEFINE_CORE(N, n, T, V)
586 
587 #define DEFINE_PROPERTY_REF_WITH_SETTER_AND_GETTER(N, n, T, V) \
588  public: \
589  T get##N() const; \
590  void set##N(const T& value); \
591  DEFINE_CORE(N, n, T, V)
592 
593 #define DEFINE_PROPERTY_REF_ENUM(N, n, T, V) \
594  public: \
595  const T& get##N() const { return _##n; } \
596  void set##N(const T& value) { _##n = value; _##n##Changed = true; } \
597  QString get##N##AsString() const; \
598  void set##N##FromString(const QString& name); \
599  DEFINE_CORE(N, n, T, V)
600 
601 #define DEBUG_PROPERTY(D, P, N, n, x) \
602  D << " " << #n << ":" << P.get##N() << x << "[changed:" << P.n##Changed() << "]\n";
603 
604 #define DEBUG_PROPERTY_IF_CHANGED(D, P, N, n, x) \
605  if (P.n##Changed()) { \
606  D << " " << #n << ":" << P.get##N() << x << "\n"; \
607  }
608 
609 // EntityItem helpers
610 #define DEFINE_VARIABLE_NO_GETTER_SETTER(N, n, T, V) \
611  protected: \
612  T _##n = V;
613 
614 #define DEFINE_VARIABLE(N, n, T, V) \
615  public: \
616  T get##N() const; \
617  void set##N(T value); \
618  protected: \
619  T _##n = V;
620 
621 #define DEFINE_VARIABLE_REF(N, n, T, V) \
622  public: \
623  T get##N() const; \
624  void set##N(const T& value); \
625  protected: \
626  T _##n = V;
627 
628 #define DEFINE_VARIABLE_BASIC(N, n, T, V) \
629  public: \
630  T get##N() const { \
631  return resultWithReadLock<T>([&] { \
632  return _##n; \
633  }); \
634  } \
635  void set##N(T value) { \
636  withWriteLock([&] { \
637  _##n = value; \
638  }); \
639  } \
640  protected: \
641  T _##n = V;
642 
643 #define DEFINE_VARIABLE_BASIC_REF(N, n, T, V) \
644  public: \
645  T get##N() const { \
646  return resultWithReadLock<T>([&] { \
647  return _##n; \
648  }); \
649  } \
650  void set##N(const T& value) { \
651  withWriteLock([&] { \
652  _##n = value; \
653  }); \
654  } \
655  protected: \
656  T _##n = V;
657 
658 #define DEFINE_VARIABLE_RENDER(N, n, T, V) \
659  public: \
660  T get##N() const { \
661  return resultWithReadLock<T>([&] { \
662  return _##n; \
663  }); \
664  } \
665  void set##N(T value) { \
666  withWriteLock([&] { \
667  _needsRenderUpdate |= _##n != value; \
668  _##n = value; \
669  }); \
670  } \
671  protected: \
672  T _##n = V;
673 
674 #define DEFINE_VARIABLE_RENDER_REF(N, n, T, V) \
675  public: \
676  T get##N() const { \
677  return resultWithReadLock<T>([&] { \
678  return _##n; \
679  }); \
680  } \
681  void set##N(const T& value) { \
682  withWriteLock([&] { \
683  _needsRenderUpdate |= _##n != value; \
684  _##n = value; \
685  }); \
686  } \
687  protected: \
688  T _##n = V;
689 
690 #define ENTITY_PROPERTY_SUBCLASS_METHODS \
691  EntityItemProperties getProperties(const EntityPropertyFlags& desiredProperties, \
692  bool allowEmptyDesiredProperties) const override; \
693  bool setSubClassProperties(const EntityItemProperties& properties) override; \
694  EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \
695  void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params, \
696  EntityTreeElementExtraEncodeDataPointer entityTreeElementExtraEncodeData, \
697  EntityPropertyFlags& requestedProperties, \
698  EntityPropertyFlags& propertyFlags, \
699  EntityPropertyFlags& propertiesDidntFit, \
700  int& propertyCount, \
701  OctreeElement::AppendState& appendState) const override; \
702  int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \
703  ReadBitstreamToTreeParams& args, \
704  EntityPropertyFlags& propertyFlags, bool overwriteLocalData, \
705  bool& somethingChanged) override; \
706  virtual void debugDump() const override;
707 
708 #define ENTITY_PROPERTY_GROUP_METHODS(P) \
709  virtual void copyToScriptValue(const EntityPropertyFlags& desiredProperties, ScriptValue& properties, \
710  ScriptEngine* engine, bool skipDefaults, \
711  EntityItemProperties& defaultEntityProperties, \
712  bool returnNothingOnEmptyPropertyFlags, \
713  AvatarEntityOwnership ownership) const override; \
714  virtual void copyFromScriptValue(const ScriptValue& object, const QSet<QString> &namesSet, \
715  bool& _defaultSettings) override; \
716  void merge(const P& other); \
717  virtual void debugDump() const override; \
718  virtual void listChangedProperties(QList<QString>& out) override; \
719  virtual bool appendToEditPacket(OctreePacketData* packetData, \
720  EntityPropertyFlags& requestedProperties, \
721  EntityPropertyFlags& propertyFlags, \
722  EntityPropertyFlags& propertiesDidntFit, \
723  int& propertyCount, \
724  OctreeElement::AppendState& appendState) const override; \
725  virtual bool decodeFromEditPacket(EntityPropertyFlags& propertyFlags, \
726  const unsigned char*& dataAt, int& processedBytes) override; \
727  virtual void markAllChanged() override; \
728  virtual EntityPropertyFlags getChangedProperties() const override; \
729  virtual void getProperties(EntityItemProperties& propertiesOut) const override; \
730  virtual bool setProperties(const EntityItemProperties& properties) override; \
731  virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const override; \
732  virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, \
733  ReadBitstreamToTreeParams& args, \
734  EntityPropertyFlags& propertyFlags, \
735  bool overwriteLocalData, bool& somethingChanged) override; \
736  static void addPropertyMap(QHash<QString, EntityPropertyInfo>& _propertyInfos, \
737  QHash<EntityPropertyList, QString>& _enumsToPropertyStrings);
738 
739 #endif // hifi_EntityItemPropertiesMacros_h
Abstract ID for editing model items. Used in EntityItem JS API.
Definition: EntityItemID.h:28
Provides an engine-independent interface for a scripting engine.
Definition: ScriptEngine.h:93
[ScriptInterface] Provides an engine-independent interface for QScriptValue
Definition: ScriptValue.h:40