少年修仙传客户端代码仓库
hch
2025-04-03 c154ac0832fe4379a00d3e1cda700e7d2a7383c7
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
//--------------------------------------------------------
//    [Author]:           第二世界
//    [  Date ]:           Wednesday, March 14, 2018
//--------------------------------------------------------
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using vnxbqy.UI;
using System;
using LitJson;
using System.Collections.Generic;
using System.Linq;
 
public class CutTreeModel : Model, IBeforePlayerDataInitialize, IPlayerLoginOk
{
    //砍树速度
    public int cutTreeSpeed = 1; //月卡开启加速, 速度越大越快
 
    public event Action OnSelectMainType;
 
    //0:主界面砍树 1:战斗界面
    private int m_SelectMainType = 0;
    public int SelectMainType
    {
        get
        {
            return m_SelectMainType;
        }
        set
        {
            if (m_SelectMainType != value)
            {
                m_SelectMainType = value;
                OnSelectMainType?.Invoke();
            }
        }
 
    }
 
    public event Action OnCutTreeResult;
    public Action AfterPlayCutTreeAnimEvent; //砍树动画播放完毕后的事件
    public List<Item> m_ExItemList = new List<Item>(); // 砍树获得额外物品奖励(非装备) 存储起来统一展示
    public int m_EquipCount;
    public int[] equipUIEffectLights;  //砍树装备掉落特效
    public int[] cutTreeAtkEffects; //砍树攻击特效
    public int upgradeTreeMoneyType; //升级仙树消耗的货币类型
    public int timeUpTreeItemID; //加速仙树升级的道具ID
    public int timeUpTreeItemSubTime; //减少仙树升级时间的道具减少的时间
 
    public Dictionary<int, int> taskClickGuide = new Dictionary<int, int>(); //点击任务引导 任务类型-引导id
    public Dictionary<int, int> realmWinClickGuide = new Dictionary<int, int>(); //点击境界窗口引导 境界类型-引导id
    public Dictionary<int, int> defeadWinClickGuide = new Dictionary<int, int>(); //点击副本战败引导 副本id-引导id
    public int[] autoGuideList; //小于x级y秒内无任何点击自动引导【等级,秒】
    public Dictionary<int, int> newEquipIDToGuideID = new Dictionary<int, int>(); //新装备id对应的引导id
    public ItemModel selectFloorEquip; //选中的地板装备
    public bool dontNotifyDecompose = false;    // 是否提示更好装备分解警告
    public bool dontNotifyExchangeDecompose = false;     // 是否提示更好装备替换会被分解警告
    public bool waitEquipOPPack = false;    //等待装备操作(分解/替换)包返回
    public bool waitCutTreePack = false;    //等待砍树结果包返回
    public event Action OnEquipOPResultAction;
    public float lastModelAnimateTime = 0; //上次模型最后一次砍树动画时间
    public bool isPlayCutTreeAnim = false; //是否正在播放砍树动画,用于重复点击砍树按钮的判断
 
    //仙树信息
    int m_TreeLV;    // 当前仙树等级
    public int m_LVUPState;    // 0-非升级中;1-升级中
    int m_LVUPRemainTime;    // 升级剩余时间,秒;当升级中且倒计时为0时可发送B223执行升级包进行升级
    int m_LVPackTime; //收包时间用于计算剩余时间m_LVUPRemainTime
    public float cutTreeDuration = 0.8f; //砍树动画基础不加速的单次间隔
    public event Action UpdateTreeLVEvent;
    bool loginOKTreePack = false; //登录时是否已经收到仙树信息包,用于判定是否仙树升级
    public bool isCreateNewUIModel = true; //砍树界面是否创建新的UI模型,用于换模型功能或者重登时刷新界面模型
 
    //砍树任务 另外一套逻辑
    public int m_CutTreeTaskID = 0;
    public int m_CutTreeTaskValue = 0;
    public int m_CutTreeTaskState = 0; // 任务状态 1-进行中 2-可领取
    public event Action OnCutTreeTaskEvent;
 
