ro-webgl/Assets/Src/SecureDetector/ActDetectorBase.cs
2021-12-21 09:40:39 +08:00

222 lines
7.7 KiB
C#

using UnityEngine;
using UnityEngine.Events;
public abstract class ActDetectorBase : MonoBehaviour
{
protected const string CONTAINER_NAME = "anticheat detectors";
protected const string MENU_PATH = "poc/anticheat/";
protected const string GAME_OBJECT_MENU_PATH = "GameObject/Create Other/" + MENU_PATH;
protected static GameObject detectorsContainer;
/// <summary>
/// Allows to start detector automatically.
/// Otherwise, you'll need to call StartDetection() method to start it.
/// </summary>
/// Useful in conjunction with proper Detection Event configuration in the inspector.
/// Allows to use detector without writing any code except the actual reaction on cheating.
[Tooltip("Automatically start detector. Detection Event will be called on detection.")]
public bool autoStart = false;
/// <summary>
/// Detector will survive new level (scene) load if checked. Otherwise it will be destroyed.
/// </summary>
/// On dispose Detector follows 2 rules:
/// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically
/// destroyed if no other Detectors left attached regardless of any other components or children;<br/>
/// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only
/// if it has neither other components nor children attached;
[Tooltip("Detector will survive new level (scene) load if checked.")]
public bool keepAlive = true;
/// <summary>
/// Detector component will be automatically disposed after firing callback if enabled.
/// Otherwise, it will just stop internal processes.
/// </summary>
/// On dispose Detector follows 2 rules:
/// - if Game Object's name is "Anti-Cheat Toolkit Detectors": it will be automatically
/// destroyed if no other Detectors left attached regardless of any other components or children;<br/>
/// - if Game Object's name is NOT "Anti-Cheat Toolkit Detectors": it will be automatically destroyed only
/// if it has neither other components nor children attached;
[Tooltip("Automatically dispose Detector after firing callback.")]
public bool autoDispose = true;
[SerializeField]
protected UnityEvent detectionEvent = null;
protected UnityAction detectionAction = null;
[SerializeField]
protected bool detectionEventHasListener = false;
protected bool isRunning;
protected bool started;
#region detectors placement
#if UNITY_EDITOR
/*[UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + "All detectors", false, 0)]
private static void AddAllDetectorsToScene()
{
AddInjectionDetectorToScene();
AddSpeedHackDetectorToScene();
}
[UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + InjectionDetector.COMPONENT_NAME, false, 1)]
private static void AddInjectionDetectorToScene()
{
SetupDetectorInScene<InjectionDetector>();
}
[UnityEditor.MenuItem(GAME_OBJECT_MENU_PATH + SpeedHackDetector.COMPONENT_NAME, false, 1)]
private static void AddSpeedHackDetectorToScene()
{
SetupDetectorInScene<SpeedHackDetector>();
}*/
static void SetupDetectorInScene<T>() where T : ActDetectorBase
{
T component = FindObjectOfType<T>();
string detectorName = typeof(T).Name;
if(component !=null)
{
if(component.gameObject.name == CONTAINER_NAME)
{
UnityEditor.EditorUtility.DisplayDialog(detectorName + " already exists!", detectorName + " already exists in scene and correctly placed on object \"" + CONTAINER_NAME + "\"", "OK");
}
else
{
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");
switch (dialogResult)
{
case 0:
GameObject container = GameObject.Find(CONTAINER_NAME);
if (container == null)
{
container = new GameObject(CONTAINER_NAME);
}
T newComponent = container.AddComponent<T>();
UnityEditor.EditorUtility.CopySerialized(component, newComponent);
DestroyDetectorImmediate(component);
break;
case 1:
DestroyDetectorImmediate(component);
break;
}
}
}else
{
GameObject container = GameObject.Find(CONTAINER_NAME);
if (container == null)
{
container = new GameObject(CONTAINER_NAME);
UnityEditor.Undo.RegisterCreatedObjectUndo(container, "Create " + CONTAINER_NAME);
}
UnityEditor.Undo.AddComponent<T>(container);
UnityEditor.EditorUtility.DisplayDialog(detectorName + " added!", detectorName + " successfully added to the object \"" + CONTAINER_NAME + "\"", "OK");
}
}
static void DestroyDetectorImmediate(ActDetectorBase component)
{
if (component.transform.childCount == 0 && component.GetComponentsInChildren<Component>(true).Length <= 2)
{
DestroyImmediate(component.gameObject);
}
else
{
DestroyImmediate(component);
}
}
#endif
#endregion
#region UNITY_MESSAGES
private void Start()
{
if (detectorsContainer == null && gameObject.name == CONTAINER_NAME)
{
detectorsContainer = gameObject;
}
if (autoStart && !started)
{
StartDetectionAutomatically();
}
}
private void OnEnable()
{
if (!started || (!detectionEventHasListener && detectionAction == null))
return;
ResumeDetector();
}
private void OnDisable()
{
if (!started) return;
PauseDetector();
}
private void OnApplicationQuit()
{
DisposeInternal();
}
protected virtual void OnDestroy()
{
StopDetectionInternal();
if (transform.childCount == 0 && GetComponentsInChildren<Component>().Length <= 2)
{
Destroy(gameObject);
}
else if (name == CONTAINER_NAME && GetComponentsInChildren<ActDetectorBase>().Length <= 1)
{
Destroy(gameObject);
}
}
#endregion
protected virtual bool Init(ActDetectorBase instance, string detectorName)
{
if (instance != null && instance != this && instance.keepAlive)
{
Destroy(this);
return false;
}
DontDestroyOnLoad(gameObject);
return true;
}
protected virtual void DisposeInternal()
{
Destroy(this);
}
internal virtual void OnCheatingDetected()
{
if (detectionAction != null) detectionAction();
if (detectionEventHasListener) detectionEvent.Invoke();
//if (autoDispose)
//{
// DisposeInternal();
//}
//else
//{
// StopDetectionInternal();
//}
}
protected abstract void StartDetectionAutomatically();
protected abstract void StopDetectionInternal();
protected abstract void PauseDetector();
protected abstract void ResumeDetector();
}