少年修仙传客户端代码仓库
client_linchunjie
2019-04-16 6dde220aad8d90ef32128c5de178db8c3d9c3e26
3335 缥缈仙域
9个文件已修改
4个文件已添加
652 ■■■■■ 已修改文件
Core/GameEngine/Model/Config/MapNpcRefreshConfig.cs 216 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/GameEngine/Model/Config/MapNpcRefreshConfig.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/NetworkPackage/ClientPack/ClientToMapServer/CA2_Interaction/CA234_tagCMGetCustomSceneCollectAward.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/NetworkPackage/ClientPack/ClientToMapServer/CA2_Interaction/CA234_tagCMGetCustomSceneCollectAward.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/NetworkPackage/DTCFile/ServerPack/HA3_Function/DTCA326_tagMCNPCIDCollectionCntInfo.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA714_tagMCNPCCntList.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
System/Dungeon/DungeonModel.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
System/Dungeon/DungeonTargetBehaviour.cs 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
System/HazyRegion/ClientHazyGrassStage.cs 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
System/HazyRegion/HazyGrassDungeonWin.cs 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
System/HazyRegion/HazyGrassModel.cs 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Utility/ConfigInitiator.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Utility/EnumHelper.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Core/GameEngine/Model/Config/MapNpcRefreshConfig.cs
New file
@@ -0,0 +1,216 @@
//--------------------------------------------------------
//    [Author]:           Fish
//    [  Date ]:           Tuesday, April 16, 2019
//--------------------------------------------------------
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System;
using UnityEngine;
[XLua.LuaCallCSharp]
public partial class MapNpcRefreshConfig
{
    public readonly int id;
    public readonly int MapID;
    public readonly int[] NPCIDList;
    public readonly int RefreshSeconds;
    public readonly int RefreshPerMinutes;
    public MapNpcRefreshConfig()
    {
    }
    public MapNpcRefreshConfig(string input)
    {
        try
        {
            var tables = input.Split('\t');
            int.TryParse(tables[0],out id);
            int.TryParse(tables[1],out MapID);
            string[] NPCIDListStringArray = tables[2].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
            NPCIDList = new int[NPCIDListStringArray.Length];
            for (int i=0;i<NPCIDListStringArray.Length;i++)
            {
                 int.TryParse(NPCIDListStringArray[i],out NPCIDList[i]);
            }
            int.TryParse(tables[3],out RefreshSeconds);
            int.TryParse(tables[4],out RefreshPerMinutes);
        }
        catch (Exception ex)
        {
            DebugEx.Log(ex);
        }
    }
    static Dictionary<string, MapNpcRefreshConfig> configs = new Dictionary<string, MapNpcRefreshConfig>();
    public static MapNpcRefreshConfig Get(string id)
    {
        if (!inited)
        {
            Debug.Log("MapNpcRefreshConfig 还未完成初始化。");
            return null;
        }
        if (configs.ContainsKey(id))
        {
            return configs[id];
        }
        MapNpcRefreshConfig config = null;
        if (rawDatas.ContainsKey(id))
        {
            config = configs[id] = new MapNpcRefreshConfig(rawDatas[id]);
            rawDatas.Remove(id);
        }
        return config;
    }
    public static MapNpcRefreshConfig Get(int id)
    {
        return Get(id.ToString());
    }
    public static List<string> GetKeys()
    {
        var keys = new List<string>();
        keys.AddRange(configs.Keys);
        keys.AddRange(rawDatas.Keys);
        return keys;
    }
    public static List<MapNpcRefreshConfig> GetValues()
    {
        var values = new List<MapNpcRefreshConfig>();
        values.AddRange(configs.Values);
        var keys = new List<string>(rawDatas.Keys);
        foreach (var key in keys)
        {
            values.Add(Get(key));
        }
        return values;
    }
    public static bool Has(string id)
    {
        return configs.ContainsKey(id) || rawDatas.ContainsKey(id);
    }
    public static bool Has(int id)
    {
        return Has(id.ToString());
    }
    public static bool inited { get; private set; }
    protected static Dictionary<string, string> rawDatas = new Dictionary<string, string>();
    public static void Init(bool sync=false)
    {
        inited = false;
        var path = string.Empty;
        if (AssetSource.refdataFromEditor)
        {
            path = ResourcesPath.CONFIG_FODLER +"/MapNpcRefresh.txt";
        }
        else
        {
            path = AssetVersionUtility.GetAssetFilePath("config/MapNpcRefresh.txt");
        }
        var tempConfig = new MapNpcRefreshConfig();
        var preParse = tempConfig is IConfigPostProcess;
        if (sync)
        {
            var lines = File.ReadAllLines(path);
            if (!preParse)
            {
                rawDatas = new Dictionary<string, string>(lines.Length - 3);
            }
            for (int i = 3; i < lines.Length; i++)
            {
                try
                {
                    var line = lines[i];
                    var index = line.IndexOf("\t");
                    if (index == -1)
                    {
                        continue;
                    }
                    var id = line.Substring(0, index);
                    if (preParse)
                    {
                        var config = new MapNpcRefreshConfig(line);
                        configs[id] = config;
                        (config as IConfigPostProcess).OnConfigParseCompleted();
                    }
                    else
                    {
                        rawDatas[id] = line;
                    }
                }
                catch (System.Exception ex)
                {
                    Debug.LogError(ex);
                }
            }
            inited = true;
        }
        else
        {
            ThreadPool.QueueUserWorkItem((object _object) =>
            {
                var lines = File.ReadAllLines(path);
                if (!preParse)
                {
                    rawDatas = new Dictionary<string, string>(lines.Length - 3);
                }
                for (int i = 3; i < lines.Length; i++)
                {
                    try
                    {
                       var line = lines[i];
                        var index = line.IndexOf("\t");
                        if (index == -1)
                        {
                            continue;
                        }
                        var id = line.Substring(0, index);
                        if (preParse)
                        {
                            var config = new MapNpcRefreshConfig(line);
                            configs[id] = config;
                            (config as IConfigPostProcess).OnConfigParseCompleted();
                        }
                        else
                        {
                            rawDatas[id] = line;
                        }
                    }
                    catch (System.Exception ex)
                    {
                        Debug.LogError(ex);
                    }
                }
                inited = true;
            });
        }
    }
}
Core/GameEngine/Model/Config/MapNpcRefreshConfig.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a541b078663e0ee43999b0532249d30d
timeCreated: 1555404500
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Core/NetworkPackage/ClientPack/ClientToMapServer/CA2_Interaction/CA234_tagCMGetCustomSceneCollectAward.cs
New file
@@ -0,0 +1,18 @@
using UnityEngine;
using System.Collections;
// A2 34 自定义场景中获取采集奖励 #tagCMGetCustomSceneCollectAward
public class CA234_tagCMGetCustomSceneCollectAward : GameNetPackBasic {
    public uint NPCID;    //采集的NPCID
    public CA234_tagCMGetCustomSceneCollectAward () {
        combineCmd = (ushort)0x03FE;
        _cmd = (ushort)0xA234;
    }
    public override void WriteToBytes () {
        WriteBytes (NPCID, NetDataType.DWORD);
    }
}
Core/NetworkPackage/ClientPack/ClientToMapServer/CA2_Interaction/CA234_tagCMGetCustomSceneCollectAward.cs.meta
New file
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: f0d0635cf0a0bd64f8f4742fb964f93f
timeCreated: 1555412785
licenseType: Pro
MonoImporter:
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Core/NetworkPackage/DTCFile/ServerPack/HA3_Function/DTCA326_tagMCNPCIDCollectionCntInfo.cs
@@ -34,6 +34,8 @@
            {
                smallBoxCollectCount += collect.CollectionCnt;
            }
            ModelCenter.Instance.GetModel<DungeonModel>().UpdateDungeonCollectNpcInfo((int)collect.NPCID, collect.CollectionCnt);
        }
        model.bigBoxCollectCount = bigBoxCollectCount;
