三国卡牌客户端基础资源仓库
yyl
2026-03-04 e16af931f6624da01566311524aaf6956f54a3df
466 h5版本 资源规则修改 打包修改(未完成 勿拉取)
16个文件已修改
2个文件已添加
532 ■■■■■ 已修改文件
Assets/AssetBundleCollectorSetting.asset 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/ConfigGen/ConfigGenerater.cs 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/ClientPackage.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/ClientPackage_Standalone.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/PrefabCreateTool.cs 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/Tool/WindowTool.cs 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/UI/UIAdjustEditor.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Editor/YooAsset/YooAssetBuildTool.cs 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/DownLoadAndDiscompressTask.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/LocalSave.cs 270 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Common/ResourcesPath.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Launch.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/Manager/LocalResManager.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/UI/LaunchWins/LaunchExWin.cs 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/Launch/VersionConfigEx.cs 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/WXGameDefine.cs 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/WXGameDefine.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ProjectSettings/ProjectSettings.asset 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Assets/AssetBundleCollectorSetting.asset
@@ -33,7 +33,7 @@
      - CollectPath: Assets/ResourcesOut/UI
        CollectorGUID: 0a5282bb472d1144ab08a2d07b5a3801
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -41,7 +41,7 @@
      - CollectPath: Assets/ResourcesOut/UIComp
        CollectorGUID: cafb96babf67f0e47aa47d7bd7e851f9
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -49,7 +49,7 @@
      - CollectPath: Assets/ResourcesOut/Sprite
        CollectorGUID: d525c1ea56911ef46968923700fee47f
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -57,7 +57,7 @@
      - CollectPath: Assets/ResourcesOut/Texture
        CollectorGUID: cc4265f3ee528e64e8afa76bd8f7d3f7
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -108,7 +108,7 @@
      - CollectPath: Assets/ResourcesOut/Materials
        CollectorGUID: 676c8b4532d6ca646804bf73ed43dd96
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -116,7 +116,7 @@
      - CollectPath: Assets/ResourcesOut/ScriptableObject
        CollectorGUID: 1482db32e9d88d444bc22e54075bf994
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -124,7 +124,7 @@
      - CollectPath: Assets/ResourcesOut/Scenes
        CollectorGUID: b3332ee13576c994186d5570af59b0b6
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -132,7 +132,7 @@
      - CollectPath: Assets/ResourcesOut/Config
        CollectorGUID: 6a0e1d814ea59174985b17c9f4ecaba3
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -168,7 +168,7 @@
      - CollectPath: Assets/ResourcesOut/UIEffect
        CollectorGUID: 62eb3abc624381e4b8950f355812a8e9
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileNameWithExt
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -190,7 +190,7 @@
      - CollectPath: Assets/ResourcesOut/Hero
        CollectorGUID: 4ef1d5e33efbd83438f79bd2fd7c44ac
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -198,7 +198,7 @@
      - CollectPath: Assets/ResourcesOut/Battle
        CollectorGUID: f4b5330ed101c7b4c8cbfba3f0daff9f
        CollectorType: 0
        AddressRuleName: AddressByFolderAndFileName
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags: 
@@ -225,3 +225,47 @@
        FilterRuleName: CollectAll
        AssetTags: 
        UserData: 
  - PackageName: Video
    PackageDesc: video resources
    EnableAddressable: 1
    SupportExtensionless: 1
    LocationToLower: 0
    IncludeAssetGUID: 1
    AutoCollectShaders: 1
    IgnoreRuleName: NormalIgnoreRule
    Groups:
    - GroupName: Prefab
      GroupDesc:
      AssetTags:
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/Video
        CollectorGUID:
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
  - PackageName: Builtin
    PackageDesc: builtin resources
    EnableAddressable: 1
    SupportExtensionless: 1
    LocationToLower: 0
    IncludeAssetGUID: 1
    AutoCollectShaders: 1
    IgnoreRuleName: NormalIgnoreRule
    Groups:
    - GroupName: Prefab
      GroupDesc:
      AssetTags:
      ActiveRuleName: EnableGroup
      Collectors:
      - CollectPath: Assets/ResourcesOut/BuiltIn
        CollectorGUID: e5f9df9a324df2b46b1a92fa8da26b67
        CollectorType: 0
        AddressRuleName: AddressByRelativePath
        PackRuleName: PackDirectory
        FilterRuleName: CollectAll
        AssetTags:
        UserData:
