You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

663 lines
24 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using Google.Protobuf.WellKnownTypes;
using Sog;
using ProtoCSStruct;
using LitJson;
namespace Game
{
public enum ShopRefreshType
{
None = 0,
Common = 1, //固定天数
Week = 2, //每周一
Month = 3, //每月一日
WeekSomeDay = 4, //每周固定某天
SomeDayHour = 5, //每天x小时后刷新
}
public static class MarketShopSvc
{
public static int GetShopDataIndex(PlayerOnGame player, int shopId)
{
for (int i = 0; i < player.RoleData.MarketShopData.ShopData.Count; i++)
{
if (player.RoleData.MarketShopData.ShopData[i].ShopId == shopId)
{
return i;
}
}
return -1;
}
public static ref OneShopData GetShopDataByIndex(PlayerOnGame player, int index)
{
return ref player.RoleData.MarketShopData.ShopData[index];
}
// 返回index, -1表示失败
public static int CreateShopDataIfNotExist(PlayerOnGame player, int shopId, bool notifyClient)
{
int index = GetShopDataIndex(player, shopId);
if (index != -1)
{
return index;
}
ref var shopList = ref player.RoleData.MarketShopData.ShopData;
if (shopList.Count >= shopList.GetMaxCount())
{
TraceLog.Error("MarketShopSvc.CreateShopDataIfNotExist uid {0} shopId {1} not enough space",
player.UserID, shopId);
return -1;
}
var desc = MarketShopDescMgr.Instance.GetConfig(shopId);
if (desc == null || desc.goodsNum == 0)
{
TraceLog.Error("MarketShopSvc.CreateShopDataIfNotExist shopId {0} invalid params", shopId);
return -1;
}
var nowSec = GameServerUtils.GetTimeSecond();
var shopData = new OneShopData { ShopId = shopId, LastHandRefreshTime = nowSec };
{
if (!RefreshShop(player, ref shopData, desc))
{
TraceLog.Error("MarketShopSvc.CreateShopDataIfNotExist shopId {0} refresh shop fail", shopId);
return -1;
}
}
var nextAutoRefreshTime = GetNextAutoRefreshTime(ref shopData, nowSec);
shopData.NextAutoRefreshTime = nextAutoRefreshTime;
shopList.Add(ref shopData);
player.MakeDirty();
if (notifyClient)
{
SendPlayerShopRefreshRes(player, ref shopData);
}
TraceLog.Debug("MarketShopSvc.CreateShopDataIfNotExist shopId {0} succ", shopId);
return shopList.Count - 1;
}
public static CSErrCode MarketShopBuyGoods(PlayerOnGame player, ref CSMarketShopBuyGoodsReq req
, ref OneShopData oneShopdata, ref OneGridGoods gridGoods,ref CSMarketShopBuyGoodsRes res)
{
var goodsDesc = MarketShopGoodsDescMgr.Instance.GetConfigByInternal(gridGoods.GoodsId);
if (goodsDesc == null)
{
TraceLog.Error("MarketShopSvc.MarketShopBuyGoods invalid shopId {0} or goodsIndex {1}"
, req.ShopId, gridGoods.GoodsId);
return CSErrCode.Fail;
}
if (goodsDesc.maxBuyTimes > 0 && gridGoods.CurBuyTimes + req.BuyTimes > goodsDesc.maxBuyTimes)
{
TraceLog.Error(
"MarketShopSvc.MarketShopBuyGoods shopId {0} goodsIndex {1} curr buy {2} req buy {3} > max buy {4}"
, req.ShopId, gridGoods.GoodsId, gridGoods.CurBuyTimes, req.BuyTimes, goodsDesc.maxBuyTimes);
return CSErrCode.BuyTimesNotEnough;
}
if (goodsDesc.chapterCondition.Length > 0)
{
var chapterData = player.RoleData.ChapterData;
if (chapterData.ChapterId < goodsDesc.chapterCondition[0] &&
chapterData.BattleId < goodsDesc.chapterCondition[1])
{
TraceLog.Error(
"MarketShopSvc.MarketShopBuyGoods shopId {0} goodsIndex {1} chapter condition error"
, req.ShopId, gridGoods.GoodsId);
return CSErrCode.BuyTimesNotEnough;
}
}
JsonData costInfo = new JsonData();
var bagOp = new UnifyOp(player, BillChangeItemReason.BuyMarketShopGoods, req.ShopId.ToString());
for (int i = 0; i < goodsDesc.costGoodsType.Length; i++)
{
if (goodsDesc.costGoodsType[i] <= 0)
{
continue;
}
if (goodsDesc.costGoodsType[i] != (int)GoodsType.Items)
{
TraceLog.Error("MarketShopSvc.MarketShopBuyGoods invalid cost type {0}",
goodsDesc.costGoodsType[i]);
return CSErrCode.Fail;
}
var costNum = (long)goodsDesc.costGoodsNum[i] * req.BuyTimes;
var count = bagOp.GetItemCount(goodsDesc.costGoodsId[i]);
if (count < costNum)
{
return CSErrCode.Fail;
}
bagOp.CostItem(goodsDesc.costGoodsId[i], costNum);
var item = new JsonData
{
["cost_item_id"] = goodsDesc.costGoodsId[i],
["cost_type"] = goodsDesc.costGoodsType[i],
["buy_cost"] = costNum
};
costInfo.Add(item);
}
long buyNum = (long)req.BuyTimes * goodsDesc.buyGoodsNum;
bagOp.AddGoods(goodsDesc.buyGoodsType, goodsDesc.buyGoodsId, buyNum);
List<CSItemChgInfo> list = new List<CSItemChgInfo>();
var ret = bagOp.DoOp(retList:list);
if (ret != 0)
{
TraceLog.Error("MarketShopSvc.MarketShopBuyGoods uid {0} bag DoOp fail", player.UserID);
return ret;
}
foreach (var chgInfo in list)
{
if (chgInfo.ChgCount <= 0)
{
continue;
}
res.Rewards.Add(chgInfo);
}
TraceLog.Debug("MarketShopSvc.MarketShopBuyGoods succ, uid {0} shop {1} goodsIndex {2}"
, player.UserID, goodsDesc.shopId, goodsDesc.goodsIndex);
GameBDCLogUtils.ShopBuy(player, goodsDesc.buyGoodsType, goodsDesc.buyGoodsId, (int)buyNum,
costInfo.ToJson(), req.ShopId);
GameTALogUtils.LogShopBuy(player, goodsDesc.buyGoodsType, goodsDesc.buyGoodsId, (int)buyNum, ref costInfo,
req.ShopId, gridGoods.GoodsId);
TaskEXEvent.TriggerMarkShopEquip(player);
TaskEXEvent.TriggerBuyShopGoodsN(player, oneShopdata.ShopId, (int)buyNum);
return 0;
}
public static int GetOneGridGoodsPosByGoodsIndex(ref OneShopData oneShop, int goodsId)
{
if (goodsId <= 0)
{
return -1;
}
for (int i = 0; i < oneShop.GridGoods.Count; i++)
{
if (oneShop.GridGoods[i].GoodsId == goodsId)
{
return i;
}
}
return -1;
}
public static CSErrCode CostItemOnHandRefresh(PlayerOnGame player, MarketShopDesc marketdesc,
ref OneShopData shopData)
{
if (shopData.HandRefreshTimes < CommParamDescMgr.Instance.ShopReFreeTime.int_val)
{
shopData.HandRefreshTimes++;
shopData.LastHandRefreshTime = GameServerUtils.GetTimeSecond();
return CSErrCode.None;
}
var bagOp = new UnifyOp(player, BillChangeItemReason.RefreshMarketShop, marketdesc.shopId.ToString());
//var desc = CommParamDescMgr.Instance.ShopReCostFrag;
// var costId = desc.str_val;
// var costNum = desc.int_val;
//var num = bagOp.GetItemCount(desc.str_val);
//if (num < desc.int_val)
//{
var desc = CommParamDescMgr.Instance.ShopReCostDiam;
var num = bagOp.GetItemCount(desc.str_val);
var costId = desc.str_val;
var costNum = desc.int_val;
if (num < desc.int_val)
{
return CSErrCode.Fail;
}
// }
bagOp.CostItem(costId, costNum);
CSErrCode ret = bagOp.DoOp();
if (ret != CSErrCode.None)
{
TraceLog.Error("MarketShopSvc.CostItemOnHandRefresh uid {0} shopId {1} bagOp fail"
, player.UserID, shopData.ShopId);
}
return ret;
}
// 手动刷新商店
public static CSErrCode HandRefreshShop(PlayerOnGame player, MarketShopDesc marketdesc,
ref OneShopData shopData)
{
var ret = CostItemOnHandRefresh(player, marketdesc, ref shopData);
if (ret != CSErrCode.None)
{
return ret;
}
if (RefreshShop(player, ref shopData, marketdesc))
{
return CSErrCode.None;
}
return CSErrCode.SysFailure;
}
public static void AutoRefreshAllShop(PlayerOnGame player, long nowSec)
{
ref var shopDataList = ref player.RoleData.MarketShopData.ShopData;
for (int i = 0; i < shopDataList.Count; i++)
{
ref var shopData = ref shopDataList[i];
var shopId = shopDataList[i].ShopId;
var marketShopDesc = MarketShopDescMgr.Instance.GetConfig(shopId);
if (marketShopDesc == null || marketShopDesc.autoRefreshType <= 0)
{
continue;
}
AutoRefreshShop(player, ref shopData, nowSec);
}
}
private static void AutoRefreshShop(PlayerOnGame player, ref OneShopData shopData, long nowSec)
{
if (nowSec < shopData.NextAutoRefreshTime)
{
return;
}
MarketShopDesc desc = MarketShopDescMgr.Instance.GetConfig(shopData.ShopId);
if (desc == null)
{
return;
}
long nextAutoRefreshTime = GetNextAutoRefreshTime(ref shopData, nowSec);
if (nextAutoRefreshTime <= nowSec)
{
TraceLog.Error("MarketShopSvc.AutoRefreshShop shopId {0} error, next refreshTime {1} < now {2}",
shopData.ShopId, nextAutoRefreshTime, nowSec);
return;
}
if (!RefreshShop(player, ref shopData, desc))
{
return;
}
shopData.NextAutoRefreshTime = nextAutoRefreshTime;
shopData.HandRefreshTimes = 0;
SendPlayerShopRefreshRes(player,ref shopData);
player.MakeDirty();
}
public static void RefreshShopByAdv(PlayerOnGame player, int shopId)
{
ref var shopDataList = ref player.RoleData.MarketShopData.ShopData;
var index = -1;
for (var i = 0; i < shopDataList.Count; i++)
{
if (shopDataList[i].ShopId != shopId) continue;
index = i;
break;
}
if (index < 0)
{
return;
}
ref var shopData = ref shopDataList[index];
var desc = MarketShopDescMgr.Instance.GetConfig(shopId);
if (!RefreshShop(player, ref shopData, desc))
{
return;
}
SendPlayerShopRefreshRes(player,ref shopData);
player.MakeDirty();
}
private static long GetNextAutoRefreshTime(ref OneShopData shopData, long nowSec)
{
MarketShopDesc desc = MarketShopDescMgr.Instance.GetConfig(shopData.ShopId);
if (desc == null)
{
return 0;
}
long nextAutoRefreshTime = 0;
switch ((ShopRefreshType)desc.autoRefreshType)
{
case ShopRefreshType.Common:
nextAutoRefreshTime =
AppTime.GetNextTime(nowSec + AppTime.SECONDS_ADAY * (desc.autoRefreshDay - 1), 0, AppTime.GetGameResetHour());
break;
case ShopRefreshType.Week:
nextAutoRefreshTime = AppTime.GetNextTime(nowSec, 1, AppTime.GetGameResetHour());
break;
case ShopRefreshType.Month:
nextAutoRefreshTime = AppTime.GetNextMonthTime(nowSec);
break;
case ShopRefreshType.WeekSomeDay:
nextAutoRefreshTime = AppTime.GetNextTime(nowSec, desc.autoRefreshWeek, AppTime.GetGameResetHour());
break;
case ShopRefreshType.SomeDayHour:
var todayStartTime = AppTime.GetTodayStartTime(nowSec);
var hour = desc.autoRefreshHour;
var maxDuration = 24 / desc.autoRefreshHour;
var nextTime = todayStartTime;
for (var i = 1; i <= maxDuration; i++)
{
var curr = todayStartTime + (AppTime.SECONDS_AHOUR * hour * i);
if (curr > nowSec)
{
nextTime = curr;
break;
}
}
nextAutoRefreshTime = nextTime;
break;
}
return nextAutoRefreshTime;
}
public static bool RefreshShop(PlayerOnGame player, ref OneShopData shopData, MarketShopDesc marketdesc)
{
if (marketdesc.goodsNum <= 0)
{
TraceLog.Debug("MarketShopSvc.RefreshShop shopId {0} goods num is 0", shopData.ShopId);
return true;
}
var groupDesc = MarketShopGoodsDescMgr.Instance.GetGroup(shopData.ShopId);
if (groupDesc == null)
{
TraceLog.Error("MarketShopSvc.RefreshShop invalid shopId {0}", shopData.ShopId);
return false;
}
TraceLog.Debug("MarketShopSvc.RefreshShop player:{0} shopId {1}", player.UserID, shopData.ShopId);
shopData.GridGoods.Clear();
int playerLv = player.GetLevel();
var validGoods = new Dictionary<int, MarketShopGoodsDesc>();
// 找到所有符合条件的商品
GetValidGoods(player, validGoods, groupDesc, null, playerLv, 0);
int needNum = Math.Min(marketdesc.goodsNum, shopData.GridGoods.GetMaxCount());
var randomList=new List<MarketShopGoodsDesc>();
for (int i = 1; i <= needNum; i++)
{
var goodsDesc = RandomOneGoodsIndex(validGoods, i);
if (goodsDesc == null)
{
break;
}
validGoods.Remove(goodsDesc.goodsIndex);
randomList.Add(goodsDesc);
}
var list = randomList.ToArray();
list = SortShopGoods(shopData, list);
foreach (var g in list)
{
var goods = new OneGridGoods { GoodsId = g.InternalId };
shopData.GridGoods.Add(ref goods);
}
return true;
}
private static MarketShopGoodsDesc[] SortShopGoods(OneShopData shopData, MarketShopGoodsDesc[] goods)
{
var shopId = shopData.ShopId;
var shopDesc = MarketShopDescMgr.Instance.GetConfig(shopId);
if (shopDesc.sortingType is MarkSortingType.NoSorting or MarkSortingType.None)
{
return goods;
}
var ret = new List<MarketShopGoodsDesc>();
var sortGroup = shopDesc.sortingNum;
foreach (var t in sortGroup)
{
var type = t;
var array = goods.Where(g => g.buyGoodsType == type).ToArray();
if (array.Length == 0)
{
continue;
}
Array.Sort(array, (p1, p2) =>
{
var v1 = 0;
var v2 = 0;
switch (p1.buyGoodsType)
{
case (int)GoodsType.Items:
v1 = (int)ItemDescMgr.Instance.GetConfig(p1.buyGoodsId).quality;
v2 = (int)ItemDescMgr.Instance.GetConfig(p2.buyGoodsId).quality;
break;
case (int)GoodsType.Equipment:
v1 = (int)EquipDescMgr.Instance.GetConfig(p1.buyGoodsId).quality;
v2 = (int)EquipDescMgr.Instance.GetConfig(p2.buyGoodsId).quality;
break;
case (int)GoodsType.EquipSkin:
v1 = (int)RoleModelDescMgr.Instance.GetConfig(int.Parse(p1.buyGoodsId)).quality;
v2 = (int)RoleModelDescMgr.Instance.GetConfig(int.Parse(p2.buyGoodsId)).quality;
break;
}
return v2.CompareTo(v1);
});
ret.AddRange(array);
}
return ret.Count == 0 ? goods : ret.ToArray();
}
public static MarketShopGoodsDesc RandomOneGoodsIndex(
Dictionary<int, MarketShopGoodsDesc> validGoods, int pos)
{
var temp = new Dictionary<int, MarketShopGoodsDesc>();
foreach (var desc in validGoods.Values)
{
if (desc.goodsPos == pos)
{
temp.Add(desc.goodsIndex, desc);
}
}
// pos没有指定物品就从全部有效物品中随机
if (temp.Count == 0)
{
temp = validGoods;
}
if (temp.Count == 1)
{
return temp.Values.First();
}
int totalWeight = 0;
foreach (var desc in temp.Values)
{
totalWeight += desc.goodsWeight;
}
int randProp = GameServerUtils.GetApp().Rand.Next(totalWeight);
foreach (var desc in temp.Values)
{
if (randProp < desc.goodsWeight)
{
return desc;
}
randProp -= desc.goodsWeight;
}
return null;
}
public static void GetValidGoods(PlayerOnGame player, Dictionary<int, MarketShopGoodsDesc> validGoods,
SortedList<int, MarketShopGoodsDesc> shopGoodsGroupDesc, HashSet<int> exclude,
int playerLv, int pos)
{
//先清除所有,后逐个添加
validGoods.Clear();
foreach (MarketShopGoodsDesc desc in shopGoodsGroupDesc.Values)
{
// 排除部分物品
if (exclude != null && exclude.Contains(desc.goodsIndex))
{
continue;
}
// 不符合等级条件
if (playerLv < desc.limitLV_Min || (desc.limitLV_Max != 0 && playerLv > desc.limitLV_Max))
{
continue;
}
var currBattleId = player.RoleData.ChapterData.BattleId;
// 不符合章节条件
if (desc.Chapter_Min > 0 && (currBattleId < desc.Chapter_Min || currBattleId > desc.Chapter_Max))
{
continue;
}
// 0号适用于所有pos, 减少策划配置数量
if (desc.goodsPos == 0 || pos == 0 || desc.goodsPos == pos)
{
validGoods.Add(desc.goodsIndex, desc);
}
}
}
public static bool NeedRefreshShop(PlayerOnGame player, ref OneShopData shopData, MarketShopDesc desc)
{
// 商店配置发送变化时重新刷新
if (shopData.GridGoods.Count != desc.goodsNum)
{
return true;
}
int level = player.GetLevel();
// 简单处理, 只要商店有一个商品不符合条件就重新刷新商店
for (int i = 0; i < shopData.GridGoods.Count; i++)
{
ref var goods = ref shopData.GridGoods[i];
var goodsDesc = MarketShopGoodsDescMgr.Instance.GetConfigByInternal(goods.GoodsId);
if (goodsDesc == null)
{
return true;
}
if (level < goodsDesc.limitLV_Min || level > goodsDesc.limitLV_Max)
{
return true;
}
}
return false;
}
public static void RefreshAllShop(PlayerOnGame player, bool notifyClient)
{
ref var shopList = ref player.RoleData.MarketShopData.ShopData;
// 删除不存在的商店
for (int i = shopList.Count - 1; i >= 0; i--)
{
var desc = MarketShopDescMgr.Instance.GetConfig(shopList[i].ShopId);
if (desc == null)
{
player.RoleData.MarketShopData.ShopData.RemoveAt(i);
}
}
// 开启或刷新商店
foreach (var desc in MarketShopDescMgr.Instance.ItemTable.Values)
{
int index = GetShopDataIndex(player, desc.shopId);
if (index == -1)
{
if (SystemUnlockSvc.IsUnlockSys(player, desc.shopUnlock))
{
CreateShopDataIfNotExist(player, desc.shopId, notifyClient);
}
continue;
}
ref OneShopData shopData = ref GetShopDataByIndex(player, index);
if (NeedRefreshShop(player, ref shopData, desc)) //配置变化强制刷新
{
RefreshShop(player, ref shopData, desc);
if (notifyClient)
{
SendPlayerShopRefreshRes(player, ref shopData);
}
}
}
}
public static void SendPlayerShopRefreshRes(PlayerOnGame player, ref OneShopData shopData)
{
var res = new CSMarketShopRefreshRes { ShopData = shopData };
player.SendToClient((int)CSGameMsgID.MarketShopRefreshRes, ref res);
}
public static void OnNewDayStart(PlayerOnGame player, bool notifyClient)
{
ResetShopHeadTimes(player);
}
public static void ResetShopHeadTimes(PlayerOnGame player)
{
var now = AppTime.GetNowSysSecond();
ref var marketShopData = ref player.RoleData.MarketShopData;
ref var shopList = ref marketShopData.ShopData;
for (int i = 0; i < shopList.Count; i++)
{
ref var shopData = ref shopList[i];
if (AppTime.IsSameDay(now, shopData.LastHandRefreshTime))
{
continue;
}
shopData.HandRefreshTimes = 0;
shopData.LastHandRefreshTime = now;
SendPlayerShopRefreshRes(player, ref shopData);
}
}
}
}