프로젝트 세팅 중
This commit is contained in:
parent
b0a7d91e8e
commit
a703835aef
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 998de5b9fe51f3848967851e68354d90
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,378 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Callbacks;
|
||||
#if UNITY_ANDROID
|
||||
#elif UNITY_IOS
|
||||
using UnityEditor.iOS.Xcode;
|
||||
using UnityEditor.iOS.Xcode.Extensions;
|
||||
using Facebook.Unity.Settings;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
public static class AutoBuild
|
||||
{
|
||||
static string path_dev = "AndroidData/mysticatshop_Test_";
|
||||
static string path_dev_onestore = "AndroidData/mysticatshop_Test_OneStore_";
|
||||
static string path_live = "AndroidData/mysticatshop_Live_";
|
||||
static string path_live_onestore = "AndroidData/mysticatshop_Live_OneStore";
|
||||
|
||||
// 툴씬 이름 목록
|
||||
private static readonly string[] toolScenes =
|
||||
{
|
||||
"96_Tool_MobScale",
|
||||
"97_Tool_Effect",
|
||||
"98_Tool_Mob",
|
||||
"99_Tool"
|
||||
};
|
||||
private static List<EditorBuildSettingsScene> backupScenes;
|
||||
|
||||
static void Common(BuildTargetGroup _btg, BuildTarget _bt)
|
||||
{
|
||||
// 씬 빼기
|
||||
backupScenes = EditorBuildSettings.scenes.ToList();
|
||||
var filtered = backupScenes
|
||||
.Where(scene => !toolScenes.Any(tool => scene.path.Contains(tool)))
|
||||
.ToList();
|
||||
EditorBuildSettings.scenes = filtered.ToArray();
|
||||
|
||||
PlayerSettings.applicationIdentifier = "com.nerdnavis.mysticatshop";
|
||||
EditorUserBuildSettings.SwitchActiveBuildTarget(_btg, _bt);
|
||||
|
||||
if (_bt == BuildTarget.Android)
|
||||
{
|
||||
PlayerSettings.Android.splitApplicationBinary = false;
|
||||
File.WriteAllText("Assets/Resources/VersionCode.txt", PlayerSettings.Android.bundleVersionCode.ToString());
|
||||
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARMv7 | AndroidArchitecture.ARM64;
|
||||
}
|
||||
else
|
||||
{
|
||||
File.WriteAllText("Assets/Resources/VersionCode.txt", PlayerSettings.iOS.buildNumber);
|
||||
PlayerSettings.iOS.appleDeveloperTeamID = "788PYWMPC6"; // 필굿밴디츠
|
||||
//PlayerSettings.iOS.appleDeveloperTeamID = "A9997B8HR5"; // 나인탭
|
||||
PlayerSettings.iOS.appleEnableAutomaticSigning = true;
|
||||
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.DeviceSDK;
|
||||
}
|
||||
}
|
||||
static void Common_End()
|
||||
{
|
||||
// 씬 넣기
|
||||
if (backupScenes != null)
|
||||
{
|
||||
EditorBuildSettings.scenes = backupScenes.ToArray();
|
||||
}
|
||||
EmptySymbol();
|
||||
}
|
||||
|
||||
static void Show_BuildFolder(BuildTarget _bt)
|
||||
{
|
||||
if (_bt == BuildTarget.Android) System.Diagnostics.Process.Start("AndroidData");
|
||||
else System.Diagnostics.Process.Start("IOSData");
|
||||
}
|
||||
static void BuildStart(string path, BuildTarget _bt)
|
||||
{
|
||||
BuildPipeline.BuildPlayer(EditorBuildSettings.scenes, path, _bt, BuildOptions.None);
|
||||
Show_BuildFolder(_bt);
|
||||
}
|
||||
#if UNITY_ANDROID
|
||||
[MenuItem("AutoBuild/EmptySymbol")]
|
||||
static void EmptySymbol()
|
||||
{
|
||||
PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.Android, "");
|
||||
}
|
||||
[MenuItem("AutoBuild/Set_AndroidKeyStore")]
|
||||
static void Set_AndroidKeyStore()
|
||||
{
|
||||
PlayerSettings.Android.useCustomKeystore = true;
|
||||
PlayerSettings.Android.keystoreName = "AndroidData/mysticatshop.keystore";
|
||||
PlayerSettings.Android.keyaliasName = "nerdnavis";
|
||||
PlayerSettings.Android.keystorePass = PlayerSettings.Android.keyaliasPass = "nerdnavis!!098";
|
||||
}
|
||||
[MenuItem("AutoBuild/Set_OneStoreKeyStore")]
|
||||
static void Set_OneStoreKeyStore()
|
||||
{
|
||||
PlayerSettings.Android.useCustomKeystore = true;
|
||||
PlayerSettings.Android.keystoreName = "AndroidData/mysticatshop_One.keystore";
|
||||
PlayerSettings.Android.keyaliasName = "nerdnavis";
|
||||
PlayerSettings.Android.keystorePass = PlayerSettings.Android.keyaliasPass = "nerdnavis!!098";
|
||||
}
|
||||
[MenuItem("AutoBuild/Build APK with KeyStore")]
|
||||
static void Build_APK_with_KeyStore()
|
||||
{
|
||||
Common(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
Set_AndroidKeyStore();
|
||||
//PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel23;
|
||||
|
||||
var curVer = PlayerSettings.bundleVersion;
|
||||
PlayerSettings.bundleVersion = "9.9.9";
|
||||
EditorUserBuildSettings.buildAppBundle = false;
|
||||
BuildStart(path_dev + Application.version + "_(" + PlayerSettings.Android.bundleVersionCode + ").apk", BuildTarget.Android);
|
||||
PlayerSettings.bundleVersion = curVer;
|
||||
Common_End();
|
||||
}
|
||||
[MenuItem("AutoBuild/Build APK with KeyStore (OneStore)")]
|
||||
static void Build_APK_OneStore()
|
||||
{
|
||||
Common(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
Set_OneStoreKeyStore();
|
||||
//PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel23;
|
||||
|
||||
EditorUserBuildSettings.buildAppBundle = false;
|
||||
BuildStart(path_dev_onestore + Application.version + "_(" + PlayerSettings.Android.bundleVersionCode + ").apk", BuildTarget.Android);
|
||||
Common_End();
|
||||
}
|
||||
[MenuItem("AutoBuild/Build Live AAB")]
|
||||
static void Build_AAB()
|
||||
{
|
||||
++PlayerSettings.Android.bundleVersionCode;
|
||||
Common(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
Set_AndroidKeyStore();
|
||||
|
||||
PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.Android, "");
|
||||
EditorUserBuildSettings.buildAppBundle = true;
|
||||
BuildStart(path_live + Application.version + "_(" + PlayerSettings.Android.bundleVersionCode + ").aab", BuildTarget.Android);
|
||||
Common_End();
|
||||
//if (EditorUtility.DisplayDialog("라이브 빌드", "현재 버전 : " + PlayerSettings.bundleVersion + " " + PlayerSettings.Android.bundleVersionCode.ToString(), "OK", "Not Build"))
|
||||
// AppBundlePublisher.Build();
|
||||
}
|
||||
[MenuItem("AutoBuild/Build Live AAB (OneStore)")]
|
||||
static void Build_AAB_OneStore()
|
||||
{
|
||||
++PlayerSettings.Android.bundleVersionCode;
|
||||
Common(BuildTargetGroup.Android, BuildTarget.Android);
|
||||
Set_OneStoreKeyStore();
|
||||
|
||||
PlayerSettings.SetScriptingDefineSymbols(UnityEditor.Build.NamedBuildTarget.Android, "");
|
||||
EditorUserBuildSettings.buildAppBundle = true;
|
||||
BuildStart(path_live_onestore + Application.version + "_(" + PlayerSettings.Android.bundleVersionCode + ").aab", BuildTarget.Android);
|
||||
Common_End();
|
||||
//if (EditorUtility.DisplayDialog("라이브 빌드", "현재 버전 : " + PlayerSettings.bundleVersion + " " + PlayerSettings.Android.bundleVersionCode.ToString(), "OK", "Not Build"))
|
||||
// AppBundlePublisher.Build();
|
||||
}
|
||||
#endif
|
||||
#if UNITY_IOS
|
||||
[MenuItem("AutoBuild/IOS Xcode")]
|
||||
static void Build_IOS_Xcode()
|
||||
{
|
||||
PlayerSettings.iOS.buildNumber = (int.Parse(PlayerSettings.iOS.buildNumber) + 1).ToString();
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, "FGB_LIVE");
|
||||
Common(BuildTargetGroup.iOS, BuildTarget.iOS);
|
||||
|
||||
BuildStart("IOSData/IOSXcodeLive_" + Application.version + "_" + PlayerSettings.iOS.buildNumber, BuildTarget.iOS);
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, "");
|
||||
}
|
||||
[MenuItem("AutoBuild/IOS Xcode Test")]
|
||||
static void Build_IOS_Xcode_Test()
|
||||
{
|
||||
PlayerSettings.iOS.buildNumber = (int.Parse(PlayerSettings.iOS.buildNumber) + 1).ToString();
|
||||
Common(BuildTargetGroup.iOS, BuildTarget.iOS);
|
||||
|
||||
BuildStart("IOSData/IOSSRDebugOn_" + Application.version + "_" + PlayerSettings.iOS.buildNumber, BuildTarget.iOS);
|
||||
}
|
||||
[MenuItem("AutoBuild/Test IOS Simulator")]
|
||||
static void Build_Test_IOS_Simulator()
|
||||
{
|
||||
Common(BuildTargetGroup.iOS, BuildTarget.iOS);
|
||||
PlayerSettings.iOS.sdkVersion = iOSSdkVersion.SimulatorSDK;
|
||||
|
||||
BuildStart("IOSData/IOSTestBuild_" + Application.version + "_" + PlayerSettings.iOS.buildNumber, BuildTarget.iOS);
|
||||
}
|
||||
#endif
|
||||
|
||||
[PostProcessBuild(1)]
|
||||
static void OnPostProcessBuild(BuildTarget buildTarget, string path)
|
||||
{
|
||||
if (buildTarget == BuildTarget.iOS)
|
||||
{
|
||||
#if UNITY_IOS
|
||||
Debug.Log("OnPostProcessBuild : " + path);
|
||||
|
||||
var plistPath = Path.Combine(path, "Info.plist");
|
||||
var plist = new PlistDocument();
|
||||
plist.ReadFromFile(plistPath);
|
||||
|
||||
PlistElementDict allowsDict = plist.root.CreateDict("NSAppTransportSecurity");
|
||||
allowsDict.SetBoolean("NSAllowsArbitraryLoads", true);
|
||||
PlistElementDict exceptionsDict = allowsDict.CreateDict("NSExceptionDomains");
|
||||
PlistElementDict domainDict = exceptionsDict.CreateDict("amazonaws.com");
|
||||
domainDict.SetBoolean("NSExceptionAllowsInsecureHTTPLoads", true);
|
||||
domainDict.SetBoolean("NSIncludesSubdomains", true);
|
||||
domainDict = exceptionsDict.CreateDict("inonotebook.iptime.org");
|
||||
domainDict.SetBoolean("NSExceptionAllowsInsecureHTTPLoads", true);
|
||||
domainDict.SetBoolean("NSIncludesSubdomains", true);
|
||||
|
||||
plist.root.SetBoolean("GADIsAdManagerApp", true);
|
||||
plist.root.SetBoolean("FirebaseMessagingAutoInitEnabled", false);
|
||||
plist.root.SetBoolean("FirebaseAppStoreReceiptURLCheckEnabled", false);
|
||||
plist.root.SetBoolean("ITSAppUsesNonExemptEncryption", false);
|
||||
plist.root.SetString("NSAdvertisingAttributionReportEndpoint", "https://appsflyer-skadnetwork.com/");
|
||||
|
||||
// Add string setting
|
||||
// SKAdNetwork IDs integration(for iOS14+)
|
||||
var arraySKAdNetworkItems = plist.root.CreateArray("SKAdNetworkItems");
|
||||
foreach (string id in SKAdNetworkIdentifiers)
|
||||
{
|
||||
var dict = arraySKAdNetworkItems.AddDict();
|
||||
dict.SetString("SKAdNetworkIdentifier", id);
|
||||
}
|
||||
|
||||
plist.root.SetString("FacebookAppID", FacebookSettings.AppId);
|
||||
plist.root.SetString("FacebookDisplayName", Application.productName);
|
||||
// Add URL Scheme
|
||||
var array = plist.root.CreateArray("CFBundleURLTypes");
|
||||
var urlDict = array.AddDict();
|
||||
urlDict.SetString("CFBundleURLName", Application.identifier);
|
||||
var urlInnerArray = urlDict.CreateArray("CFBundleURLSchemes");
|
||||
urlInnerArray.AddString("fb" + FacebookSettings.AppId);
|
||||
var googleiosurlscheme = urlDict.CreateArray("CFBundleURLSchemes");
|
||||
googleiosurlscheme.AddString("com.googleusercontent.apps.107333004578-n74n1eaap2bgtg2od6ia1vk4ls5c139j");
|
||||
|
||||
var fbArray = plist.root.CreateArray("LSApplicationQueriesSchemes");
|
||||
fbArray.AddString("fbapi");
|
||||
fbArray.AddString("fb-messenger-api");
|
||||
fbArray.AddString("fbauth2");
|
||||
fbArray.AddString("fbshareextension");
|
||||
|
||||
plist.WriteToFile(plistPath);
|
||||
|
||||
// get project info
|
||||
string pbxPath = PBXProject.GetPBXProjectPath(path);
|
||||
var proj = new PBXProject();
|
||||
proj.ReadFromFile(pbxPath);
|
||||
var guid = proj.GetUnityMainTargetGuid();
|
||||
var unitytest = proj.TargetGuidByName(PBXProject.GetUnityTestTargetName());
|
||||
var unityframework = proj.GetUnityFrameworkTargetGuid();
|
||||
|
||||
proj.AddBuildProperty(guid, "OTHER_LDFLAGS", "-lc++");
|
||||
proj.SetBuildProperty(guid, "ENABLE_BITCODE", "NO");
|
||||
proj.SetBuildProperty(guid, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "YES");
|
||||
proj.SetBuildProperty(unitytest, "ENABLE_BITCODE", "NO");
|
||||
proj.SetBuildProperty(unityframework, "ENABLE_BITCODE", "NO");
|
||||
proj.SetBuildProperty(unityframework, "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", "NO");
|
||||
|
||||
// Add Push framework
|
||||
proj.AddFrameworkToProject(guid, "UserNotifications.framework", false);
|
||||
|
||||
proj.WriteToFile(pbxPath);
|
||||
|
||||
// get entitlements path
|
||||
string[] idArray = Application.identifier.Split('.');
|
||||
var entitlementsPath = $"Unity-iPhone/{idArray[idArray.Length - 1]}.entitlements";
|
||||
|
||||
// create capabilities manager
|
||||
var capManager = new ProjectCapabilityManager(pbxPath, entitlementsPath, null, guid);
|
||||
|
||||
// Add necessary capabilities
|
||||
capManager.AddPushNotifications(true);
|
||||
capManager.AddSignInWithApple();
|
||||
capManager.AddBackgroundModes(BackgroundModesOptions.RemoteNotifications);
|
||||
|
||||
// Write to file
|
||||
capManager.WriteToFile();
|
||||
|
||||
Debug.Log("OnPostProcessBuild end");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
[PostProcessBuild(45)]//must be between 40 and 50 to ensure that it's not overriden by Podfile generation (40) and that it's added before "pod install" (50)
|
||||
public static void FixPodFile(BuildTarget buildTarget, string buildPath)
|
||||
{
|
||||
if (buildTarget != BuildTarget.iOS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
Debug.Log("FixPodFile");
|
||||
using (StreamWriter sw = File.AppendText(buildPath + "/Podfile"))
|
||||
{
|
||||
sw.WriteLine("post_install do |installer|");
|
||||
sw.WriteLine("installer.generated_projects.each do |project|");
|
||||
sw.WriteLine("project.targets.each do |target|");
|
||||
sw.WriteLine("target.build_configurations.each do |config|");
|
||||
sw.WriteLine("config.build_settings[\"DEVELOPMENT_TEAM\"] = \"788PYWMPC6\"");
|
||||
sw.WriteLine("end\nend\nend\nend");
|
||||
}
|
||||
|
||||
//string podfilePath = Path.Combine(buildPath, "Podfile");
|
||||
//if (File.Exists(podfilePath))
|
||||
//{
|
||||
// string[] lines = File.ReadAllLines(podfilePath);
|
||||
// for (int i = 0; i < lines.Length; i++)
|
||||
// {
|
||||
// if (lines[i].Contains("Firebase/Auth"))
|
||||
// lines[i] = " pod 'Firebase/Auth', '10.28.1'";
|
||||
// else if (lines[i].Contains("GoogleSignIn"))
|
||||
// lines[i] = " pod 'GoogleSignIn', '5.0.0'";
|
||||
// else if (lines[i].Contains("GTMSessionFetcher/Core'"))
|
||||
// lines[i] = " pod 'GTMSessionFetcher/Core'', '2.1'";
|
||||
// }
|
||||
// File.WriteAllLines(podfilePath, lines);
|
||||
//}
|
||||
}
|
||||
|
||||
private static readonly string[] SKAdNetworkIdentifiers = new string[]
|
||||
{
|
||||
"v9wttpbfk9.skadnetwork",
|
||||
"n38lu8286q.skadnetwork",
|
||||
"su67r6k2v3.skadnetwork",
|
||||
"9t245vhmpl.skadnetwork",
|
||||
"m8dbw4sv7c.skadnetwork",
|
||||
"tl55sbb4fm.skadnetwork",
|
||||
"wzmmz9fp6w.skadnetwork",
|
||||
"4fzdc2evr5.skadnetwork",
|
||||
"294l99pt4k.skadnetwork",
|
||||
"4w7y6s5ca2.skadnetwork",
|
||||
"7ug5zh24hu.skadnetwork",
|
||||
"5l3tpt7t6e.skadnetwork",
|
||||
"t38b2kh725.skadnetwork",
|
||||
"c6k4g5qg8m.skadnetwork",
|
||||
"wg4vff78zm.skadnetwork",
|
||||
"v72qych5uu.skadnetwork",
|
||||
"mp6xlyr22a.skadnetwork",
|
||||
"cstr6suwn9.skadnetwork",
|
||||
"4pfyvq9l8r.skadnetwork",
|
||||
"w9q455wk68.skadnetwork",
|
||||
"44jx6755aq.skadnetwork",
|
||||
"k6y4y55b64.skadnetwork",
|
||||
"8s468mfl3y.skadnetwork",
|
||||
"mlmmfzh3r3.skadnetwork",
|
||||
"4dzt52r2t5.skadnetwork",
|
||||
"ydx93a7ass.skadnetwork",
|
||||
"3qy4746246.skadnetwork",
|
||||
"prcb7njmu6.skadnetwork",
|
||||
"v79kvwwj4g.skadnetwork",
|
||||
"glqzh8vgby.skadnetwork",
|
||||
"s39g8k73mm.skadnetwork",
|
||||
"238da6jt44.skadnetwork",
|
||||
"424m5254lk.skadnetwork",
|
||||
"5a6flpkh64.skadnetwork",
|
||||
"hs6bdukanm.skadnetwork",
|
||||
"x44k69ngh6.skadnetwork",
|
||||
"a8cz6cu7e5.skadnetwork",
|
||||
"488r3q3dtq.skadnetwork",
|
||||
"32z4fx6l9h.skadnetwork",
|
||||
"22mmun2rn5.skadnetwork",
|
||||
"3rd42ekr43.skadnetwork",
|
||||
"6yxyv74ff7.skadnetwork",
|
||||
"ppxm28t8ap.skadnetwork",
|
||||
"lr83yxwka7.skadnetwork",
|
||||
"578prtvx9j.skadnetwork",
|
||||
"a2p9lx4jpn.skadnetwork",
|
||||
"av6w8kgt66.skadnetwork",
|
||||
"4468km3ulz.skadnetwork",
|
||||
"9rd848q2bz.skadnetwork",
|
||||
"5lm9lj6jb7.skadnetwork",
|
||||
"f7s53z58qe.skadnetwork",
|
||||
"k674qkevps.skadnetwork",
|
||||
"kbd757ywx3.skadnetwork",
|
||||
"yclnxrl5pm.skadnetwork",
|
||||
"zq492l623r.skadnetwork",
|
||||
"zmvfpc5aq8.skadnetwork",
|
||||
"f73kdq92p3.skadnetwork",
|
||||
"f38h382jlk.skadnetwork",
|
||||
"2u9pt9hc89.skadnetwork",
|
||||
"5tjdwbrq8w.skadnetwork",
|
||||
"3sh42y64q3.skadnetwork",
|
||||
"9nlqeag3gk.skadnetwork"
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e7f08087432fca54d824025a36d4f1aa
|
||||
|
|
@ -0,0 +1,506 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.AI;
|
||||
|
||||
public static class MyEditorUtil
|
||||
{
|
||||
struct TransformData
|
||||
{
|
||||
public Vector3 localPosition;
|
||||
public Quaternion localRotation;
|
||||
public Vector3 localScale;
|
||||
|
||||
public TransformData(Vector3 localPosition, Quaternion localRotation, Vector3 localScale)
|
||||
{
|
||||
this.localPosition = localPosition;
|
||||
this.localRotation = localRotation;
|
||||
this.localScale = localScale;
|
||||
}
|
||||
}
|
||||
private static TransformData _data;
|
||||
|
||||
[MenuItem("Edit/Copy Transform Values &%#q", false, -101)]
|
||||
public static void CopyTransformValues()
|
||||
{
|
||||
if (Selection.gameObjects.Length == 0) return;
|
||||
var selectionTr = Selection.gameObjects[0].transform;
|
||||
_data = new TransformData(selectionTr.localPosition, selectionTr.localRotation, selectionTr.localScale);
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Paste Transform Values &%#w", false, -101)]
|
||||
public static void PasteTransformValues()
|
||||
{
|
||||
foreach (var selection in Selection.gameObjects)
|
||||
{
|
||||
Transform selectionTr = selection.transform;
|
||||
Undo.RecordObject(selectionTr, "Paste Transform Values");
|
||||
selectionTr.localPosition = _data.localPosition;
|
||||
selectionTr.localRotation = _data.localRotation;
|
||||
selectionTr.localScale = _data.localScale;
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Del All Child", false, -102)]
|
||||
public static void DelAllChild()
|
||||
{
|
||||
foreach (var selection in Selection.gameObjects)
|
||||
{
|
||||
Transform selectionTr = selection.transform;
|
||||
for (int i = 0; i < selectionTr.childCount; i++)
|
||||
{
|
||||
GameObject.DestroyImmediate(selectionTr.GetChild(i).gameObject);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Edit/Set Mob Data", false, -103)]
|
||||
public static void SetMobData()
|
||||
{ // 설정된 몹 프리팹을 지우고 몹 데이터만 남긴다. 해당 데이터로 게임 내에서 몹을 동적 로딩한다.
|
||||
//foreach (var selection in Selection.gameObjects)
|
||||
//{
|
||||
// var mobs = selection.GetComponentsInChildren<Actor>();
|
||||
// var dic_wave = new Dictionary<string, LoadMobData>();
|
||||
// for (int i = 0; i < mobs.Length; i++)
|
||||
// {
|
||||
// var parent = mobs[i].transform.parent;
|
||||
// if (!dic_wave.ContainsKey(parent.name))
|
||||
// {
|
||||
// var loaddata = parent.GetComponent<LoadMobData>();
|
||||
// if (loaddata == null) loaddata = parent.gameObject.AddComponent<LoadMobData>();
|
||||
// dic_wave.Add(parent.name, loaddata);
|
||||
// }
|
||||
|
||||
// var detaildata = new LoadMobDetailData
|
||||
// {
|
||||
// m_Position = mobs[i].transform.position,
|
||||
// m_Rotation = mobs[i].transform.rotation,
|
||||
// m_Role = mobs[i].m_Role,
|
||||
// m_SubRole = mobs[i].m_SubRole,
|
||||
// m_MagicID = (mobs[i] as MobActor).MagicID,
|
||||
// };
|
||||
|
||||
// if (mobs[i].name.Contains("("))
|
||||
// {
|
||||
// var split = mobs[i].name.Split(' ');
|
||||
// detaildata.m_PrefabName = "";
|
||||
// if (split.Length == 2)
|
||||
// detaildata.m_PrefabName = split[0];
|
||||
// else
|
||||
// for (int j = 0; j < split.Length - 1; j++)
|
||||
// {
|
||||
// if (j == split.Length - 2)
|
||||
// detaildata.m_PrefabName += split[j];
|
||||
// else
|
||||
// detaildata.m_PrefabName += split[j] + " ";
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// detaildata.m_PrefabName = mobs[i].name;
|
||||
|
||||
// var witch = mobs[i] as WitchEnemyActor;
|
||||
// if (witch != null)
|
||||
// detaildata.list_MagicID = witch.list_MagicID;
|
||||
|
||||
// dic_wave[parent.name].list_mobdata.Add(detaildata);
|
||||
// GameObject.DestroyImmediate(mobs[i].gameObject);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
[MenuItem("Edit/GetFolderFileNames", false, -105)]
|
||||
public static void GetFolderFileNames()
|
||||
{
|
||||
DirectoryInfo di = new DirectoryInfo("Assets/ResWork/UIPrefabs/Title");
|
||||
var ext = ".prefab"; // ".mat";
|
||||
|
||||
var filenames = "";
|
||||
foreach (FileInfo file in di.GetFiles("*" + ext))
|
||||
filenames += file.Name.Replace(ext, "") + "\n";
|
||||
Debug.Log(filenames);
|
||||
}
|
||||
|
||||
private static List<ObjectSettings> objectSettingsList = new List<ObjectSettings>();
|
||||
|
||||
[MenuItem("Edit/MobSetting &s", false, -1001)]
|
||||
static void MobSetting()
|
||||
{
|
||||
//var selectedObjects = Selection.gameObjects;
|
||||
|
||||
//foreach (var go in selectedObjects)
|
||||
//{
|
||||
// var ma = go.GetComponent<MobActor>();
|
||||
// if (ma == null) ma = go.AddComponent<MobActor>();
|
||||
|
||||
// var m_bc = go.GetComponent<BoxCollider>();
|
||||
// if (m_bc == null) m_bc = go.AddComponent<BoxCollider>();
|
||||
|
||||
// CommonSetting(go, ObstacleAvoidanceType.LowQualityObstacleAvoidance, 0, "Actor");
|
||||
//}
|
||||
}
|
||||
|
||||
[MenuItem("Edit/PetSetting", false, -1002)]
|
||||
static void PetSetting()
|
||||
{
|
||||
//var selectedObjects = Selection.gameObjects;
|
||||
|
||||
//foreach (var go in selectedObjects)
|
||||
//{
|
||||
// var ma = go.GetComponent<PetActor>();
|
||||
// if (ma == null) ma = go.AddComponent<PetActor>();
|
||||
// ma.m_Role = eRole.Pet;
|
||||
|
||||
// CommonSetting(go, ObstacleAvoidanceType.NoObstacleAvoidance, 99, "Actor");
|
||||
//}
|
||||
}
|
||||
[MenuItem("Edit/PCSetting", false, -1003)]
|
||||
static void PCSetting()
|
||||
{
|
||||
//var selectedObjects = Selection.gameObjects;
|
||||
|
||||
//foreach (var go in selectedObjects)
|
||||
//{
|
||||
// // 프리팹 에셋 경로 가져오기
|
||||
// string prefabPath = PrefabUtility.GetPrefabAssetPathOfNearestInstanceRoot(go);
|
||||
|
||||
// // Prefab인지 확인
|
||||
// if (!string.IsNullOrEmpty(prefabPath))
|
||||
// {
|
||||
// // Prefab Asset 가져오기
|
||||
// var prefabAsset = PrefabUtility.LoadPrefabContents(prefabPath);
|
||||
|
||||
// var ma = prefabAsset.GetComponent<WizardActor>();
|
||||
// if (ma == null) ma = prefabAsset.AddComponent<WizardActor>();
|
||||
// ma.m_Role = eRole.PC;
|
||||
|
||||
// var navmesh = prefabAsset.GetComponent<NavMeshAgent>();
|
||||
// if (navmesh == null) navmesh = prefabAsset.AddComponent<NavMeshAgent>();
|
||||
// navmesh.speed = 6f;
|
||||
// navmesh.angularSpeed = 300f;
|
||||
// navmesh.acceleration = 140f;
|
||||
// navmesh.stoppingDistance = 4f;
|
||||
// navmesh.autoBraking = true;
|
||||
// navmesh.radius = 0.4f;
|
||||
// navmesh.height = 2f;
|
||||
// navmesh.avoidancePriority = 50;
|
||||
// navmesh.obstacleAvoidanceType = ObstacleAvoidanceType.LowQualityObstacleAvoidance;
|
||||
|
||||
// Set_CommonRigidBody(prefabAsset, "Actor");
|
||||
|
||||
// var cc = prefabAsset.GetComponent<CapsuleCollider>();
|
||||
// if (cc == null) cc = prefabAsset.AddComponent<CapsuleCollider>();
|
||||
// cc.center = Vector3.up * 0.79f;
|
||||
// cc.radius = 0.55f;
|
||||
// cc.height = 1.58f;
|
||||
// cc.direction = 1;
|
||||
|
||||
// var pcactor = prefabAsset.GetComponent<PCActor>();
|
||||
// List<Transform> list_tr = new List<Transform>();
|
||||
|
||||
// // 프리팹 내부 수정
|
||||
// var wristL = FindDeepChild(prefabAsset.transform, "Wrist_L");
|
||||
// var wristR = FindDeepChild(prefabAsset.transform, "Wrist_R");
|
||||
|
||||
// if (wristL != null)
|
||||
// {
|
||||
// var strName = "w_shield";
|
||||
// var shield = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (shield == null) shield = new GameObject(strName).transform;
|
||||
// shield.parent = wristL;
|
||||
// shield.localPosition = new Vector3(0.0184f, -0.0158f, 0.0261f);
|
||||
// shield.localEulerAngles = new Vector3(-21.84897f, 162.9937f, -171.4406f);
|
||||
// shield.localScale = Vector3.one * 0.6f;
|
||||
// list_tr.Add(shield);
|
||||
// }
|
||||
// if (wristR != null)
|
||||
// {
|
||||
// var strName = "w_righthand";
|
||||
// var mace = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (mace == null) mace = new GameObject(strName).transform;
|
||||
// mace.parent = wristR;
|
||||
// mace.localPosition = new Vector3(-0.0749f, 0.1431f, -0.024f);
|
||||
// mace.localEulerAngles = new Vector3(0, 0, 10.6f);
|
||||
// mace.localScale = new Vector3(1f, 0.7f, 1f);
|
||||
// list_tr.Add(mace);
|
||||
// }
|
||||
|
||||
// if (wristR != null)
|
||||
// {
|
||||
// var strName = "w_onehand";
|
||||
// var onehand = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (onehand == null) onehand = new GameObject(strName).transform;
|
||||
// onehand.parent = wristR;
|
||||
// onehand.localPosition = new Vector3(-0.0546f, -0.001f, -0.0271f);
|
||||
// onehand.localEulerAngles = new Vector3(0f, 107.83f, 0f);
|
||||
// onehand.localScale = Vector3.one * 0.8f;
|
||||
// list_tr.Add(onehand);
|
||||
// }
|
||||
|
||||
// if (wristL != null)
|
||||
// {
|
||||
// var strName = "w_bladedancer_l";
|
||||
// var bd_l = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (bd_l == null) bd_l = new GameObject(strName).transform;
|
||||
// bd_l.parent = wristL;
|
||||
// bd_l.localPosition = new Vector3(0.0413f, 0.015f, 0.0255f);
|
||||
// bd_l.localEulerAngles = new Vector3(6.747354f, -168.0254f, 157.2563f);
|
||||
// bd_l.localScale = Vector3.one;
|
||||
// list_tr.Add(bd_l);
|
||||
// }
|
||||
// if (wristR != null)
|
||||
// {
|
||||
// var strName = "w_bladedancer_r";
|
||||
// var bd_r = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (bd_r == null) bd_r = new GameObject(strName).transform;
|
||||
// bd_r.parent = wristR;
|
||||
// bd_r.localPosition = new Vector3(-0.0546f, -0.001f, -0.0271f);
|
||||
// bd_r.localEulerAngles = new Vector3(0f, 107.83f, 0f);
|
||||
// bd_r.localScale = Vector3.one * 0.8f;
|
||||
// list_tr.Add(bd_r);
|
||||
// }
|
||||
// if (wristR != null)
|
||||
// {
|
||||
// var strName = "w_orb";
|
||||
// var bd_r = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (bd_r == null) bd_r = new GameObject(strName).transform;
|
||||
// bd_r.parent = wristR;
|
||||
// bd_r.localPosition = new Vector3(-0.05439695f, -0.00136376f, -0.02748983f);
|
||||
// bd_r.localEulerAngles = new Vector3(-1.791351f, 107.4387f, 1.349683f);
|
||||
// bd_r.localScale = Vector3.one * 0.1f;
|
||||
// list_tr.Add(bd_r);
|
||||
// }
|
||||
|
||||
// if (wristL != null)
|
||||
// {
|
||||
// var strName = "w_archer_l";
|
||||
// var bow_l = FindDeepChild(prefabAsset.transform, strName);
|
||||
// if (bow_l == null) bow_l = new GameObject(strName).transform;
|
||||
// bow_l.parent = wristL;
|
||||
// bow_l.localPosition = new Vector3(0.069f, -0.01f, 0.034f);
|
||||
// bow_l.localEulerAngles = new Vector3(-2.139496f, 0f, -3.480011f);
|
||||
// bow_l.localScale = Vector3.one * 1.3f;
|
||||
// list_tr.Add(bow_l);
|
||||
// }
|
||||
|
||||
// pcactor.tfs_weapon = list_tr.ToArray();
|
||||
|
||||
// // 수정한 프리팹 저장
|
||||
// PrefabUtility.SaveAsPrefabAsset(prefabAsset, prefabPath);
|
||||
// PrefabUtility.UnloadPrefabContents(prefabAsset);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Debug.LogError($"{go.name}은(는) 프리팹 인스턴스가 아닙니다!");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
static Transform FindDeepChild(Transform parent, string name)
|
||||
{
|
||||
foreach (Transform child in parent)
|
||||
{
|
||||
if (child.name == name)
|
||||
return child;
|
||||
var result = FindDeepChild(child, name);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void CommonSetting(GameObject go, ObstacleAvoidanceType avoid, int avoidancePriority, string layer)
|
||||
{
|
||||
Set_Collideer(go);
|
||||
|
||||
var navmesh = go.GetComponent<NavMeshAgent>();
|
||||
if (navmesh == null) navmesh = go.AddComponent<NavMeshAgent>();
|
||||
navmesh.speed = 4.5f;
|
||||
navmesh.angularSpeed = 300f;
|
||||
navmesh.acceleration = 140f;
|
||||
navmesh.stoppingDistance = 0.1f;
|
||||
navmesh.autoBraking = true;
|
||||
navmesh.radius = 0.25f;
|
||||
navmesh.avoidancePriority = avoidancePriority;
|
||||
navmesh.obstacleAvoidanceType = avoid;
|
||||
|
||||
Set_CommonRigidBody(go, layer);
|
||||
}
|
||||
static void Set_CommonRigidBody(GameObject go, string layer)
|
||||
{
|
||||
go.layer = LayerMask.NameToLayer(layer);
|
||||
var rigidbody = go.GetComponent<Rigidbody>();
|
||||
if (rigidbody == null) rigidbody = go.AddComponent<Rigidbody>();
|
||||
rigidbody.useGravity = false;
|
||||
rigidbody.mass = 1;
|
||||
rigidbody.linearDamping = 0;
|
||||
rigidbody.angularDamping = 0.05f;
|
||||
rigidbody.automaticCenterOfMass = true;
|
||||
rigidbody.automaticInertiaTensor = true;
|
||||
rigidbody.collisionDetectionMode = CollisionDetectionMode.Discrete;
|
||||
rigidbody.constraints = RigidbodyConstraints.FreezeAll;
|
||||
}
|
||||
|
||||
private static void UpdateAllObjects()
|
||||
{
|
||||
for (int i = objectSettingsList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var settings = objectSettingsList[i];
|
||||
if (settings.tick < 0)
|
||||
{
|
||||
var bounds = settings.m_smr.bounds;
|
||||
settings.m_bc.center = bounds.center;
|
||||
settings.m_bc.size = bounds.size + Vector3.up;
|
||||
settings.m_smr.updateWhenOffscreen = false;
|
||||
settings.go.transform.localScale = settings.m_Scale;
|
||||
objectSettingsList.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
settings.tick--;
|
||||
}
|
||||
}
|
||||
|
||||
if (objectSettingsList.Count == 0)
|
||||
{
|
||||
EditorApplication.update -= UpdateAllObjects;
|
||||
}
|
||||
}
|
||||
|
||||
private class ObjectSettings
|
||||
{
|
||||
public GameObject go;
|
||||
public Vector3 m_Scale;
|
||||
public BoxCollider m_bc;
|
||||
public SkinnedMeshRenderer m_smr;
|
||||
public int tick;
|
||||
}
|
||||
|
||||
|
||||
[MenuItem("Edit/SetCollider", false, -2000)]
|
||||
static void SetCollider()
|
||||
{
|
||||
foreach (var go in Selection.gameObjects)
|
||||
Set_Collideer(go);
|
||||
}
|
||||
static void Set_Collideer(GameObject go)
|
||||
{
|
||||
var objData = new ObjectSettings { go = go, m_Scale = go.transform.localScale, tick = 10 };
|
||||
go.transform.localScale = Vector3.one;
|
||||
|
||||
var m_bc = go.GetComponent<BoxCollider>();
|
||||
if (m_bc == null) m_bc = go.AddComponent<BoxCollider>();
|
||||
objData.m_bc = m_bc;
|
||||
|
||||
var rds = go.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
SkinnedMeshRenderer m_smr = null;
|
||||
if (rds.Length == 1) m_smr = rds[0];
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < rds.Length; i++)
|
||||
{
|
||||
if (rds[i].name.ToLower().Contains("skin"))
|
||||
{
|
||||
m_smr = rds[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_smr == null) m_smr = rds[0];
|
||||
}
|
||||
|
||||
m_smr.updateWhenOffscreen = true;
|
||||
objData.m_smr = m_smr;
|
||||
|
||||
objectSettingsList.Add(objData);
|
||||
|
||||
EditorApplication.update += UpdateAllObjects;
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Del_AddrResource")]
|
||||
static void Del_AddrResource()
|
||||
{
|
||||
bool result = EditorUtility.DisplayDialog(
|
||||
"경고!", // 제목
|
||||
"모든 어드레서블 데이터를 삭제하시겠습니까?", // 메시지
|
||||
"확인", // 확인 버튼
|
||||
"취소" // 취소 버튼
|
||||
);
|
||||
|
||||
if (result)
|
||||
{
|
||||
Caching.ClearCache();
|
||||
EditorUtility.DisplayDialog("알림", "삭제 완료", "확인");
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/MobActorImageFill", false, 1)]
|
||||
static void MobActorImageFill()
|
||||
{
|
||||
var srs = Selection.activeGameObject.GetComponentsInChildren<SpriteRenderer>();
|
||||
for (int i = 0; i < srs.Length; i++)
|
||||
{
|
||||
var child = srs[i];
|
||||
if (child.name == "sr_actor")
|
||||
child.GetComponent<SpriteRenderer>().sprite =
|
||||
AssetDatabase.LoadAssetAtPath<Sprite>("Assets/Res_Addr/Monster/10001.png");
|
||||
}
|
||||
}
|
||||
[MenuItem("Tools/MobActorImageEmpty", false, 2)]
|
||||
static void MobActorImageEmpty()
|
||||
{
|
||||
var srs = Selection.activeGameObject.GetComponentsInChildren<SpriteRenderer>();
|
||||
for (int i = 0; i < srs.Length; i++)
|
||||
{
|
||||
var child = srs[i];
|
||||
if (child.name == "sr_actor")
|
||||
child.GetComponent<SpriteRenderer>().sprite = null;
|
||||
}
|
||||
}
|
||||
//[MenuItem("Edit/Find All Particle", false, -103)]
|
||||
//public static void FindAllParticle()
|
||||
//{
|
||||
// foreach (var selection in Selection.gameObjects)
|
||||
// {
|
||||
// var pats = selection.transform.GetComponentsInChildren<ParticleSystem>();
|
||||
// for (int i = 0; i < pats.Length; i++)
|
||||
// Debug.Log(pats[i].name);
|
||||
// }
|
||||
//}
|
||||
|
||||
|
||||
//[MenuItem("Ino/Test %g")]
|
||||
//static void Ino_Test()
|
||||
//{
|
||||
// ModelImporter modelImporter = (ModelImporter)AssetImporter.GetAtPath("Assets/ResWork/Quirky Series Vol.1 [v1.3]/Arctic Vol.1/Animations/Penguin_Animations.fbx");
|
||||
// for (int i = 0; i < modelImporter.clipAnimations.Length; i++)
|
||||
// {
|
||||
// switch(modelImporter.clipAnimations[i].name)
|
||||
// {
|
||||
// case "Attack":
|
||||
// break;
|
||||
// }
|
||||
|
||||
// }
|
||||
//}
|
||||
|
||||
//[MenuItem("Ino/Test")]
|
||||
//static void FindHUD()
|
||||
//{
|
||||
// Debug.Log("시작");
|
||||
// for (int i = 0; i < Selection.gameObjects.Length; i++)
|
||||
// {
|
||||
// var hud = Selection.gameObjects[i].transform.Find("HUD");
|
||||
// if (hud == null) Debug.Log(Selection.gameObjects[i]);
|
||||
// }
|
||||
// Debug.Log("끝");
|
||||
//}
|
||||
|
||||
//[MenuItem("Ino/Bip001 to Bip002")]
|
||||
//static void ChangeBip01Bip02()
|
||||
//{
|
||||
// var tf = Selection.activeGameObject.transform;
|
||||
// ChangeName(tf);
|
||||
//}
|
||||
|
||||
// 자식까지 포함해서 레이어를 재귀적으로 설정하는 함수
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3334bb993485f194bb4fd632194b1518
|
||||
|
|
@ -0,0 +1,497 @@
|
|||
using TMPro;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public static class MyUIUtil
|
||||
{
|
||||
static string path_whitebg = "Assets/ResWork/UI_Image/Common/whitebg.png";
|
||||
|
||||
static void SetLayerRecursively(GameObject obj, string newLayer = "UI")
|
||||
{
|
||||
obj.layer = LayerMask.NameToLayer(newLayer);
|
||||
|
||||
foreach (Transform child in obj.transform)
|
||||
SetLayerRecursively(child.gameObject, newLayer); // 재귀 호출로 자식까지 처리
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/New Image &i")] // &i는 Alt + I를 의미
|
||||
static void CreateUIImage()
|
||||
{
|
||||
GameObject imageObject = new GameObject("New Image", typeof(Image));
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(imageObject, "New Image");
|
||||
|
||||
var img = imageObject.GetComponent<Image>();
|
||||
img.raycastTarget = false;
|
||||
img.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
imageObject.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(imageObject);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = imageObject;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Text Only &t")] // &t는 Alt + T를 의미
|
||||
static void CreateUITextMeshPro()
|
||||
{
|
||||
GameObject textObject = new GameObject("New TMP", typeof(TextMeshProUGUI));
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(textObject, "New TMP");
|
||||
|
||||
var tm = textObject.GetComponent<TextMeshProUGUI>();
|
||||
tm.raycastTarget = false;
|
||||
tm.alignment = TextAlignmentOptions.Midline;
|
||||
tm.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
textObject.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(textObject);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = textObject;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
[MenuItem("GameObject/UI/Text - Local &y")]
|
||||
static void CreateUITextMeshProWithLocal()
|
||||
{
|
||||
GameObject textObject = new GameObject("Local TMP", typeof(TextMeshProUGUI));
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(textObject, "Local TMP");
|
||||
|
||||
textObject.AddComponent<SetLocalText>();
|
||||
var tm = textObject.GetComponent<TextMeshProUGUI>();
|
||||
tm.raycastTarget = false;
|
||||
tm.alignment = TextAlignmentOptions.Midline;
|
||||
tm.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
textObject.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(textObject);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = textObject;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/Button &b")] // Alt + B: Button 생성 (Image, Button, PlayClickSound_Only 추가)
|
||||
static void CreateUIButton()
|
||||
{
|
||||
// 버튼 오브젝트 생성 (Image, Button 컴포넌트 포함)
|
||||
GameObject buttonObject = new GameObject("btn_");
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(buttonObject, "btn_");
|
||||
|
||||
buttonObject.AddComponent<Image>().sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
buttonObject.AddComponent<Button>();
|
||||
buttonObject.AddComponent<PlayClickSound_Only>();
|
||||
|
||||
// TextMeshPro-UGUI 생성 및 설정
|
||||
GameObject textObject = new GameObject("btnName", typeof(TextMeshProUGUI));
|
||||
textObject.AddComponent<SetLocalText>();
|
||||
TextMeshProUGUI tmp = textObject.GetComponent<TextMeshProUGUI>();
|
||||
tmp.text = "Button";
|
||||
tmp.alignment = TextAlignmentOptions.Midline;
|
||||
tmp.raycastTarget = false;
|
||||
|
||||
// Text 객체를 Button의 자식으로 설정
|
||||
textObject.transform.SetParent(buttonObject.transform, false);
|
||||
RectTransform textRect = textObject.GetComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
|
||||
// 버튼 오브젝트의 부모 설정
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
buttonObject.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(buttonObject);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = buttonObject;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/My Slider &%#s")] // Alt + Ctrl + Shift + S: Slider 생성
|
||||
static void CreateUISlider()
|
||||
{
|
||||
var slider = Make_Slider("Slider_", true, Color.yellow, 0.3f);
|
||||
var sliderbase = slider.gameObject.AddComponent<SliderBase>();
|
||||
sliderbase.m_slider = slider;
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(slider.gameObject, "Slider_");
|
||||
|
||||
var middleslider = Make_Slider("SliderMiddle_", false, Color.red, 0.6f);
|
||||
sliderbase.m_middleslider = middleslider;
|
||||
middleslider.transform.SetParent(slider.transform, false);
|
||||
middleslider.transform.SetSiblingIndex(1);
|
||||
}
|
||||
static Slider Make_Slider(string name, bool makebg, Color color, float slidervalue)
|
||||
{
|
||||
GameObject sliderObject = new GameObject(name, typeof(Slider));
|
||||
|
||||
sliderObject.GetComponent<RectTransform>().sizeDelta = new Vector2(200f, 20f);
|
||||
|
||||
Slider slider = sliderObject.GetComponent<Slider>();
|
||||
slider.value = slidervalue;
|
||||
|
||||
if (makebg)
|
||||
{
|
||||
// Slider의 자식 오브젝트로 Background 이미지 추가
|
||||
GameObject backgroundObject = new GameObject("Background", typeof(Image));
|
||||
backgroundObject.transform.SetParent(sliderObject.transform, false);
|
||||
var img = backgroundObject.GetComponent<Image>();
|
||||
img.raycastTarget = false;
|
||||
img.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
RectTransform bgRect = backgroundObject.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = new Vector2(0, 0);
|
||||
bgRect.anchorMax = new Vector2(1, 1);
|
||||
bgRect.offsetMin = new Vector2(0, 0); // Custom Stretch 적용
|
||||
bgRect.offsetMax = new Vector2(0, 0); // Custom Stretch 적용
|
||||
}
|
||||
else
|
||||
{
|
||||
RectTransform sliderRect = slider.transform as RectTransform;
|
||||
sliderRect.anchorMin = new Vector2(0, 0);
|
||||
sliderRect.anchorMax = new Vector2(1, 1);
|
||||
sliderRect.offsetMin = new Vector2(0, 0); // Custom Stretch 적용
|
||||
sliderRect.offsetMax = new Vector2(0, 0); // Custom Stretch 적용
|
||||
}
|
||||
|
||||
// Fill Area 오브젝트 추가
|
||||
GameObject fillAreaObject = new GameObject("Fill Area", typeof(RectTransform));
|
||||
fillAreaObject.transform.SetParent(sliderObject.transform, false);
|
||||
RectTransform fillAreaRect = fillAreaObject.GetComponent<RectTransform>();
|
||||
fillAreaRect.anchorMin = new Vector2(0, 0);
|
||||
fillAreaRect.anchorMax = new Vector2(1, 1);
|
||||
fillAreaRect.offsetMin = new Vector2(0, 0); // Custom Stretch 적용
|
||||
fillAreaRect.offsetMax = new Vector2(0, 0); // Custom Stretch 적용
|
||||
|
||||
// Fill Area 자식으로 Fill 이미지 추가
|
||||
GameObject fillObject = new GameObject("Fill", typeof(Image));
|
||||
fillObject.transform.SetParent(fillAreaObject.transform, false);
|
||||
slider.targetGraphic = fillObject.GetComponent<Image>();
|
||||
slider.targetGraphic.color = color;
|
||||
slider.targetGraphic.raycastTarget = false;
|
||||
var fillimg = slider.targetGraphic as Image;
|
||||
fillimg.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
fillimg.type = Image.Type.Filled;
|
||||
fillimg.fillMethod = Image.FillMethod.Horizontal;
|
||||
RectTransform fillRect = fillObject.GetComponent<RectTransform>();
|
||||
fillRect.anchorMin = new Vector2(0, 0);
|
||||
fillRect.anchorMax = new Vector2(1, 1);
|
||||
fillRect.offsetMin = new Vector2(0, 0);
|
||||
fillRect.offsetMax = new Vector2(0, 0); // Stretch left 적용
|
||||
|
||||
// Fill 이미지 설정
|
||||
slider.fillRect = fillRect;
|
||||
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
sliderObject.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(sliderObject);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = sliderObject;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
|
||||
return slider;
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/My CheckUI &%#c")]
|
||||
static void CreateUICheck()
|
||||
{
|
||||
// 0. "check_" GameObject 생성
|
||||
GameObject gocheck = new GameObject("check_");
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(gocheck, "check_");
|
||||
|
||||
gocheck.AddComponent<RectTransform>();
|
||||
|
||||
// 1. 자식으로 크기 27x27 Image 추가
|
||||
GameObject imageObject1 = new GameObject("checkbg", typeof(Image));
|
||||
imageObject1.GetComponent<Image>().sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
imageObject1.transform.SetParent(gocheck.transform, false); // gocheck의 자식으로 설정
|
||||
RectTransform image1Rect = imageObject1.GetComponent<RectTransform>();
|
||||
image1Rect.sizeDelta = new Vector2(50, 50); // 크기 설정
|
||||
// 버튼 및 버튼음 추가
|
||||
imageObject1.AddComponent<Button>();
|
||||
imageObject1.AddComponent<PlayClickSound_Only>();
|
||||
|
||||
// 2. 1 의 자식으로 크기 39x30 Image 추가
|
||||
GameObject imageObject2 = new GameObject("check", typeof(Image));
|
||||
imageObject2.GetComponent<Image>().sprite = AssetDatabase.LoadAssetAtPath<Sprite>("Assets/ResWork/UI/NewRes/bg/checkmark.png");
|
||||
imageObject2.transform.SetParent(imageObject1.transform, false); // imageObject1의 자식으로 설정
|
||||
RectTransform image2Rect = imageObject2.GetComponent<RectTransform>();
|
||||
image2Rect.sizeDelta = new Vector2(50, 37); // 크기 설정
|
||||
|
||||
// 3. 1의 오른쪽에 1과 같은 깊이로 TMP 추가
|
||||
GameObject textObject = new GameObject("checkName", typeof(TextMeshProUGUI));
|
||||
textObject.AddComponent<SetLocalText>();
|
||||
textObject.transform.SetParent(gocheck.transform, false); // gocheck의 자식으로 설정
|
||||
RectTransform textRect = textObject.GetComponent<RectTransform>();
|
||||
textRect.sizeDelta = new Vector2(100, 30); // TMP의 기본 크기 설정
|
||||
textRect.anchoredPosition = new Vector2(image1Rect.sizeDelta.x + 50, 0); // Image1의 오른쪽으로 배치
|
||||
|
||||
TextMeshProUGUI tmp = textObject.GetComponent<TextMeshProUGUI>();
|
||||
tmp.alignment = TextAlignmentOptions.MidlineLeft;
|
||||
tmp.text = "체크 UI";
|
||||
tmp.raycastTarget = false;
|
||||
|
||||
// 현재 선택된 오브젝트를 부모로 설정 (선택된 오브젝트가 있을 때만)
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
gocheck.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = gocheck;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/My Scroll &#v")] // Alt + Shift + V 단축키
|
||||
static void CreateUIScrollview()
|
||||
{
|
||||
// 0. "scrollview_" GameObject 생성
|
||||
GameObject go_sv = new GameObject("scrollview_");
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(go_sv, "scrollview_");
|
||||
|
||||
var img = go_sv.AddComponent<Image>();
|
||||
img.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
var sr = go_sv.AddComponent<ScrollRect>();
|
||||
sr.horizontal = false;
|
||||
|
||||
// 1. 자식으로 Viewport 추가
|
||||
GameObject go_vp = new GameObject("Viewport", typeof(Image));
|
||||
go_vp.AddComponent<Mask>().showMaskGraphic = false;
|
||||
go_vp.transform.SetParent(go_sv.transform, false); // 자식으로 설정
|
||||
var rt_vp = go_vp.GetComponent<RectTransform>(); // 이미 추가된 RectTransform 가져오기
|
||||
rt_vp.anchorMin = Vector2.zero;
|
||||
rt_vp.anchorMax = Vector2.one;
|
||||
rt_vp.pivot = Vector2.up;
|
||||
rt_vp.offsetMin = Vector2.zero; // Left와 Bottom을 0으로 설정
|
||||
rt_vp.offsetMax = Vector2.zero; // Right와 Top을 0으로 설정
|
||||
var img_vp = go_vp.GetComponent<Image>();
|
||||
img_vp.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
|
||||
// ScrollRect의 Viewport를 설정
|
||||
sr.viewport = rt_vp;
|
||||
|
||||
// 2. 1의 자식으로 Content 추가
|
||||
GameObject go_ct = new GameObject("Content");
|
||||
go_ct.transform.SetParent(go_vp.transform, false); // Content를 Viewport의 자식으로 설정
|
||||
go_ct.AddComponent<ContentSizeFitter>().verticalFit = ContentSizeFitter.FitMode.PreferredSize; // ContentSizeFitter 설정
|
||||
var rt_ct = go_ct.GetComponent<RectTransform>();
|
||||
rt_ct.anchorMin = Vector2.up;
|
||||
rt_ct.anchorMax = Vector2.one;
|
||||
rt_ct.pivot = Vector2.up;
|
||||
rt_ct.offsetMin = Vector2.zero; // Left와 Bottom을 0으로 설정
|
||||
rt_ct.offsetMax = Vector2.zero; // Right와 Top을 0으로 설정
|
||||
|
||||
// ScrollRect의 content 설정
|
||||
sr.content = rt_ct;
|
||||
|
||||
// 현재 선택된 오브젝트를 부모로 설정 (선택된 오브젝트가 있을 때만)
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
go_sv.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(go_sv);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = go_sv;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/TMP InputField &%#i")] // Alt + Ctrl + Shift + i 단축키
|
||||
static void CreateTMPInputField()
|
||||
{
|
||||
// 0. GameObject 생성
|
||||
GameObject go_if = new GameObject("inputfield_");
|
||||
|
||||
// 생성된 오브젝트에 대한 Undo 기록 추가
|
||||
Undo.RegisterCreatedObjectUndo(go_if, "inputfield_");
|
||||
|
||||
var img = go_if.AddComponent<Image>();
|
||||
img.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
img.color = new Color32(175, 175, 175, 255);
|
||||
var tmp_if = go_if.AddComponent<TMP_InputField>();
|
||||
var rt_if = go_if.GetComponent<RectTransform>();
|
||||
rt_if.sizeDelta = new Vector2(160, 50);
|
||||
|
||||
// 1. 자식으로 Text Area 추가
|
||||
GameObject go_vp = new GameObject("Text Area", typeof(RectMask2D), typeof(RectTransform));
|
||||
go_vp.GetComponent<RectMask2D>().padding = new Vector4(-8, -5, -8, -5);
|
||||
go_vp.transform.SetParent(go_if.transform, false); // 자식으로 설정
|
||||
var rt_vp = go_vp.GetComponent<RectTransform>();
|
||||
Set_RectTransform_CenterStretch(rt_vp);
|
||||
tmp_if.textViewport = rt_vp;
|
||||
|
||||
// 2. 1의 자식으로 Placeholder 추가
|
||||
GameObject go_ph = new GameObject("Placeholder", typeof(RectTransform));
|
||||
go_ph.transform.SetParent(go_vp.transform, false); // 자식으로 설정
|
||||
var rt_ph = go_ph.GetComponent<RectTransform>();
|
||||
Set_RectTransform_CenterStretch(rt_ph);
|
||||
var text_ph = go_ph.AddComponent<TextMeshProUGUI>();
|
||||
text_ph.raycastTarget = false;
|
||||
text_ph.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
text_ph.alignment = TextAlignmentOptions.Midline;
|
||||
text_ph.text = "";
|
||||
text_ph.color = Color.black;
|
||||
text_ph.fontSize = 30;
|
||||
tmp_if.placeholder = text_ph;
|
||||
go_ph.AddComponent<LayoutElement>().ignoreLayout = true;
|
||||
|
||||
// 3. 1의 자식으로 Text 추가
|
||||
GameObject go_txt = new GameObject("Text", typeof(RectTransform));
|
||||
go_txt.transform.SetParent(go_vp.transform, false); // 자식으로 설정
|
||||
var rt_txt = go_txt.GetComponent<RectTransform>();
|
||||
Set_RectTransform_CenterStretch(rt_txt);
|
||||
var text_txt = go_txt.AddComponent<TextMeshProUGUI>();
|
||||
text_txt.raycastTarget = false;
|
||||
text_txt.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
text_txt.alignment = TextAlignmentOptions.Midline;
|
||||
text_txt.color = Color.black;
|
||||
tmp_if.textComponent = text_txt;
|
||||
tmp_if.pointSize = 30;
|
||||
|
||||
// 현재 선택된 오브젝트를 부모로 설정 (선택된 오브젝트가 있을 때만)
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
go_if.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(go_if);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = go_if;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
static void Set_RectTransform_CenterStretch(RectTransform rtf)
|
||||
{
|
||||
rtf.anchorMin = Vector2.zero;
|
||||
rtf.anchorMax = Vector2.one;
|
||||
rtf.pivot = new Vector2(0.5f, 0.5f);
|
||||
rtf.offsetMin = Vector2.zero;
|
||||
rtf.offsetMax = Vector2.zero;
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/UI/My Tab H %#q")] // Ctrl + Shift + Q: 탭 생성 (가로)
|
||||
static void CreateUITab_Hori()
|
||||
{
|
||||
Set_Tab_Common<HorizontalLayoutGroup>("tab_layout_h");
|
||||
}
|
||||
[MenuItem("GameObject/UI/My Tab V %#w")] // Ctrl + Shift + W: 탭 생성 (세로)
|
||||
static void CreateUITab_Veti()
|
||||
{
|
||||
Set_Tab_Common<VerticalLayoutGroup>("tab_layout_v");
|
||||
}
|
||||
static void Set_Tab_Common<T>(string layoutName) where T : HorizontalOrVerticalLayoutGroup
|
||||
{
|
||||
GameObject obj = new GameObject(layoutName);
|
||||
var layout = obj.AddComponent<T>();
|
||||
layout.childForceExpandWidth = false;
|
||||
layout.childForceExpandHeight = false;
|
||||
layout.spacing = 5;
|
||||
var tabbase = obj.AddComponent<TabUIBase>();
|
||||
tabbase.m_Content = obj;
|
||||
obj.GetComponent<RectTransform>().sizeDelta = Vector2.zero;
|
||||
Undo.RegisterCreatedObjectUndo(obj, layoutName);
|
||||
|
||||
GameObject tab = new GameObject("tab_dontDelete");
|
||||
tabbase.go_card = tab;
|
||||
tab.transform.SetParent(obj.transform, false);
|
||||
var rt = tab.AddComponent<RectTransform>();
|
||||
rt.sizeDelta = new Vector2(300, 100);
|
||||
var tabcard = tab.AddComponent<TabCardBase>();
|
||||
tabcard.images = new Image[2];
|
||||
tabcard.texts = new TextMeshProUGUI[1];
|
||||
|
||||
GameObject tab_bg = new GameObject("i_bg");
|
||||
tab_bg.transform.SetParent(tab.transform, false);
|
||||
var i_bg = tab_bg.AddComponent<Image>();
|
||||
tabcard.images[0] = i_bg;
|
||||
var bgRect = tab_bg.GetComponent<RectTransform>();
|
||||
bgRect.anchorMin = new Vector2(0, 0);
|
||||
bgRect.anchorMax = new Vector2(1, 1);
|
||||
bgRect.offsetMin = new Vector2(0, 0); // Custom Stretch 적용
|
||||
bgRect.offsetMax = new Vector2(0, 0); // Custom Stretch 적용
|
||||
i_bg.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
tabcard.m_btn = tab_bg.AddComponent<Button>();
|
||||
tab_bg.AddComponent<PlayClickSound_Only>();
|
||||
|
||||
GameObject tab_img = new GameObject("i_img");
|
||||
tab_img.transform.SetParent(tab.transform, false);
|
||||
var i_img = tab_img.AddComponent<Image>();
|
||||
tabcard.images[1] = i_img;
|
||||
i_img.rectTransform.sizeDelta = new Vector2(100, 50);
|
||||
i_img.raycastTarget = false;
|
||||
i_img.sprite = AssetDatabase.LoadAssetAtPath<Sprite>(path_whitebg);
|
||||
i_img.color = Color.black;
|
||||
tab_img.AddComponent<Button>();
|
||||
tab_img.AddComponent<PlayClickSound_Only>();
|
||||
|
||||
// TextMeshPro-UGUI 생성 및 설정
|
||||
GameObject textObject = new GameObject("btnName", typeof(TextMeshProUGUI));
|
||||
//textObject.AddComponent<LocalizeStringEvent>();
|
||||
TextMeshProUGUI tmp = textObject.GetComponent<TextMeshProUGUI>();
|
||||
tabcard.texts[0] = tmp;
|
||||
tmp.raycastTarget = false;
|
||||
tmp.text = "Tab";
|
||||
tmp.alignment = TextAlignmentOptions.Midline;
|
||||
|
||||
// Text 객체의 부모 설정
|
||||
textObject.transform.SetParent(tab.transform, false);
|
||||
RectTransform textRect = textObject.GetComponent<RectTransform>();
|
||||
textRect.anchorMin = Vector2.zero;
|
||||
textRect.anchorMax = Vector2.one;
|
||||
textRect.offsetMin = Vector2.zero;
|
||||
textRect.offsetMax = Vector2.zero;
|
||||
|
||||
// 버튼 오브젝트의 부모 설정
|
||||
if (Selection.activeGameObject != null)
|
||||
{
|
||||
obj.transform.SetParent(Selection.activeGameObject.transform, false);
|
||||
SetLayerRecursively(obj);
|
||||
|
||||
// 새로 생성된 오브젝트를 선택
|
||||
Selection.activeGameObject = obj;
|
||||
|
||||
// 씬 뷰에서 해당 오브젝트에 포커스 맞추기
|
||||
//SceneView.lastActiveSceneView.FrameSelected();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 843a27393872fef44b875537c93822ab
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
public class SpriteSingleModeImporter : AssetPostprocessor
|
||||
{
|
||||
const int PostProcessOrder = 0;
|
||||
public override int GetPostprocessOrder() => PostProcessOrder;
|
||||
|
||||
void OnPreprocessTexture()
|
||||
{
|
||||
var importer = assetImporter as TextureImporter;
|
||||
|
||||
if (importer.importSettingsMissing is false)
|
||||
return;
|
||||
|
||||
importer.spriteImportMode = SpriteImportMode.Single;
|
||||
importer.mipmapEnabled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 277602c7288246242b11a5008f725350
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8d94ea3741ad8d344a76cca0aa62f67e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 37892793e608e8248b098847128be0c3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 80ab48d20daeb5b4cb0bc1e64f5acd64
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 52c313066dda63c459f7c826dbb8eed1
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
Please, check out latest Anti-Cheat Toolkit Code Library API Docs here:
|
||||
https://codestage.net/uas_files/actk/api/
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f4c375fd5bde53c42b0ebc6ee503f7a1
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/API.txt
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,519 @@
|
|||
# Changelog
|
||||
Changelog format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
#### Types of changes
|
||||
- **Added** for new features.
|
||||
- **Changed** for changes in existing functionality.
|
||||
- **Deprecated** for soon-to-be removed features.
|
||||
- **Removed** for now removed features.
|
||||
- **Fixed** for any bug fixes.
|
||||
- **Security** in case of vulnerabilities.
|
||||
|
||||
💡 _Always remove previous plugin version before updating_
|
||||
|
||||
## [6.2.0] - 2025-07-18
|
||||
|
||||
### Added
|
||||
- Add TimeScale watching to the SpeedHackDetector
|
||||
- New `WatchTimeScale` property (enabled by default) to detect unauthorized Time.timeScale modifications
|
||||
- New `SpeedHackDetector.SetTimeScale()` API for safe timeScale changes
|
||||
- New `SpeedHackDetector.AllowAnyTimeScaleFor()` API for temporary third-party asset control
|
||||
- New `SpeedHackDetector.AllowAnyTimeScale()` / `StopAllowingAnyTimeScale()` APIs for indefinite control
|
||||
- New `SpeedHackProofTime.timeScale` property as drop-in replacement for Time.timeScale
|
||||
|
||||
## [6.1.0] - 2025-06-23
|
||||
|
||||
### Added
|
||||
- Add ObscuredDateTimeOffset type
|
||||
- Add ObscuredGuid type
|
||||
|
||||
## [6.0.0] - 2025-04-09
|
||||
|
||||
### Changed
|
||||
- Change versioning to be year-agnostic (following Unity decision)
|
||||
|
||||
### Fixed
|
||||
- Fix false positives after changing serialized obscured variables in ScriptableObject at PlayMode
|
||||
- Fix GC allocations from ObscuredFloat in newer Unity versions
|
||||
|
||||
## [2024.3.5] - 2025-03-04
|
||||
|
||||
### Fixed
|
||||
- Fix obscured types migration and fixing when used in nested types (thx sol3breaker)
|
||||
|
||||
## [2024.3.4] - 2025-02-28
|
||||
|
||||
### Fixed
|
||||
- Fix a false positives from inconsistent hashing (thx Dmitry Statsenko & Icaro)
|
||||
|
||||
## [2024.3.3] - 2024-12-26
|
||||
|
||||
### Fixed
|
||||
- Fix a false positive while editing ObscuredString in Play Mode (thx Thiago)
|
||||
|
||||
## [2024.3.2] - 2024-12-19
|
||||
|
||||
### Fixed
|
||||
- Fix a regression with error from empty ObscuredStrings editing in Inspector
|
||||
|
||||
## [2024.3.1] - 2024-12-18
|
||||
|
||||
### Changed
|
||||
- Improve error handling in serialized data parser
|
||||
|
||||
### Fixed
|
||||
- Fix possible exceptions while parsing serialized data
|
||||
- Fix invalid variables Inspector highlight inside nested items
|
||||
- Fix possible edge case obscured false positives
|
||||
|
||||
## [2024.3.0] - 2024-12-10
|
||||
|
||||
### Added
|
||||
- Add obscured types validation / migration in Build scenes
|
||||
|
||||
### Changed
|
||||
- Improve URP / HDRP compatibility
|
||||
- Update icons
|
||||
- Update changelog format and [release as html](https://docs.codestage.net/actk/changelog/)
|
||||
|
||||
### Security
|
||||
- Fix SpeedHackDetector vulnerability
|
||||
|
||||
### Fixed
|
||||
- Fix deprecation warnings when migrating from PlayerPrefs to ObscuredPrefs
|
||||
|
||||
## [2024.2.1] - 2024-11-18
|
||||
|
||||
### Fixed
|
||||
- Fix default ObscuredBool was rendered as True in Inspector (thx sol3breaker)
|
||||
|
||||
## [2024.2.0] - 2024-11-17
|
||||
|
||||
### Added
|
||||
- Add Project View context menus to validate or migrate specified assets
|
||||
|
||||
### Changed
|
||||
- Improve RAM usage while validating or migrating assets
|
||||
- Improve asset validation and migration API for more flexibility
|
||||
|
||||
### Fixed
|
||||
- Fix possible exceptions while iterating scripting objects
|
||||
- Fix non-initialized obscured variables were marked as invalid
|
||||
|
||||
## [2024.1.0] - 2024-11-04
|
||||
|
||||
### Added
|
||||
- Add Honeypot option to the ObscuredCheatingDetector
|
||||
|
||||
### Changed
|
||||
- Improve Obscured types cheating resistance
|
||||
- Improve ObscuredTypesNewtonsoftConverter performance
|
||||
- Improve ObscuredVector2Int API compatibility
|
||||
- Improve ObscuredVector3Int API compatibility
|
||||
|
||||
### Security
|
||||
- Fix few reported vulnerabilities
|
||||
|
||||
### Deprecated
|
||||
- Deprecate ACTK_OBSCURED_AUTO_MIGRATION flag with auto-migration from legacy versions
|
||||
|
||||
### Fixed
|
||||
- Fix AndroidScreenRecordingBlocker example
|
||||
- Fix rare ObscuredBigInteger data corruption
|
||||
- Fix ObscuredUInt inspector couldn't be set to values more than 2147483647
|
||||
|
||||
## [2024.0.0] - 2024-07-07
|
||||
|
||||
### Added
|
||||
- Add prevent screen recording feature for Android platform
|
||||
|
||||
### Changed
|
||||
- Improve Unity 6 compatibility
|
||||
- Increase minimum Android supported version to Android 5.0 (API SDK 21)
|
||||
|
||||
### Fixed
|
||||
- Fix few compilation warnings
|
||||
|
||||
## [2023.2.6] - 2024-01-14
|
||||
|
||||
### Fixed
|
||||
- Fix Obscured Types json serialization could produce exception in obfuscated build (thx Thiago)
|
||||
|
||||
## [2023.2.5] - 2024-01-04
|
||||
|
||||
### Fixed
|
||||
- Fix ObscuredPrefs.HasKey() could return wrong value when migrating from v1 format (thx Avocco)
|
||||
|
||||
## [2023.2.4] - 2023-12-19
|
||||
|
||||
### Changed
|
||||
- Make sure domain reload support is editor-only
|
||||
|
||||
### Fixed
|
||||
- Fix CodeHashGenerator warnings in Editor
|
||||
|
||||
## [2023.2.3] - 2023-09-12
|
||||
|
||||
### Fixed
|
||||
- Fix harmless errors in console while using Prefs Editor (thx Rono)
|
||||
- Fix rare RuntimeInitializeOnLoadMethodAttribute errors (thx Silent)
|
||||
|
||||
## [2023.2.2] - 2023-07-08
|
||||
|
||||
### Changed
|
||||
- Improve disabled domain reload compatibility (thx KonstantGames)
|
||||
|
||||
## [2023.2.1] - 2023-06-16
|
||||
|
||||
### Fixed
|
||||
- Fix ObscuredFilePrefs didn't allow saving after removing a key (thx Tyle)
|
||||
|
||||
## [2023.2.0] - 2023-05-31
|
||||
|
||||
### Changed
|
||||
- Improve ObscuredDateTime compatibility
|
||||
- ObscuredDateTime.GetDecrypted() now returns DateTime instead of binary long value
|
||||
- Improve AppInstallationSource accuracy for PackageInstaller source
|
||||
- Make ObscuredBigInteger serialize into JSON as human-readable string instead of b64 bytes
|
||||
|
||||
### Fixed
|
||||
- Fix wrong Culture could be used while deserializing obscured types from JSON (thx spikyworm5)
|
||||
|
||||
## [2023.1.0] - 2023-05-20
|
||||
|
||||
### Added
|
||||
- Add ObscuredDateTime (thx spikyworm5)
|
||||
|
||||
### Changed
|
||||
- Include ObscuredDecimal into the obscured types validation
|
||||
|
||||
### Fixed
|
||||
- Fix ObscuredDecimal might not parse properly from the Inspector
|
||||
- Fix ObscuredString equality check against regular string (thx haeggongs)
|
||||
|
||||
## [2023.0.1] - 2023-05-11
|
||||
|
||||
### Added
|
||||
- Add switch for the ACTK_NEWTONSOFT_JSON conditional in ACTk Settings
|
||||
|
||||
### Fixed
|
||||
- Fix CodeHashGeneratorPostprocessor.HashesGenerated event didn't invoke on post build step (thx mhosoya)
|
||||
|
||||
## [2023.0.0] - 2023-05-09
|
||||
|
||||
### Added
|
||||
- Add AppInstallationSourceValidator to easily figure out Android app installation source
|
||||
- Add ObscuredCheatingDetector.LastDetectionInfo property with detection context
|
||||
- Add built-in Newtonsoft Json Converter for Obscured Types
|
||||
- Add CodeHashGenerator.GenerateAsync() API
|
||||
- Add CodeHashGeneratorPostprocessor APIs:
|
||||
- CalculateBuildReportHashesAsync() method
|
||||
- CalculateExternalBuildHashesAsync() method
|
||||
- Add HashGeneratorResult.PrintToConsole() API for debugging purposes
|
||||
- Add state corruption checks when API accessed too early (before Awake)
|
||||
- Add Windows build hashing progress bar in Editor
|
||||
- Add Normalize() method and normalized property to ObscuredVector2, ObscuredVector3, ObscuredQuaternion
|
||||
- Add buildPath argument to CalculateExternalBuildHashes so you could calculate hashes for any build path from CLI
|
||||
- Add migration notes to the User Manual to help you migrate from v2021 to v2023
|
||||
|
||||
### Changed
|
||||
- Update minimum Unity version to 2019.4
|
||||
- Improve Obscured Types equality checks
|
||||
- Improve how ObscuredFile handles custom path in some rare cases
|
||||
- Significantly improve CodeHashGenerator performance:
|
||||
- Utilize all available cores in Editor's CodeHashGeneratorPostprocessor
|
||||
- Utilize specified threads count in Runtime CodeHashGenerator
|
||||
- Make Summary Hash generation magnitudes faster
|
||||
- Change CodeHashGeneratorPostprocessor API:
|
||||
- Refactor Instance.callbackOrder to static CallbackOrder
|
||||
- Refactor Instance.HashesGenerated to static HashesGenerated
|
||||
- Refactor HashesGenerated delegate `BuildHashes[]` hashedBuilds argument to `IReadOnlyList<BuildHashes> hashedBuilds`
|
||||
- Refactor BuildHashes.FileHashes property type from Array to IReadOnlyList
|
||||
- Refactor HashGeneratorResult.FileHashes property type from Array to IReadOnlyList
|
||||
- Improve CodeHashGeneratorPostprocessor progress reporting in Editor
|
||||
- Improve CodeHashGenerator filtering to include all .dex and .so files on Android
|
||||
- Prepare CodeHashGenerator filtering to include content files so whole build could be covered in future
|
||||
- Introduce various minor improvements
|
||||
|
||||
### Removed
|
||||
- Remove static CodeHashGeneratorPostprocessor.Instance property
|
||||
|
||||
### Fixed
|
||||
- Fix InjectionDetector build processor could keep the service temp file if build fails
|
||||
- Fix ObscuredBigInteger.Equals(ObscuredBigInteger) check didn't work properly
|
||||
- Fix ObscuredBigInteger.GetHashCode() did return value affected by random crypto key
|
||||
- Fix ObscuredFile could have inconsistent path delimiters in the FilePath
|
||||
- Fix some critical errors didn't print to console
|
||||
- Fix regression where ACTK_PREVENT_READ_PHONE_STATE didn't remove permissions caused by SystemInfo.deviceUniqueIdentifier
|
||||
|
||||
## [2021.6.4] - 2023-03-09
|
||||
_I know it's 2023 already, fine? xD_
|
||||
|
||||
### Changed
|
||||
- Improve Unity 2023 compatibility
|
||||
|
||||
### Fixed
|
||||
- Fix inspector fields regression introduced at v2021.2.1 for Unity versions below 2022.2 (thx mrm83)
|
||||
- Fix possible SpeedHackDetector false positives regression introduced at v2021.3.0, now DSP module is optional and off by default with proper warning about its sensitivity (thx mrm83, Kazeon, gpedrani and others 🙏)
|
||||
- Fix some buttons didn't open Project Settings in Unity 2019+
|
||||
|
||||
## [2021.6.3] - 2022-12-19
|
||||
|
||||
### Added
|
||||
- Add few more operators to the ObscuredBigInteger to better match BigInteger API.
|
||||
|
||||
### Changed
|
||||
- Change CodeHashGenerator Editor warning to error to make it more visible and reduce possible confusion
|
||||
|
||||
## [2021.6.2] - 2022-11-12
|
||||
|
||||
### Changed
|
||||
- Make ObscuredCheatingDetector to print logs when ACTK_DETECTION_BACKLOGS is enabled
|
||||
- Improve Obscured Types serialization Validation logs to include exact path and location
|
||||
|
||||
## [2021.6.1] - 2022-11-10
|
||||
|
||||
### Fixed
|
||||
- Fix rare SpeedHackDetector false positive
|
||||
|
||||
## [2021.6.0] - 2022-11-09
|
||||
|
||||
### Added
|
||||
- Add new WallHackDetector compatibility check and safety warning (thx naezith)
|
||||
- Add serialization corruption detection for Obscured Types
|
||||
|
||||
### Changed
|
||||
- Improve ObscuredVector2Int and ObscuredVector3Int vector components access performance
|
||||
|
||||
### Fixed
|
||||
- Reduce rare SpeedHackDetector false positive possibility
|
||||
- Fix few rare ObscuredCheatingDetector false positives (thx thiagolr)
|
||||
|
||||
## [2021.5.1] - 2022-09-10
|
||||
|
||||
### Changed
|
||||
- Improve ObscuredFilePrefsAutoSaver behavior in Editor (thx YeahBoi)
|
||||
|
||||
### Fixed
|
||||
- Fix ObscuredBigInteger corruption (thx jaeyoung)
|
||||
- Fix ambiguous APIs at the ObscuredBigInteger
|
||||
|
||||
## [2021.5.0] - 2022-07-31
|
||||
|
||||
### Added
|
||||
- Add IDisposable implementation to the SHA1Wrapper class
|
||||
- Add DurationSeconds property to the CodeHashGenerator results
|
||||
|
||||
### Changed
|
||||
- Improve CodeHashGenerator accuracy in Editor for IL2CPP platforms
|
||||
- Deprecate few obsolete CodeHashGenerator APIs
|
||||
- Improve Unity 2023 compatibility
|
||||
|
||||
### Fixed
|
||||
- Fix WebGL compilation regression
|
||||
|
||||
## [2021.4.2] - 2022-07-25
|
||||
|
||||
### Fixed
|
||||
- ObscuredCheatingDetector: fix possible rare false positive (thx tbiz5270)
|
||||
|
||||
## [2021.4.1] - 2022-07-21
|
||||
|
||||
### Fixed
|
||||
- SpeedHackDetector: fix possible rare false positive in Editor
|
||||
|
||||
## [2021.4.0] - 2022-07-16
|
||||
|
||||
### Added
|
||||
- Add LastOnlineTimeResult instance property to the TimeCheatingDetector
|
||||
- Add automatic ProGuard configuration to prevent errors due to minification
|
||||
- Add new menu item to configure proguard-user.txt on demand
|
||||
|
||||
### Changed
|
||||
- Make ProGuard configuration more granular to obfuscate more of the native code
|
||||
- Expose internal TimeCheatingDetector.IsReadyForForceCheck() API
|
||||
|
||||
### Fixed
|
||||
- Fix possible TimeCheatingDetector error due to certificate validation (thx murat303)
|
||||
|
||||
## [2021.3.0] - 2022-07-10
|
||||
|
||||
### Changed
|
||||
- Improve Speed Hack Detector sensitivity in sandboxed environments
|
||||
- Improve detectors' keepAlive logic when using additive scenes
|
||||
- Improve WebGL file system compatibility at Obscured File and Obscured File Prefs
|
||||
|
||||
### Fixed
|
||||
- Fix possible undesired detector self-destroy on additive scene load
|
||||
|
||||
## [2021.2.1] - 2022-07-04
|
||||
|
||||
### Changed
|
||||
- Change some property drawers to use Delayed fields to reduce CPU overhead while editing obscured fields in inspector
|
||||
|
||||
## [2021.2.0] - 2022-06-29
|
||||
|
||||
### Added
|
||||
- Add ObscuredBigInteger type
|
||||
- Add BigInteger type support to the ObscuredPrefs / ObscuredFilePrefs
|
||||
- Add TriggerDetection() utility method to all detectors
|
||||
- Add 'Trigger detection' context menu item to all detectors components
|
||||
|
||||
## [2021.1.1] - 2022-05-04
|
||||
|
||||
### Added
|
||||
- Add TimeCheatingDetector.GetOnlineTimeTask() overloads with CancellationToken argument
|
||||
|
||||
## [2021.1.0] - 2022-04-11
|
||||
|
||||
### Added
|
||||
- Add ObscuredFilePrefs Auto Save on mobile platforms (enabled by default)
|
||||
- Automatically saves unsaved changes on app loose focus / pause
|
||||
- Add API to disable ObscuredFilePrefs Auto Save (disables Auto Save on both mobile and non-mobile platforms)
|
||||
- Introduce IObscuredFileSettings to improve API usage experience
|
||||
|
||||
### Changed
|
||||
- Add locks to the ObscuredFilePrefs sync operations to improve stability when accessing it from different threads
|
||||
- Move ObscuredFilePrefs Save-On-Quit code to the Auto Save feature entity so it's disableable now
|
||||
|
||||
### Fixed
|
||||
- Prevent ObscuredFilePrefs Save-On-Quit while not initialized
|
||||
- Fix ObscuredFilePrefs behavior with disabled Reload Domain
|
||||
- Fix compilation error at Unity 2018 Android
|
||||
- Fix compilation warnings for WebGL platform
|
||||
|
||||
## [2021.0.10] - 2022-03-09
|
||||
|
||||
### Fixed
|
||||
- Fix ObscuredString name in Inspector might render incorrect in arrays (thx Sungmin An)
|
||||
|
||||
## [2021.0.9] - 2022-03-06
|
||||
|
||||
### Changed
|
||||
- CodeHashGenerator's Summary Hash is no longer printed for AAB builds
|
||||
- Skip Android Patch Packages hashing by CodeHashGenerator
|
||||
|
||||
### Fixed
|
||||
- Fix obsolete API usage leading to compilation error in Unity 2022.1
|
||||
|
||||
## [2021.0.8] - 2022-02-08
|
||||
|
||||
### Changed
|
||||
- Minor Prefs Editor UI improvements
|
||||
|
||||
### Fixed
|
||||
- Fix Prefs Editor window didn't update properly under specific conditions (thx Todd Gillissie)
|
||||
|
||||
## [2021.0.7] - 2021-11-18
|
||||
|
||||
### Fixed
|
||||
- Fix iOS Conditional compilation constants settings could not apply in some Unity versions (thx Hesham)
|
||||
- Fix empty ObscuredString fields automatic migration (thx thiagolr)
|
||||
|
||||
## [2021.0.6] - 2021-11-18
|
||||
|
||||
### Changed
|
||||
- Warn when trying to use ObscuredFile with StreamingAssets on Android and WebGL (thx Harama)
|
||||
|
||||
### Fixed
|
||||
- Fix automatic ObscuredString migration didn't happen properly in some cases (thx thiagolr)
|
||||
- Fix exception in ObscuredFilePrefs on iOS could happen under rare conditions
|
||||
- Fix ObscuredString example log
|
||||
|
||||
## [2021.0.5] - 2021-10-26
|
||||
|
||||
### Changed
|
||||
- Improve ObscuredPrefs and ObscuredFilePrefs compatibility with Obscured types
|
||||
|
||||
### Fixed
|
||||
- Fix TimeUtils could be disposed unexpectedly (thx Hesham)
|
||||
- Fix TimeUtils might not reinitialize properly in rare case
|
||||
|
||||
## [2021.0.4] - 2021-10-02
|
||||
|
||||
### Fixed
|
||||
- Fix BehaviorDesigner integration package compilation errors (thx Levent)
|
||||
|
||||
## [2021.0.3] - 2021-09-27
|
||||
|
||||
### Changed
|
||||
- Improve TimeCheatingDetector performance a bit
|
||||
|
||||
### Fixed
|
||||
- Fix missing script at the example scene
|
||||
- Fix CodeHashGeneratorListener example compilation errors
|
||||
|
||||
## [2021.0.2] - 2021-09-17
|
||||
|
||||
### Fixed
|
||||
- Fix empty string was read as null from ObscuredPrefs and ObscuredFilePrefs (thx C0dingschmuser)
|
||||
|
||||
## [2021.0.1] - 2021-09-10
|
||||
|
||||
### Changed
|
||||
- Improve exceptions logging a bit
|
||||
|
||||
### Fixed
|
||||
- Fix compilation exception for iOS platform (thx Vladnee)
|
||||
|
||||
## [2021.0.0] - 2021-09-06
|
||||
|
||||
### Added
|
||||
- Add new ObscuredFile and ObscuredFilePrefs tools to the ACTk 🧰
|
||||
- Encrypted and plain modes
|
||||
- All modes have data consistency validation
|
||||
- All modes have lock to device feature
|
||||
- ObscuredFilePrefs has simple and easy to use PlayerPrefs-like APIs
|
||||
- Async compatible
|
||||
- Supports UWP starting from Unity 2019.1
|
||||
- BehaviorDesigner and PlayMaker Actions
|
||||
- Add generic APIs to ObscuredPrefs
|
||||
- Add new types support to ObscuredPrefs:
|
||||
- rest of simple C# types (SByte, Byte, Int16, UInt16, Char)
|
||||
- System.DateTime
|
||||
- Color (it's possible to save HDR colors now)
|
||||
- Matrix4x4, RangeInt, Ray, Ray2D, RectInt, Vector2Int, Vector3Int, Vector4
|
||||
- Add ObscuredQuaternion property drawer (now it's editable from inspector)
|
||||
- Add automatic link.xml generation option to complement fix for WallHack Detector false positives due to stripping
|
||||
- Add additional information to the important error logs
|
||||
- Make ThreadSafeRandom utility public
|
||||
- Add Copy Player Prefs path context menu item to the Prefs Editor tab
|
||||
- Add ObscuredPrefs Vector2Int and Vector3Int support to BehaviorDesigner integration
|
||||
- Add new support contact, let's chat at [Discord](https://discord.gg/Ppsb89naWf)!
|
||||
|
||||
### Changed
|
||||
- Swap Changelog to md version to better match Unity packages format ([Keep a Changelog](https://keepachangelog.com/en/1.0.0/))
|
||||
- Rename following ObscuredPrefs API in order to better suite coding style:
|
||||
- OnAlterationDetected -> NotGenuineDataDetected
|
||||
- OnPossibleForeignSavesDetected -> DataFromAnotherDeviceDetected
|
||||
- lockToDevice -> DeviceLockLevel
|
||||
- Move ObscuredPrefs.DeviceLockLevel enum out from the ObscuredPrefs type
|
||||
- Introduce DeviceLockTamperingSensitivity instead of readForeignSaves and emergencyMode settings for additional clarity
|
||||
- Decimal values processing at ObscuredPrefs are much faster now with much lesser GC-allocations footprint
|
||||
- Improve exceptions handling across whole codebase
|
||||
- Improve incorrect type usage handling at ObscuredPrefs (thx David E)
|
||||
- Improve Settings UI a bit
|
||||
- Improve detectors startup a bit
|
||||
- Improve Prefs Editor error handling
|
||||
- Minor code refactoring and cleanup
|
||||
- Update some API docs
|
||||
|
||||
### Deprecated
|
||||
- Deprecate non-generic ObscuredPrefs APIs (to be removed in future versions)
|
||||
|
||||
### Removed
|
||||
- Remove .NET 3.5 scripting runtime version support
|
||||
|
||||
### Fixed
|
||||
- Fix possible data corruption at all Obscured types in super rare scenarios (only one rare case for ObscuredBool was found)
|
||||
- Fix possible false positives from WallHackDetector on Unity 2019.3 or newer when IL2CPP "Strip Engine Code" setting is used (thx Hesham)
|
||||
- Fix compilation warning on UWP platform
|
||||
- Fix redundant injection detector support were added into IL2CPP builds in some conditions
|
||||
- Fix exceptions in Unity 2021.2 and newer while browsing ACTk settings
|
||||
- Fix code hash pre-generation was run redundantly when building with Create Visual Studio Solution option enabled
|
||||
- Fix Behavior Tree at BehaviorDesigner's integration ObscuredPrefsExample scene
|
||||
- Fix other minor stuff here and there
|
||||
|
||||
## [2.3.4] and older
|
||||
|
||||
See older versions changelog in legacy text format [here](https://codestage.net/uas_files/actk/changelog-legacy.txt)
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a707e4914fc9f014790c02a3cd0b455d
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/CHANGELOG.md
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ac5220baa6a51bb47a5c640ddf6c0ce8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "ACTk.Editor",
|
||||
"references": [
|
||||
"ACTk.Runtime"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [
|
||||
{
|
||||
"name": "com.unity.modules.audio",
|
||||
"expression": "",
|
||||
"define": "UNITY_AUDIO_MODULE"
|
||||
}
|
||||
],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8ef82b58ed1acc8419a02b8a05286620
|
||||
timeCreated: 1554196096
|
||||
licenseType: Store
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/ACTk.Editor.asmdef
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1ff6bc3cba85fba4e922af0d4a624023
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
internal static class ACTkEditorConstants
|
||||
{
|
||||
internal static class Conditionals
|
||||
{
|
||||
public const string WallhackLinkXML = "ACTK_WALLHACK_LINK_XML";
|
||||
public const string ExcludeObfuscation = "ACTK_EXCLUDE_OBFUSCATION";
|
||||
public const string PreventReadPhoneState = "ACTK_PREVENT_READ_PHONE_STATE";
|
||||
public const string PreventInternetPermission = "ACTK_PREVENT_INTERNET_PERMISSION";
|
||||
public const string ThirdPartyIntegration = "ACTK_IS_HERE";
|
||||
public const string UsExportCompatible = "ACTK_US_EXPORT_COMPATIBLE";
|
||||
public const string NewtonsoftJson = "ACTK_NEWTONSOFT_JSON";
|
||||
|
||||
public const string InjectionDebug = "ACTK_INJECTION_DEBUG";
|
||||
public const string InjectionDebugVerbose = "ACTK_INJECTION_DEBUG_VERBOSE";
|
||||
public const string InjectionDebugParanoid = "ACTK_INJECTION_DEBUG_PARANOID";
|
||||
public const string WallhackDebug = "ACTK_WALLHACK_DEBUG";
|
||||
public const string DetectionBacklogs = "ACTK_DETECTION_BACKLOGS";
|
||||
public const string GenericDevLogs = "ACTK_DEV_LOGS";
|
||||
}
|
||||
|
||||
public const string SettingsProviderPath = "Code Stage/Anti-Cheat Toolkit";
|
||||
public const string MenuPath = "Code Stage/🕵 Anti-Cheat Toolkit/";
|
||||
public const string AssetsMenuPath = "Assets/Code Stage/🕵 Anti-Cheat Toolkit/";
|
||||
public const string ToolsMenuPath = "Tools/" + MenuPath;
|
||||
public const string GameObjectMenuPath = "GameObject/Create Other/" + MenuPath;
|
||||
|
||||
public static readonly string ProjectFolder = Path.GetFullPath(Path.Combine(Application.dataPath, "../"));
|
||||
public static readonly string ProjectTempFolder = Path.Combine(ProjectFolder, "Temp");
|
||||
public static readonly string ProjectLibraryFolder = Path.Combine(ProjectFolder, "Library");
|
||||
public static readonly string ProjectSettingsFolder = Path.Combine(ProjectFolder, "ProjectSettings");
|
||||
public static readonly string AssetsFolder = Path.Combine(ProjectFolder, "Assets");
|
||||
|
||||
public static readonly string[] HexTable = Enumerable.Range(0, 256).Select(v => v.ToString("x2")).ToArray();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a9ee7d4a58674ac69c27bc7c29417309
|
||||
timeCreated: 1552925230
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkEditorConstants.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Use it to guess current directory of the Anti-Cheat Toolkit.
|
||||
/// </summary>
|
||||
public class ACTkMarker : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns raw path of the ACTkMarker script for further reference.
|
||||
/// </summary>
|
||||
/// <returns>Path of the ACTkMarker ScriptableObject asset.</returns>
|
||||
public static string GetAssetPath()
|
||||
{
|
||||
string result;
|
||||
|
||||
var tempInstance = CreateInstance<ACTkMarker>();
|
||||
var script = MonoScript.FromScriptableObject(tempInstance);
|
||||
if (script != null)
|
||||
{
|
||||
result = AssetDatabase.GetAssetPath(script);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = AssetDatabase.FindAssets("ACTkMarker")[0];
|
||||
result = AssetDatabase.GUIDToAssetPath(result);
|
||||
}
|
||||
|
||||
DestroyImmediate(tempInstance);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 00b850c709170d1469bcd89e6f80b16c
|
||||
timeCreated: 1557660868
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMarker.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,233 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.Detectors;
|
||||
using CodeStage.AntiCheat.EditorCode.PostProcessors;
|
||||
using CodeStage.AntiCheat.EditorCode.Processors;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
internal static class ACTkMenuItems
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
public const string BuildProfilesLabel = "Build Profiles";
|
||||
#else
|
||||
public const string BuildProfilesLabel = "Build Settings";
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Main menu items
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Settings...", false, 100)]
|
||||
private static void ShowSettingsWindow()
|
||||
{
|
||||
ACTkSettings.Show();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Injection Detector Whitelist Editor...", false, 1000)]
|
||||
private static void ShowAssembliesWhitelistWindow()
|
||||
{
|
||||
UserWhitelistEditor.ShowWindow();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Calculate external build hashes", false, 1200)]
|
||||
private static async void HashExternalBuild()
|
||||
{
|
||||
try
|
||||
{
|
||||
var buildHashes = await CodeHashGeneratorPostprocessor.CalculateExternalBuildHashesAsync(null, true);
|
||||
if (buildHashes == null || buildHashes.FileHashes.Count == 0)
|
||||
{
|
||||
Debug.LogError(ACTk.LogPrefix + "External build hashing was not successful. " +
|
||||
"See previous log messages for possible details.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("External build hashing exception!", e);
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Configure proguard-user.txt", false, 1201)]
|
||||
private static void CheckProGuard()
|
||||
{
|
||||
BuildPreProcessor.CheckProGuard(true);
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types in Prefabs and Scriptable Objects...", false, 1500)]
|
||||
private static void MigrateObscuredTypesInAssets()
|
||||
{
|
||||
MigrateAssets();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types in opened scenes...", false, 1501)]
|
||||
private static void MigrateObscuredTypesInScene()
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateOpenedScenes();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Migrate/Migrate obscured types in " + BuildProfilesLabel + " scenes...",
|
||||
false, 1502)]
|
||||
private static void MigrateObscuredTypesInBuildSettingsScenes()
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateBuildProfilesScenes();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in Prefabs and Scriptable Objects...", false, 1500)]
|
||||
private static void ValidateObscuredTypesInAssets()
|
||||
{
|
||||
ValidateAssets();
|
||||
}
|
||||
|
||||
private static void ValidateAssets(string[] assetPaths = null)
|
||||
{
|
||||
var invalidAssetsPaths = ObscuredTypesValidator.ValidateProjectAssets(assetPaths);
|
||||
if (invalidAssetsPaths != null && invalidAssetsPaths.Length > 0)
|
||||
{
|
||||
var result = ConfirmMigrationAfterValidation();
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
MigrateAssets(invalidAssetsPaths, true);
|
||||
break;
|
||||
case 2:
|
||||
MigrateAssets(invalidAssetsPaths, true, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void MigrateAssets(string[] assetPaths = null, bool fixOnly = false, bool skipInteraction = false)
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateProjectAssets(assetPaths, fixOnly, skipInteraction);
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in opened scenes...", false,
|
||||
1501)]
|
||||
private static void ValidateObscuredTypesInOpenedScenes()
|
||||
{
|
||||
ValidateObscuredTypesInScenes(() => ObscuredTypesValidator.ValidateOpenedScenes(),
|
||||
(fixOnly, skipInteraction) => ObscuredTypesMigrator.MigrateOpenedScenes(fixOnly, skipInteraction));
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.ToolsMenuPath + "Validate/Validate obscured types in " + BuildProfilesLabel + " scenes...",
|
||||
false, 1502)]
|
||||
private static void ValidateObscuredTypesInBuildSettingsScenes()
|
||||
{
|
||||
ValidateObscuredTypesInScenes(() => ObscuredTypesValidator.ValidateBuildProfilesScenes(),
|
||||
(fixOnly, skipInteraction) =>
|
||||
ObscuredTypesMigrator.MigrateBuildProfilesScenes(fixOnly, skipInteraction));
|
||||
}
|
||||
|
||||
private static void ValidateObscuredTypesInScenes(Func<int> validateFunc, Action<bool, bool> migrateFunc)
|
||||
{
|
||||
var invalidPropertiesFound = validateFunc();
|
||||
if (invalidPropertiesFound > 0)
|
||||
{
|
||||
var result = ConfirmMigrationAfterValidation();
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
migrateFunc(true, false);
|
||||
break;
|
||||
case 2:
|
||||
migrateFunc(true, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// GameObject menu items
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + "All detectors", false, 0)]
|
||||
private static void AddAllDetectorsToScene()
|
||||
{
|
||||
AddInjectionDetectorToScene();
|
||||
AddObscuredCheatingDetectorToScene();
|
||||
AddSpeedHackDetectorToScene();
|
||||
AddWallHackDetectorToScene();
|
||||
AddTimeCheatingDetectorToScene();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + InjectionDetector.ComponentName, false, 1)]
|
||||
private static void AddInjectionDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<InjectionDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + ObscuredCheatingDetector.ComponentName, false, 1)]
|
||||
private static void AddObscuredCheatingDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<ObscuredCheatingDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + SpeedHackDetector.ComponentName, false, 1)]
|
||||
private static void AddSpeedHackDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<SpeedHackDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + WallHackDetector.ComponentName, false, 1)]
|
||||
private static void AddWallHackDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<WallHackDetector>();
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.GameObjectMenuPath + TimeCheatingDetector.ComponentName, false, 1)]
|
||||
private static void AddTimeCheatingDetectorToScene()
|
||||
{
|
||||
DetectorTools.SetupDetectorInScene<TimeCheatingDetector>();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// Project menu items
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
[MenuItem(ACTkEditorConstants.AssetsMenuPath + "Validate Obscured Types on Prefabs and Scriptable Objects", false, 200)]
|
||||
private static void ValidateObscuredTypesInSelectedFolder()
|
||||
{
|
||||
var targetFiles = AssetTools.GetMigratableAssetsFilePaths(Selection.assetGUIDs);
|
||||
ValidateAssets(targetFiles);
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.AssetsMenuPath + "Validate Obscured Types on Prefabs and Scriptable Objects", true, 200)]
|
||||
private static bool ValidateObscuredTypesInSelectedFolderValidate()
|
||||
{
|
||||
var targetFiles = AssetTools.GetMigratableAssetsFilePaths(Selection.assetGUIDs);
|
||||
return targetFiles != null && targetFiles.Length > 0;
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.AssetsMenuPath + "Migrate Obscured Types on Prefabs and Scriptable Objects", false, 200)]
|
||||
private static void MigrateObscuredTypesInSelectedFolder()
|
||||
{
|
||||
var targetFiles = AssetTools.GetMigratableAssetsFilePaths(Selection.assetGUIDs);
|
||||
MigrateAssets(targetFiles);
|
||||
}
|
||||
|
||||
[MenuItem(ACTkEditorConstants.AssetsMenuPath + "Migrate Obscured Types on Prefabs and Scriptable Objects", true, 200)]
|
||||
private static bool MigrateObscuredTypesInSelectedFolderValidate()
|
||||
{
|
||||
var targetFiles = AssetTools.GetMigratableAssetsFilePaths(Selection.assetGUIDs);
|
||||
return targetFiles != null && targetFiles.Length > 0;
|
||||
}
|
||||
|
||||
private static int ConfirmMigrationAfterValidation()
|
||||
{
|
||||
return EditorUtility.DisplayDialogComplex(ObscuredTypesValidator.ModuleName,
|
||||
"Invalid types found. It's recommended to try migrate and / or fix them.\n" +
|
||||
"Select 'Migrate and fix' only if you did update from the older ACTk version.",
|
||||
"Migrate and fix", "Cancel", "Fix only");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e10289b3bdb7db64c8f2c624b337d331
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ACTkMenuItems.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("CodeStage.ACTk.Service")]
|
||||
[assembly: InternalsVisibleTo("CodeStage.ACTk.Tests.Editor")]
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a1cc293465f841498ad940f7813ccedd
|
||||
timeCreated: 1588809689
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/AssemblyInfo.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d9e6164ee563b444d87cbe3437d6012a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b51e1480187f1ad4ab95559fe4ef5720
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
#region copyright
|
||||
// -------------------------------------------------------
|
||||
// Copyright (C) Dmitry Yuhanov [https://codestage.net]
|
||||
// -------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.EditorCommon.Tools
|
||||
{
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
internal static class CSColorTools
|
||||
{
|
||||
internal enum ColorKind
|
||||
{
|
||||
Green,
|
||||
Red,
|
||||
Purple
|
||||
}
|
||||
|
||||
public const string GreenHex = "02C85F";
|
||||
public const string GreenDarkHex = "02981F";
|
||||
public const string PurpleHex = "A76ED1";
|
||||
public const string PurpleDarkHex = "7030A0";
|
||||
public const string RedHex = "FF4040";
|
||||
public const string RedAltHex = "FF6060";
|
||||
public const string RedDarkHex = "FF1010";
|
||||
public const string BrightGreyHex = "E5E5E5";
|
||||
|
||||
public readonly static Color32 Green = new Color32(2, 200, 95, 255);
|
||||
public readonly static Color32 GreenDark = new Color32(2, 152, 31, 255);
|
||||
public readonly static Color32 Purple = new Color32(167, 110, 209, 255);
|
||||
public readonly static Color32 PurpleDark = new Color32(112, 48, 160, 255);
|
||||
public readonly static Color32 RedAlt = new Color32(255, 96, 96, 255);
|
||||
public readonly static Color32 RedDark = new Color32(255, 16, 16, 255);
|
||||
public readonly static Color32 BrightGrey = new Color32(229, 229, 229, 255);
|
||||
|
||||
public static string EditorGreenHex
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? GreenHex : GreenDarkHex;
|
||||
}
|
||||
}
|
||||
|
||||
public static string EditorPurpleHex
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? PurpleHex : PurpleDarkHex;
|
||||
}
|
||||
}
|
||||
|
||||
public static string EditorRedHex
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? RedAltHex : RedDarkHex;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color EditorGreen
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? Green : GreenDark;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color EditorPurple
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? Purple : PurpleDark;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color EditorRed
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? RedAlt : RedDark;
|
||||
}
|
||||
}
|
||||
|
||||
public static Color DimmedColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChangeAlpha(GUI.skin.label.normal.textColor, 150);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color BrightGreyDimmed
|
||||
{
|
||||
get
|
||||
{
|
||||
return ChangeAlpha(BrightGrey, 150);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color GreenColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return LerpToGreen(GUI.skin.label.normal.textColor, 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color RedColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return LerpToRed(GUI.skin.label.normal.textColor, 0.3f);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color BackgroundGreenTint
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? new Color32(0, 255, 0, 150) : new Color32(0, 255, 0, 30);
|
||||
}
|
||||
}
|
||||
|
||||
public static Color BackgroundRedTint
|
||||
{
|
||||
get
|
||||
{
|
||||
return EditorGUIUtility.isProSkin ? new Color32(255, 0, 0, 150) : new Color32(255, 0, 0, 30);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WrapBool(bool value)
|
||||
{
|
||||
return WrapString(value.ToString(), value ? ColorKind.Green : ColorKind.Red);
|
||||
}
|
||||
|
||||
public static string WrapString(string inputGood, string inputBad, bool good)
|
||||
{
|
||||
return WrapString(good ? inputGood : inputBad, good ? ColorKind.Green : ColorKind.Red);
|
||||
}
|
||||
|
||||
public static string WrapString(string input, bool good)
|
||||
{
|
||||
return WrapString(input, good ? ColorKind.Green : ColorKind.Red);
|
||||
}
|
||||
|
||||
public static string WrapString(string input, ColorKind colorKind)
|
||||
{
|
||||
switch (colorKind)
|
||||
{
|
||||
case ColorKind.Green:
|
||||
return WrapString(input, EditorGreenHex);
|
||||
case ColorKind.Red:
|
||||
return WrapString(input, EditorRedHex);
|
||||
case ColorKind.Purple:
|
||||
return WrapString(input, EditorPurpleHex);
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("colorKind", colorKind, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string WrapString(string input, Color color)
|
||||
{
|
||||
var colorString = ColorUtility.ToHtmlStringRGBA(color);
|
||||
return WrapString(input, colorString);
|
||||
}
|
||||
|
||||
// color argument should be in rrggbbaa format or match standard html color name, without '#'
|
||||
public static string WrapString(string input, string color)
|
||||
{
|
||||
return "<color=#" + color + ">" + input + "</color>";
|
||||
}
|
||||
|
||||
public static Color32 LerpToRed(Color32 inValue, float greenAmountPercent)
|
||||
{
|
||||
return Color.Lerp(inValue, Color.red, greenAmountPercent);
|
||||
}
|
||||
|
||||
public static Color32 LerpToGreen(Color32 inValue, float greenAmountPercent)
|
||||
{
|
||||
return Color.Lerp(inValue, Color.green, greenAmountPercent);
|
||||
}
|
||||
|
||||
public static Color32 LerpToYellow(Color32 inValue, float greenAmountPercent)
|
||||
{
|
||||
return Color.Lerp(inValue, Color.yellow, greenAmountPercent);
|
||||
}
|
||||
|
||||
private static Color32 ChangeAlpha(Color32 inValue, byte alphaValue)
|
||||
{
|
||||
inValue.a = alphaValue;
|
||||
return inValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9243bbab60b6a3b4bafdac4bdac4d91f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSColorTools.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#region copyright
|
||||
// -------------------------------------------------------
|
||||
// Copyright (C) Dmitry Yuhanov [https://codestage.net]
|
||||
// -------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.EditorCommon.Tools
|
||||
{
|
||||
using UnityEngine;
|
||||
|
||||
internal static class CSEditorIcons
|
||||
{
|
||||
public static Texture AssetStore { get { return CSTextureLoader.GetIconTexture("Asset Store", ImageKind.InternalIcon); } }
|
||||
public static Texture Error { get { return CSTextureLoader.GetIconTexture("console.erroricon", ImageKind.InternalIcon); } }
|
||||
public static Texture ErrorSmall { get { return CSTextureLoader.GetIconTexture("console.erroricon.sml", ImageKind.InternalIcon); } }
|
||||
public static Texture Favorite { get { return CSTextureLoader.GetIconTexture("Favorite", ImageKind.InternalIcon); } }
|
||||
public static Texture FavoriteIcon { get { return CSTextureLoader.GetIconTexture("Favorite Icon", ImageKind.InternalIcon); } }
|
||||
public static Texture FilterByType { get { return CSTextureLoader.GetIconTexture("FilterByType", ImageKind.InternalIcon); } }
|
||||
public static Texture Folder { get { return CSTextureLoader.GetIconTexture("Folder Icon", ImageKind.InternalIcon); } }
|
||||
public static Texture GameObject { get { return CSTextureLoader.GetTypeImage(typeof(GameObject)); } }
|
||||
public static Texture Help { get { return CSTextureLoader.GetIconTexture("_Help", ImageKind.InternalIcon); } }
|
||||
public static Texture HierarchyView { get { return CSTextureLoader.GetIconTexture("UnityEditor.SceneHierarchyWindow", ImageKind.InternalIcon); } }
|
||||
public static Texture Info { get { return CSTextureLoader.GetIconTexture("console.infoicon", ImageKind.InternalIcon); } }
|
||||
public static Texture InfoSmall { get { return CSTextureLoader.GetIconTexture("console.infoicon.sml", ImageKind.InternalIcon); } }
|
||||
public static Texture Inspector { get { return CSTextureLoader.GetIconTexture("UnityEditor.InspectorWindow", ImageKind.InternalIcon); } }
|
||||
public static Texture Prefab { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.prefab"); } }
|
||||
public static Texture ProjectView { get { return CSTextureLoader.GetIconTexture("Project", ImageKind.InternalIcon); } }
|
||||
public static Texture Scene { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.unity"); } }
|
||||
public static Texture Script { get { return UnityEditorInternal.InternalEditorUtility.FindIconForFile("dummy.cs"); } }
|
||||
public static Texture Search { get { return CSTextureLoader.GetIconTexture("Search Icon", ImageKind.InternalIcon); } }
|
||||
public static Texture Settings { get { return CSTextureLoader.GetIconTexture("Settings", ImageKind.InternalIcon); } }
|
||||
public static Texture Warn { get { return CSTextureLoader.GetIconTexture("console.warnicon", ImageKind.InternalIcon); } }
|
||||
public static Texture WarnSmall { get { return CSTextureLoader.GetIconTexture("console.warnicon.sml", ImageKind.InternalIcon); } }
|
||||
public static Texture Menu { get { return CSTextureLoader.GetIconTexture("_Menu@2x", ImageKind.InternalIcon); } }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 66cb067166e1b12439fba7d0d810a0bc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSEditorIcons.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#region copyright
|
||||
// -------------------------------------------------------
|
||||
// Copyright (C) Dmitry Yuhanov [https://codestage.net]
|
||||
// -------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.EditorCommon.Tools
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
internal static class CSFileTools
|
||||
{
|
||||
public static void DeleteFile(string path)
|
||||
{
|
||||
if (!File.Exists(path)) return;
|
||||
RemoveReadOnlyAttribute(path);
|
||||
File.Delete(path);
|
||||
}
|
||||
|
||||
private static void RemoveReadOnlyAttribute(string filePath)
|
||||
{
|
||||
var attributes = File.GetAttributes(filePath);
|
||||
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||
File.SetAttributes(filePath, attributes & ~FileAttributes.ReadOnly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64edcf809efa9c64c899a0bd87134443
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSFileTools.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine.SceneManagement;
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
using UnityEditor.Build.Profile;
|
||||
using System.Linq;
|
||||
#endif
|
||||
|
||||
namespace CodeStage.EditorCommon.Tools
|
||||
{
|
||||
internal static class CSSceneTools
|
||||
{
|
||||
public static Scene[] GetOpenedScenes()
|
||||
{
|
||||
var openScenes = new Scene[SceneManager.sceneCount];
|
||||
for (var i = 0; i < SceneManager.sceneCount; i++)
|
||||
{
|
||||
openScenes[i] = SceneManager.GetSceneAt(i);
|
||||
}
|
||||
return openScenes;
|
||||
}
|
||||
|
||||
public static string[] GetOpenedValidScenesPaths()
|
||||
{
|
||||
var openedScenes = GetOpenedScenes();
|
||||
var scenePaths = new List<string>();
|
||||
foreach (var scene in openedScenes)
|
||||
{
|
||||
if (scene.IsValid())
|
||||
scenePaths.Add(scene.path);
|
||||
}
|
||||
return scenePaths.ToArray();
|
||||
}
|
||||
|
||||
public static string[] GetBuildProfilesScenesPaths(bool includeDisabled = false)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
var scenePaths = new HashSet<string>(GetBuildSettingsSceneList(includeDisabled)); // uses EditorBuildSettings.scenes
|
||||
var allBuildProfiles = AssetDatabase.FindAssets("t:BuildProfile");
|
||||
foreach (var buildProfileGuid in allBuildProfiles)
|
||||
{
|
||||
var buildProfile = AssetDatabase.LoadAssetAtPath<BuildProfile>(AssetDatabase.GUIDToAssetPath(buildProfileGuid));
|
||||
#if UNITY_6000_1_OR_NEWER
|
||||
var overrideGlobalSceneList = buildProfile.overrideGlobalScenes;
|
||||
#else
|
||||
var overrideGlobalSceneList = false;
|
||||
try
|
||||
{
|
||||
var overrideGlobalSceneListProperty = typeof(BuildProfile).GetProperty("overrideGlobalSceneList",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
overrideGlobalSceneList = overrideGlobalSceneListProperty != null &&
|
||||
(bool)overrideGlobalSceneListProperty.GetValue(buildProfile);
|
||||
}
|
||||
catch { // ignored
|
||||
}
|
||||
#endif
|
||||
if (!overrideGlobalSceneList)
|
||||
continue;
|
||||
|
||||
foreach (var overridenSceneListScene in buildProfile.scenes)
|
||||
{
|
||||
scenePaths.Add(overridenSceneListScene.path);
|
||||
}
|
||||
}
|
||||
return scenePaths.ToArray();
|
||||
#else
|
||||
return GetBuildSettingsSceneList().ToArray();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static List<string> GetBuildSettingsSceneList(bool includeDisabled = false)
|
||||
{
|
||||
var scenes = EditorBuildSettings.scenes;
|
||||
var scenePaths = new List<string>();
|
||||
foreach (var scene in scenes)
|
||||
{
|
||||
if (includeDisabled || scene.enabled)
|
||||
scenePaths.Add(scene.path);
|
||||
}
|
||||
return scenePaths;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0fe63d325ce40684ab7b869a405e8bbb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSSceneTools.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
#region copyright
|
||||
// -------------------------------------------------------
|
||||
// Copyright (C) Dmitry Yuhanov [https://codestage.net]
|
||||
// -------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.EditorCommon.Tools
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
internal enum ImageKind
|
||||
{
|
||||
External,
|
||||
InternalTexture,
|
||||
InternalIcon
|
||||
}
|
||||
|
||||
internal static class CSTextureLoader
|
||||
{
|
||||
public static string ExternalTexturesFolder { get; set; }
|
||||
public static string LogPrefix { get; set; }
|
||||
|
||||
private static readonly Dictionary<string, Texture> CachedTextures = new Dictionary<string, Texture>();
|
||||
|
||||
public static Texture GetTexture(string fileName)
|
||||
{
|
||||
return GetTexture(fileName, false);
|
||||
}
|
||||
|
||||
public static Texture GetIconTexture(string fileName, ImageKind kind = ImageKind.External)
|
||||
{
|
||||
return GetTexture(fileName, true, kind);
|
||||
}
|
||||
|
||||
private static Texture GetTexture(string fileName, bool icon, ImageKind kind = ImageKind.External)
|
||||
{
|
||||
Texture result;
|
||||
var isDark = EditorGUIUtility.isProSkin;
|
||||
|
||||
var textureName = fileName;
|
||||
if (isDark)
|
||||
textureName = "d_" + textureName;
|
||||
|
||||
if (CachedTextures.ContainsKey(textureName))
|
||||
{
|
||||
result = CachedTextures[textureName];
|
||||
}
|
||||
else
|
||||
{
|
||||
var path = fileName;
|
||||
|
||||
if (kind == ImageKind.External)
|
||||
{
|
||||
fileName = textureName;
|
||||
path = Path.Combine(ExternalTexturesFolder, "Textures");
|
||||
|
||||
if (icon)
|
||||
path = Path.Combine(path, "Icons");
|
||||
|
||||
path = Path.Combine(path, fileName);
|
||||
if (!File.Exists(Path.GetFullPath(path)) && !Path.HasExtension(path))
|
||||
{
|
||||
path = Path.ChangeExtension(path, "png");
|
||||
}
|
||||
|
||||
if (!File.Exists(Path.GetFullPath(path)))
|
||||
{
|
||||
Debug.LogWarning("Couldn't find icon " + fileName + " at path " + path);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
switch (kind)
|
||||
{
|
||||
case ImageKind.External:
|
||||
result = AssetDatabase.LoadAssetAtPath(path, typeof(Texture2D)) as Texture2D;
|
||||
break;
|
||||
case ImageKind.InternalTexture:
|
||||
result = EditorGUIUtility.FindTexture(path);
|
||||
break;
|
||||
case ImageKind.InternalIcon:
|
||||
result = EditorGUIUtility.IconContent(path).image;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("kind", kind, null);
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
Debug.LogError(LogPrefix + "Some error occurred while looking for image\n" + path);
|
||||
else
|
||||
CachedTextures[textureName] = result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Texture GetTypeImage(Type type)
|
||||
{
|
||||
var key = type.ToString();
|
||||
if (CachedTextures.ContainsKey(key))
|
||||
{
|
||||
return CachedTextures[key];
|
||||
}
|
||||
|
||||
var texture = EditorGUIUtility.ObjectContent(null, type).image;
|
||||
CachedTextures.Add(key, texture);
|
||||
|
||||
return texture;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 67cfa036dfc9bcf4292fa6a9f8b35555
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Common/Tools/CSTextureLoader.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f0c63cf6cabe3a547a0b46de95bff055
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Detectors;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof (InjectionDetector))]
|
||||
internal class InjectionDetectorEditor : KeepAliveBehaviourEditor<InjectionDetector>
|
||||
{
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
if (!ACTkSettings.Instance.InjectionDetectorEnabled)
|
||||
{
|
||||
using (GUITools.Vertical(GUITools.PanelWithBackground))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.HelpBox("Injection Detector support is not enabled! Injection Detector will not work properly",
|
||||
MessageType.Error, true);
|
||||
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
if (GUILayout.Button("Enable Now"))
|
||||
{
|
||||
ACTkSettings.Instance.InjectionDetectorEnabled = true;
|
||||
}
|
||||
if (GUILayout.Button("Enable In settings..."))
|
||||
{
|
||||
ACTkSettings.Show();
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (SettingsUtils.IsIL2CPPEnabled())
|
||||
{
|
||||
EditorGUILayout.HelpBox("Mono Injections are not possible in IL2CPP, this detector is not needed in IL2CPP builds",
|
||||
MessageType.Info, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!InjectionRoutines.IsTargetPlatformCompatible())
|
||||
{
|
||||
EditorGUILayout.HelpBox("Injection Detection is only supported in Standalone and Android builds",
|
||||
MessageType.Warning, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6025f911d895a7e43a5d5c6229254129
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/InjectionDetectorEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Common;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
internal class KeepAliveBehaviourEditor<T> : Editor where T: KeepAliveBehaviour<T>
|
||||
{
|
||||
protected T self;
|
||||
|
||||
private SerializedProperty autoStart;
|
||||
private SerializedProperty autoDispose;
|
||||
private SerializedProperty keepAlive;
|
||||
private SerializedProperty detectionEvent;
|
||||
private SerializedProperty detectionEventHasListener;
|
||||
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
autoStart = serializedObject.FindProperty("autoStart");
|
||||
autoDispose = serializedObject.FindProperty("autoDispose");
|
||||
keepAlive = serializedObject.FindProperty("keepAlive");
|
||||
detectionEvent = serializedObject.FindProperty("detectionEvent");
|
||||
detectionEventHasListener = serializedObject.FindProperty("detectionEventHasListener");
|
||||
|
||||
self = (T)target;
|
||||
|
||||
FindUniqueDetectorProperties();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
if (self == null) return;
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUIUtility.labelWidth = 140;
|
||||
EditorGUILayout.Space();
|
||||
DrawHeader("Base settings");
|
||||
|
||||
EditorGUILayout.PropertyField(autoStart);
|
||||
detectionEventHasListener.boolValue = EditorTools.CheckUnityEventHasActivePersistentListener(detectionEvent);
|
||||
|
||||
CheckAdditionalEventsForListeners();
|
||||
|
||||
if (autoStart.boolValue && !detectionEventHasListener.boolValue && !AdditionalEventsHasListeners())
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent("You need to add at least one active item to the Events in order to use Auto Start feature!"), GUITools.BoldLabel);
|
||||
}
|
||||
else if (!autoStart.boolValue)
|
||||
{
|
||||
EditorGUILayout.LabelField(new GUIContent("Don't forget to start detection!", "You should start detector from code using ObscuredCheatingDetector.StartDetection() method. See readme for details."), GUITools.BoldLabel);
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
EditorGUILayout.PropertyField(autoDispose);
|
||||
EditorGUILayout.PropertyField(keepAlive);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (DrawUniqueDetectorProperties())
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
|
||||
//DrawHeader("Events");
|
||||
|
||||
EditorGUILayout.PropertyField(detectionEvent);
|
||||
DrawAdditionalEvents();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
EditorGUIUtility.labelWidth = 0;
|
||||
}
|
||||
|
||||
protected virtual void DrawHeader(string text)
|
||||
{
|
||||
GUITools.DrawHeader(text);
|
||||
}
|
||||
|
||||
protected virtual bool AdditionalEventsHasListeners()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected virtual void FindUniqueDetectorProperties() {}
|
||||
protected virtual bool DrawUniqueDetectorProperties() { return false; }
|
||||
protected virtual void CheckAdditionalEventsForListeners() {}
|
||||
protected virtual void DrawAdditionalEvents() {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6b59c308aff5e054991de809a3b5985b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/KeepAliveBehaviourEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Detectors;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof (ObscuredCheatingDetector))]
|
||||
internal class ObscuredCheatingDetectorEditor : KeepAliveBehaviourEditor<ObscuredCheatingDetector>
|
||||
{
|
||||
private SerializedProperty honeyPot;
|
||||
private SerializedProperty doubleEpsilon;
|
||||
private SerializedProperty floatEpsilon;
|
||||
private SerializedProperty vector2Epsilon;
|
||||
private SerializedProperty vector3Epsilon;
|
||||
private SerializedProperty quaternionEpsilon;
|
||||
|
||||
protected override void FindUniqueDetectorProperties()
|
||||
{
|
||||
honeyPot = serializedObject.FindProperty("honeyPot");
|
||||
doubleEpsilon = serializedObject.FindProperty("doubleEpsilon");
|
||||
floatEpsilon = serializedObject.FindProperty("floatEpsilon");
|
||||
vector2Epsilon = serializedObject.FindProperty("vector2Epsilon");
|
||||
vector3Epsilon = serializedObject.FindProperty("vector3Epsilon");
|
||||
quaternionEpsilon = serializedObject.FindProperty("quaternionEpsilon");
|
||||
}
|
||||
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
DrawHeader("Specific settings");
|
||||
|
||||
EditorGUILayout.PropertyField(honeyPot);
|
||||
EditorGUILayout.PropertyField(doubleEpsilon);
|
||||
EditorGUILayout.PropertyField(floatEpsilon);
|
||||
EditorGUILayout.PropertyField(vector2Epsilon, new GUIContent("Vector2 Epsilon"));
|
||||
EditorGUILayout.PropertyField(vector3Epsilon, new GUIContent("Vector3 Epsilon"));
|
||||
EditorGUILayout.PropertyField(quaternionEpsilon);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8df36b70906d65d43bcb3ddce3fe36ba
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/ObscuredCheatingDetectorEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Detectors;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.EditorTools;
|
||||
using UnityEngine;
|
||||
using EditorTools = EditorCode.EditorTools;
|
||||
|
||||
[CustomEditor(typeof (SpeedHackDetector))]
|
||||
internal class SpeedHackDetectorEditor : KeepAliveBehaviourEditor<SpeedHackDetector>
|
||||
{
|
||||
private SerializedProperty interval;
|
||||
private SerializedProperty threshold;
|
||||
private SerializedProperty maxFalsePositives;
|
||||
private SerializedProperty coolDown;
|
||||
private SerializedProperty useDsp;
|
||||
private SerializedProperty watchTimeScale;
|
||||
|
||||
protected override void FindUniqueDetectorProperties()
|
||||
{
|
||||
interval = serializedObject.FindProperty("interval");
|
||||
threshold = serializedObject.FindProperty("threshold");
|
||||
maxFalsePositives = serializedObject.FindProperty("maxFalsePositives");
|
||||
coolDown = serializedObject.FindProperty("coolDown");
|
||||
|
||||
useDsp = serializedObject.GetProperty(nameof(SpeedHackDetector.UseDsp));
|
||||
watchTimeScale = serializedObject.GetProperty(nameof(SpeedHackDetector.WatchTimeScale));
|
||||
}
|
||||
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
DrawHeader("Specific settings");
|
||||
|
||||
EditorGUILayout.PropertyField(interval);
|
||||
EditorGUILayout.PropertyField(threshold);
|
||||
EditorGUILayout.PropertyField(maxFalsePositives);
|
||||
EditorGUILayout.PropertyField(coolDown);
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
EditorGUILayout.PropertyField(useDsp);
|
||||
#else
|
||||
EditorGUILayout.PropertyField(useDsp, new GUIContent( ObjectNames.NicifyVariableName(nameof(SpeedHackDetector.UseDsp)), useDsp.tooltip));
|
||||
#endif
|
||||
if (useDsp.boolValue)
|
||||
EditorGUILayout.HelpBox("Dsp timers may cause false positives on some hardware.\nMake sure to test on target devices before using this in production.", MessageType.Warning);
|
||||
|
||||
#if UNITY_AUDIO_MODULE
|
||||
if (!EditorTools.IsAudioManagerEnabled())
|
||||
{
|
||||
EditorGUILayout.HelpBox("Dsp option is not available since Disable Unity Audio option is enabled.", MessageType.Error);
|
||||
if (GUILayout.Button("Open Audio Settings"))
|
||||
{
|
||||
SettingsService.OpenProjectSettings("Project/Audio");
|
||||
#if UNITY_2021_3_OR_NEWER
|
||||
Highlighter.Highlight("Project Settings", EditorTools.GetAudioManagerEnabledPropertyPath(), HighlightSearchMode.Identifier);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
EditorGUILayout.HelpBox("Dsp option is not available since built-in Audio module is disabled.", MessageType.Error);
|
||||
#endif
|
||||
|
||||
#if UNITY_2020_1_OR_NEWER
|
||||
EditorGUILayout.PropertyField(watchTimeScale);
|
||||
#else
|
||||
EditorGUILayout.PropertyField(watchTimeScale, new GUIContent(ObjectNames.NicifyVariableName(nameof(SpeedHackDetector.WatchTimeScale)), watchTimeScale.tooltip));
|
||||
#endif
|
||||
if (watchTimeScale.boolValue)
|
||||
{
|
||||
EditorGUILayout.HelpBox("TimeScale watching monitors for unauthorized changes to Time.timeScale.\n" +
|
||||
"Use SpeedHackDetector.SetTimeScale and AllowAnyTimeScale APIs to change timeScale safely.", MessageType.Info);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 199f39969debe8f46afc5f32b333be3b
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/SpeedHackDetectorEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Detectors;
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof(TimeCheatingDetector))]
|
||||
internal class TimeCheatingDetectorEditor : KeepAliveBehaviourEditor<TimeCheatingDetector>
|
||||
{
|
||||
#if !ACTK_PREVENT_INTERNET_PERMISSION
|
||||
private SerializedProperty requestUrl;
|
||||
private SerializedProperty requestMethod;
|
||||
private SerializedProperty timeoutSeconds;
|
||||
private SerializedProperty interval;
|
||||
private SerializedProperty realCheatThreshold;
|
||||
private SerializedProperty wrongTimeThreshold;
|
||||
private SerializedProperty ignoreSetCorrectTime;
|
||||
|
||||
protected override void FindUniqueDetectorProperties()
|
||||
{
|
||||
requestUrl = serializedObject.FindProperty("requestUrl");
|
||||
requestMethod = serializedObject.FindProperty("requestMethod");
|
||||
timeoutSeconds = serializedObject.FindProperty("timeoutSeconds");
|
||||
interval = serializedObject.FindProperty("interval");
|
||||
realCheatThreshold = serializedObject.FindProperty("realCheatThreshold");
|
||||
wrongTimeThreshold = serializedObject.FindProperty("wrongTimeThreshold");
|
||||
ignoreSetCorrectTime = serializedObject.FindProperty("ignoreSetCorrectTime");
|
||||
}
|
||||
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
DrawHeader("Specific settings");
|
||||
|
||||
EditorGUIUtility.labelWidth += 10;
|
||||
EditorGUILayout.PropertyField(ignoreSetCorrectTime);
|
||||
EditorGUIUtility.labelWidth -= 10;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
EditorGUILayout.PropertyField(requestUrl, new GUIContent("URL", requestUrl.tooltip));
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
self.RequestUrl = requestUrl.stringValue;
|
||||
}
|
||||
|
||||
#if UNITY_WEBGL
|
||||
GUILayout.Label("<b>To avoid CORS limitations while running in WebGL, URL will be changed to the current domain, if it does points to any other domain</b>", GUITools.RichMiniLabel);
|
||||
EditorGUILayout.Space();
|
||||
#endif
|
||||
|
||||
EditorGUILayout.PropertyField(requestMethod, new GUIContent("Method", requestMethod.tooltip));
|
||||
|
||||
EditorGUILayout.PropertyField(timeoutSeconds);
|
||||
EditorGUILayout.PropertyField(interval);
|
||||
EditorGUILayout.PropertyField(realCheatThreshold);
|
||||
EditorGUILayout.PropertyField(wrongTimeThreshold);
|
||||
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
GUILayout.Label("<b>Detector disabled with ACTK_PREVENT_INTERNET_PERMISSION conditional symbol</b>", GUITools.RichLabel);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2fb4c7beaf58d554ab0f85d86b53726e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/TimeCheatingDetectorEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.Editors
|
||||
{
|
||||
using Detectors;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[CustomEditor(typeof (WallHackDetector))]
|
||||
internal class WallHackDetectorEditor : KeepAliveBehaviourEditor<WallHackDetector>
|
||||
{
|
||||
private SerializedProperty wireframeDelay;
|
||||
private SerializedProperty raycastDelay;
|
||||
private SerializedProperty spawnPosition;
|
||||
private SerializedProperty maxFalsePositives;
|
||||
|
||||
private SerializedProperty checkRigidbody;
|
||||
private SerializedProperty checkController;
|
||||
private SerializedProperty checkWireframe;
|
||||
private SerializedProperty checkRaycast;
|
||||
|
||||
protected override void FindUniqueDetectorProperties()
|
||||
{
|
||||
raycastDelay = serializedObject.FindProperty("raycastDelay");
|
||||
wireframeDelay = serializedObject.FindProperty("wireframeDelay");
|
||||
spawnPosition = serializedObject.FindProperty("spawnPosition");
|
||||
maxFalsePositives = serializedObject.FindProperty("maxFalsePositives");
|
||||
|
||||
checkRigidbody = serializedObject.FindProperty("checkRigidbody");
|
||||
checkController = serializedObject.FindProperty("checkController");
|
||||
checkWireframe = serializedObject.FindProperty("checkWireframe");
|
||||
checkRaycast = serializedObject.FindProperty("checkRaycast");
|
||||
}
|
||||
|
||||
protected override bool DrawUniqueDetectorProperties()
|
||||
{
|
||||
var detector = self;
|
||||
if (detector == null) return false;
|
||||
|
||||
DrawHeader("Specific settings");
|
||||
|
||||
if (PropertyFieldChanged(checkRigidbody, new GUIContent("Rigidbody")))
|
||||
{
|
||||
detector.CheckRigidbody = checkRigidbody.boolValue;
|
||||
}
|
||||
|
||||
if (PropertyFieldChanged(checkController, new GUIContent("Character Controller")))
|
||||
{
|
||||
detector.CheckController = checkController.boolValue;
|
||||
}
|
||||
|
||||
if (PropertyFieldChanged(checkWireframe, new GUIContent("Wireframe")))
|
||||
{
|
||||
detector.CheckWireframe = checkWireframe.boolValue;
|
||||
}
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(wireframeDelay, new GUIContent("Delay"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
if (PropertyFieldChanged(checkRaycast, new GUIContent("Raycast")))
|
||||
{
|
||||
detector.CheckRaycast = checkRaycast.boolValue;
|
||||
}
|
||||
EditorGUI.indentLevel++;
|
||||
EditorGUILayout.PropertyField(raycastDelay, new GUIContent("Delay"));
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
EditorGUILayout.PropertyField(spawnPosition);
|
||||
if (Vector3.Distance(spawnPosition.vector3Value, Vector3.zero) <= 0.001f)
|
||||
{
|
||||
EditorGUILayout.HelpBox("Please consider placing spawn position as far from your moving objects as possible to avoid false positives", MessageType.Warning);
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
EditorGUILayout.PropertyField(maxFalsePositives);
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
|
||||
if (checkWireframe.boolValue && !SettingsGUI.IsWallhackDetectorShaderIncluded())
|
||||
{
|
||||
using (GUITools.Vertical(GUITools.PanelWithBackground))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
EditorGUILayout.HelpBox("Wallhack Detector shader for Wireframe checks is not included into the build! Detector may work incorrectly",
|
||||
MessageType.Error, true);
|
||||
|
||||
if (GUILayout.Button("Include in Settings..."))
|
||||
{
|
||||
ACTkSettings.Show();
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
}
|
||||
|
||||
if (checkRaycast.boolValue || checkController.boolValue || checkRigidbody.boolValue)
|
||||
{
|
||||
var layerId = LayerMask.NameToLayer("Ignore Raycast");
|
||||
if (Physics.GetIgnoreLayerCollision(layerId, layerId))
|
||||
{
|
||||
EditorGUILayout.LabelField("IgnoreRaycast physics layer should collide with itself to avoid false positives! See readme's troubleshooting section for details.", EditorStyles.wordWrappedLabel);
|
||||
if (GUILayout.Button("Edit in Physics settings"))
|
||||
{
|
||||
SettingsService.OpenProjectSettings("Project/Physics");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool PropertyFieldChanged(SerializedProperty property, GUIContent content, params GUILayoutOption[] options)
|
||||
{
|
||||
var result = false;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
if (content == null)
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, options);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, content, options);
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2f88f8bd1134b464fa26c27d9979e6db
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Editors/WallHackDetectorEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b60780b31b4fac0448812d7db515e8a7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0eab0a2d46900f5498873b929a503bad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ae78be353f2d8243b15efd15919c5f5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.Genuine.CodeHash;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
|
||||
{
|
||||
/// <summary>
|
||||
/// Does calculates code hash after build if you use option "Generate code hash".
|
||||
/// Listen to HashesGenerated or look for hash for each build in the Editor Console.
|
||||
/// </summary>
|
||||
/// Resulting hash in most cases should match value you get from the \ref CodeStage.AntiCheat.Genuine.CodeHash.CodeHashGenerator "CodeHashGenerator"
|
||||
public class CodeHashGeneratorPostprocessor : IPostprocessBuildWithReport
|
||||
{
|
||||
/// <summary>
|
||||
/// Equals int.MaxValue to make sure this postprocessor will run as late as possible
|
||||
/// so you could run own postprocessors before and subscribe to HashesGenerated event.
|
||||
/// </summary>
|
||||
/// Used at CodeHashGeneratorListener example.
|
||||
public const int CallbackOrder = int.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// HashesGenerated event delegate.
|
||||
/// </summary>
|
||||
/// <param name="report">Standard post-build report from Unity.</param>
|
||||
/// <param name="hashedBuilds">Build hashing results array.</param>
|
||||
///
|
||||
/// You may generate multiple actual builds within single build operation,
|
||||
/// like multiple APKs when you use "Split APKs by target architecture" option,
|
||||
/// so you may have more than one valid hashed builds for one actual build procedure.
|
||||
public delegate void OnHashesGenerated(BuildReport report, IReadOnlyList<BuildHashes> hashedBuilds);
|
||||
|
||||
/// <summary>
|
||||
/// You may listen to this event if you wish to post-process resulting code hash,
|
||||
/// e.g. upload it to the server for the later runtime check with CodeHashGenerator.
|
||||
/// </summary>
|
||||
/// Make sure to enable "Generate code hash on build completion" option in the ACTk settings to make this event work.
|
||||
public static event OnHashesGenerated HashesGenerated;
|
||||
|
||||
int IOrderedCallback.callbackOrder => CallbackOrder;
|
||||
async void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
if (!ACTkSettings.Instance.PreGenerateBuildHash || !CodeHashGenerator.IsTargetPlatformCompatible())
|
||||
return;
|
||||
|
||||
await CalculateBuildReportHashesAsync(report, true, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls selection dialog and calculates hashes for the selected build.
|
||||
/// </summary>
|
||||
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <returns>Valid BuildHashes instance or null in case of error / user cancellation.</returns>
|
||||
public static BuildHashes CalculateExternalBuildHashes(string buildPath, bool printToConsole)
|
||||
{
|
||||
return AsyncHelpers.RunSync(() => CalculateExternalBuildHashesAsync(buildPath, printToConsole));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls selection dialog and calculates hashes for the selected build.
|
||||
/// </summary>
|
||||
/// <param name="buildPath">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <param name="printToConsole">Path to the .apk / .aab or .exe file. Pass null to show file selection dialog.</param>
|
||||
/// <returns>Task with Valid BuildHashes instance or null in case of error / user cancellation.</returns>
|
||||
public static async Task<BuildHashes> CalculateExternalBuildHashesAsync(string buildPath, bool printToConsole)
|
||||
{
|
||||
if (buildPath == null)
|
||||
{
|
||||
buildPath = EditorUtility.OpenFilePanel(
|
||||
"Select Standalone Windows build exe or Android build apk / aab", "", "exe,apk,aab");
|
||||
if (string.IsNullOrEmpty(buildPath))
|
||||
{
|
||||
Debug.Log(ACTk.LogPrefix + "Hashing cancelled by user.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
var extension = Path.GetExtension(buildPath);
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
return null;
|
||||
|
||||
extension = extension.ToLower(CultureInfo.InvariantCulture);
|
||||
|
||||
try
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0);
|
||||
BuildHashes hashes;
|
||||
|
||||
if (extension == ".apk" || extension == ".aab")
|
||||
hashes = (await AndroidBuildHashGenerator.GetBuildHashes(new[] { buildPath })).FirstOrDefault();
|
||||
else
|
||||
hashes = (await WindowsBuildHashGenerator.GetBuildHashes(buildPath)).FirstOrDefault();
|
||||
|
||||
if (printToConsole)
|
||||
hashes?.PrintToConsole();
|
||||
|
||||
return hashes;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Error while trying to hash build!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates hashes for the given build report. Can be useful if you wish to hash build you just made with BuildPipeline.
|
||||
/// </summary>
|
||||
/// Will not trigger the HashesGenerated event.
|
||||
/// <param name="report">BuildReport you wish to calculates hashes for</param>
|
||||
/// <param name="printToConsole">Specifies if calculated hashes should be printed to Unity Console</param>
|
||||
/// <returns>Readonly List of the BuildHashes, one per each resulting build from the BuildReport.</returns>
|
||||
public static Task<IReadOnlyList<BuildHashes>> CalculateBuildReportHashesAsync(BuildReport report,
|
||||
bool printToConsole)
|
||||
{
|
||||
return CalculateBuildReportHashesAsync(report, false, printToConsole);
|
||||
}
|
||||
|
||||
private static async Task<IReadOnlyList<BuildHashes>> CalculateBuildReportHashesAsync(BuildReport report,
|
||||
bool triggerEvent, bool printLogs)
|
||||
{
|
||||
if (EditorUserBuildSettings.GetPlatformSettings(report.summary.platformGroup.ToString(),
|
||||
"CreateSolution") == "true")
|
||||
{
|
||||
Debug.Log(
|
||||
ACTk.LogPrefix + "Build hashing is skipped due to the 'Create Visual Studio Solution' option.");
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("ACTk: Generating code hash", "Preparing...", 0);
|
||||
|
||||
var hashedBuilds = await GetHashedBuilds(report);
|
||||
|
||||
if (hashedBuilds == null || hashedBuilds.Count == 0)
|
||||
{
|
||||
Debug.Log(ACTk.LogPrefix + "Couldn't pre-generate code hash. " +
|
||||
"Please run your build and generate hash with CodeHashGenerator.");
|
||||
return null;
|
||||
}
|
||||
|
||||
if (printLogs)
|
||||
{
|
||||
foreach (var hashedBuild in hashedBuilds)
|
||||
{
|
||||
hashedBuild.PrintToConsole();
|
||||
}
|
||||
}
|
||||
|
||||
if (triggerEvent)
|
||||
HashesGenerated?.Invoke(report, hashedBuilds);
|
||||
|
||||
return hashedBuilds;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Error while trying to hash build!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static async Task<IReadOnlyList<BuildHashes>> GetHashedBuilds(BuildReport report)
|
||||
{
|
||||
var platform = report.summary.platform;
|
||||
switch (platform)
|
||||
{
|
||||
case BuildTarget.StandaloneWindows64:
|
||||
case BuildTarget.StandaloneWindows:
|
||||
return await WindowsBuildHashGenerator.GetBuildHashes(report.summary.outputPath);
|
||||
case BuildTarget.Android:
|
||||
return await AndroidBuildHashGenerator.GetBuildHashes(report);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c82c021ded9a49b44b3701f1859341cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/CodeHashGeneratorPostprocessor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 881ba0c65bee45139ca757895221c6ab
|
||||
timeCreated: 1680806941
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.EditorCode.ICSharpCode.SharpZipLib.Zip;
|
||||
using CodeStage.AntiCheat.Genuine.CodeHash;
|
||||
using CodeStage.AntiCheat.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build.Reporting;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
|
||||
{
|
||||
internal static class AndroidBuildHashGenerator
|
||||
{
|
||||
private static readonly object ProgressLock = new object();
|
||||
|
||||
public static async Task<BuildHashes[]> GetBuildHashes(BuildReport report)
|
||||
{
|
||||
if ((report.summary.options & BuildOptions.PatchPackage) != 0)
|
||||
{
|
||||
Debug.Log(ACTk.LogPrefix + "Patch hashing is skipped, only full build hashing is supported.");
|
||||
return Array.Empty<BuildHashes>();
|
||||
}
|
||||
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
var files = report.GetFiles();
|
||||
#else
|
||||
var files = report.files;
|
||||
#endif
|
||||
var filePaths = new string[files.Length];
|
||||
for (var i = 0; i < filePaths.Length; i++)
|
||||
{
|
||||
filePaths[i] = files[i].path;
|
||||
}
|
||||
|
||||
return await GetBuildHashes(filePaths);
|
||||
}
|
||||
|
||||
public static async Task<BuildHashes[]> GetBuildHashes(string[] files)
|
||||
{
|
||||
var result = new List<BuildHashes>();
|
||||
|
||||
foreach (var path in files)
|
||||
{
|
||||
var extension = Path.GetExtension(path);
|
||||
if (!string.IsNullOrEmpty(extension))
|
||||
extension = extension.ToLower(CultureInfo.InvariantCulture);
|
||||
|
||||
if (extension != ".apk" && extension != ".aab")
|
||||
continue;
|
||||
|
||||
var progress = FilesProgress.CreateNew("ACTk: Generating code hash");
|
||||
var filters = GetFilters();
|
||||
var buildHashes = await Task.Run(() => HashSuitableFilesInZipFile(path, filters,
|
||||
progress));
|
||||
if (buildHashes != null)
|
||||
result.Add(buildHashes);
|
||||
}
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
if (!EditorUserBuildSettings.exportAsGoogleAndroidProject)
|
||||
ACTk.PrintExceptionForSupport("Couldn't find compiled APK or AAB build!");
|
||||
else
|
||||
Debug.LogWarning("Couldn't find compiled APK or AAB build! " +
|
||||
"This is fine if you use Export Project feature.");
|
||||
}
|
||||
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private static BuildHashes HashSuitableFilesInZipFile(string path, FilteringData filters,
|
||||
IProgress<FilesProgress> progress)
|
||||
{
|
||||
ZipFile zf = null;
|
||||
|
||||
try
|
||||
{
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
var latestPercent = 0;
|
||||
var filesChecked = 0;
|
||||
var fileHashes = new ConcurrentBag<FileHash>();
|
||||
var fs = File.OpenRead(path);
|
||||
zf = new ZipFile(fs);
|
||||
var count = zf.Count;
|
||||
|
||||
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount };
|
||||
var sha1Pool = new ThreadSafeDisposablesPool<SHA1Wrapper>(() => new SHA1Wrapper());
|
||||
|
||||
Parallel.ForEach(zf.Cast<ZipEntry>(), options, zipEntry =>
|
||||
{
|
||||
string entryFileName = null;
|
||||
var skipped = true;
|
||||
try
|
||||
{
|
||||
// skip folders since we can't hash them
|
||||
if (!zipEntry.IsFile)
|
||||
return;
|
||||
|
||||
entryFileName = zipEntry.Name;
|
||||
if (filters.IsIgnored(entryFileName))
|
||||
return;
|
||||
|
||||
if (!filters.IsIncluded(entryFileName))
|
||||
return;
|
||||
|
||||
using (var zipStream = zf.GetInputStream(zipEntry))
|
||||
{
|
||||
fileHashes.Add(new FileHash(entryFileName, zipStream, sha1Pool));
|
||||
}
|
||||
|
||||
skipped = false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine(e);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
lock (ProgressLock)
|
||||
{
|
||||
filesChecked++;
|
||||
if (!skipped)
|
||||
progress?.ReportPercent(ref latestPercent, filesChecked, count, Path.GetFileName(entryFileName));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
sha1Pool.Dispose();
|
||||
progress?.Report(FilesProgress.None());
|
||||
sw.Stop();
|
||||
|
||||
if (fileHashes.Count == 0)
|
||||
return null;
|
||||
|
||||
var result = new BuildHashes(path, fileHashes.ToArray())
|
||||
{
|
||||
DurationSeconds = sw.Elapsed.TotalSeconds
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Error while calculating code hash!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (zf != null)
|
||||
{
|
||||
zf.IsStreamOwner = true;
|
||||
zf.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static FilteringData GetFilters()
|
||||
{
|
||||
var il2Cpp = false;
|
||||
#if UNITY_EDITOR
|
||||
il2Cpp = SettingsUtils.IsIL2CPPEnabled();
|
||||
#elif ENABLE_IL2CPP
|
||||
il2Cpp = true;
|
||||
#endif
|
||||
return FiltersProducer.GetFileFiltersAndroid(il2Cpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9717d52c2bf842caaa8575f8f2947afa
|
||||
timeCreated: 1680806503
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/AndroidBuildHashGenerator.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.Genuine.CodeHash;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
|
||||
{
|
||||
internal static class WindowsBuildHashGenerator
|
||||
{
|
||||
public static async Task<IReadOnlyList<BuildHashes>> GetBuildHashes(string buildPath)
|
||||
{
|
||||
var folder = Path.GetDirectoryName(buildPath);
|
||||
if (folder == null)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Could not found build folder for this file: " + buildPath);
|
||||
return Array.Empty<BuildHashes>();
|
||||
}
|
||||
|
||||
var progress = FilesProgress.CreateNew("ACTk: Generating code hash");
|
||||
var filters = GetFilters();
|
||||
var buildHashes = await Task.Run(()=> StandaloneWindowsWorker.GetBuildHashes(folder, filters, Environment.ProcessorCount,
|
||||
progress));
|
||||
|
||||
if (buildHashes == null)
|
||||
return Array.Empty<BuildHashes>();
|
||||
|
||||
return new [] { buildHashes };
|
||||
}
|
||||
|
||||
private static FilteringData GetFilters()
|
||||
{
|
||||
var il2Cpp = false;
|
||||
#if UNITY_EDITOR
|
||||
il2Cpp = SettingsUtils.IsIL2CPPEnabled();
|
||||
#elif ENABLE_IL2CPP
|
||||
il2Cpp = true;
|
||||
#endif
|
||||
return FiltersProducer.GetFileFiltersStandaloneWindows(il2Cpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 02b38fd3639d4fd7a1a6732fadbeebc8
|
||||
timeCreated: 1680806778
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Genuine/CodeHash/PostProcess/Platforms/WindowsBuildHashGenerator.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 59e19c7338f04be697d7788c76f0cde6
|
||||
timeCreated: 1552927805
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Describes assembly which is added to the InjectionDetector "white list".
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class AllowedAssembly
|
||||
{
|
||||
[Obsolete("Please use Name property instead.", false)]
|
||||
public string name => Name;
|
||||
|
||||
[Obsolete("Please use Hashes property instead.", false)]
|
||||
public int[] hashes => Hashes;
|
||||
|
||||
/// <summary>
|
||||
/// Assembly name, i.e.: ACTk.Runtime.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Array of whitelisted hashes for the assembly with given Name.
|
||||
/// </summary>
|
||||
public int[] Hashes { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructs new instance.
|
||||
/// </summary>
|
||||
/// <param name="name">Sets Name property.</param>
|
||||
/// <param name="hashes">Sets Hashes property.</param>
|
||||
public AllowedAssembly(string name, int[] hashes)
|
||||
{
|
||||
Name = name;
|
||||
Hashes = hashes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows adding new hash to the Hashes collection.
|
||||
/// </summary>
|
||||
/// <param name="hash">New whitelisted hash for the assembly with specified Name.</param>
|
||||
/// <returns>True if hash was added and false otherwise (i.e. when hash already existed in the collection).</returns>
|
||||
public bool AddHash(int hash)
|
||||
{
|
||||
if (Array.IndexOf(Hashes, hash) != -1) return false;
|
||||
|
||||
var oldLen = Hashes.Length;
|
||||
var newLen = oldLen + 1;
|
||||
|
||||
var newHashesArray = new int[newLen];
|
||||
Array.Copy(Hashes, newHashesArray, oldLen);
|
||||
|
||||
Hashes = newHashesArray;
|
||||
Hashes[oldLen] = hash;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name + " (hashes: " + Hashes.Length + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 99e59ee643091664d874b8418be8b78e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/AllowedAssembly.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System.IO;
|
||||
|
||||
internal static class InjectionConstants
|
||||
{
|
||||
public const string LegacyWhitelistRelativePath = "InjectionDetectorData/UserWhitelist.bytes";
|
||||
|
||||
public const string PrefsKey = "ACTDIDEnabledGlobal";
|
||||
public const string DataSeparator = ":";
|
||||
|
||||
public static readonly string ResourcesFolder = Path.Combine(ACTkEditorConstants.AssetsFolder, "Resources");
|
||||
public static readonly string DataFilePath = Path.Combine(ResourcesFolder, DataFileName);
|
||||
|
||||
private const string DataFileName = "fndid.bytes";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fdb8abbb3fde4da3aa210fccf74e9524
|
||||
timeCreated: 1552925592
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionConstants.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
#if (UNITY_STANDALONE || UNITY_ANDROID)
|
||||
#define UNITY_SUPPORTED_PLATFORM
|
||||
#endif
|
||||
|
||||
#define ACTK_DEBUG
|
||||
#undef ACTK_DEBUG
|
||||
|
||||
#define ACTK_DEBUG_VERBOSE
|
||||
#undef ACTK_DEBUG_VERBOSE
|
||||
|
||||
#define ACTK_DEBUG_PARANIOD
|
||||
#undef ACTK_DEBUG_PARANIOD
|
||||
|
||||
#if ACTK_DEBUG_PARANIOD
|
||||
#define ACTK_DEBUG
|
||||
#define ACTK_DEBUG_VERBOSE
|
||||
#endif
|
||||
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
#define ACTK_DEBUG
|
||||
#endif
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Common;
|
||||
using ObscuredTypes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
internal static class InjectionRoutines
|
||||
{
|
||||
private static bool cleanupDone;
|
||||
|
||||
public static bool IsInjectionPossible()
|
||||
{
|
||||
return IsTargetPlatformCompatible() && !SettingsUtils.IsIL2CPPEnabled();
|
||||
}
|
||||
|
||||
public static bool IsTargetPlatformCompatible()
|
||||
{
|
||||
#if UNITY_SUPPORTED_PLATFORM
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int GetAssemblyHash(AssemblyName ass)
|
||||
{
|
||||
var hashInfo = ass.Name;
|
||||
|
||||
var bytes = ass.GetPublicKeyToken();
|
||||
if (bytes != null && bytes.Length == 8)
|
||||
{
|
||||
hashInfo += PublicKeyTokenToString(bytes);
|
||||
}
|
||||
|
||||
// Jenkins hash function (http://en.wikipedia.org/wiki/Jenkins_hash_function)
|
||||
var result = 0;
|
||||
var len = hashInfo.Length;
|
||||
|
||||
for (var i = 0; i < len; ++i)
|
||||
{
|
||||
result += hashInfo[i];
|
||||
result += (result << 10);
|
||||
result ^= (result >> 6);
|
||||
}
|
||||
result += (result << 3);
|
||||
result ^= (result >> 11);
|
||||
result += (result << 15);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static List<AllowedAssembly> MergeAllowedAssemblies(IEnumerable<AllowedAssembly> collection1, IEnumerable<AllowedAssembly> collection2)
|
||||
{
|
||||
var result = new List<AllowedAssembly>(collection1);
|
||||
|
||||
foreach (var whiteListedAssembly in collection2)
|
||||
{
|
||||
var exists = false;
|
||||
foreach (var assembly in result)
|
||||
{
|
||||
if (assembly.Name != whiteListedAssembly.Name) continue;
|
||||
|
||||
exists = true;
|
||||
foreach (var hash in whiteListedAssembly.Hashes)
|
||||
{
|
||||
if (Array.IndexOf(assembly.Hashes, hash) == -1)
|
||||
{
|
||||
assembly.AddHash(hash);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
result.Add(whiteListedAssembly);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void InitCleanup()
|
||||
{
|
||||
cleanupDone = false;
|
||||
}
|
||||
|
||||
public static void Cleanup()
|
||||
{
|
||||
if (cleanupDone) return;
|
||||
cleanupDone = true;
|
||||
|
||||
TryMigrateSettings();
|
||||
TryMigrateLegacyInjectionWhitelist();
|
||||
|
||||
if (File.Exists(InjectionConstants.DataFilePath))
|
||||
{
|
||||
#if ACTK_DEBUG
|
||||
Debug.Log(ACTk.LogPrefix + "Data file found and going to be removed: " + InjectionConstants.DataFilePath);
|
||||
#endif
|
||||
EditorTools.DeleteFile(InjectionConstants.DataFilePath);
|
||||
EditorTools.DeleteFile(AssetDatabase.GetTextMetaFilePathFromAssetPath(InjectionConstants.DataFilePath));
|
||||
EditorTools.RemoveDirectoryIfEmpty(InjectionConstants.ResourcesFolder);
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
private static string PublicKeyTokenToString(byte[] bytes)
|
||||
{
|
||||
var result = "";
|
||||
|
||||
// AssemblyName.GetPublicKeyToken() returns 8 bytes
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
result += ACTkEditorConstants.HexTable[bytes[i]];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void TryMigrateSettings()
|
||||
{
|
||||
if (!EditorPrefs.HasKey(InjectionConstants.PrefsKey)) return;
|
||||
|
||||
ACTkSettings.Instance.InjectionDetectorEnabled = EditorPrefs.GetBool(InjectionConstants.PrefsKey);
|
||||
EditorPrefs.DeleteKey(InjectionConstants.PrefsKey);
|
||||
}
|
||||
|
||||
private static void TryMigrateLegacyInjectionWhitelist()
|
||||
{
|
||||
if (!File.Exists(InjectionConstants.LegacyWhitelistRelativePath)) return;
|
||||
var whitelistedAssemblies = LoadAndParseLegacyWhitelist();
|
||||
ACTkSettings.Instance.InjectionDetectorWhiteList = MergeAllowedAssemblies(ACTkSettings.Instance.InjectionDetectorWhiteList, whitelistedAssemblies);
|
||||
}
|
||||
|
||||
private static IEnumerable<AllowedAssembly> LoadAndParseLegacyWhitelist()
|
||||
{
|
||||
var result = new List<AllowedAssembly>();
|
||||
string[] separator = { InjectionConstants.DataSeparator };
|
||||
|
||||
var fs = new FileStream(InjectionConstants.LegacyWhitelistRelativePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
var br = new BinaryReader(fs);
|
||||
|
||||
try
|
||||
{
|
||||
var count = br.ReadInt32();
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var line = br.ReadString();
|
||||
line = new string(ObscuredString.Encrypt(line, ACTk.StringKey));
|
||||
var strArr = line.Split(separator, StringSplitOptions.RemoveEmptyEntries);
|
||||
var stringsCount = strArr.Length;
|
||||
if (stringsCount > 1)
|
||||
{
|
||||
var assemblyName = strArr[0];
|
||||
|
||||
var hashes = new int[stringsCount - 1];
|
||||
for (var j = 1; j < stringsCount; j++)
|
||||
{
|
||||
var success = int.TryParse(strArr[j], out var parseResult);
|
||||
if (success)
|
||||
{
|
||||
hashes[j - 1] = parseResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError(ACTk.LogPrefix + "Could not parse value: " + strArr[j] +
|
||||
", line:\n" + line);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(new AllowedAssembly(assemblyName, hashes));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Error parsing whitelist file line!");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Error while reading legacy whitelist!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
br.Close();
|
||||
fs.Close();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 682e4f8bd25b4b3f9ab90c2c080decf5
|
||||
timeCreated: 1552927820
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionRoutines.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,234 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
#define ACTK_DEBUG
|
||||
#undef ACTK_DEBUG
|
||||
|
||||
#define ACTK_DEBUG_VERBOSE
|
||||
#undef ACTK_DEBUG_VERBOSE
|
||||
|
||||
#define ACTK_DEBUG_PARANIOD
|
||||
#undef ACTK_DEBUG_PARANIOD
|
||||
|
||||
#if ACTK_DEBUG_PARANIOD
|
||||
#define ACTK_DEBUG
|
||||
#define ACTK_DEBUG_VERBOSE
|
||||
#endif
|
||||
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
#define ACTK_DEBUG
|
||||
#endif
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Common;
|
||||
using Detectors;
|
||||
using ObscuredTypes;
|
||||
using PostProcessors;
|
||||
using UnityEditor;
|
||||
using Debug = UnityEngine.Debug;
|
||||
|
||||
#if ACTK_DEBUG
|
||||
using System.Diagnostics;
|
||||
#endif
|
||||
|
||||
internal static class InjectionWhitelistBuilder
|
||||
{
|
||||
private const string ProgressCaption = "ACTk: Building InjectionDetector Whitelist";
|
||||
|
||||
#if ACTK_DEBUG
|
||||
private static Stopwatch sw;
|
||||
#endif
|
||||
|
||||
public static void GenerateWhitelist()
|
||||
{
|
||||
try
|
||||
{
|
||||
GenerateWhitelistInternal();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport($"Something went wrong while building {nameof(InjectionDetector)} whitelist!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
|
||||
private static void GenerateWhitelistInternal()
|
||||
{
|
||||
#if ACTK_DEBUG
|
||||
sw = Stopwatch.StartNew();
|
||||
sw.Stop();
|
||||
Debug.Log("=== Injection Detector Whitelist Build Start ===");
|
||||
sw.Start();
|
||||
#endif
|
||||
EditorUtility.DisplayProgressBar(ProgressCaption, "Gathering assemblies", 0);
|
||||
|
||||
var assembliesInBuild = GetAssembliesInBuild();
|
||||
if (assembliesInBuild.Length == 0)
|
||||
ACTk.PrintExceptionForSupport("Can't find any assemblies in build!");
|
||||
|
||||
var assembliesAllowedByUser = GetUserWhiteListAssemblies();
|
||||
var allAllowedAssemblies = InjectionRoutines.MergeAllowedAssemblies(assembliesInBuild, assembliesAllowedByUser);
|
||||
|
||||
EditorUtility.DisplayProgressBar(ProgressCaption, "Writing assemblies hashes", 0);
|
||||
|
||||
WriteAllowedAssemblies(allAllowedAssemblies);
|
||||
|
||||
#if ACTK_DEBUG
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "WhiteList build duration: " + sw.ElapsedMilliseconds + " ms.");
|
||||
#endif
|
||||
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private static AllowedAssembly[] GetAssembliesInBuild()
|
||||
{
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Trying to guess which assemblies can get into the build...");
|
||||
sw.Start();
|
||||
#endif
|
||||
var libraries = BuildPostProcessor.GetGuessedLibrariesForBuild();
|
||||
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Total libraries candidates: " + libraries.Length);
|
||||
sw.Start();
|
||||
|
||||
var invalidAssemblies = string.Empty;
|
||||
#endif
|
||||
|
||||
var result = new List<AllowedAssembly>();
|
||||
|
||||
foreach (var libraryPath in libraries)
|
||||
{
|
||||
#if ACTK_DEBUG_PARANIOD
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Checking library at the path: " + libraryPath);
|
||||
sw.Start();
|
||||
#endif
|
||||
try
|
||||
{
|
||||
var assName = AssemblyName.GetAssemblyName(libraryPath);
|
||||
var name = assName.Name;
|
||||
var hash = InjectionRoutines.GetAssemblyHash(assName);
|
||||
|
||||
var allowed = result.FirstOrDefault(allowedAssembly => allowedAssembly.Name == name);
|
||||
if (allowed != null)
|
||||
{
|
||||
allowed.AddHash(hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
allowed = new AllowedAssembly(name, new[] { hash });
|
||||
result.Add(allowed);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// not a valid IL assembly, skipping
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
invalidAssemblies += libraryPath + "\n";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
if (!string.IsNullOrEmpty(invalidAssemblies))
|
||||
{
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Not valid assemblies:\n" + invalidAssemblies);
|
||||
sw.Start();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ACTK_DEBUG
|
||||
sw.Stop();
|
||||
var trace = ACTk.LogPrefix + "Found assemblies in build (" + result.Count + ", " + sw.ElapsedMilliseconds + " ms):\n";
|
||||
|
||||
foreach (var allowedAssembly in result)
|
||||
{
|
||||
trace += " Name: " + allowedAssembly.name + "\n";
|
||||
trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n"));
|
||||
}
|
||||
Debug.Log(trace);
|
||||
sw.Start();
|
||||
#endif
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
private static AllowedAssembly[] GetUserWhiteListAssemblies()
|
||||
{
|
||||
var userWhiteList = ACTkSettings.Instance.InjectionDetectorWhiteList;
|
||||
#if ACTK_DEBUG
|
||||
sw.Stop();
|
||||
var trace = ACTk.LogPrefix + "User White List assemblies (" + userWhiteList.Count + "):\n";
|
||||
|
||||
foreach (var allowedAssembly in userWhiteList)
|
||||
{
|
||||
trace += " Name: " + allowedAssembly.name + "\n";
|
||||
trace = allowedAssembly.hashes.Aggregate(trace, (current, hash) => current + (" Hash: " + hash + "\n"));
|
||||
}
|
||||
Debug.Log(trace);
|
||||
sw.Start();
|
||||
#endif
|
||||
return userWhiteList.ToArray();
|
||||
}
|
||||
|
||||
private static void WriteAllowedAssemblies(List<AllowedAssembly> assemblies)
|
||||
{
|
||||
Directory.CreateDirectory(InjectionConstants.ResourcesFolder);
|
||||
var bw = new BinaryWriter(new FileStream(InjectionConstants.DataFilePath, FileMode.Create, FileAccess.Write, FileShare.Read), Encoding.Unicode);
|
||||
|
||||
bw.Write(assemblies.Count);
|
||||
|
||||
#if ACTK_DEBUG_VERBOSE
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Writing assemblies data, count: " + assemblies.Count);
|
||||
sw.Start();
|
||||
#endif
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
var name = assembly.Name;
|
||||
var hashes = "";
|
||||
|
||||
for (var j = 0; j < assembly.Hashes.Length; j++)
|
||||
{
|
||||
hashes += assembly.Hashes[j].ToString(CultureInfo.InvariantCulture);
|
||||
if (j < assembly.Hashes.Length - 1)
|
||||
{
|
||||
hashes += InjectionConstants.DataSeparator;
|
||||
}
|
||||
}
|
||||
|
||||
var line = ObscuredString.Encrypt(name + InjectionConstants.DataSeparator + hashes, ACTk.StringKey);
|
||||
|
||||
#if ACTK_DEBUG_PARANIOD
|
||||
sw.Stop();
|
||||
Debug.Log(ACTk.LogPrefix + "Writing assembly:\n" + name + InjectionConstants.DataSeparator + hashes + "\n" +
|
||||
new string(line) + ", length: " + line.Length);
|
||||
sw.Start();
|
||||
#endif
|
||||
bw.Write(line.Length);
|
||||
bw.Write(line, 0, line.Length);
|
||||
}
|
||||
|
||||
bw.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4ed4f862c6dc42a49c1f47d1e9ee2fb5
|
||||
timeCreated: 1552945114
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/InjectionWhitelistBuilder.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bb730acf6c1569848b1187cd6c0e312c
|
||||
folderAsset: yes
|
||||
timeCreated: 1552913902
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PostProcessors
|
||||
{
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Common;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Build;
|
||||
using UnityEditor.Build.Reporting;
|
||||
|
||||
internal class BuildPostProcessor : IPreprocessBuildWithReport, IPostBuildPlayerScriptDLLs, IPostprocessBuildWithReport
|
||||
{
|
||||
int IOrderedCallback.callbackOrder => int.MaxValue - 1;
|
||||
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
if (!ACTkSettings.Instance.InjectionDetectorEnabled ||
|
||||
!InjectionRoutines.IsInjectionPossible())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InjectionRoutines.InitCleanup();
|
||||
Prepare();
|
||||
}
|
||||
|
||||
public void OnPostBuildPlayerScriptDLLs(BuildReport report)
|
||||
{
|
||||
if (!ACTkSettings.Instance.InjectionDetectorEnabled ||
|
||||
!InjectionRoutines.IsInjectionPossible())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InjectionWhitelistBuilder.GenerateWhitelist();
|
||||
}
|
||||
|
||||
public void OnPostprocessBuild(BuildReport report)
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
public static string[] GetGuessedLibrariesForBuild()
|
||||
{
|
||||
var stagingAreaFolder = Path.Combine(ACTkEditorConstants.ProjectTempFolder, "StagingArea");
|
||||
return EditorTools.FindLibrariesAt(stagingAreaFolder);
|
||||
}
|
||||
|
||||
private void Prepare()
|
||||
{
|
||||
try
|
||||
{
|
||||
EditorApplication.LockReloadAssemblies();
|
||||
|
||||
if (!Directory.Exists(InjectionConstants.ResourcesFolder))
|
||||
{
|
||||
Directory.CreateDirectory(InjectionConstants.ResourcesFolder);
|
||||
}
|
||||
|
||||
File.WriteAllText(InjectionConstants.DataFilePath, "please remove me", Encoding.Unicode);
|
||||
AssetDatabase.Refresh();
|
||||
|
||||
EditorApplication.update += OnEditorUpdate;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ACTk.PrintExceptionForSupport("Injection Detector preparation failed!", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.UnlockReloadAssemblies();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEditorUpdate()
|
||||
{
|
||||
if (!BuildPipeline.isBuildingPlayer)
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
private void Cleanup()
|
||||
{
|
||||
InjectionRoutines.Cleanup();
|
||||
EditorApplication.update -= OnEditorUpdate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e79f56c36f349f64995908c2bc571662
|
||||
timeCreated: 1552680217
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/PostProcess/BuildPostProcessor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,276 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
internal class UserWhitelistEditor : EditorWindow
|
||||
{
|
||||
private const string InitialCustomName = "AssemblyName, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null";
|
||||
private static List<AllowedAssembly> whitelist;
|
||||
private static string whitelistPath;
|
||||
|
||||
private Vector2 scrollPosition;
|
||||
private bool manualAssemblyWhitelisting;
|
||||
private string manualAssemblyWhitelistingName = InitialCustomName;
|
||||
|
||||
internal static void ShowWindow()
|
||||
{
|
||||
EditorWindow myself = GetWindow<UserWhitelistEditor>(false, "Whitelist Editor", true);
|
||||
myself.minSize = new Vector2(500, 200);
|
||||
}
|
||||
|
||||
private void OnLostFocus()
|
||||
{
|
||||
manualAssemblyWhitelisting = false;
|
||||
manualAssemblyWhitelistingName = InitialCustomName;
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (whitelist == null)
|
||||
{
|
||||
whitelist = new List<AllowedAssembly>();
|
||||
LoadAndParseWhitelist();
|
||||
}
|
||||
|
||||
var tmpStyle = new GUIStyle(EditorStyles.largeLabel)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter,
|
||||
fontStyle = FontStyle.Bold
|
||||
};
|
||||
GUILayout.Label("User-defined Whitelist of Assemblies trusted by Injection Detector", tmpStyle);
|
||||
|
||||
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
|
||||
var whitelistUpdated = false;
|
||||
|
||||
var count = whitelist.Count;
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var assembly = whitelist[i];
|
||||
using (GUITools.Horizontal())
|
||||
{
|
||||
GUILayout.Label(assembly.ToString());
|
||||
if (GUILayout.Button(new GUIContent("-", "Remove Assembly from Whitelist"), GUILayout.Width(30)))
|
||||
{
|
||||
whitelist.Remove(assembly);
|
||||
whitelistUpdated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tmpStyle = new GUIStyle(EditorStyles.largeLabel)
|
||||
{
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
GUILayout.Label("- no Assemblies added so far (use buttons below to add) -", tmpStyle);
|
||||
}
|
||||
|
||||
if (manualAssemblyWhitelisting)
|
||||
{
|
||||
manualAssemblyWhitelistingName = EditorGUILayout.TextField(manualAssemblyWhitelistingName);
|
||||
|
||||
using (GUITools.Horizontal())
|
||||
{
|
||||
if (GUILayout.Button("Save"))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (manualAssemblyWhitelistingName.StartsWith("Cause:"))
|
||||
{
|
||||
throw new Exception("Please remove Cause: from the assembly name!");
|
||||
}
|
||||
|
||||
var assName = new AssemblyName(manualAssemblyWhitelistingName.Trim());
|
||||
|
||||
var res = TryWhitelistAssemblyName(assName, true);
|
||||
if (res != WhitelistingResult.Exists)
|
||||
{
|
||||
whitelistUpdated = true;
|
||||
}
|
||||
manualAssemblyWhitelisting = false;
|
||||
manualAssemblyWhitelistingName = InitialCustomName;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ShowNotification(new GUIContent(e.Message));
|
||||
}
|
||||
|
||||
GUI.FocusControl("");
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Cancel"))
|
||||
{
|
||||
manualAssemblyWhitelisting = false;
|
||||
manualAssemblyWhitelistingName = InitialCustomName;
|
||||
GUI.FocusControl("");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.EndScrollView();
|
||||
|
||||
using (GUITools.Horizontal())
|
||||
{
|
||||
GUILayout.Space(20);
|
||||
if (GUILayout.Button("Add Assembly"))
|
||||
{
|
||||
var assemblyPath = EditorUtility.OpenFilePanel("Choose an Assembly to add", "", "dll");
|
||||
if (!string.IsNullOrEmpty(assemblyPath))
|
||||
{
|
||||
whitelistUpdated |= TryWhitelistAssemblies(new[] {assemblyPath}, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Add Assemblies from Folder"))
|
||||
{
|
||||
var selectedFolder = EditorUtility.OpenFolderPanel("Choose a Folder with Assemblies", "", "");
|
||||
if (!string.IsNullOrEmpty(selectedFolder))
|
||||
{
|
||||
var libraries = EditorTools.FindLibrariesAt(selectedFolder);
|
||||
whitelistUpdated |= TryWhitelistAssemblies(libraries);
|
||||
}
|
||||
}
|
||||
|
||||
if (!manualAssemblyWhitelisting)
|
||||
{
|
||||
if (GUILayout.Button("Add Assembly manually"))
|
||||
{
|
||||
manualAssemblyWhitelisting = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
if (GUILayout.Button("Clear"))
|
||||
{
|
||||
if (EditorUtility.DisplayDialog("Please confirm",
|
||||
"Are you sure you wish to completely clear your Injection Detector whitelist?", "Yes", "No"))
|
||||
{
|
||||
whitelist.Clear();
|
||||
whitelistUpdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
GUILayout.Space(20);
|
||||
}
|
||||
|
||||
GUILayout.Space(20);
|
||||
|
||||
if (whitelistUpdated)
|
||||
{
|
||||
WriteWhitelist();
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryWhitelistAssemblies(IList<string> libraries, bool singleFile = false)
|
||||
{
|
||||
var added = 0;
|
||||
var updated = 0;
|
||||
|
||||
var count = libraries.Count;
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var libraryPath = libraries[i];
|
||||
try
|
||||
{
|
||||
var assName = AssemblyName.GetAssemblyName(libraryPath);
|
||||
var whitelistingResult = TryWhitelistAssemblyName(assName, singleFile);
|
||||
switch (whitelistingResult)
|
||||
{
|
||||
case WhitelistingResult.Added:
|
||||
added++;
|
||||
break;
|
||||
case WhitelistingResult.Updated:
|
||||
updated++;
|
||||
break;
|
||||
case WhitelistingResult.Exists:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
if (singleFile)
|
||||
ShowNotification(new GUIContent("Selected file is not a valid .NET assembly!"));
|
||||
}
|
||||
}
|
||||
|
||||
if (!singleFile)
|
||||
{
|
||||
ShowNotification(new GUIContent("Assemblies added: " + added + ", updated: " + updated));
|
||||
}
|
||||
|
||||
return added > 0 || updated > 0;
|
||||
}
|
||||
|
||||
private WhitelistingResult TryWhitelistAssemblyName(AssemblyName assName, bool singleFile)
|
||||
{
|
||||
var result = WhitelistingResult.Exists;
|
||||
|
||||
var assNameString = assName.Name;
|
||||
var hash = InjectionRoutines.GetAssemblyHash(assName);
|
||||
|
||||
var allowed = whitelist.FirstOrDefault(allowedAssembly => allowedAssembly.Name == assNameString);
|
||||
|
||||
if (allowed != null)
|
||||
{
|
||||
if (allowed.AddHash(hash))
|
||||
{
|
||||
if (singleFile) ShowNotification(new GUIContent("New hash added!"));
|
||||
result = WhitelistingResult.Updated;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (singleFile) ShowNotification(new GUIContent("Assembly already exists!"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
allowed = new AllowedAssembly(assNameString, new[] {hash});
|
||||
whitelist.Add(allowed);
|
||||
|
||||
if (singleFile) ShowNotification(new GUIContent("Assembly added!"));
|
||||
result = WhitelistingResult.Added;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void LoadAndParseWhitelist()
|
||||
{
|
||||
whitelist = ACTkSettings.Instance.InjectionDetectorWhiteList;
|
||||
}
|
||||
|
||||
private static void WriteWhitelist()
|
||||
{
|
||||
ACTkSettings.Instance.InjectionDetectorWhiteList = whitelist;
|
||||
}
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
private enum WhitelistingResult : byte
|
||||
{
|
||||
Exists,
|
||||
Added,
|
||||
Updated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bd28be63d7a09224da0cac7e3178896d
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/Injection/UserWhitelistEditor.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1140a4b6184eae45916fdae3da40a10
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 071f007b436a44fc8f2b6425b606b621
|
||||
timeCreated: 1666516531
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
public static class MigrateUtils
|
||||
{
|
||||
[Obsolete("Use " + nameof(ObscuredTypesMigrator) + "." + nameof(ObscuredTypesMigrator.MigrateProjectAssets) + "(). " +
|
||||
"This method will be removed in future versions.", true)]
|
||||
public static void MigrateObscuredTypesInAssets(bool skipInteraction = false)
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateProjectAssets(skipInteraction);
|
||||
}
|
||||
|
||||
[Obsolete("Use " + nameof(ObscuredTypesMigrator) + "." + nameof(ObscuredTypesMigrator.MigrateProjectAssets) + "(). " +
|
||||
"This method will be removed in future versions.", true)]
|
||||
public static void MigrateObscuredTypesInAssets(bool fixOnly, bool skipInteraction)
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateProjectAssets(fixOnly, skipInteraction);
|
||||
}
|
||||
|
||||
[Obsolete("Use " + nameof(ObscuredTypesMigrator) + "." + nameof(ObscuredTypesMigrator.MigrateOpenedScenes) + "(). " +
|
||||
"This method will be removed in future versions.", true)]
|
||||
public static void MigrateObscuredTypesInScene(bool skipInteraction = false)
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateOpenedScenes(skipInteraction);
|
||||
}
|
||||
|
||||
[Obsolete("Use " + nameof(ObscuredTypesMigrator) + "." + nameof(ObscuredTypesMigrator.MigrateOpenedScenes) + "(). " +
|
||||
"This method will be removed in future versions.", true)]
|
||||
public static void MigrateObscuredTypesInScene(bool fixOnly, bool skipInteraction, bool skipSave = false)
|
||||
{
|
||||
ObscuredTypesMigrator.MigrateOpenedScenes(fixOnly, skipInteraction, skipSave);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c1c7ff960ccd8a243ad385a3fe965e9e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Maintenance/MigrateUtils.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,260 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
using Common;
|
||||
using ObscuredTypes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
/// <summary>
|
||||
/// Class with utility functions to help with ACTk migrations after updates.
|
||||
/// </summary>
|
||||
public static class ObscuredTypesMigrator
|
||||
{
|
||||
private const string ModuleName = "Obscured Types Migration";
|
||||
private static bool fixOnlyMode = false;
|
||||
|
||||
private static readonly string[] TypesToMigrate =
|
||||
{
|
||||
nameof(ObscuredBigInteger),
|
||||
nameof(ObscuredBool),
|
||||
nameof(ObscuredDateTime),
|
||||
nameof(ObscuredDateTimeOffset),
|
||||
nameof(ObscuredDecimal),
|
||||
nameof(ObscuredDouble),
|
||||
nameof(ObscuredFloat),
|
||||
nameof(ObscuredGuid),
|
||||
nameof(ObscuredInt),
|
||||
nameof(ObscuredLong),
|
||||
nameof(ObscuredQuaternion),
|
||||
nameof(ObscuredShort),
|
||||
nameof(ObscuredString),
|
||||
nameof(ObscuredUInt),
|
||||
nameof(ObscuredULong),
|
||||
nameof(ObscuredVector2),
|
||||
nameof(ObscuredVector2Int),
|
||||
nameof(ObscuredVector3),
|
||||
nameof(ObscuredVector3Int),
|
||||
};
|
||||
|
||||
private delegate bool MigrateDelegate(SerializedProperty sp, bool fixOnly);
|
||||
|
||||
private static readonly Dictionary<Type, MigrateDelegate> MigrateMappings = new Dictionary<Type, MigrateDelegate>
|
||||
{
|
||||
{ typeof(ObscuredBigInteger), Migrate<SerializedObscuredBigInteger> },
|
||||
{ typeof(ObscuredBool), Migrate<SerializedObscuredBool> },
|
||||
{ typeof(ObscuredDateTime), Migrate<SerializedObscuredDateTime> },
|
||||
{ typeof(ObscuredDateTimeOffset), Migrate<SerializedObscuredDateTimeOffset> },
|
||||
{ typeof(ObscuredDecimal), Migrate<SerializedObscuredDecimal> },
|
||||
{ typeof(ObscuredDouble), Migrate<SerializedObscuredDouble> },
|
||||
{ typeof(ObscuredFloat), Migrate<SerializedObscuredFloat> },
|
||||
{ typeof(ObscuredGuid), Migrate<SerializedObscuredGuid> },
|
||||
{ typeof(ObscuredInt), Migrate<SerializedObscuredInt> },
|
||||
{ typeof(ObscuredLong), Migrate<SerializedObscuredLong> },
|
||||
{ typeof(ObscuredQuaternion), Migrate<SerializedObscuredQuaternion> },
|
||||
{ typeof(ObscuredShort), Migrate<SerializedObscuredShort> },
|
||||
{ typeof(ObscuredString), Migrate<SerializedObscuredString> },
|
||||
{ typeof(ObscuredUInt), Migrate<SerializedObscuredUInt> },
|
||||
{ typeof(ObscuredULong), Migrate<SerializedObscuredULong> },
|
||||
{ typeof(ObscuredVector2), Migrate<SerializedObscuredVector2> },
|
||||
{ typeof(ObscuredVector2Int), Migrate<SerializedObscuredVector2Int> },
|
||||
{ typeof(ObscuredVector3), Migrate<SerializedObscuredVector3> },
|
||||
{ typeof(ObscuredVector3Int), Migrate<SerializedObscuredVector3Int> }
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Checks all assets in project for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateProjectAssets(bool skipInteraction = false)
|
||||
{
|
||||
MigrateProjectAssets(false, skipInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all assets in project for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateProjectAssets(bool fixOnly, bool skipInteraction)
|
||||
{
|
||||
MigrateProjectAssets(null, fixOnly, skipInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks specified assets in project for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateProjectAssets(string[] assetPaths, bool fixOnly, bool skipInteraction)
|
||||
{
|
||||
var result = 0;
|
||||
|
||||
if (!skipInteraction)
|
||||
{
|
||||
if (assetPaths == null || assetPaths.Length == 0)
|
||||
{
|
||||
result = EditorUtility.DisplayDialogComplex(ModuleName,
|
||||
"Are you sure you wish to scan ALL Prefabs and Scriptable Objects and automatically migrate and / or fix invalid values?\n" +
|
||||
"Select 'Migrate and fix' only if you did update from the older ACTk version.",
|
||||
"Migrate and fix", "Cancel", "Fix only");
|
||||
}
|
||||
else if (assetPaths.Length > 1000)
|
||||
result = EditorUtility.DisplayDialogComplex(ModuleName,
|
||||
$"Are you sure you wish to scan {assetPaths.Length} Prefabs and Scriptable Objects and automatically migrate and / or fix invalid values?\n" +
|
||||
"Select 'Migrate and fix' only if you did update from the older ACTk version.",
|
||||
"Migrate and fix", "Cancel", "Fix only");
|
||||
}
|
||||
|
||||
if (!skipInteraction)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case 0:
|
||||
fixOnly = false;
|
||||
break;
|
||||
case 2:
|
||||
fixOnly = true;
|
||||
break;
|
||||
default:
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": canceled by user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fixOnlyMode = fixOnly;
|
||||
EditorTools.TraverseSerializedScriptsAssets(assetPaths, ProcessProperty, TypesToMigrate);
|
||||
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": complete.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all currently opened scenes for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateOpenedScenes(bool skipInteraction = false)
|
||||
{
|
||||
MigrateOpenedScenes(false, skipInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all currently opened scenes for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateOpenedScenes(bool fixOnly, bool skipInteraction, bool skipSave = false)
|
||||
{
|
||||
if (!skipInteraction)
|
||||
{
|
||||
var confirmationResult = ConfirmMigration("all opened Scenes");
|
||||
switch (confirmationResult)
|
||||
{
|
||||
case 0:
|
||||
fixOnly = false;
|
||||
break;
|
||||
case 2:
|
||||
fixOnly = true;
|
||||
break;
|
||||
default:
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": canceled by user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MigrateScenes(EditorTools.TraverseSerializedScriptsInOpenedScenes, fixOnly, skipSave);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all scenes in Build Settings for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateBuildProfilesScenes(bool skipInteraction = false)
|
||||
{
|
||||
MigrateBuildProfilesScenes(false, skipInteraction);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks all scenes in Build Settings for old version of obscured types and tries to migrate values to the new version
|
||||
/// or fix corrupt states if possible.
|
||||
/// </summary>
|
||||
public static void MigrateBuildProfilesScenes(bool fixOnly, bool skipInteraction, bool skipSave = false)
|
||||
{
|
||||
if (!skipInteraction)
|
||||
{
|
||||
var confirmationResult = ConfirmMigration("all scenes in " + ACTkMenuItems.BuildProfilesLabel);
|
||||
switch (confirmationResult)
|
||||
{
|
||||
case 0:
|
||||
fixOnly = false;
|
||||
break;
|
||||
case 2:
|
||||
fixOnly = true;
|
||||
break;
|
||||
default:
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": canceled by user.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MigrateScenes(EditorTools.TraverseSerializedScriptsInBuildProfilesScenes, fixOnly, skipSave);
|
||||
}
|
||||
|
||||
private static void MigrateScenes(Action<ProcessSerializedProperty, string[], bool> traverseAction, bool fixOnly, bool skipSave)
|
||||
{
|
||||
fixOnlyMode = fixOnly;
|
||||
|
||||
var types = TypeCache.GetTypesDerivedFrom<ISerializableObscuredType>().Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.Select(type => type.Name).ToArray();
|
||||
traverseAction(ProcessProperty, types, skipSave);
|
||||
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": complete.");
|
||||
}
|
||||
|
||||
private static int ConfirmMigration(string target)
|
||||
{
|
||||
return EditorUtility.DisplayDialogComplex(ModuleName,
|
||||
$"Are you sure you wish to scan {target} and automatically migrate and / or fix invalid values?\n" +
|
||||
"Select 'Migrate and fix' only if you did update from the older ACTk version.",
|
||||
"Migrate and fix", "Cancel", "Fix only");
|
||||
}
|
||||
|
||||
private static bool ProcessProperty(Object target, SerializedProperty sp, AssetLocationData location, string type)
|
||||
{
|
||||
var obscured = sp.GetValue<ISerializableObscuredType>();
|
||||
if (obscured == null || obscured.IsDataValid)
|
||||
return false;
|
||||
|
||||
if (MigrateMappings.TryGetValue(obscured.GetType(), out var migrate))
|
||||
{
|
||||
var modified = migrate(sp, fixOnlyMode);
|
||||
|
||||
if (modified)
|
||||
Debug.Log($"{ACTk.LogPrefix}{ModuleName} migrated property {sp.displayName}:{type} at\n{location.ToString()}", target);
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool Migrate<TSerialized>(SerializedProperty sp, bool fixOnly) where TSerialized : ISerializedObscuredType, new()
|
||||
{
|
||||
var serialized = new TSerialized();
|
||||
serialized.Init(sp);
|
||||
|
||||
if (!fixOnly && serialized.IsCanMigrate)
|
||||
return serialized.Migrate();
|
||||
|
||||
return serialized.Fix();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 101a5a0542a54c1a854f4459447108d2
|
||||
timeCreated: 1729782845
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Maintenance/ObscuredTypesMigrator.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode
|
||||
{
|
||||
public delegate void InvalidPropertyFound(Object target, SerializedProperty sp, string location, string type);
|
||||
|
||||
/// <summary>
|
||||
/// Class with utility functions to help with ACTk migrations after updates.
|
||||
/// </summary>
|
||||
public static class ObscuredTypesValidator
|
||||
{
|
||||
internal const string ModuleName = "Obscured Types Validator";
|
||||
|
||||
private static InvalidPropertyFound lastPassedCallback;
|
||||
private static HashSet<string> invalidAssetPaths;
|
||||
private static int invalidPropertiesFound;
|
||||
|
||||
/// <summary>
|
||||
/// Traverses all prefabs and scriptable objects in the project and checks if they contain any Obscured types with anomalies.
|
||||
/// </summary>
|
||||
/// <param name="assetPaths">Specify target asset(s) or pass null to scan whole project.</param>
|
||||
/// <param name="callback">Pass callback if you wish to process invalid objects.</param>
|
||||
/// <param name="skipInteraction">Skips intro confirmation.</param>
|
||||
/// <returns>Array of paths that require migration.</returns>
|
||||
public static string[] ValidateProjectAssets(string[] assetPaths = null, InvalidPropertyFound callback = null, bool skipInteraction = false)
|
||||
{
|
||||
if (!skipInteraction)
|
||||
{
|
||||
if (assetPaths == null || assetPaths.Length == 0)
|
||||
{
|
||||
if (!EditorUtility.DisplayDialog(ModuleName,
|
||||
"Are you sure you wish to scan ALL Prefabs and Scriptable Objects?\n" +
|
||||
"This can take some time to complete.",
|
||||
"Yes", "No"))
|
||||
{
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": canceled by user.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (assetPaths.Length > 1000 && !EditorUtility.DisplayDialog(ModuleName,
|
||||
$"Are you sure you wish to scan {assetPaths.Length} Prefabs and Scriptable Objects?",
|
||||
"Yes", "No"))
|
||||
{
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": canceled by user.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
invalidAssetPaths = new HashSet<string>();
|
||||
|
||||
var types = TypeCache.GetTypesDerivedFrom<ISerializableObscuredType>().Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.Select(type => type.Name).ToArray();
|
||||
lastPassedCallback = callback;
|
||||
EditorTools.TraverseSerializedScriptsAssets(assetPaths, ValidateProperty, types);
|
||||
lastPassedCallback = null;
|
||||
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": complete.");
|
||||
|
||||
return invalidAssetPaths.ToArray();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Traverse all currently opened scenes and checks if they contain any non-valid Obscured types.
|
||||
/// </summary>
|
||||
/// <param name="callback">Pass callback if you wish to process invalid objects.</param>
|
||||
/// <param name="skipInteraction">Skips intro confirmation.</param>
|
||||
/// <returns>Number of invalid properties.</returns>
|
||||
public static int ValidateOpenedScenes(InvalidPropertyFound callback = null, bool skipInteraction = false)
|
||||
{
|
||||
if (!skipInteraction && !ConfirmValidation("all opened Scenes"))
|
||||
return invalidPropertiesFound;
|
||||
|
||||
return ValidateScenes(EditorTools.TraverseSerializedScriptsInOpenedScenes, callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Traverses all scenes added to all BuildProfiles (ex BuildSettings) and checks if they contain any non-valid Obscured types.
|
||||
/// </summary>
|
||||
/// <param name="callback">Pass callback if you wish to process invalid objects.</param>
|
||||
/// <param name="skipInteraction">Skips intro confirmation.</param>
|
||||
/// <returns>Number of invalid properties.</returns>
|
||||
public static int ValidateBuildProfilesScenes(InvalidPropertyFound callback = null, bool skipInteraction = false)
|
||||
{
|
||||
if (!skipInteraction && !ConfirmValidation("all scenes in " + ACTkMenuItems.BuildProfilesLabel))
|
||||
return invalidPropertiesFound;
|
||||
|
||||
return ValidateScenes(EditorTools.TraverseSerializedScriptsInBuildProfilesScenes, callback);
|
||||
}
|
||||
|
||||
private static bool ConfirmValidation(string target)
|
||||
{
|
||||
return EditorUtility.DisplayDialog(ModuleName,
|
||||
$"Are you sure you wish to scan {target} and validate all found obscured types?",
|
||||
"Yes", "No");
|
||||
}
|
||||
|
||||
private static int ValidateScenes(Action<ProcessSerializedProperty, string[], bool> traverseAction, InvalidPropertyFound callback)
|
||||
{
|
||||
invalidPropertiesFound = 0;
|
||||
|
||||
var types = TypeCache.GetTypesDerivedFrom<ISerializableObscuredType>().Where(t => !t.IsAbstract && !t.IsInterface)
|
||||
.Select(type => type.Name).ToArray();
|
||||
lastPassedCallback = callback;
|
||||
traverseAction(ValidateProperty, types, true);
|
||||
lastPassedCallback = null;
|
||||
|
||||
Debug.Log(ACTk.LogPrefix + ModuleName + ": complete.");
|
||||
|
||||
return invalidPropertiesFound;
|
||||
}
|
||||
|
||||
private static bool ValidateProperty(Object target, SerializedProperty sp, AssetLocationData location, string type)
|
||||
{
|
||||
var obscured = sp.GetValue<ISerializableObscuredType>();
|
||||
if (obscured != null && !obscured.IsDataValid)
|
||||
{
|
||||
lastPassedCallback?.Invoke(target, sp, location.ToString(), type);
|
||||
target = EditorTools.GetPingableObject(target);
|
||||
Debug.LogWarning($"{ACTk.LogPrefix}{ModuleName} found invalid property [{sp.displayName}] of type [{type}] at:\n{location}", target);
|
||||
invalidPropertiesFound++;
|
||||
invalidAssetPaths?.Add(location.AssetPath);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7ec1712370d34ee1b38697a83d773c14
|
||||
timeCreated: 1666516545
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/Maintenance/ObscuredTypesValidator.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: dfff86e18b5565b499779c37590c4d83
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73f17e3e136e49bb8ff04e8fe09dc26e
|
||||
timeCreated: 1724779708
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using CodeStage.AntiCheat.Common;
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
public abstract class ObscuredTypeDrawer<TSerializedObscuredType, TPlainType> : PropertyDrawer
|
||||
where TSerializedObscuredType : SerializedObscuredType<TPlainType>, new()
|
||||
{
|
||||
protected TSerializedObscuredType serialized;
|
||||
protected TPlainType plain;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty sp, GUIContent label)
|
||||
{
|
||||
serialized = new TSerializedObscuredType();
|
||||
serialized.Init(sp);
|
||||
plain = serialized.Plain;
|
||||
var instance = sp.GetValue<ISerializableObscuredType>();
|
||||
|
||||
BeforeOnGUI(ref position, ref sp, ref label);
|
||||
|
||||
var labelWidth = EditorGUIUtility.labelWidth;
|
||||
label = EditorGUI.BeginProperty(position, label, sp);
|
||||
|
||||
if (instance != null && !instance.IsDataValid)
|
||||
DrawFixButton(ref position);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
DrawProperty(position, sp, label);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
ApplyChanges();
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
EditorGUIUtility.labelWidth = labelWidth;
|
||||
}
|
||||
|
||||
private void DrawFixButton(ref Rect position)
|
||||
{
|
||||
var fixPosition = EditorGUI.IndentedRect(position);
|
||||
var fixButtonRect = new Rect(fixPosition) { width = 40 };
|
||||
fixPosition.x += 45;
|
||||
position.x += 45;
|
||||
position.width -= 45;
|
||||
EditorGUIUtility.labelWidth -= 45;
|
||||
DrawFixBackground(fixPosition);
|
||||
|
||||
if (GUI.Button(fixButtonRect, new GUIContent("Fix",
|
||||
"Fix invalid state with either migrating from older version or overriding hash.")))
|
||||
{
|
||||
if (serialized.IsCanMigrate)
|
||||
{
|
||||
var migrated = serialized.GetMigrationResultString();
|
||||
|
||||
EditorApplication.delayCall += () =>
|
||||
{
|
||||
var option = EditorUtility.DisplayDialogComplex(
|
||||
"Anti-Cheat Toolkit",
|
||||
$"This variable can be migrated to:\n'{migrated}'.\nDo you wish to migrate?",
|
||||
"Migrate",
|
||||
"Only fix",
|
||||
"Cancel"
|
||||
);
|
||||
|
||||
switch (option)
|
||||
{
|
||||
case 0:
|
||||
if (!serialized.Migrate())
|
||||
ACTk.PrintExceptionForSupport("Couldn't migrate obscured type instance!");
|
||||
break;
|
||||
case 1:
|
||||
if (!serialized.Fix())
|
||||
ACTk.PrintExceptionForSupport("Couldn't fix obscured type instance!");
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!serialized.Fix())
|
||||
ACTk.PrintExceptionForSupport("Couldn't fix obscured type instance!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DrawFixBackground(Rect position)
|
||||
{
|
||||
var width = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * 15;
|
||||
var bgRect = new Rect(position) { width = width};
|
||||
EditorGUI.DrawRect(bgRect, new Color32(255, 0, 0, 25));
|
||||
}
|
||||
|
||||
protected abstract void DrawProperty(Rect position, SerializedProperty sp, GUIContent label);
|
||||
protected abstract void ApplyChanges();
|
||||
protected virtual void BeforeOnGUI(ref Rect position, ref SerializedProperty sp, ref GUIContent label) { }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a672b282a2a46fe985667865fdba49d
|
||||
timeCreated: 1724779717
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/Abstract/ObscuredTypeDrawer.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
public abstract class WideObscuredTypeDrawer<TSerializedObscuredType, TPlainType> : ObscuredTypeDrawer<TSerializedObscuredType, TPlainType>
|
||||
where TSerializedObscuredType : SerializedObscuredType<TPlainType>, new()
|
||||
{
|
||||
protected override void DrawFixBackground(Rect position)
|
||||
{
|
||||
if (EditorGUIUtility.wideMode)
|
||||
base.DrawFixBackground(position);
|
||||
}
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
return EditorGUIUtility.wideMode ? EditorGUIUtility.singleLineHeight : EditorGUIUtility.singleLineHeight * 2f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0d5b5067d6a1403e8c65b6b63f7acade
|
||||
timeCreated: 1724782025
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/Abstract/WideObscuredTypeDrawer.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System.Numerics;
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using CodeStage.AntiCheat.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ObscuredBigInteger))]
|
||||
internal class ObscuredBigIntegerDrawer : ObscuredTypeDrawer<SerializedObscuredBigInteger, BigInteger>
|
||||
{
|
||||
private string input;
|
||||
|
||||
protected override void DrawProperty(Rect position, SerializedProperty sp, GUIContent label)
|
||||
{
|
||||
#if UNITY_2022_1_OR_NEWER
|
||||
input = EditorGUI.DelayedTextField(position, label, plain.ToString());
|
||||
#else
|
||||
input = EditorGUI.TextField(position, label, plain.ToString());
|
||||
#endif
|
||||
}
|
||||
|
||||
protected override void ApplyChanges()
|
||||
{
|
||||
if (!BigInteger.TryParse(input, out var newValue))
|
||||
newValue = 0;
|
||||
|
||||
plain = newValue;
|
||||
|
||||
serialized.Hidden = ObscuredBigInteger.Encrypt(plain, serialized.Key);
|
||||
serialized.Hash = HashUtils.CalculateHash(plain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c48a363379404a3f8ffa0970bd1f7653
|
||||
timeCreated: 1653693062
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBigIntegerDrawer.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using CodeStage.AntiCheat.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ObscuredBool))]
|
||||
internal class ObscuredBoolDrawer : ObscuredTypeDrawer<SerializedObscuredBool, bool>
|
||||
{
|
||||
protected override void DrawProperty(Rect position, SerializedProperty sp, GUIContent label)
|
||||
{
|
||||
plain = EditorGUI.Toggle(position, label, plain);
|
||||
}
|
||||
|
||||
protected override void ApplyChanges()
|
||||
{
|
||||
serialized.Hidden = ObscuredBool.Encrypt(plain, serialized.Key);
|
||||
serialized.Hash = HashUtils.CalculateHash(plain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2a0ae33a4804dd5468c37cee3d9e4a15
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredBoolDrawer.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using CodeStage.AntiCheat.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ObscuredDateTime))]
|
||||
internal class ObscuredDateTimeDrawer : ObscuredTypeDrawer<SerializedObscuredDateTime, DateTime>
|
||||
{
|
||||
private string input;
|
||||
|
||||
protected override void DrawProperty(Rect position, SerializedProperty sp, GUIContent label)
|
||||
{
|
||||
var posW = position.width;
|
||||
position.width *= 0.75f;
|
||||
|
||||
var kindRect = position;
|
||||
kindRect.x = position.xMax + 5;
|
||||
kindRect.width = posW - position.width - 5;
|
||||
|
||||
var dateString = plain.ToString("o", DateTimeFormatInfo.InvariantInfo);
|
||||
input = EditorGUI.DelayedTextField(position, label, dateString);
|
||||
|
||||
label = EditorGUI.BeginProperty(kindRect, GUIContent.none, sp);
|
||||
using (var scope = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var kind = plain.Kind;
|
||||
var kindInput = (DateTimeKind)EditorGUI.EnumPopup(kindRect, label, kind);
|
||||
if (scope.changed)
|
||||
{
|
||||
plain = DateTime.SpecifyKind(plain, kindInput);
|
||||
input = plain.ToString("o", DateTimeFormatInfo.InvariantInfo);
|
||||
ApplyChanges();
|
||||
}
|
||||
}
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
protected override void ApplyChanges()
|
||||
{
|
||||
DateTime.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out plain);
|
||||
|
||||
serialized.Hidden = ObscuredDateTime.Encrypt(plain, serialized.Key);
|
||||
serialized.Hash = HashUtils.CalculateHash(plain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d4822eb673254d3fa09b8add898e8445
|
||||
timeCreated: 1684493697
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeDrawer.cs
|
||||
uploadId: 773557
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
#region copyright
|
||||
// ------------------------------------------------------
|
||||
// Copyright (C) Dmitriy Yukhanov [https://codestage.net]
|
||||
// ------------------------------------------------------
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using CodeStage.AntiCheat.ObscuredTypes;
|
||||
using CodeStage.AntiCheat.ObscuredTypes.EditorCode;
|
||||
using CodeStage.AntiCheat.Utils;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace CodeStage.AntiCheat.EditorCode.PropertyDrawers
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ObscuredDateTimeOffset))]
|
||||
internal class ObscuredDateTimeOffsetDrawer : ObscuredTypeDrawer<SerializedObscuredDateTimeOffset, DateTimeOffset>
|
||||
{
|
||||
private string input;
|
||||
|
||||
protected override void DrawProperty(Rect position, SerializedProperty sp, GUIContent label)
|
||||
{
|
||||
var dateString = plain.ToString("o", DateTimeFormatInfo.InvariantInfo);
|
||||
input = EditorGUI.DelayedTextField(position, label, dateString);
|
||||
}
|
||||
|
||||
protected override void ApplyChanges()
|
||||
{
|
||||
DateTimeOffset.TryParse(input, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out plain);
|
||||
|
||||
serialized.Hidden = ObscuredDateTimeOffset.Encrypt(plain, serialized.Key);
|
||||
serialized.Hash = HashUtils.CalculateHash(plain.UtcTicks);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6c0b323727b533b45af6ac5ade85b55d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 202695
|
||||
packageName: Anti-Cheat Toolkit
|
||||
packageVersion: 6.2.0
|
||||
assetPath: Assets/Plugins/CodeStage/AntiCheatToolkit/Editor/Scripts/ObscuredTypes/PropertyDrawers/ObscuredDateTimeOffsetDrawer.cs
|
||||
uploadId: 773557
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue