feat: grid fight basic feature

This commit is contained in:
StopWuyu
2025-10-26 12:06:07 +08:00
parent 443a1f6791
commit 4a721d37df
42 changed files with 3857 additions and 95 deletions

View File

@@ -0,0 +1,73 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Internationalization;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.Command.Command.Cmd;
[CommandInfo("grid", "Game.Command.Grid.Desc", "Game.Command.Grid.Usage")]
public class CommandGrid : ICommand
{
[CommandMethod("role")]
public async ValueTask AddRole(CommandArg arg)
{
if (arg.Target == null)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.PlayerNotFound"));
return;
}
var inst = arg.Target.Player!.GridFightManager?.GridFightInstance;
if (inst == null)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Grid.NotInGame"));
return;
}
if (arg.BasicArgs.Count < 2)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.InvalidArguments"));
return;
}
var roleId = (uint)arg.GetInt(0);
var tier = (uint)arg.GetInt(1);
if (!GameData.GridFightRoleStarData.ContainsKey(roleId << 2 | tier))
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Grid.InvalidRole"));
return;
}
await inst.GetComponent<GridFightAvatarComponent>().AddAvatar(roleId, tier);
await arg.SendMsg(I18NManager.Translate("Game.Command.Grid.AddedRole"));
}
[CommandMethod("gold")]
public async ValueTask UpdateGold(CommandArg arg)
{
if (arg.Target == null)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.PlayerNotFound"));
return;
}
var inst = arg.Target.Player!.GridFightManager?.GridFightInstance;
if (inst == null)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Grid.NotInGame"));
return;
}
if (arg.BasicArgs.Count < 1)
{
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.InvalidArguments"));
return;
}
var gold = arg.GetInt(0);
await inst.GetComponent<GridFightBasicComponent>().UpdateGoldNum(gold, true, GridFightSrc.KGridFightSrcNone);
await arg.SendMsg(I18NManager.Translate("Game.Command.Grid.UpdateGold", gold.ToString()));
}
}

View File

@@ -0,0 +1,29 @@
using Newtonsoft.Json;
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("GridFightPlayerLevel.json")]
public class GridFightPlayerLevelExcel : ExcelResource
{
public uint PlayerLevel { get; set; }
public uint LevelUpExp { get; set; }
public uint AvatarMaxNumber { get; set; }
public uint Rarity1Weight { get; set; }
public uint Rarity2Weight { get; set; }
public uint Rarity3Weight { get; set; }
public uint Rarity4Weight { get; set; }
public uint Rarity5Weight { get; set; }
[JsonIgnore] public List<uint> RarityWeights =>
[Rarity1Weight, Rarity2Weight, Rarity3Weight, Rarity4Weight, Rarity5Weight];
public override int GetId()
{
return (int)PlayerLevel;
}
public override void Loaded()
{
GameData.GridFightPlayerLevelData.TryAdd(PlayerLevel, this);
}
}

View File

@@ -0,0 +1,19 @@
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("GridFightRoleStar.json")]
public class GridFightRoleStarExcel : ExcelResource
{
public uint ID { get; set; }
public uint Star { get; set; }
public uint BEID { get; set; }
public override int GetId()
{
return (int)ID;
}
public override void Loaded()
{
GameData.GridFightRoleStarData.TryAdd(ID << 2 | Star, this);
}
}

View File

@@ -0,0 +1,30 @@
using Newtonsoft.Json;
namespace EggLink.DanhengServer.Data.Excel;
[ResourceEntity("GridFightShopPrice.json")]
public class GridFightShopPriceExcel : ExcelResource
{
public uint Rarity { get; set; }
public uint BuyGoldStar1 { get; set; }
public uint BuyGoldStar2 { get; set; }
public uint BuyGoldStar3 { get; set; }
public uint BuyGoldStar4 { get; set; }
public uint SellGoldStar1 { get; set; }
public uint SellGoldStar2 { get; set; }
public uint SellGoldStar3 { get; set; }
public uint SellGoldStar4 { get; set; }
[JsonIgnore] public List<uint> BuyGoldList => [BuyGoldStar1, BuyGoldStar2, BuyGoldStar3, BuyGoldStar4];
[JsonIgnore] public List<uint> SellGoldList => [SellGoldStar1, SellGoldStar2, SellGoldStar3, SellGoldStar4];
public override int GetId()
{
return (int)Rarity;
}
public override void Loaded()
{
GameData.GridFightShopPriceData.TryAdd(Rarity, this);
}
}

View File

@@ -105,10 +105,13 @@ public static class GameData
#region GridFight
public static Dictionary<uint, GridFightRoleBasicInfoExcel> GridFightRoleBasicInfoData { get; private set; } = [];
public static Dictionary<uint, GridFightRoleStarExcel> GridFightRoleStarData { get; private set; } = [];
public static Dictionary<uint, GridFightDivisionInfoExcel> GridFightDivisionInfoData { get; private set; } = [];
public static Dictionary<uint, GridFightEquipmentExcel> GridFightEquipmentData { get; private set; } = [];
public static Dictionary<uint, GridFightConsumablesExcel> GridFightConsumablesData { get; private set; } = [];
public static Dictionary<uint, GridFightCampExcel> GridFightCampData { get; private set; } = [];
public static Dictionary<uint, GridFightShopPriceExcel> GridFightShopPriceData { get; private set; } = [];
public static Dictionary<uint, GridFightPlayerLevelExcel> GridFightPlayerLevelData { get; private set; } = [];
public static Dictionary<uint, GridFightMonsterExcel> GridFightMonsterData { get; private set; } = [];
public static Dictionary<uint, GridFightAugmentExcel> GridFightAugmentData { get; private set; } = [];
public static Dictionary<uint, GridFightPortalBuffExcel> GridFightPortalBuffData { get; private set; } = [];

View File