Assets/Editor/ConfigGen/ConfigGenerater.cs
@@ -40,29 +40,55 @@
    {
        try
        {
            // 获取所有配置类
            List<string> configClasses = GetAllConfigClasses();
            // 1. 获取所有配置类(去除排除项)
            List<string> configClasses = GetAllConfigClasses()
                .Where(c => !ExcludeClassList.Contains(c))
                .Where(c => !string.IsNullOrEmpty(c) && char.IsUpper(c[0]))
                .ToList();
            if (System.IO.File.Exists(Path.Combine(Application.dataPath, "fastConfig.txt")))
            // 2. 自动生成 ConfigManager.cs 的 LoadConfigs 方法,全部异步加载
            string configManagerPath = Path.Combine(Application.dataPath, ConfigManagerPath.Replace("Assets/", ""));
            var lines = File.ReadAllLines(configManagerPath).ToList();
            // 查找 LoadConfigs 方法起止行
            int startIdx = lines.FindIndex(l => l.Contains("protected async UniTask LoadConfigs()"));
            int openBrace = lines.FindIndex(startIdx, l => l.Trim() == "{");
            int endIdx = openBrace;
            int braceCount = 1;
            for (int i = openBrace + 1; i < lines.Count; i++)
            {
                // 如果存在 fastConfig.txt 文件,读取其中的配置类
                string[] fastConfigs = System.IO.File.ReadAllLines(Path.Combine(Application.dataPath, "fastConfig.txt"));
                ExcludeClassList.AddRange(fastConfigs);
                if (lines[i].Contains("{")) braceCount++;
                if (lines[i].Contains("}")) braceCount--;
                if (braceCount == 0) { endIdx = i; break; }
            }
            configClasses = new List<string>(configClasses.Where(config => !ExcludeClassList.Contains(config)));
            // 生成 configTypes 初始化代码
            var configTypeLines = new List<string>();
            configTypeLines.Add("        // 自动生成:收集所有配置类型");
            configTypeLines.Add("        HashSet<Type> configTypes = new HashSet<Type>() {");
            for (int i = 0; i < configClasses.Count; i++)
            {
                configTypeLines.Add($"            typeof({configClasses[i]}){(i < configClasses.Count - 1 ? "," : "")}");
            }
            configTypeLines.Add("        };");
            // 生成配置管理器代码
            GenerateConfigManager(configClasses);
            Debug.Log($"配置管理器生成完成,共找到 {configClasses.Count} 个配置类: {string.Join(", ", configClasses)}");
            // 刷新资源
            // 替换原有 configTypes 初始化段
            int configTypesStart = lines.FindIndex(startIdx, l => l.Contains("HashSet<Type> configTypes"));
            int configTypesEnd = configTypesStart;
            while (configTypesEnd < lines.Count && !lines[configTypesEnd].Trim().EndsWith("};")) configTypesEnd++;
            configTypesEnd++;
            lines.RemoveRange(configTypesStart, configTypesEnd - configTypesStart);
            lines.InsertRange(configTypesStart, configTypeLines);
            // 保存文件
            File.WriteAllLines(configManagerPath, lines);
            Debug.Log($"ConfigManager.cs 自动生成 LoadConfigs 配置类型成功,共 {configClasses.Count} 个类型。");
            AssetDatabase.Refresh();
        }
        catch (Exception ex)
        {
            Debug.LogError($"生成配置管理器时发生错误: {ex.Message}\n{ex.StackTrace}");
            Debug.LogError($"自动生成 ConfigManager.LoadConfigs 时发生错误: {ex.Message}\n{ex.StackTrace}");
        }
    }
    