Core/NetworkPackage/DTCFile/ServerPack/HA7_Interaction/DTCA714_tagMCNPCCntList.cs
@@ -20,6 +20,7 @@
        model.UpdateMonsterSurplusInfo(package);
        crossServerBossModel.UpdateMonsterSurplusInfo(package);
        ModelCenter.Instance.GetModel<HazyGrassModel>().ReceivePackage(package);
    }
}
System/Dungeon/DungeonModel.cs
@@ -22,6 +22,7 @@
        Dictionary<int, int> mapIdToDataMapId = new Dictionary<int, int>();
        Dictionary<int, DateTime> dungeonCountRemainTimes = new Dictionary<int, DateTime>();
        Dictionary<int, List<DungeonInspireConfig>> dungeonInspireDict = new Dictionary<int, List<DungeonInspireConfig>>();
        Dictionary<int, int> dungeonCollectNpcInfos = new Dictionary<int, int>();
        List<int> trialDungeonMapList = new List<int>();
        public event Action<DungeonCoolDownType> dungeonCoolDownEvent;
@@ -38,6 +39,7 @@
        public event Action<int> countRemainTimeChangeEvent;
        public event Action<Dungeon> kylinDifficultySelectedEvent;
        public event Action<DungeonFightStage> dungeonFightStageChangeEevent;
        public event Action onCollectNpcInfoRefresh;
        List<Item> sweepResultRewards = new List<Item>();
        List<Item> sweepResultItems = new List<Item>();