@@ -4,6 +4,7 @@ using EggLink.DanhengServer.Database;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.Enums.Avatar;
using EggLink.DanhengServer.GameServer.Game.Battle.Custom;
using EggLink.DanhengServer.GameServer.Game.Lineup;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.Scene;
@@ -67,6 +68,7 @@ public class BattleInstance(PlayerInstance player, LineupInfo lineup, List<Stage
public Dictionary<int, BattleTargetList> BattleTargets { get; set; } = [];
public BattleCollegeConfigExcel? CollegeConfigExcel { get; set; }
public PVEBattleResultCsReq? BattleResult { get; set; }
public BattleGridFightOptions? GridFightOptions { get; set; }
public bool IsTournRogue { get; set; }
public ItemList GetDropItemList()
@@ -214,62 +216,69 @@ public class BattleInstance(PlayerInstance player, LineupInfo lineup, List<Stage
LogicRandomSeed = (uint)Random.Shared.Next()
};
if (MagicInfo != null) proto.BattleRogueMagicInfo = MagicInfo;
foreach (var protoWave in Stages.Select(wave => wave.ToProto()))
if (GridFightOptions != null)
{
if (CustomLevel > 0)
foreach (var item in protoWave)
item.MonsterParam.Level = (uint)CustomLevel;
proto.MonsterWaveList.AddRange(protoWave);
GridFightOptions.HandleProto(proto, this); // grid fight will handle the proto itself
}
if (Player.BattleManager!.NextBattleMonsterIds.Count > 0)
else
{
var ids = Player.BattleManager!.NextBattleMonsterIds;
// split every 5
for (var i = 0; i < (ids.Count - 1) / 5 + 1; i++)
if (MagicInfo != null) proto.BattleRogueMagicInfo = MagicInfo;
foreach (var protoWave in Stages.Select(wave => wave.ToProto()))
{
var count = Math.Min(5, ids.Count - i * 5);
var waveIds = ids.GetRange(i * 5, count);
if (CustomLevel > 0)
foreach (var item in protoWave)
item.MonsterParam.Level = (uint)CustomLevel;
proto.MonsterWaveList.Add(new SceneMonsterWave
{
BattleStageId = (uint)(Stages.FirstOrDefault()?.StageID ?? 0),
BattleWaveId = (uint)(proto.MonsterWaveList.Count + 1),
MonsterParam = new SceneMonsterWaveParam(),
MonsterList =
{
waveIds.Select(x => new SceneMonster
{
MonsterId = (uint)x
})
}
});
proto.MonsterWaveList.AddRange(protoWave);
}
if (Player.BattleManager!.NextBattleMonsterIds.Count > 0)
{
var ids = Player.BattleManager!.NextBattleMonsterIds;
// split every 5
for (var i = 0; i < (ids.Count - 1) / 5 + 1; i++)
{
var count = Math.Min(5, ids.Count - i * 5);
var waveIds = ids.GetRange(i * 5, count);
proto.MonsterWaveList.Add(new SceneMonsterWave
{
BattleStageId = (uint)(Stages.FirstOrDefault()?.StageID ?? 0),
BattleWaveId = (uint)(proto.MonsterWaveList.Count + 1),
MonsterParam = new SceneMonsterWaveParam(),
MonsterList =
{
waveIds.Select(x => new SceneMonster
{
MonsterId = (uint)x
})
}
});
}
}
var avatars = GetBattleAvatars();
foreach (var avatar in avatars)
proto.BattleAvatarList.Add(avatar.AvatarInfo.ToBattleProto(
new PlayerDataCollection(Player.Data, Player.InventoryManager!.Data, Lineup), avatar.AvatarType));
System.Threading.Tasks.Task.Run(async () =>
{
foreach (var monster in EntityMonsters) await monster.ApplyBuff(this);
foreach (var avatar in AvatarInfo)
if (avatars.Select(x => x.AvatarInfo).FirstOrDefault(x =>
x.BaseAvatarId == avatar.AvatarInfo.BaseAvatarId) !=
null) // if avatar is in lineup
await avatar.ApplyBuff(this);
}).Wait();
foreach (var buff in Buffs.Clone())
if (Enum.IsDefined(typeof(DamageTypeEnum), buff.BuffID))
Buffs.RemoveAll(x => x.BuffID == buff.BuffID && x.DynamicValues.Count == 0);
}
var avatars = GetBattleAvatars();
foreach (var avatar in avatars)
proto.BattleAvatarList.Add(avatar.AvatarInfo.ToBattleProto(
new PlayerDataCollection(Player.Data, Player.InventoryManager!.Data, Lineup), avatar.AvatarType));
System.Threading.Tasks.Task.Run(async () =>
{
foreach (var monster in EntityMonsters) await monster.ApplyBuff(this);
foreach (var avatar in AvatarInfo)
if (avatars.Select(x => x.AvatarInfo).FirstOrDefault(x =>
x.BaseAvatarId == avatar.AvatarInfo.BaseAvatarId) !=
null) // if avatar is in lineup
await avatar.ApplyBuff(this);
}).Wait();
foreach (var buff in Buffs.Clone())
if (Enum.IsDefined(typeof(DamageTypeEnum), buff.BuffID))
Buffs.RemoveAll(x => x.BuffID == buff.BuffID && x.DynamicValues.Count == 0);
foreach (var eventInstance in BattleEvents.Values) proto.BattleEvent.Add(eventInstance.ToProto());
for (var i = 1; i <= 5; i++)

View File

@@ -2,6 +2,9 @@
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.Database.Inventory;
using EggLink.DanhengServer.GameServer.Game.Battle.Custom;
using EggLink.DanhengServer.GameServer.Game.GridFight;
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Game.RogueMagic;
using EggLink.DanhengServer.GameServer.Game.Scene;
@@ -292,6 +295,34 @@ public class BattleManager(PlayerInstance player) : BasePlayerManager(player)
return (Retcode.RetSucc, battleInstance);
}
public BattleInstance? StartGridFightBattle(GridFightInstance inst)
{
if (Player.BattleInstance != null) return null;
var levelComponent = inst.GetComponent<GridFightLevelComponent>();
var curSection = levelComponent.CurrentSection;
var stageConfigId = curSection.Excel.StageID;
GameData.StageConfigData.TryGetValue((int)stageConfigId, out var stageConfig);
if (stageConfig == null) return null;
BattleInstance battleInstance = new(Player, Player.LineupManager!.GetCurLineup()!, [stageConfig])
{
WorldLevel = Player.Data.WorldLevel,
AvatarInfo = [],
GridFightOptions = new BattleGridFightOptions(curSection, inst, Player)
};
Player.BattleInstance = battleInstance;
Player.QuestManager!.OnBattleStart(battleInstance);
InvokeOnPlayerEnterBattle(Player, battleInstance);
return battleInstance;
}
public async ValueTask EndBattle(PVEBattleResultCsReq req)
{
InvokeOnPlayerQuitBattle(Player, req);
@@ -383,6 +414,12 @@ public class BattleManager(PlayerInstance player) : BasePlayerManager(player)
if (Player.ActivityManager!.TrialActivityInstance != null && req.EndStatus == BattleEndStatus.BattleEndWin)
await Player.ActivityManager.TrialActivityInstance.EndActivity(TrialActivityStatus.Finish);
if (Player.GridFightManager?.GridFightInstance != null &&
battle.GridFightOptions != null)
{
await Player.GridFightManager!.GridFightInstance!.EndBattle(battle);
}
await Player.SendPacket(new PacketPVEBattleResultScRsp(req, Player, battle));
}
}

