hch
2025-11-21 eb27e5fd31f73b998a4bbd85511a31e40b8c61b7
Main/System/Invest/InvestModel.cs
@@ -6,44 +6,51 @@
public class InvestModel : GameSystemManager<InvestModel>
{
    // public ILOpenServerActivityProxy activity;
    public const int FuncID = 25;
    public const int monthCardType = 1; // 月卡
    public const int foreverCardType = 2; //永久卡 权限
    //投资对应奖励
    Dictionary<int, Dictionary<int, List<Item>>> m_InvestItems = new Dictionary<int, Dictionary<int, List<Item>>>();
    Dictionary<int, int[][]> m_InvestItems = new Dictionary<int, int[][]>();
    Dictionary<int, int> m_InvestDays = new Dictionary<int, int>(); //投资对应天数
    Dictionary<int, int> m_InvestMaxDays = new Dictionary<int, int>();  //投资对应最大购买累加天数
    //投资对应充值ID
    Dictionary<int, int[]> m_InvestRechargeIds = new Dictionary<int, int[]>();
    Dictionary<int, int> m_InvestCTGIDToType = new Dictionary<int, int>();
    //投资对应购买情况
    Dictionary<int, InvestInfo> m_InvestInfos = new Dictionary<int, InvestInfo>();
    //{投资类型:[领取天,当前天]} 天从1开始
    Dictionary<int, List<List<int>>> m_InvestSingleInfos = new Dictionary<int, List<List<int>>>();
    //投资对应的红点
    Dictionary<int, Redpoint> m_Redpoints = new Dictionary<int, Redpoint>();
    //投资类型
    public List<int> investTypes = new List<int>();
    //--特权--
    //增加副本购买次数
    Dictionary<int, Dictionary<int, int>> m_InvestAddFBCount = new Dictionary<int, Dictionary<int, int>>();
    //副本购买次数免费的副本ID 和 m_InvestAddFBCount 配合使用 相当于 特权增加副本上限但是发包流程需和服务端商量
    Dictionary<int, int[]> m_InvestFreeFBID = new Dictionary<int, int[]>();
    //演武场增加上限
    Dictionary<int, int> m_InvestArenaMaxCnt = new Dictionary<int, int>();
    //祝福树能量增加上限
    Dictionary<int, int> m_InvestAddBlessEnergyCount = new Dictionary<int, int>();
    //永久卡 权限
    public const int foreverCardType = 12; //投资类型
    public const int monthCardType = 7; // 月卡7
    // 特权权限数量
    Dictionary<int, int> m_PrivilegeLins = new Dictionary<int, int>();
    // 战斗倍数开启对应特权
    Dictionary<int, int> m_PrivilegeFightSpeed = new Dictionary<int, int>();
    // 英雄积分招募开启的特权类型
    int[] heroScoreCallOpenType;
    public event Action onSelectUpdate;
    public event Action<int> onInvestUpdate;
    public const int redpointID = 20931;
    public Redpoint redpoint = new Redpoint(MainRedDot.REDPOINT_OPENSERVER, redpointID);
    public Redpoint redpoint1 = new Redpoint(MainRedDot.RedPoint_PrivilegeCard, MainRedDot.RedPoint_PrivilegeCard * 10 + 1);
    public Redpoint redpoint2 = new Redpoint(MainRedDot.RedPoint_PrivilegeCard, MainRedDot.RedPoint_PrivilegeCard * 10 + 2);
    public override void Init()
    {
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitialize;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        //通过配置决定是否有此投资项,如港台没有登录投资
        ParseConfig();
@@ -53,77 +60,225 @@
    public override void Release()
    {
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitialize;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
    }
    public bool IsOpen()
    {
        return FuncOpen.Instance.IsFuncOpen(FuncID);
        return FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.PrivilegeCard);
    }
    
