Add project files.

This commit is contained in:
2023-10-08 18:51:40 +02:00
commit 51cc9df14f
2249 changed files with 636804 additions and 0 deletions

8
Assets/Scripts/Apng.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 055f725890d872b4bb22fa493ed06356
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,281 @@
/* HaRepacker - WZ extractor and repacker
* Copyright (C) 2009, 2010 haha01haha01
* This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
* This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
namespace SharpApng
{
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using uGIF;
using UnityEngine;
public class Frame : IDisposable
{
#region Fields
private Image m_bmp;
private int m_den;
private int m_num;
#endregion Fields
#region Constructors
public Frame(Image bmp, int num, int den)
{
this.m_num = num;
this.m_den = den;
this.m_bmp = bmp;
}
#endregion Constructors
#region Properties
public Image Bitmap
{
get
{
return m_bmp;
}
set
{
m_bmp = value;
}
}
public int DelayDen
{
get
{
return m_den;
}
set
{
m_den = value;
}
}
public int DelayNum
{
get
{
return m_num;
}
set
{
m_num = value;
}
}
#endregion Properties
#region Methods
public void Dispose()
{
}
#endregion Methods
}
internal class Apng : IDisposable
{
#region Fields
private List<Frame> m_frames = new List<Frame>();
#endregion Fields
#region Constructors
public Apng()
{
}
#endregion Constructors
#region Indexers
public Frame this[int index]
{
get
{
if (index < m_frames.Count) return m_frames[index];
else return null;
}
set
{
if (index < m_frames.Count) m_frames[index] = value;
}
}
#endregion Indexers
#region Methods
public void AddFrame(Frame frame)
{
m_frames.Add(frame);
}
public void AddFrame(Image bmp, int num, int den)
{
m_frames.Add(new Frame(bmp, num, den));
}
public void Dispose()
{
foreach (Frame frame in m_frames)
frame.Dispose();
m_frames.Clear();
}
public void WriteApng(string path, bool firstFrameHidden, bool disposeAfter)
{
Size maxSize = new Size(m_frames.Max(f => f.Bitmap.width), m_frames.Max(f => f.Bitmap.height));
for (int i = 0; i < m_frames.Count; i++)
{
Frame frame = m_frames[i];
//if (frame.Bitmap.Width != maxSize.Width || frame.Bitmap.Height != maxSize.Height)
//frame.Bitmap = ExtendImage(frame.Bitmap, maxSize);
ApngBasicWrapper.CreateFrameManaged(frame.Bitmap, frame.DelayNum, frame.DelayDen, i);
}
ApngBasicWrapper.SaveApngManaged(path, m_frames.Count, maxSize.Width, maxSize.Height, firstFrameHidden);
if (disposeAfter) Dispose();
}
private static Image ExtendImage(Image source, Size newSize)
{
Image result = new Image(newSize.Width, newSize.Height);
//using (Graphics g = Graphics.FromImage(result))
//{
// g.DrawImageUnscaled(source, 0, 0);
//}
return result;
}
#endregion Methods
}
internal static class ApngBasicWrapper
{
#region Fields
private const string apngdll = "apng64.dll";
private const int PIXEL_DEPTH = 4;
#endregion Fields
#region Methods
internal static void CreateFrameManaged(Image source, int num, int den, int i)
{
IntPtr ptr = MarshalByteArray(TranslateImage(source));
CreateFrame(ptr, num, den, i, source.width * source.height * PIXEL_DEPTH);
ReleaseData(ptr);
}
internal static void SaveApngManaged(string path, int frameCount, int width, int height, bool firstFrameHidden)
{
IntPtr pathPtr = MarshalString(path);
byte firstFrame = firstFrameHidden ? (byte)1 : (byte)0;
SaveAPNG(pathPtr, frameCount, width, height, PIXEL_DEPTH, firstFrame);
var bufferSize = GetBufferSize();
//Call and return the pointer
IntPtr returnedPtr = GetBufferContent();
//Create new Variable to Store the result
byte[] returnedResult = new byte[bufferSize];
//Copy from result pointer to the C# variable
Marshal.Copy(returnedPtr, returnedResult, 0, bufferSize);
File.WriteAllBytes(path, returnedResult);
Debug.Log("saved");
ReleaseData(pathPtr);
}
[DllImport(apngdll, CallingConvention = CallingConvention.StdCall)]
private static extern void CreateFrame(IntPtr pdata, int num, int den, int i, int len);
[DllImport(apngdll)]
private static extern void SaveAPNG(IntPtr path, int frameCount, int width, int height, int bytesPerPixel, byte firstFrameHidden);
[DllImport(apngdll)]
private static extern int GetBufferSize();
[DllImport(apngdll)]
private static extern IntPtr GetBufferContent();
private static IntPtr MarshalByteArray(byte[] source)
{
int size = Marshal.SizeOf(source[0]) * source.Length;
IntPtr pnt = Marshal.AllocHGlobal(size);
Marshal.Copy(source, 0, pnt, source.Length);
return pnt;
}
private static IntPtr MarshalString(string source)
{
byte[] toMarshal = Encoding.ASCII.GetBytes(source);
int size = Marshal.SizeOf(source[0]) * source.Length;
IntPtr pnt = Marshal.AllocHGlobal(size + Marshal.SizeOf(source[0]));
Marshal.Copy(toMarshal, 0, pnt, source.Length);
//Marshal.Copy(new byte[] { 0 }, 0, new IntPtr(pnt.ToInt32() + size), 1);
return pnt;
}
private static void ReleaseData(IntPtr ptr)
{
Marshal.FreeHGlobal(ptr);
}
static byte[] TranslateImage(Image texture)
{
int width = texture.width, height = texture.height;
Color32[] original = new Color32[texture.pixels.Length];
texture.pixels.CopyTo(original, 0);
byte[] result = new byte[texture.width * texture.height * PIXEL_DEPTH];
int p = 0;
Debug.Log("1");
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int index = (y * width + x);
int index2 = ((height-y-1) * width + x);
result[index * PIXEL_DEPTH] = original[index2].b;
result[index * PIXEL_DEPTH + 1] = original[index2].g;
result[index * PIXEL_DEPTH + 2] = original[index2].r;
result[index * PIXEL_DEPTH + 3] = original[index2].a;
}
p += 1;
}
Debug.Log("2");
return result;
}
#endregion Methods
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de9592c4ae9713d41ae7a9ae40d1b549
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,125 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CameraOrbit : MonoBehaviour
{
public static CameraOrbit Instance;
bool controlOn;
[Header("Light")]
public Vector3 TargetCenter;
EventSystem eventSystem;
[Header("Orbit Camera")]
public float camZoomMin = 1, camZoomMax = 15;
public float camZoom = 2.4f;
public float moveSpeed = 1;
public float zoomSpeed = 1f;
private void Awake()
{
Instance = this;
eventSystem = EventSystem.current;
}
void Update()
{
OrbitAround(false);
}
float baseZoom;
float baseDist;
Vector2 lastMouse;
Vector2 lastTouch;
int lastTouchCount;
void OrbitAround(bool aroundCharacter = false)
{
Vector2 mouse = Input.mousePosition;
Vector2 mouseDelta = (mouse - lastMouse) * Time.deltaTime;
Vector2 touchDelta = Vector2.zero;
lastMouse = mouse;
TargetCenter = Vector3.zero;
Vector3 position = transform.position;
if (Input.GetMouseButtonDown(0) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
{
controlOn = true;
}
if (Input.GetMouseButton(0) && controlOn)
{
position -= mouseDelta.x * moveSpeed * transform.right;
position -= mouseDelta.y * moveSpeed * transform.up;
}
else
{
controlOn = false;
}
Vector2 touch0 = Vector2.zero, touch1;
if (Input.touchCount > 0 && !eventSystem.IsPointerOverGameObject(0))
{
touch0 = Input.GetTouch(0).position;
if (lastTouchCount > Input.touchCount || lastTouch == -Vector2.one)
{
touchDelta = Vector2.zero;
}
else
{
touchDelta = (touch0 - lastTouch) * Time.deltaTime;
}
lastTouch = touch0;
}
else
{
lastTouch = -Vector2.one;
baseDist = 0;
lastTouchCount = 0;
}
if (Input.touchCount == 1 && !eventSystem.IsPointerOverGameObject(0))
{
position -= touchDelta.x * moveSpeed * transform.right;
position -= touchDelta.y * moveSpeed * transform.up;
lastTouchCount = 1;
}
else if (Input.touchCount >= 2 && !eventSystem.IsPointerOverGameObject(0))
{
touch1 = Input.GetTouch(1).position;
if (baseDist == 0)
{
baseDist = Vector2.Distance(touch0, touch1);
baseZoom = camZoom;
}
camZoom = baseZoom - (Vector2.Distance(touch0, touch1) - baseDist) * 0.01f;
lastTouchCount = 2;
}
if (!eventSystem.IsPointerOverGameObject())
{
camZoom -= Input.mouseScrollDelta.y * zoomSpeed;
}
camZoom = Mathf.Clamp(camZoom, camZoomMin, camZoomMax);
float camDist = camZoom;
Camera.main.orthographicSize = camDist;
transform.position = position;
}
public void SetZoomSpeed(float value)
{
zoomSpeed = value;
}
public void SetMoveSpeed(float value)
{
moveSpeed = value;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 278fb6ec5b3d906479f56f047f620777
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,154 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
public class CameraOrbit3D : MonoBehaviour
{
public static bool CameraLock = true;
public static int CameraMode = 0;
private Camera cam;
bool controlOn, heightOn;
public GameObject CameraTargetHelper;
public Vector3 TargetCenter;
EventSystem eventSystem;
[Header("Orbit Camera")]
float camHeightMin = 2, camHeightMax = 2;
float targetHeightMin = -100, targetHeightMax = 100f;
public float camZoom = 2.4f;
public float camHeight = 0.87f;
public float targetHeight = 0.87f;
public float fov = 45;
private void Awake()
{
cam = GetComponentInChildren<Camera>();
eventSystem = EventSystem.current;
CameraLock = false;
}
void Update()
{
OrbitAround(false);
}
float baseZoom;
float baseDist;
Vector2 lastMouse;
Vector2 lastTouch;
int lastTouchCount;
#region Camera
/// <summary>
/// Orbit camera around world center
/// </summary>
void OrbitAround(bool aroundCharacter = false)
{
CameraOrbit original = GetComponent<CameraOrbit>();
Vector2 mouse = Input.mousePosition;
Vector2 mouseDelta = (mouse - lastMouse) * Time.deltaTime;
Vector2 touchDelta = Vector2.zero;
lastMouse = mouse;
TargetCenter = Vector3.zero;
cam.fieldOfView = fov;
Vector3 position = transform.position;
Vector3 rotation = cam.transform.localEulerAngles;
if (Input.GetMouseButtonDown(0) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
{
controlOn = true;
}
if (Input.GetMouseButton(0) && controlOn)
{
position -= mouseDelta.x * original.moveSpeed * transform.right;
camHeight -= mouseDelta.y * original.moveSpeed;
}
else
{
controlOn = false;
}
if (Input.GetMouseButtonDown(1) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
{
heightOn = true;
}
if (Input.GetMouseButton(1) && heightOn)
{
targetHeight -= mouseDelta.y * 0.5f;
targetHeight = Mathf.Clamp(targetHeight, targetHeightMin, targetHeightMax);
}
else
{
heightOn = false;
}
Vector2 touch0 = Vector2.zero, touch1;
if (Input.touchCount > 0 && !eventSystem.IsPointerOverGameObject(0))
{
touch0 = Input.GetTouch(0).position;
if (lastTouchCount > Input.touchCount || lastTouch == -Vector2.one)
{
touchDelta = Vector2.zero;
}
else
{
touchDelta = (touch0 - lastTouch) * Time.deltaTime;
}
lastTouch = touch0;
}
else
{
lastTouch = -Vector2.one;
baseDist = 0;
lastTouchCount = 0;
}
if (Input.touchCount == 1 && !eventSystem.IsPointerOverGameObject(0))
{
position -= touchDelta.x * original.moveSpeed * transform.right;
camHeight -= touchDelta.y * original.moveSpeed;
lastTouchCount = 1;
}
else if(Input.touchCount >= 2 && !eventSystem.IsPointerOverGameObject(0))
{
touch1 = Input.GetTouch(1).position;
if (baseDist == 0)
{
baseDist = Vector2.Distance(touch0, touch1);
baseZoom = camZoom;
}
camZoom = baseZoom - (Vector2.Distance(touch0, touch1) - baseDist) * 0.01f;
targetHeight -= touchDelta.y * 0.5f;
targetHeight = Mathf.Clamp(targetHeight, targetHeightMin, targetHeightMax);
lastTouchCount = 2;
}
if (!eventSystem.IsPointerOverGameObject())
{
camZoom -= Input.mouseScrollDelta.y * original.zoomSpeed;
}
camZoom = Mathf.Clamp(camZoom, original.camZoomMin, original.camZoomMax);
float camDist = camZoom;
camHeightMax = targetHeight + camDist;
camHeightMin = targetHeight - camDist;
camHeight = Mathf.Clamp(camHeight, camHeightMin, camHeightMax);
Vector3 target = TargetCenter + targetHeight * Vector3.up; //set target offsets
position.y = TargetCenter.y + camHeight; //set camera height
transform.position = position; //set final position of camera at target
//Debug.Log(rotation);
transform.LookAt(target); //look at target position
transform.position = target - transform.forward * camDist; //move away from target
}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df0c736ae643c464986a460f3f8686f1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

30
Assets/Scripts/Error.cs Normal file
View File

@@ -0,0 +1,30 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Error : MonoBehaviour
{
public static GameObject ErrorText;
public static GameObject CanvasContent;
private void Awake()
{
ErrorText = Resources.Load("ErrorText") as GameObject;
CanvasContent = GameObject.Find("Canvas/ErrorScrollView/Viewport/Content");
}
public static void Log(Color color, string message, float time = 5)
{
Log(message, color, time);
}
public static void Log(string message, Color color, float time = 5)
{
Debug.Log(message);
Text text = Instantiate(ErrorText, CanvasContent.transform).GetComponent<Text>();
text.text = message;
text.color = color;
Destroy(text.gameObject, CanvasContent.transform.childCount + 1 * time);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 07843c4377dd7cb4495bedfa1057ddc7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,69 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
public class FateAssetManager : MonoBehaviour
{
public static FateAssetManager Instance;
void Awake()
{
Instance = this;
}
public static IEnumerator DownloadTexture(string url, System.Action<Texture2D> callback)
{
Texture2D outTex = null;
Debug.Log("Downloading Texture " + url);
UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(www.error);
}
else
{
outTex = ((DownloadHandlerTexture)www.downloadHandler).texture;
outTex.wrapMode = TextureWrapMode.Clamp;
}
callback(outTex);
}
public static IEnumerator DownloadText(string url, System.Action<string> callback)
{
UnityWebRequest www = UnityWebRequest.Get(url);
yield return www.SendWebRequest();
if (www.result != UnityWebRequest.Result.Success)
{
Debug.Log(url);
Debug.Log(www.error);
callback(null);
}
else
{
var str = www.downloadHandler.text;
callback(str);
}
}
public static IEnumerator DownloadBundle(string url, System.Action<AssetBundle> callback)
{
Error.Log(Color.green, $"Downloading bundle from {url}");
UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url);
yield return www.SendWebRequest();
AssetBundle bundlea = null;
if (www.result != UnityWebRequest.Result.Success)
{
Error.Log(Color.red, www.error);
}
else
{
bundlea = DownloadHandlerAssetBundle.GetContent(www);
}
callback(bundlea);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a27da48354afb9a4faf06ab69ecb72df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,487 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
public class FateModelBuilder : MonoBehaviour
{
public Material ParticleMaterial;
public static FateModelBuilder Instance;
public bool LoadingInProgress = false;
public AnimatorOverrideController AnimatorController;
private void Awake()
{
Instance = this;
}
public IEnumerator ReplaceServant(string id)
{
if (LoadingInProgress)
{
Error.Log(Color.red, "Loading already in progress!");
yield break;
}
if (FateViewerMain.SelectedServant != null)
{
FateViewerMain.SelectedServant.DeleteModel();
}
yield return LoadServant(id);
}
public IEnumerator LoadServant(string id)
{
if (LoadingInProgress) yield break;
LoadingInProgress = true;
var Servants = FateViewerMain.Instance.Servants;
int idNum = int.Parse(id);
var urlBase = $"{FateViewerMain.AAContent}Servants/{idNum}";
var costume = Servants.GetAllCostumes().FirstOrDefault(s => s.battleCharaId == idNum);
if (costume != null)
{
var servant = Servants.Entries.First(s => s.costumes.Contains(costume));
var lcButt = UIController.Instance.LoadedCharaButton;
lcButt.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = servant.name + " - AA database";
lcButt.GetComponentInChildren<Button>().onClick.RemoveAllListeners();
lcButt.GetComponentInChildren<Button>().onClick.AddListener(() => Application.OpenURL("https://apps.atlasacademy.io/db/JP/servant/" + servant.collectionNo));
}
AssetBundle assetBundle = null;
string url = $"{urlBase}/manifest.json";
Manifest manifest = null;
yield return FateAssetManager.DownloadText(url, (txt) =>
{
if (string.IsNullOrEmpty(txt)) return;
txt = $"{{\"Entries\": {txt} }}";
manifest = (Manifest)JsonUtility.FromJson(txt, typeof(Manifest));
});
if (manifest == null)
{
Error.Log(Color.red, "Failed to download manifest from " + url);
LoadingInProgress = false;
yield break;
}
Error.Log(Color.green, "Loading character id " + id);
url = $"{urlBase}/{manifest.GetFilePath(idNum.ToString())}";
yield return FateAssetManager.DownloadBundle(url, (cb) =>
{
assetBundle = cb;
});
if (assetBundle == null)
{
Error.Log(Color.red, "Loading assetbundle failed!");
LoadingInProgress = false;
yield break;
}
StartCoroutine(BuildModel(assetBundle, manifest, urlBase));
}
public void ReplaceTexture()
{
StartCoroutine(ReplaceTexture1());
}
private IEnumerator ReplaceTexture1()
{
if (!FateViewerMain.SelectedServant)
{
Error.Log(Color.red, "No servant loaded!");
UIController.Instance.ReactivateTextureLoad();
yield break;
}
var uploader = WebGLUpDownExamples._webGLUpload;
var newMat = new Material(Shader.Find("Legacy Shaders/Diffuse"));
//var targetMaterial = Materials.FirstOrDefault(m=>m.mainTexture.name )
uploader.UploadTexture(WebGLUpload.ImageFormat.png, 0, true, newMat);
do
{
yield return new WaitForEndOfFrame();
}
while (!uploader.TextureReady);
uploader.TextureReady = false;
Debug.Log($"file {newMat.mainTexture.name} loaded");
foreach (var mat in FateViewerMain.SelectedServant.Materials)
{
if (mat.mainTexture.name == newMat.mainTexture.name)
{
mat.mainTexture = newMat.mainTexture;
}
}
Destroy(newMat);
UIController.Instance.ReactivateTextureLoad();
}
public IEnumerator BuildModel(AssetBundle assetBundle, Manifest manifest, string modelUrl)
{
if (assetBundle == null)
{
Error.Log(Color.red, "Asset load fail");
Debug.LogError("Asset load fail");
LoadingInProgress = false;
assetBundle.Unload(true);
yield break;
}
FateServantContainer servant = new GameObject().AddComponent<FateServantContainer>();
servant.name = assetBundle.name;
foreach (var asset in assetBundle.LoadAllAssets())
{
if (asset == null) { continue; }
else if (asset.GetType() == typeof(GameObject))
{
if((asset as GameObject).name == "chr")
{
servant.BodyMain = asset as GameObject;
}
}
else if (asset.GetType() == typeof(Texture2D))
{
Texture2D tex = asset as Texture2D;
yield return FateAssetManager.DownloadTexture(modelUrl + "/" + manifest.GetFilePath(tex.name + ".png"), (tex2) =>
{
if(tex2 == null)
{
Error.Log(Color.red, "Downloading " + tex.name + " failed");
return;
}
tex2.name = tex.name;
servant.Textures.Add(tex2);
});
}
else if (asset.GetType() == typeof(Material))
{
servant.Materials.Add(asset as Material);
}
else if (asset.GetType() == typeof(TextAsset))
{
}
else if (asset.GetType() == typeof(AnimationClip))
{
}
else
{
//Error.Log(Color.yellow, asset.GetType().ToString());
//Debug.LogWarning(asset.GetType());
}
}
UIController.Instance.CutoffSlider?.onValueChanged.RemoveAllListeners();
foreach (Material mat in servant.Materials)
{
if (mat.shader.name.Contains("Particle"))
{
mat.shader = Shader.Find("Particles/Standard Unlit");
var tex = mat.mainTexture;
var color = mat.color;
mat.CopyPropertiesFromMaterial(ParticleMaterial);
mat.mainTexture = tex;
mat.color = color;
}
else
{
mat.shader = Shader.Find("FateShader3Compatible");
if (mat.mainTexture != null)
{
var texture = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name);
if (texture != null)
{
mat.SetTexture("_MainTex", texture);
}
else
{
Error.Log(Color.red, $"Texture {mat.mainTexture.name} not found");
}
var alpha = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name + "a" || t.name == mat.mainTexture.name + "_alpha");
if (alpha)
{
mat.SetTexture("_Alpha", alpha);
}
}
Material temp = mat;
mat.SetFloat("_Cutoff", 0.91f);
UIController.Instance.CutoffSlider?.onValueChanged.AddListener((value) => { temp.SetFloat("_Cutoff", value / 100);});
}
}
if(servant.BodyMain == null)
{
Error.Log(Color.red, "Servant body was not loaded");
assetBundle.Unload(true);
LoadingInProgress = false;
yield break;
}
servant.BodyMain = Instantiate(servant.BodyMain, servant.transform);
servant.InstantiatedObjects.Add(servant.BodyMain);
var simpleAnimation = servant.GetComponentInChildren<SimpleAnimation>();
simpleAnimation.enabled = false;
servant.AnimationClips.AddRange(simpleAnimation.GetStates());
servant.Animator = servant.BodyMain.GetComponentInChildren<Animator>();
if (servant.Animator)
{
servant.OverrideController = new AnimatorOverrideController(AnimatorController);
servant.OverrideController["clip"] = null;
servant.Animator.speed = 0;
servant.Animator.runtimeAnimatorController = servant.OverrideController;
servant.Animator.Play(null);
}
GameObject MeshToggle = Resources.Load("MeshToggle") as GameObject;
var meshes = servant.Meshes = servant.BodyMain.GetComponentsInChildren<Renderer>().ToList();
for (int i = 0; i < meshes.Count; i++)
{
int meshId = i;
GameObject go = Instantiate(MeshToggle, UIController.Instance.MeshesListContent);
servant.InstantiatedObjects.Add(go);
go.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = meshes[i].name;
if (meshes[i].enabled)
{
string[] splitName = meshes[i].name.Split('_');
if (splitName.Length >= 3)
{
//Debug.LogWarning(meshes[i].name);
string partName = splitName[0];
var sameParts = meshes.Where(r => r.name.Split('_').Length >= 3).Where(r => r.name.Split('_')[0] == partName);
var bestPart = sameParts.OrderBy(r => r.name.Split('_')[2]).Reverse().Take(1);
//Debug.LogWarning(sameParts.Count());
foreach (var part in sameParts.Except(bestPart))
{
part.enabled = false;
}
}
}
go.GetComponentInChildren<Toggle>().isOn = meshes[i].enabled;
go.GetComponentInChildren<Toggle>().onValueChanged.AddListener((value) => meshes[meshId].enabled = value);
}
FateViewerMain.Instance.SpawnedServants.Add(servant);
FateViewerMain.SelectedServant = servant;
UIController.Instance.SetBodyAnimationDropdownData(servant.AnimationClips.Select(a => a.name).ToList());
var animId = UIController.Instance.BodyAnimationDropdown.options.IndexOf(UIController.Instance.BodyAnimationDropdown.options.FirstOrDefault(a => a.text == "Default"));
UIController.Instance.BodyAnimationDropdown.SetValueWithoutNotify(animId);
servant.PlayAnimation("Default");
assetBundle.Unload(false);
CenterCamera();
LoadingInProgress = false;
}
public IEnumerator BuildNP(AssetBundle assetBundle)
{
if (assetBundle == null)
{
Error.Log(Color.red, "Asset load fail");
Debug.LogError("Asset load fail");
LoadingInProgress = false;
assetBundle.Unload(true);
yield break;
}
FateServantContainer servant = new GameObject().AddComponent<FateServantContainer>();
servant.name = assetBundle.name;
foreach (var asset in assetBundle.LoadAllAssets())
{
if (asset == null) { continue; }
else if (asset.GetType() == typeof(GameObject))
{
if (asset.name.StartsWith("chr_"))
{
servant.BodyMain = asset as GameObject;
}
else if (asset.name.StartsWith("model_"))
{
Instantiate(asset, servant.transform);
}
}
else if (asset.GetType() == typeof(Texture2D))
{
Texture2D tex = asset as Texture2D;
servant.Textures.Add(tex);
}
else if (asset.GetType() == typeof(Material))
{
servant.Materials.Add(asset as Material);
}
else if (asset.GetType() == typeof(TextAsset))
{
}
else if (asset.GetType() == typeof(AnimationClip))
{
}
else
{
Error.Log(Color.yellow, asset.GetType().ToString());
Debug.LogWarning(asset.GetType());
}
}
UIController.Instance.CutoffSlider?.onValueChanged.RemoveAllListeners();
foreach (Material mat in servant.Materials)
{
if (mat.shader.name.Contains("Particle"))
{
mat.shader = Shader.Find("Particles/Standard Unlit");
var tex = mat.mainTexture;
var color = mat.color;
mat.CopyPropertiesFromMaterial(ParticleMaterial);
mat.mainTexture = tex;
mat.color = color;
}
else
{
mat.shader = Shader.Find("FateShader3Compatible");
if (mat.mainTexture != null)
{
var texture = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name);
if (texture != null)
{
mat.SetTexture("_MainTex", texture);
}
else
{
Error.Log(Color.red, $"Texture {mat.mainTexture.name} not found");
}
var alpha = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name + "a" || t.name == mat.mainTexture.name + "_alpha");
if (alpha)
{
mat.SetTexture("_Alpha", alpha);
}
}
Material temp = mat;
mat.SetFloat("_Cutoff", 0.91f);
UIController.Instance.CutoffSlider?.onValueChanged.AddListener((value) => { temp.SetFloat("_Cutoff", value / 100); });
}
}
if (servant.BodyMain == null)
{
Error.Log(Color.red, "Servant body was not loaded");
assetBundle.Unload(true);
LoadingInProgress = false;
yield break;
}
servant.BodyMain = Instantiate(servant.BodyMain, servant.transform);
servant.InstantiatedObjects.Add(servant.BodyMain);
servant.BodyMain.SetActive(true);
var simpleAnimation = servant.GetComponentInChildren<SimpleAnimation>();
simpleAnimation.enabled = false;
servant.AnimationClips.AddRange(simpleAnimation.GetStates());
servant.Animator = servant.BodyMain.GetComponentInChildren<Animator>();
if (servant.Animator)
{
servant.OverrideController = new AnimatorOverrideController(AnimatorController);
servant.OverrideController["clip"] = null;
servant.Animator.speed = 0;
servant.Animator.runtimeAnimatorController = servant.OverrideController;
servant.Animator.Play(null);
}
//GameObject MeshToggle = Resources.Load("MeshToggle") as GameObject;
//var meshes = servant.Meshes = servant.BodyMain.GetComponentsInChildren<Renderer>().ToList();
//for (int i = 0; i < meshes.Count; i++)
//{
// int meshId = i;
// GameObject go = Instantiate(MeshToggle, UIController.Instance.MeshesListContent);
// servant.InstantiatedObjects.Add(go);
// go.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = meshes[i].name;
// if (meshes[i].enabled)
// {
// string[] splitName = meshes[i].name.Split('_');
// if (splitName.Length >= 3)
// {
// string partName = splitName[0];
// var sameParts = meshes.Where(r => r.name.Split('_').Length >= 3).Where(r => r.name.Split('_')[0] == partName);
// var bestPart = sameParts.OrderBy(r => r.name.Split('_')[2]).Reverse().Take(1);
// foreach (var part in sameParts.Except(bestPart))
// {
// part.enabled = false;
// }
// }
// }
// go.GetComponentInChildren<Toggle>().isOn = meshes[i].enabled;
// go.GetComponentInChildren<Toggle>().onValueChanged.AddListener((value) => meshes[meshId].enabled = value);
//}
FateViewerMain.Instance.SpawnedServants.Add(servant);
FateViewerMain.SelectedServant = servant;
UIController.Instance.SetBodyAnimationDropdownData(servant.AnimationClips.Select(a => a.name).ToList());
var animId = 0;
UIController.Instance.BodyAnimationDropdown.SetValueWithoutNotify(animId);
servant.PlayAnimation("Default");
assetBundle.Unload(false);
CenterCamera();
LoadingInProgress = false;
}
public void CenterCamera()
{
/*
foreach (Transform t in MainBone)
{
AnimBounds.Encapsulate(new Bounds(t.transform.position, Vector3.one * 1.5f));
}
Bounds AnimBounds = CharaModel.GetComponentInChildren<SkinnedMeshRenderer>().bounds; //CharaModel.GetComponentInChildren<SkinnedMeshRenderer>().localBounds;
foreach (var renderer in CharaModel.GetComponentsInChildren<SkinnedMeshRenderer>())
{
AnimBounds.Encapsulate(renderer.bounds);
}
Camera.main.transform.position = new Vector3(-5, AnimBounds.center.y, 0);
Camera.main.transform.eulerAngles = new Vector3(0, 90, 0);
var orbit = GameObject.FindObjectOfType<CameraOrbit>();
var max = Mathf.Max(AnimBounds.size.x, AnimBounds.size.y, AnimBounds.size.z);
orbit.camZoom = max / 2;
orbit.camZoomMax = max > 15 ? max : 15;
orbit.camZoomMin = 0.2f;
*/
var orbit = GameObject.FindObjectOfType<CameraOrbit>();
orbit.camZoom = 1.5f;
orbit.camZoomMax = 500;
orbit.camZoomMin = 0.2f;
Camera.main.transform.eulerAngles = new Vector3(0, 90, 0);
Camera.main.transform.position = new Vector3(-5, 1, 0);
}
//public IEnumerator CreateRuntimeMask()
//{
// //GameObject activeGameObject = CharaModel;
// //AvatarMask avatarMask = new AvatarMask();
// //avatarMask.AddTransformPath(activeGameObject.transform);
// //var layers = OriginalController.layers;
// //layers[1].avatarMask = avatarMask;
// //OriginalController.layers = layers;
// //Animator.runtimeAnimatorController = OriginalController;
// //for (int i = 0; i < avatarMask.transformCount; i++)
// //{
// // bool value = avatarMask.GetTransformPath(i).Contains("joint_eye") || avatarMask.GetTransformPath(i).Contains("joint_mouth");
// // avatarMask.SetTransformActive(i, value);
// //}
// //OverrideController = new AnimatorOverrideController(Animator.runtimeAnimatorController);
// //Animator.runtimeAnimatorController = OverrideController;
// yield return PlayAnimation("Default");
// yield return PlayAnimationLayer2("Default");
//}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2635ae45de879d24f8ef8ed4092a90b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class FateNPContainer : MonoBehaviour
{
public GameObject BodyMain;
public List<SimpleAnimation.State> AnimationClips = new List<SimpleAnimation.State>();
public List<Texture2D> Textures = new List<Texture2D>();
public List<Material> Materials = new List<Material>();
public List<Renderer> Meshes = new List<Renderer>();
public Animator Animator;
public AnimatorOverrideController OverrideController;
public float CurrentFrame = 0;
public float CurrentFrame2 = 0;
private AnimationClip _currentClip;
public int ClipFrameCount = 0;
public int ClipFrameCount2 = 0;
private bool _animationReady;
private bool _animationReady2;
[Header("Garbage")]
public List<GameObject> InstantiatedObjects = new List<GameObject>();
private void Update()
{
if (_animationReady)
{
Animate();
}
}
private void Animate()
{
Animator.Play("clip", 0, Mathf.Round(CurrentFrame) / ClipFrameCount);
CurrentFrame += FateViewerMain.Instance.TimeScale;
CurrentFrame = (CurrentFrame) % (ClipFrameCount + 1);
}
public void PlayAnimation(string animationName)
{
_animationReady = false;
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
OverrideController["clip"] = bbb;
_currentClip = OverrideController["clip"];
CurrentFrame = 0;
ClipFrameCount = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
Debug.Log("----now playing----");
Debug.Log(_currentClip.name);
Debug.Log($"Framerate: {_currentClip.frameRate}");
Debug.Log($"Length: {_currentClip.length}");
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount})");
Animator?.Play("clip", 0, 0);
_animationReady = true;
}
public void PlayAnimationLayer2(string animationName)
{
_animationReady2 = false;
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
OverrideController["clip2"] = bbb;
_currentClip = OverrideController["clip2"];
CurrentFrame2 = 0;
ClipFrameCount2 = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
Debug.Log("----now playing----");
Debug.Log(_currentClip.name);
Debug.Log($"Framerate: {_currentClip.frameRate}");
Debug.Log($"Length: {_currentClip.length}");
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount2})");
Animator?.Play("clip2", 1, 0);
_animationReady2 = true;
}
#region affect things
public void ToggleTextureFiltering()
{
if (Textures.Count <= 0) return;
FilterMode filter = Textures[0].filterMode;
foreach (var tex in Textures)
{
tex.filterMode = filter == FilterMode.Point ? FilterMode.Bilinear : FilterMode.Point;
}
}
public void SwitchShaderToScreenshot(bool value)
{
foreach (var mat in Materials)
{
if (value)
{
if (mat.shader.name == "FateShader3Compatible")
{
mat.shader = Shader.Find("FateScreenshotShaderCompatible");
}
}
else
{
if (mat.shader.name == "FateScreenshotShaderCompatible")
{
mat.shader = Shader.Find("FateShader3Compatible");
}
}
}
}
#endregion
public void DeleteModel()
{
_animationReady = false;
foreach (var rend in BodyMain.GetComponentsInChildren<Renderer>())
{
for (int i = rend.materials.Length - 1; i >= 0; i--)
{
Destroy(rend.materials[i]);
}
}
for (int i = Textures.Count - 1; i >= 0; i--)
{
Destroy(Textures[i]);
}
for (int i = InstantiatedObjects.Count - 1; i >= 0; i--)
{
if (InstantiatedObjects[i] != null)
{
Destroy(InstantiatedObjects[i]);
}
}
Destroy(this.gameObject, 0.5f);
Resources.UnloadUnusedAssets();
System.GC.Collect();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4a606390c64e1b42b06632b11729acc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,148 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class FateServantContainer : MonoBehaviour
{
public GameObject BodyMain;
public List<SimpleAnimation.State> AnimationClips = new List<SimpleAnimation.State>();
public List<Texture2D> Textures = new List<Texture2D>();
public List<Material> Materials = new List<Material>();
public List<Renderer> Meshes = new List<Renderer>();
public Animator Animator;
public AnimatorOverrideController OverrideController;
public float CurrentFrame = 0;
public float CurrentFrame2 = 0;
private AnimationClip _currentClip;
public int ClipFrameCount = 0;
public int ClipFrameCount2 = 0;
private bool _animationReady;
private bool _animationReady2;
[Header("Garbage")]
public List<GameObject> InstantiatedObjects = new List<GameObject>();
private void Update()
{
//if (Input.GetKeyDown(KeyCode.F))
//{
// StartCoroutine(CreateRuntimeMask());
//}
if (_animationReady)// && _animationReady2)
{
Animate();
}
}
private void Animate()
{
//Debug.Log($"Frame: {CurrentFrame}/{ClipFrameCount}");
//Debug.Log($"Frame: {CurrentFrame2}/{ClipFrameCount2}");
Animator.Play("clip", 0, Mathf.Round(CurrentFrame) / ClipFrameCount);
CurrentFrame += FateViewerMain.Instance.TimeScale;
CurrentFrame = (CurrentFrame) % (ClipFrameCount + 1);
//Animator.Play("clip2", 1, Mathf.Round(CurrentFrame2) / ClipFrameCount2);
//CurrentFrame2 += FateViewerMain.Instance.TimeScale;
//CurrentFrame2 = Mathf.Clamp(CurrentFrame2, 0, ClipFrameCount2);
}
public void PlayAnimation(string animationName)
{
_animationReady = false;
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
OverrideController["clip"] = bbb;
_currentClip = OverrideController["clip"];
CurrentFrame = 0;
ClipFrameCount = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
Debug.Log("----now playing----");
Debug.Log(_currentClip.name);
Debug.Log($"Framerate: {_currentClip.frameRate}");
Debug.Log($"Length: {_currentClip.length}");
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount})");
Animator?.Play("clip", 0, 0);
_animationReady = true;
}
public void PlayAnimationLayer2(string animationName)
{
_animationReady2 = false;
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
OverrideController["clip2"] = bbb;
_currentClip = OverrideController["clip2"];
CurrentFrame2 = 0;
ClipFrameCount2 = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
Debug.Log("----now playing----");
Debug.Log(_currentClip.name);
Debug.Log($"Framerate: {_currentClip.frameRate}");
Debug.Log($"Length: {_currentClip.length}");
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount2})");
Animator?.Play("clip2", 1, 0);
_animationReady2 = true;
}
#region affect things
public void ToggleTextureFiltering()
{
if (Textures.Count <= 0) return;
FilterMode filter = Textures[0].filterMode;
foreach (var tex in Textures)
{
tex.filterMode = filter == FilterMode.Point ? FilterMode.Bilinear : FilterMode.Point;
}
}
public void SwitchShaderToScreenshot(bool value)
{
foreach (var mat in Materials)
{
if (value)
{
if (mat.shader.name == "FateShader3Compatible")
{
mat.shader = Shader.Find("FateScreenshotShaderCompatible");
}
}
else
{
if (mat.shader.name == "FateScreenshotShaderCompatible")
{
mat.shader = Shader.Find("FateShader3Compatible");
}
}
}
}
#endregion
public void DeleteModel()
{
_animationReady = false;
foreach (var rend in BodyMain.GetComponentsInChildren<Renderer>())
{
for (int i = rend.materials.Length - 1; i >= 0; i--)
{
Destroy(rend.materials[i]);
}
}
for (int i = Textures.Count - 1; i >= 0; i--)
{
Destroy(Textures[i]);
}
for (int i = InstantiatedObjects.Count - 1; i >= 0; i--)
{
if(InstantiatedObjects[i] != null)
{
Destroy(InstantiatedObjects[i]);
}
}
Destroy(this.gameObject, 0.5f);
Resources.UnloadUnusedAssets();
System.GC.Collect();
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2acb976eaa1073f40a3075dbbda868ed
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,343 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using System;
using UnityEngine.UI;
using System.Linq;
#if PLATFORM_ANDROID
using UnityEngine.Android;
#endif
public class FateViewerMain : MonoBehaviour
{
public static FateViewerMain Instance;
[Header("Online Data")]
public string AAAPI = "https://api.atlasacademy.io/export/";
public static string AAContent { get; set; } = "https://static.atlasacademy.io/JP/";
public string Region = "JP";
public string debugUrl = "this.is.a.test/website/modelViewer.html?id=303800";
[Header("Selected Servant")]
public List<FateServantContainer> SpawnedServants = new List<FateServantContainer>();
public static FateServantContainer SelectedServant;
[Header("General")]
public string AnimationName;
public BasicServant Servants;
public BasicServant Enemies;
[Header("Global")]
public GameObject Cam;
public float TimeScale = 1;
public Slider TimeScaleSlider;
private void Awake()
{
if (Instance != null)
{
Destroy(Instance);
}
Instance = this;
}
private void Start()
{
Application.targetFrameRate = 30;
Cam = Camera.main.gameObject;
StartCoroutine(AtlasStart());
}
private IEnumerator AtlasStart()
{
Error.Log(Color.green, "Version: " + Application.version);
string url = Application.absoluteURL;
string fullId = "";
string ascension = "1";
#if UNITY_EDITOR || PLATFORM_STANDALONE
url = debugUrl;
#endif
//Error.Log(Color.green, url);
string[] parts = url.Split('?');
foreach (var part in parts)
{
string partL = part.ToLower();
if (partL.StartsWith("id="))
{
if (int.TryParse(partL.Split('=')[1], out int result))
{
fullId = result.ToString();
}
}
else if (partL.StartsWith("ascension="))
{
ascension = partL.Split('=')[1];
}
else if (partL.StartsWith("customurl="))
{
AAContent = part.Split('=')[1];
}
else if (partL.StartsWith("region="))
{
switch (partL.Split('=')[1])
{
case "na":
Region = "NA"; break;
case "jp":
Region = "JP"; break;
default:
Error.Log(Color.yellow, $"Region {partL.Split('=')[1]} not available. Defaulting to JP");
Region = "JP";
break;
}
}
else if (partL.StartsWith("animation="))
{
AnimationName = partL.Split('=')[1];
}
else if (partL.StartsWith("debug"))
{
Error.CanvasContent.SetActive(true);
foreach (var parameter in url.Split('?'))
{
if (parameter.StartsWith("http"))
{
continue;
}
else if (parameter.Split('=').Length <= 1)
{
Error.Log(Color.green, $"{parameter} is ON");
}
else
{
Error.Log(Color.green, $"{parameter.Split('=')[0]} is {parameter.Split('=')[1]}");
}
}
}
}
yield return LoadCharaList();
yield return LoadEnemyList();
//StartCoroutine(LoadStage("39510"));
//yield break;
if (string.IsNullOrEmpty(fullId) || fullId == "-1")
{
Error.Log(Color.yellow, "Loading random");
int result = Servants.GetAllCostumes()[UnityEngine.Random.Range(0, Servants.GetAllCostumes().Count)].battleCharaId;
StartCoroutine(FateModelBuilder.Instance.LoadServant(result.ToString()));
}
else
{
StartCoroutine(FateModelBuilder.Instance.LoadServant(fullId));
}
}
public void ChangeAnimationTimeScale(float time)
{
TimeScale = time / 100;
}
public void ChangeAnimationFrame(int value)
{
TimeScaleSlider.value = 0;
foreach(var servant in GameObject.FindObjectsOfType<FateServantContainer>())
{
servant.CurrentFrame = mod(Mathf.RoundToInt(servant.CurrentFrame + value), servant.ClipFrameCount + 1);
}
}
int mod(int x, int m)
{
return (x % m + m) % m;
}
public IEnumerator LoadCharaList()
{
string url = $"{AAAPI}JP/basic_servant_lang_en.json";
if (Region == "NA")
{
url = $"{AAAPI}NA/basic_servant.json";
}
yield return FateAssetManager.DownloadText(url, (txt) =>
{
txt = $"{{\"Entries\": {txt} }}";
Servants = Newtonsoft.Json.JsonConvert.DeserializeObject<BasicServant>(txt);
foreach (var servant in Servants.Entries)
{
servant.costumes = servant.costume.Select(c => c.Value).ToList();
if (servant.costumes.FirstOrDefault(c => c.battleCharaId == servant.id) == null)
servant.costumes.Insert(0, new BasicServant.Costume()
{
battleCharaId = servant.id,
id = 0,
shortName = servant.name,
});
}
Servants.Entries = Servants.Entries.OrderBy(e => e.collectionNo).ToList();
});
if (Servants.Entries.Count > 0)
{
GameObject servantContainer = Resources.Load("ServantContainer") as GameObject;
foreach (var servant in Servants.Entries)
{
var servant1 = servant;
ServantUIContainer go = Instantiate(servantContainer, UIController.Instance.ServantList.content).GetComponent<ServantUIContainer>();
go.Servant = servant1;
go.FaceUrl = servant1.face;
go.ID.text = servant1.id.ToString();
go.Name.text = servant1.name.ToString();
go.Button.onClick.AddListener(() => {
UIController.Instance.OpenServantCostumePanel(servant1);
});
}
}
}
public IEnumerator LoadEnemyList()
{
string url = $"{AAAPI}JP/basic_svt_lang_en.json";
Dictionary<string, List<BasicServant.Costume>> entries = new Dictionary<string, List<BasicServant.Costume>>();
yield return FateAssetManager.DownloadText(url, (txt) =>
{
txt = $"{{\"Entries\": {txt} }}";
Enemies = Newtonsoft.Json.JsonConvert.DeserializeObject<BasicServant>(txt);
Enemies.Entries = Enemies.Entries.Where(e => e.type == "enemy").ToList();
Enemies.Entries = Enemies.Entries.OrderBy(e => e.name).ToList();
foreach (var enemy in Enemies.Entries)
{
enemy.costumes = enemy.costume.Select(c => c.Value).ToList();
foreach (var costume in enemy.costumes)
{
var cos = new BasicServant.Costume()
{
name = costume.name,
shortName = costume.shortName,
id = costume.id,
battleCharaId = costume.battleCharaId
};
if (entries.ContainsKey(enemy.name))
{
if (!entries[enemy.name].Any(c => c.battleCharaId == costume.battleCharaId))
entries[enemy.name].Add(cos);
}
else
{
entries[enemy.name] = new List<BasicServant.Costume>() { cos };
}
}
}
});
if (entries.Count() > 0)
{
GameObject servantContainer = Resources.Load("ServantContainer") as GameObject;
foreach (var enemy in entries)
{
var servant1 = enemy.Value;
ServantUIContainer go = Instantiate(servantContainer, UIController.Instance.EnemiesList.content).GetComponent<ServantUIContainer>();
//go.Servant = servant1[0];
go.FaceUrl = $"https://static.atlasacademy.io/JP/Enemys/{servant1[0].battleCharaId}1.png";
go.ID.text = servant1[0].battleCharaId.ToString();
go.Name.text = enemy.Key;
go.Button.onClick.AddListener(() => {
UIController.Instance.OpenEnemyCostumePanel(servant1);
});
}
}
}
public void ToggleCameraMode()
{
if(Cam.GetComponent<CameraOrbit>().enabled == false)
{
Cam.GetComponent<CameraOrbit3D>().enabled = false;
Cam.GetComponent<Camera>().orthographic = true;
Cam.GetComponent<CameraOrbit>().enabled = true;
FateModelBuilder.Instance.CenterCamera();
}
else
{
Cam.GetComponent<CameraOrbit>().enabled = false;
Cam.GetComponent<Camera>().orthographic = false;
Cam.GetComponent<CameraOrbit3D>().enabled = true;
}
}
#region Unused/WIP
//IEnumerator GalleryMode()
//{
// foreach (var servant in Servants.Entries)
// {
// yield return FateModelBuilder.Instance.ReplaceServant(servant.id.ToString());
// do
// {
// yield return new WaitForEndOfFrame();
// }
// while (FateModelBuilder.Instance.LoadingInProgress);
// yield return new WaitForEndOfFrame();
// Screenshot.GrabFrame(2000, 2000);
// yield return new WaitForEndOfFrame();
// }
//}
//IEnumerator LoadStage(string id)
//{
// AssetBundle assetBundle = AssetBundle.LoadFromMemory((Resources.Load(id) as TextAsset).bytes);
// List<GameObject> SpawnedGos = new List<GameObject>();
// foreach (string name in assetBundle.GetAllAssetNames())
// {
// //Error.Log(Color.green, name);
// object asset = assetBundle.LoadAsset(name);
// if (asset == null) { continue; }
// else if (asset.GetType() == typeof(GameObject))
// {
// if (name.EndsWith(".prefab"))
// SpawnedGos.Add(Instantiate(asset as GameObject));
// }
// }
// foreach (var go in SpawnedGos)
// {
// foreach (var rend in go.GetComponentsInChildren<Renderer>())
// {
// foreach (Material mat in rend.materials)
// {
// if (mat.name.ToLower().Contains("particle"))
// {
// mat.shader = Shader.Find("Particles/Standard Unlit");
// var tex = mat.mainTexture;
// var color = mat.color;
// mat.CopyPropertiesFromMaterial(FateModelBuilder.Instance.ParticleMaterial);
// mat.mainTexture = tex;
// mat.color = color;
// }
// else
// mat.shader = Shader.Find("FateStgShader");
// }
// }
// foreach (var particles in go.GetComponentsInChildren<ParticleSystemRenderer>())
// {
// particles.sortingOrder = 1000;
// }
// }
// assetBundle.Unload(false);
// yield break;
//}
//public void LoadNP()
//{
// var NP1 = AssetBundle.LoadFromMemory(((TextAsset)Resources.Load("NoblePhantasm/403800")).bytes);
// StartCoroutine(FateModelBuilder.Instance.BuildNP(NP1));
//}
//public static string GetDownloadFolder()
//{
// string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
// return (temp[0] + "/Download");
//}
#endregion
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dec20ea0ce00a8e42973c5a4f74e55e2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e705b8da674681d43a72563db32ed69c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: 2a9e9df3c14e9034eb587348635c8f09
folderAsset: yes
DefaultImporter:
userData:

View File

@@ -0,0 +1,65 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UI;
namespace HSVPicker.Editors
{
[CustomEditor(typeof(BoxSlider), true)]
[CanEditMultipleObjects]
public class BoxSliderEditor : SelectableEditor
{
SerializedProperty m_HandleRect;
SerializedProperty m_MinValue;
SerializedProperty m_MaxValue;
SerializedProperty m_WholeNumbers;
SerializedProperty m_Value;
SerializedProperty m_ValueY;
SerializedProperty m_OnValueChanged;
protected override void OnEnable()
{
base.OnEnable();
m_HandleRect = serializedObject.FindProperty("m_HandleRect");
m_MinValue = serializedObject.FindProperty("m_MinValue");
m_MaxValue = serializedObject.FindProperty("m_MaxValue");
m_WholeNumbers = serializedObject.FindProperty("m_WholeNumbers");
m_Value = serializedObject.FindProperty("m_Value");
m_ValueY = serializedObject.FindProperty("m_ValueY");
m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
EditorGUILayout.Space();
serializedObject.Update();
EditorGUILayout.PropertyField(m_HandleRect);
if (m_HandleRect.objectReferenceValue != null)
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_MinValue);
EditorGUILayout.PropertyField(m_MaxValue);
EditorGUILayout.PropertyField(m_WholeNumbers);
EditorGUILayout.Slider(m_Value, m_MinValue.floatValue, m_MaxValue.floatValue);
EditorGUILayout.Slider(m_ValueY, m_MinValue.floatValue, m_MaxValue.floatValue);
// Draw the event notification options
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_OnValueChanged);
}
else
{
EditorGUILayout.HelpBox("Specify a RectTransform for the slider fill or the slider handle or both. Each must have a parent RectTransform that it can slide within.", MessageType.Info);
}
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8701e045b26e51f4eb345f2ccb3c13f5
timeCreated: 1426804458
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,17 @@
{
"name": "HSVPicker.Editors",
"references": [
"HSVPicker"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 485edc8694d264a8fb6d3a830531425d
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 5d3904d3d18ddd544820bd8518990fee
folderAsset: yes
timeCreated: 1442586617
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,13 @@
using UnityEngine;
public enum ColorValues
{
R,
G,
B,
A,
Hue,
Saturation,
Value
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 859a1720e083e504cb68917f781e87c7
timeCreated: 1442586608
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 6bb0d49c64210014e9a24ed9345928c2
folderAsset: yes
timeCreated: 1442747310
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
using UnityEngine;
using System;
using UnityEngine.Events;
[Serializable]
public class ColorChangedEvent : UnityEvent<Color>
{
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ff46fbecea7739f4690e4285c88f53c5
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,6 @@
using UnityEngine.Events;
public class HSVChangedEvent : UnityEvent<float, float, float>
{
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3d95ce8fba3dbbf4eb14411412169b88
timeCreated: 1442747317
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,15 @@
{
"name": "HSVPicker",
"references": [
"GUID:6055be8ebefd69e48b49212b09b47b2f"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 413a95a52ca644b7dac76988ad8915af
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 916ee089a0d7b63419075f91e1c657ec
timeCreated: 1442747914
licenseType: Free
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,28 @@
HSV color picker using Unity UI.
Github https://github.com/judah4/HSV-Color-Picker-Unity
Usage:
Drag picker prefab onto a UI canvas.
Setup:
On the color picker setup section.
Show Rgb: Show RGB sliders.
Show Hsv: Show HSV sliders.
Show Alpha: Show the alpha slider.
Show Color Box: Show the larger color selection box and color column.
Show Color Slider Toggle: Show the button to toggle the HSV and RGB sliders.
Show Header: Options to show the top header with color preview and hex code.
* Hide: Hide the top header.
* Show Color: Show only the color preview in the header.
* Show Color Code: Show only the color code in the header.
* Show All: Show the entire top header.
Color Presets:
The prefabs starts with 4 colors in the color presets. This can be updated in the Setup section of the picker prefab.
Set the Preset Colors Id for different shared list between color pickers.

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 78aa9aa1471451045b0f2f552ad0c361
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2b5fe4e314cbd9944bcaa93e814e9bd5
folderAsset: yes
timeCreated: 1442586536
licenseType: Free
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,30 @@
using UnityEngine;
using UnityEngine.UI;
namespace HSVPicker
{
[RequireComponent(typeof(Image))]
public class ColorImage : MonoBehaviour
{
public ColorPicker picker;
private Image image;
private void Awake()
{
image = GetComponent<Image>();
picker.onValueChanged.AddListener(ColorChanged);
}
private void OnDestroy()
{
picker.onValueChanged.RemoveListener(ColorChanged);
}
private void ColorChanged(Color newColor)
{
image.color = newColor;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6bca58eb07ad66b498a2f158bcb13225
timeCreated: 1442675622
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace HSVPicker
{
[RequireComponent(typeof(TMP_Text))]
public class ColorLabel : MonoBehaviour
{
public ColorPicker picker;
public ColorValues type;
public string prefix = "R: ";
public float minValue = 0;
public float maxValue = 255;
public int precision = 0;
[SerializeField, HideInInspector]
private TMP_Text label;
private void Awake()
{
label = GetComponent<TMP_Text>();
}
private void OnEnable()
{
if (Application.isPlaying && picker != null)
{
picker.onValueChanged.AddListener(ColorChanged);
picker.onHSVChanged.AddListener(HSVChanged);
}
}
private void OnDestroy()
{
if (picker != null)
{
picker.onValueChanged.RemoveListener(ColorChanged);
picker.onHSVChanged.RemoveListener(HSVChanged);
}
}
#if UNITY_EDITOR
private void OnValidate()
{
label = GetComponent<TMP_Text>();
UpdateValue();
}
#endif
private void ColorChanged(Color color)
{
UpdateValue();
}
private void HSVChanged(float hue, float sateration, float value)
{
UpdateValue();
}
private void UpdateValue()
{
if(label == null)
return;
if (picker == null)
{
label.text = prefix + "-";
}
else
{
float value = minValue + (picker.GetValue(type) * (maxValue - minValue));
label.text = prefix + ConvertToDisplayString(value);
}
}
private string ConvertToDisplayString(float value)
{
if (precision > 0)
return value.ToString("f " + precision);
else
return Mathf.FloorToInt(value).ToString();
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 6b10e832a32d2d14facd8a3f489ee8d6
timeCreated: 1442587803
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,306 @@
using UnityEngine;
namespace HSVPicker
{
public class ColorPicker : MonoBehaviour
{
private float _hue = 0;
private float _saturation = 0;
private float _brightness = 0;
[SerializeField]
private Color _color = Color.red;
[Header("Setup")]
public ColorPickerSetup Setup;
[Header("Event")]
public ColorChangedEvent onValueChanged = new ColorChangedEvent();
public HSVChangedEvent onHSVChanged = new HSVChangedEvent();
public Color CurrentColor
{
get
{
return _color;
}
set
{
if (CurrentColor == value)
return;
_color = value;
RGBChanged();
SendChangedEvent();
}
}
private void Start()
{
Setup.AlphaSlidiers.Toggle(Setup.ShowAlpha);
Setup.ColorToggleElement.Toggle(Setup.ShowColorSliderToggle);
Setup.RgbSliders.Toggle(Setup.ShowRgb);
Setup.HsvSliders.Toggle(Setup.ShowHsv);
Setup.ColorBox.Toggle(Setup.ShowColorBox);
HandleHeaderSetting(Setup.ShowHeader);
UpdateColorToggleText();
RGBChanged();
SendChangedEvent();
}
public float H
{
get
{
return _hue;
}
set
{
if (_hue == value)
return;
_hue = value;
HSVChanged();
SendChangedEvent();
}
}
public float S
{
get
{
return _saturation;
}
set
{
if (_saturation == value)
return;
_saturation = value;
HSVChanged();
SendChangedEvent();
}
}
public float V
{
get
{
return _brightness;
}
set
{
if (_brightness == value)
return;
_brightness = value;
HSVChanged();
SendChangedEvent();
}
}
public float R
{
get
{
return _color.r;
}
set
{
if (_color.r == value)
return;
_color.r = value;
RGBChanged();
SendChangedEvent();
}
}
public float G
{
get
{
return _color.g;
}
set
{
if (_color.g == value)
return;
_color.g = value;
RGBChanged();
SendChangedEvent();
}
}
public float B
{
get
{
return _color.b;
}
set
{
if (_color.b == value)
return;
_color.b = value;
RGBChanged();
SendChangedEvent();
}
}
private float A
{
get
{
return _color.a;
}
set
{
if (_color.a == value)
return;
_color.a = value;
SendChangedEvent();
}
}
private void RGBChanged()
{
HsvColor color = HSVUtil.ConvertRgbToHsv(CurrentColor);
_hue = color.normalizedH;
_saturation = color.normalizedS;
_brightness = color.normalizedV;
}
private void HSVChanged()
{
Color color = HSVUtil.ConvertHsvToRgb(_hue * 360, _saturation, _brightness, _color.a);
_color = color;
}
private void SendChangedEvent()
{
onValueChanged.Invoke(CurrentColor);
onHSVChanged.Invoke(_hue, _saturation, _brightness);
}
public void AssignColor(ColorValues type, float value)
{
switch (type)
{
case ColorValues.R:
R = value;
break;
case ColorValues.G:
G = value;
break;
case ColorValues.B:
B = value;
break;
case ColorValues.A:
A = value;
break;
case ColorValues.Hue:
H = value;
break;
case ColorValues.Saturation:
S = value;
break;
case ColorValues.Value:
V = value;
break;
default:
break;
}
}
public void AssignColor(Color color)
{
CurrentColor = color;
}
public float GetValue(ColorValues type)
{
switch (type)
{
case ColorValues.R:
return R;
case ColorValues.G:
return G;
case ColorValues.B:
return B;
case ColorValues.A:
return A;
case ColorValues.Hue:
return H;
case ColorValues.Saturation:
return S;
case ColorValues.Value:
return V;
default:
throw new System.NotImplementedException("");
}
}
public void ToggleColorSliders()
{
Setup.ShowHsv = !Setup.ShowHsv;
Setup.ShowRgb = !Setup.ShowRgb;
Setup.HsvSliders.Toggle(Setup.ShowHsv);
Setup.RgbSliders.Toggle(Setup.ShowRgb);
UpdateColorToggleText();
}
void UpdateColorToggleText()
{
if (Setup.ShowRgb)
{
Setup.SliderToggleButtonText.text = "RGB";
}
if (Setup.ShowHsv)
{
Setup.SliderToggleButtonText.text = "HSV";
}
}
private void HandleHeaderSetting(ColorPickerSetup.ColorHeaderShowing setupShowHeader)
{
if (setupShowHeader == ColorPickerSetup.ColorHeaderShowing.Hide)
{
Setup.ColorHeader.Toggle(false);
return;
}
Setup.ColorHeader.Toggle(true);
Setup.ColorPreview.Toggle(setupShowHeader != ColorPickerSetup.ColorHeaderShowing.ShowColorCode);
Setup.ColorCode.Toggle(setupShowHeader != ColorPickerSetup.ColorHeaderShowing.ShowColor);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8262e4a8322117f4da079921eaa72834
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,58 @@

using UnityEngine;
using TMPro;
namespace HSVPicker
{
[System.Serializable]
public class ColorPickerSetup
{
public enum ColorHeaderShowing
{
Hide,
ShowColor,
ShowColorCode,
ShowAll,
}
[System.Serializable]
public class UiElements
{
public RectTransform[] Elements;
public void Toggle(bool active)
{
for (int cnt = 0; cnt < Elements.Length; cnt++)
{
Elements[cnt].gameObject.SetActive(active);
}
}
}
public bool ShowRgb = true;
public bool ShowHsv;
public bool ShowAlpha = true;
public bool ShowColorBox = true;
public bool ShowColorSliderToggle = true;
public ColorHeaderShowing ShowHeader = ColorHeaderShowing.ShowAll;
public UiElements RgbSliders;
public UiElements HsvSliders;
public UiElements ColorToggleElement;
public UiElements AlphaSlidiers;
public UiElements ColorHeader;
public UiElements ColorCode;
public UiElements ColorPreview;
public UiElements ColorBox;
public TMP_Text SliderToggleButtonText;
public string PresetColorsId = "default";
public Color[] DefaultPresetColors;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5f1e0a31fe4cdb5458d5a88aa1268434
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
namespace HSVPicker
{
public static class ColorPresetManager
{
private static Dictionary<string, ColorPresetList> _presets = new Dictionary<string, ColorPresetList>();
public static ColorPresetList Get(string listId = "default")
{
ColorPresetList preset;
if (!_presets.TryGetValue(listId, out preset))
{
preset = new ColorPresetList(listId);
_presets.Add(listId, preset);
}
return preset;
}
}
public class ColorPresetList
{
public string ListId { get; private set; }
public List<Color> Colors { get; private set; }
public event UnityAction<List<Color>> OnColorsUpdated;
public ColorPresetList(string listId, List<Color> colors = null)
{
if (colors == null)
{
colors = new List<Color>();
}
Colors = colors;
ListId = listId;
}
public void AddColor(Color color)
{
Colors.Add(color);
if (OnColorsUpdated != null)
{
OnColorsUpdated.Invoke(Colors);
}
}
public void UpdateList(IEnumerable<Color> colors)
{
Colors.Clear();
Colors.AddRange(colors);
if (OnColorsUpdated != null)
{
OnColorsUpdated.Invoke(Colors);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55b59bed8e892614e9397d8a20e36e0c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,86 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
namespace HSVPicker
{
public class ColorPresets : MonoBehaviour
{
public ColorPicker picker;
public GameObject[] presets;
public Image createPresetImage;
private ColorPresetList _colors;
void Awake()
{
// picker.onHSVChanged.AddListener(HSVChanged);
picker.onValueChanged.AddListener(ColorChanged);
}
void Start()
{
_colors = ColorPresetManager.Get(picker.Setup.PresetColorsId);
if (_colors.Colors.Count < picker.Setup.DefaultPresetColors.Length)
{
_colors.UpdateList(picker.Setup.DefaultPresetColors);
}
_colors.OnColorsUpdated += OnColorsUpdate;
OnColorsUpdate(_colors.Colors);
}
private void OnColorsUpdate(List<Color> colors)
{
for (int cnt = 0; cnt < presets.Length; cnt++)
{
if (colors.Count <= cnt)
{
presets[cnt].SetActive(false);
continue;
}
presets[cnt].SetActive(true);
presets[cnt].GetComponent<Image>().color = colors[cnt];
}
createPresetImage.gameObject.SetActive(colors.Count < presets.Length);
}
public void CreatePresetButton()
{
_colors.AddColor(picker.CurrentColor);
// for (var i = 0; i < presets.Length; i++)
//{
// if (!presets[i].activeSelf)
// {
// presets[i].SetActive(true);
// presets[i].GetComponent<Image>().color = picker.CurrentColor;
// break;
// }
//}
}
public void PresetSelect(Image sender)
{
picker.CurrentColor = sender.color;
}
// Not working, it seems ConvertHsvToRgb() is broken. It doesn't work when fed
// input h, s, v as shown below.
// private void HSVChanged(float h, float s, float v)
// {
// createPresetImage.color = HSVUtil.ConvertHsvToRgb(h, s, v, 1);
// }
private void ColorChanged(Color color)
{
createPresetImage.color = color;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 0923373e76e77402c9c53a2f1250ad3e
timeCreated: 1456875791
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
using UnityEngine;
using UnityEngine.UI;
namespace HSVPicker
{
/// <summary>
/// Displays one of the color values of aColorPicker
/// </summary>
[RequireComponent(typeof(Slider))]
public class ColorSlider : MonoBehaviour
{
public ColorPicker hsvpicker;
/// <summary>
/// Which value this slider can edit.
/// </summary>
public ColorValues type;
private Slider slider;
private bool listen = true;
private void Awake()
{
slider = GetComponent<Slider>();
hsvpicker.onValueChanged.AddListener(ColorChanged);
hsvpicker.onHSVChanged.AddListener(HSVChanged);
slider.onValueChanged.AddListener(SliderChanged);
}
private void OnDestroy()
{
hsvpicker.onValueChanged.RemoveListener(ColorChanged);
hsvpicker.onHSVChanged.RemoveListener(HSVChanged);
slider.onValueChanged.RemoveListener(SliderChanged);
}
private void ColorChanged(Color newColor)
{
listen = false;
switch (type)
{
case ColorValues.R:
slider.normalizedValue = newColor.r;
break;
case ColorValues.G:
slider.normalizedValue = newColor.g;
break;
case ColorValues.B:
slider.normalizedValue = newColor.b;
break;
case ColorValues.A:
slider.normalizedValue = newColor.a;
break;
default:
break;
}
}
private void HSVChanged(float hue, float saturation, float value)
{
listen = false;
switch (type)
{
case ColorValues.Hue:
slider.normalizedValue = hue; //1 - hue;
break;
case ColorValues.Saturation:
slider.normalizedValue = saturation;
break;
case ColorValues.Value:
slider.normalizedValue = value;
break;
default:
break;
}
}
private void SliderChanged(float newValue)
{
if (listen)
{
newValue = slider.normalizedValue;
//if (type == ColorValues.Hue)
// newValue = 1 - newValue;
hsvpicker.AssignColor(type, newValue);
}
listen = true;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: c600592efa0cf25479655321bf4fb08a
timeCreated: 1442586558
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,206 @@
using UnityEngine;
using UnityEngine.UI;
namespace HSVPicker
{
[RequireComponent(typeof(RawImage)), ExecuteInEditMode()]
public class ColorSliderImage : MonoBehaviour
{
public ColorPicker picker;
/// <summary>
/// Which value this slider can edit.
/// </summary>
public ColorValues type;
public Slider.Direction direction;
private RawImage image;
private RectTransform rectTransform
{
get
{
return transform as RectTransform;
}
}
private void Awake()
{
image = GetComponent<RawImage>();
if(Application.isPlaying)
RegenerateTexture();
}
private void OnEnable()
{
if (picker != null && Application.isPlaying)
{
picker.onValueChanged.AddListener(ColorChanged);
picker.onHSVChanged.AddListener(HSVChanged);
}
}
private void OnDisable()
{
if (picker != null)
{
picker.onValueChanged.RemoveListener(ColorChanged);
picker.onHSVChanged.RemoveListener(HSVChanged);
}
}
private void OnDestroy()
{
if (image.texture != null)
DestroyImmediate(image.texture);
}
private void ColorChanged(Color newColor)
{
switch (type)
{
case ColorValues.R:
case ColorValues.G:
case ColorValues.B:
case ColorValues.Saturation:
case ColorValues.Value:
RegenerateTexture();
break;
case ColorValues.A:
case ColorValues.Hue:
default:
break;
}
}
private void HSVChanged(float hue, float saturation, float value)
{
switch (type)
{
case ColorValues.R:
case ColorValues.G:
case ColorValues.B:
case ColorValues.Saturation:
case ColorValues.Value:
RegenerateTexture();
break;
case ColorValues.A:
case ColorValues.Hue:
default:
break;
}
}
private void RegenerateTexture()
{
Color32 baseColor = picker != null ? picker.CurrentColor : Color.black;
float h = picker != null ? picker.H : 0;
float s = picker != null ? picker.S : 0;
float v = picker != null ? picker.V : 0;
Texture2D texture;
Color32[] colors;
bool vertical = direction == Slider.Direction.BottomToTop || direction == Slider.Direction.TopToBottom;
bool inverted = direction == Slider.Direction.TopToBottom || direction == Slider.Direction.RightToLeft;
int size;
switch (type)
{
case ColorValues.R:
case ColorValues.G:
case ColorValues.B:
case ColorValues.A:
size = 255;
break;
case ColorValues.Hue:
size = 360;
break;
case ColorValues.Saturation:
case ColorValues.Value:
size = 100;
break;
default:
throw new System.NotImplementedException("");
}
if (vertical)
texture = new Texture2D(1, size);
else
texture = new Texture2D(size, 1);
texture.hideFlags = HideFlags.DontSave;
colors = new Color32[size];
switch (type)
{
case ColorValues.R:
for (byte i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = new Color32(i, baseColor.g, baseColor.b, 255);
}
break;
case ColorValues.G:
for (byte i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, i, baseColor.b, 255);
}
break;
case ColorValues.B:
for (byte i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, baseColor.g, i, 255);
}
break;
case ColorValues.A:
for (byte i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = new Color32(i, i, i, 255);
}
break;
case ColorValues.Hue:
for (int i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(i, 1, 1, 1);
}
break;
case ColorValues.Saturation:
for (int i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, (float)i / size, v, 1);
}
break;
case ColorValues.Value:
for (int i = 0; i < size; i++)
{
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, s, (float)i / size, 1);
}
break;
default:
throw new System.NotImplementedException("");
}
texture.SetPixels32(colors);
texture.Apply();
if (image.texture != null)
DestroyImmediate(image.texture);
image.texture = texture;
switch (direction)
{
case Slider.Direction.BottomToTop:
case Slider.Direction.TopToBottom:
image.uvRect = new Rect(0, 0, 2, 1);
break;
case Slider.Direction.LeftToRight:
case Slider.Direction.RightToLeft:
image.uvRect = new Rect(0, 0, 1, 2);
break;
default:
break;
}
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7ca76dd9ad6eb204c9b0481aece34497
timeCreated: 1442682013
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,53 @@
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace HSVPicker
{
[RequireComponent(typeof(TMP_InputField))]
public class HexColorField : MonoBehaviour
{
public ColorPicker hsvpicker;
public bool displayAlpha;
private TMP_InputField hexInputField;
private void Awake()
{
hexInputField = GetComponent<TMP_InputField>();
// Add listeners to keep text (and color) up to date
hexInputField.onEndEdit.AddListener(UpdateColor);
hsvpicker.onValueChanged.AddListener(UpdateHex);
}
private void OnDestroy()
{
hexInputField.onValueChanged.RemoveListener(UpdateColor);
hsvpicker.onValueChanged.RemoveListener(UpdateHex);
}
private void UpdateHex(Color newColor)
{
hexInputField.text = ColorToHex(newColor);
}
private void UpdateColor(string newHex)
{
Color color;
if (!newHex.StartsWith("#"))
newHex = "#"+newHex;
if (ColorUtility.TryParseHtmlString(newHex, out color))
hsvpicker.CurrentColor = color;
else
Debug.Log("hex value is in the wrong format, valid formats are: #RGB, #RGBA, #RRGGBB and #RRGGBBAA (# is optional)");
}
private string ColorToHex(Color32 color)
{
return displayAlpha
? string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.r, color.g, color.b, color.a)
: string.Format("#{0:X2}{1:X2}{2:X2}", color.r, color.g, color.b);
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d85c534b3c1560544b09d0996dfeba84
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,121 @@
using UnityEngine;
using UnityEngine.UI;
namespace HSVPicker
{
[RequireComponent(typeof(BoxSlider), typeof(RawImage)), ExecuteInEditMode()]
public class SVBoxSlider : MonoBehaviour
{
public ColorPicker picker;
private BoxSlider slider;
private RawImage image;
private int textureWidth = 128;
private int textureHeight = 128;
private float lastH = -1;
private bool listen = true;
public RectTransform rectTransform
{
get
{
return transform as RectTransform;
}
}
private void Awake()
{
slider = GetComponent<BoxSlider>();
image = GetComponent<RawImage>();
if(Application.isPlaying)
{
RegenerateSVTexture ();
}
}
private void OnEnable()
{
if (Application.isPlaying && picker != null)
{
slider.onValueChanged.AddListener(SliderChanged);
picker.onHSVChanged.AddListener(HSVChanged);
}
}
private void OnDisable()
{
if (picker != null)
{
slider.onValueChanged.RemoveListener(SliderChanged);
picker.onHSVChanged.RemoveListener(HSVChanged);
}
}
private void OnDestroy()
{
if ( image.texture != null )
{
DestroyImmediate (image.texture);
}
}
private void SliderChanged(float saturation, float value)
{
if (listen)
{
picker.AssignColor(ColorValues.Saturation, saturation);
picker.AssignColor(ColorValues.Value, value);
}
listen = true;
}
private void HSVChanged(float h, float s, float v)
{
if (!lastH.Equals(h))
{
lastH = h;
RegenerateSVTexture();
}
if (!s.Equals(slider.normalizedValue))
{
listen = false;
slider.normalizedValue = s;
}
if (!v.Equals(slider.normalizedValueY))
{
listen = false;
slider.normalizedValueY = v;
}
}
private void RegenerateSVTexture()
{
double h = picker != null ? picker.H * 360 : 0;
if ( image.texture != null )
DestroyImmediate (image.texture);
var texture = new Texture2D (textureWidth, textureHeight);
texture.wrapMode = TextureWrapMode.Clamp;
texture.hideFlags = HideFlags.DontSave;
for ( int s = 0; s < textureWidth; s++ )
{
Color[] colors = new Color[textureHeight];
for ( int v = 0; v < textureHeight; v++ )
{
colors[v] = HSVUtil.ConvertHsvToRgb (h, (float)s / textureWidth, (float)v / textureHeight, 1);
}
texture.SetPixels (s, 0, 1, textureHeight, colors);
}
texture.Apply();
image.texture = texture;
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1e4240873631f724496efec97d7151b3
timeCreated: 1442650713
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 2b33138f525222146865861432dbe845
folderAsset: yes
timeCreated: 1426051345
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,448 @@
using System;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
namespace HSVPicker
{
[AddComponentMenu("UI/BoxSlider", 35)]
[RequireComponent(typeof(RectTransform))]
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
{
public enum Direction
{
LeftToRight,
RightToLeft,
BottomToTop,
TopToBottom,
}
[Serializable]
public class BoxSliderEvent : UnityEvent<float, float> { }
[SerializeField]
private RectTransform m_HandleRect;
public RectTransform handleRect { get { return m_HandleRect; } set { if (SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
[Space(6)]
[SerializeField]
private float m_MinValue = 0;
public float minValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_MaxValue = 1;
public float maxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private bool m_WholeNumbers = false;
public bool wholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
[SerializeField]
private float m_Value = 1f;
public float value
{
get
{
if (wholeNumbers)
return Mathf.Round(m_Value);
return m_Value;
}
set
{
Set(value);
}
}
public float normalizedValue
{
get
{
if (Mathf.Approximately(minValue, maxValue))
return 0;
return Mathf.InverseLerp(minValue, maxValue, value);
}
set
{
this.value = Mathf.Lerp(minValue, maxValue, value);
}
}
[SerializeField]
private float m_ValueY = 1f;
public float valueY
{
get
{
if (wholeNumbers)
return Mathf.Round(m_ValueY);
return m_ValueY;
}
set
{
SetY(value);
}
}
public float normalizedValueY
{
get
{
if (Mathf.Approximately(minValue, maxValue))
return 0;
return Mathf.InverseLerp(minValue, maxValue, valueY);
}
set
{
this.valueY = Mathf.Lerp(minValue, maxValue, value);
}
}
[Space(6)]
// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
[SerializeField]
private BoxSliderEvent m_OnValueChanged = new BoxSliderEvent();
public BoxSliderEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = value; } }
// Private fields
//private Image m_FillImage;
//private Transform m_FillTransform;
//private RectTransform m_FillContainerRect;
private Transform m_HandleTransform;
private RectTransform m_HandleContainerRect;
// The offset from handle position to mouse down position
private Vector2 m_Offset = Vector2.zero;
private DrivenRectTransformTracker m_Tracker;
// Size of each step.
float stepSize { get { return wholeNumbers ? 1 : (maxValue - minValue) * 0.1f; } }
protected BoxSlider()
{ }
#if UNITY_EDITOR
protected override void OnValidate()
{
base.OnValidate();
if (wholeNumbers)
{
m_MinValue = Mathf.Round(m_MinValue);
m_MaxValue = Mathf.Round(m_MaxValue);
}
//Onvalidate is called before OnEnabled. We need to make sure not to touch any other objects before OnEnable is run.
if (IsActive())
{
UpdateCachedReferences();
Set(m_Value, false);
SetY(m_ValueY, false);
// Update rects since other things might affect them even if value didn't change.
UpdateVisuals();
}
#if UNITY_2018_3_OR_NEWER
if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
#else
var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
#endif
}
#endif // if UNITY_EDITOR
public virtual void Rebuild(CanvasUpdate executing)
{
#if UNITY_EDITOR
if (executing == CanvasUpdate.Prelayout)
onValueChanged.Invoke(value, valueY);
#endif
}
public void LayoutComplete()
{
}
public void GraphicUpdateComplete()
{
}
public static bool SetClass<T>(ref T currentValue, T newValue) where T: class
{
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
return false;
currentValue = newValue;
return true;
}
public static bool SetStruct<T>(ref T currentValue, T newValue) where T: struct
{
if (currentValue.Equals(newValue))
return false;
currentValue = newValue;
return true;
}
protected override void OnEnable()
{
base.OnEnable();
UpdateCachedReferences();
Set(m_Value, false);
SetY(m_ValueY, false);
// Update rects since they need to be initialized correctly.
UpdateVisuals();
}
protected override void OnDisable()
{
m_Tracker.Clear();
base.OnDisable();
}
void UpdateCachedReferences()
{
if (m_HandleRect)
{
m_HandleTransform = m_HandleRect.transform;
if (m_HandleTransform.parent != null)
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
}
else
{
m_HandleContainerRect = null;
}
}
// Set the valueUpdate the visible Image.
void Set(float input)
{
Set(input, true);
}
void Set(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, minValue, maxValue);
if (wholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_Value.Equals(newValue))
return;
m_Value = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(newValue, valueY);
}
void SetY(float input)
{
SetY(input, true);
}
void SetY(float input, bool sendCallback)
{
// Clamp the input
float newValue = Mathf.Clamp(input, minValue, maxValue);
if (wholeNumbers)
newValue = Mathf.Round(newValue);
// If the stepped value doesn't match the last one, it's time to update
if (m_ValueY.Equals(newValue))
return;
m_ValueY = newValue;
UpdateVisuals();
if (sendCallback)
m_OnValueChanged.Invoke(value, newValue);
}
protected override void OnRectTransformDimensionsChange()
{
base.OnRectTransformDimensionsChange();
UpdateVisuals();
}
enum Axis
{
Horizontal = 0,
Vertical = 1
}
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
private void UpdateVisuals()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
UpdateCachedReferences();
#endif
m_Tracker.Clear();
//to business!
if (m_HandleContainerRect != null)
{
m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
Vector2 anchorMin = Vector2.zero;
Vector2 anchorMax = Vector2.one;
anchorMin[0] = anchorMax[0] = (normalizedValue);
anchorMin[1] = anchorMax[1] = ( normalizedValueY);
m_HandleRect.anchorMin = anchorMin;
m_HandleRect.anchorMax = anchorMax;
}
}
// Update the slider's position based on the mouse.
void UpdateDrag(PointerEventData eventData, Camera cam)
{
RectTransform clickRect = m_HandleContainerRect;
if (clickRect != null && clickRect.rect.size[0] > 0)
{
Vector2 localCursor;
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
return;
localCursor -= clickRect.rect.position;
float val = Mathf.Clamp01((localCursor - m_Offset)[0] / clickRect.rect.size[0]);
normalizedValue = (val);
float valY = Mathf.Clamp01((localCursor - m_Offset)[1] / clickRect.rect.size[1]);
normalizedValueY = ( valY);
}
}
private bool MayDrag(PointerEventData eventData)
{
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
}
public override void OnPointerDown(PointerEventData eventData)
{
if (!MayDrag(eventData))
return;
base.OnPointerDown(eventData);
m_Offset = Vector2.zero;
if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect, eventData.position, eventData.enterEventCamera))
{
Vector2 localMousePos;
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
m_Offset = localMousePos;
m_Offset.y = -m_Offset.y;
}
else
{
// Outside the slider handle - jump to this point instead
UpdateDrag(eventData, eventData.pressEventCamera);
}
}
public virtual void OnDrag(PointerEventData eventData)
{
if (!MayDrag(eventData))
return;
UpdateDrag(eventData, eventData.pressEventCamera);
}
//public override void OnMove(AxisEventData eventData)
//{
// if (!IsActive() || !IsInteractable())
// {
// base.OnMove(eventData);
// return;
// }
// switch (eventData.moveDir)
// {
// case MoveDirection.Left:
// if (axis == Axis.Horizontal && FindSelectableOnLeft() == null) {
// Set(reverseValue ? value + stepSize : value - stepSize);
// SetY (reverseValue ? valueY + stepSize : valueY - stepSize);
// }
// else
// base.OnMove(eventData);
// break;
// case MoveDirection.Right:
// if (axis == Axis.Horizontal && FindSelectableOnRight() == null) {
// Set(reverseValue ? value - stepSize : value + stepSize);
// SetY(reverseValue ? valueY - stepSize : valueY + stepSize);
// }
// else
// base.OnMove(eventData);
// break;
// case MoveDirection.Up:
// if (axis == Axis.Vertical && FindSelectableOnUp() == null) {
// Set(reverseValue ? value - stepSize : value + stepSize);
// SetY(reverseValue ? valueY - stepSize : valueY + stepSize);
// }
// else
// base.OnMove(eventData);
// break;
// case MoveDirection.Down:
// if (axis == Axis.Vertical && FindSelectableOnDown() == null) {
// Set(reverseValue ? value + stepSize : value - stepSize);
// SetY(reverseValue ? valueY + stepSize : valueY - stepSize);
// }
// else
// base.OnMove(eventData);
// break;
// }
//}
//public override Selectable FindSelectableOnLeft()
//{
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
// return null;
// return base.FindSelectableOnLeft();
//}
//public override Selectable FindSelectableOnRight()
//{
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
// return null;
// return base.FindSelectableOnRight();
//}
//public override Selectable FindSelectableOnUp()
//{
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
// return null;
// return base.FindSelectableOnUp();
//}
//public override Selectable FindSelectableOnDown()
//{
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
// return null;
// return base.FindSelectableOnDown();
//}
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
{
eventData.useDragThreshold = false;
}
}
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 37c44bc94a9a7f241b5b552f3ff89458
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,210 @@
using UnityEngine;
using System;
namespace HSVPicker
{
#region ColorUtilities
public static class HSVUtil
{
public static HsvColor ConvertRgbToHsv(Color color)
{
return ConvertRgbToHsv((int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255));
}
//Converts an RGB color to an HSV color.
public static HsvColor ConvertRgbToHsv(double r, double b, double g)
{
double delta, min;
double h = 0, s, v;
min = Math.Min(Math.Min(r, g), b);
v = Math.Max(Math.Max(r, g), b);
delta = v - min;
if (v.Equals(0))
s = 0;
else
s = delta / v;
if (s.Equals(0))
h = 360;
else
{
if (r.Equals(v))
h = (g - b) / delta;
else if (g.Equals(v))
h = 2 + (b - r) / delta;
else if (b.Equals(v))
h = 4 + (r - g) / delta;
h *= 60;
if (h <= 0.0)
h += 360;
}
HsvColor hsvColor = new HsvColor();
hsvColor.H = 360 - h;
hsvColor.S = s;
hsvColor.V = v / 255;
return hsvColor;
}
// Converts an HSV color to an RGB color.
public static Color ConvertHsvToRgb(double h, double s, double v, float alpha)
{
double r = 0, g = 0, b = 0;
if (s.Equals(0))
{
r = v;
g = v;
b = v;
}
else
{
int i;
double f, p, q, t;
if (h.Equals(360))
h = 0;
else
h = h / 60;
i = (int)(h);
f = h - i;
p = v * (1.0 - s);
q = v * (1.0 - (s * f));
t = v * (1.0 - (s * (1.0f - f)));
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
}
return new Color((float)r, (float)g, (float)b, alpha);
}
}
#endregion ColorUtilities
// Describes a color in terms of
// Hue, Saturation, and Value (brightness)
#region HsvColor
public struct HsvColor
{
/// <summary>
/// The Hue, ranges between 0 and 360
/// </summary>
public double H;
/// <summary>
/// The saturation, ranges between 0 and 1
/// </summary>
public double S;
// The value (brightness), ranges between 0 and 1
public double V;
public float normalizedH
{
get
{
return (float)H / 360f;
}
set
{
H = (double)value * 360;
}
}
public float normalizedS
{
get
{
return (float)S;
}
set
{
S = (double)value;
}
}
public float normalizedV
{
get
{
return (float)V;
}
set
{
V = (double)value;
}
}
public HsvColor(double h, double s, double v)
{
this.H = h;
this.S = s;
this.V = v;
}
public override string ToString()
{
return "{" + H.ToString("f2") + "," + S.ToString("f2") + "," + V.ToString("f2") + "}";
}
}
#endregion HsvColor
}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4f3189246d7fc204faba7a1e9c08e0af
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

View File

@@ -0,0 +1,11 @@
{
"name": "judah4.hsvcolorpickerunity",
"displayName": "HSVPicker",
"version": "3.0.1",
"unity": "2019.4",
"description": "HSV color picker for Unity UI",
"keywords": [
],
"dependencies": {
}
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d46aec3749789425caab28d9edf026cf
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
[Serializable]
public class Manifest
{
public List<ManifestEntry> Entries = new List<ManifestEntry>();
public string GetFilePath(string input)
{
try { return Entries.FirstOrDefault(e => Path.GetFileName(e.path).ToLower() == input.ToLower()).path; }
catch { Error.Log(UnityEngine.Color.red, input + " not found in Manifest"); return null; }
}
[Serializable]
public class ManifestEntry
{
public string path;
public string type;
}
}
[Serializable]
public class BasicServant
{
public List<BasicServantEntry> Entries = new List<BasicServantEntry>();
public List<Costume> GetAllCostumes()
{
return Entries.SelectMany(e => e.costumes).ToList();
}
[Serializable]
public class BasicServantEntry
{
public string name;
public int id;
public int collectionNo;
public string type;
public string flag;
public string className;
public string attribute;
public int rarity;
public int atkMax;
public int hpMax;
public string face;
public Dictionary<string, Costume> costume;
public List<Costume> costumes;
}
[Serializable]
public class Costume
{
public int id;
public int costumeCollectionNo;
public int battleCharaId;
public string name;
public string shortName;
}
}
[Serializable]
public class FileInput
{
public string blob;
public string name;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cf9c6b22e49e5f84cb5eea6843a0714f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,87 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.UI;
public class KeyboardShortcuts : MonoBehaviour
{
public static KeyboardShortcuts Instance;
public List<char> KeyStrokes = new List<char>();
private void Awake()
{
if (Instance != null)
{
Destroy(Instance);
}
Instance = this;
}
public void DropdownPrevious(Dropdown dropdown)
{
dropdown.value = dropdown.value - 1 < 0 ? dropdown.options.Count - 1 : dropdown.value - 1;
}
public void DropdownNext(Dropdown dropdown)
{
dropdown.value = dropdown.value + 1 >= dropdown.options.Count ? 0 : dropdown.value + 1;
}
private void Update()
{
KatboiSequence();
if (Input.anyKeyDown && !string.IsNullOrEmpty(Input.inputString))
{
try
{
}
catch(System.Exception e)
{
Debug.LogWarning("caught " + e);
}
}
//Time
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
FateViewerMain.Instance.ChangeAnimationFrame(-1);
}
if (Input.GetKeyDown(KeyCode.RightArrow))
{
FateViewerMain.Instance.ChangeAnimationFrame(1);
}
}
private void KatboiSequence()
{
List<string> sequences = new List<string>()
{
"KATBOI01"
};
if (Input.anyKeyDown && !string.IsNullOrEmpty(Input.inputString))
{
if (KeyStrokes.Count >= 10)
{
KeyStrokes = ((IEnumerable<char>)KeyStrokes).Reverse().Take(10).Reverse().ToList();
}
KeyStrokes.Add(Input.inputString.ToUpper()[0]);
}
string passcode = sequences.FirstOrDefault(s => new string(KeyStrokes.ToArray()).Contains(s));
if (!string.IsNullOrEmpty(passcode))
{
switch (passcode)
{
case "KATBOI01":
break;
default: break;
}
KeyStrokes.Clear();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9299d9abed8fe544d9243415030b02fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,29 @@
using UnityEngine;
public class MatchWidth : MonoBehaviour
{
public float sceneWidth = 1;
public float sceneHeight = 1;
UnityEngine.UI.CanvasScaler _canvas;
void Start()
{
_canvas = GameObject.FindObjectOfType<UnityEngine.UI.CanvasScaler>();
}
// Adjust the camera's height so the desired scene width fits in view
// even if the screen/window size changes dynamically.
void Update()
{
if ((float)Screen.width / Screen.height > (float)sceneWidth / sceneHeight)
{
_canvas.matchWidthOrHeight = 1;
}
else
{
_canvas.matchWidthOrHeight = 0;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 04b7f5d5c02504e4bb1b88be0835b9e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,33 @@
using UnityEngine;
#if PLATFORM_ANDROID
using UnityEngine.Android;
#endif
public class PermissionsRationaleDialog : MonoBehaviour
{
// const int kDialogWidth = 300;
// const int kDialogHeight = 100;
// private bool windowOpen = true;
// void DoMyWindow(int windowID)
// {
// GUI.Label(new Rect(10, 20, kDialogWidth - 20, kDialogHeight - 50), "Enable access to files.");
// GUI.Button(new Rect(10, kDialogHeight - 30, 100, 20), "No");
// if (GUI.Button(new Rect(kDialogWidth - 110, kDialogHeight - 30, 100, 20), "Yes"))
// {
//#if PLATFORM_ANDROID
// Permission.RequestUserPermission(Permission.ExternalStorageRead);
//#endif
// windowOpen = false;
// }
// }
// void OnGUI()
// {
// if (windowOpen)
// {
// Rect rect = new Rect((Screen.width / 2) - (kDialogWidth / 2), (Screen.height / 2) - (kDialogHeight / 2), kDialogWidth, kDialogHeight);
// GUI.ModalWindow(0, rect, DoMyWindow, "Permissions Request Dialog");
// }
// }
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 560a5b4714b2e394c8d51e04d0770f59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,52 @@
using UnityEngine;
//https://gist.github.com/AkhmadMax, modified
public static class RendererExtensions
{
/// <summary>
/// Counts the bounding box corners of the given RectTransform that are visible from the given Camera in screen space.
/// </summary>
/// <returns>The amount of bounding box corners that are visible from the Camera.</returns>
/// <param name="rectTransform">Rect transform.</param>
/// <param name="camera">Camera.</param>
private static int CountCornersVisibleFrom(this RectTransform rectTransform)
{
Rect screenBounds = new Rect(0f, 0f, Screen.width, Screen.height); // Screen space bounds (assumes camera renders across the entire screen)
Vector3[] objectCorners = new Vector3[4];
rectTransform.GetWorldCorners(objectCorners);
int visibleCorners = 0;
for (var i = 0; i < objectCorners.Length; i++) // For each corner in rectTransform
{
if (screenBounds.Contains(objectCorners[i])) // If the corner is inside the screen
{
visibleCorners++;
}
}
return visibleCorners;
}
/// <summary>
/// Determines if this RectTransform is fully visible from the specified camera.
/// Works by checking if each bounding box corner of this RectTransform is inside the cameras screen space view frustrum.
/// </summary>
/// <returns><c>true</c> if is fully visible from the specified camera; otherwise, <c>false</c>.</returns>
/// <param name="rectTransform">Rect transform.</param>
/// <param name="camera">Camera.</param>
public static bool IsFullyVisibleFrom(this RectTransform rectTransform)
{
return CountCornersVisibleFrom(rectTransform) == 4; // True if all 4 corners are visible
}
/// <summary>
/// Determines if this RectTransform is at least partially visible from the specified camera.
/// Works by checking if any bounding box corner of this RectTransform is inside the cameras screen space view frustrum.
/// </summary>
/// <returns><c>true</c> if is at least partially visible from the specified camera; otherwise, <c>false</c>.</returns>
/// <param name="rectTransform">Rect transform.</param>
/// <param name="camera">Camera.</param>
public static bool IsVisible(this RectTransform rectTransform)
{
return CountCornersVisibleFrom(rectTransform) > 0; // True if any corners are visible
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 53a97b6d15f6176478ede149c0c52a9d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,142 @@
using SharpApng;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using uGIF;
using UnityEngine;
public class Screenshot : MonoBehaviour
{
public static Screenshot Instance;
bool recording = false;
private void Awake()
{
Instance = this;
}
public static void ScreenshotDefault()
{
var image = GrabFrame(int.Parse(UIController.Instance.SSWidth.text), int.Parse(UIController.Instance.SSHeight.text));
string fileName = string.Format("FateViewer_{0}", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
byte[] pngShot = ImageConversion.EncodeToPNG(image);
WebGLDownload.DownloadFile(pngShot, fileName, "png");
Destroy(image);
}
public static Texture2D GrabFrame(int width, int height, bool gifBackground = false)
{
var dimensions = GetResolution(width, height);
width = dimensions.x;
height = dimensions.y;
Camera cam = Camera.main;
int oldMask = cam.cullingMask;
var bak_cam_clearFlags = cam.clearFlags;
cam.cullingMask = ~LayerMask.GetMask("UI");
if (gifBackground)
{
cam.clearFlags = CameraClearFlags.SolidColor;
cam.backgroundColor = new Color32(0, 0, 0, 0);
}
else
{
cam.clearFlags = CameraClearFlags.Depth;
}
var tex_color = new Texture2D(width, height, TextureFormat.ARGB32, false);
var tex_alpha = new Texture2D(width, height, TextureFormat.ARGB32, false);
var render_texture = RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.ARGB32);
var grab_area = new Rect(0, 0, width, height);
RenderTexture.active = render_texture;
cam.targetTexture = render_texture;
cam.Render();
tex_color.ReadPixels(grab_area, 0, 0);
tex_color.Apply();
foreach(var servant in GameObject.FindObjectsOfType<FateServantContainer>())
{
servant.SwitchShaderToScreenshot(true);
}
cam.Render();
tex_alpha.ReadPixels(grab_area, 0, 0);
tex_alpha.Apply();
var alpha = tex_alpha.GetPixels();
var color = tex_color.GetPixels();
for (int i = 0; i < color.Length; i++)
{
color[i].a = alpha[i].a;
}
tex_color.SetPixels(color);
Destroy(tex_alpha);
foreach (var servant in GameObject.FindObjectsOfType<FateServantContainer>())
{
servant.SwitchShaderToScreenshot(false);
}
cam.clearFlags = bak_cam_clearFlags;
cam.cullingMask = oldMask;
cam.targetTexture = null;
RenderTexture.active = null;
RenderTexture.ReleaseTemporary(render_texture);
return tex_color;
}
public static Vector2Int GetResolution(int width, int height)
{
if (width == 0 && height == 0)
{
width = Screen.width;
height = Screen.height;
}
else if (width == 0)
{
float ratio = (float)Screen.width / (float)Screen.height;
width = Mathf.RoundToInt((float)height * ratio);
}
else if (height == 0)
{
float ratio = (float)Screen.height / (float)Screen.width;
height = Mathf.RoundToInt((float)width * ratio);
}
return new Vector2Int(width, height);
}
public void StartAnimRecord()
{
if (recording) return;
recording = true;
StartCoroutine(RecordAnim());
}
public IEnumerator RecordAnim()
{
Error.Log(Color.yellow, "Recording! Don't touch anything!");
FateViewerMain.SelectedServant.CurrentFrame = 0;
StartCoroutine(CaptureToGIFCustom.Instance.Encode());
while (FateViewerMain.SelectedServant.CurrentFrame <= FateViewerMain.SelectedServant.ClipFrameCount)
{
yield return new WaitForEndOfFrame();
var tex = GrabFrame(int.Parse(UIController.Instance.GifWidth.text), int.Parse(UIController.Instance.GifHeight.text), true);
CaptureToGIFCustom.Instance.Frames.Add(new Image(tex));
Destroy(tex);
//Debug.Log(FateViewerMain.SelectedServant.CurrentFrame);
if (FateViewerMain.SelectedServant.CurrentFrame == FateViewerMain.SelectedServant.ClipFrameCount) break;
}
CaptureToGIFCustom.Instance.stop = true;
recording = false;
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16e36c739b6e83d43b3787f158318a87
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ServantUIContainer : MonoBehaviour
{
public BasicServant.BasicServantEntry Servant;
public string FaceUrl;
public Image Face;
public TMPro.TextMeshProUGUI Name;
public TMPro.TextMeshProUGUI ID;
public Button Button;
bool _done;
private void OnEnable()
{
if (_done) return;
StartCoroutine(LoadIcon());
}
private IEnumerator LoadIcon()
{
yield return new WaitForEndOfFrame();
while (!GetComponent<RectTransform>().IsVisible())
{
yield return new WaitForEndOfFrame();
}
_done = true;
if (!string.IsNullOrEmpty(FaceUrl))
{
Davinci.get().load(FaceUrl).into(Face).start();
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f4f0afd5a5cafa4c9b498907eb2f207
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 8fc03674866ae9a4f9fdacc1444511bf
folderAsset: yes
timeCreated: 1493740709
licenseType: Pro
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,11 @@
using UnityEngine;
using UnityEngine.Playables;
public static class CustomPlayableExtensions
{
public static void ResetTime(this Playable playable, float time)
{
playable.SetTime(time);
playable.SetTime(time);
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1d6aadfd4af940c47a915f6e609245bd
timeCreated: 1519667576
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 13eb8d583b55e3f4998b9c8d1fc4f631
folderAsset: yes
timeCreated: 1502472444
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,12 @@
{
"name": "SimpleAnimationComponent-Editor",
"references": [
"SimpleAnimationComponent"
],
"optionalUnityReferences": [],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4073e604354115342b874ea3137b12f7
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,92 @@
using UnityEngine;
using UnityEditor;
[CustomEditor(typeof(SimpleAnimation))]
public class SimpleAnimationEditor : Editor
{
static class Styles
{
public static GUIContent animation = new GUIContent("Animation", "The clip that will be played if Play() is called, or if \"Play Automatically\" is enabled");
public static GUIContent animations = new GUIContent("Animations", "These clips will define the States the component will start with");
public static GUIContent playAutomatically = new GUIContent("Play Automatically", "If checked, the default clip will automatically be played");
public static GUIContent animatePhysics = new GUIContent("Animate Physics", "If checked, animations will be updated at the same frequency as Fixed Update");
public static GUIContent cullingMode = new GUIContent("Culling Mode", "Controls what is updated when the object has been culled");
}
SerializedProperty clip;
SerializedProperty states;
SerializedProperty playAutomatically;
SerializedProperty animatePhysics;
SerializedProperty cullingMode;
void OnEnable()
{
clip = serializedObject.FindProperty("m_Clip");
states = serializedObject.FindProperty("m_States");
playAutomatically = serializedObject.FindProperty("m_PlayAutomatically");
animatePhysics = serializedObject.FindProperty("m_AnimatePhysics");
cullingMode = serializedObject.FindProperty("m_CullingMode");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(clip, Styles.animation);
EditorGUILayout.PropertyField(states, Styles.animations, true);
EditorGUILayout.PropertyField(playAutomatically, Styles.playAutomatically);
EditorGUILayout.PropertyField(animatePhysics, Styles.animatePhysics);
EditorGUILayout.PropertyField(cullingMode, Styles.cullingMode);
serializedObject.ApplyModifiedProperties();
}
}
[CustomPropertyDrawer(typeof(SimpleAnimation.EditorState))]
class StateDrawer : PropertyDrawer
{
class Styles
{
public static readonly GUIContent disabledTooltip = new GUIContent("", "The Default state cannot be edited, change the Animation clip to change the Default State");
}
// Draw the property inside the given rect
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
// Draw label
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
EditorGUILayout.BeginHorizontal();
// Calculate rects
Rect clipRect = new Rect(position.x, position.y, position.width/2 - 5, position.height);
Rect nameRect = new Rect(position.x + position.width/2 + 5, position.y, position.width/2 - 5, position.height);
EditorGUI.BeginDisabledGroup(property.FindPropertyRelative("defaultState").boolValue);
EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("clip"), GUIContent.none);
EditorGUI.PropertyField(clipRect, property.FindPropertyRelative("name"), GUIContent.none);
if (property.FindPropertyRelative("defaultState").boolValue)
{
EditorGUI.LabelField(position, Styles.disabledTooltip);
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.EndHorizontal();
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b42bbe25e28af494dadccf960ecfc32e
timeCreated: 1502472599
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,211 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityEngine.Playables;
[RequireComponent(typeof(Animator))]
public partial class SimpleAnimation: MonoBehaviour
{
public interface State
{
bool enabled { get; set; }
bool isValid { get; }
float time { get; set; }
float normalizedTime { get; set; }
float speed { get; set; }
string name { get; set; }
float weight { get; set; }
float length { get; }
AnimationClip clip { get; }
WrapMode wrapMode { get; set; }
}
public Animator animator
{
get
{
if (m_Animator == null)
{
m_Animator = GetComponent<Animator>();
}
return m_Animator;
}
}
public bool animatePhysics
{
get { return m_AnimatePhysics; }
set { m_AnimatePhysics = value; animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal; }
}
public AnimatorCullingMode cullingMode
{
get { return animator.cullingMode; }
set { m_CullingMode = value; animator.cullingMode = m_CullingMode; }
}
public bool isPlaying { get { return m_Playable.IsPlaying(); } }
public bool playAutomatically
{
get { return m_PlayAutomatically; }
set { m_PlayAutomatically = value; }
}
public AnimationClip clip
{
get { return m_Clip; }
set
{
LegacyClipCheck(value);
m_Clip = value;
}
}
public WrapMode wrapMode
{
get { return m_WrapMode; }
set { m_WrapMode = value; }
}
public void AddClip(AnimationClip clip, string newName)
{
LegacyClipCheck(clip);
AddState(clip, newName);
}
public void Blend(string stateName, float targetWeight, float fadeLength)
{
m_Animator.enabled = true;
Kick();
m_Playable.Blend(stateName, targetWeight, fadeLength);
}
public void CrossFade(string stateName, float fadeLength)
{
m_Animator.enabled = true;
Kick();
m_Playable.Crossfade(stateName, fadeLength);
}
public void CrossFadeQueued(string stateName, float fadeLength, QueueMode queueMode)
{
m_Animator.enabled = true;
Kick();
m_Playable.CrossfadeQueued(stateName, fadeLength, queueMode);
}
public int GetClipCount()
{
return m_Playable.GetClipCount();
}
public bool IsPlaying(string stateName)
{
return m_Playable.IsPlaying(stateName);
}
public void Stop()
{
m_Playable.StopAll();
}
public void Stop(string stateName)
{
m_Playable.Stop(stateName);
}
public void Sample()
{
m_Graph.Evaluate();
}
public bool Play()
{
m_Animator.enabled = true;
Kick();
if (m_Clip != null && m_PlayAutomatically)
{
m_Playable.Play(kDefaultStateName);
}
return false;
}
public void AddState(AnimationClip clip, string name)
{
LegacyClipCheck(clip);
Kick();
if (m_Playable.AddClip(clip, name))
{
RebuildStates();
}
}
public void RemoveState(string name)
{
if (m_Playable.RemoveClip(name))
{
RebuildStates();
}
}
public bool Play(string stateName)
{
m_Animator.enabled = true;
Kick();
return m_Playable.Play(stateName);
}
public void PlayQueued(string stateName, QueueMode queueMode)
{
m_Animator.enabled = true;
Kick();
m_Playable.PlayQueued(stateName, queueMode);
}
public void RemoveClip(AnimationClip clip)
{
if (clip == null)
throw new System.NullReferenceException("clip");
if ( m_Playable.RemoveClip(clip) )
{
RebuildStates();
}
}
public void Rewind()
{
Kick();
m_Playable.Rewind();
}
public void Rewind(string stateName)
{
Kick();
m_Playable.Rewind(stateName);
}
public State GetState(string stateName)
{
SimpleAnimationPlayable.IState state = m_Playable.GetState(stateName);
if (state == null)
return null;
return new StateImpl(state, this);
}
public IEnumerable<State> GetStates()
{
return new StateEnumerable(this);
}
public State this[string name]
{
get { return GetState(name); }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3759e2aae0f7b9a47bb98fc64bf3c543
timeCreated: 1493315774
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,3 @@
{
"name": "SimpleAnimationComponent"
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: aff632302a0b84b498c3f33f7639b4d3
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,754 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
using System;
public partial class SimpleAnimationPlayable : PlayableBehaviour
{
LinkedList<QueuedState> m_StateQueue;
StateManagement m_States;
bool m_Initialized;
bool m_KeepStoppedPlayablesConnected = true;
public bool keepStoppedPlayablesConnected
{
get { return m_KeepStoppedPlayablesConnected; }
set
{
if (value != m_KeepStoppedPlayablesConnected)
{
m_KeepStoppedPlayablesConnected = value;
}
}
}
void UpdateStoppedPlayablesConnections()
{
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state == null)
continue;
if (state.enabled)
continue;
if (keepStoppedPlayablesConnected)
{
ConnectInput(state.index);
}
else
{
DisconnectInput(state.index);
}
}
}
protected Playable m_ActualPlayable;
protected Playable self { get { return m_ActualPlayable; } }
public Playable playable { get { return self; } }
protected PlayableGraph graph { get { return self.GetGraph(); } }
AnimationMixerPlayable m_Mixer;
public System.Action onDone = null;
public SimpleAnimationPlayable()
{
m_States = new StateManagement();
this.m_StateQueue = new LinkedList<QueuedState>();
}
public Playable GetInput(int index)
{
if (index >= m_Mixer.GetInputCount())
return Playable.Null;
return m_Mixer.GetInput(index);
}
public override void OnPlayableCreate(Playable playable)
{
m_ActualPlayable = playable;
var mixer = AnimationMixerPlayable.Create(graph, 1, true);
m_Mixer = mixer;
self.SetInputCount(1);
self.SetInputWeight(0, 1);
graph.Connect(m_Mixer, 0, self, 0);
}
public IEnumerable<IState> GetStates()
{
return new StateEnumerable(this);
}
public IState GetState(string name)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
return null;
}
return new StateHandle(this, state.index, state.playable);
}
private StateInfo DoAddClip(string name, AnimationClip clip)
{
//Start new State
StateInfo newState = m_States.InsertState();
newState.Initialize(name, clip, clip.wrapMode);
//Find at which input the state will be connected
int index = newState.index;
//Increase input count if needed
if (index == m_Mixer.GetInputCount())
{
m_Mixer.SetInputCount(index + 1);
}
var clipPlayable = AnimationClipPlayable.Create(graph, clip);
clipPlayable.SetApplyFootIK(false);
clipPlayable.SetApplyPlayableIK(false);
if (!clip.isLooping || newState.wrapMode == WrapMode.Once)
{
clipPlayable.SetDuration(clip.length);
}
newState.SetPlayable(clipPlayable);
newState.Pause();
if (keepStoppedPlayablesConnected)
ConnectInput(newState.index);
return newState;
}
public bool AddClip(AnimationClip clip, string name)
{
StateInfo state = m_States.FindState(name);
if (state != null)
{
Debug.LogError(string.Format("Cannot add state with name {0}, because a state with that name already exists", name));
return false;
}
DoAddClip(name, clip);
UpdateDoneStatus();
InvalidateStates();
return true;
}
public bool RemoveClip(string name)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot remove state with name {0}, because a state with that name doesn't exist", name));
return false;
}
RemoveClones(state);
InvalidateStates();
m_States.RemoveState(state.index);
return true;
}
public bool RemoveClip(AnimationClip clip)
{
InvalidateStates();
return m_States.RemoveClip(clip);
}
public bool Play(string name)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot play state with name {0} because there is no state with that name", name));
return false;
}
return Play(state.index);
}
private bool Play(int index)
{
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state.index == index)
{
state.Enable();
state.ForceWeight(1.0f);
}
else
{
DoStop(i);
}
}
return true;
}
public bool PlayQueued(string name, QueueMode queueMode)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot queue Play to state with name {0} because there is no state with that name", name));
return false;
}
return PlayQueued(state.index, queueMode);
}
bool PlayQueued(int index, QueueMode queueMode)
{
StateInfo newState = CloneState(index);
if (queueMode == QueueMode.PlayNow)
{
Play(newState.index);
return true;
}
m_StateQueue.AddLast(new QueuedState(StateInfoToHandle(newState), 0f));
return true;
}
public void Rewind(string name)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot Rewind state with name {0} because there is no state with that name", name));
return;
}
Rewind(state.index);
}
private void Rewind(int index)
{
m_States.SetStateTime(index, 0f);
}
public void Rewind()
{
for (int i = 0; i < m_States.Count; i++)
{
if (m_States[i] != null)
m_States.SetStateTime(i, 0f);
}
}
private void RemoveClones(StateInfo state)
{
var it = m_StateQueue.First;
while (it != null)
{
var next = it.Next;
StateInfo queuedState = m_States[it.Value.state.index];
if (queuedState.parentState.index == state.index)
{
m_StateQueue.Remove(it);
DoStop(queuedState.index);
}
it = next;
}
}
public bool Stop(string name)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot stop state with name {0} because there is no state with that name", name));
return false;
}
DoStop(state.index);
UpdateDoneStatus();
return true;
}
private void DoStop(int index)
{
StateInfo state = m_States[index];
if (state == null)
return;
m_States.StopState(index, state.isClone);
if (!state.isClone)
{
RemoveClones(state);
}
}
public bool StopAll()
{
for (int i = 0; i < m_States.Count; i++)
{
DoStop(i);
}
playable.SetDone(true);
return true;
}
public bool IsPlaying()
{
return m_States.AnyStatePlaying();
}
public bool IsPlaying(string stateName)
{
StateInfo state = m_States.FindState(stateName);
if (state == null)
return false;
return state.enabled || IsClonePlaying(state);
}
private bool IsClonePlaying(StateInfo state)
{
for (int i = 0; i < m_States.Count; i++)
{
StateInfo otherState = m_States[i];
if (otherState == null)
continue;
if (otherState.isClone && otherState.enabled && otherState.parentState.index == state.index)
{
return true;
}
}
return false;
}
public int GetClipCount()
{
int count=0;
for (int i = 0; i < m_States.Count; i++)
{
if (m_States[i] != null)
{
count++;
}
}
return count;
}
private void SetupLerp(StateInfo state, float targetWeight, float time)
{
float travel = Mathf.Abs(state.weight - targetWeight);
float newSpeed = time != 0f ? travel / time : Mathf.Infinity;
// If we're fading to the same target as before but slower, assume CrossFade was called multiple times and ignore new speed
if (state.fading && Mathf.Approximately(state.targetWeight, targetWeight) && newSpeed < state.fadeSpeed)
return;
state.FadeTo(targetWeight, newSpeed);
}
private bool Crossfade(int index, float time)
{
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state == null)
continue;
if (state.index == index)
{
m_States.EnableState(index);
}
if (state.enabled == false)
continue;
float targetWeight = state.index == index ? 1.0f : 0.0f;
SetupLerp(state, targetWeight, time);
}
return true;
}
private StateInfo CloneState(int index)
{
StateInfo original = m_States[index];
string newName = original.stateName + "Queued Clone";
StateInfo clone = DoAddClip(newName, original.clip);
clone.SetAsCloneOf(new StateHandle(this, original.index, original.playable));
return clone;
}
public bool Crossfade(string name, float time)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot crossfade to state with name {0} because there is no state with that name", name));
return false;
}
if (time == 0f)
return Play(state.index);
return Crossfade(state.index, time);
}
public bool CrossfadeQueued(string name, float time, QueueMode queueMode)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot queue crossfade to state with name {0} because there is no state with that name", name));
return false;
}
return CrossfadeQueued(state.index, time, queueMode);
}
private bool CrossfadeQueued(int index, float time, QueueMode queueMode)
{
StateInfo newState = CloneState(index);
if (queueMode == QueueMode.PlayNow)
{
Crossfade(newState.index, time);
return true;
}
m_StateQueue.AddLast(new QueuedState(StateInfoToHandle(newState), time));
return true;
}
private bool Blend(int index, float targetWeight, float time)
{
StateInfo state = m_States[index];
if (state.enabled == false)
m_States.EnableState(index);
if (time == 0f)
{
state.ForceWeight(targetWeight);
}
else
{
SetupLerp(state, targetWeight, time);
}
return true;
}
public bool Blend(string name, float targetWeight, float time)
{
StateInfo state = m_States.FindState(name);
if (state == null)
{
Debug.LogError(string.Format("Cannot blend state with name {0} because there is no state with that name", name));
return false;
}
return Blend(state.index, targetWeight, time);
}
public override void OnGraphStop(Playable playable)
{
//if the playable is not valid, then we are destroying, and our children won't be valid either
if (!self.IsValid())
return;
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state == null)
continue;
if (state.fadeSpeed == 0f && state.targetWeight == 0f)
{
Playable input = m_Mixer.GetInput(state.index);
if (!input.Equals(Playable.Null))
{
input.ResetTime(0f);
}
}
}
}
private void UpdateDoneStatus()
{
if (!m_States.AnyStatePlaying())
{
bool wasDone = playable.IsDone();
playable.SetDone(true);
if (!wasDone && onDone != null)
{
onDone();
}
}
}
private void CleanClonedStates()
{
for (int i = m_States.Count-1; i >= 0; i--)
{
StateInfo state = m_States[i];
if (state == null)
continue;
if (state.isReadyForCleanup)
{
Playable toDestroy = m_Mixer.GetInput(state.index);
graph.Disconnect(m_Mixer, state.index);
graph.DestroyPlayable(toDestroy);
m_States.RemoveState(i);
}
}
}
private void DisconnectInput(int index)
{
if (keepStoppedPlayablesConnected)
{
m_States[index].Pause();
}
graph.Disconnect(m_Mixer, index);
}
private void ConnectInput(int index)
{
StateInfo state = m_States[index];
graph.Connect(state.playable, 0, m_Mixer, state.index);
}
private void UpdateStates(float deltaTime)
{
bool mustUpdateWeights = false;
float totalWeight = 0f;
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
//Skip deleted states
if (state == null)
{
continue;
}
//Update crossfade weight
if (state.fading)
{
state.SetWeight(Mathf.MoveTowards(state.weight, state.targetWeight, state.fadeSpeed *deltaTime));
if (Mathf.Approximately(state.weight, state.targetWeight))
{
state.ForceWeight(state.targetWeight);
if (state.weight == 0f)
{
state.Stop();
}
}
}
if (state.enabledDirty)
{
if (state.enabled)
state.Play();
else
state.Pause();
if (!keepStoppedPlayablesConnected)
{
Playable input = m_Mixer.GetInput(i);
//if state is disabled but the corresponding input is connected, disconnect it
if (input.IsValid() && !state.enabled)
{
DisconnectInput(i);
}
else if (state.enabled && !input.IsValid())
{
ConnectInput(state.index);
}
}
}
if (state.enabled && state.wrapMode == WrapMode.Once)
{
bool stateIsDone = state.isDone;
float speed = state.speed;
float time = state.GetTime();
float duration = state.playableDuration;
stateIsDone |= speed < 0f && time < 0f;
stateIsDone |= speed >= 0f && time >= duration;
if (stateIsDone)
{
state.Stop();
state.Disable();
if (!keepStoppedPlayablesConnected)
DisconnectInput(state.index);
}
}
totalWeight += state.weight;
if (state.weightDirty)
{
mustUpdateWeights = true;
}
state.ResetDirtyFlags();
}
if (mustUpdateWeights)
{
bool hasAnyWeight = totalWeight > 0.0f;
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state == null)
continue;
float weight = hasAnyWeight ? state.weight / totalWeight : 0.0f;
m_Mixer.SetInputWeight(state.index, weight);
}
}
}
private float CalculateQueueTimes()
{
float longestTime = -1f;
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
//Skip deleted states
if (state == null || !state.enabled || !state.playable.IsValid())
continue;
if (state.wrapMode == WrapMode.Loop)
{
return Mathf.Infinity;
}
float speed = state.speed;
float stateTime = m_States.GetStateTime(state.index);
float remainingTime;
if (speed > 0 )
{
remainingTime = (state.clip.length - stateTime) / speed;
}
else if(speed < 0 )
{
remainingTime = (stateTime) / speed;
}
else
{
remainingTime = Mathf.Infinity;
}
if (remainingTime > longestTime)
{
longestTime = remainingTime;
}
}
return longestTime;
}
private void ClearQueuedStates()
{
using (var it = m_StateQueue.GetEnumerator())
{
while (it.MoveNext())
{
QueuedState queuedState = it.Current;
m_States.StopState(queuedState.state.index, true);
}
}
m_StateQueue.Clear();
}
private void UpdateQueuedStates()
{
bool mustCalculateQueueTimes = true;
float remainingTime = -1f;
var it = m_StateQueue.First;
while(it != null)
{
if (mustCalculateQueueTimes)
{
remainingTime = CalculateQueueTimes();
mustCalculateQueueTimes = false;
}
QueuedState queuedState = it.Value;
if (queuedState.fadeTime >= remainingTime)
{
Crossfade(queuedState.state.index, queuedState.fadeTime);
mustCalculateQueueTimes = true;
m_StateQueue.RemoveFirst();
it = m_StateQueue.First;
}
else
{
it = it.Next;
}
}
}
void InvalidateStateTimes()
{
int count = m_States.Count;
for (int i = 0; i < count; i++)
{
StateInfo state = m_States[i];
if (state == null)
continue;
state.InvalidateTime();
}
}
public override void PrepareFrame(Playable owner, FrameData data)
{
InvalidateStateTimes();
UpdateQueuedStates();
UpdateStates(data.deltaTime);
//Once everything is calculated, update done status
UpdateDoneStatus();
CleanClonedStates();
}
public bool ValidateInput(int index, Playable input)
{
if (!ValidateIndex(index))
return false;
StateInfo state = m_States[index];
if (state == null || !state.playable.IsValid() || state.playable.GetHandle() != input.GetHandle())
return false;
return true;
}
public bool ValidateIndex(int index)
{
return index >= 0 && index < m_States.Count;
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e979d7febf8bb72429b0869d1791a78a
timeCreated: 1493310304
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,718 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
using System;
public partial class SimpleAnimationPlayable : PlayableBehaviour
{
private int m_StatesVersion = 0;
private void InvalidateStates() { m_StatesVersion++; }
private class StateEnumerable: IEnumerable<IState>
{
private SimpleAnimationPlayable m_Owner;
public StateEnumerable(SimpleAnimationPlayable owner)
{
m_Owner = owner;
}
public IEnumerator<IState> GetEnumerator()
{
return new StateEnumerator(m_Owner);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new StateEnumerator(m_Owner);
}
class StateEnumerator : IEnumerator<IState>
{
private int m_Index = -1;
private int m_Version;
private SimpleAnimationPlayable m_Owner;
public StateEnumerator(SimpleAnimationPlayable owner)
{
m_Owner = owner;
m_Version = m_Owner.m_StatesVersion;
Reset();
}
private bool IsValid() { return m_Owner != null && m_Version == m_Owner.m_StatesVersion; }
IState GetCurrentHandle(int index)
{
if (!IsValid())
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
if (index < 0 || index >= m_Owner.m_States.Count)
throw new InvalidOperationException("Enumerator is invalid");
StateInfo state = m_Owner.m_States[index];
if (state == null)
throw new InvalidOperationException("Enumerator is invalid");
return new StateHandle(m_Owner, state.index, state.playable);
}
object IEnumerator.Current { get { return GetCurrentHandle(m_Index); } }
IState IEnumerator<IState>.Current { get { return GetCurrentHandle(m_Index); } }
public void Dispose() { }
public bool MoveNext()
{
if (!IsValid())
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
do
{ m_Index++; } while (m_Index < m_Owner.m_States.Count && m_Owner.m_States[m_Index] == null);
return m_Index < m_Owner.m_States.Count;
}
public void Reset()
{
if (!IsValid())
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
m_Index = -1;
}
}
}
public interface IState
{
bool IsValid();
bool enabled { get; set; }
float time { get; set; }
float normalizedTime { get; set; }
float speed { get; set; }
string name { get; set; }
float weight { get; set; }
float length { get; }
AnimationClip clip { get; }
WrapMode wrapMode { get; }
}
public class StateHandle : IState
{
public StateHandle(SimpleAnimationPlayable s, int index, Playable target)
{
m_Parent = s;
m_Index = index;
m_Target = target;
}
public bool IsValid()
{
return m_Parent.ValidateInput(m_Index, m_Target);
}
public bool enabled
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States[m_Index].enabled;
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
if (value)
m_Parent.m_States.EnableState(m_Index);
else
m_Parent.m_States.DisableState(m_Index);
}
}
public float time
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateTime(m_Index);
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
m_Parent.m_States.SetStateTime(m_Index, value);
}
}
public float normalizedTime
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
float length = m_Parent.m_States.GetClipLength(m_Index);
if (length == 0f)
length = 1f;
return m_Parent.m_States.GetStateTime(m_Index) / length;
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
float length = m_Parent.m_States.GetClipLength(m_Index);
if (length == 0f)
length = 1f;
m_Parent.m_States.SetStateTime(m_Index, value *= length);
}
}
public float speed
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateSpeed(m_Index);
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
m_Parent.m_States.SetStateSpeed(m_Index, value);
}
}
public string name
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateName(m_Index);
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
if (value == null)
throw new System.ArgumentNullException("A null string is not a valid name");
m_Parent.m_States.SetStateName(m_Index, value);
}
}
public float weight
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States[m_Index].weight;
}
set
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
if (value < 0)
throw new System.ArgumentException("Weights cannot be negative");
m_Parent.m_States.SetInputWeight(m_Index, value);
}
}
public float length
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateLength(m_Index);
}
}
public AnimationClip clip
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateClip(m_Index);
}
}
public WrapMode wrapMode
{
get
{
if (!IsValid())
throw new System.InvalidOperationException("This StateHandle is not valid");
return m_Parent.m_States.GetStateWrapMode(m_Index);
}
}
public int index { get { return m_Index; } }
private SimpleAnimationPlayable m_Parent;
private int m_Index;
private Playable m_Target;
}
private class StateInfo
{
public void Initialize(string name, AnimationClip clip, WrapMode wrapMode)
{
m_StateName = name;
m_Clip = clip;
m_WrapMode = wrapMode;
}
public float GetTime()
{
if (m_TimeIsUpToDate)
return m_Time;
m_Time = (float)m_Playable.GetTime();
m_TimeIsUpToDate = true;
return m_Time;
}
public void SetTime(float newTime)
{
m_Time = newTime;
m_Playable.ResetTime(m_Time);
m_Playable.SetDone(m_Time >= m_Playable.GetDuration());
}
public void Enable()
{
if (m_Enabled)
return;
m_EnabledDirty = true;
m_Enabled = true;
}
public void Disable()
{
if (m_Enabled == false)
return;
m_EnabledDirty = true;
m_Enabled = false;
}
public void Pause()
{
m_Playable.SetPlayState(PlayState.Paused);
}
public void Play()
{
m_Playable.SetPlayState(PlayState.Playing);
}
public void Stop()
{
m_FadeSpeed = 0f;
ForceWeight(0.0f);
Disable();
SetTime(0.0f);
m_Playable.SetDone(false);
if (isClone)
{
m_ReadyForCleanup = true;
}
}
public void ForceWeight(float weight)
{
m_TargetWeight = weight;
m_Fading = false;
m_FadeSpeed = 0f;
SetWeight(weight);
}
public void SetWeight(float weight)
{
m_Weight = weight;
m_WeightDirty = true;
}
public void FadeTo(float weight, float speed)
{
m_Fading = Mathf.Abs(speed) > 0f;
m_FadeSpeed = speed;
m_TargetWeight = weight;
}
public void DestroyPlayable()
{
if (m_Playable.IsValid())
{
m_Playable.GetGraph().DestroySubgraph(m_Playable);
}
}
public void SetAsCloneOf(StateHandle handle)
{
m_ParentState = handle;
m_IsClone = true;
}
public bool enabled
{
get { return m_Enabled; }
}
private bool m_Enabled;
public int index
{
get { return m_Index; }
set
{
Debug.Assert(m_Index == 0, "Should never reassign Index");
m_Index = value;
}
}
private int m_Index;
public string stateName
{
get { return m_StateName; }
set { m_StateName = value; }
}
private string m_StateName;
public bool fading
{
get { return m_Fading; }
}
private bool m_Fading;
private float m_Time;
public float targetWeight
{
get { return m_TargetWeight; }
}
private float m_TargetWeight;
public float weight
{
get { return m_Weight; }
}
float m_Weight;
public float fadeSpeed
{
get { return m_FadeSpeed; }
}
float m_FadeSpeed;
public float speed
{
get { return (float)m_Playable.GetSpeed(); }
set { m_Playable.SetSpeed(value); }
}
public float playableDuration
{
get { return (float)m_Playable.GetDuration(); }
}
public AnimationClip clip
{
get { return m_Clip; }
}
private AnimationClip m_Clip;
public void SetPlayable(Playable playable)
{
m_Playable = playable;
}
public bool isDone { get { return m_Playable.IsDone(); } }
public Playable playable
{
get { return m_Playable; }
}
private Playable m_Playable;
public WrapMode wrapMode
{
get { return m_WrapMode; }
}
private WrapMode m_WrapMode;
//Clone information
public bool isClone
{
get { return m_IsClone; }
}
private bool m_IsClone;
public bool isReadyForCleanup
{
get { return m_ReadyForCleanup; }
}
private bool m_ReadyForCleanup;
public StateHandle parentState
{
get { return m_ParentState; }
}
public StateHandle m_ParentState;
public bool enabledDirty { get { return m_EnabledDirty; } }
public bool weightDirty { get { return m_WeightDirty; } }
public void ResetDirtyFlags()
{
m_EnabledDirty = false;
m_WeightDirty = false;
}
private bool m_WeightDirty;
private bool m_EnabledDirty;
public void InvalidateTime() { m_TimeIsUpToDate = false; }
private bool m_TimeIsUpToDate;
}
private StateHandle StateInfoToHandle(StateInfo info)
{
return new StateHandle(this, info.index, info.playable);
}
private class StateManagement
{
private List<StateInfo> m_States;
public int Count { get { return m_Count; } }
private int m_Count;
public StateInfo this[int i]
{
get
{
return m_States[i];
}
}
public StateManagement()
{
m_States = new List<StateInfo>();
}
public StateInfo InsertState()
{
StateInfo state = new StateInfo();
int firstAvailable = m_States.FindIndex(s => s == null);
if (firstAvailable == -1)
{
firstAvailable = m_States.Count;
m_States.Add(state);
}
else
{
m_States.Insert(firstAvailable, state);
}
state.index = firstAvailable;
m_Count++;
return state;
}
public bool AnyStatePlaying()
{
return m_States.FindIndex(s => s != null && s.enabled) != -1;
}
public void RemoveState(int index)
{
StateInfo removed = m_States[index];
m_States[index] = null;
removed.DestroyPlayable();
m_Count = m_States.Count;
}
public bool RemoveClip(AnimationClip clip)
{
bool removed = false;
for (int i = 0; i < m_States.Count; i++)
{
StateInfo state = m_States[i];
if (state != null &&state.clip == clip)
{
RemoveState(i);
removed = true;
}
}
return removed;
}
public StateInfo FindState(string name)
{
int index = m_States.FindIndex(s => s != null && s.stateName == name);
if (index == -1)
return null;
return m_States[index];
}
public void EnableState(int index)
{
StateInfo state = m_States[index];
state.Enable();
}
public void DisableState(int index)
{
StateInfo state = m_States[index];
state.Disable();
}
public void SetInputWeight(int index, float weight)
{
StateInfo state = m_States[index];
state.SetWeight(weight);
}
public void SetStateTime(int index, float time)
{
StateInfo state = m_States[index];
state.SetTime(time);
}
public float GetStateTime(int index)
{
StateInfo state = m_States[index];
return state.GetTime();
}
public bool IsCloneOf(int potentialCloneIndex, int originalIndex)
{
StateInfo potentialClone = m_States[potentialCloneIndex];
return potentialClone.isClone && potentialClone.parentState.index == originalIndex;
}
public float GetStateSpeed(int index)
{
return m_States[index].speed;
}
public void SetStateSpeed(int index, float value)
{
m_States[index].speed = value;
}
public float GetInputWeight(int index)
{
return m_States[index].weight;
}
public float GetStateLength(int index)
{
AnimationClip clip = m_States[index].clip;
if (clip == null)
return 0f;
float speed = m_States[index].speed;
if (speed == 0f)
return Mathf.Infinity;
return clip.length / speed;
}
public float GetClipLength(int index)
{
AnimationClip clip = m_States[index].clip;
if (clip == null)
return 0f;
return clip.length;
}
public float GetStatePlayableDuration(int index)
{
return m_States[index].playableDuration;
}
public AnimationClip GetStateClip(int index)
{
return m_States[index].clip;
}
public WrapMode GetStateWrapMode(int index)
{
return m_States[index].wrapMode;
}
public string GetStateName(int index)
{
return m_States[index].stateName;
}
public void SetStateName(int index, string name)
{
m_States[index].stateName = name;
}
public void StopState(int index, bool cleanup)
{
if (cleanup)
{
RemoveState(index);
}
else
{
m_States[index].Stop();
}
}
}
private struct QueuedState
{
public QueuedState(StateHandle s, float t)
{
state = s;
fadeTime = t;
}
public StateHandle state;
public float fadeTime;
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ce4f5507fa3bef446a3981a7e6d2475e
timeCreated: 1502387922
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,405 @@
using System;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.Playables;
[RequireComponent(typeof(Animator))]
public partial class SimpleAnimation: MonoBehaviour, IAnimationClipSource
{
const string kDefaultStateName = "Default";
private class StateEnumerable : IEnumerable<State>
{
private SimpleAnimation m_Owner;
public StateEnumerable(SimpleAnimation owner)
{
m_Owner = owner;
}
public IEnumerator<State> GetEnumerator()
{
return new StateEnumerator(m_Owner);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new StateEnumerator(m_Owner);
}
class StateEnumerator : IEnumerator<State>
{
private SimpleAnimation m_Owner;
private IEnumerator<SimpleAnimationPlayable.IState> m_Impl;
public StateEnumerator(SimpleAnimation owner)
{
m_Owner = owner;
m_Impl = m_Owner.m_Playable.GetStates().GetEnumerator();
Reset();
}
State GetCurrent()
{
return new StateImpl(m_Impl.Current, m_Owner);
}
object IEnumerator.Current { get { return GetCurrent(); } }
State IEnumerator<State>.Current { get { return GetCurrent(); } }
public void Dispose() { }
public bool MoveNext()
{
return m_Impl.MoveNext();
}
public void Reset()
{
m_Impl.Reset();
}
}
}
private class StateImpl : State
{
public StateImpl(SimpleAnimationPlayable.IState handle, SimpleAnimation component)
{
m_StateHandle = handle;
m_Component = component;
}
private SimpleAnimationPlayable.IState m_StateHandle;
private SimpleAnimation m_Component;
bool State.enabled
{
get { return m_StateHandle.enabled; }
set
{
m_StateHandle.enabled = value;
if (value)
{
m_Component.Kick();
}
}
}
bool State.isValid
{
get { return m_StateHandle.IsValid(); }
}
float State.time
{
get { return m_StateHandle.time; }
set { m_StateHandle.time = value;
m_Component.Kick(); }
}
float State.normalizedTime
{
get { return m_StateHandle.normalizedTime; }
set { m_StateHandle.normalizedTime = value;
m_Component.Kick();}
}
float State.speed
{
get { return m_StateHandle.speed; }
set { m_StateHandle.speed = value;
m_Component.Kick();}
}
string State.name
{
get { return m_StateHandle.name; }
set { m_StateHandle.name = value; }
}
float State.weight
{
get { return m_StateHandle.weight; }
set { m_StateHandle.weight = value;
m_Component.Kick();}
}
float State.length
{
get { return m_StateHandle.length; }
}
AnimationClip State.clip
{
get { return m_StateHandle.clip; }
}
WrapMode State.wrapMode
{
get { return m_StateHandle.wrapMode; }
set { Debug.LogError("Not Implemented"); }
}
}
[System.Serializable]
public class EditorState
{
public AnimationClip clip;
public string name;
public bool defaultState;
}
protected void Kick()
{
if (!m_IsPlaying)
{
m_Graph.Play();
m_IsPlaying = true;
}
}
protected PlayableGraph m_Graph;
protected PlayableHandle m_LayerMixer;
protected PlayableHandle m_TransitionMixer;
protected Animator m_Animator;
protected bool m_Initialized;
protected bool m_IsPlaying;
protected SimpleAnimationPlayable m_Playable;
[SerializeField]
protected bool m_PlayAutomatically = true;
[SerializeField]
protected bool m_AnimatePhysics = false;
[SerializeField]
protected AnimatorCullingMode m_CullingMode = AnimatorCullingMode.CullUpdateTransforms;
[SerializeField]
protected WrapMode m_WrapMode;
[SerializeField]
protected AnimationClip m_Clip;
[SerializeField]
private EditorState[] m_States;
protected virtual void OnEnable()
{
Initialize();
m_Graph.Play();
if (m_PlayAutomatically)
{
Stop();
Play();
}
}
protected virtual void OnDisable()
{
if (m_Initialized)
{
Stop();
m_Graph.Stop();
}
}
private void Reset()
{
if (m_Graph.IsValid())
m_Graph.Destroy();
m_Initialized = false;
}
private void Initialize()
{
if (m_Initialized)
return;
m_Animator = GetComponent<Animator>();
m_Animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
m_Animator.cullingMode = m_CullingMode;
m_Graph = PlayableGraph.Create();
m_Graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
SimpleAnimationPlayable template = new SimpleAnimationPlayable();
var playable = ScriptPlayable<SimpleAnimationPlayable>.Create(m_Graph, template, 1);
m_Playable = playable.GetBehaviour();
m_Playable.onDone += OnPlayableDone;
if (m_States == null)
{
m_States = new EditorState[1];
m_States[0] = new EditorState();
m_States[0].defaultState = true;
m_States[0].name = "Default";
}
if (m_States != null)
{
foreach (var state in m_States)
{
if (state.clip)
{
m_Playable.AddClip(state.clip, state.name);
}
}
}
EnsureDefaultStateExists();
AnimationPlayableUtilities.Play(m_Animator, m_Playable.playable, m_Graph);
Play();
Kick();
m_Initialized = true;
}
private void EnsureDefaultStateExists()
{
if ( m_Playable != null && m_Clip != null && m_Playable.GetState(kDefaultStateName) == null )
{
m_Playable.AddClip(m_Clip, kDefaultStateName);
Kick();
}
}
protected virtual void Awake()
{
Initialize();
}
protected void OnDestroy()
{
if (m_Graph.IsValid())
{
m_Graph.Destroy();
}
}
private void OnPlayableDone()
{
m_Graph.Stop();
m_IsPlaying = false;
}
private void RebuildStates()
{
var playableStates = GetStates();
var list = new List<EditorState>();
foreach (var state in playableStates)
{
var newState = new EditorState();
newState.clip = state.clip;
newState.name = state.name;
list.Add(newState);
}
m_States = list.ToArray();
}
EditorState CreateDefaultEditorState()
{
var defaultState = new EditorState();
defaultState.name = "Default";
defaultState.clip = m_Clip;
defaultState.defaultState = true;
return defaultState;
}
static void LegacyClipCheck(AnimationClip clip)
{
if (clip && clip.legacy)
{
throw new ArgumentException(string.Format("Legacy clip {0} cannot be used in this component. Set .legacy property to false before using this clip", clip));
}
}
void InvalidLegacyClipError(string clipName, string stateName)
{
Debug.LogErrorFormat(this.gameObject,"Animation clip {0} in state {1} is Legacy. Set clip.legacy to false, or reimport as Generic to use it with SimpleAnimationComponent", clipName, stateName);
}
private void OnValidate()
{
//Don't mess with runtime data
if (Application.isPlaying)
return;
if (m_Clip && m_Clip.legacy)
{
Debug.LogErrorFormat(this.gameObject,"Animation clip {0} is Legacy. Set clip.legacy to false, or reimport as Generic to use it with SimpleAnimationComponent", m_Clip.name);
m_Clip = null;
}
//Ensure at least one state exists
if (m_States == null || m_States.Length == 0)
{
m_States = new EditorState[1];
}
//Create default state if it's null
if (m_States[0] == null)
{
m_States[0] = CreateDefaultEditorState();
}
//If first state is not the default state, create a new default state at index 0 and push back the rest
if (m_States[0].defaultState == false || m_States[0].name != "Default")
{
var oldArray = m_States;
m_States = new EditorState[oldArray.Length + 1];
m_States[0] = CreateDefaultEditorState();
oldArray.CopyTo(m_States, 1);
}
//If default clip changed, update the default state
if (m_States[0].clip != m_Clip)
m_States[0].clip = m_Clip;
//Make sure only one state is default
for (int i = 1; i < m_States.Length; i++)
{
if (m_States[i] == null)
{
m_States[i] = new EditorState();
}
m_States[i].defaultState = false;
}
//Ensure state names are unique
int stateCount = m_States.Length;
string[] names = new string[stateCount];
for (int i = 0; i < stateCount; i++)
{
EditorState state = m_States[i];
if (state.name == "" && state.clip)
{
state.name = state.clip.name;
}
#if UNITY_EDITOR
state.name = ObjectNames.GetUniqueName(names, state.name);
#endif
names[i] = state.name;
if (state.clip && state.clip.legacy)
{
InvalidLegacyClipError(state.clip.name, state.name);
state.clip = null;
}
}
m_Animator = GetComponent<Animator>();
m_Animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
m_Animator.cullingMode = m_CullingMode;
}
public void GetAnimationClips(List<AnimationClip> results)
{
foreach (var state in m_States)
{
if (state.clip != null)
results.Add(state.clip);
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 11c2ad7a923243841ab35b83723a6473
timeCreated: 1502394771
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 52d9c3bfd6589ad4fad615672d33562b
folderAsset: yes
timeCreated: 1502464957
licenseType: Pro
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show More