View File

@@ -0,0 +1,77 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.GameServer.Game.GridFight;
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.Battle.Custom;
public class BattleGridFightOptions(GridFightGameSectionInfo curSection, GridFightInstance inst, PlayerInstance player)
{
public GridFightGameEncounterInfo Encounter { get; set; } = curSection.Encounters.RandomElement();
public GridFightInstance Inst { get; set; } = inst;
public GridFightAvatarComponent AvatarComponent { get; set; } = inst.GetComponent<GridFightAvatarComponent>();
public GridFightBasicComponent BasicComponent { get; set; } = inst.GetComponent<GridFightBasicComponent>();
public GridFightGameSectionInfo CurSection { get; set; } = curSection;
public PlayerInstance Player { get; set; } = player;
public void HandleProto(SceneBattleInfo proto, BattleInstance battle)
{
var avatars = AvatarComponent.GetForegroundAvatarInfos();
var formatted = avatars.Select(x =>
x.ToBattleProto(
new PlayerDataCollection(Player.Data, Player.InventoryManager!.Data,
Player.LineupManager!.GetCurLineup()!), AvatarType.AvatarGridFightType)).ToList();
proto.BattleAvatarList.Add(formatted);
foreach (var wave in Encounter.MonsterWaves)
{
proto.MonsterWaveList.Add(new SceneMonsterWave
{
BattleStageId = proto.StageId,
BattleWaveId = wave.Wave,
MonsterParam = new SceneMonsterWaveParam
{
Level = 89
},
MonsterList =
{
wave.Monsters.Select(x => new SceneMonster
{
MonsterId = x.MonsterID
})
}
});
}
foreach (var role in AvatarComponent.Data.Roles)
{
if (!GameData.GridFightRoleStarData.TryGetValue(role.RoleId << 2 | role.Tier, out var roleConf)) continue;
battle.BattleEvents.TryAdd((int)roleConf.BEID, new BattleEventInstance((int)roleConf.BEID, 5000));
}
proto.BattleGridFightInfo = new BattleGridFightInfo
{
GridGameAvatarList =
{
AvatarComponent.Data.Roles.Where(x => x.Pos <= 4).Select(x => x.ToBattleInfo())
},
BattleWaveId = 1,
GridFightCurLevel = BasicComponent.Data.CurLevel,
GridFightLineupHp = BasicComponent.Data.CurHp,
GridFightAvatarList = { formatted },
GridFightStageInfo = new BattleGridFightStageInfo
{
ChapterId = CurSection.ChapterId,
RouteId = CurSection.Excel.ID,
SectionId = CurSection.SectionId
},
IsOverlock = Inst.IsOverLock,
Season = Inst.Season
};
}
}

View File

@@ -1,22 +1,124 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.GridFight;
using EggLink.DanhengServer.Database.Avatar;
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component;
public class GridFightAvatarComponent(GridFightInstance inst) : BaseGridFightComponent(inst)
{
public List<GridFightAvatarInfo> Avatars { get; set; } = [];
private uint _curUniqueId;
public GridFightAvatarInfoPb Data { get; set; } = new();
public async ValueTask AddAvatar(uint roleId, uint tier = 1)
public async ValueTask<List<BaseGridFightSyncData>> AddAvatar(uint roleId, uint tier = 1, bool sendPacket = true)
{
var info = new GridFightAvatarInfo(roleId, ++_curUniqueId, tier);
Avatars.Add(info);
var pos = 1u;
// get first empty pos
var usedPos = Data.Roles.Select(x => x.Pos).ToHashSet();
for (var i = 1u; i <= 20u; i++)
{
if (usedPos.Contains(i)) continue;
pos = i;
break;
}
// TODO sync
await ValueTask.CompletedTask;
var info = new GridFightRoleInfoPb
{
RoleId = roleId,
UniqueId = ++Data.CurUniqueId,
Tier = tier,
Pos = pos
};
Data.Roles.Add(info);
List<BaseGridFightSyncData> syncs = [new GridFightRoleAddSyncData(GridFightSrc.KGridFightSrcBuyGoods, info)];
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
return syncs;
}
public async ValueTask<List<BaseGridFightSyncData>> SellAvatar(uint uniqueId, bool sendPacket = true)
{
var role = Data.Roles.FirstOrDefault(x => x.UniqueId == uniqueId);
if (role == null)
{
return [];
}
Data.Roles.Remove(role);
var tier = role.Tier;
var rarity = GameData.GridFightRoleBasicInfoData[role.RoleId].Rarity;
var sellPrice = GameData.GridFightShopPriceData.GetValueOrDefault(rarity)
?.SellGoldList[(int)(tier - 1)] ?? 1;
var basicComp = Inst.GetComponent<GridFightBasicComponent>();
await basicComp.UpdateGoldNum((int)sellPrice, false, GridFightSrc.KGridFightSrcRecycleRole);
List<BaseGridFightSyncData> syncs =
[
new GridFightRoleRemoveSyncData(GridFightSrc.KGridFightSrcRecycleRole, role),
new GridFightGoldSyncData(GridFightSrc.KGridFightSrcRecycleRole, basicComp.Data)
];
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
return syncs;
}
public List<BaseAvatarInfo> GetForegroundAvatarInfos()
{
var foreground = Data.Roles.Where(x => x.Pos <= 4).ToList();
List<BaseAvatarInfo> res = [];
foreach (var role in foreground)
{
var excel = GameData.GridFightRoleBasicInfoData[role.RoleId];
// get formal or special
var formal = Inst.Player.AvatarManager!.GetFormalAvatar((int)excel.AvatarID);
if (formal != null)
{
res.Add(formal);
}
else
{
var special = Inst.Player.AvatarManager.GetTrialAvatar((int)excel.SpecialAvatarID);
if (special != null)
{
res.Add(special);
}
}
}
return res;
}
public async ValueTask UpdatePos(List<GridFightPosInfo> posList)
{
List<BaseGridFightSyncData> syncs = [];
foreach (var pos in posList)
{
var role = Data.Roles.FirstOrDefault(x => x.UniqueId == pos.UniqueId);
if (role != null)
{
role.Pos = pos.Pos;
syncs.Add(new GridFightRoleUpdateSyncData(GridFightSrc.KGridFightSrcCopyRole, role));
}
}
if (syncs.Count > 0)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
}
public override GridFightGameInfo ToProto()
@@ -25,27 +127,34 @@ public class GridFightAvatarComponent(GridFightInstance inst) : BaseGridFightCom
{
GridAvatarGameInfo = new GridFightGameAvatarInfo
{
GridGameAvatarList = { Avatars.Select(x => x.ToProto()) }
GridGameAvatarList = { Data.Roles.Select(x => x.ToProto()) }
}
};
}
}
public class GridFightAvatarInfo(uint roleId, uint uniqueId, uint tier = 1)
public static class GridFightRoleInfoPbExtensions
{
public GridFightRoleBasicInfoExcel RoleInfo { get; set; } = GameData.GridFightRoleBasicInfoData[roleId];
public GridFightRolePositionEnum Pos { get; set; } = GridFightRolePositionEnum.Foreground;
public uint Tier { get; set; } = tier;
public uint UniqueId { get; set; } = uniqueId;
public GridGameAvatarInfo ToProto()
public static GridGameAvatarInfo ToProto(this GridFightRoleInfoPb info)
{
return new GridGameAvatarInfo
{
Id = RoleInfo.ID,
Pos = (uint)Pos,
Tier = Tier,
UniqueId = UniqueId
Id = info.RoleId,
UniqueId = info.UniqueId,
Tier = info.Tier,
Pos = info.Pos
};
}
public static BattleGridFightRoleInfo ToBattleInfo(this GridFightRoleInfoPb info)
{
return new BattleGridFightRoleInfo
{
RoleBasicId = info.RoleId,
UniqueId = info.UniqueId,
Tier = info.Tier,
Pos = info.Pos,
AvatarId = GameData.GridFightRoleBasicInfoData[info.RoleId].AvatarID
};
}
}