@@ -138,6 +140,7 @@
        {
            dungeonCountRemainTimes.Clear();
            dungeonInspireCounts.Clear();
            dungeonCollectNpcInfos.Clear();
        }
        public void OnAfterPlayerDataInitialize()
@@ -645,6 +648,15 @@
            }
        }
        public void UpdateDungeonCollectNpcInfo(int npcId,int count)
        {
            dungeonCollectNpcInfos[npcId] = count;
            if (onCollectNpcInfoRefresh != null)
            {
                onCollectNpcInfoRefresh();
            }
        }
        public void RequestClearEnterCD(int _mapID)
        {
            var clearpack = new CA210_tagCMClearFBCD();
@@ -747,6 +759,15 @@
            return endTime;
        }
        public int GetDugneonNpcCollectCount(int npcId)
        {
            if (dungeonCollectNpcInfos.ContainsKey(npcId))
            {
                return dungeonCollectNpcInfos[npcId];
            }
            return 0;
        }
        public void UpdateMission(string _mission)
        {
            var mapId = GetDataMapIdByMapId(PlayerDatas.Instance.baseData.MapID);
System/Dungeon/DungeonTargetBehaviour.cs
@@ -51,21 +51,21 @@
                var desc = config.targetDescription1[step < config.targetDescription1.Length ? step : 0];
                var npcId = config.NPC1ID.Length == 0 ? 0 : config.NPC1ID[step < config.NPC1ID.Length ? step : 0];
                var targetValue = config.targetValue1.Length == 0 ? 0 : config.targetValue1[step < config.targetValue1.Length ? step : 0];
                GetTargetInfo(0, desc, targetValue, step, config.targetType1, npcId);
                GetTargetInfo(0, desc, targetValue, step, config.targetType1, npcId, config.NPC1ID);
            }
            if (config.targetNum >= 2)
            {
                var desc = config.targetDescription2[step < config.targetDescription2.Length ? step : 0];
                var npcId = config.NPC2ID.Length == 0 ? 0 : config.NPC2ID[step < config.NPC2ID.Length ? step : 0];
                var targetValue = config.targetValue2.Length == 0 ? 0 : config.targetValue2[step < config.targetValue2.Length ? step : 0];
                GetTargetInfo(1, desc, targetValue, step, config.targetType2, npcId);
                GetTargetInfo(1, desc, targetValue, step, config.targetType2, npcId, config.NPC2ID);
            }
            if (config.targetNum >= 3)
            {
                var desc = config.targetDescription3[step < config.targetDescription2.Length ? step : 0];
                var npcId = config.NPC3ID.Length == 0 ? 0 : config.NPC3ID[step < config.NPC3ID.Length ? step : 0];
                var targetValue = config.targetValue3.Length == 0 ? 0 : config.targetValue3[step < config.targetValue3.Length ? step : 0];
                GetTargetInfo(2, desc, targetValue, step, config.targetType3, npcId);
                GetTargetInfo(2, desc, targetValue, step, config.targetType3, npcId, config.NPC3ID);
            }
            switch (dateMapId)
