Browse Source

添加识别定位

jiajun.hu.x 2 years ago
parent
commit
452197a60b
37 changed files with 5587 additions and 673 deletions
  1. 209 164
      Assets/ImmersalSDK/Samples/Scenes/MappingApp.unity
  2. 528 509
      Assets/NRSDK/Resources/NRUI/NRHomeMenu.prefab
  3. 0 0
      Assets/Scripts/MonoSingleton.cs
  4. 0 0
      Assets/Scripts/MonoSingleton.cs.meta
  5. 2 0
      Assets/Scripts/NRLocalizer.cs
  6. 0 0
      Assets/Scripts/NRLocalizer.cs.meta
  7. 0 0
      Assets/Scripts/TestGrid.cs
  8. 0 0
      Assets/Scripts/TestGrid.cs.meta
  9. 1148 0
      Assets/StartTrack.unity
  10. 7 0
      Assets/StartTrack.unity.meta
  11. 8 0
      Assets/UnityTool.meta
  12. BIN
      Assets/UnityTool/NPinyin.dll
  13. 33 0
      Assets/UnityTool/NPinyin.dll.meta
  14. 31 0
      Assets/UnityTool/Singleton.cs
  15. 11 0
      Assets/UnityTool/Singleton.cs.meta
  16. 8 0
      Assets/UnityTool/System.Web.Util.meta
  17. 38 0
      Assets/UnityTool/System.Web.Util/Helpers.cs
  18. 8 0
      Assets/UnityTool/System.Web.Util/Helpers.cs.meta
  19. 862 0
      Assets/UnityTool/System.Web.Util/HttpEncoder.cs
  20. 8 0
      Assets/UnityTool/System.Web.Util/HttpEncoder.cs.meta
  21. 8 0
      Assets/UnityTool/System.Web.meta
  22. 714 0
      Assets/UnityTool/System.Web/HttpUtility.cs
  23. 8 0
      Assets/UnityTool/System.Web/HttpUtility.cs.meta
  24. 207 0
      Assets/UnityTool/TimerMgr.cs
  25. 11 0
      Assets/UnityTool/TimerMgr.cs.meta
  26. 309 0
      Assets/UnityTool/UnityLog.cs
  27. 11 0
      Assets/UnityTool/UnityLog.cs.meta
  28. 91 0
      Assets/UnityTool/UnitySingleton.cs
  29. 11 0
      Assets/UnityTool/UnitySingleton.cs.meta
  30. 1074 0
      Assets/UnityTool/UnityUtil.cs
  31. 11 0
      Assets/UnityTool/UnityUtil.cs.meta
  32. 94 0
      Assets/UnityTool/XColor.cs
  33. 11 0
      Assets/UnityTool/XColor.cs.meta
  34. 52 0
      Assets/UnityTool/XVector2.cs
  35. 11 0
      Assets/UnityTool/XVector2.cs.meta
  36. 52 0
      Assets/UnityTool/XVector3.cs
  37. 11 0
      Assets/UnityTool/XVector3.cs.meta

File diff suppressed because it is too large
+ 209 - 164
Assets/ImmersalSDK/Samples/Scenes/MappingApp.unity


File diff suppressed because it is too large
+ 528 - 509
Assets/NRSDK/Resources/NRUI/NRHomeMenu.prefab


+ 0 - 0
Assets/MonoSingleton.cs → Assets/Scripts/MonoSingleton.cs


+ 0 - 0
Assets/MonoSingleton.cs.meta → Assets/Scripts/MonoSingleton.cs.meta


+ 2 - 0
Assets/NRLocalizer.cs → Assets/Scripts/NRLocalizer.cs

@@ -4,6 +4,7 @@ using System;
 using System.Threading.Tasks;
 using Unity.Collections.LowLevel.Unsafe;
 using UnityEngine;