View File

@@ -1,29 +1,117 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component;
public class GridFightBasicComponent(GridFightInstance inst) : BaseGridFightComponent(inst)
{
public GridFightBasicInfoPb Data { get; set; } = new()
{
CurHp = 100,
CurLevel = 1,
CurOnGroundAvatarCount = 1,
BuyLevelCost = 1,
CurGold = 5
};
public async ValueTask<Retcode> UpdateGoldNum(int changeNum, bool sendPacket = true, GridFightSrc src = GridFightSrc.KGridFightSrcManualRefreshGoods)
{
if (changeNum < 0 && -changeNum > Data.CurGold)
{
return Retcode.RetGridFightCoinNotEnough;
}
Data.CurGold = (uint)(Data.CurGold + changeNum);
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(new GridFightGoldSyncData(src, Data)));
}
return Retcode.RetSucc;
}
public async ValueTask<Retcode> BuyLevelExp(bool sendPacket = true)
{
if (!GameData.GridFightPlayerLevelData.TryGetValue(Data.CurLevel, out var levelConf) || levelConf.LevelUpExp == 0)
return Retcode.RetGridFightGameplayLevelMax;
// COST
if (await UpdateGoldNum((int)-Data.BuyLevelCost, false) != Retcode.RetSucc)
return Retcode.RetGridFightCoinNotEnough;
Data.LevelExp += 1;
// LEVEL UP
if (Data.LevelExp >= levelConf.LevelUpExp)
{
await UpgradeLevel(1, false);
}
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(
new GridFightGoldSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightPlayerLevelSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightMaxAvatarNumSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightBuyExpCostSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data)));
}
return Retcode.RetSucc;
}
public async ValueTask<Retcode> UpgradeLevel(uint level, bool sendPacket = true)
{
if (!GameData.GridFightPlayerLevelData.TryGetValue(level + Data.CurLevel, out var levelConf))
return Retcode.RetGridFightGameplayLevelMax;
Data.CurLevel += level;
Data.LevelExp = 0;
Data.BuyLevelCost = (uint)Math.Ceiling(Data.CurLevel / 2f);
Data.CurOnGroundAvatarCount = levelConf.AvatarMaxNumber;
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(
new GridFightGoldSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightPlayerLevelSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightMaxAvatarNumSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data),
new GridFightBuyExpCostSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data)));
}
return Retcode.RetSucc;
}
public uint GetFieldCount()
{
return 4 + 6;
}
public override GridFightGameInfo ToProto()
{
return new GridFightGameInfo
{
GridBasicInfo = new GridFightGameBasicInfo
{
GridFightCurLevel = 1,
GridFightCurLevelExp = 1,
GridFightLevelCost = 1,
GridFightMaxAvatarCount = 2,
GridFightOffFieldMaxCount = 9,
GridFightMaxFieldCount = 13,
GridFightLineupHp = 100,
GridFightCurGold = 200,
GridFightCurLevel = Data.CurLevel,
GridFightCurLevelExp = Data.LevelExp,
GridFightLevelCost = Data.BuyLevelCost,
GridFightMaxAvatarCount = Data.CurOnGroundAvatarCount,
GridFightOffFieldMaxCount = 6,
GridFightMaxFieldCount = 8,
GridFightLineupHp = Data.CurHp,
GridFightCurGold = Data.CurGold,
GridFightMaxGold = 2000,
OCMGMEHECBB = new OPIBBPCHFII
{
IJDIAOMINLB = new BHJALAPDBLH()
},
CALCJMHAKPF = new OLEIDBLBILD()
CALCJMHAKPF = new OLEIDBLBILD
{
}
}
};
}

View File

@@ -1,6 +1,8 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.Data.Excel;
using EggLink.DanhengServer.Enums.GridFight;
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Util;
@@ -36,6 +38,34 @@ public class GridFightLevelComponent : BaseGridFightComponent
}
}
public async ValueTask<List<BaseGridFightSyncData>> EnterNextSection(bool sendPacket = true)
{
// if last section of chapter
if (_curSectionId >= Sections[_curChapterId].Count)
{
if (_curChapterId >= Sections.Count)
{
// end of game
return [];
}
_curChapterId++;
_curSectionId = 1;
}
else
{
_curSectionId++;
}
List<BaseGridFightSyncData> syncs = [new GridFightLevelSyncData(GridFightSrc.KGridFightSrcBattleEnd, this)];
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
return syncs;
}
public List<GridFightMonsterInfo> GetBossMonsters()
{
// get every chapter last section camp
@@ -91,9 +121,8 @@ public class GridFightLevelComponent : BaseGridFightComponent
Sections.Values.SelectMany(x => x).Select(s => s.ToProto())
}
},
CGAIJCCLKBH = new()
LevelSttInfo = new GridFightLevelSttInfo
{
DILHFEHBGDN = new ACHJGEEKCAH()
}
}
};