    public bool clickEquipTipOnMain = false; //主界面点击在身上装备的tip显示
 
    //功能入口
    public int[] dongfuFuncArr;
    public int[] tiaozhanFuncArr;
    public Dictionary<int, int> funcIDToDailyIDDic = new Dictionary<int, int>(); //功能id对应的日常id, 用于进度完成显示
    public Dictionary<int, int> funcShowLVDic = new Dictionary<int, int>(); //功能显示的最低等级 不是开启功能的等级
    public Dictionary<int, int> funcRedpointDic = new Dictionary<int, int>();
    public int selectFuncArrNum = 0; //选择的功能组序号 0-洞府 1-挑战
 
    PackModel packModel { get { return ModelCenter.Instance.GetModel<PackModel>(); } }
    EquipModel equipModel { get { return ModelCenter.Instance.GetModel<EquipModel>(); } }
    AutoCutTreeModel autoCutTreeModel { get { return ModelCenter.Instance.GetModel<AutoCutTreeModel>(); } }
    TaskModel taskModel { get { return ModelCenter.Instance.GetModel<TaskModel>(); } }
    DungeonModel dungeonModel { get { return ModelCenter.Instance.GetModel<DungeonModel>(); } }
 
    public override void Init()
    {
        DTC0721_tagMakeItemAnswer.MakeItemAnswerEvent += OnEquipResult;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        PlayerDatas.Instance.playerDataRefreshEvent += OnPlayerDataRefreshEvent;
        ParseConfig();
    }
 
