LoggingContactListener.h 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Physics/Collision/ContactListener.h>
  5. // Contact listener that just logs the calls made to it for later validation
  6. class LoggingContactListener : public ContactListener
  7. {
  8. public:
  9. // Contact callback type
  10. enum class EType
  11. {
  12. Validate,
  13. Add,
  14. Persist,
  15. Remove
  16. };
  17. // Entry written when a contact callback happens
  18. struct LogEntry
  19. {
  20. EType mType;
  21. BodyID mBody1;
  22. BodyID mBody2;
  23. ContactManifold mManifold;
  24. };
  25. virtual ValidateResult OnContactValidate(const Body &inBody1, const Body &inBody2, const CollideShapeResult &inCollisionResult) override
  26. {
  27. // Check contract that body 1 is dynamic or that body2 is not dynamic
  28. bool contract = inBody1.IsDynamic() || !inBody2.IsDynamic();
  29. CHECK(contract);
  30. lock_guard lock(mLogMutex);
  31. mLog.push_back({ EType::Validate, inBody1.GetID(), inBody2.GetID(), ContactManifold() });
  32. return ValidateResult::AcceptContact;
  33. }
  34. virtual void OnContactAdded(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  35. {
  36. // Check contract that body 1 < body 2
  37. CHECK(inBody1.GetID() < inBody2.GetID());
  38. lock_guard lock(mLogMutex);
  39. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  40. CHECK(mExistingContacts.insert(key).second); // Validate that contact does not exist yet
  41. mLog.push_back({ EType::Add, inBody1.GetID(), inBody2.GetID(), inManifold });
  42. }
  43. virtual void OnContactPersisted(const Body &inBody1, const Body &inBody2, const ContactManifold &inManifold, ContactSettings &ioSettings) override
  44. {
  45. // Check contract that body 1 < body 2
  46. CHECK(inBody1.GetID() < inBody2.GetID());
  47. lock_guard lock(mLogMutex);
  48. SubShapeIDPair key(inBody1.GetID(), inManifold.mSubShapeID1, inBody2.GetID(), inManifold.mSubShapeID2);
  49. CHECK(mExistingContacts.find(key) != mExistingContacts.end()); // Validate that OnContactAdded was called
  50. mLog.push_back({ EType::Persist, inBody1.GetID(), inBody2.GetID(), inManifold });
  51. }
  52. virtual void OnContactRemoved(const SubShapeIDPair &inSubShapePair) override
  53. {
  54. // Check contract that body 1 < body 2
  55. CHECK(inSubShapePair.GetBody1ID() < inSubShapePair.GetBody2ID());
  56. lock_guard lock(mLogMutex);
  57. CHECK(mExistingContacts.erase(inSubShapePair) == 1); // Validate that OnContactAdded was called
  58. mLog.push_back({ EType::Remove, inSubShapePair.GetBody1ID(), inSubShapePair.GetBody2ID(), ContactManifold() });
  59. }
  60. void Clear()
  61. {
  62. mLog.clear();
  63. }
  64. size_t GetEntryCount() const
  65. {
  66. return mLog.size();
  67. }
  68. const LogEntry & GetEntry(size_t inIdx) const
  69. {
  70. return mLog[inIdx];
  71. }
  72. // Find first event with a particular type and involving two particular bodies
  73. int Find(EType inType, const BodyID &inBody1, const BodyID &inBody2) const
  74. {
  75. for (size_t i = 0; i < mLog.size(); ++i)
  76. {
  77. const LogEntry &e = mLog[i];
  78. if (e.mType == inType && ((e.mBody1 == inBody1 && e.mBody2 == inBody2) || (e.mBody1 == inBody2 && e.mBody2 == inBody1)))
  79. return int(i);
  80. }
  81. return -1;
  82. }
  83. // Check if event with a particular type and involving two particular bodies exists
  84. bool Contains(EType inType, const BodyID &inBody1, const BodyID &inBody2) const
  85. {
  86. return Find(inType, inBody1, inBody2) >= 0;
  87. }
  88. private:
  89. Mutex mLogMutex; // Callbacks are made from a thread, make sure we don't corrupt the log
  90. Array<LogEntry> mLog;
  91. UnorderedSet<SubShapeIDPair> mExistingContacts; // For validation purposes: the contacts that are currently active
  92. };