View File

@@ -0,0 +1,244 @@
using EggLink.DanhengServer.Data;
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
using EggLink.DanhengServer.Util;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Component;
public class GridFightShopComponent(GridFightInstance inst) : BaseGridFightComponent(inst)
{
public GridFightShopInfoPb Data { get; set; } = new()
{
RefreshCost = 3,
FreeRefreshCount = 1
};
public static uint GetGoodsPrice(uint rarity, uint tier)
{
return GameData.GridFightShopPriceData.GetValueOrDefault(rarity)
?.BuyGoldList[(int)(tier - 1)] ?? 1;
}
public async ValueTask LockGoods(bool locked, bool sendPacket = true)
{
var curLevel = Inst.GetComponent<GridFightBasicComponent>().Data.CurLevel;
Data.ShopLocked = locked;
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(new GridFightShopSyncData(GridFightSrc.KGridFightSrcNone, Data, curLevel)));
}
}
public async ValueTask<Retcode> BuyGoods(List<uint> indexes, bool sendPacket = true)
{
var curLevel = Inst.GetComponent<GridFightBasicComponent>().Data.CurLevel;
var targetGoods = indexes
.Where(x => x < Data.ShopItems.Count)
.Select(x => Data.ShopItems[(int)x])
.ToList();
var totalCost = (uint)targetGoods.Select(x => GetGoodsPrice(x.Rarity, x.RoleItem.Tier)).Sum(x => x);
// COST
var code = await Inst.GetComponent<GridFightBasicComponent>().UpdateGoldNum((int)-totalCost, false);
if (code != Retcode.RetSucc)
{
return code;
}
// GIVE ITEMS
List<BaseGridFightSyncData> syncs = [];
var avatarComp = Inst.GetComponent<GridFightAvatarComponent>();
foreach (var item in targetGoods)
{
if (item.ItemTypeCase == GridFightShopItemPb.ItemTypeOneofCase.RoleItem)
{
syncs.AddRange(await avatarComp.AddAvatar(item.RoleItem.RoleId, item.RoleItem.Tier, false));
}
else
{
// TODO other item types
}
}
// REMOVE ITEMS FROM SHOP
foreach (var index in indexes)
{
Data.ShopItems.RemoveAt((int)index);
}
if (sendPacket)
{
syncs.Insert(0, new GridFightGoldSyncData(GridFightSrc.KGridFightSrcBuyGoods, Inst.GetComponent<GridFightBasicComponent>().Data));
syncs.Add(new GridFightShopSyncData(GridFightSrc.KGridFightSrcBuyGoods, Data, curLevel));
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
return Retcode.RetSucc;
}
public async ValueTask<Retcode> RefreshShop(bool isEnterSection, bool sendPacket = true)
{
if (!isEnterSection)
{
if (Data.FreeRefreshCount > 0)
Data.FreeRefreshCount--;
else
{
// cost
var code = await Inst.GetComponent<GridFightBasicComponent>().UpdateGoldNum((int)-Data.RefreshCost);
if (code != Retcode.RetSucc)
{
return code;
}
Data.RefreshCost += 2;
}
}
else
{
Data.RefreshCost = 3;
Data.FreeRefreshCount++;
if (Data.ShopLocked)
{
await LockGoods(false, false);
return Retcode.RetGridFightShopLocked;
}
}
// refresh
var curLevel = Inst.GetComponent<GridFightBasicComponent>().Data.CurLevel;
var rules = GameData.GridFightPlayerLevelData.GetValueOrDefault(curLevel)?.RarityWeights ??
[100, 0, 0, 0, 0];
Data.ShopItems.Clear();
List<uint> usedIds = [];
// generate items
for (var i = 0; i < 5; i++)
{
// select rarity
var rand = (uint)Random.Shared.Next(1, 101);
var targetRarity = 0;
for (var j = 0; j < 5; j++)
{
if (rand <= rules[j])
{
targetRarity = j + 1;
break;
}
rand -= rules[j];
}
// get item pool
var pool = GameData.GridFightRoleBasicInfoData.Values
.Where(x => !usedIds.Contains(x.ID) && x.IsInPool && x.Rarity == targetRarity).ToList();
var target = pool.RandomElement();
usedIds.Add(target.ID);
var tier = 1u;
Data.ShopItems.Add(new GridFightShopItemPb
{
Rarity = target.Rarity,
RoleItem = new GridFightShopRoleItemPb
{
RoleId = target.ID,
Tier = tier
}
});
}
if (sendPacket)
{
await Inst.Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(new GridFightShopSyncData(GridFightSrc.KGridFightSrcManualRefreshGoods, Data, curLevel)));
}
return Retcode.RetSucc;
}
public override GridFightGameInfo ToProto()
{
var rarity = 1u;
var rules = GameData.GridFightPlayerLevelData
.GetValueOrDefault(Inst.GetComponent<GridFightBasicComponent>().Data.CurLevel)?.RarityWeights ??
[100, 0, 0, 0, 0];
return new GridFightGameInfo
{
GridShopInfo = new GridFightGameShopInfo
{
ShopIsLocked = Data.ShopLocked,
GridFightShopRandomRule = new GridFightShopRandomRuleInfo
{
GridFightShopRuleList = { rules.Select(x => new GridFightShopRandomRule
{
ShopItemWeight = x,
ShopItemRarity = rarity++
}) }
},
ShopGoodsList = { Data.ShopItems.Select(x => x.ToProto()) },
ShopFreeRefreshCount = Data.FreeRefreshCount,
ShopRefreshCost = Data.RefreshCost
}
};
}
}
public static class GridFightShopInfoPbExtensions
{
public static GridFightShopGoodsInfo ToProto(this GridFightShopItemPb info)
{
var proto = new GridFightShopGoodsInfo();
if (info.ItemTypeCase == GridFightShopItemPb.ItemTypeOneofCase.RoleItem)
{
proto.ShopGoodsPrice = GameData.GridFightShopPriceData.GetValueOrDefault(info.Rarity)
?.BuyGoldList[(int)(info.RoleItem.Tier - 1)] ?? 1;
proto.RoleGoodsInfo = new GridFightRoleGoodsInfo
{
RoleBasicId = info.RoleItem.RoleId,
Tier = info.RoleItem.Tier
};
}
else
{
// TODO
}
return proto;
}
public static GridFightShopSyncInfo ToSyncInfo(this GridFightShopInfoPb info, uint level)
{
var rarity = 1u;
var rules = GameData.GridFightPlayerLevelData
.GetValueOrDefault(level)?.RarityWeights ??
[100, 0, 0, 0, 0];
return new GridFightShopSyncInfo
{
ShopIsLocked = info.ShopLocked,
GridFightShopRandomRule = new GridFightShopRandomRuleInfo
{
GridFightShopRuleList =
{
rules.Select(x => new GridFightShopRandomRule
{
ShopItemWeight = x,
ShopItemRarity = rarity++
})
}
},
ShopGoodsList = { info.ShopItems.Select(x => x.ToProto()) },
ShopFreeRefreshCount = info.FreeRefreshCount,
ShopRefreshCost = info.RefreshCost
};
}
}