+using XRTool.Util;
 
 
 /*===============================================================================
@@ -80,6 +81,7 @@ namespace Immersal.AR.Nreal
 			}
 		}
 
+
 		public override void StartLocalizing()
 		{
 			CamTexture.Play();

+ 0 - 0
Assets/NRLocalizer.cs.meta → Assets/Scripts/NRLocalizer.cs.meta


+ 0 - 0
Assets/TestGrid.cs → Assets/Scripts/TestGrid.cs


+ 0 - 0
Assets/TestGrid.cs.meta → Assets/Scripts/TestGrid.cs.meta


File diff suppressed because it is too large
+ 1148 - 0
Assets/StartTrack.unity


+ 7 - 0
Assets/StartTrack.unity.meta

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

+ 8 - 0
Assets/UnityTool.meta

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

BIN
Assets/UnityTool/NPinyin.dll


+ 33 - 0
Assets/UnityTool/NPinyin.dll.meta

@@ -0,0 +1,33 @@
+fileFormatVersion: 2
+guid: f0c376f63f86ea141b911f04ec4b2007
+PluginImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  iconMap: {}
+  executionOrder: {}
+  defineConstraints: []
+  isPreloaded: 0
+  isOverridable: 0
+  isExplicitlyReferenced: 0
+  validateReferences: 1
+  platformData:
+  - first:
+      Any: 
+    second:
+      enabled: 1
+      settings: {}
+  - first:
+      Editor: Editor
+    second:
+      enabled: 0
+      settings:
+        DefaultValueInitialized: true
+  - first:
+      Windows Store Apps: WindowsStoreApps
+    second:
+      enabled: 0
+      settings:
+        CPU: AnyCPU
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Assets/UnityTool/Singleton.cs

@@ -0,0 +1,31 @@
+using System;
+namespace XRTool.Util
+{
+    /// <summary>
+    /// 基本的单例,不依附Unity
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class Singleton<T> where T :class, new()
+    {
+        private static T instance;
+        private static readonly object syslock = new object();
+        public static T Instance
+        {
+            get
+            {
+                //线程安全锁
+                if (instance == null)
+                {
+                    lock (syslock)
+                    {
+                        if (instance == null)
+                        {
+                            instance = new T();
+                        }
+                    }
+                }
+                return instance;
+            }
+        }
+    }
+}

+ 11 - 0
Assets/UnityTool/Singleton.cs.meta

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

+ 8 - 0
Assets/UnityTool/System.Web.Util.meta

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

+ 38 - 0
Assets/UnityTool/System.Web.Util/Helpers.cs

@@ -0,0 +1,38 @@
+//
+// System.Web.Util.Helpers
+//
+// Authors:
+//	Marek Habersack (mhabersack@novell.com)
+//
+// (C) 2009 Novell, Inc (http://novell.com)
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Globalization;
+
+namespace System.Web.Util
+{
+	class Helpers
+	{
+		public static readonly CultureInfo InvariantCulture = CultureInfo.InvariantCulture;
+	}
+}

+ 8 - 0
Assets/UnityTool/System.Web.Util/Helpers.cs.meta

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

+ 862 - 0
Assets/UnityTool/System.Web.Util/HttpEncoder.cs

@@ -0,0 +1,862 @@
+//
+// Authors:
+//   Patrik Torstensson (Patrik.Torstensson@labs2.com)
+//   Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
+//   Tim Coleman (tim@timcoleman.com)
+//   Gonzalo Paniagua Javier (gonzalo@ximian.com)
+
+//   Marek Habersack <mhabersack@novell.com>
+//
+// (C) 2005-2010 Novell, Inc (http://novell.com/)
+//
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.IO;
+using System.Text;
+#if NET_4_0 && !MOBILE
+using System.Web.Configuration;
+#endif
+
+namespace System.Web.Util
+{
+#if NET_4_0
+	public
+#endif
+	class HttpEncoder
+	{
+		static char [] hexChars = "0123456789abcdef".ToCharArray ();
+		static object entitiesLock = new object ();
+		static SortedDictionary <string, char> entities;
+#if NET_4_0
+		static Lazy <HttpEncoder> defaultEncoder;
+		static Lazy <HttpEncoder> currentEncoderLazy;
+#else
+		static HttpEncoder defaultEncoder;
+#endif
+		static HttpEncoder currentEncoder;
+
+		static IDictionary <string, char> Entities {
+			get {
+				lock (entitiesLock) {
+					if (entities == null)
+						InitEntities ();
+
+					return entities;
+				}
+			}
+		}
+		
+		public static HttpEncoder Current {
+			get {
+#if NET_4_0
+				if (currentEncoder == null)
+					currentEncoder = currentEncoderLazy.Value;
+#endif
+				return currentEncoder;
+			}
+#if NET_4_0
+			set {
+				if (value == null)
+					throw new ArgumentNullException ("value");
+				currentEncoder = value;
+			}
+#endif
+		}
+
+		public static HttpEncoder Default {
+			get {
+#if NET_4_0
+				return defaultEncoder.Value;
+#else
+				return defaultEncoder;
+#endif
+			}
+		}
+
+		static HttpEncoder ()
+		{
+#if NET_4_0
+			defaultEncoder = new Lazy <HttpEncoder> (() => new HttpEncoder ());
+			currentEncoderLazy = new Lazy <HttpEncoder> (new Func <HttpEncoder> (GetCustomEncoderFromConfig));
+#else
+			defaultEncoder = new HttpEncoder ();
+			currentEncoder = defaultEncoder;
+#endif
+		}
+		
+		public HttpEncoder ()
+		{
+		}
+#if NET_4_0	
+		protected internal virtual
+#else
+		internal static
+#endif
+		void HeaderNameValueEncode (string headerName, string headerValue, out string encodedHeaderName, out string encodedHeaderValue)
+		{
+			if (String.IsNullOrEmpty (headerName))
+				encodedHeaderName = headerName;
+			else
+				encodedHeaderName = EncodeHeaderString (headerName);
+
+			if (String.IsNullOrEmpty (headerValue))
+				encodedHeaderValue = headerValue;
+			else
+				encodedHeaderValue = EncodeHeaderString (headerValue);
+		}
+
+		static void StringBuilderAppend (string s, ref StringBuilder sb)
+		{
+			if (sb == null)
+				sb = new StringBuilder (s);
+			else
+				sb.Append (s);
+		}
+		
+		static string EncodeHeaderString (string input)
+		{
+			StringBuilder sb = null;
+			
+			for (int i = 0; i < input.Length; i++) {
+				char ch = input [i];
+
+				if ((ch < 32 && ch != 9) || ch == 127)
+					StringBuilderAppend (String.Format ("%{0:x2}", (int)ch), ref sb);
+			}
+
+			if (sb != null)
+				return sb.ToString ();
+
+			return input;
+		}
+#if NET_4_0		
+		protected internal virtual void HtmlAttributeEncode (string value, TextWriter output)
+		{
+
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			if (String.IsNullOrEmpty (value))
+				return;
+
+			output.Write (HtmlAttributeEncode (value));
+		}
+
+		protected internal virtual void HtmlDecode (string value, TextWriter output)
+		{
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			output.Write (HtmlDecode (value));
+		}
+
+		protected internal virtual void HtmlEncode (string value, TextWriter output)
+		{
+			if (output == null)
+				throw new ArgumentNullException ("output");
+
+			output.Write (HtmlEncode (value));
+		}
+
+		protected internal virtual byte[] UrlEncode (byte[] bytes, int offset, int count)
+		{
+			return UrlEncodeToBytes (bytes, offset, count);
+		}
+
+		static HttpEncoder GetCustomEncoderFromConfig ()
+		{
+#if MOBILE
+			return defaultEncoder.Value;
+#else
+			var cfg = HttpRuntime.Section;
+			string typeName = cfg.EncoderType;
+
+			if (String.Compare (typeName, "System.Web.Util.HttpEncoder", StringComparison.OrdinalIgnoreCase) == 0)
+				return Default;
+			
+			Type t = Type.GetType (typeName, false);
+			if (t == null)
+				throw new ConfigurationErrorsException (String.Format ("Could not load type '{0}'.", typeName));
+			
+			if (!typeof (HttpEncoder).IsAssignableFrom (t))
+				throw new ConfigurationErrorsException (
+					String.Format ("'{0}' is not allowed here because it does not extend class 'System.Web.Util.HttpEncoder'.", typeName)
+				);
+
+			return Activator.CreateInstance (t, false) as HttpEncoder;
+#endif
+		}
+#endif
+#if NET_4_0
+		protected internal virtual
+#else
+		internal static
+#endif
+		string UrlPathEncode (string value)
+		{
+			if (String.IsNullOrEmpty (value))
+				return value;
+
+			MemoryStream result = new MemoryStream ();
+			int length = value.Length;
+			for (int i = 0; i < length; i++)
+				UrlPathEncodeChar (value [i], result);
+			
+			return Encoding.ASCII.GetString (result.ToArray ());
+		}
+		
+		internal static byte[] UrlEncodeToBytes (byte[] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				throw new ArgumentNullException ("bytes");
+			
+			int blen = bytes.Length;
+			if (blen == 0)
+				return new byte [0];
+			
+			if (offset < 0 || offset >= blen)
+				throw new ArgumentOutOfRangeException("offset");
+
+			if (count < 0 || count > blen - offset)
+				throw new ArgumentOutOfRangeException("count");
+
+			MemoryStream result = new MemoryStream (count);
+			int end = offset + count;
+			for (int i = offset; i < end; i++)
+				UrlEncodeChar ((char)bytes [i], result, false);
+
+			return result.ToArray();
+		}
+		
+		internal static string HtmlEncode (string s) 
+		{
+			if (s == null)
+				return null;
+
+			if (s.Length == 0)
+				return String.Empty;
+			
+			bool needEncode = false;
+			for (int i = 0; i < s.Length; i++) {
+				char c = s [i];
+				if (c == '&' || c == '"' || c == '<' || c == '>' || c > 159
+#if NET_4_0
+				    || c == '\''
+#endif
+				) {
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			StringBuilder output = new StringBuilder ();
+			int len = s.Length;
+			
+			for (int i = 0; i < len; i++) {
+				char ch = s [i];
+				switch (ch) {
+					case '&' :
+						output.Append ("&amp;");
+						break;
+					case '>' : 
+						output.Append ("&gt;");
+						break;
+					case '<' :
+						output.Append ("&lt;");
+						break;
+					case '"' :
+						output.Append ("&quot;");
+						break;
+#if NET_4_0
+					case '\'':
+						output.Append ("&#39;");
+						break;
+#endif
+					case '\uff1c':
+						output.Append ("&#65308;");
+						break;
+
+					case '\uff1e':
+						output.Append ("&#65310;");
+						break;
+						
+					default:
+						if (ch > 159 && ch < 256) {
+							output.Append ("&#");
+							output.Append (((int) ch).ToString (Helpers.InvariantCulture));
+							output.Append (";");
+						} else
+							output.Append (ch);
+						break;
+				}	
+			}
+			
+			return output.ToString ();			
+		}
+		
+		internal static string HtmlAttributeEncode (string s) 
+		{
+#if NET_4_0
+			if (String.IsNullOrEmpty (s))
+				return String.Empty;
+#else
+			if (s == null) 
+				return null;
+			
+			if (s.Length == 0)
+				return String.Empty;
+#endif			
+			bool needEncode = false;
+			for (int i = 0; i < s.Length; i++) {
+				char c = s [i];
+				if (c == '&' || c == '"' || c == '<'
+#if NET_4_0
+				    || c == '\''
+#endif
+				) {
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			StringBuilder output = new StringBuilder ();
+			int len = s.Length;
+
+			for (int i = 0; i < len; i++) {
+				char ch = s [i];
+				switch (ch) {
+					case '&' : 
+						output.Append ("&amp;");
+						break;
+					case '"' :
+						output.Append ("&quot;");
+						break;
+					case '<':
+						output.Append ("&lt;");
+						break;
+#if NET_4_0
+					case '\'':
+						output.Append ("&#39;");
+						break;
+#endif
+					default:
+						output.Append (ch);
+						break;
+				}
+			}
+
+			return output.ToString();
+		}
+		
+		internal static string HtmlDecode (string s)
+		{
+			if (s == null)
+				return null;
+
+			if (s.Length == 0)
+				return String.Empty;
+			
+			if (s.IndexOf ('&') == -1)
+				return s;
+#if NET_4_0
+			StringBuilder rawEntity = new StringBuilder ();
+#endif
+			StringBuilder entity = new StringBuilder ();
+			StringBuilder output = new StringBuilder ();
+			int len = s.Length;
+			// 0 -> nothing,
+			// 1 -> right after '&'
+			// 2 -> between '&' and ';' but no '#'
+			// 3 -> '#' found after '&' and getting numbers
+			int state = 0;
+			int number = 0;
+			bool is_hex_value = false;
+			bool have_trailing_digits = false;
+	
+			for (int i = 0; i < len; i++) {
+				char c = s [i];
+				if (state == 0) {
+					if (c == '&') {
+						entity.Append (c);
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+						state = 1;
+					} else {
+						output.Append (c);
+					}
+					continue;
+				}
+
+				if (c == '&') {
+					state = 1;
+					if (have_trailing_digits) {
+						entity.Append (number.ToString (Helpers.InvariantCulture));
+						have_trailing_digits = false;
+					}
+
+					output.Append (entity.ToString ());
+					entity.Length = 0;
+					entity.Append ('&');
+					continue;
+				}
+
+				if (state == 1) {
+					if (c == ';') {
+						state = 0;
+						output.Append (entity.ToString ());
+						output.Append (c);
+						entity.Length = 0;
+					} else {
+						number = 0;
+						is_hex_value = false;
+						if (c != '#') {
+							state = 2;
+						} else {
+							state = 3;
+						}
+						entity.Append (c);
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					}
+				} else if (state == 2) {
+					entity.Append (c);
+					if (c == ';') {
+						string key = entity.ToString ();
+						if (key.Length > 1 && Entities.ContainsKey (key.Substring (1, key.Length - 2)))
+							key = Entities [key.Substring (1, key.Length - 2)].ToString ();
+
+						output.Append (key);
+						state = 0;
+						entity.Length = 0;
+#if NET_4_0
+						rawEntity.Length = 0;
+#endif
+					}
+				} else if (state == 3) {
+					if (c == ';') {
+#if NET_4_0
+						if (number == 0)
+							output.Append (rawEntity.ToString () + ";");
+						else
+#endif
+						if (number > 65535) {
+							output.Append ("&#");
+							output.Append (number.ToString (Helpers.InvariantCulture));
+							output.Append (";");
+						} else {
+							output.Append ((char) number);
+						}
+						state = 0;
+						entity.Length = 0;
+#if NET_4_0
+						rawEntity.Length = 0;
+#endif
+						have_trailing_digits = false;
+					} else if (is_hex_value &&  Uri.IsHexDigit(c)) {
+						number = number * 16 + Uri.FromHex(c);
+						have_trailing_digits = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					} else if (Char.IsDigit (c)) {
+						number = number * 10 + ((int) c - '0');
+						have_trailing_digits = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					} else if (number == 0 && (c == 'x' || c == 'X')) {
+						is_hex_value = true;
+#if NET_4_0
+						rawEntity.Append (c);
+#endif
+					} else {
+						state = 2;
+						if (have_trailing_digits) {
+							entity.Append (number.ToString (Helpers.InvariantCulture));
+							have_trailing_digits = false;
+						}
+						entity.Append (c);
+					}
+				}
+			}
+
+			if (entity.Length > 0) {
+				output.Append (entity.ToString ());
+			} else if (have_trailing_digits) {
+				output.Append (number.ToString (Helpers.InvariantCulture));
+			}
+			return output.ToString ();
+		}
+
+		internal static bool NotEncoded (char c)
+		{
+			return (c == '!' || c == '(' || c == ')' || c == '*' || c == '-' || c == '.' || c == '_'
+#if !NET_4_0
+				|| c == '\''
+#endif
+			);
+		}
+		
+		internal static void UrlEncodeChar (char c, Stream result, bool isUnicode) {
+			if (c > 255) {
+				//FIXME: what happens when there is an internal error?
+				//if (!isUnicode)
+				//	throw new ArgumentOutOfRangeException ("c", c, "c must be less than 256");
+				int idx;
+				int i = (int) c;
+
+				result.WriteByte ((byte)'%');
+				result.WriteByte ((byte)'u');
+				idx = i >> 12;
+				result.WriteByte ((byte)hexChars [idx]);
+				idx = (i >> 8) & 0x0F;
+				result.WriteByte ((byte)hexChars [idx]);
+				idx = (i >> 4) & 0x0F;
+				result.WriteByte ((byte)hexChars [idx]);
+				idx = i & 0x0F;
+				result.WriteByte ((byte)hexChars [idx]);
+				return;
+			}
+			
+			if (c > ' ' && NotEncoded (c)) {
+				result.WriteByte ((byte)c);
+				return;
+			}
+			if (c==' ') {
+				result.WriteByte ((byte)'+');
+				return;
+			}
+			if (	(c < '0') ||
+				(c < 'A' && c > '9') ||
+				(c > 'Z' && c < 'a') ||
+				(c > 'z')) {
+				if (isUnicode && c > 127) {
+					result.WriteByte ((byte)'%');
+					result.WriteByte ((byte)'u');
+					result.WriteByte ((byte)'0');
+					result.WriteByte ((byte)'0');
+				}
+				else
+					result.WriteByte ((byte)'%');
+				
+				int idx = ((int) c) >> 4;
+				result.WriteByte ((byte)hexChars [idx]);
+				idx = ((int) c) & 0x0F;
+				result.WriteByte ((byte)hexChars [idx]);
+			}
+			else
+				result.WriteByte ((byte)c);
+		}
+
+		internal static void UrlPathEncodeChar (char c, Stream result)
+		{
+			if (c < 33 || c > 126) {
+				byte [] bIn = Encoding.UTF8.GetBytes (c.ToString ());
+				for (int i = 0; i < bIn.Length; i++) {
+					result.WriteByte ((byte) '%');
+					int idx = ((int) bIn [i]) >> 4;
+					result.WriteByte ((byte) hexChars [idx]);
+					idx = ((int) bIn [i]) & 0x0F;
+					result.WriteByte ((byte) hexChars [idx]);
+				}
+			}
+			else if (c == ' ') {
+				result.WriteByte ((byte) '%');
+				result.WriteByte ((byte) '2');
+				result.WriteByte ((byte) '0');
+			}
+			else
+				result.WriteByte ((byte) c);
+		}
+		
+		static void InitEntities ()
+		{
+			// Build the hash table of HTML entity references.  This list comes
+			// from the HTML 4.01 W3C recommendation.
+			entities = new SortedDictionary <string, char> (StringComparer.Ordinal);
+			
+			entities.Add ("nbsp", '\u00A0');
+			entities.Add ("iexcl", '\u00A1');
+			entities.Add ("cent", '\u00A2');
+			entities.Add ("pound", '\u00A3');
+			entities.Add ("curren", '\u00A4');
+			entities.Add ("yen", '\u00A5');
+			entities.Add ("brvbar", '\u00A6');
+			entities.Add ("sect", '\u00A7');
+			entities.Add ("uml", '\u00A8');
+			entities.Add ("copy", '\u00A9');
+			entities.Add ("ordf", '\u00AA');
+			entities.Add ("laquo", '\u00AB');
+			entities.Add ("not", '\u00AC');
+			entities.Add ("shy", '\u00AD');
+			entities.Add ("reg", '\u00AE');
+			entities.Add ("macr", '\u00AF');
+			entities.Add ("deg", '\u00B0');
+			entities.Add ("plusmn", '\u00B1');
+			entities.Add ("sup2", '\u00B2');
+			entities.Add ("sup3", '\u00B3');
+			entities.Add ("acute", '\u00B4');
+			entities.Add ("micro", '\u00B5');
+			entities.Add ("para", '\u00B6');
+			entities.Add ("middot", '\u00B7');
+			entities.Add ("cedil", '\u00B8');
+			entities.Add ("sup1", '\u00B9');
+			entities.Add ("ordm", '\u00BA');
+			entities.Add ("raquo", '\u00BB');
+			entities.Add ("frac14", '\u00BC');
+			entities.Add ("frac12", '\u00BD');
+			entities.Add ("frac34", '\u00BE');
+			entities.Add ("iquest", '\u00BF');
+			entities.Add ("Agrave", '\u00C0');
+			entities.Add ("Aacute", '\u00C1');
+			entities.Add ("Acirc", '\u00C2');
+			entities.Add ("Atilde", '\u00C3');
+			entities.Add ("Auml", '\u00C4');
+			entities.Add ("Aring", '\u00C5');
+			entities.Add ("AElig", '\u00C6');
+			entities.Add ("Ccedil", '\u00C7');
+			entities.Add ("Egrave", '\u00C8');
+			entities.Add ("Eacute", '\u00C9');
+			entities.Add ("Ecirc", '\u00CA');
+			entities.Add ("Euml", '\u00CB');
+			entities.Add ("Igrave", '\u00CC');
+			entities.Add ("Iacute", '\u00CD');
+			entities.Add ("Icirc", '\u00CE');
+			entities.Add ("Iuml", '\u00CF');
+			entities.Add ("ETH", '\u00D0');
+			entities.Add ("Ntilde", '\u00D1');
+			entities.Add ("Ograve", '\u00D2');
+			entities.Add ("Oacute", '\u00D3');
+			entities.Add ("Ocirc", '\u00D4');
+			entities.Add ("Otilde", '\u00D5');
+			entities.Add ("Ouml", '\u00D6');
+			entities.Add ("times", '\u00D7');
+			entities.Add ("Oslash", '\u00D8');
+			entities.Add ("Ugrave", '\u00D9');
+			entities.Add ("Uacute", '\u00DA');
+			entities.Add ("Ucirc", '\u00DB');
+			entities.Add ("Uuml", '\u00DC');
+			entities.Add ("Yacute", '\u00DD');
+			entities.Add ("THORN", '\u00DE');
+			entities.Add ("szlig", '\u00DF');
+			entities.Add ("agrave", '\u00E0');
+			entities.Add ("aacute", '\u00E1');
+			entities.Add ("acirc", '\u00E2');
+			entities.Add ("atilde", '\u00E3');
+			entities.Add ("auml", '\u00E4');
+			entities.Add ("aring", '\u00E5');
+			entities.Add ("aelig", '\u00E6');
+			entities.Add ("ccedil", '\u00E7');
+			entities.Add ("egrave", '\u00E8');
+			entities.Add ("eacute", '\u00E9');
+			entities.Add ("ecirc", '\u00EA');
+			entities.Add ("euml", '\u00EB');
+			entities.Add ("igrave", '\u00EC');
+			entities.Add ("iacute", '\u00ED');
+			entities.Add ("icirc", '\u00EE');
+			entities.Add ("iuml", '\u00EF');
+			entities.Add ("eth", '\u00F0');
+			entities.Add ("ntilde", '\u00F1');
+			entities.Add ("ograve", '\u00F2');
+			entities.Add ("oacute", '\u00F3');
+			entities.Add ("ocirc", '\u00F4');
+			entities.Add ("otilde", '\u00F5');
+			entities.Add ("ouml", '\u00F6');
+			entities.Add ("divide", '\u00F7');
+			entities.Add ("oslash", '\u00F8');
+			entities.Add ("ugrave", '\u00F9');
+			entities.Add ("uacute", '\u00FA');
+			entities.Add ("ucirc", '\u00FB');
+			entities.Add ("uuml", '\u00FC');
+			entities.Add ("yacute", '\u00FD');
+			entities.Add ("thorn", '\u00FE');
+			entities.Add ("yuml", '\u00FF');
+			entities.Add ("fnof", '\u0192');
+			entities.Add ("Alpha", '\u0391');
+			entities.Add ("Beta", '\u0392');
+			entities.Add ("Gamma", '\u0393');
+			entities.Add ("Delta", '\u0394');
+			entities.Add ("Epsilon", '\u0395');
+			entities.Add ("Zeta", '\u0396');
+			entities.Add ("Eta", '\u0397');
+			entities.Add ("Theta", '\u0398');
+			entities.Add ("Iota", '\u0399');
+			entities.Add ("Kappa", '\u039A');
+			entities.Add ("Lambda", '\u039B');
+			entities.Add ("Mu", '\u039C');
+			entities.Add ("Nu", '\u039D');
+			entities.Add ("Xi", '\u039E');
+			entities.Add ("Omicron", '\u039F');
+			entities.Add ("Pi", '\u03A0');
+			entities.Add ("Rho", '\u03A1');
+			entities.Add ("Sigma", '\u03A3');
+			entities.Add ("Tau", '\u03A4');
+			entities.Add ("Upsilon", '\u03A5');
+			entities.Add ("Phi", '\u03A6');
+			entities.Add ("Chi", '\u03A7');
+			entities.Add ("Psi", '\u03A8');
+			entities.Add ("Omega", '\u03A9');
+			entities.Add ("alpha", '\u03B1');
+			entities.Add ("beta", '\u03B2');
+			entities.Add ("gamma", '\u03B3');
+			entities.Add ("delta", '\u03B4');
+			entities.Add ("epsilon", '\u03B5');
+			entities.Add ("zeta", '\u03B6');
+			entities.Add ("eta", '\u03B7');
+			entities.Add ("theta", '\u03B8');
+			entities.Add ("iota", '\u03B9');
+			entities.Add ("kappa", '\u03BA');
+			entities.Add ("lambda", '\u03BB');
+			entities.Add ("mu", '\u03BC');
+			entities.Add ("nu", '\u03BD');
+			entities.Add ("xi", '\u03BE');
+			entities.Add ("omicron", '\u03BF');
+			entities.Add ("pi", '\u03C0');
+			entities.Add ("rho", '\u03C1');
+			entities.Add ("sigmaf", '\u03C2');
+			entities.Add ("sigma", '\u03C3');
+			entities.Add ("tau", '\u03C4');
+			entities.Add ("upsilon", '\u03C5');
+			entities.Add ("phi", '\u03C6');
+			entities.Add ("chi", '\u03C7');
+			entities.Add ("psi", '\u03C8');
+			entities.Add ("omega", '\u03C9');
+			entities.Add ("thetasym", '\u03D1');
+			entities.Add ("upsih", '\u03D2');
+			entities.Add ("piv", '\u03D6');
+			entities.Add ("bull", '\u2022');
+			entities.Add ("hellip", '\u2026');
+			entities.Add ("prime", '\u2032');
+			entities.Add ("Prime", '\u2033');
+			entities.Add ("oline", '\u203E');
+			entities.Add ("frasl", '\u2044');
+			entities.Add ("weierp", '\u2118');
+			entities.Add ("image", '\u2111');
+			entities.Add ("real", '\u211C');
+			entities.Add ("trade", '\u2122');
+			entities.Add ("alefsym", '\u2135');
+			entities.Add ("larr", '\u2190');
+			entities.Add ("uarr", '\u2191');
+			entities.Add ("rarr", '\u2192');
+			entities.Add ("darr", '\u2193');
+			entities.Add ("harr", '\u2194');
+			entities.Add ("crarr", '\u21B5');
+			entities.Add ("lArr", '\u21D0');
+			entities.Add ("uArr", '\u21D1');
+			entities.Add ("rArr", '\u21D2');
+			entities.Add ("dArr", '\u21D3');
+			entities.Add ("hArr", '\u21D4');
+			entities.Add ("forall", '\u2200');
+			entities.Add ("part", '\u2202');
+			entities.Add ("exist", '\u2203');
+			entities.Add ("empty", '\u2205');
+			entities.Add ("nabla", '\u2207');
+			entities.Add ("isin", '\u2208');
+			entities.Add ("notin", '\u2209');
+			entities.Add ("ni", '\u220B');
+			entities.Add ("prod", '\u220F');
+			entities.Add ("sum", '\u2211');
+			entities.Add ("minus", '\u2212');
+			entities.Add ("lowast", '\u2217');
+			entities.Add ("radic", '\u221A');
+			entities.Add ("prop", '\u221D');
+			entities.Add ("infin", '\u221E');
+			entities.Add ("ang", '\u2220');
+			entities.Add ("and", '\u2227');
+			entities.Add ("or", '\u2228');
+			entities.Add ("cap", '\u2229');
+			entities.Add ("cup", '\u222A');
+			entities.Add ("int", '\u222B');
+			entities.Add ("there4", '\u2234');
+			entities.Add ("sim", '\u223C');
+			entities.Add ("cong", '\u2245');
+			entities.Add ("asymp", '\u2248');
+			entities.Add ("ne", '\u2260');
+			entities.Add ("equiv", '\u2261');
+			entities.Add ("le", '\u2264');
+			entities.Add ("ge", '\u2265');
+			entities.Add ("sub", '\u2282');
+			entities.Add ("sup", '\u2283');
+			entities.Add ("nsub", '\u2284');
+			entities.Add ("sube", '\u2286');
+			entities.Add ("supe", '\u2287');
+			entities.Add ("oplus", '\u2295');
+			entities.Add ("otimes", '\u2297');
+			entities.Add ("perp", '\u22A5');
+			entities.Add ("sdot", '\u22C5');
+			entities.Add ("lceil", '\u2308');
+			entities.Add ("rceil", '\u2309');
+			entities.Add ("lfloor", '\u230A');
+			entities.Add ("rfloor", '\u230B');
+			entities.Add ("lang", '\u2329');
+			entities.Add ("rang", '\u232A');
+			entities.Add ("loz", '\u25CA');
+			entities.Add ("spades", '\u2660');
+			entities.Add ("clubs", '\u2663');
+			entities.Add ("hearts", '\u2665');
+			entities.Add ("diams", '\u2666');
+			entities.Add ("quot", '\u0022');
+			entities.Add ("amp", '\u0026');
+			entities.Add ("lt", '\u003C');
+			entities.Add ("gt", '\u003E');
+			entities.Add ("OElig", '\u0152');
+			entities.Add ("oelig", '\u0153');
+			entities.Add ("Scaron", '\u0160');
+			entities.Add ("scaron", '\u0161');
+			entities.Add ("Yuml", '\u0178');
+			entities.Add ("circ", '\u02C6');
+			entities.Add ("tilde", '\u02DC');
+			entities.Add ("ensp", '\u2002');
+			entities.Add ("emsp", '\u2003');
+			entities.Add ("thinsp", '\u2009');
+			entities.Add ("zwnj", '\u200C');
+			entities.Add ("zwj", '\u200D');
+			entities.Add ("lrm", '\u200E');
+			entities.Add ("rlm", '\u200F');
+			entities.Add ("ndash", '\u2013');
+			entities.Add ("mdash", '\u2014');
+			entities.Add ("lsquo", '\u2018');
+			entities.Add ("rsquo", '\u2019');
+			entities.Add ("sbquo", '\u201A');
+			entities.Add ("ldquo", '\u201C');
+			entities.Add ("rdquo", '\u201D');
+			entities.Add ("bdquo", '\u201E');
+			entities.Add ("dagger", '\u2020');
+			entities.Add ("Dagger", '\u2021');
+			entities.Add ("permil", '\u2030');
+			entities.Add ("lsaquo", '\u2039');
+			entities.Add ("rsaquo", '\u203A');
+			entities.Add ("euro", '\u20AC');
+		}
+	}
+}

+ 8 - 0
Assets/UnityTool/System.Web.Util/HttpEncoder.cs.meta

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

+ 8 - 0
Assets/UnityTool/System.Web.meta

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

+ 714 - 0
Assets/UnityTool/System.Web/HttpUtility.cs

@@ -0,0 +1,714 @@
+// 
+// System.Web.HttpUtility
+//
+// Authors:
+//   Patrik Torstensson (Patrik.Torstensson@labs2.com)
+//   Wictor Wilén (decode/encode functions) (wictor@ibizkit.se)
+//   Tim Coleman (tim@timcoleman.com)
+//   Gonzalo Paniagua Javier (gonzalo@ximian.com)
+//
+// Copyright (C) 2005-2010 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+using System.Globalization;
+using System.IO;
+using System.Security.Permissions;
+using System.Text;
+using System.Web.Util;
+
+namespace System.Web {
+
+
+	public sealed class HttpUtility
+	{
+		sealed class HttpQSCollection : NameValueCollection
+		{
+			public override string ToString ()
+			{
+				int count = Count;
+				if (count == 0)
+					return "";
+				StringBuilder sb = new StringBuilder ();
+				string [] keys = AllKeys;
+				for (int i = 0; i < count; i++) {
+					sb.AppendFormat ("{0}={1}&", keys [i], this [keys [i]]);
+				}
+				if (sb.Length > 0)
+					sb.Length--;
+				return sb.ToString ();
+			}
+		}
+		
+		#region Constructors
+
+		public HttpUtility () 
+		{
+		}
+	
+		#endregion // Constructors
+	
+		#region Methods
+	
+		public static void HtmlAttributeEncode (string s, TextWriter output) 
+		{
+			if (output == null) {
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException (".NET emulation");
+#endif
+			}
+#if NET_4_0
+			HttpEncoder.Current.HtmlAttributeEncode (s, output);
+#else
+			output.Write (HttpEncoder.HtmlAttributeEncode (s));
+#endif
+		}
+	
+		public static string HtmlAttributeEncode (string s) 
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlAttributeEncode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlAttributeEncode (s);
+#endif
+		}
+	
+		public static string UrlDecode (string str) 
+		{
+			return UrlDecode(str, Encoding.UTF8);
+		}
+	
+		static char [] GetChars (MemoryStream b, Encoding e)
+		{
+			return e.GetChars (b.GetBuffer (), 0, (int) b.Length);
+		}
+
+		static void WriteCharBytes (IList buf, char ch, Encoding e)
+		{
+			if (ch > 255) {
+				foreach (byte b in e.GetBytes (new char[] { ch }))
+					buf.Add (b);
+			} else
+				buf.Add ((byte)ch);
+		}
+		
+		public static string UrlDecode (string s, Encoding e)
+		{
+			if (null == s) 
+				return null;
+
+			if (s.IndexOf ('%') == -1 && s.IndexOf ('+') == -1)
+				return s;
+			
+			if (e == null)
+				e = Encoding.UTF8;
+
+			long len = s.Length;
+			var bytes = new List <byte> ();
+			int xchar;
+			char ch;
+			
+			for (int i = 0; i < len; i++) {
+				ch = s [i];
+				if (ch == '%' && i + 2 < len && s [i + 1] != '%') {
+					if (s [i + 1] == 'u' && i + 5 < len) {
+						// unicode hex sequence
+						xchar = GetChar (s, i + 2, 4);
+						if (xchar != -1) {
+							WriteCharBytes (bytes, (char)xchar, e);
+							i += 5;
+						} else
+							WriteCharBytes (bytes, '%', e);
+					} else if ((xchar = GetChar (s, i + 1, 2)) != -1) {
+						WriteCharBytes (bytes, (char)xchar, e);
+						i += 2;
+					} else {
+						WriteCharBytes (bytes, '%', e);
+					}
+					continue;
+				}
+
+				if (ch == '+')
+					WriteCharBytes (bytes, ' ', e);
+				else
+					WriteCharBytes (bytes, ch, e);
+			}
+			
+			byte[] buf = bytes.ToArray ();
+			bytes = null;
+			return e.GetString (buf);
+			
+		}
+	
+		public static string UrlDecode (byte [] bytes, Encoding e)
+		{
+			if (bytes == null)
+				return null;
+
+			return UrlDecode (bytes, 0, bytes.Length, e);
+		}
+
+		static int GetInt (byte b)
+		{
+			char c = (char) b;
+			if (c >= '0' && c <= '9')
+				return c - '0';
+
+			if (c >= 'a' && c <= 'f')
+				return c - 'a' + 10;
+
+			if (c >= 'A' && c <= 'F')
+				return c - 'A' + 10;
+
+			return -1;
+		}
+
+		static int GetChar (byte [] bytes, int offset, int length)
+		{
+			int value = 0;
+			int end = length + offset;
+			for (int i = offset; i < end; i++) {
+				int current = GetInt (bytes [i]);
+				if (current == -1)
+					return -1;
+				value = (value << 4) + current;
+			}
+
+			return value;
+		}
+
+		static int GetChar (string str, int offset, int length)
+		{
+			int val = 0;
+			int end = length + offset;
+			for (int i = offset; i < end; i++) {
+				char c = str [i];
+				if (c > 127)
+					return -1;
+
+				int current = GetInt ((byte) c);
+				if (current == -1)
+					return -1;
+				val = (val << 4) + current;
+			}
+
+			return val;
+		}
+		
+		public static string UrlDecode (byte [] bytes, int offset, int count, Encoding e)
+		{
+			if (bytes == null)
+				return null;
+			if (count == 0)
+				return String.Empty;
+
+			if (bytes == null)
+				throw new ArgumentNullException ("bytes");
+
+			if (offset < 0 || offset > bytes.Length)
+				throw new ArgumentOutOfRangeException ("offset");
+
+			if (count < 0 || offset + count > bytes.Length)
+				throw new ArgumentOutOfRangeException ("count");
+
+			StringBuilder output = new StringBuilder ();
+			MemoryStream acc = new MemoryStream ();
+
+			int end = count + offset;
+			int xchar;
+			for (int i = offset; i < end; i++) {
+				if (bytes [i] == '%' && i + 2 < count && bytes [i + 1] != '%') {
+					if (bytes [i + 1] == (byte) 'u' && i + 5 < end) {
+						if (acc.Length > 0) {
+							output.Append (GetChars (acc, e));
+							acc.SetLength (0);
+						}
+						xchar = GetChar (bytes, i + 2, 4);
+						if (xchar != -1) {
+							output.Append ((char) xchar);
+							i += 5;
+							continue;
+						}
+					} else if ((xchar = GetChar (bytes, i + 1, 2)) != -1) {
+						acc.WriteByte ((byte) xchar);
+						i += 2;
+						continue;
+					}
+				}
+
+				if (acc.Length > 0) {
+					output.Append (GetChars (acc, e));
+					acc.SetLength (0);
+				}
+
+				if (bytes [i] == '+') {
+					output.Append (' ');
+				} else {
+					output.Append ((char) bytes [i]);
+				}
+			}
+
+			if (acc.Length > 0) {
+				output.Append (GetChars (acc, e));
+			}
+			
+			acc = null;
+			return output.ToString ();
+		}
+	
+		public static byte [] UrlDecodeToBytes (byte [] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			return UrlDecodeToBytes (bytes, 0, bytes.Length);
+		}
+
+		public static byte [] UrlDecodeToBytes (string str)
+		{
+			return UrlDecodeToBytes (str, Encoding.UTF8);
+		}
+
+		public static byte [] UrlDecodeToBytes (string str, Encoding e)
+		{
+			if (str == null)
+				return null;
+
+			if (e == null)
+				throw new ArgumentNullException ("e");
+
+			return UrlDecodeToBytes (e.GetBytes (str));
+		}
+
+		public static byte [] UrlDecodeToBytes (byte [] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+			if (count == 0)
+				return new byte [0];
+
+			int len = bytes.Length;
+			if (offset < 0 || offset >= len)
+				throw new ArgumentOutOfRangeException("offset");
+
+			if (count < 0 || offset > len - count)
+				throw new ArgumentOutOfRangeException("count");
+
+			MemoryStream result = new MemoryStream ();
+			int end = offset + count;
+			for (int i = offset; i < end; i++){
+				char c = (char) bytes [i];
+				if (c == '+') {
+					c = ' ';
+				} else if (c == '%' && i < end - 2) {
+					int xchar = GetChar (bytes, i + 1, 2);
+					if (xchar != -1) {
+						c = (char) xchar;
+						i += 2;
+					}
+				}
+				result.WriteByte ((byte) c);
+			}
+
+			return result.ToArray ();
+		}
+
+		public static string UrlEncode(string str) 
+		{
+			return UrlEncode(str, Encoding.UTF8);
+		}
+	
+		public static string UrlEncode (string s, Encoding Enc) 
+		{
+			if (s == null)
+				return null;
+
+			if (s == String.Empty)
+				return String.Empty;
+
+			bool needEncode = false;
+			int len = s.Length;
+			for (int i = 0; i < len; i++) {
+				char c = s [i];
+				if ((c < '0') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a') || (c > 'z')) {
+					if (HttpEncoder.NotEncoded (c))
+						continue;
+
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return s;
+
+			// avoided GetByteCount call
+			byte [] bytes = new byte[Enc.GetMaxByteCount(s.Length)];
+			int realLen = Enc.GetBytes (s, 0, s.Length, bytes, 0);
+			return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, realLen));
+		}
+	  
+		public static string UrlEncode (byte [] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return String.Empty;
+
+			return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, 0, bytes.Length));
+		}
+
+		public static string UrlEncode (byte [] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return String.Empty;
+
+			return Encoding.ASCII.GetString (UrlEncodeToBytes (bytes, offset, count));
+		}
+
+		public static byte [] UrlEncodeToBytes (string str)
+		{
+			return UrlEncodeToBytes (str, Encoding.UTF8);
+		}
+
+		public static byte [] UrlEncodeToBytes (string str, Encoding e)
+		{
+			if (str == null)
+				return null;
+
+			if (str.Length == 0)
+				return new byte [0];
+
+			byte [] bytes = e.GetBytes (str);
+			return UrlEncodeToBytes (bytes, 0, bytes.Length);
+		}
+
+		public static byte [] UrlEncodeToBytes (byte [] bytes)
+		{
+			if (bytes == null)
+				return null;
+
+			if (bytes.Length == 0)
+				return new byte [0];
+
+			return UrlEncodeToBytes (bytes, 0, bytes.Length);
+		}
+
+		public static byte [] UrlEncodeToBytes (byte [] bytes, int offset, int count)
+		{
+			if (bytes == null)
+				return null;
+#if NET_4_0
+			return HttpEncoder.Current.UrlEncode (bytes, offset, count);
+#else
+			return HttpEncoder.UrlEncodeToBytes (bytes, offset, count);
+#endif
+		}
+
+		public static string UrlEncodeUnicode (string str)
+		{
+			if (str == null)
+				return null;
+
+			return Encoding.ASCII.GetString (UrlEncodeUnicodeToBytes (str));
+		}
+
+		public static byte [] UrlEncodeUnicodeToBytes (string str)
+		{
+			if (str == null)
+				return null;
+
+			if (str.Length == 0)
+				return new byte [0];
+
+			MemoryStream result = new MemoryStream (str.Length);
+			foreach (char c in str){
+				HttpEncoder.UrlEncodeChar (c, result, true);
+			}
+			return result.ToArray ();
+		}
+
+		/// <summary>
+		/// Decodes an HTML-encoded string and returns the decoded string.
+		/// </summary>
+		/// <param name="s">The HTML string to decode. </param>
+		/// <returns>The decoded text.</returns>
+		public static string HtmlDecode (string s) 
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlDecode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlDecode (s);
+#endif
+		}
+	
+		/// <summary>
+		/// Decodes an HTML-encoded string and sends the resulting output to a TextWriter output stream.
+		/// </summary>
+		/// <param name="s">The HTML string to decode</param>
+		/// <param name="output">The TextWriter output stream containing the decoded string. </param>
+		public static void HtmlDecode(string s, TextWriter output) 
+		{
+			if (output == null) {
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException (".NET emulation");
+#endif
+			}
+				
+			if (!String.IsNullOrEmpty (s)) {
+#if NET_4_0
+				HttpEncoder.Current.HtmlDecode (s, output);
+#else
+				output.Write (HttpEncoder.HtmlDecode (s));
+#endif
+			}
+		}
+
+		public static string HtmlEncode (string s)
+		{
+#if NET_4_0
+			if (s == null)
+				return null;
+			
+			using (var sw = new StringWriter ()) {
+				HttpEncoder.Current.HtmlEncode (s, sw);
+				return sw.ToString ();
+			}
+#else
+			return HttpEncoder.HtmlEncode (s);
+#endif
+		}
+		
+		/// <summary>
+		/// HTML-encodes a string and sends the resulting output to a TextWriter output stream.
+		/// </summary>
+		/// <param name="s">The string to encode. </param>
+		/// <param name="output">The TextWriter output stream containing the encoded string. </param>
+		public static void HtmlEncode(string s, TextWriter output) 
+		{
+			if (output == null) {
+#if NET_4_0
+				throw new ArgumentNullException ("output");
+#else
+				throw new NullReferenceException (".NET emulation");
+#endif
+			}
+				
+			if (!String.IsNullOrEmpty (s)) {
+#if NET_4_0
+				HttpEncoder.Current.HtmlEncode (s, output);
+#else
+				output.Write (HttpEncoder.HtmlEncode (s));
+#endif
+			}
+		}
+#if NET_4_0
+		public static string HtmlEncode (object value)
+		{
+			if (value == null)
+				return null;
+
+#if !MOBILE
+			IHtmlString htmlString = value as IHtmlString;
+			if (htmlString != null)
+				return htmlString.ToHtmlString ();
+#endif
+
+			return HtmlEncode (value.ToString ());
+		}
+
+		public static string JavaScriptStringEncode (string value)
+		{
+			return JavaScriptStringEncode (value, false);
+		}
+
+		public static string JavaScriptStringEncode (string value, bool addDoubleQuotes)
+		{
+			if (String.IsNullOrEmpty (value))
+				return addDoubleQuotes ? "\"\"" : String.Empty;
+
+			int len = value.Length;
+			bool needEncode = false;
+			char c;
+			for (int i = 0; i < len; i++) {
+				c = value [i];
+
+				if (c >= 0 && c <= 31 || c == 34 || c == 39 || c == 60 || c == 62 || c == 92) {
+					needEncode = true;
+					break;
+				}
+			}
+
+			if (!needEncode)
+				return addDoubleQuotes ? "\"" + value + "\"" : value;
+
+			var sb = new StringBuilder ();
+			if (addDoubleQuotes)
+				sb.Append ('"');
+
+			for (int i = 0; i < len; i++) {
+				c = value [i];
+				if (c >= 0 && c <= 7 || c == 11 || c >= 14 && c <= 31 || c == 39 || c == 60 || c == 62)
+					sb.AppendFormat ("\\u{0:x4}", (int)c);
+				else switch ((int)c) {
+						case 8:
+							sb.Append ("\\b");
+							break;
+
+						case 9:
+							sb.Append ("\\t");
+							break;
+
+						case 10:
+							sb.Append ("\\n");
+							break;
+
+						case 12:
+							sb.Append ("\\f");
+							break;
+
+						case 13:
+							sb.Append ("\\r");
+							break;
+
+						case 34:
+							sb.Append ("\\\"");
+							break;
+
+						case 92:
+							sb.Append ("\\\\");
+							break;
+
+						default:
+							sb.Append (c);
+							break;
+					}
+			}
+
+			if (addDoubleQuotes)
+				sb.Append ('"');
+
+			return sb.ToString ();
+		}
+#endif
+		public static string UrlPathEncode (string s)
+		{
+#if NET_4_0
+			return HttpEncoder.Current.UrlPathEncode (s);
+#else
+			return HttpEncoder.UrlPathEncode (s);
+#endif
+		}
+
+		public static NameValueCollection ParseQueryString (string query)
+		{
+			return ParseQueryString (query, Encoding.UTF8);
+		}
+
+		public static NameValueCollection ParseQueryString (string query, Encoding encoding)
+		{
+			if (query == null)
+				throw new ArgumentNullException ("query");
+			if (encoding == null)
+				throw new ArgumentNullException ("encoding");
+			if (query.Length == 0 || (query.Length == 1 && query[0] == '?'))
+				return new HttpQSCollection ();
+			if (query[0] == '?')
+				query = query.Substring (1);
+				
+			NameValueCollection result = new HttpQSCollection ();
+			ParseQueryString (query, encoding, result);
+			return result;
+		}
+
+		internal static void ParseQueryString (string query, Encoding encoding, NameValueCollection result)
+		{
+			if (query.Length == 0)
+				return;
+
+			string decoded = HtmlDecode (query);
+			int decodedLength = decoded.Length;
+			int namePos = 0;
+			bool first = true;
+			while (namePos <= decodedLength) {
+				int valuePos = -1, valueEnd = -1;
+				for (int q = namePos; q < decodedLength; q++) {
+					if (valuePos == -1 && decoded [q] == '=') {
+						valuePos = q + 1;
+					} else if (decoded [q] == '&') {
+						valueEnd = q;
+						break;
+					}
+				}
+
+				if (first) {
+					first = false;
+					if (decoded [namePos] == '?')
+						namePos++;
+				}
+				
+				string name, value;
+				if (valuePos == -1) {
+					name = null;
+					valuePos = namePos;
+				} else {
+					name = UrlDecode (decoded.Substring (namePos, valuePos - namePos - 1), encoding);
+				}
+				if (valueEnd < 0) {
+					namePos = -1;
+					valueEnd = decoded.Length;
+				} else {
+					namePos = valueEnd + 1;
+				}
+				value = UrlDecode (decoded.Substring (valuePos, valueEnd - valuePos), encoding);
+
+				result.Add (name, value);
+				if (namePos == -1)
+					break;
+			}
+		}
+		#endregion // Methods
+	}
+}
+

+ 8 - 0
Assets/UnityTool/System.Web/HttpUtility.cs.meta

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

+ 207 - 0
Assets/UnityTool/TimerMgr.cs

@@ -0,0 +1,207 @@
+using System.Collections.Generic;
+using UnityEngine;
+using System;
+
+namespace XRTool.Util
+{
+    public delegate void TimerHandler();
+
+    public delegate void TimerArgsHandler(object[] args);
+
+    public class Timer
+    {
+        public TimerHandler Handler;           //无参的委托
+        public TimerArgsHandler ArgsHandler;   //带参数的委托
+        public float Frequency;               //时间间隔
+        public int Repeats;                   //重复次数
+        public object[] Args;
+
+        public float LastTickTime;
+
+        public event Action OnComplete;        //计时器完成一次工作
+        public event Action OnDestroy;        //计时器被销毁
+        public event Action OnFinsh;        //计时器结束工作了
+        public Timer() { }
+
+        /// <summary>
+        /// 创建一个时间事件对象
+        /// </summary>
+        /// <param name="Handler">回调函数</param>
+        /// <param name="ArgsHandler">带参数的回调函数</param>
+        /// <param name="frequency">时间内执行</param>
+        /// <param name="repeats">重复次数</param>
+        /// <param name="Args">参数  可以任意的传不定数量,类型的参数</param>
+        public Timer(TimerHandler Handler, TimerArgsHandler ArgsHandler, float frequency, int repeats, object[] Args)
+        {
+            this.Handler = Handler;
+            this.ArgsHandler = ArgsHandler;
+            this.Frequency = frequency;
+            this.Repeats = repeats == 0 ? 1 : repeats;
+            this.Args = Args;
+            this.LastTickTime = Time.time;
+        }
+
+        public void Notify()
+        {
+            Handler?.Invoke();
+            ArgsHandler?.Invoke(Args);
+            OnComplete?.Invoke();
+        }
+        /// <summary>
+        /// 清理计时器,初始化参数  同时清理事件
+        /// </summary>
+        public void CleanUp()
+        {
+            Handler = null;
+            ArgsHandler = null;
+            Repeats = 1;
+            Frequency = 0;
+            OnDestroy?.Invoke();
+            OnFinsh?.Invoke();
+            OnDestroy = null;
+            OnComplete = null;
+        }
+        /// <summary>
+        /// 立即执行回调
+        /// isBreak = false的时候需要根据是否继续执行,传time
+        /// isBreak = true,可不传time
+        /// </summary>
+        /// <param name="time">当前的时间,Time.time</param>
+        /// <param name="isBreak">执行完之后是否销毁计时器</param>
+        public void AwakeNow(float time = 0, bool isBreak = true)
+        {
+            try
+            {
+                ///唤醒可能会有异常
+                Notify();
+            }
+            catch (Exception ex)
+            {
+                UnityLog.LogException(ex);
+                UnityLog.LogError(ex.ToString());
+            }
+            finally
+            {
+                if (isBreak)
+                {
+                    OnFinsh?.Invoke();
+                    TimerMgr.Instance.DestroyTimer(this);
+                }
+                else
+                {
+                    if ((--Repeats) == 0)
+                    {
+                        OnFinsh?.Invoke();
+                        TimerMgr.Instance.DestroyTimer(this);
+                    }
+                    else
+                    {
+                        LastTickTime = time;
+                    }
+                }
+            }
+        }
+        /// <summary>
+        /// 根据当前时间判断是否要触发触发器
+        /// </summary>
+        /// <param name="time"></param>
+        public void Update(float time)
+        {
+            if (Frequency + LastTickTime <= time)
+            {
+                AwakeNow(time, false);
+            }
+        }
+    }
+
+    /// <summary>
+    /// 计时器
+    /// 添加一个计时事件
+    /// 删除一个计时事件
+    /// 更新计时事件
+    /// </summary>
+    public class TimerMgr : UnitySingleton<TimerMgr>
+    {
+        private List<Timer> _Timers;//时间管理器
+        protected override void Awake()
+        {
+            DontDestroyOnLoad(gameObject);
+            if (_Timers == null)
+            {
+                _Timers = new List<Timer>();
+            }
+            base.Awake();
+        }
+        /// <summary>
+        /// 创建一个简单的计时器
+        /// </summary>
+        /// <param name="callBack">回调函数</param>
+        /// <param name="time">计时器时间</param>
+        /// <param name="repeats">回调次数  小于0代表循环 大于0代表repeats次</param>
+        public Timer CreateTimer(TimerHandler callBack, float time, int repeats = 1)
+        {
+            return Create(callBack, null, time, repeats);
+        }
+
+        public Timer CreateTimer(TimerArgsHandler callBack, float time, int repeats, params object[] args)
+        {
+            return Create(null, callBack, time, repeats, args);
+        }
+
+        private Timer Create(TimerHandler callBack, TimerArgsHandler callBackArgs, float time, int repeats, params object[] args)
+        {
+            Timer timer = new Timer(callBack, callBackArgs, time, repeats, args);
+            _Timers.Add(timer);
+            return timer;
+        }
+
+        public Timer DestroyTimer(Timer timer)
+        {
+            if (timer != null)
+            {
+                _Timers.Remove(timer);
+                timer.CleanUp();
+                timer = null;
+            }
+            return timer;
+        }
+        /// <summary>
+        /// 禁止调用此函数
+        /// </summary>
+        public void ClearAll()
+        {
+            if (_Timers != null)
+            {
+                for (int i = 0; i < _Timers.Count; i++)
+                {
+                    _Timers[i].CleanUp();
+                }
+                _Timers.Clear();
+            }
+        }
+        /// <summary>
+        /// 固定更新检查更新的频率
+        /// </summary>
+        private void Update()
+        {
+            if (_Timers.Count != 0)
+            {
+                for (int i = _Timers.Count - 1; i >= 0 && i < _Timers.Count; i--)
+                {
+                    _Timers[i].Update(Time.time);
+                }
+            }
+        }
+
+        //private void OnEnable()
+        //{
+        //    ScenceMain.MainUpdateEvent += MainUpdate;
+
+        //}
+        //private void OnDisable()
+        //{
+        //    ScenceMain.MainUpdateEvent -= MainUpdate;
+
+        //}
+    }
+}

+ 11 - 0
Assets/UnityTool/TimerMgr.cs.meta

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

+ 309 - 0
Assets/UnityTool/UnityLog.cs

@@ -0,0 +1,309 @@
+using Newtonsoft.Json;
+using System;
+using System.IO;
+using System.Text;
+using UnityEngine;
+namespace XRTool.Util
+{
+    public enum LogLevel
+    {
+        NO = 0,
+        Low = 1,
+        Middle = 2,
+        High = 3,
+        Max = 4
+    }
+    /// <summary>
+    /// 日志输出,请勿使用Debug或者Print等自带的日志
+    /// 日志分级,普通日志,错误日志,异常日志
+    /// debug模式可以输出普通日志,其他日志必输出
+    /// 通过配置参数实现不同的日志等级
+    /// 为了避免大量日志输出,采用优化方案写入日志
+    /// </summary>
+    public static class UnityLog
+    {
+        private static string logBuilder;
+        private static FileStream logStream;
+        private static FileStream errorStream;
+        private static FileStream exceptStream;
+        public static event Action<string> MessageReceived;
+        /// <summary>
+        /// 在编辑器中是否输出日志文件
+        /// </summary>
+        public static bool isOutLogEditor = true;
+        /// <summary>
+        /// 日志等级,默认为1,正式发布版本为0
+        /// 等级越高代表可输出的日志越多
+        /// </summary>
+        public static int logLevel = 1;
+        public const string NULL = "null";
+        private static bool isFristLog = true;
+        private static bool isFristLogError = true;
+        private static bool isFristLogExcept = true;
+        private static string logPath;
+        public static FileStream LogStream
+        {
+            get
+            {
+                if (logStream == null)
+                {
+                    logStream = new FileStream(Path.Combine(LogPath, "log.txt"), FileMode.Append);
+                }
+                return logStream;
+            }
+        }
+        public static FileStream ErrorStream
+        {
+            get
+            {
+                if (errorStream == null)
+                {
+                    errorStream = new FileStream(Path.Combine(LogPath, "error.txt"), FileMode.Append);
+                }
+                return errorStream;
+            }
+        }
+        public static FileStream ExceptStream
+        {
+            get
+            {
+                if (exceptStream == null)
+                {
+                    exceptStream = new FileStream(Path.Combine(LogPath, "except.txt"), FileMode.Append);
+                }
+                return exceptStream;
+            }
+        }
+
+        public static string LogPath { get => logPath; set => logPath = value; }
+
+        static UnityLog()
+        {
+            /*
+            if (BuildConfigMgr.Instance.IsInit) { }*/
+            //LogPath = Path.Combine(BuildConfig.Instance.UserPath, "LogData");
+            LogPath = Path.Combine(Application.persistentDataPath, "LogData");
+            if (!Directory.Exists(LogPath))
+            {
+                Directory.CreateDirectory(LogPath);
+            }
+            else
+            {
+                ///缓存文件最大只留10M,超过10M后,清除日志
+                DirectoryInfo di = new DirectoryInfo(LogPath);
+                long len = 0;
+                foreach (FileInfo item in di.GetFiles())
+                {
+                    len += item.Length;
+                }
+                if (len > 10 * UnityUtil.MB)
+                {
+                    Directory.Delete(LogPath, true);
+                }
+                Directory.CreateDirectory(LogPath);
+            }
+            Application.logMessageReceived += LogMessageReceived;
+
+            //InitLog();
+        }
+        /// <summary>
+        /// 接受系统日志
+        /// </summary>
+        /// <param name="condition"></param>
+        /// <param name="stackTrace"></param>
+        /// <param name="type"></param>
+        private static void LogMessageReceived(string condition, string stackTrace, LogType type)
+        {
+            if (!isOutLogEditor)
+            {
+                return;
+            }
+            logBuilder = null;
+            FileStream fileStream = null;
+            if (string.IsNullOrEmpty(condition) && string.IsNullOrEmpty(stackTrace))
+            {
+                return;
+            }
+            bool isWriteFrist = false;
+#if UNITY_EDITOR || !BUILDTYPE_RELEASE //Release  
+            if (type == LogType.Log)
+            {
+                ///日志等级大于0时才会开启日志
+                if (logLevel >= 1)
+                {
+                    fileStream = LogStream;
+                }
+                if (isFristLog)
+                {
+                    isWriteFrist = true;
+                    isFristLog = false;
+                }
+            }
+#endif
+            if (type == LogType.Exception)
+            {
+                fileStream = ExceptStream;
+                if (isFristLogExcept)
+                {
+                    isWriteFrist = true;
+                    isFristLogExcept = false;
+                }
+            }
+            else if (type == LogType.Error)
+            {
+                fileStream = ErrorStream;
+                if (isFristLogError)
+                {
+                    isWriteFrist = true;
+                    isFristLogError = false;
+                }
+            }
+            if (fileStream != null)
+            {
+                DateTime time = DateTime.Now;
+                logBuilder = time + ": " + condition + stackTrace + "\n";
+                MessageReceived?.Invoke(logBuilder);
+                if (isWriteFrist)
+                {
+                    /*
+                    if (BuildConfigMgr.Instance.IsInit)
+                    {
+                        ReleaseLog("\n----------Version Log------------\n" +
+                            Application.productName + "_" + Application.version + "_" + JsonConvert.SerializeObject(BuildConfig.Instance) + "\n",
+                            fileStream);
+                    }*/
+                }
+                ReleaseLog(logBuilder, fileStream);
+                fileStream.Flush();
+            }
+            fileStream = null;
+            logBuilder = null;
+        }
+
+        /// <summary>
+        /// 释放资源
+        /// </summary>
+        public static void ReleaseLog()
+        {
+            Application.logMessageReceived -= LogMessageReceived;
+            if (logStream != null)
+            {
+                logStream.Close();
+            }
+            if (errorStream != null)
+            {
+                errorStream.Close();
+            }
+            if (exceptStream != null)
+            {
+                exceptStream.Close();
+            }
+            logStream = null;
+            errorStream = null;
+            exceptStream = null;
+        }
+        public static void Log(object log, int level = 1)
+        {
+            //Log(log != null ? log.ToString() : "null", logLevel);
+            ///如果是编辑器模式或者非商用APP版本,可以打日志文件
+#if UNITY_EDITOR || !BuildType_RELEASE //Release
+            bool isForce = false;
+#if UNITY_EDITOR
+            isForce = logLevel >= 4;
+#endif
+            if (isForce || level <= logLevel)
+            {
+                Debug.Log(log != null ? log.ToString() : NULL);
+            }
+#endif
+        }
+        /// <summary>
+        /// 正常的日志输出
+        /// </summary>
+        public static void Log(string log, int level = 1)
+        {
+            ///如果是编辑器模式或者非商用APP版本,可以打日志文件
+#if UNITY_EDITOR || !BuildType_RELEASE //Release
+            bool isForce = false;
+#if UNITY_EDITOR
+            isForce = logLevel >= 4;
+#endif
+            if (isForce || level <= logLevel)
+            {
+                Debug.Log(log);
+            }
+#endif
+        }
+
+
+
+        /// <summary>
+        /// 错误日志输出
+        /// </summary>
+        public static void LogError(string log, int logLevel = 1)
+        {
+            ///错误日志任何模式都会输出
+            Debug.Log(log);
+        }
+        /// <summary>
+        /// 错误日志输出
+        /// </summary>
+        public static void LogException(Exception ex, int level = 1)
+        {
+            ///异常日志由系统自动输出
+            Debug.LogException(ex);
+        }
+        /// <summary>
+        /// 日志输出,替换对应的日志文件
+        /// </summary>
+        public static void Log(string log, LogType logType, int logLevel = 1)
+        {
+            if (logType == LogType.Log)
+            {
+                Log(log, logLevel);
+            }
+
+            else if (logType == LogType.Error)
+            {
+                LogError(log, logLevel);
+            }
+        }
+
+        /// <summary>
+        /// 释放资源
+        /// </summary>
+        public static void ReleaseLog(string msg, FileStream stream)
+        {
+            if (!string.IsNullOrEmpty(msg))
+            {
+                WriteLogToFile(msg, stream);
+            }
+        }
+
+        /// <summary>
+        /// 将日志写入到文件中
+        /// </summary>
+        /// <param name="log"></param>
+        /// <param name="logType"></param>
+        public static void WriteLogToFile(string log, FileStream stream)
+        {
+            if (stream != null)
+            {
+                ///UTF8的编码格式转化成byte字节流
+                byte[] buttf = Encoding.Default.GetBytes(log);
+                stream.Write(buttf, 0, log.Length);
+            }
+        }
+
+        public static void ClearAllLog()
+        {
+            ReleaseLog();
+            if (Directory.Exists(LogPath))
+            {
+                Directory.Delete(LogPath, true);
+            }
+            Directory.CreateDirectory(LogPath);
+            //InitLog(FileMode.Create);
+        }
+    }
+}