    void ParseConfig()
    {
        var config = FuncConfigConfig.Get("CutTreeEquip");
        equipUIEffectLights = JsonMapper.ToObject<int[]>(config.Numerical1);
        var json = JsonMapper.ToObject(config.Numerical2);
        foreach (var key in json.Keys)
        {
            taskClickGuide.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
        autoGuideList = JsonMapper.ToObject<int[]>(config.Numerical3);
        json = JsonMapper.ToObject(config.Numerical4);
        foreach (var key in json.Keys)
        {
            newEquipIDToGuideID.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
 
        cutTreeAtkEffects = JsonMapper.ToObject<int[]>(config.Numerical5);
 
        config = FuncConfigConfig.Get("TreeLVUP");
        upgradeTreeMoneyType = int.Parse(config.Numerical1);
        var arr = config.Numerical2.Split('|');
        timeUpTreeItemID = int.Parse(arr[0]);
        timeUpTreeItemSubTime = int.Parse(arr[1]);
 
        config = FuncConfigConfig.Get("CutTreePanel1");
        dongfuFuncArr = JsonMapper.ToObject<int[]>(config.Numerical1);
        tiaozhanFuncArr = JsonMapper.ToObject<int[]>(config.Numerical2);
        json = JsonMapper.ToObject(config.Numerical3);
        foreach (var key in json.Keys)
        {
            funcIDToDailyIDDic.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
        json = JsonMapper.ToObject(config.Numerical4);
        foreach (var key in json.Keys)
        {
            funcShowLVDic.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
        json = JsonMapper.ToObject(config.Numerical5);
        foreach (var key in json.Keys)
        {
            funcRedpointDic.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
 
        config = FuncConfigConfig.Get("CutTreePanel2");
        json = JsonMapper.ToObject(config.Numerical1);
        foreach (var key in json.Keys)
        {
            realmWinClickGuide.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
        json = JsonMapper.ToObject(config.Numerical2);
        foreach (var key in json.Keys)
        {
            defeadWinClickGuide.Add(int.Parse(key), int.Parse(json[key].ToString()));
        }
    }
 
    public void OnBeforePlayerDataInitialize()
    {
        if (WindowCenter.Instance.IsOpen<EquipExchangeWin>())
            WindowCenter.Instance.Close<EquipExchangeWin>();
        selectFloorEquip = null;
        m_ExItemList.Clear();
        dontNotifyDecompose = false;
        dontNotifyExchangeDecompose = false;
        waitEquipOPPack = false;
        waitCutTreePack = false;
        m_TreeLV = 0;
        m_LVUPState = 0;
        m_LVUPRemainTime = 0;
        m_CutTreeTaskID = 0;
        m_CutTreeTaskValue = 0;
        m_CutTreeTaskState = 0;
        loginOKTreePack = false;
        isCreateNewUIModel = true;
        isPlayCutTreeAnim = false;
 
    }
 
 
 
    public void OnPlayerLoginOk()
    {
        var _mapConfig = MapConfig.Get(PlayerDatas.Instance.baseData.MapID);
        if (_mapConfig.MapFBType == (int)MapType.OpenCountry)
        {
            SelectMainType = 0; //后续根据具体情况调整
        }
    }
 
    public override void UnInit()
    {
        DTC0721_tagMakeItemAnswer.MakeItemAnswerEvent -= OnEquipResult;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        PlayerDatas.Instance.playerDataRefreshEvent -= OnPlayerDataRefreshEvent;
    }
 
    //是否休息时间
    public bool IsRestTime()
    {
        if (Time.realtimeSinceStartup - lastModelAnimateTime > 10)
            return true;
        return false;
    }
 
    private void OnEquipResult(H0721_tagMakeItemAnswer info)
    {
        if (info.MakeType != (int)MakeType.default1)
            return;
 
        waitEquipOPPack = false;
        OnEquipOPResultAction?.Invoke();
    }
 
    public void SendCutTree(int count)
    {
        var pack = new CB221_tagCMCutTree();
        pack.CutCount = (byte)count;
        GameNetSystem.Instance.SendInfo(pack);
        lastModelAnimateTime = Time.realtimeSinceStartup;
        isPlayCutTreeAnim = true;
    }
 
    public void CutTreeResult(HB122_tagMCCutTreeResult vNetData)
    {
        waitCutTreePack = false;
        lastModelAnimateTime = Time.realtimeSinceStartup;
        m_EquipCount = vNetData.EquipCount;
        if (vNetData.ExItemList.Length != 0)
        {
            for (int i = 0; i < vNetData.ExItemList.Length; i++)
            {
                m_ExItemList.Add(new Item() { 
                    id = (int)vNetData.ExItemList[i].ItemID,
                    count = (int)vNetData.ExItemList[i].ItemCount
                });
            }
            if (SelectMainType == 0)
            {
                ItemLogicUtility.Instance.ShowGetItem(m_ExItemList, Language.Get("CutTree1"), func: () => {
                    m_ExItemList.Clear();
                });
            }
        }
        //1.没有界面表现的砍树结果 2.有界面表现的砍树结果
        if (SelectMainType == 0 && WindowCenter.Instance.IsOpen<MainInterfaceWin>())
        {
            
 
            OnCutTreeResult?.Invoke();
        }
        else
        {
            ProcessEquipOnFloor();
        }
        
    }
 
    //不展示界面的时候按间隔时间处理地板装备
    public void ProcessEquipOnFloor()
    {
        //时间顺序:砍树动作-掉落-分解/替换
        var quality = GetStartEquipQuality();
        var betterQuality = GetBetterEquipQuality(quality);
        var cutCount = betterQuality - quality + 1;
        float delayTime = Math.Max(cutTreeDuration / cutTreeSpeed * cutCount / (1 + Math.Max(cutCount - 2, 0) * 0.3f), 0.5f);
        Clock.AlarmAfter(delayTime, () =>
        {
            if (!autoCutTreeModel.isAutoCutTree)
            {
                var betterEquip = GetBetterFloorEquip();
                if (betterEquip != null)
                {
                    OpenEquipExchangeWin(betterEquip);
                }
            }
            else
            {
                isPlayCutTreeAnim = false;
            }
        });
    }
 
    //砍树动作对应装备品质的起始表现,最小1
    public int GetStartEquipQuality()
    {
        var rateList = TreeLVConfig.Get(m_TreeLV).EquipColorRateList;
        for (int i = 0;i< rateList.Length; i++)
        {
            if (rateList[i] != 0)
                return i + 1;
        }
        return 1;
    }
 
 
    public int GetBetterEquipQuality(int quality = 1)
    {
        var items = packModel.GetItems(PackType.EquipOnFloor);
        if (items == null || items.Count == 0)
            return quality;
 
        for (int i = 0; i < items.Count; i++)
        {
            var equip = items[i];
            if (equip == null)
                continue;
            if (quality < equip.config.ItemColor)
                quality = equip.config.ItemColor;
        }
        return quality;
    }
 
    public ItemModel GetBetterFloorEquip()
    {
        var items = packModel.GetItems(PackType.EquipOnFloor);
        if (items == null || items.Count == 0)
            return null;
 
        ItemModel betterEquip = null;
        for (int i = 0; i < items.Count; i++)
        {
            var equip = items[i];
            if (equip == null)
                continue;
 
            var equipOn = equipModel.GetEquipItemModel(new Int2(PlayerDatas.Instance.baseData.suitLevel, equip.config.EquipPlace));
            if (equipOn == null)
                continue;
            //后续要处理自动功能的战斗属性对比
            if (betterEquip.score > equipOn.score)
                betterEquip = equip;
        }
        return betterEquip;
    }
 
 
    public void SendCutTreeEquipOP(byte[] itemIndexList, byte opType, bool autoDecompose = false)
    {
        if (waitEquipOPPack) return;
 
        NoteFloorEquip(itemIndexList, opType);
        var pack = new CB222_tagCMCutTreeEquipOP();
        pack.IndexCount = (byte)itemIndexList.Length;
        pack.ItemIndexList = itemIndexList;
        pack.OPType = opType;   // 操作类型:1-替换;2-分解
        pack.AutoDecompose = (byte)(autoDecompose ? 1 : 0); // 替换后是否自动分解原装备:0否1是,仅替换操作下有用
 
        waitEquipOPPack = true;
        GameNetSystem.Instance.SendInfo(pack);
    }
 
    //equipFloorInfo记录地板装备的最新一次信息,不作清除可能地板上的装备已经消失,用于替换和分解装备的表现
    public void NoteFloorEquip(byte[] itemIndexList, int opType)
    {
        equipFloorInfo.Clear();
        foreach (var girdIndex in itemIndexList)
        {
            var equip = packModel.GetItemByIndex(PackType.EquipOnFloor, girdIndex);
            if (equip == null) continue;
            equipFloorInfo[girdIndex] = new EquipOnFloorInfo()
            {
                equipID = equip.itemId,
                posX = equipOnFloorBtn[girdIndex].transform.position.x,
                posY = equipOnFloorBtn[girdIndex].transform.position.y,
                opType = opType
            };
        }
 
    }
 
 
    public void OpenEquipExchangeWin(ItemModel equip)
    {
        isPlayCutTreeAnim = false;
        if (SelectMainType == 1)
            return;
 
        //未回复装备操作结果,否则会显示旧装备
        if (waitEquipOPPack) 
            return;
 
        if (TurnFightModel.Instance.IsTurnFight())
            return;
 
        if (WindowCenter.Instance.IsOpen<EquipExchangeWin>())
            return;
 
        if (NewBieCenter.Instance.inGuiding)
            return;
 
        selectFloorEquip = equip;
        WindowCenter.Instance.Open<EquipExchangeWin>();
    }
 
    //用于飘动逻辑
    public Dictionary<int, EquipOnFloorInfo> equipFloorInfo = new Dictionary<int, EquipOnFloorInfo>(); //真实背包的索引,对应地板装备的信息
    public List<Button> equipOnFloorBtn = new List<Button>();
 
    public struct EquipOnFloorInfo
    {
        public int equipID;
        public float posX;  //全局坐标 表现再转成local
        public float posY;
        public int opType;  //操作类型:1-替换;2-分解
    }
 
    public EquipOnFloorInfo FindExchangeEquipInfo()
    {
        foreach (var info in equipFloorInfo)
        {
            if (info.Value.opType == 1)
                return info.Value;
        }
        return new EquipOnFloorInfo();
    }
 
 
 
    public void UpdateTreeInfo(HB121_tagMCTreeInfo pack)
    {
        if (!loginOKTreePack)
        {
            loginOKTreePack = true;
        }
        else if (m_TreeLV < pack.TreeLV)
        {
            //播放仙树升级特效
            EffectMgr.Instance.PlayUIEffect(7118, 1800, WindowCenter.Instance.uiRoot.baseCanvas, false);
        }
        m_TreeLV = pack.TreeLV;
        m_LVUPState = pack.LVUPState;
        m_LVUPRemainTime = (int)pack.LVUPRemainTime;
        m_LVPackTime = TimeUtility.AllSeconds;
        UpdateTreeLVEvent?.Invoke();
        UpdateTreeRedpoint();
    }
 
    public void UpdateCutTreeTaskInfo(HB110_tagMCTaskInfo pack)
    {
        for (int i = 0; i < pack.TaskCount; i++)
        {
            var task = pack.TaskList[i];
            if (task.TaskGroup == 0)
            {
                m_CutTreeTaskID = (int)task.TaskID;
                m_CutTreeTaskValue = (int)task.CurValue;
                m_CutTreeTaskState = task.State;
                OnCutTreeTaskEvent?.Invoke();
                taskModel.TreeTask(m_CutTreeTaskID, m_CutTreeTaskState);
            }
        }
    }
 
    //仙树等级
    public int GetTreeLV()
    {
        return m_TreeLV;
    }
 
    //仙树等级显示,如果服务端从0开始 需加1,根据项目情况调整
    public int GetUIShowTreeLV()
    {
        return m_TreeLV;
    }
 
    public int GetLVUPRemainTime()
    {
        if (m_LVUPState == 0)
            return 0;
        return m_LVUPRemainTime - (TimeUtility.AllSeconds - m_LVPackTime);
    }
 
    public void SendUpgradeTreeLV(int type)
    {
        var pack = new CB223_tagCMTreeLVUP();
        pack.Type = (byte)type;  // 0-开始升级(请求扣除消耗,开始升级倒计时);1-执行升级(前端自行倒计时,时间到后发送该类型)
        GameNetSystem.Instance.SendInfo(pack);
    }
 
    void OnSecondEvent()
    {
        //自动发送砍树升级
        if (m_LVUPState == 1 && GetLVUPRemainTime() <= 0)
        {
            SendUpgradeTreeLV(1);
        }
    }
 
    //还需多少个任务完成
    public int GetTaskCountToFinish(int taskID)
    {
        var config = TaskConfig.Get(taskID);
        if (config == null)
            return 9999;
        var curConfig = TaskConfig.Get(m_CutTreeTaskID);
        if (curConfig.Index >= config.Index)
            return 0;
 
        return config.Index - curConfig.Index;
    }
 
    //冒险已通过到达的当前关卡,比如第四关打过了 返回5
    public int GetAdventureFBID()
    {
        DungeonRecord dungeonRecord;
        if (dungeonModel.TryGetRecord(TurnFightModel.AdventureMapID, out dungeonRecord))
        {
            return dungeonRecord.passLineID + 1;
        }
 
        return 1;
    }
 
    private void OnPlayerDataRefreshEvent(PlayerDataType type)
    {
        if (type == HeroControler.Instance.GetMoneyPlayerDataType(upgradeTreeMoneyType))
        {
            UpdateTreeRedpoint();
        }
    }
 
    Redpoint redpointTree = new Redpoint(MainRedDot.FairyTreeRedpoint);
    void UpdateTreeRedpoint()
    {
        redpointTree.state = RedPointState.None;
        if (m_LVUPState != 0) return;
        var config = TreeLVConfig.Get(GetTreeLV());
        if (config == null) return;
        if (UIHelper.GetMoneyCnt(upgradeTreeMoneyType) >= (ulong)config.LVUPNeedMoney)
        {
            redpointTree.state = RedPointState.Simple;
        }
    }
    //!!!功能入口的红点,仙盟107,洞府1,挑战3
}