View File

@@ -1,23 +1,52 @@
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.GameServer.Game.Player;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.GridFight;
public class GridFightInstance(uint season, uint divisionId, bool isOverLock, uint uniqueId)
public class GridFightInstance(PlayerInstance player, uint season, uint divisionId, bool isOverLock, uint uniqueId)
{
public uint Season { get; } = season;
public uint DivisionId { get; } = divisionId;
public bool IsOverLock { get; } = isOverLock;
public uint UniqueId { get; } = uniqueId;
public List<BaseGridFightComponent> Components { get; } = [];
public PlayerInstance Player { get; } = player;
public BattleInstance? StartBattle()
{
return Player.BattleManager!.StartGridFightBattle(this);
}
public async ValueTask EndBattle(BattleInstance battle)
{
if (battle.BattleEndStatus != BattleEndStatus.BattleEndWin) return;
List<BaseGridFightSyncData> syncs = [];
await Player.SendPacket(new PacketGridFightEndBattleStageNotify(this));
var basicComp = GetComponent<GridFightBasicComponent>();
await basicComp.UpdateGoldNum(5, false, GridFightSrc.KGridFightSrcNone);
syncs.Add(new GridFightGoldSyncData(GridFightSrc.KGridFightSrcBattleEnd, basicComp.Data));
syncs.AddRange(await GetComponent<GridFightLevelComponent>().EnterNextSection(false));
await Player.SendPacket(new PacketGridFightSyncUpdateResultScNotify(syncs));
}
public void InitializeComponents()
{
Components.Add(new GridFightBasicComponent(this));
Components.Add(new GridFightShopComponent(this));
Components.Add(new GridFightLevelComponent(this));
Components.Add(new GridFightAvatarComponent(this));
_ = GetComponent<GridFightAvatarComponent>().AddAvatar(1414, 3); // TODO test
_ = GetComponent<GridFightAvatarComponent>().AddAvatar(1414, 3, false); // TODO test
_ = GetComponent<GridFightShopComponent>().RefreshShop(true, false);
}
public T GetComponent<T>() where T : BaseGridFightComponent

View File

@@ -21,7 +21,7 @@ public class GridFightManager(PlayerInstance player) : BasePlayerManager(player)
if (GridFightInstance != null)
return (Retcode.RetGridFightAlreadyInGameplay, GridFightInstance);
GridFightInstance = new GridFightInstance(season, divisionId, isOverLock, ++CurUniqueId);
GridFightInstance = new GridFightInstance(Player, season, divisionId, isOverLock, ++CurUniqueId);
GridFightInstance.InitializeComponents();
await ValueTask.CompletedTask;

View File

@@ -0,0 +1,9 @@
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public abstract class BaseGridFightSyncData(GridFightSrc src)
{
public GridFightSrc Src { get; set; } = src;
public abstract GridFightSyncData ToProto();
}

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightBuyExpCostSyncData(GridFightSrc src, GridFightBasicInfoPb info) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
GridFightLevelCost = info.BuyLevelCost
};
}
}

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightGoldSyncData(GridFightSrc src, GridFightBasicInfoPb basic) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
ItemValue = basic.CurGold
};
}
}

View File

@@ -0,0 +1,23 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightLevelSyncData(GridFightSrc src, GridFightLevelComponent level) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
LevelSyncInfo = new GridFightLevelSyncInfo
{
SectionId = level.CurrentSection.SectionId,
ChapterId = level.CurrentSection.ChapterId,
GridFightLayerInfo = new GridFightLayerInfo
{
RouteInfo = level.CurrentSection.ToRouteInfo()
}
}
};
}
}

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightMaxAvatarNumSyncData(GridFightSrc src, GridFightBasicInfoPb info) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
GridFightMaxAvatarCount = info.CurOnGroundAvatarCount
};
}
}

View File

@@ -0,0 +1,19 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightPlayerLevelSyncData(GridFightSrc src, GridFightBasicInfoPb info) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
PlayerLevel = new GridFightPlayerLevelSyncInfo
{
Exp = info.LevelExp,
Level = info.CurLevel
}
};
}
}

View File

@@ -0,0 +1,16 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightRoleAddSyncData(GridFightSrc src, GridFightRoleInfoPb role) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
AddRoleInfo = role.ToProto()
};
}
}

View File

@@ -0,0 +1,15 @@
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightRoleRemoveSyncData(GridFightSrc src, GridFightRoleInfoPb role) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
RemoveRoleUniqueId = role.UniqueId
};
}
}

View File

@@ -0,0 +1,16 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightRoleUpdateSyncData(GridFightSrc src, GridFightRoleInfoPb role) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
UpdateRoleInfo = role.ToProto()
};
}
}

View File

@@ -0,0 +1,16 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Proto;
using EggLink.DanhengServer.Proto.ServerSide;
namespace EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
public class GridFightShopSyncData(GridFightSrc src, GridFightShopInfoPb data, uint level) : BaseGridFightSyncData(src)
{
public override GridFightSyncData ToProto()
{
return new GridFightSyncData
{
ShopSyncInfo = data.ToSyncInfo(level)
};
}
}

View File

@@ -0,0 +1,23 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Kcp;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightBuyExpCsReq)]
public class HandlerGridFightBuyExpCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(CmdIds.GridFightBuyExpScRsp);
return;
}
var basicComp = gridFight.GetComponent<GridFightBasicComponent>();
await basicComp.BuyLevelExp();
await connection.SendPacket(CmdIds.GridFightBuyExpScRsp);
}
}

View File

@@ -0,0 +1,27 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightBuyGoodsCsReq)]
public class HandlerGridFightBuyGoodsCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GridFightBuyGoodsCsReq.Parser.ParseFrom(data);
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(new PacketGridFightBuyGoodsScRsp(Retcode.RetGridFightNotInGameplay));
return;
}
var shopComp = gridFight.GetComponent<GridFightShopComponent>();
var code = await shopComp.BuyGoods(req.BuyGoodsIndexList.ToList());
await connection.SendPacket(new PacketGridFightBuyGoodsScRsp(code));
}
}