Assets/Editor/Tool/ClientPackage.cs
@@ -69,7 +69,7 @@
    /// <param name="_buildIndex">打包序序号,用于标识名称</param>
    /// <param name="_development">是否为开发版</param>
    /// <param name="_replace">ios打包导出xcode工程模式,Append和Replace</param>
    public static void BuildPublishers(string _sdkPath, string _assetBundlePath, string _output, string _publisherString, int _buildIndex, bool _development, bool _replace)
    public static async void BuildPublishers(string _sdkPath, string _assetBundlePath, string _output, string _publisherString, int _buildIndex, bool _development, bool _replace)
    {
        var publisherIds = new List<string>();
@@ -187,7 +187,7 @@
        if (halfPackages.Count > 0)
        {
            PriorBundleConfig.LazyInit();
            await PriorBundleConfig.LazyInitAsync();
            var fromFiles = new List<FileInfo>();
            FileExtersion.GetAllDirectoryFileInfos(_assetBundlePath, fromFiles);
Assets/Editor/Tool/ClientPackage_Standalone.cs
@@ -6,6 +6,8 @@
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
using System.Threading.Tasks;
using Cysharp.Threading.Tasks;
//using Beebyte.Obfuscator;
public class ClientPackage_Standalone
@@ -37,7 +39,7 @@
        public bool development;
    }
    public static void Build(BuildParams buildParams)
    public static async Task Build(BuildParams buildParams)
    {
        var packageIds = new List<int>();
        var tempStrings = buildParams.publisher.Split(StringUtility.splitSeparator, StringSplitOptions.RemoveEmptyEntries);
@@ -85,7 +87,7 @@
        }
        BuildSmallPackage(smallPackages, buildParams.assetBundle, buildParams.output, buildParams.buildIndex, buildParams.development);
        BuildMiddlePackage(middlePackages, buildParams.assetBundle, buildParams.output, buildParams.buildIndex, buildParams.development);
        await BuildMiddlePackage(middlePackages, buildParams.assetBundle, buildParams.output, buildParams.buildIndex, buildParams.development);
        BuildBigPackage(bigPackages, buildParams.assetBundle, buildParams.output, buildParams.buildIndex, buildParams.development);
    }
@@ -136,7 +138,7 @@
        }
    }
    static void BuildMiddlePackage(List<int> packageIds, string assetPath, string output, int buildIndex, bool development)
    static async Task BuildMiddlePackage(List<int> packageIds, string assetPath, string output, int buildIndex, bool development)
    {
        if (Directory.Exists(ResourcesPath.Instance.StreamingAssetPath))
        {
@@ -148,7 +150,7 @@
            return;
        }
        PriorBundleConfig.LazyInit();
        await PriorBundleConfig.LazyInitAsync();
        var fromFiles = new List<FileInfo>();
        FileExtersion.GetAllDirectoryFileInfos(assetPath, fromFiles);
Assets/Editor/Tool/PrefabCreateTool.cs
@@ -6,6 +6,7 @@
using UnityEditor;
using System.Collections;
using UnityEngine.UI;
using Cysharp.Threading.Tasks;
public class PrefabCreateTool
@@ -73,9 +74,9 @@
    }
    [MenuItem("GameObject/UI/FunctionButton")]
    public static void CreateFunctionButton()
    public static async UniTask CreateFunctionButton()
    {
        var instance = UIUtility.CreateWidget("FunctionButtonPattern", "FunctionButton");
        var instance = await UIUtility.CreateWidget("FunctionButtonPattern", "FunctionButton");
        SetParent(instance);
    }
@@ -115,9 +116,9 @@
    }
    [MenuItem("GameObject/UI/ItemCell")]
    public static void CreateItemCell()
    public static async UniTask CreateItemCell()
    {
        var button = UIUtility.CreateWidget("ItemCell", "ItemCell");
        var button = await UIUtility.CreateWidget("ItemCell", "ItemCell");
        SetParent(button);
    }
@@ -168,9 +169,9 @@
    }
    [MenuItem("GameObject/UI/通用按钮")]
    public static void CreateButtonEx()
    public static async UniTask CreateButtonEx()
    {
        var button = UIUtility.CreateWidget("CommonButton", "CommonButton");
        var button = await UIUtility.CreateWidget("CommonButton", "CommonButton");
        var buttonEx = button.GetComponent<ButtonEx>();
        buttonEx.interval = 0.1f;
        buttonEx.pressedScale = 1.05f;
@@ -178,9 +179,9 @@
    }
    [MenuItem("GameObject/UI/红点")]
    public static void CreateRedPoint()
    public static async UniTask CreateRedPoint()
    {
        var button = UIUtility.CreateWidget("RedPoint", "RedPoint");
        var button = await UIUtility.CreateWidget("RedPoint", "RedPoint");
        SetParent(button);
    }
