chunk 1: core gameplay scripts scenes runtime assets
This commit is contained in:
187
Assets/Scripts/Utilities/CopyMultipleComponents.cs
Normal file
187
Assets/Scripts/Utilities/CopyMultipleComponents.cs
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
A simple little editor extension to copy and paste all components
|
||||
Help from http://answers.unity3d.com/questions/541045/copy-all-components-from-one-character-to-another.html
|
||||
license: WTFPL (http://www.wtfpl.net/)
|
||||
author: aeroson
|
||||
advise: ChessMax
|
||||
editor: frekons
|
||||
*/
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class CopyMultipleComponents : EditorWindow
|
||||
{
|
||||
// Use ScriptableObject to store data between editor sessions
|
||||
private class ComponentDataContainer : ScriptableObject
|
||||
{
|
||||
public List<string> componentData = new List<string>();
|
||||
public List<string> componentTypeNames = new List<string>();
|
||||
}
|
||||
|
||||
private static ComponentDataContainer dataContainer;
|
||||
|
||||
[MenuItem("Tools/Component Utilities/Copy All Components")]
|
||||
static void Copy()
|
||||
{
|
||||
if (Selection.activeGameObject == null)
|
||||
{
|
||||
Debug.LogError("No GameObject selected for copying!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create or get the data container
|
||||
if (dataContainer == null)
|
||||
dataContainer = ScriptableObject.CreateInstance<ComponentDataContainer>();
|
||||
|
||||
dataContainer.componentData.Clear();
|
||||
dataContainer.componentTypeNames.Clear();
|
||||
|
||||
Component[] components = Selection.activeGameObject.GetComponents<Component>();
|
||||
|
||||
foreach (Component component in components)
|
||||
{
|
||||
if (component == null)
|
||||
continue;
|
||||
|
||||
// Skip Transform component as it often causes issues
|
||||
if (component is Transform)
|
||||
continue;
|
||||
|
||||
// Store component data as JSON
|
||||
string json = EditorJsonUtility.ToJson(component);
|
||||
dataContainer.componentData.Add(json);
|
||||
dataContainer.componentTypeNames.Add(component.GetType().AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
if (dataContainer.componentData.Count > 0)
|
||||
{
|
||||
Debug.Log($"Copied {dataContainer.componentData.Count} components from {Selection.activeGameObject.name}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning("No components found to copy!");
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Component Utilities/Paste All Components")]
|
||||
static void Paste()
|
||||
{
|
||||
if (dataContainer == null || dataContainer.componentData.Count == 0)
|
||||
{
|
||||
Debug.LogError("Nothing is copied! Use 'Copy All Components' first.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GameObject targetGameObject in Selection.gameObjects)
|
||||
{
|
||||
if (!targetGameObject)
|
||||
continue;
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(targetGameObject, targetGameObject.name + ": Paste All Components");
|
||||
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
|
||||
for (int i = 0; i < dataContainer.componentTypeNames.Count; i++)
|
||||
{
|
||||
string typeString = dataContainer.componentTypeNames[i];
|
||||
string jsonData = dataContainer.componentData[i];
|
||||
|
||||
System.Type componentType = System.Type.GetType(typeString);
|
||||
if (componentType == null)
|
||||
{
|
||||
Debug.LogError($"Could not find type: {typeString}");
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if component already exists
|
||||
Component targetComponent = targetGameObject.GetComponent(componentType);
|
||||
|
||||
if (targetComponent == null)
|
||||
{
|
||||
// Add component if it doesn't exist
|
||||
targetComponent = Undo.AddComponent(targetGameObject, componentType);
|
||||
}
|
||||
|
||||
if (targetComponent != null)
|
||||
{
|
||||
// Apply the JSON data to the component
|
||||
EditorJsonUtility.FromJsonOverwrite(jsonData, targetComponent);
|
||||
successCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"Failed to add component: {componentType}");
|
||||
failCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Pasted to {targetGameObject.name}: {successCount} components successful, {failCount} failed");
|
||||
}
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Component Utilities/Delete All Components")]
|
||||
static void DeleteAllComponents()
|
||||
{
|
||||
if (Selection.gameObjects.Length == 0)
|
||||
{
|
||||
Debug.LogError("No GameObjects selected for component deletion!");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (GameObject targetGameObject in Selection.gameObjects)
|
||||
{
|
||||
if (!targetGameObject)
|
||||
continue;
|
||||
|
||||
Undo.RegisterCompleteObjectUndo(targetGameObject, targetGameObject.name + ": Delete All Components");
|
||||
|
||||
Component[] components = targetGameObject.GetComponents<Component>();
|
||||
int deletedCount = 0;
|
||||
|
||||
// Start from the end to avoid index issues when destroying components
|
||||
for (int i = components.Length - 1; i >= 0; i--)
|
||||
{
|
||||
Component component = components[i];
|
||||
|
||||
// Skip null components
|
||||
if (component == null)
|
||||
continue;
|
||||
|
||||
// Skip Transform component as it's required
|
||||
if (component is Transform)
|
||||
continue;
|
||||
|
||||
// Destroy the component with Undo support
|
||||
Undo.DestroyObjectImmediate(component);
|
||||
deletedCount++;
|
||||
}
|
||||
|
||||
Debug.Log($"Deleted {deletedCount} components from {targetGameObject.name}");
|
||||
}
|
||||
}
|
||||
|
||||
// Add menu items without keyboard shortcuts
|
||||
[MenuItem("GameObject/Component Utilities/Copy All Components")]
|
||||
static void CopyFromGameObjectMenu()
|
||||
{
|
||||
Copy();
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Component Utilities/Paste All Components")]
|
||||
static void PasteFromGameObjectMenu()
|
||||
{
|
||||
Paste();
|
||||
}
|
||||
|
||||
[MenuItem("GameObject/Component Utilities/Delete All Components")]
|
||||
static void DeleteAllComponentsFromGameObjectMenu()
|
||||
{
|
||||
DeleteAllComponents();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
11
Assets/Scripts/Utilities/CopyMultipleComponents.cs.meta
Normal file
11
Assets/Scripts/Utilities/CopyMultipleComponents.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7883cd428b31bf349a049a4f93d6324c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
175
Assets/Scripts/Utilities/DeviceDisplayConfigurator.cs
Normal file
175
Assets/Scripts/Utilities/DeviceDisplayConfigurator.cs
Normal file
@@ -0,0 +1,175 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
[CreateAssetMenu(fileName = "Device Display Configurator", menuName = "Scriptable Objects/Device Display Configurator", order = 1)]
|
||||
public class DeviceDisplayConfigurator : ScriptableObject
|
||||
{
|
||||
|
||||
[System.Serializable]
|
||||
public struct DeviceSet
|
||||
{
|
||||
public string deviceRawPath;
|
||||
public DeviceDisplaySettings deviceDisplaySettings;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct DisconnectedSettings
|
||||
{
|
||||
public string disconnectedDisplayName;
|
||||
public Color disconnectedDisplayColor;
|
||||
}
|
||||
|
||||
public List<DeviceSet> listDeviceSets = new List<DeviceSet>();
|
||||
|
||||
public DisconnectedSettings disconnectedDeviceSettings;
|
||||
|
||||
private Color fallbackDisplayColor = Color.white;
|
||||
|
||||
|
||||
public string GetDeviceName(PlayerInput playerInput)
|
||||
{
|
||||
|
||||
string currentDeviceRawPath = playerInput.devices[0].ToString();
|
||||
|
||||
string newDisplayName = null;
|
||||
|
||||
for(int i = 0; i < listDeviceSets.Count; i++)
|
||||
{
|
||||
|
||||
if(listDeviceSets[i].deviceRawPath == currentDeviceRawPath)
|
||||
{
|
||||
newDisplayName = listDeviceSets[i].deviceDisplaySettings.deviceDisplayName;
|
||||
}
|
||||
}
|
||||
|
||||
if(newDisplayName == null)
|
||||
{
|
||||
newDisplayName = currentDeviceRawPath;
|
||||
}
|
||||
|
||||
return newDisplayName;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public Color GetDeviceColor(PlayerInput playerInput)
|
||||
{
|
||||
|
||||
string currentDeviceRawPath = playerInput.devices[0].ToString();
|
||||
|
||||
Color newDisplayColor = fallbackDisplayColor;
|
||||
|
||||
for(int i = 0; i < listDeviceSets.Count; i++)
|
||||
{
|
||||
|
||||
if(listDeviceSets[i].deviceRawPath == currentDeviceRawPath)
|
||||
{
|
||||
newDisplayColor = listDeviceSets[i].deviceDisplaySettings.deviceDisplayColor;
|
||||
}
|
||||
}
|
||||
|
||||
return newDisplayColor;
|
||||
|
||||
}
|
||||
|
||||
public Sprite GetDeviceBindingIcon(PlayerInput playerInput, string playerInputDeviceInputBinding)
|
||||
{
|
||||
|
||||
string currentDeviceRawPath = playerInput.devices[0].ToString();
|
||||
|
||||
Sprite displaySpriteIcon = null;
|
||||
|
||||
for(int i = 0; i < listDeviceSets.Count; i++)
|
||||
{
|
||||
if(listDeviceSets[i].deviceRawPath == currentDeviceRawPath)
|
||||
{
|
||||
if(listDeviceSets[i].deviceDisplaySettings.deviceHasContextIcons != null)
|
||||
{
|
||||
displaySpriteIcon = FilterForDeviceInputBinding(listDeviceSets[i], playerInputDeviceInputBinding);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return displaySpriteIcon;
|
||||
}
|
||||
|
||||
Sprite FilterForDeviceInputBinding(DeviceSet targetDeviceSet, string inputBinding)
|
||||
{
|
||||
Sprite spriteIcon = null;
|
||||
|
||||
switch(inputBinding)
|
||||
{
|
||||
case "Button North":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.buttonNorthIcon;
|
||||
break;
|
||||
|
||||
case "Button South":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.buttonSouthIcon;
|
||||
break;
|
||||
|
||||
case "Button West":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.buttonWestIcon;
|
||||
break;
|
||||
|
||||
case "Button East":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.buttonEastIcon;
|
||||
break;
|
||||
|
||||
case "Right Shoulder":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerRightFrontIcon;
|
||||
break;
|
||||
|
||||
case "Right Trigger":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerRightBackIcon;
|
||||
break;
|
||||
|
||||
case "rightTriggerButton":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerRightBackIcon;
|
||||
break;
|
||||
|
||||
case "Left Shoulder":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerLeftFrontIcon;
|
||||
break;
|
||||
|
||||
case "Left Trigger":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerLeftBackIcon;
|
||||
break;
|
||||
|
||||
case "leftTriggerButton":
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.triggerLeftBackIcon;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
for(int i = 0; i < targetDeviceSet.deviceDisplaySettings.customContextIcons.Count; i++)
|
||||
{
|
||||
if(targetDeviceSet.deviceDisplaySettings.customContextIcons[i].customInputContextString == inputBinding)
|
||||
{
|
||||
if(targetDeviceSet.deviceDisplaySettings.customContextIcons[i].customInputContextIcon != null)
|
||||
{
|
||||
spriteIcon = targetDeviceSet.deviceDisplaySettings.customContextIcons[i].customInputContextIcon;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return spriteIcon;
|
||||
}
|
||||
|
||||
public string GetDisconnectedName()
|
||||
{
|
||||
return disconnectedDeviceSettings.disconnectedDisplayName;
|
||||
}
|
||||
|
||||
public Color GetDisconnectedColor()
|
||||
{
|
||||
return disconnectedDeviceSettings.disconnectedDisplayColor;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Utilities/DeviceDisplayConfigurator.cs.meta
Normal file
11
Assets/Scripts/Utilities/DeviceDisplayConfigurator.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fa6f1fbaea804c34cab896669f1e362b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
34
Assets/Scripts/Utilities/DeviceDisplaySettings.cs
Normal file
34
Assets/Scripts/Utilities/DeviceDisplaySettings.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
[System.Serializable]
|
||||
public struct CustomInputContextIcon
|
||||
{
|
||||
public string customInputContextString;
|
||||
public Sprite customInputContextIcon;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "Device Display Settings", menuName = "Scriptable Objects/Device Display Settings", order = 1)]
|
||||
public class DeviceDisplaySettings : ScriptableObject
|
||||
{
|
||||
|
||||
public string deviceDisplayName;
|
||||
|
||||
public Color deviceDisplayColor;
|
||||
|
||||
public bool deviceHasContextIcons;
|
||||
|
||||
public Sprite buttonNorthIcon;
|
||||
public Sprite buttonSouthIcon;
|
||||
public Sprite buttonWestIcon;
|
||||
public Sprite buttonEastIcon;
|
||||
|
||||
public Sprite triggerRightFrontIcon;
|
||||
public Sprite triggerRightBackIcon;
|
||||
public Sprite triggerLeftFrontIcon;
|
||||
public Sprite triggerLeftBackIcon;
|
||||
|
||||
public List<CustomInputContextIcon> customContextIcons = new List<CustomInputContextIcon>();
|
||||
|
||||
}
|
||||
11
Assets/Scripts/Utilities/DeviceDisplaySettings.cs.meta
Normal file
11
Assets/Scripts/Utilities/DeviceDisplaySettings.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9ea9a11d318323458a19965038cc9a3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
18
Assets/Scripts/Utilities/FileRenameEditor.cs
Normal file
18
Assets/Scripts/Utilities/FileRenameEditor.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class FileRenameEditor : MonoBehaviour
|
||||
{
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Utilities/FileRenameEditor.cs.meta
Normal file
11
Assets/Scripts/Utilities/FileRenameEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c250387bd288c2499811ef4ff609460
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
43
Assets/Scripts/Utilities/FileRenamer.cs
Normal file
43
Assets/Scripts/Utilities/FileRenamer.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
|
||||
public class FileRenamer : MonoBehaviour
|
||||
{
|
||||
// Set the folder path where your .cas files are located
|
||||
string folderPath = "C:/Users/mbiha/Downloads/Final Game-Play Animations/Cat - Game/CatFootwork - Finalised";
|
||||
|
||||
void Start()
|
||||
{
|
||||
RenameFiles();
|
||||
}
|
||||
|
||||
void RenameFiles()
|
||||
{
|
||||
// Get all .cas files in the folder
|
||||
string[] files = Directory.GetFiles(folderPath, "*.casc");
|
||||
|
||||
foreach (string filePath in files)
|
||||
{
|
||||
// Extract the filename without extension
|
||||
string fileName = Path.GetFileNameWithoutExtension(filePath);
|
||||
print(fileName);
|
||||
// Split the filename by '-'
|
||||
string[] parts = fileName.Split('-');
|
||||
|
||||
// Extract the animation name from the second part
|
||||
string[] nameParts = parts[0].Split('.');
|
||||
string animationName = nameParts[1];
|
||||
|
||||
// Construct the new file name
|
||||
string newFileName = animationName + ".casc";
|
||||
|
||||
// Construct the new file path
|
||||
string newFilePath = Path.Combine(folderPath, newFileName);
|
||||
|
||||
// Rename the file
|
||||
File.Move(filePath, newFilePath);
|
||||
|
||||
Debug.Log("File renamed from " + filePath + " to " + newFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Utilities/FileRenamer.cs.meta
Normal file
11
Assets/Scripts/Utilities/FileRenamer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f0e73e749af60b45a99bcf651085872
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
62
Assets/Scripts/Utilities/InputSafety.cs
Normal file
62
Assets/Scripts/Utilities/InputSafety.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
using UnityEngine.InputSystem;
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// Small helper to safely enable Input System artifacts without letting InputSystem exceptions crash initialization.
|
||||
/// Use InputSafety.SafeEnable(action) instead of action.Enable() when running on devices that may have many bindings.
|
||||
/// </summary>
|
||||
public static class InputSafety
|
||||
{
|
||||
#if ENABLE_INPUT_SYSTEM
|
||||
public static void SafeEnable(this InputAction action)
|
||||
{
|
||||
if (action == null) return;
|
||||
try
|
||||
{
|
||||
if (!action.enabled) action.Enable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[InputSafety] Failed to enable InputAction '{action.name}': {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeEnable(this InputActionReference actionRef)
|
||||
{
|
||||
if (actionRef == null || actionRef.action == null) return;
|
||||
SafeEnable(actionRef.action);
|
||||
}
|
||||
|
||||
public static void SafeEnable(this InputActionMap map)
|
||||
{
|
||||
if (map == null) return;
|
||||
try
|
||||
{
|
||||
map.Enable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[InputSafety] Failed to enable InputActionMap '{map.name}': {ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SafeEnable(this InputActionAsset asset)
|
||||
{
|
||||
if (asset == null) return;
|
||||
try
|
||||
{
|
||||
asset.Enable();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[InputSafety] Failed to enable InputActionAsset '{asset.name}': {ex}");
|
||||
}
|
||||
}
|
||||
#else
|
||||
// If Input System isn't enabled, provide no-op overloads so call sites don't need conditional compilation.
|
||||
public static void SafeEnable(this object _) { }
|
||||
#endif
|
||||
}
|
||||
2
Assets/Scripts/Utilities/InputSafety.cs.meta
Normal file
2
Assets/Scripts/Utilities/InputSafety.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38432e564134fa9ed83649ee9056b4d2
|
||||
74
Assets/Scripts/Utilities/SecurePlayerPrefs.cs
Normal file
74
Assets/Scripts/Utilities/SecurePlayerPrefs.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using UnityEngine;
|
||||
|
||||
public static class SecurePlayerPrefs
|
||||
{
|
||||
private static readonly byte[] salt = new byte[] { 0x13, 0x24, 0x37, 0x48, 0x59, 0x6A, 0x7B, 0x8C };
|
||||
private static readonly byte[] key = new byte[] { 0x6D, 0x5B, 0x35, 0x81, 0x49, 0x93, 0xD8, 0x10, 0x52, 0x7E, 0x2B, 0x19, 0x4C, 0xFA, 0x67, 0x8A };
|
||||
|
||||
public static void SetString(string key, string value)
|
||||
{
|
||||
byte[] encrypted = EncryptStringToBytes(value);
|
||||
string encoded = Convert.ToBase64String(encrypted);
|
||||
PlayerPrefs.SetString(key, encoded);
|
||||
}
|
||||
|
||||
public static string GetString(string key, string defaultValue = "")
|
||||
{
|
||||
string encoded = PlayerPrefs.GetString(key, defaultValue);
|
||||
byte[] encrypted = Convert.FromBase64String(encoded);
|
||||
string value = DecryptStringFromBytes(encrypted);
|
||||
return value;
|
||||
}
|
||||
|
||||
private static byte[] EncryptStringToBytes(string plainText)
|
||||
{
|
||||
byte[] encrypted;
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = key;
|
||||
aesAlg.IV = salt;
|
||||
|
||||
ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
using (MemoryStream msEncrypt = new MemoryStream())
|
||||
{
|
||||
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
|
||||
{
|
||||
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
|
||||
{
|
||||
swEncrypt.Write(plainText);
|
||||
}
|
||||
encrypted = msEncrypt.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
return encrypted;
|
||||
}
|
||||
|
||||
private static string DecryptStringFromBytes(byte[] cipherText)
|
||||
{
|
||||
string plaintext = null;
|
||||
using (Aes aesAlg = Aes.Create())
|
||||
{
|
||||
aesAlg.Key = key;
|
||||
aesAlg.IV = salt;
|
||||
|
||||
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
|
||||
|
||||
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
|
||||
{
|
||||
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
|
||||
{
|
||||
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
|
||||
{
|
||||
plaintext = srDecrypt.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return plaintext;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Utilities/SecurePlayerPrefs.cs.meta
Normal file
11
Assets/Scripts/Utilities/SecurePlayerPrefs.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4645f177416b8084cafbe683d04b9a9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
Assets/Scripts/Utilities/Singleton.cs
Normal file
91
Assets/Scripts/Utilities/Singleton.cs
Normal file
@@ -0,0 +1,91 @@
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// Be aware this will not prevent a non singleton constructor
|
||||
/// such as `T myT = new T();`
|
||||
/// To prevent that, add `protected T () {}` to your singleton class.
|
||||
/// </summary>
|
||||
public class Singleton<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
private static object _lock = new object();
|
||||
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (applicationIsQuitting)
|
||||
{
|
||||
Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
|
||||
"' already destroyed on application quit." +
|
||||
" Won't create again - returning null.");
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = (T)FindObjectOfType(typeof(T));
|
||||
|
||||
if (FindObjectsOfType(typeof(T)).Length > 1)
|
||||
{
|
||||
Debug.LogError("[Singleton] Something went really wrong " +
|
||||
" - there should never be more than 1 singleton!" +
|
||||
" Reopening the scene might fix it.");
|
||||
return _instance;
|
||||
}
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
GameObject singleton = new GameObject();
|
||||
_instance = singleton.AddComponent<T>();
|
||||
singleton.name = "(singleton) " + typeof(T).ToString();
|
||||
|
||||
Debug.Log("[Singleton] An instance of " + typeof(T) +
|
||||
" is needed in the scene, so '" + singleton +
|
||||
"' was created.");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Debug.Log("[Singleton] Using instance already created: " + _instance.gameObject.name);
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsDontDestroyOnLoad()
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// Object exists independent of Scene lifecycle, assume that means it has DontDestroyOnLoad set
|
||||
if ((_instance.gameObject.hideFlags & HideFlags.DontSave) == HideFlags.DontSave)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool applicationIsQuitting = false;
|
||||
/// <summary>
|
||||
/// When Unity quits, it destroys objects in a random order.
|
||||
/// In principle, a Singleton is only destroyed when application quits.
|
||||
/// If any script calls Instance after it have been destroyed,
|
||||
/// it will create a buggy ghost object that will stay on the Editor scene
|
||||
/// even after stopping playing the Application. Really bad!
|
||||
/// So, this was made to be sure we're not creating that buggy ghost object.
|
||||
/// </summary>
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (IsDontDestroyOnLoad())
|
||||
{
|
||||
applicationIsQuitting = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Utilities/Singleton.cs.meta
Normal file
11
Assets/Scripts/Utilities/Singleton.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 72a31edc5ff3ab544b868121001c62ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Scripts/Utilities/UnityMainThreadDispatcher.cs
Normal file
39
Assets/Scripts/Utilities/UnityMainThreadDispatcher.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class UnityMainThreadDispatcher : MonoBehaviour
|
||||
{
|
||||
private static readonly Queue<Action> executionQueue = new Queue<Action>();
|
||||
|
||||
private static UnityMainThreadDispatcher instance = null;
|
||||
public static UnityMainThreadDispatcher Instance()
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
var obj = new GameObject("UnityMainThreadDispatcher");
|
||||
instance = obj.AddComponent<UnityMainThreadDispatcher>();
|
||||
DontDestroyOnLoad(obj);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void Enqueue(Action action)
|
||||
{
|
||||
lock (executionQueue)
|
||||
{
|
||||
executionQueue.Enqueue(action);
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
lock (executionQueue)
|
||||
{
|
||||
while (executionQueue.Count > 0)
|
||||
{
|
||||
executionQueue.Dequeue().Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 29014c96e46e31947a2fe929c84c3bbe
|
||||
Reference in New Issue
Block a user