View File

@@ -0,0 +1,24 @@
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightEnterBattleStageCsReq)]
public class HandlerGridFightEnterBattleStageCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(
new PacketGridFightEnterBattleStageScRsp(Retcode.RetGridFightNotInGameplay));
return;
}
var battle = gridFight.StartBattle();
await connection.SendPacket(
new PacketGridFightEnterBattleStageScRsp(Retcode.RetSucc, battle));
}
}

View File

@@ -0,0 +1,26 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightLockShopCsReq)]
public class HandlerGridFightLockShopCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GridFightLockShopCsReq.Parser.ParseFrom(data);
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(CmdIds.GridFightRefreshShopScRsp);
return;
}
var shopComp = gridFight.GetComponent<GridFightShopComponent>();
await shopComp.LockGoods(req.IsProtected);
await connection.SendPacket(CmdIds.GridFightRefreshShopScRsp);
}
}

View File

@@ -0,0 +1,26 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightRecycleRoleCsReq)]
public class HandlerGridFightRecycleRoleCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GridFightRecycleRoleCsReq.Parser.ParseFrom(data);
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(CmdIds.GridFightRecycleRoleScRsp);
return;
}
var roleComp = gridFight.GetComponent<GridFightAvatarComponent>();
await roleComp.SellAvatar(req.UniqueId);
await connection.SendPacket(CmdIds.GridFightRecycleRoleScRsp);
}
}

View File

@@ -0,0 +1,23 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Kcp;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightRefreshShopCsReq)]
public class HandlerGridFightRefreshShopCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var gridFight = connection.Player?.GridFightManager?.GridFightInstance;
if (gridFight == null)
{
await connection.SendPacket(CmdIds.GridFightRefreshShopScRsp);
return;
}
var shopComp = gridFight.GetComponent<GridFightShopComponent>();
await shopComp.RefreshShop(false);
await connection.SendPacket(CmdIds.GridFightRefreshShopScRsp);
}
}

View File

@@ -0,0 +1,28 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.GridFight;
[Opcode(CmdIds.GridFightUpdatePosCsReq)]
public class HandlerGridFightUpdatePosCsReq : Handler
{
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
{
var req = GridFightUpdatePosCsReq.Parser.ParseFrom(data);
if (connection.Player!.GridFightManager!.GridFightInstance == null)
{
await connection.SendPacket(
new PacketGridFightUpdatePosScRsp(Retcode.RetGridFightNotInGameplay, req.GridFightPosInfoList));
return;
}
var gridFight = connection.Player.GridFightManager.GridFightInstance;
await gridFight.GetComponent<GridFightAvatarComponent>().UpdatePos(req.GridFightPosInfoList.ToList());
await connection.SendPacket(
new PacketGridFightUpdatePosScRsp(Retcode.RetSucc, req.GridFightPosInfoList));
}
}

View File

@@ -0,0 +1,17 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightBuyGoodsScRsp : BasePacket
{
public PacketGridFightBuyGoodsScRsp(Retcode retcode) : base(CmdIds.GridFightBuyGoodsScRsp)
{
var rsp = new GridFightBuyGoodsScRsp
{
Retcode = (uint)retcode
};
SetData(rsp);
}
}

View File

@@ -0,0 +1,23 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightDataScNotify : BasePacket
{
public PacketGridFightDataScNotify(GridFightSrc src, List<BaseGridFightSyncData> data) : base(CmdIds.GridFightDataScNotify)
{
var proto = new GridFightDataScNotify
{
GridUpdateSrc = src,
UpdateDynamicList = { data.Select(x => x.ToProto()) }
};
SetData(proto);
}
public PacketGridFightDataScNotify(GridFightSrc src, params BaseGridFightSyncData[] data) : this(src, data.ToList())
{
}
}

View File

@@ -0,0 +1,30 @@
using EggLink.DanhengServer.GameServer.Game.GridFight;
using EggLink.DanhengServer.GameServer.Game.GridFight.Component;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightEndBattleStageNotify : BasePacket
{
public PacketGridFightEndBattleStageNotify(GridFightInstance inst) : base(CmdIds.GridFightEndBattleStageNotify)
{
var levelComp = inst.GetComponent<GridFightLevelComponent>();
var curSec = levelComp.CurrentSection;
var proto = new GridFightEndBattleStageNotify
{
SectionId = curSec.SectionId,
RouteId = curSec.Excel.ID,
ChapterId = curSec.ChapterId,
GridFightDamageSttInfo = new GridFightDamageSttInfo(),
EMLLKALLOPL = new HEHHADKPDOC
{
CGECGAAJLJM = new(),
NMMJMPNGIGD = new()
}
};
SetData(proto);
}
}

View File

@@ -0,0 +1,22 @@
using EggLink.DanhengServer.GameServer.Game.Battle;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightEnterBattleStageScRsp : BasePacket
{
public PacketGridFightEnterBattleStageScRsp(Retcode code = Retcode.RetSucc, BattleInstance? inst = null) : base(
CmdIds.GridFightEnterBattleStageScRsp)
{
var proto = new GridFightEnterBattleStageScRsp
{
Retcode = (uint)code
};
if (inst != null)
proto.BattleInfo = inst.ToProto();
SetData(proto);
}
}

View File

@@ -0,0 +1,39 @@
using EggLink.DanhengServer.GameServer.Game.GridFight.Sync;
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
using System.Linq;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightSyncUpdateResultScNotify : BasePacket
{
public PacketGridFightSyncUpdateResultScNotify(List<BaseGridFightSyncData> data) : base(CmdIds.GridFightSyncUpdateResultScNotify)
{
Dictionary<GridFightSrc, List<BaseGridFightSyncData>> srcDict = [];
foreach (var syncData in data)
{
srcDict.TryAdd(syncData.Src, []);
srcDict[syncData.Src].Add(syncData);
}
var proto = new GridFightSyncUpdateResultScNotify
{
SyncResultDataList =
{
srcDict.Select(x => new GridFightSyncResultData
{
GridUpdateSrc = x.Key,
UpdateDynamicList = { x.Value.Select(j => j.ToProto()) },
ONMDGNHMABO = { (uint)x.Value.Count }
})
}
};
SetData(proto);
}
public PacketGridFightSyncUpdateResultScNotify( params BaseGridFightSyncData[] data) : this(data.ToList())
{
}
}

View File