@@ -194,9 +195,9 @@
    }
    [MenuItem("GameObject/UI/二级带功能框")]
    public static void CreateSecondLevelWin()
    public static async UniTask CreateSecondLevelWin()
    {
        var prefab = UIUtility.CreateWidget("SecondLevelWin", "Panel");
        var prefab = await UIUtility.CreateWidget("SecondLevelWin", "Panel");
        SetParent(prefab);
        var rectTransform = prefab.GetComponent<RectTransform>();
        // 完全填充父容器
Assets/Editor/Tool/WindowTool.cs
@@ -1,6 +1,7 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
public class WindowTool : EditorWindow
{
@@ -59,7 +60,7 @@
        if (GUILayout.Button("打开"))
        {
            // 打开窗口逻辑
            UIManager.Instance.OpenWindow(windowName);
            UIManager.Instance.OpenWindow(windowName).Forget();
        }
        if (GUILayout.Button("关闭"))
        {
@@ -73,7 +74,7 @@
                UIManager.Instance.CloseWindow(win);
            }
            UIManager.Instance.OpenWindow("BattleWin");
            UIManager.Instance.OpenWindow("BattleWin").Forget();
        }
        EditorGUILayout.EndHorizontal();
Assets/Editor/UI/UIAdjustEditor.cs
@@ -1,6 +1,7 @@
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
public class UIAdjustEditor : EditorWindow
{
@@ -27,7 +28,7 @@
        {
            if (Application.isPlaying && !string.IsNullOrEmpty(uiName))
            {
                UIManager.Instance.OpenWindow(uiName);
                UIManager.Instance.OpenWindow(uiName).Forget();
            }
            else
            {
Assets/Editor/YooAsset/YooAssetBuildTool.cs
@@ -16,7 +16,7 @@
    /// <summary>
    /// 所有需要打包的 Package 名称(与 AssetBundleCollectorSetting 一致)
    /// </summary>
    private static readonly string[] ALL_PACKAGES = { "Prefab", "UI", "UIEffect", "Battle", "Audio" };
    private static readonly string[] ALL_PACKAGES = { "Prefab", "UI", "UIEffect", "Battle", "Audio", "Video", "Builtin" };
    /// <summary>
    /// 版本号格式:日期+时间
@@ -135,6 +135,11 @@
    [MenuItem("YooAsset工具/打包单个Package/Audio", false, 304)]
    private static void BuildAudio() => BuildSingleWithDialog("Audio");
    [MenuItem("YooAsset工具/打包单个Package/Video", false, 305)]
    private static void BuildVideo() => BuildSingleWithDialog("Video");
     [MenuItem("YooAsset工具/打包单个Package/Builtin", false, 306)]
    private static void BuildBuiltin() => BuildSingleWithDialog("Builtin");
    private static void BuildSingleWithDialog(string packageName)
    {
Assets/Launch/Common/DownLoadAndDiscompressTask.cs
@@ -74,7 +74,8 @@
            for (int i = 0; i < tasks.Count; i++)
            {
                var assetVersion = tasks[i];
                var remoteURL = StringUtility.Concat(LocalResManager.Instance.versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), LocalResManager.fixPath, "/", assetVersion.relativePath);
                VersionConfigEx config = await VersionConfigEx.Get();
                var remoteURL = StringUtility.Concat(LocalResManager.Instance.versionInfo.GetResourcesURL(config.branch), LocalResManager.fixPath, "/", assetVersion.relativePath);
                var localURL = StringUtility.Concat(LocalResManager.Instance.ExternalStorePath, assetVersion.relativePath);
                DownloadMgr.Instance.AddTask(new DownloadTask(remoteURL, localURL));
            }
Assets/Launch/Common/LocalSave.cs
@@ -7,216 +7,192 @@
using System;
using System.Threading.Tasks;
#if WX_GAME
using UnityEngine;
using System.Runtime.InteropServices;
#endif
using Cysharp.Threading.Tasks;
public static class LocalSave
{
// WX_GAME 下通过 JSBridge 调用同步 API
#if WX_GAME
using UnityEngine;
using System.Runtime.InteropServices;
    [DllImport("__Internal")]
    private static extern void WXSetStorageSync(string key, string value);
    [DllImport("__Internal")]
    private static extern string WXGetStorageSync(string key);
    [DllImport("__Internal")]
    private static extern void WXRemoveStorageSync(string key);
    [DllImport("__Internal")]
    private static extern void WXClearStorageSync();
#endif
    public static void DeleteAll()
    // --- 同步接口 ---
    public static void SetString(string key, string value)
    {
        PlayerPrefs.DeleteAll();
#if WX_GAME
        WXSetStorageSync(key, value);
#else
        PlayerPrefs.SetString(key, value);
#endif
    }
    public static void DeleteKey(string _key)
    public static string GetString(string key, string defaultValue = "")
    {
        PlayerPrefs.DeleteKey(_key);
    }
    public static bool HasKey(string _key)
    {
        return PlayerPrefs.HasKey(_key);
#if WX_GAME
        var v = WXGetStorageSync(key);
        return string.IsNullOrEmpty(v) ? defaultValue : v;
#else
        if (!PlayerPrefs.HasKey(key)) return defaultValue;
        return PlayerPrefs.GetString(key);
#endif
    }
    public static void SetInt(string key, int value)
    {
        PlayerPrefs.SetInt(key, value);
        SetString(key, value.ToString());
    }
    public static int GetInt(string key, int _default = 0)
    public static int GetInt(string key, int defaultValue = 0)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return _default;
        }
        else
        {
            return PlayerPrefs.GetInt(key);
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return defaultValue;
        int.TryParse(str, out var v);
        return v;
    }
    public static void SetFloat(string key, float value)
    {
        PlayerPrefs.SetFloat(key, value);
        SetString(key, value.ToString());
    }
    public static float GetFloat(string key, float _default = 0f)
    public static float GetFloat(string key, float defaultValue = 0f)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return _default;
        }
        else
        {
            return PlayerPrefs.GetFloat(key);
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return defaultValue;
        float.TryParse(str, out var v);
        return v;
    }
    public static void SetBool(string key, bool value)
    {
        PlayerPrefs.SetInt(key, value ? 1 : 0);
        SetInt(key, value ? 1 : 0);
    }
    public static bool GetBool(string key, bool _default = false)
    public static bool GetBool(string key, bool defaultValue = false)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return _default;
        }
        else
        {
            return PlayerPrefs.GetInt(key) == 1;
        }
    }
    public static void SetString(string key, string value)
    {
        PlayerPrefs.SetString(key, value);
    }
    public static string GetString(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return string.Empty;
        }
        else
        {
            return PlayerPrefs.GetString(key);
        }
        var v = GetInt(key, defaultValue ? 1 : 0);
        return v == 1;
    }
    public static void SetVector3(string key, Vector3 value)
    {
        var sb = new StringBuilder();
        sb.Append(value.x);
        sb.Append(";");
        sb.Append(value.y);
        sb.Append(";");
        sb.Append(value.z);
        PlayerPrefs.SetString(key, sb.ToString());
        var str = $"{value.x};{value.y};{value.z}";
        SetString(key, str);
    }
    public static Vector3 GetVector3(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return Vector3.zero;
        }
        else
        {
            var v = new Vector3();
            var strArray = PlayerPrefs.GetString(key).Split(';');
            v.x = float.Parse(strArray[0]);
            v.y = float.Parse(strArray[2]);
            v.z = float.Parse(strArray[4]);
            return v;
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return Vector3.zero;
        var arr = str.Split(';');
        if (arr.Length != 3) return Vector3.zero;
        float.TryParse(arr[0], out var x);
        float.TryParse(arr[1], out var y);
        float.TryParse(arr[2], out var z);
        return new Vector3(x, y, z);
    }
    public static void SetIntArray(string key, int[] value)
    {
        if (value != null && value.Length > 0)
        if (value == null || value.Length == 0)
        {
            var sb = new StringBuilder();
            for (var i = 0; i < value.Length; i++)
            {
                sb.Append(value[i]);
                sb.Append(';');
            }
            sb.Remove(sb.Length - 1, 1);
            PlayerPrefs.SetString(key, sb.ToString());
            DeleteKey(key);
            return;
        }
        else
        {
            PlayerPrefs.DeleteKey(key);
        }
        var str = string.Join(";", value);
        SetString(key, str);
    }
    public static int[] GetIntArray(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return null;
        }
        else
        {
            var value = PlayerPrefs.GetString(key);
            var strArray = value.Split(';');
            var intArray = new int[strArray.Length];
            for (var i = 0; i < strArray.Length; i++)
            {
                int.TryParse(strArray[i], out intArray[i]);
            }
            return intArray;
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return null;
        var arr = str.Split(';');
        var result = new int[arr.Length];
        for (int i = 0; i < arr.Length; i++)
            int.TryParse(arr[i], out result[i]);
        return result;
    }
    public static void SetFloatArray(string key, float[] value)
    {
        var sb = new StringBuilder();
        for (var i = 0; i < value.Length; i++)
        if (value == null || value.Length == 0)
        {
            sb.Append(value[i]);
            sb.Append(";");
            DeleteKey(key);
            return;
        }
        sb.Remove(sb.Length - 1, 1);
        PlayerPrefs.SetString(key, sb.ToString());
        var str = string.Join(";", value);
        SetString(key, str);
    }
    public static float[] GetFloatArray(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return null;
        }
        else
        {
            var value = PlayerPrefs.GetString(key);
            var strArray = value.Split(';');
            var array = new float[strArray.Length];
            for (var i = 0; i < strArray.Length; i++)
            {
                float.TryParse(strArray[i], out array[i]);
            }
            return array;
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return null;
        var arr = str.Split(';');
        var result = new float[arr.Length];
        for (int i = 0; i < arr.Length; i++)
            float.TryParse(arr[i], out result[i]);
        return result;
    }
    public static void SetStringArray(string key, string[] value)
    {
        var valueGroup = string.Join(";", value);
        PlayerPrefs.SetString(key, valueGroup);
        if (value == null || value.Length == 0)
        {
            DeleteKey(key);
            return;
        }
        var str = string.Join(";", value);
        SetString(key, str);
    }
    public static string[] GeStringArray(string key)
    {
        if (!PlayerPrefs.HasKey(key))
        {
            return null;
        }
        else
        {
            var value = PlayerPrefs.GetString(key);
            return value.Split(';');
        }
        var str = GetString(key, null);
        if (string.IsNullOrEmpty(str)) return null;
        return str.Split(';');
    }
    public static void DeleteKey(string key)
    {
#if WX_GAME
        WXRemoveStorageSync(key);
#else
        PlayerPrefs.DeleteKey(key);
#endif
    }
    public static void DeleteAll()
    {
#if WX_GAME
        WXClearStorageSync();
#else
        PlayerPrefs.DeleteAll();
#endif
    }
    public static bool HasKey(string key)
    {
#if WX_GAME
        var v = WXGetStorageSync(key);
        return !string.IsNullOrEmpty(v);
#else
        return PlayerPrefs.HasKey(key);
#endif
    }
}
Assets/Launch/Common/ResourcesPath.cs
@@ -50,12 +50,17 @@
    public ResourcesPath()
    {
#if UNITY_ANDROID
        StreamingAssetPath = Application.streamingAssetsPath + "/android/";
#elif UNITY_IOS
        StreamingAssetPath = Application.streamingAssetsPath + "/ios/";
#if UNITY_EDITOR
            StreamingAssetPath = Application.dataPath + "/StreamingAssets/yoo/";
#else
        StreamingAssetPath = Application.streamingAssetsPath + "/standalone/";
    #if UNITY_ANDROID
            StreamingAssetPath = Application.streamingAssetsPath + "/android/";
    #elif UNITY_IOS
            StreamingAssetPath = Application.streamingAssetsPath + "/ios/";
    #else
            StreamingAssetPath = Application.streamingAssetsPath + "/standalone/";
    #endif
#endif
        if (!Application.isEditor)
Assets/Launch/Launch.cs
@@ -16,8 +16,6 @@
public class Launch : MonoBehaviour
{
#if UNITY_EDITOR
    public bool isOpenConfigTesting = false;
    public bool isOpenBattleDebug = false;
    public bool isOpenSkillLogFile = false;
@@ -90,15 +88,16 @@
    {
        try
        {
#if UNITY_EDITOR
            // 编辑器下:如果开启了 AB 模式(AssetSource.isUseAssetBundle),使用 OfflinePlayMode(随包模式)
            // 否则使用 EditorSimulateMode(无需打包即可运行)
            var playMode = AssetSource.isUseAssetBundle ? EPlayMode.OfflinePlayMode : EPlayMode.EditorSimulateMode;
#elif UNITY_WEBGL
#if UNITY_WEBGL
            // WebGL 平台(含 Editor 切到 WebGL target):BuildInFileSystem 不支持 WebGL,必须用 WebPlayMode
            var playMode = EPlayMode.WebPlayMode;
#elif UNITY_EDITOR
            // Editor 非 WebGL target:AB 模式开关控制(菜单:YooAsset工具/切换AB模式)
            var playMode = AssetSource.isUseAssetBundle ? EPlayMode.OfflinePlayMode : EPlayMode.EditorSimulateMode;
#else
            var playMode = EPlayMode.OfflinePlayMode;
#endif
            Debug.Log($"[Launch] Initializing YooAsset early with PlayMode={playMode}");
            await YooAssetInitializer.Instance.InitializeAsync(playMode);
Assets/Launch/Manager/LocalResManager.cs
@@ -191,9 +191,9 @@
        Debug.Log("提前ResManager.Release资源");
    }
    public void RequestVersionCheck()
    public async void RequestVersionCheck()
    {
        var versionConfig = VersionConfigEx.Get();
        var versionConfig = await VersionConfigEx.Get();
        var tables = new Dictionary<string, string>();
        tables["channel"] = versionConfig.appId;
        tables["versioncode"] = versionConfig.version;
@@ -212,7 +212,7 @@
        HttpRequest.Instance.RequestHttpGet(url, HttpRequest.defaultHttpContentType, 1, OnVersionCheckResult);
    }
    private void OnVersionCheckResult(bool _ok, string _result)
    private async void OnVersionCheckResult(bool _ok, string _result)
    {
        if (_ok)
        {
@@ -223,7 +223,8 @@
            assetVersions = localAssetVersions;
            step = LoadDllStep.ReadBytes;
#else
            if (VersionConfigEx.Get().assetAccess == VersionConfigEx.InstalledAsset.IngoreDownLoad)
            var versionConfig = await VersionConfigEx.Get();
            if (versionConfig.assetAccess == VersionConfigEx.InstalledAsset.IngoreDownLoad)
            {
                assetVersions = localAssetVersions;
                step = LoadDllStep.ReadBytes;
@@ -435,9 +436,10 @@
    }
    
    //LogicBytes文件的MD5信息
    public void RequestLogicBytes()
    public async void RequestLogicBytes()
    {
        var remoteURL = string.Concat(versionInfo.GetResourcesURL(VersionConfigEx.Get().branch), fixPath, "/logicbytes.txt");
        var config = await VersionConfigEx.Get();
        var remoteURL = string.Concat(versionInfo.GetResourcesURL(config.branch), fixPath, "/logicbytes.txt");
        //var localURL = string.Concat(.ExternalStorePath, "/logicbytes.txt");
        assetBytesUrl = remoteURL;
        Debug.Log("http地址:logicbytesUrl  " + assetBytesUrl);
Assets/Launch/UI/LaunchWins/LaunchExWin.cs
@@ -92,8 +92,14 @@
            m_IosProgressContainer.gameObject.SetActive(false);
            //打包版本 + 功能版本 + 语言ID
            m_Version.text = StringUtility.Concat(VersionConfigEx.Get().version, "_", VersionConfigEx.Get().buildIndex.ToString(),
                "_", InitialFunctionConfig.Get("version").Numerical1, " ", LocalResManager.Id);
            VersionConfigEx.Get().ContinueWith(config =>
             {
                 if (this == null) return; // destroyed check after await
                 m_Version.text = StringUtility.Concat(config.version, "_", config.buildIndex.ToString(),
                     "_", InitialFunctionConfig.Get("version").Numerical1, " ", LocalResManager.Id);
             }).Forget();
            // m_Version.text = StringUtility.Concat(VersionConfigEx.Get().version, "_", VersionConfigEx.Get().buildIndex.ToString(),
            //     "_", InitialFunctionConfig.Get("version").Numerical1, " ", LocalResManager.Id);
        }
Assets/Launch/VersionConfigEx.cs
@@ -1,5 +1,6 @@
using UnityEngine;
using LitJson;
using Cysharp.Threading.Tasks;
public class VersionConfigEx
{
@@ -159,12 +160,13 @@
    }
    static VersionConfigEx config = null;
    public static VersionConfigEx Get()
    public async static UniTask<VersionConfigEx> Get()
    {
        if (config == null)
        {
            var text = Resources.Load<TextAsset>("VersionConfigEx");
            var resRequest = Resources.LoadAsync<TextAsset>("VersionConfigEx");
            await resRequest;
            TextAsset text = resRequest.asset as TextAsset;
            if (text != null)
            {
                config = JsonMapper.ToObject<VersionConfigEx>(text.text);
Assets/WXGameDefine.cs
New file
@@ -0,0 +1,9 @@
// 微信小游戏平台宏定义
#if UNITY_WEBGL && !UNITY_EDITOR && WX_GAME
#define WX_GAME
#endif
// 用法示例:
// #if WX_GAME
// // 微信小游戏专用代码
// #endif
Assets/WXGameDefine.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 778f583ccb9424748b574c671e3be667
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
ProjectSettings/ProjectSettings.asset
@@ -77,6 +77,7 @@
  androidMinimumWindowHeight: 300
  androidFullscreenMode: 1
  androidAutoRotationBehavior: 1
  androidPredictiveBackSupport: 1
  defaultIsNativeResolution: 1
  macRetinaSupport: 1
  runInBackground: 1
@@ -84,6 +85,7 @@
  muteOtherAudioSources: 0
  Prepare IOS For Recording: 0
  Force IOS Speakers When Recording: 0
  audioSpatialExperience: 0
  deferSystemGesturesMode: 0
  hideHomeButton: 0
  submitAnalytics: 1
@@ -171,8 +173,6 @@
  AndroidBundleVersionCode: 1
  AndroidMinSdkVersion: 22
  AndroidTargetSdkVersion: 0
  AndroidMinSdkVersion: 24
  AndroidTargetSdkVersion: 28
  AndroidPreferredInstallLocation: 1
  aotOptions: 
  stripEngineCode: 1
@@ -187,8 +187,10 @@
  strictShaderVariantMatching: 0
  VertexChannelCompressionMask: 4054
  iPhoneSdkVersion: 988
  iOSSimulatorArchitecture: 0
  iOSTargetOSVersionString: 12.0
  tvOSSdkVersion: 0
  tvOSSimulatorArchitecture: 0
  tvOSRequireExtendedGameController: 0
  tvOSTargetOSVersionString: 12.0
  VisionOSSdkVersion: 0
@@ -583,6 +585,7 @@
  switchSocketBufferEfficiency: 4
  switchSocketInitializeEnabled: 1
  switchNetworkInterfaceManagerInitializeEnabled: 1
  switchDisableHTCSPlayerConnection: 0
  switchUseNewStyleFilepaths: 0
  switchUseLegacyFmodPriorities: 0
  switchUseMicroSleepForYield: 1
@@ -705,7 +708,7 @@
    Stadia: DOTWEEN
    Standalone: DOTWEEN
    VisionOS: DOTWEEN
    WebGL: DOTWEEN
    WebGL: DOTWEEN;H5_VERSION
    Windows Store Apps: DOTWEEN
    XboxOne: DOTWEEN
    iPhone: DOTWEEN