@@ -83,7 +83,7 @@
            }
        }
        private void GetTargetInfo(int _index, string desc, int _targetValue, int _targetStep, int _targetType, int npcId = 0)
        private void GetTargetInfo(int _index, string desc, int _targetValue, int _targetStep, int _targetType, int npcId, int[] npcIds)
        {
            m_TargetDescs[_index].text = desc;
            m_TargetNums[_index].text = string.Empty;
@@ -163,6 +163,19 @@
                        break;
                    }
                    m_TargetNums[_index].text = model.mission.step.ToString();
                    break;
                case DungeonTargetType.Collect:
                    var collectCount = 0;
                    for (int i = 0; i < npcIds.Length; i++)
                    {
                        collectCount += model.GetDugneonNpcCollectCount(npcIds[i]);
                    }
                    if (_targetValue > 0)
                    {
                        m_TargetNums[_index].text = StringUtility.Contact(collectCount, "/", _targetValue);
                        break;
                    }
                    m_TargetNums[_index].text = collectCount.ToString();
                    break;
            }
        }
System/HazyRegion/ClientHazyGrassStage.cs
@@ -12,9 +12,10 @@
    static Dictionary<Vector3, GA_NpcClientCollect> s_CollectNpcs = new Dictionary<Vector3, GA_NpcClientCollect>();
    static Dictionary<uint, Vector3> s_Sid2NpcPos = new Dictionary<uint, Vector3>();
    static Dictionary<uint, int> s_Sid2NpcIds = new Dictionary<uint, int>();
    static List<GA_NpcClientFightNorm> s_ClientFightNpcs = new List<GA_NpcClientFightNorm>();
    //static List<GA_NpcClientFightNorm> s_ClientFightNpcs = new List<GA_NpcClientFightNorm>();
    static List<HazyGrassNpcInfo> s_NpcRefreshInfos = new List<HazyGrassNpcInfo>();
    static int grassRefreshCount = 0;
    static Dictionary<int, int> s_NpcRefreshTimes = new Dictionary<int, int>();
    bool mapLoadFinish = false;
    bool initedFightNpc = false;
@@ -31,16 +32,20 @@
        s_NpcInfos.Clear();
        s_Sid2NpcIds.Clear();
        s_Sid2NpcPos.Clear();
        s_NpcRefreshTimes.Clear();
        mapLoadFinish = false;
        initedFightNpc = false;
        grassRefreshCount = 0;
        var config = HazyRegionConfig.Get(hazyRegionModel.processingIncidentId);
        if (config != null)
        {
            incidentType = (HazyRegionIncidentType)config.incidentType;
            s_NpcRefreshInfos = model.GetGrassNpcInfos(config.dungeonId);
            foreach (var npcInfo in s_NpcRefreshInfos)
            {
                s_NpcRefreshTimes.Add(npcInfo.npcId, GetNpcRefreshCount(npcInfo));
            }
        }
        UnloadAllNpc();
@@ -53,7 +58,6 @@
        base.OnStageLoadFinish();
        mapLoadFinish = true;
        model.RefreshGrassBornTime(TimeUtility.ServerNow);
        InitialPlayer();
        InitializeNpc();
@@ -67,12 +71,15 @@
        if (mapLoadFinish)
        {
            var used = Mathf.Max(0, (int)(TimeUtility.ServerNow - model.grassBornTime).TotalSeconds);
            var count = used / model.grassRefreshSeconds;
            if (count != grassRefreshCount)
            foreach (var npcInfo in s_NpcRefreshInfos)
            {
                RebornCollectedNpc();
                grassRefreshCount = count;
                var _lastCount = s_NpcRefreshTimes[npcInfo.npcId];
                var count = GetNpcRefreshCount(npcInfo);
                if (_lastCount != count)
                {
                    RebornCollectedNpc(npcInfo.npcId);
                    s_NpcRefreshTimes[npcInfo.npcId] = count;
                }
            }
        }
    }
