Half the handlers were still answering with a bare 0 or -1 even though the whole retcode table is generated. Values on the wire are unchanged, they just read properly now. Same for the item hint reasons. ActionReasonType is a generated enum and we were redeclaring six of its members as private consts in four different files.
157 lines
6.3 KiB
C#
157 lines
6.3 KiB
C#
using Yuanshen.Common.Data.Excel;
|
|
using Yuanshen.Gameserver.Controllers.Attributes;
|
|
using Yuanshen.Gameserver.Controllers.Result;
|
|
using Yuanshen.Gameserver.Database;
|
|
using Yuanshen.Gameserver.Game;
|
|
using Yuanshen.Gameserver.Network.Session;
|
|
using Yuanshen.Protocol;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
namespace Yuanshen.Gameserver.Controllers;
|
|
|
|
[NetController]
|
|
internal sealed class ShopController : ControllerBase
|
|
{
|
|
|
|
[NetCommand(CmdType.GetShopmallDataReq)]
|
|
public ValueTask<IResult> OnGetShopmallDataReq(ExcelTableCollection excel)
|
|
{
|
|
GetShopmallDataRsp rsp = new() { Retcode = Retcode.RET_SUCC };
|
|
|
|
foreach (ShopmallEntranceExcel entrance in excel.GetTable(ExcelType.ShopmallEntrance)
|
|
.Items.OfType<ShopmallEntranceExcel>().OrderBy(entrance => entrance.Order))
|
|
{
|
|
rsp.ShopTypeList.Add(entrance.ShopType);
|
|
}
|
|
|
|
return ValueTask.FromResult(Response(CmdType.GetShopmallDataRsp, rsp));
|
|
}
|
|
|
|
[NetCommand(CmdType.GetShopReq)]
|
|
public ValueTask<IResult> OnGetShopReq(Player player, ExcelTableCollection excel)
|
|
{
|
|
GetShopReq req = Packet!.DecodeBody<GetShopReq>();
|
|
|
|
Shop shop = new() { ShopType = req.ShopType };
|
|
|
|
foreach (ShopGoodsExcel goods in Goods(excel).Where(goods => goods.ShopType == req.ShopType)
|
|
.OrderBy(goods => goods.SortLevel).ThenBy(goods => goods.GoodsId))
|
|
{
|
|
shop.GoodsList.Add(BuildGoods(player, goods));
|
|
}
|
|
|
|
return ValueTask.FromResult(Response(CmdType.GetShopRsp, new GetShopRsp { Retcode = Retcode.RET_SUCC, Shop = shop }));
|
|
}
|
|
|
|
[NetCommand(CmdType.BuyGoodsReq)]
|
|
public async ValueTask<IResult> OnBuyGoodsReq(NetSession session, Player player, ExcelTableCollection excel,
|
|
PlayerPersistence persistence, ILogger<ShopController> logger)
|
|
{
|
|
BuyGoodsReq req = Packet!.DecodeBody<BuyGoodsReq>();
|
|
|
|
uint goodsId = req.Goods?.GoodsId ?? 0;
|
|
uint count = Math.Max(req.BuyCount, 1u);
|
|
|
|
ShopGoodsExcel? goods = Goods(excel).FirstOrDefault(candidate => candidate.GoodsId == goodsId);
|
|
if (goods is null)
|
|
return Response(CmdType.BuyGoodsRsp, new BuyGoodsRsp { Retcode = Retcode.RET_SHOP_CONTENT_NOT_MATCH, ShopType = req.ShopType });
|
|
|
|
uint bought = player.BoughtGoods.GetValueOrDefault(goodsId);
|
|
if (goods.BuyLimit != 0 && bought + count > goods.BuyLimit)
|
|
return Response(CmdType.BuyGoodsRsp, new BuyGoodsRsp { Retcode = Retcode.RET_SHOP_CONTENT_NOT_MATCH, ShopType = req.ShopType });
|
|
|
|
if (player.Hcoin < goods.CostHcoin * count || player.Scoin < goods.CostScoin * count)
|
|
{
|
|
logger.LogInformation("Shop refused {goods}: not enough currency", goodsId);
|
|
return Response(CmdType.BuyGoodsRsp, new BuyGoodsRsp { Retcode = Retcode.RET_SHOP_CONTENT_NOT_MATCH, ShopType = req.ShopType });
|
|
}
|
|
|
|
foreach (ShopCostItem cost in goods.CostItems.Where(cost => cost.Id != 0))
|
|
{
|
|
if (player.Materials.GetValueOrDefault(cost.Id) < cost.Count * count)
|
|
{
|
|
logger.LogInformation("Shop refused {goods}: need {n}x {item}", goodsId, cost.Count * count, cost.Id);
|
|
return Response(CmdType.BuyGoodsRsp, new BuyGoodsRsp { Retcode = Retcode.RET_SHOP_CONTENT_NOT_MATCH, ShopType = req.ShopType });
|
|
}
|
|
}
|
|
|
|
player.Hcoin -= goods.CostHcoin * count;
|
|
player.Scoin -= goods.CostScoin * count;
|
|
|
|
StoreItemChangeNotify store = new() { StoreType = StoreType.StorePack };
|
|
|
|
foreach (ShopCostItem cost in goods.CostItems.Where(cost => cost.Id != 0))
|
|
{
|
|
player.TakeMaterial(cost.Id, cost.Count * count);
|
|
store.ItemList.Add(BuildMaterial(player, cost.Id));
|
|
}
|
|
|
|
uint gained = goods.ItemCount * count;
|
|
bool isWeapon = excel.GetTable(ExcelType.Weapon).Items.OfType<WeaponExcel>().Any(weapon => weapon.Id == goods.ItemId);
|
|
|
|
if (isWeapon)
|
|
{
|
|
for (uint made = 0; made < Math.Min(gained, 50u); made++)
|
|
store.ItemList.Add(player.CreateWeapon(goods.ItemId).AsItem());
|
|
}
|
|
else
|
|
{
|
|
player.GiveMaterial(goods.ItemId, gained);
|
|
store.ItemList.Add(BuildMaterial(player, goods.ItemId));
|
|
}
|
|
|
|
player.BoughtGoods[goodsId] = bought + count;
|
|
|
|
await session.NotifyAsync(CmdType.StoreItemChangeNotify, store);
|
|
await session.NotifyAsync(CmdType.PlayerPropNotify, player.BuildCurrencyProps());
|
|
|
|
ItemAddHintNotify hint = new() { Reason = (uint)ActionReasonType.ActionReasonShop };
|
|
hint.ItemList.Add(new ItemHint { ItemId = goods.ItemId, Count = gained, IsNew = false });
|
|
await session.NotifyAsync(CmdType.ItemAddHintNotify, hint);
|
|
|
|
await persistence.SaveAsync();
|
|
|
|
logger.LogInformation("Shop {shop}: bought {count}x goods {goods} -> {n}x item {item}",
|
|
req.ShopType, count, goodsId, gained, goods.ItemId);
|
|
|
|
return Response(CmdType.BuyGoodsRsp, new BuyGoodsRsp
|
|
{
|
|
Retcode = Retcode.RET_SUCC,
|
|
ShopType = req.ShopType,
|
|
BuyCount = count,
|
|
Goods = BuildGoods(player, goods)
|
|
});
|
|
}
|
|
|
|
private static IEnumerable<ShopGoodsExcel> Goods(ExcelTableCollection excel)
|
|
=> excel.GetTable(ExcelType.ShopGoods).Items.OfType<ShopGoodsExcel>();
|
|
|
|
private static ShopGoods BuildGoods(Player player, ShopGoodsExcel goods)
|
|
{
|
|
ShopGoods result = new()
|
|
{
|
|
GoodsId = goods.GoodsId,
|
|
GoodsItem = new ItemParam { ItemId = goods.ItemId, Count = goods.ItemCount },
|
|
Scoin = goods.CostScoin,
|
|
Hcoin = goods.CostHcoin,
|
|
BoughtNum = player.BoughtGoods.GetValueOrDefault(goods.GoodsId),
|
|
BuyLimit = goods.BuyLimit,
|
|
MinLevel = goods.MinPlayerLevel,
|
|
MaxLevel = goods.MaxPlayerLevel == 0 ? 99u : goods.MaxPlayerLevel,
|
|
BeginTime = 0,
|
|
EndTime = uint.MaxValue
|
|
};
|
|
|
|
foreach (ShopCostItem cost in goods.CostItems.Where(cost => cost.Id != 0))
|
|
result.CostItemList.Add(new ItemParam { ItemId = cost.Id, Count = cost.Count });
|
|
|
|
return result;
|
|
}
|
|
|
|
private static Item BuildMaterial(Player player, uint itemId) => new()
|
|
{
|
|
ItemId = itemId,
|
|
Guid = player.MaterialGuid(itemId),
|
|
Material = new Material { Count = player.Materials.GetValueOrDefault(itemId) }
|
|
};
|
|
}
|