zoukankan      html  css  js  c++  java
  • 随记

    using System.Collections.Generic;
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    
    public class PackEditor : EditorWindow
    {
        [MenuItem("Window/发布 _F4")]
        static void PackagerWindow()
        {
            luaFilesPath = Application.dataPath + "/GameLua";
            luaZipPath = Application.streamingAssetsPath + "/lua.zip";
            PackEditor packagerEditor = (PackEditor)EditorWindow.GetWindow(typeof(PackEditor), false, "发布", true);
            packagerEditor.minSize = new Vector2(300, 220);
            packagerEditor.maxSize = new Vector2(300, 220);
            packagerEditor.Show();
        }
    
        public void OnGUI()
        {
            buildTarget = (BuildTarget)EditorGUI.EnumPopup(new Rect(80, 10, 150, 20), buildTarget);
            if (GUI.Button(new Rect(80, 50, 150, 20), "设置保存位置"))
            {
                fabuPath = EditorUtility.SaveFilePanel("文件保存路径", "c", Application.productName, JudgePlatform());
            }
            if (GUI.Button(new Rect(80, 90, 150, 20), "开始打包"))
            {
                MyBuild();
            }
            GUI.TextArea(new Rect(10, 120, 280, 90), "当前保存位置:" + fabuPath);
        }
    
        string JudgePlatform()
        {
            if (buildTarget == BuildTarget.Android)
                return "apk";
            else if (buildTarget == BuildTarget.StandaloneWindows64)
                return "exe";
            else if (buildTarget == BuildTarget.WebGL)
                return "htm";
            return "apk";
        }
    
        static string luaFilesPath = string.Empty;
        static string luaZipPath = string.Empty;
        static BuildTarget buildTarget = BuildTarget.Android;
        static string fabuPath = string.Empty;
        static void MyBuild()
        {
            if (!string.IsNullOrEmpty(fabuPath))
            {
                EditorBuildSettingsScene[] sceneArray = EditorBuildSettings.scenes;
                if (sceneArray != null && sceneArray.Length > 0)
                {
                    List<string> outScenes = new List<string>();
                    for (int i = 0; i < sceneArray.Length; i++)
                    {
                        if (sceneArray[i].enabled)
                            outScenes.Add(sceneArray[i].path);
                    }
                    if (outScenes.Count > 0)
                    {
                        GenerateZip(luaFilesPath);
                        AssetDatabase.Refresh();
                        BuildPipeline.BuildPlayer(outScenes.ToArray(), fabuPath, buildTarget, BuildOptions.None);
                        AssetDatabase.Refresh();
                        System.Diagnostics.Process.Start(Path.GetDirectoryName(fabuPath));
                    }
                }
            }
        }
    
        static void GenerateZip(string _orignalFloder)
        {
            allFiles = new List<string>();
            GetAllFiles(_orignalFloder);
            if (File.Exists(luaZipPath))
                File.Delete(luaZipPath);
            AssetDatabase.Refresh();
            CSharpUtils.CompressFiles(luaZipPath, allFiles, _orignalFloder.LastIndexOf('/') + 1, "");
        }
    
        static List<string> allFiles = null;
        public static void GetAllFiles(string path)
        {
            string[] dir = Directory.GetDirectories(path);
            DirectoryInfo fdir = new DirectoryInfo(path);
            FileInfo[] file = fdir.GetFiles();
            if (file.Length != 0 || dir.Length != 0)
            {
                foreach (FileInfo f in file)
                {
                    if (!f.FullName.Contains(".meta"))
                        allFiles.Add(f.FullName);
                }
                foreach (string d in dir)
                {
                    GetAllFiles(d);//递归   
                }
            }
        }
    }
    PackEditor
    using System.Collections;
    using System.Collections.Generic;
    using UnityEditor;
    using UnityEngine;
    
    public class LayerTagSpawn : AssetPostprocessor
    {
        static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
        {
            foreach (string s in importedAssets)
            {
                if (s.Contains("LayerTagSpawn"))
                {
                    AddLayer("dragLayer");
                    AddLayer("terrain");
                    return;
                }
            }
        }
    
        static void AddTag(string tag)
        {
            if (!isHasTag(tag))
            {
                SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
                SerializedProperty it = tagManager.GetIterator();
                while (it.NextVisible(true))
                {
                    if (it.name == "tags")
                    {
                        for (int i = 0; i < it.arraySize; i++)
                        {
                            SerializedProperty dataPoint = it.GetArrayElementAtIndex(i);
                            if (string.IsNullOrEmpty(dataPoint.stringValue))
                            {
                                dataPoint.stringValue = tag;
                                tagManager.ApplyModifiedProperties();
                                return;
                            }
                        }
                    }
                }
            }
        }
    
        static void AddLayer(string layer)
        {
            if (!isHasLayer(layer))
            {
                SerializedObject tagManager = new SerializedObject(AssetDatabase.LoadAllAssetsAtPath("ProjectSettings/TagManager.asset")[0]);
                SerializedProperty it = tagManager.GetIterator();
                while (it.NextVisible(true))
                {
                    if (it.name.StartsWith("User Layer"))
                    {
                        if (it.type == "string")
                        {
                            if (string.IsNullOrEmpty(it.stringValue))
                            {
                                it.stringValue = layer;
                                tagManager.ApplyModifiedProperties();
                                return;
                            }
                        }
                    }
                }
            }
        }
    
        static bool isHasTag(string tag)
        {
            for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.tags.Length; i++)
            {
                if (UnityEditorInternal.InternalEditorUtility.tags[i].Contains(tag))
                    return true;
            }
            return false;
        }
    
        static bool isHasLayer(string layer)
        {
            for (int i = 0; i < UnityEditorInternal.InternalEditorUtility.layers.Length; i++)
            {
                if (UnityEditorInternal.InternalEditorUtility.layers[i].Contains(layer))
                    return true;
            }
            return false;
        }
    }
    LayerTagSpawn
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class DecoratorEditors : EditorWindow
    {
    
        [MenuItem("Window/打包场景 _F3")]
        static void PackagerWindow()
        {
            DecoratorEditors packagerEditor = (DecoratorEditors)EditorWindow.GetWindow(typeof(DecoratorEditors), false, "打包", true);
            packagerEditor.minSize = new Vector2(300, 220);
            packagerEditor.maxSize = new Vector2(300, 220);
            packagerEditor.Show();
        }
    
        public void OnGUI()
        {
            buildTarget = (BuildTarget)EditorGUI.EnumPopup(new Rect(80, 50, 150, 20), buildTarget);
            if (GUI.Button(new Rect(80, 80, 150, 20), "生成场景AB"))
            {
                MyBuild();
            }
        }
    
        static BuildTarget buildTarget = BuildTarget.Android;
        static void MyBuild()
        {
            string dir = Application.streamingAssetsPath + "/";
            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
            string activeSceneName = SceneManager.GetActiveScene().name;
            string saveSceneABPath = dir + activeSceneName + "-" + buildTarget +".unity3d";
            string[] levels = { SceneManager.GetActiveScene().path };
            //生成场景的AB包
            BuildPipeline.BuildPlayer(levels, saveSceneABPath, buildTarget, BuildOptions.BuildAdditionalStreamedScenes);
            AssetDatabase.Refresh();
            System.Diagnostics.Process.Start(dir);
        }
    }
    DecoratorEditors
    using System;
    using System.IO;
    using UnityEngine;
    using XLua;
    
    public class LuaEnvGlobal : MonoBehaviour
    {
        public static LuaEnvGlobal instance;
        LuaEnv luaEnv;
        void Awake()
        {
            instance = this;
            luaEnv = new LuaEnv();
            luaEnv.AddLoader((ref string filename) =>
            {
                string luaPath = AppConfig.SearchGameLuaPath + "/" + filename + ".lua";
                if (!File.Exists(luaPath))
                    return null;
                string script = File.ReadAllText(luaPath);
                return System.Text.Encoding.UTF8.GetBytes(script);
            });
            DontDestroyOnLoad(gameObject);
        }
    
        void Start()
        {
        }
    
        private Action luaUpdate;
        private Action luaOnDestroy;
        public void StartUp()
        {
            print("启动Lua");
            luaEnv.DoString("require 'GameLua/Others/Main'");
            luaEnv.Global.Get("GlobalUpdate", out luaUpdate);
            luaEnv.Global.Get("GlobalOnDestory", out luaOnDestroy);
        }
    
        public void DoString(string luaStr)
        {
            luaEnv.DoString(luaStr);
        }
    
        public T GlobalGet<T>(string key)
        {
            T result;
            luaEnv.Global.Get(key, out result);
            return result;
        }
    
    
        void Update()
        {
            if (luaUpdate != null)
                luaUpdate();
            if (luaEnv != null)
                luaEnv.Tick();
        }
    
        void OnDestroy()
        {
            if (luaOnDestroy != null)
                luaOnDestroy();
            Clear();
            if (luaEnv != null)
                luaEnv.Dispose();
        }
    
        void Clear()
        {
            luaUpdate = null;
            luaOnDestroy = null;
        }
    }
    LuaEnvGlobal
    /*
     * Tencent is pleased to support the open source community by making xLua available.
     * Copyright (C) 2016 THL A29 Limited, a Tencent company. All rights reserved.
     * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
     * http://opensource.org/licenses/MIT
     * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
    */
    
    using System.Collections.Generic;
    using System;
    using XLua;
    using System.Reflection;
    using System.Linq;
    using UnityEngine;
    
    //配置的详细介绍请看Doc下《XLua的配置.doc》
    public static class ExampleConfig
    {
        /***************如果你全lua编程,可以参考这份自动化配置***************/
        //--------------begin 纯lua编程配置参考----------------------------
        static List<string> exclude = new List<string> {
            "HideInInspector", "ExecuteInEditMode",
            "AddComponentMenu", "ContextMenu",
            "RequireComponent", "DisallowMultipleComponent",
            "SerializeField", "AssemblyIsEditorAssembly",
            "Attribute", "Types",
            "UnitySurrogateSelector", "TrackedReference",
            "TypeInferenceRules", "FFTWindow",
            "RPC", "Network", "MasterServer",
            "BitStream", "HostData",
            "ConnectionTesterStatus", "GUI", "EventType",
            "EventModifiers", "FontStyle", "TextAlignment",
            "TextEditor", "TextEditorDblClickSnapping",
            "TextGenerator", "TextClipping", "Gizmos",
            "ADBannerView", "ADInterstitialAd",
            "Android", "Tizen", "jvalue",
            "iPhone", "iOS", "Windows", "CalendarIdentifier",
            "CalendarUnit", "CalendarUnit",
            "ClusterInput", "FullScreenMovieControlMode",
            "FullScreenMovieScalingMode", "Handheld",
            "LocalNotification", "NotificationServices",
            "RemoteNotificationType", "RemoteNotification",
            "SamsungTV", "TextureCompressionQuality",
            "TouchScreenKeyboardType", "TouchScreenKeyboard",
            "MovieTexture", "UnityEngineInternal",
            "Terrain", "Tree", "SplatPrototype",
            "DetailPrototype", "DetailRenderMode",
            "MeshSubsetCombineUtility", "AOT", "Social", "Enumerator",
            "SendMouseEvents", "Cursor", "Flash", "ActionScript",
            "OnRequestRebuild", "Ping",
            "ShaderVariantCollection", "SimpleJson.Reflection",
            "CoroutineTween", "GraphicRebuildTracker",
            "Advertisements", "UnityEditor", "WSA",
            "EventProvider", "Apple",
            "ClusterInput", "Motion",
            "UnityEngine.UI.ReflectionMethodsCache", "NativeLeakDetection",
            "NativeLeakDetectionMode", "WWWAudioExtensions", "UnityEngine.Experimental",
            "UnityEngine.Purchasing","AnimatorControllerParameter","UnityEngine.Tilemaps",
            "UnityEngine.Analytics","UnityEngine.Caching",
            "UnityEngine.EventSystems.HoloLensInput","UnityEngine.NScreenBridge",
            "UnityEngine.TestTools.LogAssert","UnityEngine.Microphone",
            "UnityEngine.CanvasRenderer","UnityEngine.Audio.AudioSpatializerMicrosoft",
            "UnityEngine.ProceduralMaterial","UnityEngine.ProceduralPropertyDescription",
            "UnityEngine.ProceduralTexture","UnityEngine.SpatialTracking",
            "FFmpeg.AutoGen","UnityEngine.PostProcessing","EntriesDrawer","SerializedProperty",
            "AQUAS_Screenshotter","TiltInputAxisStylePropertyDrawer","ReplacementListDrawer","WaypointListDrawer","ReplacementListDrawer","TransformNameComparer",
            "BatchMaterialConverter","BatchModelImporter","BatchTextureImporter","EditorHotkeysTracker","EditorPrefsX","LB_LightingSettingsHepler","HighlightingSystem.Demo",
            "FrameWork.Meta","FrameWork.vComment"
        };
    
        static bool isExcluded(Type type)
        {
            var fullName = type.FullName;
            for (int i = 0; i < exclude.Count; i++)
            {
                if (fullName.Contains(exclude[i]))
                {
                    return true;
                }
            }
            return false;
        }
    
        [LuaCallCSharp]
        public static IEnumerable<Type> LuaCallCSharp
        {
            get
            {
                var unityTypes = (from assembly in AppDomain.CurrentDomain.GetAssemblies()
                                  where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder)
                                  from type in assembly.GetExportedTypes()
                                  where type.Namespace != null && type.Namespace.StartsWith("UnityEngine") && !isExcluded(type) && type.BaseType != typeof(MulticastDelegate) && !type.IsInterface && !type.IsEnum
                                  select type);
                string[] customAssemblys = new string[] {
                    "Assembly-CSharp",
                };
                var customTypes = (from assembly in customAssemblys.Select(s => Assembly.Load(s))
                                   from type in assembly.GetExportedTypes()
                                   where (type.Namespace == null || !type.Namespace.StartsWith("XLua")) && !isExcluded(type)
                                           && type.BaseType != typeof(MulticastDelegate) && !type.IsInterface && !type.IsEnum
                                   select type);
                return unityTypes.Concat(customTypes);
            }
        }
    
        //自动把LuaCallCSharp涉及到的delegate加到CSharpCallLua列表,后续可以直接用lua函数做callback
        [CSharpCallLua]
        public static List<Type> CSharpCallLua
        {
            get
            {
                var lua_call_csharp = LuaCallCSharp;
                var delegate_types = new List<Type>();
                var flag = BindingFlags.Public | BindingFlags.Instance
                    | BindingFlags.Static | BindingFlags.IgnoreCase | BindingFlags.DeclaredOnly;
                foreach (var field in (from type in lua_call_csharp select type).SelectMany(type => type.GetFields(flag)))
                {
                    if (typeof(Delegate).IsAssignableFrom(field.FieldType))
                    {
                        if (!isExcluded(field.FieldType))
                            delegate_types.Add(field.FieldType);
                    }
                }
    
                foreach (var method in (from type in lua_call_csharp select type).SelectMany(type => type.GetMethods(flag)))
                {
                    if (typeof(Delegate).IsAssignableFrom(method.ReturnType))
                    {
                        if (!isExcluded(method.ReturnType))
                            delegate_types.Add(method.ReturnType);
                    }
                    foreach (var param in method.GetParameters())
                    {
                        var paramType = param.ParameterType.IsByRef ? param.ParameterType.GetElementType() : param.ParameterType;
                        if (typeof(Delegate).IsAssignableFrom(paramType))
                        {
                            if (!isExcluded(paramType))
                                delegate_types.Add(paramType);
                        }
                    }
                }
                return delegate_types.Distinct().ToList();
            }
        }
        //--------------end 纯lua编程配置参考----------------------------
    
        /***************热补丁可以参考这份自动化配置***************/
        [Hotfix]
        static IEnumerable<Type> HotfixInject
        {
            get
            {
                List<Type> ll = (from type in Assembly.Load("Assembly-CSharp").GetExportedTypes()
                                 where (type.Namespace == null || !type.Namespace.StartsWith("XLua")) && !isExcluded(type)
                                 select type).ToList();
                return (from type in Assembly.Load("Assembly-CSharp").GetExportedTypes()
                        where (type.Namespace == null || !type.Namespace.StartsWith("XLua")) && !isExcluded(type)
                        select type);
            }
        }
        //--------------begin 热补丁自动化配置-------------------------
        static bool hasGenericParameter(Type type)
        {
            if (type.IsGenericTypeDefinition) return true;
            if (type.IsGenericParameter) return true;
            if (type.IsByRef || type.IsArray)
            {
                return hasGenericParameter(type.GetElementType());
            }
            if (type.IsGenericType)
            {
                foreach (var typeArg in type.GetGenericArguments())
                {
                    if (hasGenericParameter(typeArg))
                    {
                        return true;
                    }
                }
            }
            return false;
        }
    
        //// 配置某Assembly下所有涉及到的delegate到CSharpCallLua下,Hotfix下拿不准那些delegate需要适配到lua function可以这么配置
        //[CSharpCallLua]
        //static IEnumerable<Type> AllDelegate
        //{
        //    get
        //    {
        //        BindingFlags flag = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
        //        List<Type> allTypes = new List<Type>();
        //        var allAssemblys = new Assembly[]
        //        {
        //            Assembly.Load("Assembly-CSharp")
        //        };
        //        foreach (var t in (from assembly in allAssemblys from type in assembly.GetTypes() select type))
        //        {
        //            var p = t;
        //            while (p != null)
        //            {
        //                allTypes.Add(p);
        //                p = p.BaseType;
        //            }
        //        }
        //        allTypes = allTypes.Distinct().ToList();
        //        var allMethods = from type in allTypes
        //                         from method in type.GetMethods(flag)
        //                         select method;
        //        var returnTypes = from method in allMethods
        //                          select method.ReturnType;
        //        var paramTypes = allMethods.SelectMany(m => m.GetParameters()).Select(pinfo => pinfo.ParameterType.IsByRef ? pinfo.ParameterType.GetElementType() : pinfo.ParameterType);
        //        var fieldTypes = from type in allTypes
        //                         from field in type.GetFields(flag)
        //                         select field.FieldType;
        //        return (returnTypes.Concat(paramTypes).Concat(fieldTypes)).Where(t => t.BaseType == typeof(MulticastDelegate) && !hasGenericParameter(t)).Distinct();
        //    }
        //}
        //--------------end 热补丁自动化配置-------------------------
    
        //黑名单
        [BlackList]
        public static List<List<string>> BlackList = new List<List<string>>()  {
                    new List<string>(){"System.Xml.XmlNodeList", "ItemOf"},
                    new List<string>(){"UnityEngine.WWW", "movie"},
        #if UNITY_WEBGL
                    new List<string>(){"UnityEngine.WWW", "threadPriority"},
        #endif
                    new List<string>(){"UnityEngine.Texture2D", "alphaIsTransparency"},
                    new List<string>(){"UnityEngine.Security", "GetChainOfTrustValue"},
                    new List<string>(){"UnityEngine.CanvasRenderer", "onRequestRebuild"},
                    new List<string>(){"UnityEngine.Light", "areaSize"},
                    new List<string>(){"UnityEngine.Light", "lightmapBakeType"},
                    new List<string>(){"UnityEngine.WWW", "MovieTexture"},
                    new List<string>(){"UnityEngine.WWW", "GetMovieTexture"},
                    new List<string>(){"UnityEngine.AnimatorOverrideController", "PerformOverrideClipListCleanup"},
        #if !UNITY_WEBPLAYER
                    new List<string>(){"UnityEngine.Application", "ExternalEval"},
        #endif
                    new List<string>(){"UnityEngine.GameObject", "networkView"}, //4.6.2 not support
                    new List<string>(){"UnityEngine.Component", "networkView"},  //4.6.2 not support
                    new List<string>(){"System.IO.FileInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
                    new List<string>(){"System.IO.FileInfo", "SetAccessControl", "System.Security.AccessControl.FileSecurity"},
                    new List<string>(){"System.IO.DirectoryInfo", "GetAccessControl", "System.Security.AccessControl.AccessControlSections"},
                    new List<string>(){"System.IO.DirectoryInfo", "SetAccessControl", "System.Security.AccessControl.DirectorySecurity"},
                    new List<string>(){"System.IO.DirectoryInfo", "CreateSubdirectory", "System.String", "System.Security.AccessControl.DirectorySecurity"},
                    new List<string>(){"System.IO.DirectoryInfo", "Create", "System.Security.AccessControl.DirectorySecurity"},
                    new List<string>(){"UnityEngine.MonoBehaviour", "runInEditMode"},
                    new List<string>(){"UnityEngine.UI.Text", "OnRebuildRequested"},
                    new List<string>(){ "UnityEngine.Input", "IsJoystickPreconfigured","System.String"},
                    new List<string>(){ "UnityEngine.AudioSettings", "GetSpatializerPluginNames"},
                    new List<string>(){ "UnityEngine.AudioSettings", "SetSpatializerPluginName","System.String"},
                    new List<string>(){ "UnityEngine.UI.Graphic", "OnRebuildRequested"},
                    new List<string>(){ "MediaPlayerCtrl", "Interrupt1"},
                    new List<string>(){ "MediaPlayerCtrl", "MediaPlayerCtrl"},
                    new List<string>(){ "MediaPlayerCtrl", "Call_SetUnityActivity"},
                };
    }
    
    
    /// <summary>
    /// xlua自定义导出
    /// </summary>
    public static class XLuaCustomExport
    {
        /// <summary>
        /// dotween的扩展方法在lua中调用
        /// </summary>
        [LuaCallCSharp]
        [ReflectionUse]
        public static List<Type> dotween_lua_call_cs_list = new List<Type>()
        {
            typeof(DG.Tweening.AutoPlay),
            typeof(DG.Tweening.AxisConstraint),
            typeof(DG.Tweening.Ease),
            typeof(DG.Tweening.LogBehaviour),
            typeof(DG.Tweening.LoopType),
            typeof(DG.Tweening.PathMode),
            typeof(DG.Tweening.PathType),
            typeof(DG.Tweening.RotateMode),
            typeof(DG.Tweening.ScrambleMode),
            typeof(DG.Tweening.TweenType),
            typeof(DG.Tweening.UpdateType),
            typeof(DG.Tweening.Ease),
    
            typeof(DG.Tweening.DOTween),
            typeof(DG.Tweening.DOVirtual),
            typeof(DG.Tweening.EaseFactory),
            typeof(DG.Tweening.Tweener),
            typeof(DG.Tweening.Tween),
            typeof(DG.Tweening.Sequence),
            typeof(DG.Tweening.TweenParams),
            typeof(DG.Tweening.Core.ABSSequentiable),
    
            typeof(DG.Tweening.Core.TweenerCore<Vector3, Vector3, DG.Tweening.Plugins.Options.VectorOptions>),
    
            typeof(DG.Tweening.TweenCallback),
            typeof(DG.Tweening.TweenExtensions),
            typeof(DG.Tweening.TweenSettingsExtensions),
            typeof(DG.Tweening.ShortcutExtensions),
            typeof(DG.Tweening.ShortcutExtensions43),
            typeof(DG.Tweening.ShortcutExtensions46),
            typeof(DG.Tweening.ShortcutExtensions50),
           
            //dotween pro 的功能
            //typeof(DG.Tweening.DOTweenPath),
            //typeof(DG.Tweening.DOTweenVisualManager),
        };
    }
    ExampleConfig
    using System;
    using System.Collections;
    using System.IO;
    using UnityEngine;
    
    public class ExtractZipHelper : MonoBehaviour
    {
        public static ExtractZipHelper instance;
    
        void Awake()
        {
            instance = this;
            zipExtractFloder = Application.persistentDataPath + "/";
        }
    
        public void StartExtract(string zipPath)
        {
            print("执行解压压缩包任务:" + zipPath);
            StartCoroutine(Extract(zipPath));
        }
    
        public Action onSuccess;
        public Action<string> onError;
        string zipExtractFloder = string.Empty;
        IEnumerator Extract(string zipfile)
        {
            using (WWW www = new WWW(zipfile))
            {
                yield return www;
                if (www.error != null)
                {
                    print("加载压缩包出错:" + www.error);
                    if (onError != null)
                        onError(www.error);
                }
                else
                {
                    print("加载压缩包成功:" + zipfile);
                    string zipExtractPath = zipExtractFloder + Path.GetFileName(zipfile);
                    using (FileStream fs = File.Create(zipExtractPath))
                    {
                        fs.Write(www.bytes, 0, www.bytes.Length);
                    }
                    ExtractToPersi(zipExtractPath);
                }
            }
        }
    
        void ExtractToPersi(string filePath)
        {
            print("开始解压压缩包" + filePath);
            byte[] bytes = File.ReadAllBytes(filePath);
            try
            {
                CSharpUtils.UncompressMemory(zipExtractFloder, bytes);
                if (onSuccess != null)
                    onSuccess();
            }
            catch (Exception ex)
            {
                print("解压出错:" + ex.Message);
                if (onError != null)
                    onError(ex.Message);
            }
        }
    }
    ExtractZipHelper
    只有在编辑器模式下用的是非PC平台的AB包才会出现shader丢失的问题,解决方案如下,但是最好的解决方案是打个PC端的AB包给程序开发时用,然后在对应发布其他端的AB包
    1、内置的shader通过Shader.Find去获取,然后代码重新设置下
    2、自定义shader通过ab加载去获取,然后代码重新设置下
    3、在Lighting面板中skybox对应的材质shader,要在Project Settings下Graphics的面板中Always Included Shaders里面包含进去,这个仅仅是为了修复编辑器模式下天空盒材质shader丢失的问题而产生的解决方案,但是如果发布到android版本是不能设置这个的,不然安卓平台会产生天空盒shader丢失的问题,为了同时满足两者的需求,我们通过代码设置天空盒材质的shader,已在ABFixShader.cs中添加进去了
    4、如果打包的是PC平台的场景ab包,切记把ProjectSettings -> Other Settings里的PC平台的Auto Graphics API for ***全部勾选上,不然材质会丢失
    打包shader注意点
    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    using System;
    using System.Threading;
    using System.Linq;
    
    public class Loom : MonoBehaviour
    {
        public static int maxThreads = 8;
        static int numThreads;
    
        private static Loom _current;
        public static Loom Current
        {
            get
            {
                Initialize();
                return _current;
            }
        }
        //####去除Awake
        //  void Awake()  
        //  {  
        //      _current = this;  
        //      initialized = true;  
        //  }  
    
        static bool initialized;
    
        //####作为初始化方法自己调用,可在初始化场景调用一次即可
        public static void Initialize()
        {
            if (!initialized)
            {
    
                if (!Application.isPlaying)
                    return;
                initialized = true;
                GameObject g = new GameObject("Loom");
                //####永不销毁
                DontDestroyOnLoad(g);
                _current = g.AddComponent<Loom>();
            }
        }
    
        private List<Action> _actions = new List<Action>();
        public struct DelayedQueueItem
        {
            public float time;
            public Action action;
        }
        private List<DelayedQueueItem> _delayed = new List<DelayedQueueItem>();
    
        List<DelayedQueueItem> _currentDelayed = new List<DelayedQueueItem>();
    
        public static void QueueOnMainThread(Action action)
        {
            QueueOnMainThread(action, 0f);
        }
        public static void QueueOnMainThread(Action action, float time)
        {
            if (time != 0)
            {
                if (Current != null)
                {
                    lock (Current._delayed)
                    {
                        Current._delayed.Add(new DelayedQueueItem { time = Time.time + time, action = action });
                    }
                }
            }
            else
            {
                if (Current != null)
                {
                    lock (Current._actions)
                    {
                        Current._actions.Add(action);
                    }
                }
            }
        }
    
        public static Thread RunAsync(Action a)
        {
            Initialize();
            while (numThreads >= maxThreads)
            {
                Thread.Sleep(1);
            }
            Interlocked.Increment(ref numThreads);
            ThreadPool.QueueUserWorkItem(RunAction, a);
            return null;
        }
    
        private static void RunAction(object action)
        {
            try
            {
                ((Action)action)();
            }
            catch
            {
            }
            finally
            {
                Interlocked.Decrement(ref numThreads);
            }
        }
    
        void OnDisable()
        {
            if (_current == this)
            {
                _current = null;
            }
        }
    
        // Use this for initialization  
        void Start()
        {
        }
    
        List<Action> _currentActions = new List<Action>();
    
        // Update is called once per frame  
        void Update()
        {
            lock (_actions)
            {
                _currentActions.Clear();
                _currentActions.AddRange(_actions);
                _actions.Clear();
            }
            foreach (var a in _currentActions)
            {
                a();
            }
            lock (_delayed)
            {
                _currentDelayed.Clear();
                _currentDelayed.AddRange(_delayed.Where(d => d.time <= Time.time));
                foreach (var item in _currentDelayed)
                    _delayed.Remove(item);
            }
            foreach (var delayed in _currentDelayed)
            {
                delayed.action();
            }
        }
    }
    Loom
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using UnityEditor;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    
    public class DecoratorEditors : EditorWindow
    {
    
        [MenuItem("Window/打包 _F2")]
        static void PackagerWindow()
        {
            DecoratorEditors packagerEditor = (DecoratorEditors)EditorWindow.GetWindow(typeof(DecoratorEditors), false, "打包", true);
            packagerEditor.minSize = new Vector2(300, 220);
            packagerEditor.maxSize = new Vector2(300, 220);
            packagerEditor.Show();
        }
    
        public void OnGUI()
        {
            buildTarget = (BuildTarget)EditorGUI.EnumPopup(new Rect(80, 50, 150, 20), buildTarget);
            if (GUI.Button(new Rect(80, 80, 150, 20), "生成场景AB"))
            {
                MyBuild();
            }
        }
    
        static string sceneABPath = string.Empty;
        static string shaderABSavePath = string.Empty;
        static BuildTarget buildTarget = BuildTarget.Android;
        static void MyBuild()
        {
            string saveABPath = Application.dataPath.Replace("Assets", "AB");
            if (!Directory.Exists(saveABPath))
                Directory.CreateDirectory(saveABPath);
    
            string activeSceneName = SceneManager.GetActiveScene().name;
            string saveSceneABPath = saveABPath + "/" + activeSceneName + ".unity3d";
            string[] levels = { SceneManager.GetActiveScene().path };
    
            //生成场景的AB包
            BuildPipeline.BuildPlayer(levels, saveSceneABPath, buildTarget, BuildOptions.BuildAdditionalStreamedScenes);
    
            ////生成场景对应的Shader的AB包
            //string shaderABName = "shader.unity3d";
            //Shader[] shaders = Resources.FindObjectsOfTypeAll<Shader>();
            //AssetBundleBuild[] abArrary = new AssetBundleBuild[shaders.Length];
            //for (int i = 0; i < shaders.Length; i++)
            //{
            //    AssetBundleBuild ab = new AssetBundleBuild();
            //    string assetPath = AssetDatabase.GetAssetPath(shaders[i]);
            //    ab.assetBundleName = shaderABName;
            //    ab.assetNames = new string[] { assetPath };
            //    ab.assetBundleVariant = "";
            //    string shaderName = shaders[i].name;
            //    if (shaderName.Contains("/"))
            //        shaderName = shaderName.Split('/')[1];
            //    ab.addressableNames = new string[] { shaderName };
            //    abArrary[i] = ab;
            //}
            //BuildPipeline.BuildAssetBundles(saveABPath, abArrary, BuildAssetBundleOptions.UncompressedAssetBundle, buildTarget);
    
            //避免让美术设置手动ab,所以不采取下面这种方式
            //BuildPipeline.BuildAssetBundles(shaderABSavePath, BuildAssetBundleOptions.UncompressedAssetBundle, buildTarget);
    
            AssetDatabase.Refresh();
            System.Diagnostics.Process.Start(saveABPath);
        }
    }
    生成场景对应的Shader的AB包
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;
    
    public class ABFixShader : MonoBehaviour
    {
    #if UNITY_EDITOR    
        string shaderABPath = string.Empty;
        void Awake()
        {
            string activeSceneName = SceneManager.GetActiveScene().name;
            shaderABPath = Application.streamingAssetsPath + "/" + activeSceneName +"-shader.unity3d";
            StartCoroutine(Download());
        }
    
        IEnumerator Download()
        {
            using (WWW www = new WWW(shaderABPath))
            {
                yield return www;
                if (www.error != null)
                {
                    Debug.Log("shader下载失败:" + www.error);
                }
                else
                {
                    Debug.Log("开始修复shader丢失问题");
                    FixShader(www.assetBundle);
                }
            }
        }
    
        Dictionary<string, Shader> shaderDic = null;
        void FixShader(AssetBundle shaderBundle)
        {
            List<GameObject> rendererList = new List<GameObject>();
            GetAllChildren(transform, rendererList);
            if (rendererList != null && rendererList.Count > 0)
            {
                shaderDic = new Dictionary<string, Shader>();
                rendererList.ForEach((go) =>
                {
                    ResetShader(go, shaderBundle);
                });
            }
            //代码修复天空盒材质shader丢失的问题
            ChangeMaterialShader(RenderSettings.skybox, shaderBundle);
        }
    
        void GetAllChildren(Transform root, List<GameObject> rendererList)
        {
            foreach (Transform item in root)
            {
                if (item.GetComponent<Renderer>() != null)
                {
                    rendererList.Add(item.gameObject);
                }
                else if (item.GetComponent<Skybox>() != null)
                {
                    rendererList.Add(item.gameObject);
                }
                GetAllChildren(item, rendererList);
            }
        }
    
        void ResetShader(GameObject target, AssetBundle shaderBundle)
        {
            Material[] materials = null;
            Renderer renderer = target.GetComponent<Renderer>();
            if (renderer != null)
            {
                materials = renderer.materials;
                ParticleSystemRenderer psr = GetComponent<ParticleSystemRenderer>();
                if (psr != null)
                {
                    materials[materials.Length] = psr.trailMaterial;
                }
            }
            else
            {
                Skybox skybox = target.GetComponent<Skybox>();
                if (skybox != null)
                {
                    materials = new Material[] { skybox.material };
                }
            }
            if (materials != null && materials.Length > 0)
            {
                for (int i = 0; i < materials.Length; i++)
                {
                    ChangeMaterialShader(materials[i], shaderBundle);
                }
            }
        }
    
        void ChangeMaterialShader(Material material, AssetBundle shaderBundle)
        {
            if (material != null && shaderBundle != null)
            {
                string shaderNode = string.Empty;
                string shaderName = string.Empty;
                shaderNode = material.shader.name;
                shaderName = shaderNode;
                if (shaderNode.Contains("/"))
                    shaderName = shaderNode.Split('/')[1];
                Shader resultShader = null;
                if (shaderDic.ContainsKey(shaderName))
                    resultShader = shaderDic[shaderName];
                else
                {
                    resultShader = shaderBundle.LoadAsset<Shader>(shaderName);
                    if (resultShader == null)
                    {
                        if (shaderDic.ContainsKey(shaderNode))
                            resultShader = shaderDic[shaderNode];
                        else
                        {
                            resultShader = Shader.Find(shaderNode);
                            if (resultShader != null)
                                shaderDic[shaderNode] = resultShader;
                        }
                    }
                    else
                    {
                        shaderDic[shaderName] = resultShader;
                    }
                }
                material.shader = resultShader;
            }
        }
    #endif
    }
    ABFixShader
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class DownloadManager : MonoBehaviour
    {
        public static DownloadManager instance;
    
        void Awake()
        {
            instance = this;
        }
    
        #region Properties
        /// <summary>
        /// 正在执行和正在等待的任务数量总和
        /// </summary>
        public int WaitingAndRunningCount { get { return mWaiting.Count + mRunning.Count; } }
        /// <summary>
        /// 最多可同时执行多少个任务
        /// </summary>
        public int MaxTaskCountInSameTime { get; private set; }
        /// <summary>
        /// 当前正在执行的任务数量
        /// </summary>
        public int RunningCount { get { return mRunning.Count; } }
        /// <summary>
        /// 已经完成的任务数量
        /// </summary>
        public int FinishedCount { get { return mFinished.Count; } }
        /// <summary>
        /// 任务是否成功完成,并且不存在失败的任务
        /// </summary>
        public bool IsCompleted { get { return WaitingAndRunningCount == 0; } }
        /// <summary>
        /// 是否正在下载
        /// </summary>
        public bool IsDownloading { get; private set; }
    
        /// <summary>
        /// 任务执行完时的回调
        /// </summary>
        public event Action WorkDone;
    
        #endregion
    
        #region Fields
        List<DownloadSocketFileHelper> mWaiting = new List<DownloadSocketFileHelper>();
        List<DownloadSocketFileHelper> mRunning = new List<DownloadSocketFileHelper>();
        List<DownloadSocketFileHelper> mFinished = new List<DownloadSocketFileHelper>();
    
        #endregion
    
        void Update()
        {
            if (!IsDownloading)
            {
                return;
            }
            if (mRunning.Count > 0)
            {
                for (int i = mRunning.Count - 1; i >= 0; i--)
                {
                    if (mRunning[i].IsSuccess)
                    {
                        mFinished.Add(mRunning[i]);
                        mRunning.RemoveAt(i);
                    }
                    else if (mRunning[i].IsFailed)
                    {
                        mWaiting.Add(mRunning[i]);
                        mRunning.RemoveAt(i);
                    }
                }
            }
    
            if (mWaiting.Count > 0)
            {
                if (mRunning.Count < MaxTaskCountInSameTime)
                {
                    DownloadSocketFileHelper urlData = FindEnabledTask();
                    if (urlData != null)
                    {
                        urlData.Start();
                        mRunning.Add(urlData);
                    }
                }
            }
    
            if (mRunning.Count == 0)
            {
                IsDownloading = false;
                if (WorkDone != null)
                {
                    WorkDone();
                }
            }
        }
    
        private DownloadSocketFileHelper FindEnabledTask()
        {
            DownloadSocketFileHelper urlData = null;
            foreach (var item in mWaiting)
            {
                if (item.TryTimes < AppConfig.MAX_TRY_TIMES)
                {
                    urlData = item;
                    mWaiting.Remove(item);
                    break;
                }
            }
            return urlData;
        }
    
        public void Init()
        {
            mWaiting.Clear();
            mRunning.Clear();
            mFinished.Clear();
    
            IsDownloading = false;
            MaxTaskCountInSameTime = AppConfig.MAX_DOWNLOAD_TASKS;
            WorkDone = null;
        }
    
        public void StartDownload()
        {
            if (IsDownloading == false)
            {
                IsDownloading = true;
            }
        }
    
        public void Retry()
        {
            if (IsDownloading == false)
            {
                //重试就要把所有失败的任务重试次数重置为0
                foreach (var item in mWaiting)
                {
                    item.TryTimes = 0;
                }
                IsDownloading = true;
            }
        }
    
        public void PushTask(string filePath, Action<string> onSuccess, Action<string> onFailed)
        {
            mWaiting.Add(new DownloadSocketFileHelper(filePath, onSuccess, onFailed));
        }
    }
    
    
    public class DownloadSocketFileHelper
    {
        int serverPort = 12345;
        int buffSize = 1024 * 1024;
        string serverIp = string.Empty;
    
        public int TryTimes = 0;
        public string filePath = string.Empty;
        string wholeFilePath = string.Empty;
    
        public int status = 0;//0为默认状态1为成功2为失败
        public DownloadSocketFileHelper(string _filePath, Action<string> _OnSuccess, Action<string> _OnError)
        {
            serverIp = AppConfig.serverIP;
            filePath = _filePath;
            OnSuccess = _OnSuccess;
            OnError = _OnError;
            TryTimes = 0;
            wholeFilePath = AppConfig.HotAssetsPath + filePath;
        }
    
        string errorMsg = string.Empty;
        Socket clientSocket;
        public void Start()
        {
            try
            {
                status = 0;
                errorMsg = string.Empty;
                IsSuccess = false;
                IsFailed = false;
                DownloadManager.instance.StartCoroutine(CheckStatus());
                clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(serverIp), serverPort);
                clientSocket.Connect(ipEndPoint);
                Thread newThread = new Thread(ReceiveFile);
                newThread.Start();
                SendMsgToServer(Encoding.UTF8.GetBytes(filePath));
                Debug.Log("开始下载 = " + filePath);
            }
            catch (Exception ex)
            {
                errorMsg = ex.Message + " = " + filePath;
                status = 2;
            }
        }
    
        Action<string> OnSuccess;
        Action<string> OnError;
    
        void ReceiveFile()
        {
            try
            {
                string dir = Path.GetDirectoryName(wholeFilePath);
                if (!Directory.Exists(dir)) Directory.CreateDirectory(dir);
                using (FileStream writer = new FileStream(wholeFilePath, FileMode.OpenOrCreate, FileAccess.Write))
                {
                    int len = 0;
                    byte[] buff = new byte[buffSize];
                    while ((len = clientSocket.Receive(buff)) != 0)
                    {
                        string msg = Encoding.UTF8.GetString(buff, len - 3, 3);
                        if (msg == "END")
                        {
                            writer.Write(buff, 0, len - 3);
                            clientSocket.Close();
                            status = 1;
                            break;
                        }
                        writer.Write(buff, 0, len);
                    }
                }
    
            }
            catch (Exception ex)
            {
                clientSocket.Close();
                errorMsg = ex.Message + " = " + filePath;
                status = 2;
            }
        }
    
        public bool IsSuccess = false;
        public bool IsFailed = false;
        IEnumerator CheckStatus()
        {
            yield return new WaitUntil(() => { return status != 0; });
            if (status == 1)
            {
                if (OnSuccess != null)
                    OnSuccess(filePath);
                IsSuccess = true;
            }
            else if (status == 2)
            {
                TryTimes++;
                if (TryTimes == AppConfig.MAX_TRY_TIMES)
                {
                    errorMsg = StaticText.DownloadOverTimes;
                }
                if (OnError != null)
                    OnError(errorMsg);
                IsFailed = true;
            }
        }
    
        public void SendMsgToServer(byte[] bytes)
        {
            clientSocket.Send(bytes);
        }
    }
    Client:DownloadManager
    using System.Collections.Generic;
    using System.IO;
    using UnityEngine;
    using UnityEngine.UI;
    
    class MyFileClient : MonoBehaviour
    {
        public Slider slider;
        public static MyFileClient instance;
        DownloadManager downloadManager;
        void Awake()
        {
            GetServerIP();
            downloadManager = GetComponent<DownloadManager>();
            instance = this;
        }
    
        void GetServerIP()
        {
            AppConfig.serverIP = File.ReadAllText(AppConfig.HotAssetsPath + AppConfig.serverIpFileName);
        }
    
        string LocalMD5FilePath = string.Empty;
        string hotAssetsPath = string.Empty;
        void Start()
        {
            LocalMD5FilePath = AppConfig.LocalMD5FilePath;
            hotAssetsPath = AppConfig.HotAssetsPath;
    
            downloadManager.Init();
            downloadManager.WorkDone += onDownloadFileListDone;
            downloadManager.PushTask(AppConfig.LIST_FILENAME, onDownLoadFileListSuccess, onDownLoadFileListFailed);
            downloadManager.StartDownload();
        }
    
        void StartGame()
        {
    
        }
    
        List<FileData> mServerFileList = null;
        void onDownLoadFileListSuccess(string filePath)
        {
            Debug.Log("文件列表下载成功");
            string[] downloadFileStringList = File.ReadAllLines(hotAssetsPath + filePath);
            mServerFileList = new List<FileData>();
            foreach (var item in downloadFileStringList)
            {
                if (string.IsNullOrEmpty(item.Trim()))
                {
                    continue;
                }
                string[] tokens = item.Split('|');
                if (tokens.Length >= 3)
                {
                    FileData data = new FileData();
                    data.needUpdate = true;
                    data.name = tokens[0].Trim();
                    data.md5 = tokens[1].Trim();
                    data.size = 0;
                    int.TryParse(tokens[2], out data.size);
                    if (data.size > 0)
                    {
                        mServerFileList.Add(data);
                    }
                }
            }
        }
    
        void onDownLoadFileListFailed(string msg)
        {
            Debug.Log(msg + "下载失败");
            ErrorHandle(msg);
        }
    
        void ErrorHandle(string msg)
        {
            MFMessageBox.Instance.PopYesNo(msg, () =>
            {
                Application.Quit();
            }, () =>
            {
                downloadManager.Retry();
            }, StaticText.QuitGame, StaticText.STR_RETRY);
        }
    
        void onDownloadFileListDone()
        {
            Debug.Log("下载任务进程结束");
            if (downloadManager.IsCompleted)
            {
                print("文件列表下载成功");
                CheckFileMD5();
            }
            else
            {
                print("文件列表下载失败");
            }
        }
    
        void CheckFileMD5()
        {
            //得到本地的文件列表
            string[] oldLines = null;
            Debug.Log("比较MD5值 = " + LocalMD5FilePath);
            if (File.Exists(LocalMD5FilePath))
            {
                oldLines = File.ReadAllLines(LocalMD5FilePath);
            }
            if (oldLines != null && oldLines.Length > 0)
            {
                //去除不需要更新的文件
                foreach (var item in oldLines)
                {
                    if (string.IsNullOrEmpty(item.Trim())) continue;
                    string[] tokens = item.Split('|');
                    if (tokens.Length < 2) continue;
    
                    string name = tokens[0].Trim();
                    string md5 = tokens[1].Trim();
                    if (!File.Exists(hotAssetsPath + name))
                    {
                        continue;
                    }
                    for (int i = 0; i < mServerFileList.Count; i++)
                    {
                        if (mServerFileList[i].name == name && mServerFileList[i].md5 == md5)
                        {
                            mServerFileList[i].needUpdate = false;
                            break;
                        }
                    }
                }
            }
            StartDownloadAssets();
        }
    
        public void StartDownloadAssets()
        {
            downloadManager.Init();
            downloadManager.WorkDone += onDownloadAllAssetDown;
            foreach (var item in mServerFileList)
            {
                if (item.needUpdate)
                {
                    print("需要下载文件 = " + item.name);
                    downloadManager.PushTask(item.name, onDownloadAssetSuccess, onDownloadAssetFailed);
                }
            }
            downloadManager.StartDownload();
        }
    
        void onDownloadAssetSuccess(string filePath)
        {
            Debug.Log(filePath + "下载成功");
            for (int i = 0; i < mServerFileList.Count; i++)
            {
                if (mServerFileList[i].name == filePath)
                {
                    mServerFileList[i].needUpdate = false;
                    break;
                }
            }
        }
        void onDownloadAssetFailed(string filePath)
        {
            Debug.Log(filePath + "下载失败");
            ErrorHandle(StaticText.DownloadAssetsUpdateError);
        }
    
        void onDownloadAllAssetDown()
        {
            Debug.Log("下载任务进程结束");
            if (downloadManager.IsCompleted)
            {
                print("所有ab资源下载成功");
                StartGame();
            }
            else
            {
                print("存在ab资源下载失败");
            }
            UpdateFileList();
        }
    
        void Update()
        {
            slider.value = (float)downloadManager.FinishedCount / downloadManager.WaitingAndRunningCount;
        }
    
        void OnApplicationQuit()
        {
            UpdateFileList();
        }
    
        void UpdateFileList()
        {
            if (mServerFileList != null && mServerFileList.Count > 0)
            {
                string reslut = string.Empty;
                FileData fileData = null;
                for (int i = 0; i < mServerFileList.Count; i++)
                {
                    fileData = mServerFileList[i];
                    if (fileData.needUpdate == false)
                    {
                        reslut += fileData.name + "|" + fileData.md5 + "|" + fileData.size + "
    ";
                    }
                }
                reslut = reslut.TrimEnd('
    ');
                File.WriteAllText(AppConfig.LocalMD5FilePath, reslut);
                print("保存已经下载的文件的MD5值");
            }
        }
    }
    Client:MyFileClient
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using UnityEngine;
    
    public class MyFileServer : MonoBehaviour
    {
        void Start()
        {
            StartUp();
        }
    
        int serverPort = 12345;
        int listenCount = 10000;
        int buffSize = 1024 * 1024;
    
    
        Socket serverSocket;
        void StartUp()
        {
            try
            {
                serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint ipEndPoint = new IPEndPoint(GetMyIP(), serverPort);
                serverSocket.Bind(ipEndPoint);
                serverSocket.Listen(listenCount);
                Thread receiveThread = new Thread(ReceiveClientMsg);
                receiveThread.Start();
                Debug.Log("启动成功");
            }
            catch (SocketException ex)
            {
                Debug.LogError(ex.Message);
            }
        }
    
        void ReceiveClientMsg()
        {
            while (true)
            {
                Socket servicesSocket = serverSocket.Accept();
                if (servicesSocket != null)
                {
                    Thread newThread = new Thread(new ParameterizedThreadStart(HandleClientMsg));
                    newThread.Start(servicesSocket);
                }
            }
        }
    
        void HandleClientMsg(object _serivesSocket)
        {
            Socket serivesSocket = (Socket)_serivesSocket;
            byte[] buff = new byte[buffSize];
            int len;
            while ((len = serivesSocket.Receive(buff)) != 0)
            {
                string msg = Encoding.UTF8.GetString(buff, 0, len);
                print("客户端返回消息 = " + msg);
                SentFileToClient(serivesSocket, "V:/Upload/" + msg);
            }
        }
    
        void SendMsgToClient(Socket serivesSocket, byte[] bytes)
        {
            serivesSocket.Send(bytes, 0, bytes.Length, SocketFlags.None);
        }
    
        void SentFileToClient(Socket serivesSocket, string filePath)
        {
            using (FileStream read = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            {
                byte[] buff = new byte[buffSize];
                int len = 0;
                while ((len = read.Read(buff, 0, buff.Length)) != 0)
                {
                    Array.Resize(ref buff, len);
                    SendMsgToClient(serivesSocket, buff);
                }
            }
            SendMsgToClient(serivesSocket, Encoding.UTF8.GetBytes("END"));
            serivesSocket.Close();
        }
    
        void OnApplicationQuit()
        {
            print("关闭socket");
            serverSocket.Close();
        }
    
        IPAddress GetMyIP()
        {
            IPHostEntry IpEntry = Dns.GetHostEntry(Dns.GetHostName());
            IPAddress ip = null;
            for (int i = 0; i < IpEntry.AddressList.Length; i++)
            {
                if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork)//检查是不是IPv4,IPv6是InterNetworkv6
                {
                    ip = IpEntry.AddressList[i];
                    break;
                }
            }
            return ip;
        }
    }
    Server:MyFileServer
    --默认值可以不传
    local ConfigHelpers = {}
    
    --设置物体高亮  target:设置对象   isLigth:是否高亮   seeThrough:是否穿透(默认为true,穿透) startColor:高亮开始颜色(默认初始化)  endColor:高亮结束颜色(默认初始化)  flashingFrequency:闪烁频率(默认为2)  flashingDelay:闪烁延迟(默认为0) nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetHeightLight( target , isLight , seeThrough , startColor , endColor , flashingFrequency , flashingDelay  , nextConfigIdList )
        local target = ConfigHelpers.FindGameObject(target)
        if target then
            flashingFrequency = flashingFrequency or 0.5
            flashingDelay = flashingDelay or 0
            seeThrough = (seeThrough == nil and {true} or {seeThrough})[1]
            startColor = startColor or Color.green
            endColor = endColor or Color.red
            GameUtils.SetHeightLight( target , isLight, seeThrough, startColor , endColor , flashingFrequency , flashingDelay ) 
            local shla = target:GetComponent("SyncHighLightAction")
            if shla == nil then
                shla = target:AddComponent(typeof(SyncHighLightAction))
            end  
            shla:UpdateStatus(isLight, seeThrough , startColor , endColor , flashingFrequency , flashingDelay)
            if nextConfigIdList then
                ConfigHelpers.ExecIdList(nextConfigIdList)
            end
        end
    end
    
    --播放动画  target:设置对象  clipName:动画名称  nextConfigIdList:完成过后要执行的id集合  speed:速度(默认为1)   normalizedTime:动画从哪播放(默认为0,从头开始播放)
    function ConfigHelpers.PlayAnimation( target , clipName , nextConfigIdList , speed , normalizedTime )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local anima = target:GetComponent('Animation')
                if anima then
                    local saa = target:GetComponent("SyncAnimationAction")
                    if saa == nil then
                        saa = target:AddComponent(typeof(SyncAnimationAction))
                    end
                    speed = speed or 1
                    normalizedTime = normalizedTime or 0
                    local clip = anima:GetClip(clipName)
                    if clip then
                        anima.clip = clip
                        local tClip = anima:get_Item(clipName)
                        tClip.speed = speed
                        tClip.normalizedTime = normalizedTime
                        anima:Play()
                        saa:SendMsgToServer()
                        if nextConfigIdList then
                            local allTime = anima.clip.length / math.abs(speed)
                            GameUtils.StartCoroutineDelaySec(function ( ... )
                                ConfigHelpers.ExecIdList(nextConfigIdList)
                            end,allTime)
                        end
                    else
                        Print_t('<color=red>error:</color>Cannot find animation object = '..clipName)
                    end
                end
            end
        end
    end
    
    --播放动画  target:设置对象  clipName:动画名称  nextConfigIdList:完成过后要执行的id集合  speed:速度(默认为1)   normalizedTime:动画从哪播放(默认为0,从头开始播放)
    function ConfigHelpers.PlayAnimator( target , clipName , layer , speed , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local anima = target:GetComponent('Animator')
                if anima then
                    local saa = target:GetComponent("SyncAnimatorAction")
                    if saa == nil then
                        target:AddComponent(typeof(SyncAnimatorAction))
                    end
                    speed = speed or 1
                    if clipName then
                        anima:Play(clipName,layer)
                        anima.speed = speed
                        if nextConfigIdList then
                            local allTime = anima:GetCurrentAnimatorStateInfo(layer).length / math.abs(speed)
                            GameUtils.StartCoroutineDelaySec(function ( ... )
                                ConfigHelpers.ExecIdList(nextConfigIdList)
                            end,allTime)
                        end
                    else
                        Print_t('<color=red>error:</color>Cannot find animation object = '..clipName)
                    end
                end
            end
        end
    end
    
    --延迟几秒执行     sec:延迟秒数    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.DelaySec( sec , nextConfigIdList )
        GameUtils.StartCoroutineDelaySec(function ( ... )
            if nextConfigIdList then
                ConfigHelpers.ExecIdList(nextConfigIdList)
            end 
        end,sec)
    end
    
    --播放声音  audioName:音频名称   delaySec:延迟几秒播放(默认为0)  nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.PlayAudio( audioName , delaySec , nextConfigIdList )
        local audioLibrary = AudioLibrary.instance
        local audioClip = audioLibrary:GetAudioClip(audioName)
        if audioClip then
            delaySec = delaySec or 0
            AudioSourceGlobal.clip = audioClip
            AudioSourceGlobal:PlayDelayed(delaySec)
            audioLibrary:SendSyncAudio(audioName,delaySec)
            if nextConfigIdList then
                GameUtils.StartCoroutineDelaySec(function ( ... )
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end,delaySec + audioClip.length)
            end
        else
            Print_t('<color=red>error:</color>Cannot find audio object = '..audioName)
        end
    end
    
    --关闭音频播放   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.CloseAudio( nextConfigIdList )
        AudioSourceGlobal.clip = nil
        AudioSourceGlobal:Stop()
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end 
    end
    
    --设置组件状态  target:设置对象  enabled:是否关闭   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetComponentEnabled( target , componentName , enabled , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local component = target:GetComponent(componentName)
                if component then
                    component.enabled = enabled
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end 
                else
                    Print_t('<color=red>error:</color>Cannot find component object = '..clipName)
                end
            end
        end
    end
    
    --开始计时    nextConfigIdList:完成过后要执行的id集合
    local isEndTime = false
    local tempTime = 0
    function ConfigHelpers.StartTime( nextConfigIdList )
        tempTime = 0
        isEndTime = false
        GameUtils.StartCoroutineWaitUntil(function (  )
            tempTime = tempTime + Time.deltaTime
            return isEndTime
        end)
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end 
    end
    
    --计时结束      nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.EndTime( target , nextConfigIdList )
        isEndTime = true
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local textObj = target:GetComponent('Text')
                if textObj then
                    textObj.text = ConfigHelpers.FormatSecond(tempTime)
                    local sta = target:GetComponent("SyncTextAction")
                    if sta == nil then
                        target:AddComponent(typeof(SyncTextAction))
                    end
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end 
                end
            end
        end
    end
    
    --初始化总分    nextConfigIdList:完成过后要执行的id集合
    local allScore = 100
    function ConfigHelpers.InitScore( score , nextConfigIdList )
        allScore = score
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end 
    end
    
    --更新分数     nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.UpdateScore( value , nextConfigIdList )
        allScore = allScore + value
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end 
    end
    
    --获取分数并显示      nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.GetScore( nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return allScore
    end
    
    --计时器  target:设置对象    direction:(1为正计时,-1为倒计时) startCount:起始点  endCount:目标点  nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.Timer( target , direction , startCount , endCount , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local textObj = target:GetComponent('Text')
                if textObj then
                    GameUtils.StartCoroutineWaitUntil(function (  )
                        if direction > 0 then
                            startCount = startCount + Time.deltaTime
                            if startCount >= endCount then
                                if nextConfigIdList then
                                    ConfigHelpers.ExecIdList(nextConfigIdList)
                                end
                                Print_t('正计时结束')
                            end                        
                            textObj.text = tostring(math.floor(startCount))
                        else
                            startCount = startCount - Time.deltaTime
                            if startCount <= endCount then
                                if nextConfigIdList then
                                    ConfigHelpers.ExecIdList(nextConfigIdList)
                                end
                                Print_t('倒计时结束')
                            end                        
                            textObj.text = tostring(math.ceil(startCount))
                        end
                        local sta = target:GetComponent("SyncTextAction")
                        if sta == nil then
                            target:AddComponent(typeof(SyncTextAction))
                        end
                        local result = (direction > 0 and {startCount >= endCount} or {startCount <= endCount})[1]
                        return result
                    end)
                end
            end
        end
    end
    
    --淡入淡出  finishNextConfigIdList:淡出后要执行的id集合    stayNextConfigIdList:黑屏时要执行的集合   fadeInTime:淡入花费时间   stayTime:黑屏花费时间  fadeOutTime:弹出花费时间
    function ConfigHelpers.FadeInOut( finishNextConfigIdList , stayNextConfigIdList , fadeInTime , stayTime , fadeOutTime )
        fadeInTime = fadeInTime or 1.5
        stayTime = stayTime or 0.5
        fadeOutTime = fadeOutTime or 1.5
        GameUtils.FadeInOut(BlackBgGlobal,fadeInTime,stayTime,fadeOutTime,function ( ... )
            if finishNextConfigIdList then
                ConfigHelpers.ExecIdList(finishNextConfigIdList)
            end
        end,function ( ... )
            if stayNextConfigIdList then
                ConfigHelpers.ExecIdList(stayNextConfigIdList)
            end
        end)
    end
    
    --设置对象激活状态   target:设置对象   isActive:是否激活    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetGameObjectActive( target , isActive , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then            
                local saa = target:GetComponent("SyncActiveAction")
                if saa == nil then
                    saa = target:AddComponent(typeof(SyncActiveAction))
                end            
                target.gameObject:SetActive(isActive)
                saa:UpdateStatus()
                if nextConfigIdList then
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end 
            end
        end
    end
    
    --设置物体FillAmount
    function ConfigHelpers.SetFillAmount( path , value , nextConfigIdList )
       if path then
            target = ConfigHelpers.FindGameObject(path)
            if target then 
                local v = target:GetComponent('Image')
                if v then
                    v.fillAmount = value
                    GameUtils.SyncFillAmount(path,value)
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end 
                end
            end
        end
    end
    
    --实例化物体   target:要实例化的目标对象    name:为实例化的对象重命名
    function  ConfigHelpers.CloneGo( path , name , nextConfigIdList )
        if path then
            local target = ConfigHelpers.FindGameObject(path)
            local result = nil
            if target then
                GameUtils.SyncCloneGo(path,name)
                result = GameObject.Instantiate(target)
                result.transform.parent = target.transform.parent
                result.transform.localEulerAngles = target.transform.localEulerAngles
                result.transform.localPosition = target.transform.localPosition
                result.transform.localScale = target.transform.localScale
                result.name = name
                if nextConfigIdList then
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end 
                return result
            end
        end
        return result
    end
    
    --销毁物体   target:要销毁的对象
    function  ConfigHelpers.DestoryGo( path , isImmediate , nextConfigIdList )
        if path then
            local target = ConfigHelpers.FindGameObject(path)
            if target then
                isImmediate = (isImmediate == nil and {false} or {isImmediate})[1]
                if isImmediate then            
                    CS.UnityEngine.Object.DestroyImmediate(target)
                else
                    CS.UnityEngine.Object.Destroy(target)
                end
                GameUtils.SyncDestoryGo(path,isImmediate)
                if nextConfigIdList then
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end 
            end
        end
    end
    
    --设置对象旋转   target:设置对象   isLocal:是否本地坐标旋转  time:旋转所需时间    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.Rotation( target , isLocal , time , rx , ry , rz , nextConfigIdList )
         if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local tween
                if isLocal then
                    tween = target.transform:DOLocalRotate(Vector3(rx, ry, rz), time):SetEase(Ease.Linear)
                else
                    tween = target.transform:DORotate(Vector3(rx, ry, rz), time):SetEase(Ease.Linear)
                end
                local sta = target:GetComponent("SyncTransformAction")
                if sta == nil then
                    target:AddComponent(typeof(SyncTransformAction))
                end
                tween:OnComplete(function ( ... )
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end
                end)
            end
        end
    end
    
    --设置对象缩放   target:设置对象   time:缩放所需时间    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.Scale( target , time , sx , sy , sz , nextConfigIdList )
         if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local tween
                tween = target.transform:DOScale(Vector3(sx, sy, sz), time):SetEase(Ease.Linear)
                local sta = target:GetComponent("SyncTransformAction")
                if sta == nil then
                    target:AddComponent(typeof(SyncTransformAction))
                end
                tween:OnComplete(function ( ... )
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end
                end)
            end
        end
    end
    
    --设置主角位置  target:设置对象   px:x值   py:y值   pz:z值   lookTarget:面对的对象   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetPlayerTransform( px , py , pz , lookTarget , nextConfigIdList )
        local target = nil
        if lookTarget ~= nil then
            target = ConfigHelpers.FindGameObject(lookTarget)
        end
        GameUtils.SetPlayerTransform(px,py,pz,target and target.transform or nil) 
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end   
    end
    
    --设置文本内容  target:设置对象   content:内容    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetText( target , content , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local text = target:GetComponent('Text')
                if text then
                    local sta = target:GetComponent("SyncTextAction")
                    if sta == nil then
                        target:AddComponent(typeof(SyncTextAction))
                    end
                    text.text = tostring(content)
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end   
                end
            end
        end
    end
    
    --移动位置   target:设置对象   isLocal:是否是本地坐标   time:移动所需时间  nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.MoveToTarget( target , isLocal , px , py , pz , rx , ry , rz , time , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                rx = rx or 0
                ry = ry or 0
                rz = rz or 0
                local sta = target:GetComponent("SyncTransformAction")
                if sta == nil then
                    target:AddComponent(typeof(SyncTransformAction))
                end
                GameUtils.MoveToTarget(target,isLocal,px,py,pz,rx,ry,rz ,time,function ( ... )
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end
                end)
            end
        end
    end
    
    local dataLibrary = {}
    --设置数据   dataName:数据名称   dataValue:数据的值   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetData( dataName , dataValue , nextConfigIdList )
        dataLibrary[dataName] = dataValue
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --获取数据   dataName:数据名称   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.GetData( dataName , nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return dataLibrary[dataName]
    end
    
    -- local needExecNextConfigIdList
    -- function ConfigHelpers.SceneLoaded( scene , mode )
    --     LoadConfig(scene.name,needExecNextConfigIdList)
    --     SceneManager.sceneLoaded('-', ConfigHelpers.SceneLoaded)
    -- end
    
    --切换场景    sceneName:要切换的场景    nextConfigIdList:完成过后要执行的id集合
    function ChangseSceneClearData()
        -- needExecNextConfigIdList = nextConfigIdList
        -- SceneManager.sceneLoaded('+', ConfigHelpers.SceneLoaded)
        -- SceneManager.LoadSceneAsync(sceneName)
        ConfigHelpers.CloseAudio()
        ConfigHelpers.ClearLongPressMove()
        followMeDic = {}
        lookAtDic = {}
        MF.Route.ClearUpdate()
        ConfigHelpers.SetRaySelectListenerStatus(true)
        ConfigHelpers.StopAllCoroutine()
    end
    
    --切换场景    sceneName:要切换的场景    nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.ChangeScene( sceneName , nextConfigIdList )
        -- needExecNextConfigIdList = nextConfigIdList
        -- SceneManager.sceneLoaded('+', ConfigHelpers.SceneLoaded)
        -- SceneManager.LoadSceneAsync(sceneName)
        GameUtils.LoadScene(sceneName,nextConfigIdList,nil,nil)
    end
    
    --停止已经开始的所有流程
    function ConfigHelpers.StopAllCoroutine( nextConfigIdList )
        GameUtils.StopAllCoroutine()
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --设置摄像机远近
    function ConfigHelpers.SetCameraNearFar( near , far , nextConfigIdList )
        GameUtils.SetNearFar(near,far)
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --切换操作模式(手柄或者凝视)
    function ConfigHelpers.ChangeEventMode( isHandle , nextConfigIdList )
        GameUtils.ChangeEventMode(isHandle)
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --为按钮注册事件  target:设置对象   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.RegisterClick( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target and nextConfigIdList then
                GameUtils.RegisterClick(target,function ( ... )
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end)
            end
        end
    end
    
    function ConfigHelpers.RemoveClick( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                GameUtils.RemoveClick(target)
            end
            if nextConfigIdList then
                ConfigHelpers.ExecIdList(nextConfigIdList)
            end
        end
    end
    
    function ConfigHelpers.OnMouseEnter( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target and nextConfigIdList then
                GameUtils.OnMouseEnter(target,function ( ... )
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end)
            end
        end
    end
    
    function ConfigHelpers.RemoveMouseEnter( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                GameUtils.RemoveMouseEnter(target)
            end
            if nextConfigIdList then
                ConfigHelpers.ExecIdList(nextConfigIdList)
            end
        end
    end
    
    function ConfigHelpers.OnMouseExit( target , nextConfigIdList )
       if target then
            target = ConfigHelpers.FindGameObject(target)
            if target and nextConfigIdList then
                GameUtils.OnMouseExit(target,function ( ... )
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end)
            end
        end
    end
    
    function ConfigHelpers.RemoveMouseExit( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                GameUtils.RemoveMouseExit(target)
            end
            if nextConfigIdList then
                ConfigHelpers.ExecIdList(nextConfigIdList)
            end
        end
    end
    
    function ConfigHelpers.SetRaySelectListenerStatus( active , nextConfigIdList )
        GameUtils.SetRaySelectListenerStatus(active)
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --设置父物体    target:设置对象   parent:父物体   nextConfigIdList:完成过后要执行的id集合
    function ConfigHelpers.SetParent( target , parent , px , py , pz , rx , ry , rz , sx , sy , sz , nextConfigIdList )
        if target and parent then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                parent = ConfigHelpers.FindGameObject(parent)
                if parent then
                    local sta = target:GetComponent("SyncTransformAction")
                    if sta == nil then
                        target:AddComponent(typeof(SyncTransformAction))
                    end
                    local t = target.transform
                    t:SetParent(parent.transform)
                    t.localPosition = Vector3( px , py , pz )
                    t.localEulerAngles = Vector3( rx , ry , rz )
                    t.localScale = Vector3( sx , sy , sz )
                    sta:UpdateTargetPath()
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end
                end
            end
        end
    end
    
    --跟随摄像机   target:目标对象  isFollow:是否跟随  distance:面向的距离  nextConfigIdList:执行的id集合
    local followMeDic = {}
    function ConfigHelpers.FollowMe( target , isFollow , ver , hor , distance , nextConfigIdList)
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                if isFollow then
                    local sta = target:GetComponent("SyncTransformAction")
                    if sta == nil then
                        target:AddComponent(typeof(SyncTransformAction))
                    end
                    local player = GameObject.Find('FrameWork/Customs/ViveFocus/WaveVR/head').transform
                    distance = distance or 4  
                    ver = ver or 0
                    hor = hor or 0
                    local spanEulerAngles = target.transform.eulerAngles - player.eulerAngles
                    followMeDic[target] = true
                    GameUtils.StartCoroutineWaitUntil(function ( ... )
                        local v = player.position
                        local result = v + (player.forward * distance)  + (player.right * hor)  + (player.up * ver)
                        target.transform.position = result
                        target.transform.eulerAngles = spanEulerAngles + player.eulerAngles
                        return not followMeDic[target]
                    end)
                else
                    followMeDic[target] = nil
                end
                if nextConfigIdList then
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end
            end
        end
    end
    
    --跟随摄像机   target:目标对象  isStop:是否停止面向自己(默认为false)
    local lookAtDic = {}
    function ConfigHelpers.LookMe( target , isStop , nextConfigIdList)
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local sta = target:GetComponent("SyncTransformAction")
                if sta == nil then
                    target:AddComponent(typeof(SyncTransformAction))
                end
                local player = GameObject.Find('FrameWork/Customs/ViveFocus/WaveVR/head').transform
                if not isStop then
                    lookAtDic[target] = true
                    local isUI = GameUtils.IsUI(target)
                    GameUtils.StartCoroutineWaitUntil(function ( ... )
                        target.transform:LookAt(player.position)
                        if isUI then
                            target.transform:Rotate(Vector3.up, 180)
                        end
                        return not lookAtDic[target]
                    end)
                else
                    lookAtDic[target] = nil
                end
                if nextConfigIdList then
                    ConfigHelpers.ExecIdList(nextConfigIdList)
                end
            end
        end
    end
    
    --播放视频   target:目标对象   videoName:视频名称(视频放到StreamingAssets文件夹下才有效)  isLoop:是否重复播放(默认重复)  nextConfigIdList:如果isLoop是true的话,那么会立马执行id集合,否则会等视频播放完才执行id集合
    function ConfigHelpers.PlayVedio( target , videoName , isLoop , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                target:SetActive(false)
                isLoop = (isLoop == nil and {false} or {isLoop})[1]
                local mp = target:GetComponent('MediaPlayerCtrl')
                if mp == nil then
                    mp = target:AddComponent(typeof(MediaPlayerCtrl))
                end
                mp.m_TargetMaterial = { target }
                -- mp.m_objResize = { target }
                mp:Load(videoName)
                mp.m_bLoop = isLoop
                mp:Play()
                target:SetActive(true)
                if isLoop then
                    if nextConfigIdList then
                        ConfigHelpers.ExecIdList(nextConfigIdList)
                    end
                else
                    mp.OnEnd = function ( ... )
                        if nextConfigIdList then
                            ConfigHelpers.ExecIdList(nextConfigIdList)
                        end
                    end
                end            
            end
        end
    end
    
    --获取手柄在圆形区域的触摸点
    function ConfigHelpers.GetTouchPadPosition( nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return GameUtils.GetTouchPadPosition()
    end
    
    --判断手柄上某键是否按下或者鼠标左键是否按下
    function ConfigHelpers.GetKeyDown( keycode , nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return GameUtils.GetKeyDown(keycode)
    end
    
    --判断手柄上某键是否抬起或者鼠标左键是否抬起
    function ConfigHelpers.GetKeyUp( keycode , nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return GameUtils.GetKeyUp(keycode)
    end
    
    --判断手柄上某键是否长按
    function ConfigHelpers.GetKey( keycode , nextConfigIdList )
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
        return GameUtils.GetKey(keycode)
    end
    
    --增加物体长按拖动
    function ConfigHelpers.AddLongPressMove( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                local sta = target:GetComponent("SyncTransformAction")
                if sta == nil then
                    target:AddComponent(typeof(SyncTransformAction))
                end
                GameUtils.AddLongPressMove(target)
            end
        end
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --移除物体长按拖动
    function ConfigHelpers.RemoveLongPressMove( target , nextConfigIdList )
        if target then
            target = ConfigHelpers.FindGameObject(target)
            if target then
                GameUtils.RemoveLongPressMove(target)
            end
        end
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    --清除所有能拖拽物体的状态,使之不能被拖拽
    function ConfigHelpers.ClearLongPressMove( nextConfigIdList )
        GameUtils.ClearLongPressMove()
        if nextConfigIdList then
            ConfigHelpers.ExecIdList(nextConfigIdList)
        end
    end
    
    function ConfigHelpers.ExecId( id )
        if id == nil then
            Print_t('<color=red>This ID is illegal</color>')
            return
        end
        if ConfigGlobal[id] == nil or ConfigGlobal[id].action == nil then
            Print_t('<color=red>This ID does not exist = '..id..'</color>')
            return
        end
        Print_t(id..' = '..ConfigGlobal[id].action)
        if ConfigGlobal[id].action then
            -- assert(load(ConfigGlobal[id].action))()
            xpcall(load(ConfigGlobal[id].action),function ( ... )
                Print_t(debug.traceback(),'<color=red>error</color>')
            end)
        end
    end
    
    function ConfigHelpers.ExecIdList( idListOrFunc )
        if idListOrFunc then
            if type(idListOrFunc) == 'table' then
                for i,id in ipairs(idListOrFunc) do
                    ConfigHelpers.ExecId(id)
                end
            else
                idListOrFunc()
            end
        end
    end
    
    function ConfigHelpers.FindGameObject( path )
        if path and path ~= '' then
            local target = GameObject.Find(path)
            if target then
                return target
            else
                local startIndex = string.find(path,'/')
                if startIndex then
                    local rootPath = string.sub(path,0,startIndex-1)
                    local root = GameObject.Find('/'..rootPath)
                    if root then
                        local childPath = string.sub(path,startIndex+1,path.length)
                        local result = root.transform:Find(childPath)
                        if result then
                            return result.gameObject
                        end
                    end
                end
            end
        end
        Print_t('<color=red>error:</color>No object was found = '..(path or ''))
        return nil
    end
    
    --总秒数格式化   传总秒数   返回的时间格式为 59:34   第二个参数表示是否显示小时
    function ConfigHelpers.FormatSecond( senconds , isShowHour )
        local min,sec = math.modf(senconds / 60)
        local hour,sec = math.modf(senconds / 3600)
    
        sec = math.floor(senconds - min*60)
        if sec < 10 then
           sec = '0'..sec
        end
        if hour < 10 then
           hour = '0'..hour
        end
        local t = min ..':'..sec
        return isShowHour and hour..t or t
    end
    
    return ConfigHelpers
    ConfigHelpers
  • 相关阅读:
    Java里if...else语句
    Java里for循环和增强版循环;break语句:跳出循环;continue:跳转循环
    Java里while循环和do...while循环
    static 修饰符
    Java类变量(静态变量)
    Java实例变量
    Java局部变量
    Java访问实例变量和调用成员方法
    Java里import语句使用
    声明式服务调用
  • 原文地址:https://www.cnblogs.com/MrZivChu/p/hr.html
Copyright © 2011-2022 走看看