@@ -86,12 +93,24 @@
        GA_NpcClientCollect.OnCollectFinished -= OnCollectFinished;
    }
    int GetNpcRefreshCount(HazyGrassNpcInfo npcInfo)
    {
        var used = TimeUtility.Minute * 60 + TimeUtility.Second;
        var refreshSeconds = npcInfo.refreshMinute * 60;
        return used / refreshSeconds;
    }
    private void OnCollectFinished(uint _sid)
    {
        if (s_Sid2NpcIds.ContainsKey(_sid))
        {
            var npcId = s_Sid2NpcIds[_sid];
            Debug.Log("采集了Npc:--" + npcId);
            var pak = new CA234_tagCMGetCustomSceneCollectAward();
            pak.NPCID = (uint)npcId;
            GameNetSystem.Instance.SendInfo(pak);
            s_Sid2NpcIds.Remove(_sid);
        }
        if (s_Sid2NpcPos.ContainsKey(_sid))
@@ -102,6 +121,8 @@
                s_CollectNpcs.Remove(pos);
            }
        }
        RefreshMapNpcCount();
    }
    void InitializeNpc()
@@ -131,10 +152,14 @@
        CameraController.Instance.Apply();
    }
    void RebornCollectedNpc()
    void RebornCollectedNpc(int npcId = 0)
    {
        foreach (var npcInfo in s_NpcInfos)
        {
            if (npcId != 0 && npcInfo.npcId != npcId)
            {
                continue;
            }
            switch (npcInfo.npcType)
            {
                case E_NpcType.Collect:
@@ -155,20 +180,38 @@
                    }
                    break;
                case E_NpcType.Fight:
                    if (!initedFightNpc)
                    {
                        var fightNpc = GAMgr.Instance.ReqClntFightNpc<GA_NpcClientFightNorm>((uint)npcInfo.npcId,
                             E_ActorGroup.Enemy);
                        if (fightNpc != null)
                        {
                            fightNpc.Pos = npcInfo.position;
                            fightNpc.OnAttacked -= OnAttackNpc;
                            fightNpc.OnAttacked += OnAttackNpc;
                        }
                        s_ClientFightNpcs.Add(fightNpc);
                    }
                    //if (!initedFightNpc)
                    //{
                    //    var fightNpc = GAMgr.Instance.ReqClntFightNpc<GA_NpcClientFightNorm>((uint)npcInfo.npcId,
                    //         E_ActorGroup.Enemy);
                    //    if (fightNpc != null)
                    //    {
                    //        fightNpc.Pos = npcInfo.position;
                    //        fightNpc.OnAttacked -= OnAttackNpc;
                    //        fightNpc.OnAttacked += OnAttackNpc;
                    //    }
                    //    s_ClientFightNpcs.Add(fightNpc);
                    //}
                    break;
            }
        }
        RefreshMapNpcCount();
    }
    void RefreshMapNpcCount()
    {
        foreach (var npcInfo in s_NpcRefreshInfos)
        {
            var count = 0;
            foreach (var npcId in s_Sid2NpcIds.Values)
            {
                if (npcId == npcInfo.npcId)
                {
                    count++;
                }
            }
            model.RefreshMapNpcCount(npcInfo.npcId, count);
        }
    }
@@ -190,18 +233,18 @@
            }
        }
        foreach (var _npc in s_ClientFightNpcs)
        {
            if (_npc != null)
            {
                _npc.OnAttacked -= OnAttackNpc;
                _npc.ActorInfo.serverDie = true;
                GAMgr.Instance.ServerDie(_npc.ServerInstID);
                GAMgr.Instance.Release(_npc);
            }
        }
        s_ClientFightNpcs.Clear();
        //foreach (var _npc in s_ClientFightNpcs)
        //{
        //    if (_npc != null)
        //    {
        //        _npc.OnAttacked -= OnAttackNpc;
        //        _npc.ActorInfo.serverDie = true;
        //        GAMgr.Instance.ServerDie(_npc.ServerInstID);
        //        GAMgr.Instance.Release(_npc);
        //    }
        //}
        //
        //s_ClientFightNpcs.Clear();
        s_CollectNpcs.Clear();
    }
