mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
feat: offering system
This commit is contained in:
22
Common/Data/Excel/OfferingLevelConfigExcel.cs
Normal file
22
Common/Data/Excel/OfferingLevelConfigExcel.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
namespace EggLink.DanhengServer.Data.Excel;
|
||||
|
||||
[ResourceEntity("OfferingLevelConfig.json")]
|
||||
public class OfferingLevelConfigExcel : ExcelResource
|
||||
{
|
||||
public int ItemCost { get; set; }
|
||||
public int Level { get; set; }
|
||||
public int RewardID { get; set; }
|
||||
public int TypeID { get; set; }
|
||||
public int UnlockID { get; set; }
|
||||
|
||||
public override int GetId()
|
||||
{
|
||||
return TypeID * 1000 + Level;
|
||||
}
|
||||
|
||||
public override void Loaded()
|
||||
{
|
||||
GameData.OfferingLevelConfigData.TryAdd(TypeID, []);
|
||||
GameData.OfferingLevelConfigData[TypeID].Add(Level, this);
|
||||
}
|
||||
}
|
||||
23
Common/Data/Excel/OfferingTypeConfigExcel.cs
Normal file
23
Common/Data/Excel/OfferingTypeConfigExcel.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace EggLink.DanhengServer.Data.Excel;
|
||||
|
||||
[ResourceEntity("OfferingTypeConfig.json")]
|
||||
public class OfferingTypeConfigExcel : ExcelResource
|
||||
{
|
||||
public int MaxLevel { get; set; }
|
||||
public int ItemID { get; set; }
|
||||
public int ActivityModuleID { get; set; }
|
||||
public int LongTailLimit { get; set; }
|
||||
public int ID { get; set; }
|
||||
public int UnlockID { get; set; }
|
||||
public bool IsAutoOffer { get; set; }
|
||||
|
||||
public override int GetId()
|
||||
{
|
||||
return ID;
|
||||
}
|
||||
|
||||
public override void Loaded()
|
||||
{
|
||||
GameData.OfferingTypeConfigData.TryAdd(ID, this);
|
||||
}
|
||||
}
|
||||
@@ -111,6 +111,13 @@ public static class GameData
|
||||
|
||||
#endregion
|
||||
|
||||
#region Offering
|
||||
|
||||
public static Dictionary<int, OfferingTypeConfigExcel> OfferingTypeConfigData { get; private set; } = [];
|
||||
public static Dictionary<int, Dictionary<int, OfferingLevelConfigExcel>> OfferingLevelConfigData { get; private set; } = [];
|
||||
|
||||
#endregion
|
||||
|
||||
#region Maze
|
||||
|
||||
public static Dictionary<int, NPCDataExcel> NpcDataData { get; private set; } = [];
|
||||
|
||||
37
Common/Database/Inventory/OfferingData.cs
Normal file
37
Common/Database/Inventory/OfferingData.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using EggLink.DanhengServer.Data;
|
||||
using EggLink.DanhengServer.Data.Excel;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using SqlSugar;
|
||||
|
||||
namespace EggLink.DanhengServer.Database.Inventory;
|
||||
|
||||
[SugarTable("offering_data")]
|
||||
public class OfferingData : BaseDatabaseDataHelper
|
||||
{
|
||||
[SugarColumn(IsJson = true, ColumnDataType = "TEXT")]
|
||||
public Dictionary<int, OfferingTypeData> Offerings { get; set; } = [];
|
||||
}
|
||||
|
||||
public class OfferingTypeData
|
||||
{
|
||||
public OfferingState State { get; set; } = OfferingState.Open;
|
||||
public int CurExp { get; set; }
|
||||
public int OfferingId { get; set; }
|
||||
public int Level { get; set; }
|
||||
public List<int> TakenReward { get; set; } = [];
|
||||
|
||||
public OfferingInfo ToProto()
|
||||
{
|
||||
var totalExp = CurExp + Enumerable.Range(1, Level).Select(level => GameData.OfferingLevelConfigData.GetValueOrDefault(OfferingId)?.GetValueOrDefault(level)).OfType<OfferingLevelConfigExcel>().Sum(config => config.ItemCost);
|
||||
|
||||
return new OfferingInfo
|
||||
{
|
||||
OfferingState = State,
|
||||
HasTakenRewardIdList = { TakenReward.Select(x => (uint)x) },
|
||||
LevelExp = (uint)CurExp,
|
||||
OfferingId = (uint)OfferingId,
|
||||
OfferingLevel = (uint)Level,
|
||||
TotalExp = (uint)totalExp
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -414,7 +414,7 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<List<ItemData>> HandleReward(int rewardId, bool notify = false)
|
||||
public async ValueTask<List<ItemData>> HandleReward(int rewardId, bool notify = false, bool sync = true)
|
||||
{
|
||||
GameData.RewardDataData.TryGetValue(rewardId, out var rewardData);
|
||||
if (rewardData == null) return [];
|
||||
@@ -426,7 +426,8 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
if (i != null) items.Add(i);
|
||||
}
|
||||
|
||||
await Player.SendPacket(new PacketPlayerSyncScNotify(items));
|
||||
if (sync)
|
||||
await Player.SendPacket(new PacketPlayerSyncScNotify(items));
|
||||
|
||||
var hCoin = await AddItem(1, rewardData.Hcoin, notify, sync: false);
|
||||
if (hCoin != null)
|
||||
|
||||
140
GameServer/Game/Inventory/OfferingManager.cs
Normal file
140
GameServer/Game/Inventory/OfferingManager.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using EggLink.DanhengServer.Data;
|
||||
using EggLink.DanhengServer.Database;
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.GameServer.Game.Player;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.PlayerSync;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Game.Inventory;
|
||||
|
||||
public class OfferingManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
{
|
||||
public OfferingData Data = DatabaseHelper.Instance!.GetInstanceOrCreateNew<OfferingData>(player.Uid);
|
||||
|
||||
public OfferingTypeData? GetOfferingData(int offeringId)
|
||||
{
|
||||
if (Data.Offerings.TryGetValue(offeringId, out var offeringData))
|
||||
{
|
||||
return offeringData;
|
||||
}
|
||||
|
||||
var gameData = GameData.OfferingTypeConfigData.GetValueOrDefault(offeringId); // create a new one
|
||||
if (gameData == null) return null;
|
||||
|
||||
var unlockId = gameData.UnlockID;
|
||||
var data = new OfferingTypeData
|
||||
{
|
||||
OfferingId = offeringId,
|
||||
State = OfferingState.Lock
|
||||
};
|
||||
|
||||
if (Player.QuestManager!.UnlockHandler.GetUnlockStatus(unlockId))
|
||||
{
|
||||
data.State = OfferingState.Open;
|
||||
}
|
||||
|
||||
Data.Offerings[offeringId] = data;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public async ValueTask UpdateOfferingData()
|
||||
{
|
||||
List<OfferingTypeData> syncData = [];
|
||||
foreach (var offering in Data.Offerings.Values)
|
||||
{
|
||||
var gameData = GameData.OfferingTypeConfigData.GetValueOrDefault(offering.OfferingId); // create a new one
|
||||
if (gameData == null) continue;
|
||||
|
||||
if (Player.QuestManager!.UnlockHandler.GetUnlockStatus(gameData.UnlockID) &&
|
||||
offering.State != OfferingState.Open)
|
||||
{
|
||||
offering.State = OfferingState.Open;
|
||||
syncData.Add(offering);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Player.QuestManager!.UnlockHandler.GetUnlockStatus(gameData.UnlockID) ||
|
||||
offering.State == OfferingState.Lock) continue;
|
||||
|
||||
offering.State = OfferingState.Lock;
|
||||
syncData.Add(offering);
|
||||
}
|
||||
|
||||
foreach (var data in syncData)
|
||||
{
|
||||
await Player.SendPacket(new PacketOfferingInfoScNotify(data));
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<(Retcode, OfferingTypeData? data)> SubmitOfferingItem(int offeringId)
|
||||
{
|
||||
var offering = GetOfferingData(offeringId);
|
||||
if (offering is not { State: OfferingState.Open }) return (Retcode.RetOfferingNotUnlock, null);
|
||||
|
||||
var gameData = GameData.OfferingTypeConfigData.GetValueOrDefault(offeringId);
|
||||
if (gameData == null) return (Retcode.RetOfferingNotUnlock, null);
|
||||
|
||||
if (offering.Level >= gameData.MaxLevel) return (Retcode.RetOfferingReachMaxLevel, offering);
|
||||
|
||||
var item = Player.InventoryManager!.GetItem(gameData.ItemID);
|
||||
if (item is not { Count: >= 1 }) return (Retcode.RetOfferingItemNotEnough, offering);
|
||||
|
||||
var exp = item.Count;
|
||||
while (true)
|
||||
{
|
||||
if (offering.Level >= gameData.MaxLevel) break;
|
||||
var config = GameData.OfferingLevelConfigData.GetValueOrDefault(offeringId)?.GetValueOrDefault(offering.Level + 1);
|
||||
if (config == null) break;
|
||||
|
||||
if (exp + offering.CurExp < config.ItemCost)
|
||||
{
|
||||
offering.CurExp += exp;
|
||||
exp = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
exp -= config.ItemCost - offering.CurExp;
|
||||
offering.Level++;
|
||||
offering.CurExp = 0;
|
||||
}
|
||||
|
||||
await Player.InventoryManager!.RemoveItem(item.ItemId, item.Count - exp);
|
||||
|
||||
return (Retcode.RetSucc, offering);
|
||||
}
|
||||
|
||||
public async ValueTask<(Retcode, OfferingTypeData? data, List<ItemData> reward)> TakeOfferingReward(int offeringId, List<int> takeList)
|
||||
{
|
||||
var offering = GetOfferingData(offeringId);
|
||||
if (offering is not { State: OfferingState.Open }) return (Retcode.RetOfferingNotUnlock, null, []);
|
||||
|
||||
var gameData = GameData.OfferingTypeConfigData.GetValueOrDefault(offeringId);
|
||||
if (gameData == null) return (Retcode.RetOfferingNotUnlock, offering, []);
|
||||
|
||||
List<int> rewardIdList = [];
|
||||
foreach (var excel in takeList.Select(take => GameData.OfferingLevelConfigData.GetValueOrDefault(offeringId)?.GetValueOrDefault(take)))
|
||||
{
|
||||
if (excel != null && excel.Level <= offering.Level && !offering.TakenReward.Contains(excel.Level))
|
||||
{
|
||||
rewardIdList.Add(excel.RewardID);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Retcode.RetOfferingLevelNotUnlock, offering, []);
|
||||
}
|
||||
}
|
||||
|
||||
offering.TakenReward.AddRange(takeList);
|
||||
List<ItemData> reward = [];
|
||||
foreach (var id in rewardIdList)
|
||||
{
|
||||
reward.AddRange(await Player.InventoryManager!.HandleReward(id, sync:false));
|
||||
}
|
||||
|
||||
await Player.SendPacket(new PacketPlayerSyncScNotify(reward));
|
||||
|
||||
return (Retcode.RetSucc, offering, reward);
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using static EggLink.DanhengServer.GameServer.Plugin.Event.PluginEvent;
|
||||
using OfferingManager = EggLink.DanhengServer.GameServer.Game.Inventory.OfferingManager;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Game.Player;
|
||||
|
||||
@@ -62,6 +63,7 @@ public class PlayerInstance(PlayerData data)
|
||||
|
||||
public GachaManager? GachaManager { get; private set; }
|
||||
public ShopService? ShopService { get; private set; }
|
||||
public OfferingManager? OfferingManager { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -184,6 +186,7 @@ public class PlayerInstance(PlayerData data)
|
||||
QuestManager = new QuestManager(this);
|
||||
TrainPartyManager = new TrainPartyManager(this);
|
||||
MatchThreeManager = new MatchThreeManager(this);
|
||||
OfferingManager = new OfferingManager(this);
|
||||
|
||||
PlayerUnlockData = InitializeDatabase<PlayerUnlockData>();
|
||||
SceneData = InitializeDatabase<SceneData>();
|
||||
@@ -416,6 +419,9 @@ public class PlayerInstance(PlayerData data)
|
||||
if (SceneInstance != null)
|
||||
await SceneInstance.OnHeartBeat();
|
||||
|
||||
if (OfferingManager != null)
|
||||
await OfferingManager.UpdateOfferingData();
|
||||
|
||||
DatabaseHelper.ToSaveUidList.SafeAdd(Uid);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Offering;
|
||||
|
||||
[Opcode(CmdIds.GetOfferingInfoCsReq)]
|
||||
public class HandlerGetOfferingInfoCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = GetOfferingInfoCsReq.Parser.ParseFrom(data);
|
||||
|
||||
List<OfferingTypeData> dataList = [];
|
||||
dataList.AddRange(req.OfferingIdList.Select(id => connection.Player!.OfferingManager!.GetOfferingData((int)id)).OfType<OfferingTypeData>());
|
||||
|
||||
await connection.SendPacket(new PacketGetOfferingInfoScRsp(dataList));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Offering;
|
||||
|
||||
[Opcode(CmdIds.SubmitOfferingItemCsReq)]
|
||||
public class HandlerSubmitOfferingItemCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = SubmitOfferingItemCsReq.Parser.ParseFrom(data);
|
||||
|
||||
var res = await connection.Player!.OfferingManager!.SubmitOfferingItem((int)req.OfferingId);
|
||||
|
||||
await connection.SendPacket(new PacketSubmitOfferingItemScRsp(res.Item1, res.data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Offering;
|
||||
|
||||
[Opcode(CmdIds.TakeOfferingRewardCsReq)]
|
||||
public class HandlerTakeOfferingRewardCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = TakeOfferingRewardCsReq.Parser.ParseFrom(data);
|
||||
var res = await connection.Player!.OfferingManager!.TakeOfferingReward((int)req.OfferingId,
|
||||
req.TakeOfferingRewardIdList.Select(x => (int)x).ToList());
|
||||
|
||||
await connection.SendPacket(new PacketTakeOfferingRewardScRsp(res.Item1, res.data, res.reward));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
|
||||
public class PacketGetOfferingInfoScRsp : BasePacket
|
||||
{
|
||||
public PacketGetOfferingInfoScRsp(List<OfferingTypeData> dataList) : base(CmdIds.GetOfferingInfoScRsp)
|
||||
{
|
||||
var proto = new GetOfferingInfoScRsp
|
||||
{
|
||||
OfferingInfoList = { dataList.Select(data => data.ToProto()).ToList() }
|
||||
};
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
|
||||
public class PacketOfferingInfoScNotify : BasePacket
|
||||
{
|
||||
public PacketOfferingInfoScNotify(OfferingTypeData data) : base(CmdIds.OfferingInfoScNotify)
|
||||
{
|
||||
var proto = new OfferingInfoScNotify
|
||||
{
|
||||
OfferingInfo = data.ToProto()
|
||||
};
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
|
||||
public class PacketSubmitOfferingItemScRsp : BasePacket
|
||||
{
|
||||
public PacketSubmitOfferingItemScRsp(Retcode ret, OfferingTypeData? data) : base(CmdIds.SubmitOfferingItemScRsp)
|
||||
{
|
||||
var proto = new SubmitOfferingItemScRsp
|
||||
{
|
||||
Retcode = (uint)ret
|
||||
};
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
proto.OfferingInfo = data.ToProto();
|
||||
}
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Offering;
|
||||
|
||||
public class PacketTakeOfferingRewardScRsp : BasePacket
|
||||
{
|
||||
public PacketTakeOfferingRewardScRsp(Retcode ret, OfferingTypeData? data, List<ItemData> reward) : base(CmdIds.TakeOfferingRewardScRsp)
|
||||
{
|
||||
var proto = new TakeOfferingRewardScRsp
|
||||
{
|
||||
Retcode = (uint)ret,
|
||||
};
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
proto.OfferingInfo = data.ToProto();
|
||||
proto.Reward = new ItemList
|
||||
{
|
||||
ItemList_ = { reward.Select(x => x.ToProto()) }
|
||||
};
|
||||
}
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user