    public void OnBeforePlayerDataInitialize()
    {
        m_InvestInfos.Clear();
        m_InvestSingleInfos.Clear();
        lastTotalBuyCountDict.Clear();
    }
    public void OnPlayerLoginOk()
    {
        UpdateRedpoint();
    }
    void ParseConfig()
    {
        investTypes.Clear();
        var funcConfig = FuncConfigConfig.Get("InvestCost");
        m_InvestRechargeIds = ConfigParse.ParseIntArrayDict(funcConfig.Numerical3);
        //m_Redpoints
        investTypes = m_InvestRechargeIds.Keys.ToList();
        investTypes.Sort();
        var configs = InvestConfig.GetValues();
        for (int i = 0; i < configs.Count; i++)
        m_InvestRechargeIds = ConfigParse.ParseIntArrayDict(funcConfig.Numerical1);
        foreach (var item in m_InvestRechargeIds)
        {
            var config = configs[i];
            if (!investTypes.Contains(config.type))
            {
                continue;
            }
            m_InvestCTGIDToType[item.Value[0]] = item.Key;
        }
            Dictionary<int, List<Item>> dict;
            if (!m_InvestItems.TryGetValue(config.type, out dict))
            {
                dict = new Dictionary<int, List<Item>>();
                m_InvestItems.Add(config.type, dict);
            }
        funcConfig = FuncConfigConfig.Get("InvestDay");
        m_InvestDays = ConfigParse.ParseIntDict(funcConfig.Numerical1);
        m_InvestMaxDays = ConfigParse.ParseIntDict(funcConfig.Numerical2);
        m_InvestItems = ConfigParse.ParseIntArray2Dict(funcConfig.Numerical3);
            List<Item> items;
            if (!dict.TryGetValue(config.id, out items))
            {
                items = new List<Item>();
                dict.Add(config.id, items);
            }
            var itemArray = config.award[1];    //1暂时约定月卡 永久卡,其他的自定义后续再定
            for (int j = 0; j < itemArray.Length; j++)
        funcConfig = FuncConfigConfig.Get("InvestPower");
        m_InvestAddFBCount = ConfigParse.ParseDictInDict(funcConfig.Numerical1);
        m_InvestFreeFBID = ConfigParse.ParseIntArrayDict(funcConfig.Numerical2);
        m_InvestArenaMaxCnt = ConfigParse.ParseIntDict(funcConfig.Numerical3);
        m_InvestAddBlessEnergyCount = ConfigParse.ParseIntDict(funcConfig.Numerical4);
        funcConfig = FuncConfigConfig.Get("PrivilegeCard");
        m_PrivilegeLins = ConfigParse.ParseIntDict(funcConfig.Numerical1);
        m_PrivilegeFightSpeed = ConfigParse.ParseIntDict(funcConfig.Numerical2);
        heroScoreCallOpenType = JsonMapper.ToObject<int[]>(funcConfig.Numerical3);
    }
    Dictionary<int, int> lastTotalBuyCountDict = new Dictionary<int, int>();
    void OnRechargeCountEvent(int ctgID)
    {
        if (m_InvestCTGIDToType.ContainsKey(ctgID))
        {
            var type = m_InvestCTGIDToType[ctgID];
            RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount);
            if (!DTC0403_tagPlayerLoginLoadOK.finishedLogin)
            {
                items.Add(new Item()
                {
                    id = itemArray[j][0],
                    countEx = itemArray[j][1],
                    bind = itemArray[j][2],
                });
                lastTotalBuyCountDict[type] = rechargeCount.totalCount;
                return;
            }
            var count = 0;
            lastTotalBuyCountDict.TryGetValue(type, out count);
            if (count < rechargeCount.totalCount)
            {
                lastTotalBuyCountDict[type] = rechargeCount.totalCount;
                UIManager.Instance.OpenWindow<PrivilegeActiveCardWin>(type);
            }
        }
    }
    public OrderInfoConfig GetOrderInfoId(int type)
    //获取投资剩余时间 秒
    public int GetInvestLeftTime(int type)
    {
        if (type == 1 && m_InvestInfos[type].InvestEndTime > 0)
        {
            //月卡 限时类型的投资 未到期就算投资
            return m_InvestInfos[type].InvestEndTime - TimeUtility.AllSeconds;
        }
        return 0;
    }
    //0-未投资 1-可领取 2-已领取
    public int GetInvestState(int type)
    {
        if (IsInvested(type))
        {
            if (m_InvestInfos[type].AwardState == 0)
            {
                return 1;
            }
            return 2;
        }
        return 0;
    }
    //判断是否购买了投资
    public bool IsInvested(int type)
    {
        if (!m_InvestInfos.ContainsKey(type))
        {
            return false;
        }
        if (type == 1)
        {
            //月卡 限时类型的投资 未到期就算投资
            return m_InvestInfos[type].InvestEndTime > 0 && m_InvestInfos[type].InvestEndTime > TimeUtility.AllSeconds;
        }
        //永久类型的投资 只要购买了就算投资
        return m_InvestInfos[type].InvestBuyTime > 0;
    }
    //type 投资类型
    public void SendGetReward(int type, int id = 0)
    {
        var pak = new CA541_tagCMGetInvestReward();
        pak.InvestType = (byte)type;
        pak.RewardIndex = (byte)id;
        GameNetSystem.Instance.SendInfo(pak);
    }
    //购买投资
    public void BuyInvest(int type)
    {
        RechargeManager.Instance.CTG(GetOrderInfo(type));
    }
    public void UpdateInvestInfo(HA338_tagSCInvestInfo package)
    {
        m_InvestInfos[package.InvestType] = new InvestInfo()
        {
            InvestBuyTime = (int)package.InvestBuyTime,
            InvestEndTime = (int)package.InvestEndTime,
            AwardState = package.AwardState
        };
        UpdateRedpoint();
        if (onInvestUpdate != null)
        {
            onInvestUpdate(package.InvestType);
        }
    }
    void UpdateRedpoint()
    {
        if (!IsOpen())
        {
            return;
        }
        redpoint1.state = GetInvestState(monthCardType) == 1 ? RedPointState.Simple : RedPointState.None;
        redpoint2.state = GetInvestState(foreverCardType) == 1 ? RedPointState.Simple : RedPointState.None;
    }
    #region 特权接口
    //副本增加的购买次数上限
    public int GetAddFBBuyCount(int _mapID)
    {
        int addCount = 0;
        foreach (var item in m_InvestAddFBCount)
        {
            if (!IsInvested(item.Key))
            {
                continue;
            }
            foreach (var mapID in item.Value.Keys)
            {
                if (mapID == _mapID)
                {
                    addCount += item.Value[mapID];
                }
            }
        }
        return addCount;
    }
    //副本免费的购买次数
    public bool GetFBIsFree(int _mapID)
    {
        foreach (var item in m_InvestFreeFBID)
        {
            if (!IsInvested(item.Key))
            {
                continue;
            }
            foreach (var mapID in item.Value)
            {
                if (mapID == _mapID)
                {
                    return true;
                }
            }
        }
        return false;
    }
    public int GetPrivilegeLins(int type)
    {
        if (m_PrivilegeLins.ContainsKey(type))
        {
            return m_PrivilegeLins[type];
        }
        return 0;
    }
    public OrderInfoConfig GetOrderInfo(int type)
    {
        var ids = m_InvestRechargeIds[type];
        for (int i = 0; i < ids.Length; i++)
@@ -137,241 +292,100 @@
        return null;
    }
    public bool hasInvestType(int type)
    public int GetCTGID(int type)
    {
        return investTypes.Contains(type);
        return m_InvestRechargeIds[type][0];
    }
    public int GetInvestPassDays(int type)
    public int[][] GetDayAwards(int type)
    {
        return m_InvestInfos.ContainsKey(type) ? m_InvestInfos[type].days : 0;
        return m_InvestItems[type];
    }
    //获得单投资的总收益
    public long GetTotalIncome(int type)
    //演武场凭证上限
    public int GetArenaAddMaxCount()
    {
        long income = 0;
        if (m_InvestItems.ContainsKey(type))
        int addCount = 0;
        foreach (var item in m_InvestArenaMaxCnt)
        {
            var keyList = m_InvestItems[type].Keys.ToList();
            for (int i = 0; i < keyList.Count; i++)
            if (!IsInvested(item.Key))
            {
                var items = m_InvestItems[type][keyList[i]];
                for (var j = 0; j < items.Count; j++)
                {
                    var item = items[j];
                    if (item.id == 20 || item.id == 30)
                        income += item.countEx;
                }
                continue;
            }
            addCount += item.Value;
        }
        return income;
        return addCount;
    }
    //id 为表里的ID
    //0-未投资 1-未达成 2-可领取 3-已领取
    public int GetSingleInvestState(int type, int id)
    //购买天数是否达上限
    public bool IsBuyMaxDay(int type)
    {
        if (IsInvested(type))
        if (m_InvestMaxDays.ContainsKey(type) && m_InvestInfos.ContainsKey(type))
        {
            var day = GetInvestPassDays(type);
            if (m_InvestItems.ContainsKey(type)
                && m_InvestItems[type].ContainsKey(id))
            if (m_InvestInfos[type].InvestEndTime > 0)
            {
                if (IsRewardGot(type, id))
                {
                    return 3;
                }
                var config = InvestConfig.Get(id);
                if (!m_InvestSingleInfos.ContainsKey(type))
                {
                    return 0;
                }
                var index = id % 100;
                //每个数按位存31个激活索引
                var listIndex = index / 31;
                var bitIndex = index % 31;
                return day < config.needDay ? 1 : 2;
                return (m_InvestInfos[type].InvestEndTime - TimeUtility.AllSeconds) / 60 / 60 / 24 + m_InvestDays[type] >= m_InvestMaxDays[type];
            }
        }
        return 0;
    }
    public bool TryGetItems(int type, int id, out List<Item> items)
    {
        items = null;
        if (m_InvestItems.ContainsKey(type))
        {
            return m_InvestItems[type].TryGetValue(id, out items);
        }
        return false;
    }
    public List<int> GetIdsByType(int type)
    //祝福能量上限
    public int GetBlessAddEnergyMax()
    {
        if (m_InvestItems.ContainsKey(type))
        int addCount = 0;
        foreach (var item in m_InvestAddBlessEnergyCount)
        {
            return m_InvestItems[type].Keys.ToList();
            if (!IsInvested(item.Key))
            {
                continue;
            }
            addCount += item.Value;
        }
        return null;
        return addCount;
    }
    //判断是否购买了投资
    public bool IsInvested(int type)
    //是否激活英雄积分召唤
    public bool IsActiveHeroScoreCall()
    {
        return m_InvestInfos.ContainsKey(type) && m_InvestInfos[type].money > 0;
    }
    //奖励是否已领取
    public bool IsRewardGot(int type, int id)
    {
        if (m_InvestSingleInfos.ContainsKey(type))
        foreach (var type in heroScoreCallOpenType)
        {
            var index = id % 100;
            //每个数按位存31个激活索引
            var listIndex = index / 31;
            var bitIndex = index % 31;
            return ((int)Math.Pow(2, bitIndex) & m_InvestSingleInfos[type][1][listIndex]) != 0;
            if (IsInvested(type))
            {
                return true;
            }
        }
        return false;
    }
    private void OnFuncStateChangeEvent(int id)
    public bool IsActiveFightSpeed(int speed)
    {
        if (id == FuncID)
        foreach (var item in m_PrivilegeFightSpeed)
        {
            // activity.StateUpdate(id);
            UpdateRedpoint();
        }
    }
    public void SendGetReward(int type, int id)
    {
        var pak = new CA541_tagCMGetInvestReward();
        pak.InvestType = (byte)type;
        pak.RewardIndex = (byte)(id % 100);
        GameNetSystem.Instance.SendInfo(pak);
    }
    //购买投资
    public void BuyInvest(int type)
    {
        RechargeManager.Instance.CTG(GetOrderInfoId(type));
    }
    public void UpdateInvestInfo(HA338_tagMCInvestInfo package)
    {
        if (!investTypes.Contains(package.InvestType))
        {
            return;
        }
        m_InvestInfos[package.InvestType] = new InvestInfo()
        {
            days = (int)package.CurDay,
            money = package.CurDay >= 1 ? 1 : 0,
        };
        List<List<int>> singleInfos;
        if (!m_InvestSingleInfos.TryGetValue(package.InvestType, out singleInfos))
        {
            singleInfos = new List<List<int>>();
            m_InvestSingleInfos.Add(package.InvestType, singleInfos);
        }
        singleInfos.Clear();
        singleInfos.Add(new List<int>());
        singleInfos.Add(new List<int>());
        singleInfos.Add(new List<int>());
        singleInfos[0].Add((int)package.CurDay);
        for (int i = 0; i < package.ValueCount; i++)
        {
            singleInfos[1].Add((int)package.RewardValue[i]);
            singleInfos[2].Add((int)package.ProgressValue[i]);
        }
        UpdateRedpoint();
        if (onInvestUpdate != null)
        {
            onInvestUpdate(package.InvestType);
        }
    }
    void UpdateRedpoint()
    {
        List<int> redpointTypes = new List<int>();
        if (IsOpen())
        {
            for (var i = 0; i < investTypes.Count; i++)
            if (!IsInvested(item.Key))
            {
                var type = investTypes[i];
                if (!IsInvested(type))
                {
                    continue;
                }
                var keyList = m_InvestItems[type].Keys.ToList();
                for (int j = 0; j < keyList.Count; j++)
                {
                    var id = keyList[j];
                    if (GetSingleInvestState(type, id) == 2)
                    {
                        redpointTypes.Add(type);
                        break;
                    }
                }
                continue;
            }
            if (item.Value == speed)
            {
                return true;
            }
        }
        var redList = m_Redpoints.Keys.ToList();
        for (int j = 0; j < redList.Count; j++)
        {
            var type = redList[j];
            m_Redpoints[type].state = redpointTypes.Contains(type) ? RedPointState.Simple : RedPointState.None;
        }
        return false;
    }
    #endregion
    //已经购买并领取所有物品
    public bool IsFinish()
    {
        for (int i = 0; i < investTypes.Count; i++)
        {
            int type = investTypes[i];
            //忽略永久卡
            if (type == foreverCardType)
                continue;
            var idsList = GetIdsByType(type);
            if (idsList.IsNullOrEmpty())
                continue;
            for (int j = 0; j < idsList.Count; j++)
            {
                int id = idsList[j];
                if (GetSingleInvestState(type, id) != 3)
                {
                    return false;
                }
            }
        }
        return true;
    }
    public struct InvestInfo
    {
        public int money;
        public int days;
        public int InvestBuyTime;    // 投资购买时间戳,永久的通过该时间判断是否有效或已过天数,任意类型均有该值,过期没有重置,前端自己判断
        public int InvestEndTime;    // 投资到期时间戳,非永久的通过该时间判断到期时间,有天数限制的才有值
        public int AwardState;    // 今日是否已领取奖励
    }
}