System/HazyRegion/HazyGrassDungeonWin.cs
@@ -6,6 +6,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UI;
@@ -15,10 +16,10 @@
    public class HazyGrassDungeonWin : Window
    {
        [SerializeField] DungeonTargetBehaviour m_DungeonTarget;
        [SerializeField] Text m_BasicGrassCount;
        [SerializeField] Text m_FairyGrassCount;
        [SerializeField] Text m_BasicGrassRefreshTime;
        [SerializeField] Text m_FairyGrassRefreshTime;
        [SerializeField] HazyGrassCountBeha[] m_GrassCountBehas;
        [SerializeField] Text[] m_GrassTimes;
        float timer = 0f;
        DungeonModel model { get { return ModelCenter.Instance.GetModel<DungeonModel>(); } }
        HazyRegionModel hazyRegionModel { get { return ModelCenter.Instance.GetModel<HazyRegionModel>(); } }
@@ -36,7 +37,11 @@
        {
            Display();
            timer = 0f;
            RequestGrassCount();
            GlobalTimeEvent.Instance.secondEvent += PerSecond;
            hazyGrassModel.onMapNpcCountRefresh += OnMapNpcCountRefresh;
        }
        protected override void OnAfterOpen()
@@ -46,10 +51,22 @@
        protected override void OnPreClose()
        {
            GlobalTimeEvent.Instance.secondEvent -= PerSecond;
            hazyGrassModel.onMapNpcCountRefresh -= OnMapNpcCountRefresh;
        }
        protected override void OnAfterClose()
        {
        }
        protected override void LateUpdate()
        {
            base.LateUpdate();
            timer += Time.deltaTime;
            if (timer >= 5f)
            {
                timer = 0f;
                RequestGrassCount();
            }
        }
        #endregion
@@ -72,19 +89,102 @@
            }
            DisplayGrassRefreshTime();
            DisplayGrassCount();
        }
        void DisplayGrassCount()
        {
            var mapId = hazyGrassModel.GetGrassMapId(hazyRegionModel.processingIncidentId);
            var npcInfos = hazyGrassModel.GetGrassNpcInfos(mapId);
            for (int i = 0; i < m_GrassCountBehas.Length; i++)
            {
                if (npcInfos != null && i < npcInfos.Count)
                {
                    m_GrassCountBehas[i].SetActive(true);
                    m_GrassCountBehas[i].Display(npcInfos[i].npcId,
                        hazyGrassModel.GetMapNpcCount(npcInfos[i].npcId));
                }
                else
                {
                    m_GrassCountBehas[i].SetActive(false);
                }
            }
        }
        void DisplayGrassRefreshTime()
        {
            var used = Mathf.Max(0, (int)(TimeUtility.ServerNow - hazyGrassModel.grassBornTime).TotalSeconds);
            var refreshSeconds = hazyGrassModel.grassRefreshSeconds - used % hazyGrassModel.grassRefreshSeconds;
            m_BasicGrassRefreshTime.text = Language.Get("HazyBasicGrassRefresh", TimeUtility.SecondsToMS(refreshSeconds));
            m_FairyGrassRefreshTime.text = Language.Get("HazyFairyGrassRefresh", TimeUtility.SecondsToMS(refreshSeconds));
            var mapId = hazyGrassModel.GetGrassMapId(hazyRegionModel.processingIncidentId);
            var npcInfos = hazyGrassModel.GetGrassNpcInfos(mapId);
            for (int i = 0; i < m_GrassTimes.Length; i++)
            {
                if (npcInfos != null && i < npcInfos.Count)
                {
                    m_GrassTimes[i].gameObject.SetActive(true);
                    var used = TimeUtility.Minute * 60 + TimeUtility.Second;
                    var refreshSeconds = npcInfos[i].refreshMinute * 60;
                    var seconds = refreshSeconds - used % refreshSeconds;
                    var npcConfig = NPCConfig.Get(npcInfos[i].npcId);
                    m_GrassTimes[i].text = string.Format("{0}{1}后刷新", npcConfig.charName,
                        TimeUtility.SecondsToMS(seconds));
                }
                else
                {
                    m_GrassTimes[i].gameObject.SetActive(false);
                }
            }
        }
        void RequestGrassCount()
        {
            if (!ClientDungeonStageUtility.isClientDungeon)
            {
                var config = HazyRegionConfig.Get(hazyRegionModel.processingIncidentId);
                if (config != null)
                {
                    var npcInfos = hazyGrassModel.GetGrassNpcInfos(config.dungeonId);
                    if (npcInfos != null)
                    {
                        int[] npcs = new int[npcInfos.Count];
                        for (int i = 0; i < npcInfos.Count; i++)
                        {
                            npcs[i] = npcInfos[i].npcId;
                        }
                        var pak = new CA227_tagCMQueryNPCCntInfo();
                        pak.MapID = (uint)config.dungeonId;
                        pak.LineID = (ushort)config.lineId;
                        pak.NPCIDList = LitJson.JsonMapper.ToJson(npcs);
                        pak.NPCIDListLen = (byte)pak.NPCIDList.Length;
                        GameNetSystem.Instance.SendInfo(pak);
                    }
                }
            }
        }
        private void OnMapNpcCountRefresh()
        {
            DisplayGrassCount();
        }
        [Serializable]
        public class HazyGrassCountBeha
        {
            [SerializeField] Transform m_Container;
            [SerializeField] Text m_Title;
            [SerializeField] Text m_Count;
            public void Display(int npcId, int count)
            {
                var npcConfig = NPCConfig.Get(npcId);
                m_Title.text = string.Format("剩余{0}数量:", npcConfig.charName);
                m_Count.text = count.ToString();
                m_Count.color = UIHelper.GetUIColor(count > 0 ? TextColType.Green : TextColType.Red);
            }
            public void SetActive(bool active)
            {
                m_Container.gameObject.SetActive(active);
            }
        }
    }