@@ -0,0 +1,19 @@
using EggLink.DanhengServer.Kcp;
using EggLink.DanhengServer.Proto;
using Google.Protobuf.Collections;
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.GridFight;
public class PacketGridFightUpdatePosScRsp : BasePacket
{
public PacketGridFightUpdatePosScRsp(Retcode code, RepeatedField<GridFightPosInfo> list) : base(CmdIds.GridFightUpdatePosScRsp)
{
var proto = new GridFightUpdatePosScRsp
{
Retcode = (uint)code,
GridFightPosInfoList = { list }
};
SetData(proto);
}
}

View File

@@ -55,10 +55,12 @@ namespace EggLink.DanhengServer.Proto.ServerSide {
"Q2hhbGxlbmdlTWVtb3J5RGF0YVBiSAASJgoFc3RvcnkYAiABKAsyFS5DaGFs",
"bGVuZ2VTdG9yeURhdGFQYkgAEiQKBGJvc3MYAyABKAsyFC5DaGFsbGVuZ2VC",
"b3NzRGF0YVBiSAASJAoEcGVhaxgEIAEoCzIULkNoYWxsZW5nZVBlYWtEYXRh",
"UGJIAEIQCg5jaGFsbGVuZ2VfdHlwZSpRChVDaGFsbGVuZ2VMaW5ldXBUeXBl",
"UGISCAoETm9uZRAAEg4KCkNoYWxsZW5nZTEQARIOCgpDaGFsbGVuZ2UyEAMS",
"DgoKQ2hhbGxlbmdlMxAEQimqAiZFZ2dMaW5rLkRhbmhlbmdTZXJ2ZXIuUHJv",
"dG8uU2VydmVyU2lkZWIGcHJvdG8z"));
"UGJIAEIQCg5jaGFsbGVuZ2VfdHlwZSqpAQoVQ2hhbGxlbmdlTGluZXVwVHlw",
"ZVBiEh4KGkNoYWxsZW5nZUxpbmV1cFR5cGVQYl9Ob25lEAASJAogQ2hhbGxl",
"bmdlTGluZXVwVHlwZVBiX0NoYWxsZW5nZTEQARIkCiBDaGFsbGVuZ2VMaW5l",
"dXBUeXBlUGJfQ2hhbGxlbmdlMhADEiQKIENoYWxsZW5nZUxpbmV1cFR5cGVQ",
"Yl9DaGFsbGVuZ2UzEARCKaoCJkVnZ0xpbmsuRGFuaGVuZ1NlcnZlci5Qcm90",
"by5TZXJ2ZXJTaWRlYgZwcm90bzM="));
descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
new pbr::FileDescriptor[] { },
new pbr::GeneratedClrTypeInfo(new[] {typeof(global::EggLink.DanhengServer.Proto.ServerSide.ChallengeLineupTypePb), }, null, new pbr::GeneratedClrTypeInfo[] {
@@ -75,10 +77,10 @@ namespace EggLink.DanhengServer.Proto.ServerSide {
}
#region Enums
public enum ChallengeLineupTypePb {
[pbr::OriginalName("None")] None = 0,
[pbr::OriginalName("Challenge1")] Challenge1 = 1,
[pbr::OriginalName("Challenge2")] Challenge2 = 3,
[pbr::OriginalName("Challenge3")] Challenge3 = 4,
[pbr::OriginalName("ChallengeLineupTypePb_None")] None = 0,
[pbr::OriginalName("ChallengeLineupTypePb_Challenge1")] Challenge1 = 1,
[pbr::OriginalName("ChallengeLineupTypePb_Challenge2")] Challenge2 = 3,
[pbr::OriginalName("ChallengeLineupTypePb_Challenge3")] Challenge3 = 4,
}
#endregion

File diff suppressed because it is too large Load Diff

View File

@@ -3,10 +3,10 @@ syntax = "proto3";
option csharp_namespace = "EggLink.DanhengServer.Proto.ServerSide";
enum ChallengeLineupTypePb {
None = 0;
Challenge1 = 1;
Challenge2 = 3;
Challenge3 = 4;
ChallengeLineupTypePb_None = 0;
ChallengeLineupTypePb_Challenge1 = 1;
ChallengeLineupTypePb_Challenge2 = 3;
ChallengeLineupTypePb_Challenge3 = 4;
}
message Vector3Pb {

View File

@@ -0,0 +1,59 @@
syntax = "proto3";
option csharp_namespace = "EggLink.DanhengServer.Proto.ServerSide";
message GridFightShopRoleItemPb {
uint32 RoleId = 1;
uint32 Tier = 2;
}
message GridFightShopItemPb {
oneof ItemType {
GridFightShopRoleItemPb RoleItem = 1;
}
uint32 Rarity = 2;
}
message GridFightShopInfoPb {
bool ShopLocked = 1;
uint32 FreeRefreshCount = 2;
uint32 RefreshCost = 3;
repeated GridFightShopItemPb ShopItems = 4;
}
message GridFightGameInfoPb {
uint32 UniqueId = 1;
uint32 DivisionId = 2;
bool IsOverLock = 3;
uint32 Season = 4;
repeated GridFightComponentPb Components = 5;
}
message GridFightBasicInfoPb {
uint32 CurGold = 1;
uint32 CurLevel = 2;
uint32 LevelExp = 3;
uint32 BuyLevelCost = 4;
uint32 CurHp = 5;
uint32 CurOnGroundAvatarCount = 6;
}
message GridFightRoleInfoPb {
uint32 RoleId = 1;
uint32 Tier = 2;
uint32 Pos = 3;
uint32 UniqueId = 4;
}
message GridFightAvatarInfoPb {
repeated GridFightRoleInfoPb Roles = 1;
uint32 CurUniqueId = 2;
}
message GridFightComponentPb {
oneof ComponentType {
GridFightShopInfoPb ShopInfo = 1;
GridFightBasicInfoPb BasicInfo = 2;
GridFightAvatarInfoPb AvatarInfo = 3;
}
}

View File

@@ -0,0 +1,24 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ServerSideProto", "ServerSideProto.csproj", "{A82F6F83-1D15-A42D-FE70-06D6029F1524}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{A82F6F83-1D15-A42D-FE70-06D6029F1524}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A82F6F83-1D15-A42D-FE70-06D6029F1524}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A82F6F83-1D15-A42D-FE70-06D6029F1524}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A82F6F83-1D15-A42D-FE70-06D6029F1524}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {239E7A80-377D-46D8-B82D-54CDFBA24AF1}
EndGlobalSection
EndGlobal