ActDetectorBase.cs 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using UnityEngine;
  2. using UnityEngine.Events;
  3. public abstract class ActDetectorBase : MonoBehaviour
  4. {
  5. protected const string CONTAINER_NAME = "anticheat detectors";
  6. protected const string MENU_PATH = "poc/anticheat/";
  7. protected const string GAME_OBJECT_MENU_PATH = "GameObject/Create Other/" + MENU_PATH;
  8. protected static GameObject detectorsContainer;
  9. /// <summary>
  10. /// Allows to start detector automatically.
  11. /// Otherwise, you'll need to call StartDetection() method to start it.
  12. /// </summary>
  13. /// Useful in conjunction with proper Detection Event configuration in the inspector.
  14. /// Allows to use detector without writing any code except the actual reaction on cheating.
  15. [Tooltip("Automatically start detector. Detection Event will be called on detection.")]
  16. public bool autoStart = false;
  17. /// <summary>
  18. /// Detector will survive new level (scene) load if checked. Otherwise it will be destroyed.
  19. /// </summary>
  20. /// On dispose Detector follows 2 rules:
  21. /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically
  22. /// destroyed if no other Detectors left attached regardless of any other components or children;<br/>
  23. /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only
  24. /// if it has neither other components nor children attached;
  25. [Tooltip("Detector will survive new level (scene) load if checked.")]
  26. public bool keepAlive = true;
  27. /// <summary>
  28. /// Detector component will be automatically disposed after firing callback if enabled.
  29. /// Otherwise, it will just stop internal processes.
  30. /// </summary>
  31. /// On dispose Detector follows 2 rules:
  32. /// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically
  33. /// destroyed if no other Detectors left attached regardless of any other components or children;<br/>
  34. /// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only
  35. /// if it has neither other components nor children attached;
  36. [Tooltip("Automatically dispose Detector after firing callback.")]
  37. public bool autoDispose = true;
  38. [SerializeField]
  39. protected UnityEvent detectionEvent = null;
  40. protected UnityAction detectionAction = null;
  41. [SerializeField]
  42. protected bool detectionEventHasListener = false;
  43. protected bool isRunning;
  44. protected bool started;
  45. #region detectors placement
  46. #if UNITY_EDITOR
  47. /*[UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + "All detectors", false, 0)]
  48. private static void AddAllDetectorsToScene()
  49. {
  50. AddInjectionDetectorToScene();
  51. AddSpeedHackDetectorToScene();
  52. }
  53. [UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + InjectionDetector.COMPONENT_NAME, false, 1)]
  54. private static void AddInjectionDetectorToScene()
  55. {
  56. SetupDetectorInScene<InjectionDetector>();
  57. }
  58. [UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + SpeedHackDetector.COMPONENT_NAME, false, 1)]
  59. private static void AddSpeedHackDetectorToScene()
  60. {
  61. SetupDetectorInScene<SpeedHackDetector>();
  62. }*/
  63. static void SetupDetectorInScene<T>() where T : ActDetectorBase
  64. {
  65. T component = FindObjectOfType<T>();
  66. string detectorName = typeof(T).Name;
  67. if(component !=null)
  68. {
  69. if(component.gameObject.name == CONTAINER_NAME)
  70. {
  71. UnityEditor.EditorUtility.DisplayDialog(detectorName + " already exists!", detectorName + " already exists in scene and correctly placed on object \"" + CONTAINER_NAME + "\"", "OK");
  72. }
  73. else
  74. {
  75. int dialogResult = UnityEditor.EditorUtility.DisplayDialogComplex(detectorName + " already exists!", detectorName + " already exists in scene and placed on object \"" + component.gameObject.name + "\". Do you wish to move it to the Game Object \"" + CONTAINER_NAME + "\" or delete it from scene at all?", "Move", "Delete", "Cancel");
  76. switch (dialogResult)
  77. {
  78. case 0:
  79. GameObject container = GameObject.Find(CONTAINER_NAME);
  80. if (container == null)
  81. {
  82. container = new GameObject(CONTAINER_NAME);
  83. }
  84. T newComponent = container.AddComponent<T>();
  85. UnityEditor.EditorUtility.CopySerialized(component, newComponent);
  86. DestroyDetectorImmediate(component);
  87. break;
  88. case 1:
  89. DestroyDetectorImmediate(component);
  90. break;
  91. }
  92. }
  93. }else
  94. {
  95. GameObject container = GameObject.Find(CONTAINER_NAME);
  96. if (container == null)
  97. {
  98. container = new GameObject(CONTAINER_NAME);
  99. UnityEditor.Undo.RegisterCreatedObjectUndo(container, "Create " + CONTAINER_NAME);
  100. }
  101. UnityEditor.Undo.AddComponent<T>(container);
  102. UnityEditor.EditorUtility.DisplayDialog(detectorName + " added!", detectorName + " successfully added to the object \"" + CONTAINER_NAME + "\"", "OK");
  103. }
  104. }
  105. static void DestroyDetectorImmediate(ActDetectorBase component)
  106. {
  107. if (component.transform.childCount == 0 && component.GetComponentsInChildren<Component>(true).Length <= 2)
  108. {
  109. DestroyImmediate(component.gameObject);
  110. }
  111. else
  112. {
  113. DestroyImmediate(component);
  114. }
  115. }
  116. #endif
  117. #endregion
  118. #region UNITY_MESSAGES
  119. private void Start()
  120. {
  121. if (detectorsContainer == null && gameObject.name == CONTAINER_NAME)
  122. {
  123. detectorsContainer = gameObject;
  124. }
  125. if (autoStart && !started)
  126. {
  127. StartDetectionAutomatically();
  128. }
  129. }
  130. private void OnEnable()
  131. {
  132. if (!started || (!detectionEventHasListener && detectionAction == null))
  133. return;
  134. ResumeDetector();
  135. }
  136. private void OnDisable()
  137. {
  138. if (!started) return;
  139. PauseDetector();
  140. }
  141. private void OnApplicationQuit()
  142. {
  143. DisposeInternal();
  144. }
  145. protected virtual void OnDestroy()
  146. {
  147. StopDetectionInternal();
  148. if (transform.childCount == 0 && GetComponentsInChildren<Component>().Length <= 2)
  149. {
  150. Destroy(gameObject);
  151. }
  152. else if (name == CONTAINER_NAME && GetComponentsInChildren<ActDetectorBase>().Length <= 1)
  153. {
  154. Destroy(gameObject);
  155. }
  156. }
  157. #endregion
  158. protected virtual bool Init(ActDetectorBase instance, string detectorName)
  159. {
  160. if (instance != null && instance != this && instance.keepAlive)
  161. {
  162. Destroy(this);
  163. return false;
  164. }
  165. DontDestroyOnLoad(gameObject);
  166. return true;
  167. }
  168. protected virtual void DisposeInternal()
  169. {
  170. Destroy(this);
  171. }
  172. internal virtual void OnCheatingDetected()
  173. {
  174. if (detectionAction != null) detectionAction();
  175. if (detectionEventHasListener) detectionEvent.Invoke();
  176. //if (autoDispose)
  177. //{
  178. // DisposeInternal();
  179. //}
  180. //else
  181. //{
  182. // StopDetectionInternal();
  183. //}
  184. }
  185. protected abstract void StartDetectionAutomatically();
  186. protected abstract void StopDetectionInternal();
  187. protected abstract void PauseDetector();
  188. protected abstract void ResumeDetector();
  189. }