System/HazyRegion/HazyGrassModel.cs
@@ -6,6 +6,9 @@
{
    public class HazyGrassModel : Model, IBeforePlayerDataInitialize, IPlayerLoginOk
    {
        Dictionary<int, List<HazyGrassNpcInfo>> mapNpcs = new Dictionary<int, List<HazyGrassNpcInfo>>();
        Dictionary<int, int> m_MapNpcCount = new Dictionary<int, int>();
        public const int ReikiGrassMapId = 32040;
        public const int FairyGrassMapId = 32050;
        public const int Client_ReikiGrassMapID = 3240;
@@ -13,11 +16,10 @@
        public bool IsInDungeon { get; private set; }
        public int grassRefreshSeconds { get; private set; }
        public DateTime grassBornTime { get; private set; }
        public event Action onMapNpcCountRefresh;
        HazyRegionModel hazyRegionModel { get { return ModelCenter.Instance.GetModel<HazyRegionModel>(); } }
        DungeonModel dungeonModel { get { return ModelCenter.Instance.GetModel<DungeonModel>(); } }
        public override void Init()
        {
@@ -41,12 +43,35 @@
        void ParseConfig()
        {
            grassRefreshSeconds = 20;
            var mapNpcConfigs = MapNpcRefreshConfig.GetValues();
            foreach (var config in mapNpcConfigs)
            {
                if (config.MapID == ReikiGrassMapId
                    || config.MapID == FairyGrassMapId)
                {
                    List<HazyGrassNpcInfo> _npcs = null;
                    if (!mapNpcs.TryGetValue(config.MapID, out _npcs))
                    {
                        _npcs = new List<HazyGrassNpcInfo>();
                        mapNpcs.Add(config.MapID, _npcs);
                    }
                    for (int i = 0; i < config.NPCIDList.Length; i++)
                    {
                        _npcs.Add(new HazyGrassNpcInfo()
                        {
                            npcId = config.NPCIDList[i],
                            refreshMinute = config.RefreshPerMinutes,
                        });
                    }
                }
            }
        }
        private void OnStageLoadFinish()
        {
            var mapId = PlayerDatas.Instance.baseData.MapID;
            m_MapNpcCount.Clear();
            IsInDungeon = false;
            if (IsInGrassDungeon(mapId))
@@ -89,14 +114,83 @@
            return 0;
        }
        public void RefreshGrassBornTime()
        public int GetGrassMapId(int incidentId)
        {
            var config = HazyRegionConfig.Get(incidentId);
            if (config != null)
            {
                return config.dungeonId;
            }
            return 0;
        }
        public void RefreshGrassBornTime(DateTime _time)
        public List<HazyGrassNpcInfo> GetGrassNpcInfos(int mapId)
        {
            grassBornTime = _time;
            if (mapNpcs.ContainsKey(mapId))
            {
                return mapNpcs[mapId];
            }
            return null;
        }
        public int GetMapNpcCount(int npcId)
        {
            if (m_MapNpcCount.ContainsKey(npcId))
            {
                return m_MapNpcCount[npcId];
            }
            return 0;
        }
        public bool CanCollectNpc(int npcId)
        {
            var collectCount = dungeonModel.GetDugneonNpcCollectCount(npcId);
            if (ClientDungeonStageUtility.isClientDungeon
                && ClientDungeonStageUtility.clientMapId == Client_ReikiGrassMapID)
            {
                var config = HazyRegionConfig.Get(hazyRegionModel.processingIncidentId);
                if (config != null)
                {
                    var hintId = dungeonModel.GetDungeonHintId(config.dungeonId, config.lineId);
                    var hintConfig = DungeonHintConfig.Get(hintId);
                    if (hintConfig.NPC1ID.Length > 0 && hintConfig.NPC1ID[0] == npcId)
                    {
                        return collectCount < hintConfig.targetValue1[0];
                    }
                    else if (hintConfig.NPC2ID.Length > 0 && hintConfig.NPC2ID[0] == npcId)
                    {
                        return collectCount < hintConfig.targetValue2[0];
                    }
                }
            }
            return true;
        }
        public void ReceivePackage(HA714_tagMCNPCCntList package)
        {
            if (package.MapID != ReikiGrassMapId
                && package.MapID != FairyGrassMapId)
            {
                return;
            }
            for (int i = 0; i < package.NPCInfoCnt; i++)
            {
                var data = package.NPCInfoList[i];
                m_MapNpcCount[(int)data.NPCID] = (int)data.Cnt;
            }
            if (onMapNpcCountRefresh != null)
            {
                onMapNpcCountRefresh();
            }
        }
        public void RefreshMapNpcCount(int npcId, int count)
        {
            m_MapNpcCount[npcId] = count;
            if (onMapNpcCountRefresh != null)
            {
                onMapNpcCountRefresh();
            }
        }
        public void RequestEnterClientDungeon()
@@ -145,5 +239,11 @@
            });
        }
    }
    public struct HazyGrassNpcInfo
    {
        public int npcId;
        public int refreshMinute;
    }
}
Utility/ConfigInitiator.cs
@@ -291,6 +291,7 @@
        normalTasks.Add(new ConfigInitTask("ReikiRootConfig", () => { ReikiRootConfig.Init(); }, () => { return ReikiRootConfig.inited; }));
        normalTasks.Add(new ConfigInitTask("HazyRegionConfig", () => { HazyRegionConfig.Init(); }, () => { return HazyRegionConfig.inited; }));
        normalTasks.Add(new ConfigInitTask("AdventureDialogueConfig", () => { AdventureDialogueConfig.Init(); }, () => { return AdventureDialogueConfig.inited; }));
        normalTasks.Add(new ConfigInitTask("MapNpcRefreshConfig", () => { MapNpcRefreshConfig.Init(); }, () => { return MapNpcRefreshConfig.inited; }));
    }
    static List<ConfigInitTask> doingTasks = new List<ConfigInitTask>();
Utility/EnumHelper.cs
@@ -1186,6 +1186,7 @@
    NPCDialogue = 8,    //npc对话
    VictorySumCnt = 9, //(仙魔胜利总场数)
    StageVictoryCnt = 10, //(阶段胜利场数)
    Collect,
}
public enum AchievementType