+ 11 - 0
Assets/UnityTool/UnityLog.cs.meta

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

+ 91 - 0
Assets/UnityTool/UnitySingleton.cs

@@ -0,0 +1,91 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License. See LICENSE in the project root for license information.
+
+using System;
+using UnityEngine;
+
+namespace XRTool.Util
+{
+    /// <summary>
+    /// Unity的单例
+    /// Singleton behaviour class, used for components that should only have one instance
+    /// 
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public abstract class UnitySingleton<T> : MonoBehaviour where T : UnitySingleton<T>
+    {
+        public static event Action InitComplte;
+        public static event Action DeleteSingle;
+        private static T instance;
+        public static T Instance
+        {
+            get
+            {
+                try
+                {
+                    return instance;
+
+                }
+                catch
+                {
+                    return null;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Returns whether the instance has been initialized or not.
+        /// </summary>
+        public static bool IsInitialized
+        {
+            get
+            {
+                return instance != null;
+            }
+        }
+
+        /// <summary>
+        /// 强制实例化某对象
+        /// 注意,尽量避免在多处使用或者在awake中使用,避免产生多个实例化多项
+        /// </summary>
+        public static T ForceInstance()
+        {
+            if (!instance)
+            {
+                GameObject obj = new GameObject();
+                instance= obj.AddComponent<T>();
+            }
+            return instance;
+        }
+
+        /// <summary>
+        /// Base awake method that sets the singleton's unique instance.
+        /// </summary>
+        protected virtual void Awake()
+        {
+            if (instance != null && instance.gameObject != gameObject)
+            {
+                Debug.LogErrorFormat("{0}为单例对象,但是场景中存在多个{0},已删除本对象", GetType().Name);
+                Destroy(gameObject);
+            }
+            else
+            {
+                DeleteSingle = null;
+                instance = (T)this;
+                InitComplte?.Invoke();
+            }
+        }
+        /// <summary>
+        /// 对象被销毁时的事件传递
+        /// </summary>
+        protected virtual void OnDestroy()
+        {
+            if (instance == this)
+            {
+                instance = null;
+                DeleteSingle?.Invoke();
+            }
+            InitComplte = null;
+        }
+    }
+}

+ 11 - 0
Assets/UnityTool/UnitySingleton.cs.meta

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

+ 1074 - 0
Assets/UnityTool/UnityUtil.cs

@@ -0,0 +1,1074 @@
+using NPinyin;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+using UnityEngine;
+using UnityEngine.Networking;
+using UnityEngine.Video;
+
+namespace XRTool.Util
+{
+    /// <summary>
+    /// 工具类,各种常用算法的集合脚本
+    /// </summary>
+    public static class UnityUtil
+    {
+        /*
+        public const int B = 1;
+        public const int KB = 1024;
+        public const int MB = 1024 * 1024;
+        public const long GB = 1024 * 1024 * 1024;*/
+        public const int B = 1;
+        public const int KB = 1000;
+        public const int MB = 1000 * 1000;
+        public const long GB = 1000 * 1000 * 1000;
+        public const string BString = "B";
+        public const string KBString = "KB";
+        public const string MBString = "MB";
+        public const string GBString = "GB";
+        /// <summary>
+        /// 全局唯一id
+        /// 自动自增
+        /// </summary>
+        private static int unicode = 10000000;
+#if UNITY_EDITOR
+        /// <summary>
+        /// 尝试得到一个未命名的名称
+        /// 下标从0开始检索,如果不存在此名字的文字,则返回此名字
+        /// 如果存在,下标++
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="path"></param>
+        /// <param name="suffix"></param>
+        /// <returns></returns>
+        public static string TryGetName<T>(string path, string suffix = ".asset")
+        {
+            int index = 0;
+            string confName = "";
+            UnityEngine.Object obj = null;
+            do
+            {
+                confName = path + "/" + typeof(T).Name + "_" + index + suffix;
+                obj = AssetDatabase.LoadAssetAtPath(confName, typeof(T));
+                index++;
+            } while (obj);
+            return confName;
+        }
+        public static string TryGetName(Type T, string path, string suffix = ".asset")
+        {
+            int index = 0;
+            string confName = "";
+            UnityEngine.Object obj = null;
+            do
+            {
+                confName = path + "/" + T.Name + "_" + index + suffix;
+                obj = AssetDatabase.LoadAssetAtPath(confName, T);
+                index++;
+            } while (obj);
+            return confName;
+        }
+#endif
+        /// <summary>
+        /// 获取指定名称类型的对象
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="childName"></param>
+        /// <returns></returns>
+        public static T GetChild<T>(Transform target, string childName)
+        {
+            var child = target.Find(childName);
+            if (child)
+            {
+                return child.GetComponent<T>();
+            }
+            return default(T);
+        }
+        /// <summary>
+        /// 深度优先搜索查找子物体
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="childName"></param>
+        /// <returns></returns>
+        public static T GetDepthChild<T>(Transform transform, string childName)
+        {
+            Transform target = FindDepthTransf(transform, childName);
+            if (target)
+                return GetT<T>(target.gameObject);
+            return default(T);
+        }
+        public static GameObject GetDepthChild(Transform transform, string childName)
+        {
+            Transform target = FindDepthTransf(transform, childName);
+            if (target)
+                return target.gameObject;
+            return null;
+        }
+        /// <summary>
+        /// 广度优先查找子物体
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="childName"></param>
+        /// <returns></returns>
+        public static T GetBreadthChild<T>(Transform transform, string childName)
+        {
+            Transform target = FindBreadthTransf(transform, childName);
+            if (target)
+                return GetT<T>(target.gameObject);
+            return default(T);
+        }
+        public static GameObject GetBreadthChild(Transform transform, string childName)
+        {
+            Transform target = FindBreadthTransf(transform, childName);
+            if (target)
+                return target.gameObject;
+            return null;
+        }
+        public static T GetParent<T>(Transform transform)
+        {
+            return transform.GetComponentInParent<T>();
+        }
+        public static T GetChild<T>(Transform trans)
+        {
+            return trans.GetComponentInChildren<T>();
+        }
+        public static T GetT<T>(GameObject target)
+        {
+            return target.GetComponent<T>();
+        }
+        /// <summary>
+        /// 深度优先检索子物体
+        /// </summary>
+        /// <param name="check"></param>
+        /// <param name="childName"></param>
+        /// <returns></returns>
+        public static Transform FindDepthTransf(Transform check, string childName)
+        {
+            if (check.name == childName) return check;
+            for (int i = 0; i < check.childCount; i++)
+            {
+                Transform obj = FindDepthTransf(check.GetChild(i), childName);
+                if (obj)
+                    return obj;
+            }
+            return null;
+        }
+
+        /// <summary>
+        /// 广度优先检索子物体
+        /// </summary>
+        /// <param name="check"></param>
+        /// <param name="childName"></param>
+        /// <returns></returns>
+        public static Transform FindBreadthTransf(Transform check, string childName)
+        {
+            Transform forreturn = check.Find(childName);
+            if (forreturn)
+            {
+                return forreturn;
+            }
+            if (check.childCount > 0)
+            {
+                for (int i = 0; i < check.childCount; i++)
+                {
+                    var target = FindBreadthTransf(check.GetChild(i), childName);
+                    if (target)
+                    {
+                        return target;
+                    }
+                }
+            }
+            return forreturn;
+        }
+        public static void SetParent(Transform parent, Transform child)
+        {
+            child.SetParent(parent);
+            child.localPosition = Vector3.zero;
+            child.localRotation = Quaternion.identity;
+            child.localScale = Vector3.one;
+        }
+        /// <summary>
+                /// 去除文件bom头后的字符
+                /// </summary>
+                /// <param name="buffer"></param>
+                /// <returns></returns>
+        public static string GetUTF8String(byte[] buffer)
+        {
+            if (buffer == null)
+                return null;
+
+            if (buffer.Length <= 3)
+            {
+                return Encoding.UTF8.GetString(buffer);
+            }
+
+            byte[] bomBuffer = new byte[] { 0xef, 0xbb, 0xbf };
+
+            if (buffer[0] == bomBuffer[0]
+              && buffer[1] == bomBuffer[1]
+              && buffer[2] == bomBuffer[2])
+            {
+                return new UTF8Encoding(false).GetString(buffer, 3, buffer.Length - 3);
+            }
+
+            return Encoding.UTF8.GetString(buffer);
+        }
+        /// <summary>
+        /// 获取距离放歌最近的数字
+        /// 四舍五入
+        /// </summary>
+        /// <param name="num"></param>
+        /// <param name="cell"></param>
+        /// <returns></returns>
+        public static float GetNearst(float num, float cell)
+        {
+            int dir = num < 0 ? -1 : 1;
+            return ((int)(num + cell / 2 * dir) / (int)cell) * cell;
+        }
+        /// <summary>
+        /// 判断两个矩形是否相交
+        /// 如果两个矩形中心点在x、y轴的投影距离分别小于矩形的边长之和,则此矩形相交
+        /// </summary>
+        /// <param name="a"></param>
+        /// <param name="b"></param>
+        /// <returns></returns>
+        public static bool IsCrossLine(Rect a, Rect b)
+        {
+            Vector2 dis = b.center - a.center;
+            if (((int)a.width + (int)b.width) / 2 > Math.Abs(dis.x) && ((int)a.height + (int)b.height) / 2 > Math.Abs(dis.y))
+            {
+                return true;
+            }
+            return false;
+        }
+        public static void ChangeMateColor(Renderer render, Color color, string name = "_Color")
+        {
+            if (render)
+            {
+                MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetColor(name, color);
+                render.SetPropertyBlock(propertyBlock);
+                //ChangeMateValue(render, propertyBlock);
+                propertyBlock = null;
+            }
+        }
+        public static void ChangeMateColor(MaterialPropertyBlock propertyBlock, Renderer render, Color color, string name = "_Color")
+        {
+            if (render)
+            {
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetColor(name, color);
+                render.SetPropertyBlock(propertyBlock);
+                //ChangeMateValue(render, propertyBlock);
+                //propertyBlock = null;
+            }
+        }
+        public static void ChangeMateTexture2D(Renderer render, Texture2D img, string name = "_MainTex")
+        {
+            if (render)
+            {
+                MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetTexture(name, img);
+                render.SetPropertyBlock(propertyBlock);
+                propertyBlock = null;
+            }
+        }
+        public static void ChangeMateVideo(GameObject obj, VideoClip video, string name = "_MainTex")
+        {
+            if (obj)
+            {
+                VideoPlayer vp = obj.GetComponent<VideoPlayer>();
+                vp.clip = video;
+            }
+        }
+        public static void ChangeMateTexture(Renderer render, Texture img, string name = "_MainTex")
+        {
+            if (render)
+            {
+                MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetTexture(name, img);
+                render.SetPropertyBlock(propertyBlock);
+                propertyBlock = null;
+            }
+        }
+        public static void ChangeMateValue(Renderer render, float att, string name = "_Smoothness")
+        {
+            if (render)
+            {
+                MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetFloat(name, att);
+                render.SetPropertyBlock(propertyBlock);
+                //ChangeMateValue(render, propertyBlock);
+                propertyBlock = null;
+            }
+        }
+        public static void ChangeMateValue(Renderer render, Vector4 att, string name = "_Smoothness")
+        {
+            if (render)
+            {
+                MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                propertyBlock.SetVector(name, att);
+                render.SetPropertyBlock(propertyBlock);
+                //ChangeMateValue(render, propertyBlock);
+                propertyBlock = null;
+            }
+        }
+        public static void ChangeMateValue(Renderer render, MaterialPropertyBlock propertyBlock)
+        {
+            if (render)
+            {
+                //MaterialPropertyBlock propertyBlock = new MaterialPropertyBlock();
+                render.GetPropertyBlock(propertyBlock);
+                //propertyBlock.SetVector(name, att);
+                render.SetPropertyBlock(propertyBlock);
+            }
+        }
+        /// <summary>
+        /// 材质复制
+        /// </summary>
+        /// <param name="resMate"></param>
+        /// <param name="targetMate"></param>
+        public static void CopyMate(Material resMate, Material targetMate)
+        {
+            if (resMate && resMate != targetMate)
+            {
+                resMate.shader = targetMate.shader;
+                resMate.CopyPropertiesFromMaterial(targetMate);
+            }
+        }
+        ///// <summary>
+        ///// 
+        ///// </summary>
+        ///// <returns></returns>
+        //public static string ArtTransferInfo(ArtInfo info)
+        //{
+        //    Vector3 pos = GameSession.Instance.GetHeadForwadPos(info.Distance);
+        //    if (GameNode.Instance)
+        //    {
+        //        pos = GameNode.Instance.transform.InverseTransformPoint(pos);
+        //    }
+        //    var angle = Vector3.zero;
+        //    var scale = Vector3.one * info.Size;
+        //    return TransferToString(pos, angle, scale, 2);
+        //}
+        public static string TransferToString(Transform tranfer, int state)
+        {
+            return TransferToString(tranfer.localPosition, tranfer.localEulerAngles, tranfer.localScale, state);
+        }
+        public static int maxTransfer = 1000;
+        public static string TransferToString(Vector3 pos, Vector3 ang, Vector3 sca, int state)
+        {
+            string info = "";
+            pos *= maxTransfer;
+            ang *= maxTransfer;
+            sca *= maxTransfer;
+            string position = (int)(pos.x) + "," + (int)(pos.y) + "," + (int)(pos.z);
+            string angle = (int)(ang.x) + "," + (int)(ang.y) + "," + (int)(ang.z);
+            string scale = (int)(sca.x) + "," + (int)(sca.y) + "," + (int)(sca.z);
+            info = position + "|" + angle + "|" + scale;
+            //if (state == 2)
+            //{
+            //    info = pos + "|" + angle + "|" + scale;
+            //}
+            //else if (state == 1)
+            //{
+            //    info = pos + "|" + angle;
+            //}
+            //else if (state == 1)
+            //{
+            //    info = pos;
+            //}
+            return info;
+        }
+        //public static Posture GetPosture(Transform info)
+        //{
+        //    Posture posture = new Posture();
+        //    posture.position = info.localPosition;
+        //    posture.angle = info.localEulerAngles;
+        //    posture.scale = info.localScale;
+        //    posture.count = 2;
+        //    return posture;
+        //}
+        //public static void SetPosture(Transform info, Posture posture, float time = -1)
+        //{
+        //    if (time <= 0)
+        //    {
+        //        info.localPosition = posture.position;
+        //        info.localEulerAngles = posture.angle;
+        //        info.localScale = posture.scale;
+        //    }
+        //    else
+        //    {
+        //        info.DOKill();
+        //        if (posture.count >= 0)
+        //        {
+        //            info.DOLocalMove(posture.position, time);
+        //        }
+        //        if (posture.count >= 1)
+        //        {
+        //            info.DOLocalRotate(posture.angle, time);
+        //        }
+        //        if (posture.count >= 2)
+        //        {
+        //            info.DOScale(posture.scale, time);
+        //        }
+        //    }
+        //}
+        //public static Posture GetPosture(string info)
+        //{
+        //    Posture posture = new Posture();
+        //    string[] arr = info.Split('|');
+        //    for (int i = 0; i < arr.Length; i++)
+        //    {
+        //        if (string.IsNullOrEmpty(arr[i]))
+        //        {
+        //            continue;
+        //        }
+        //        string[] v = arr[i].Split(',');
+        //        Vector3 vector = Vector3.zero;
+        //        vector.x = float.Parse(v[0]);
+        //        vector.y = float.Parse(v[1]);
+        //        vector.z = float.Parse(v[2]);
+        //        //for (int j = 0; j < v.Length; j++)
+        //        //{
+        //        //    float value = float.Parse(v[j]);
+        //        //    if (j == 0)
+        //        //    {
+        //        //        vector.x = value;
+        //        //    }
+        //        //    else if (j == 1)
+        //        //    {
+        //        //        vector.y = value;
+        //        //    }
+        //        //    else if (j == 2)
+        //        //    {
+        //        //        vector.z = value;
+        //        //    }
+        //        //}
+        //        vector /= maxTransfer;
+        //        if (i == 0)
+        //        {
+        //            posture.position = vector;
+        //        }
+        //        else if (i == 1)
+        //        {
+        //            posture.angle = vector;
+        //        }
+        //        else if (i == 2)
+        //        {
+        //            posture.scale = vector;
+        //        }
+        //        posture.count = i;
+        //    }
+
+        //    return posture;
+        //}
+        //public static Posture GetPosture(string info)
+        //{
+        //    Posture posture = new Posture();
+        //    string[] arr = info.Split('|');
+        //    for (int i = 0; i < arr.Length; i++)
+        //    {
+        //        if (string.IsNullOrEmpty(arr[i]))
+        //        {
+        //            continue;
+        //        }
+        //        string[] v = arr[i].Split(',');
+        //        Vector3 vector = Vector3.zero;
+        //        for (int j = 0; j < v.Length; j++)
+        //        {
+        //            float value = float.Parse(v[j]);
+        //            if (j == 0)
+        //            {
+        //                vector.x = value;
+        //            }
+        //            else if (j == 1)
+        //            {
+        //                vector.y = value;
+        //            }
+        //            else if (j == 2)
+        //            {
+        //                vector.z = value;
+        //            }
+        //        }
+        //        vector *= maxTransfer;
+        //        if (i == 0)
+        //        {
+        //            posture.position = vector;
+        //        }
+        //        else if (i == 1)
+        //        {
+        //            posture.angle = vector;
+        //        }
+        //        else if (i == 2)
+        //        {
+        //            posture.scale = vector;
+        //        }
+        //        posture.count = i;
+        //    }
+
+        //    return posture;
+        //}
+        public static Vector3 StringToVector3(string v)
+        {
+            Vector3 z = Vector3.zero;
+            v = v.Replace("(", "").Replace(")", "");
+            string[] s = v.Split(',');
+            if (s.Length > 2)
+            {
+                z.x = float.Parse(s[0]);
+                z.y = float.Parse(s[1]);
+                z.z = float.Parse(s[2]);
+                z /= maxTransfer;
+            }
+            return z;
+        }
+        public static string Vector3ToString(Vector3 v)
+        {
+            return v.ToString();
+        }
+        public static string QuaterToString(Quaternion q)
+        {
+            q.x *= maxTransfer;
+            q.y *= maxTransfer;
+            q.z *= maxTransfer;
+            q.w *= maxTransfer;
+            return q.ToString();
+        }
+        public static Quaternion StringToQuater(string v)
+        {
+            Quaternion q = Quaternion.identity;
+            v = v.Replace("(", "").Replace(")", "");
+            string[] s = v.Split(',');
+            if (s.Length > 3)
+            {
+                q.x = float.Parse(s[0]) / maxTransfer;
+                q.y = float.Parse(s[1]) / maxTransfer;
+                q.z = float.Parse(s[2]) / maxTransfer;
+                q.w = float.Parse(s[3]) / maxTransfer;
+            }
+            return q;
+        }
+        public static Vector3 RealForward(Transform body)
+        {
+            Vector3 right = body.right;
+            right.y = 0;
+            return Vector3.Cross(right, Vector3.up);
+        }
+        public static string CurTimeString
+        {
+            get { return DateTime.Now.ToString("MMddHHmmssf"); }
+        }
+        /// <summary>
+        /// 通过时间生成一个绝对的唯一的id
+        /// 此id的生成有可能存在重复,如果存在同时的调用方式时
+        /// </summary>
+        public static string TimeID
+        {
+            get { return DateTime.Now.ToString("HHmmssfffff"); }
+        }
+        /// <summary>
+        /// 全局唯一id
+        /// </summary>
+        public static int Unicode
+        {
+            get
+            {
+                return ++unicode;
+            }
+        }
+        /// <summary>
+        /// 从URl下载指定的资源
+        /// </summary>
+        /// <param name="url">资源的地址,可以是网络路径,也可以是本地文件路径</param>
+        /// <param name="updateProcess">下载的进度,当前已下载文件大小,以及进度</param>
+        /// <param name="complete"></param>
+        /// <param name="form">请求的参数,如果为空代表Get请求,不为空代表Post请求</param>
+        /// <returns></returns>
+        public static IEnumerator RequestDownData(string url, Action<string, UnityWebRequest> complete, DownloadHandler hander = null, Action<float, float> updateProcess = null, WWWForm form = null)
+        {
+            UnityWebRequest web;
+            Debug.Log("RequestDownData" + url);
+
+            if (form == null)
+            {
+                web = UnityWebRequest.Get(url);
+            }
+            else
+            {
+                web = UnityWebRequest.Post(url, form);
+            }
+            if (hander != null)
+            {
+                web.downloadHandler = hander;
+            }
+            web.SendWebRequest();
+            while (!web.isDone)
+            {
+                updateProcess?.Invoke(web.downloadedBytes, web.downloadProgress);
+                yield return 0;
+            }
+            if (web.isDone)
+            {
+                updateProcess?.Invoke(web.downloadedBytes, 1);
+            }
+            if (web.isNetworkError || web.isHttpError)
+            {
+                complete?.Invoke(web.error, web);
+                Debug.LogError(web.error + url);
+            }
+            else
+            {
+                complete?.Invoke(null, web);
+            }
+            web.Dispose();
+        }
+        /// <summary>
+        /// 拷贝文件
+        /// </summary>
+        /// <param name="SourcePath"></param>
+        /// <param name="DestinationPath"></param>
+        /// <param name="overwriteexisting">是否覆盖</param>
+        /// <returns></returns>
+        public static bool CopyDirectory(string SourcePath, string DestinationPath, bool overwriteexisting)
+        {
+            bool ret = false;
+            try
+            {
+                SourcePath = SourcePath.EndsWith(@"\") ? SourcePath : SourcePath + @"\";
+                DestinationPath = DestinationPath.EndsWith(@"\") ? DestinationPath : DestinationPath + @"\";
+
+                if (Directory.Exists(SourcePath))
+                {
+                    if (Directory.Exists(DestinationPath) == false)
+                        Directory.CreateDirectory(DestinationPath);
+
+                    foreach (string fls in Directory.GetFiles(SourcePath))
+                    {
+                        FileInfo flinfo = new FileInfo(fls);
+                        flinfo.CopyTo(DestinationPath + flinfo.Name, overwriteexisting);
+                        UnityEngine.Debug.Log(flinfo.CreationTime.ToString());
+                    }
+                    foreach (string drs in Directory.GetDirectories(SourcePath))
+                    {
+                        DirectoryInfo drinfo = new DirectoryInfo(drs);
+                        if (CopyDirectory(drs, DestinationPath + drinfo.Name, overwriteexisting) == false)
+                            ret = false;
+                    }
+                }
+                ret = true;
+            }
+            catch (Exception ex)
+            {
+                ret = false;
+                UnityLog.LogError(ex.ToString());
+            }
+            return ret;
+        }
+        /// <summary>
+        /// 广度优先,遍历文件
+        /// </summary>
+        /// <param name="path"></param>
+        /// <param name="callBack"></param>
+        public static void FindFileBreadth(string path, Action<string> callBack)
+        {
+            try
+            {
+                DirectoryInfo di = new DirectoryInfo(path);
+                FileInfo[] fis = di.GetFiles();
+                for (int i = 0; i < fis.Length; i++)
+                {
+                    callBack?.Invoke(fis[i].FullName);
+                }
+                DirectoryInfo[] dis = di.GetDirectories();
+                for (int j = 0; j < dis.Length; j++)
+                {
+                    FindFileBreadth(dis[j].FullName, callBack);
+                }
+            }
+            catch (Exception ex)
+            {
+                UnityLog.LogError(ex.ToString());
+            }
+        }
+        /// <summary>
+        /// 深度优先,遍历文件
+        /// </summary>
+        /// <param name="dir"></param>
+        public static void FindFileByDepth(string dir, Action<string> callBack)
+        {
+            try
+            {
+                DirectoryInfo d = new DirectoryInfo(dir);
+                FileSystemInfo[] fsinfos = d.GetFileSystemInfos();
+                foreach (FileSystemInfo fsinfo in fsinfos)
+                {
+                    if (fsinfo is DirectoryInfo)
+                    {
+                        FindFileByDepth(fsinfo.FullName, callBack);
+                    }
+                    else
+                    {
+                        callBack?.Invoke(fsinfo.FullName);
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                UnityLog.LogError(ex.ToString());
+            }
+        }
+        /// <summary>
+        /// 获取文件MD5值
+        /// </summary>
+        /// <param name="fileName">文件绝对路径</param>
+        /// <returns>MD5值</returns>
+        public static string GetMD5HashFromFile(string fileName)
+        {
+            try
+            {
+                FileStream file = new FileStream(fileName, FileMode.Open);
+                System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider();
+                byte[] retVal = md5.ComputeHash(file);
+                file.Close();
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < retVal.Length; i++)
+                {
+                    sb.Append(retVal[i].ToString("x2"));
+                }
+                return sb.ToString();
+            }
+            catch (Exception ex)
+            {
+                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
+            }
+        }
+        /// <summary>
+        /// 重命名文件
+        /// </summary>
+        /// <param name="file"></param>
+        /// <param name="newFile"></param>
+        public static void ReNameFile(string file, string newFile)
+        {
+            if (File.Exists(file))
+            {
+                try
+                {
+                    string dir = Path.GetDirectoryName(newFile);
+                    if (!Directory.Exists(dir))
+                    {
+                        Directory.CreateDirectory(dir);
+                    }
+                    if (File.Exists(newFile))
+                    {
+                        File.Delete(newFile);
+                    }
+                    FileInfo info = new FileInfo(file);
+                    info.MoveTo(newFile);
+                }
+                catch (Exception ex)
+                {
+                    UnityLog.LogError(file + " is error" + ex.ToString());
+                }
+            }
+        }
+        /// <summary>
+        /// 删除文件
+        /// </summary>
+        /// <param name="file"></param>
+        /// <param name="newFile"></param>
+        public static void DelFile(string file)
+        {
+            UnityLog.Log(file + " is Del", 3);
+            if (File.Exists(file))
+            {
+                try
+                {
+                    File.Delete(file);
+                }
+                catch (Exception ex)
+                {
+                    UnityLog.LogError(file + " is error" + ex.ToString());
+                }
+            }
+        }
+        public static string AutoDateTrans(long bytes, int count = 2)
+        {
+            if (bytes >= GB)
+            {
+                return ByteToGB(bytes, count);
+            }
+            else if (bytes >= MB)
+            {
+                return ByteToMB(bytes, count);
+            }
+            else if (bytes >= KB)
+            {
+                return ByteToKB(bytes, count);
+            }
+            return ByteToB(bytes, count);
+        }
+        public static string ByteToB(long bytes, int count = 2)
+        {
+            return TransNUM(bytes, B, BString, count);
+        }
+        public static string ByteToKB(long bytes, int count = 2)
+        {
+            return TransNUM(bytes, KB, KBString, count);
+        }
+        public static string ByteToMB(long bytes, int count = 2)
+        {
+            return TransNUM(bytes, MB, MBString, count);
+        }
+        public static string ByteToGB(long bytes, int count = 2)
+        {
+            return TransNUM(bytes, GB, GBString, count);
+        }
+        public static string TransNUM(long bytes, long jinzhi, string houzui = "", int count = 2)
+        {
+            float num = bytes * 1f / jinzhi;
+            return num.ToString("f" + count) + houzui;
+        }
+        public static Sprite CreateSpriteByData(byte[] data)
+        {
+            Texture2D tex = new Texture2D(64, 64);
+            tex.LoadImage(data);
+            return Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
+        }
+        public static Texture2D CreateTextureByData(byte[] data)
+        {
+        //    Debug.Log("CreateTextureByData====>"+data.Length);
+            Texture2D tex = new Texture2D(32, 32);
+            tex.LoadImage(data);
+            return tex;
+        }
+        /// <summary>
+        /// 获取URL对应的名称,可以作为文件主键的数据
+        /// </summary>
+        /// <param name="url"></param>
+        /// <returns></returns>
+        public static string GetUrlName(string url)
+        {
+            string name = Regex.Replace(url, @"[^a-zA-Z0-9\u4e00-\u9fa5\s]", "");
+            return name.Replace(" ", "_");
+        }
+        /// <summary>
+        /// 获取url对应的本地路径
+        /// </summary>
+        /// <param name="url"></param>
+        /// <returns></returns>
+        public static string GetFilePath(string url, int count = 2)
+        {
+            var p = url.Split('?');
+            if (p.Length > 1)
+            {
+                url = p[p.Length - 2];
+            }
+            else
+            {
+                url = p[0];
+            }
+            string[] arr = url.Split('/');
+            string path = url;
+            if (arr.Length > count)
+            {
+                path = "";
+                //maxLen = 30;
+                for (int i = arr.Length - count; i < arr.Length; i++)
+                {
+                    if (i != arr.Length - 1)
+                    {
+                        string strAfter = Regex.Replace(arr[i], @"[^a-zA-Z0-9\u4e00-\u9fa5\s]", "");
+                        if (strAfter.Length > maxLen)
+                        {
+                            strAfter = strAfter.Substring(strAfter.Length - maxLen, maxLen);
+                        }
+                        path += strAfter + "/";
+                    }
+                    else
+                    {
+                        string strAfter = Regex.Replace(arr[i], @"[^a-zA-Z0-9_.\u4e00-\u9fa5\s]", "");
+                        if (strAfter.Length > maxLen)
+                        {
+                            strAfter = strAfter.Substring(strAfter.Length - maxLen, maxLen);
+                        }
+                        path += strAfter;
+                    }
+                }
+            }
+            return path;
+        }
+        public static string GetVideoTime(long time)
+        {
+            string timeStr;
+            if (time < 60)
+            {
+                timeStr = string.Format("00:00:{0:00}", time % 60);
+            }
+            else if (time < 3600)
+            {
+                timeStr = string.Format("00:{0:00}:", time / 60) + string.Format("{0:00}", time % 60);
+            }
+            else
+            {
+                timeStr = string.Format("{0:00}:", time / 3600) + string.Format("{0:00}:", (time % 3600) / 60) + string.Format("{0:00}", time % 60);
+            }
+            return timeStr;
+        }
+        public static void WriteFile(string path, byte[] bytes)
+        {
+            string dir = Path.GetDirectoryName(path);
+            if (!Directory.Exists(dir))
+            {
+                Directory.CreateDirectory(dir);
+            }
+            using (FileStream stream = new FileStream(path, FileMode.OpenOrCreate))
+            {
+                stream.Write(bytes, 0, bytes.Length);
+                stream.Flush();
+                stream.Close();
+                stream.Dispose();
+            }
+        }
+        /// <summary>
+        /// 汉字转化为拼音
+        /// </summary>
+        /// <param name="str">汉字</param>
+        /// <returns>全拼</returns>
+        public static string GetPinyin(string str)
+        {
+            var result = "";
+            if (!string.IsNullOrEmpty(str))
+            {
+                result = Pinyin.GetPinyin(str)?.Replace(" ", "").ToLower();
+            }
+            return result;
+        }
+
+        /// <summary>
+        /// 汉字转化为拼音首字母
+        /// </summary>
+        /// <param name="str">汉字</param>
+        /// <returns>首字母</returns>
+        public static string GetInitials(string str)
+        {
+            var result = "";
+            if (!string.IsNullOrEmpty(str))
+            {
+                result = Pinyin.GetInitials(str)?.Trim().ToLower();
+            }
+            return result;
+        }
+        /// <summary>
+        /// 控制一组对象的显示或者隐藏
+        /// </summary>
+        /// <param name="list">对象组</param>
+        /// <param name="isShow">是否显示或者隐藏</param>
+        /// <param name="isForce">是否强制</param>
+        /// <param name="exits">排除对象组中的数据</param>
+        public static void ControlChildActive(List<GameObject> list, bool isShow, bool isForce = false, params GameObject[] exits)
+        {
+            if (list != null)
+            {
+                List<GameObject> others = list;
+                if (exits != null)
+                {
+                    if (isForce)
+                    {
+                        for (int i = 0; i < exits.Length; i++)
+                        {
+                            if (exits[i].activeSelf == isShow)
+                            {
+                                exits[i].SetActive(!isShow);
+                            }
+                        }
+                    }
+                    others = list.Except(exits).ToList();
+                }
+                for (int i = 0; i < others.Count; i++)
+                {
+                    if (others[i].activeSelf != isShow)
+                    {
+                        others[i].SetActive(isShow);
+                    }
+                }
+            }
+        }
+        // 时间戳转为C#格式时间
+        public static DateTime SpanToDateTime(string timeSpan)
+        {
+            long lTime = long.Parse(timeSpan);
+            return SpanToDateTime(lTime);
+        }
+        // 时间戳转为C#格式时间
+        public static DateTime SpanToDateTime(long timeSpan)
+        {
+            DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
+            return dateTimeStart.AddSeconds(timeSpan);
+            /*
+            DateTime dateTimeStart = TimeZone.CurrentTimeZone.ToUniversalTime(new DateTime(1970, 1, 1));
+            TimeSpan toNow = new TimeSpan(timeSpan);
+            return dateTimeStart.Add(toNow);*/
+        }
+
+        // DateTime时间格式转换为Unix时间戳格式
+        public static long DateTimeToSpan(DateTime time)
+        {
+            DateTime startTime = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
+            return (long)((time - startTime).TotalSeconds);
+        }
+        public static string[] dayOfWeek = new string[] { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
+        private static int maxLen = 30;
+
+        public static string GetDateTimeMsg(DateTime date)
+        {/*
+            if (LanguageMgr.Instance.LanIndex == 0)
+            {*/
+                return date.ToString("yyyy年MM月dd日") + dayOfWeek[(int)date.DayOfWeek];
+                /*
+            }
+            else
+            {
+                return date.ToString("ddd, dd MMM yyyy", new System.Globalization.CultureInfo("en-US"));
+            }*/
+        }
+
+
+
+        /// <summary>
+        /// 获取游戏对象的路径
+        /// </summary>
+        /// <param name="obj"></param>
+        /// <returns></returns>
+        public static string GetGameObjectPath(Transform obj)
+        {
+            if (obj != null)
+            {
+                string path = obj.name;
+                Transform temp = obj;
+                while (temp.parent!=null)
+                {
+                    temp = temp.parent;
+                    path = temp.name + "/" + path;
+                }
+                return path;
+            }
+            else
+            {
+                Debug.LogError("GetGameObjectPath==>obj=null");
+                return default;
+            }
+        }
+    }
+}

+ 11 - 0
Assets/UnityTool/UnityUtil.cs.meta

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

+ 94 - 0
Assets/UnityTool/XColor.cs

@@ -0,0 +1,94 @@
+using UnityEngine;
+
+namespace PublicTools.Unity
+{
+    public struct XColor
+    {
+        //
+        // 摘要:
+        //     Red component of the color.
+        public float r;
+        //
+        // 摘要:
+        //     Green component of the color.
+        public float g;
+        //
+        // 摘要:
+        //     Blue component of the color.
+        public float b;
+        //
+        // 摘要:
+        //     Alpha component of the color (0 is transparent, 1 is opaque).
+        public float a;
+        //
+        // 摘要:
+        //     Constructs a new Color with given r,g,b components and sets a to 1.
+        //
+        // 参数:
+        //   r:
+        //     Red component.
+        //
+        //   g:
+        //     Green component.
+        //
+        //   b:
+        //     Blue component.
+        public XColor(float r, float g, float b)
+        {
+            this.r = r;
+            this.g = g;
+            this.b = b;
+            this.a = 1;
+        }
+        //
+        // 摘要:
+        //     Constructs a new Color with given r,g,b,a components.
+        //
+        // 参数:
+        //   r:
+        //     Red component.
+        //
+        //   g:
+        //     Green component.
+        //
+        //   b:
+        //     Blue component.
+        //
+        //   a:
+        //     Alpha component.
+        public XColor(float r, float g, float b, float a)
+        {
+            this.r = r;
+            this.g = g;
+            this.b = b;
+            this.a = a;
+        }
+        public XColor(Color color)
+        {
+            this.r = color.r;
+            this.g = color.g;
+            this.b = color.b;
+            this.a = color.a;
+        }
+        public Color Trans()
+        {
+            Color color = Color.black;
+            color.r = this.r;
+            color.g = this.g;
+            color.b = this.b;
+            color.a = this.a;
+            return color;
+        }
+        public void Trans(Color color)
+        {
+            this.r = color.r;
+            this.g = color.g;
+            this.b = color.b;
+            this.a = color.a;
+        }
+        //public override string ToString()
+        //{
+        //    return JsonConvert.SerializeObject(this);
+        //}
+    }
+}

+ 11 - 0
Assets/UnityTool/XColor.cs.meta

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

+ 52 - 0
Assets/UnityTool/XVector2.cs

@@ -0,0 +1,52 @@
+//using Newtonsoft.Json;
+using UnityEngine;
+
+namespace PublicTools.Unity
+{
+    public struct XVector2
+    {
+        //
+        // 摘要:
+        //     X component of the vector.
+        public float x;
+        //
+        // 摘要:
+        //     Y component of the vector.
+        public float y;
+        //
+        // 摘要:
+        //     Constructs a new vector with given x, y components.
+        //
+        // 参数:
+        //   x:
+        //
+        //   y:
+        public XVector2(float x, float y)
+        {
+            this.x = x;
+            this.y = y;
+        }
+        public XVector2(Vector2 vector2)
+        {
+            this.x = vector2.x;
+            this.y = vector2.y;
+        }
+
+        public Vector2 Trans()
+        {
+            Vector2 vector = Vector2.zero;
+            vector.x = this.x;
+            vector.y = this.y;
+            return vector;
+        }
+        public void Trans(Vector2 vector2)
+        {
+            this.x = vector2.x;
+            this.y = vector2.y;
+        }
+        //public override string ToString()
+        //{
+        //    return JsonConvert.SerializeObject(this);
+        //}
+    }
+}

+ 11 - 0
Assets/UnityTool/XVector2.cs.meta

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

+ 52 - 0
Assets/UnityTool/XVector3.cs

@@ -0,0 +1,52 @@
+using System;
+using UnityEngine;
+
+namespace PublicTools.Unity
+{
+    public struct XVector3
+    {
+        //
+        // 摘要:
+        //     X component of the vector.
+        public float x;
+        //
+        // 摘要:
+        //     Y component of the vector.
+        public float y;
+        //
+        // 摘要:
+        //     Z component of the vector.
+        public float z;
+        public XVector3(float x, float y, float z)
+        {
+            this.x = x;
+            this.y = y;
+            this.z = z;
+        }
+        public XVector3(Vector3 vector3)
+        {
+            this.x = vector3.x;
+            this.y = vector3.y;
+            this.z = vector3.z;
+        }
+        public XVector3(Vector3 vector3, int count)
+        {
+            this.x = (float)Math.Round(vector3.x, count);
+            this.y = (float)Math.Round(vector3.y, count);
+            this.z = (float)Math.Round(vector3.z, count);
+        }
+
+        public Vector3 Trans()
+        {
+            Vector3 vector = Vector3.zero;
+            vector.x = this.x;
+            vector.y = this.y;
+            vector.z = this.z;
+            return vector;
+        }
+        //public override string ToString()
+        //{
+        //    return JsonConvert.SerializeObject(this);
+        //}
+    }
+}

+ 11 - 0
Assets/UnityTool/XVector3.cs.meta

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

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