mirror of
https://github.com/EggLinks/DanhengServer-OpenSource.git
synced 2026-01-02 20:26:03 +08:00
sync: main repo
This commit is contained in:
@@ -23,7 +23,7 @@ public class CommandGiveall : ICommand
|
||||
|
||||
arg.CharacterArgs.TryGetValue("r", out var rankStr);
|
||||
arg.CharacterArgs.TryGetValue("l", out var levelStr);
|
||||
rankStr ??= "1";
|
||||
rankStr ??= "0";
|
||||
levelStr ??= "1";
|
||||
if (!int.TryParse(rankStr, out var rank) || !int.TryParse(levelStr, out var level))
|
||||
{
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System.Text;
|
||||
using EggLink.DanhengServer.Data.Config;
|
||||
using EggLink.DanhengServer.Enums.Mission;
|
||||
using EggLink.DanhengServer.GameServer.Game.Mission;
|
||||
using EggLink.DanhengServer.Internationalization;
|
||||
|
||||
namespace EggLink.DanhengServer.Command.Command.Cmd;
|
||||
@@ -57,8 +59,8 @@ public class CommandMission : ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
var mission = arg.Target!.Player!.MissionManager!;
|
||||
var runningMissions = mission.GetRunningSubMissionList();
|
||||
MissionManager mission = arg.Target!.Player!.MissionManager!;
|
||||
List<SubMissionInfo> runningMissions = mission.GetRunningSubMissionList();
|
||||
if (runningMissions.Count == 0)
|
||||
{
|
||||
await arg.SendMsg(I18NManager.Translate("Game.Command.Mission.NoRunningMissions"));
|
||||
@@ -68,6 +70,7 @@ public class CommandMission : ICommand
|
||||
await arg.SendMsg(I18NManager.Translate("Game.Command.Mission.RunningMissions"));
|
||||
Dictionary<int, List<int>> missionMap = [];
|
||||
|
||||
//build missionMap
|
||||
foreach (var m in runningMissions)
|
||||
{
|
||||
if (!missionMap.TryGetValue(m.MainMissionID, out var value))
|
||||
@@ -78,7 +81,24 @@ public class CommandMission : ICommand
|
||||
|
||||
value.Add(m.ID);
|
||||
}
|
||||
|
||||
if ((arg.BasicArgs.Count == 1 && arg.BasicArgs[0] == "-all") || mission.Data.TrackingMainMissionId == 0)
|
||||
{
|
||||
//Show all the missions
|
||||
await ShowMissionList(mission, missionMap, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Only show tracking missions
|
||||
Dictionary<int, List<int>> runningMissionMap = [];
|
||||
runningMissionMap[mission.Data.TrackingMainMissionId] = missionMap[mission.Data.TrackingMainMissionId];
|
||||
await ShowMissionList(mission, runningMissionMap, arg);
|
||||
}
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async ValueTask ShowMissionList(MissionManager mission, Dictionary<int, List<int>> missionMap, CommandArg arg)
|
||||
{
|
||||
var possibleStuckIds = new List<int>();
|
||||
var morePossibleStuckIds = new List<int>();
|
||||
|
||||
@@ -124,8 +144,6 @@ public class CommandMission : ICommand
|
||||
|
||||
await arg.SendMsg(sb.ToString());
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
}
|
||||
|
||||
[CommandMethod("0 reaccept")]
|
||||
|
||||
@@ -15,7 +15,7 @@ public class CommandRelic : ICommand
|
||||
return;
|
||||
}
|
||||
|
||||
if (arg.BasicArgs.Count < 3)
|
||||
if (arg.BasicArgs.Count < 2)
|
||||
{
|
||||
await arg.SendMsg(I18NManager.Translate("Game.Command.Notice.InvalidArguments"));
|
||||
return;
|
||||
|
||||
@@ -85,6 +85,12 @@ public class ServerOption
|
||||
public ServerProfile ServerProfile { get; set; } = new();
|
||||
public bool AutoCreateUser { get; set; } = true;
|
||||
public bool SavePersonalDebugFile { get; set; } = false;
|
||||
public int FarmingDropRate { get; set; } = 1;
|
||||
|
||||
public int ValidFarmingDropRate()
|
||||
{
|
||||
return Math.Max(Math.Min(FarmingDropRate, 999), 1);
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerAnnounce
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
@@ -183,6 +186,129 @@ public class MappingInfoExcel : ExcelResource
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ItemData> GenerateRelicDrops()
|
||||
{
|
||||
var relicsMap = new Dictionary<int, List<MappingInfoItem>>();
|
||||
foreach (var relic in DropRelicItemList)
|
||||
{
|
||||
GameData.ItemConfigData.TryGetValue(relic.ItemID, out var itemData);
|
||||
if (itemData == null) continue;
|
||||
switch (itemData.Rarity)
|
||||
{
|
||||
case ItemRarityEnum.NotNormal:
|
||||
AddRelicToMap(relic, 2, relicsMap);
|
||||
break;
|
||||
case ItemRarityEnum.Rare:
|
||||
AddRelicToMap(relic, 3, relicsMap);
|
||||
break;
|
||||
case ItemRarityEnum.VeryRare:
|
||||
AddRelicToMap(relic, 4, relicsMap);
|
||||
break;
|
||||
case ItemRarityEnum.SuperRare:
|
||||
AddRelicToMap(relic, 5, relicsMap);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
List<ItemData> drops = [];
|
||||
// Add higher rarity relics first
|
||||
for (var rarity = 5; rarity >= 2; rarity--)
|
||||
{
|
||||
var count = GetRelicCountByWorldLevel(rarity) *
|
||||
ConfigManager.Config.ServerOption.ValidFarmingDropRate();
|
||||
if (count <= 0) continue;
|
||||
if (!relicsMap.TryGetValue(rarity, out var value)) continue;
|
||||
if (value.IsNullOrEmpty()) continue;
|
||||
while (count > 0)
|
||||
{
|
||||
var relic = value.RandomElement();
|
||||
drops.Add(new ItemData
|
||||
{
|
||||
ItemId = relic.ItemID,
|
||||
Count = 1
|
||||
});
|
||||
count--;
|
||||
}
|
||||
}
|
||||
|
||||
return drops;
|
||||
}
|
||||
|
||||
private void AddRelicToMap(MappingInfoItem relic, int rarity, Dictionary<int, List<MappingInfoItem>> relicsMap)
|
||||
{
|
||||
if (relicsMap.TryGetValue(rarity, out var value))
|
||||
{
|
||||
value.Add(relic);
|
||||
}
|
||||
else
|
||||
{
|
||||
relicsMap.Add(rarity, [relic]);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetRelicCountByWorldLevel(int rarity)
|
||||
{
|
||||
return WorldLevel switch
|
||||
{
|
||||
1 => rarity switch
|
||||
{
|
||||
2 => 6,
|
||||
3 => 3,
|
||||
4 => 1,
|
||||
5 => 0,
|
||||
_ => 0
|
||||
},
|
||||
2 => rarity switch
|
||||
{
|
||||
2 => 2,
|
||||
3 => 4,
|
||||
4 => 2 + LuckyRelicDropped(),
|
||||
5 => 0,
|
||||
_ => 0
|
||||
},
|
||||
3 => rarity switch
|
||||
{
|
||||
2 => 0,
|
||||
3 => 4,
|
||||
4 => 2,
|
||||
5 => 1,
|
||||
_ => 0
|
||||
},
|
||||
4 => rarity switch
|
||||
{
|
||||
2 => 0,
|
||||
3 => 3,
|
||||
4 => 2 + LuckyRelicDropped(),
|
||||
5 => 1 + LuckyRelicDropped(),
|
||||
_ => 0
|
||||
},
|
||||
5 => rarity switch
|
||||
{
|
||||
2 => 0,
|
||||
3 => 1 + LuckyRelicDropped(),
|
||||
4 => 3,
|
||||
5 => 2,
|
||||
_ => 0
|
||||
},
|
||||
6 => rarity switch
|
||||
{
|
||||
2 => 0,
|
||||
3 => 0,
|
||||
4 => 5,
|
||||
5 => 2 + LuckyRelicDropped(),
|
||||
_ => 0
|
||||
},
|
||||
_ => 0
|
||||
};
|
||||
}
|
||||
|
||||
private int LuckyRelicDropped()
|
||||
{
|
||||
return Random.Shared.Next(100) < 25 ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public class MappingInfoItem
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace EggLink.DanhengServer.Data.Excel;
|
||||
@@ -54,7 +55,7 @@ public class MonsterDropExcel : ExcelResource
|
||||
result.Add(new ItemData
|
||||
{
|
||||
ItemId = item.ItemID,
|
||||
Count = count
|
||||
Count = count * ConfigManager.Config.ServerOption.ValidFarmingDropRate()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ public class RelicMainAffixConfigExcel : ExcelResource
|
||||
public int GroupID { get; set; }
|
||||
public int AffixID { get; set; }
|
||||
|
||||
public bool IsAvailable { get; set; }
|
||||
public string? Property { get; set; }
|
||||
|
||||
public override int GetId()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using EggLink.DanhengServer.Data;
|
||||
using EggLink.DanhengServer.Data.Excel;
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using SqlSugar;
|
||||
@@ -60,15 +61,22 @@ public class ItemData
|
||||
|
||||
public void AddRandomRelicSubAffix(int count = 1)
|
||||
{
|
||||
// Avoid illegal count of relic sub affixes
|
||||
if (count is < 1 or > 4 || SubAffixes.Count >= 4) return;
|
||||
GameData.RelicConfigData.TryGetValue(ItemId, out var config);
|
||||
if (config == null) return;
|
||||
GameData.RelicSubAffixData.TryGetValue(config.SubAffixGroup, out var affixes);
|
||||
|
||||
if (affixes == null) return;
|
||||
|
||||
// Avoid same property on both main affix and sub affixes
|
||||
GameData.RelicMainAffixData.TryGetValue(config.MainAffixGroup, out var mainAffixes);
|
||||
if (mainAffixes == null) return;
|
||||
var mainProperty = mainAffixes[MainAffix].Property;
|
||||
|
||||
var rollPool = new List<RelicSubAffixConfigExcel>();
|
||||
foreach (var affix in affixes.Values)
|
||||
if (SubAffixes.Find(x => x.Id == affix.AffixID) == null)
|
||||
if (affix.Property != mainProperty & SubAffixes.Find(x => x.Id == affix.AffixID) == null)
|
||||
rollPool.Add(affix);
|
||||
|
||||
for (var i = 0; i < count; i++)
|
||||
@@ -77,11 +85,68 @@ public class ItemData
|
||||
ItemSubAffix subAffix = new(affixConfig, 1);
|
||||
SubAffixes.Add(subAffix);
|
||||
rollPool.Remove(affixConfig);
|
||||
if (SubAffixes.Count >= 4) break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init relic sub affixes based on rarity
|
||||
* 20% chance to get one more affix
|
||||
* r3 1-2
|
||||
* r4 2-3
|
||||
* r5 3-4
|
||||
*/
|
||||
public void InitRandomRelicSubAffixesByRarity(ItemRarityEnum rarity = ItemRarityEnum.Unknown)
|
||||
{
|
||||
if (rarity == ItemRarityEnum.Unknown)
|
||||
{
|
||||
GameData.ItemConfigData.TryGetValue(ItemId, out var config);
|
||||
if (config == null) return;
|
||||
rarity = config.Rarity;
|
||||
}
|
||||
|
||||
int initSubAffixesCount;
|
||||
switch (rarity)
|
||||
{
|
||||
case ItemRarityEnum.Rare:
|
||||
initSubAffixesCount = 1 + LuckyRelicSubAffixCount();
|
||||
break;
|
||||
case ItemRarityEnum.VeryRare:
|
||||
initSubAffixesCount = 2 + LuckyRelicSubAffixCount();
|
||||
break;
|
||||
case ItemRarityEnum.SuperRare:
|
||||
initSubAffixesCount = 3 + LuckyRelicSubAffixCount();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
AddRandomRelicSubAffix(initSubAffixesCount);
|
||||
}
|
||||
|
||||
public int LuckyRelicSubAffixCount()
|
||||
{
|
||||
return Random.Shared.Next(100) < 20 ? 1 : 0;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public int CalcTotalExpGained()
|
||||
{
|
||||
if (Level <= 0) return Exp;
|
||||
GameData.RelicConfigData.TryGetValue(ItemId, out var costExcel);
|
||||
if (costExcel == null) return 0;
|
||||
var exp = 0;
|
||||
for (var i = 0; i < Level; i++)
|
||||
{
|
||||
GameData.RelicExpTypeData.TryGetValue(costExcel.ExpType * 100 + i, out var typeExcel);
|
||||
if (typeExcel != null)
|
||||
exp += typeExcel.Exp;
|
||||
}
|
||||
|
||||
return exp + Exp;
|
||||
}
|
||||
|
||||
#region Serialization
|
||||
|
||||
public Material ToMaterialProto()
|
||||
|
||||
@@ -5,6 +5,7 @@ public enum MultiPathAvatarTypeEnum
|
||||
Warrior = 8001,
|
||||
Knight = 8003,
|
||||
Shaman = 8005,
|
||||
Memory = 8007,
|
||||
Mar_7thKnight = 1001,
|
||||
Mar_7thRogue = 1224
|
||||
}
|
||||
}
|
||||
|
||||
@@ -314,11 +314,13 @@ public class MissionTextCHS
|
||||
public string Desc =>
|
||||
"管理玩家的任务\n" +
|
||||
"使用 pass 完成当前正在进行的所有任务,此命令易造成严重卡顿,请尽量使用 /mission finish 替代\n" +
|
||||
"使用 running 获取正在进行的任务以及可能卡住的任务,使用后可能会出现较长任务列表,请注意甄别\n" +
|
||||
"使用 reaccept 可重新进行指定主任务,请浏览 handbook 来获取主任务ID";
|
||||
"使用 finish [子任务ID] 完成指定子任务,请浏览 handbook 来获取子任务ID\n" +
|
||||
"使用 finishmain [主任务ID] 完成指定主任务,请浏览 handbook 来获取主任务ID\n" +
|
||||
"使用 running <-all> 获取正在追踪的任务,增加'-all'则显示所有正在进行的任务以及可能卡住的任务,使用后可能会出现较长任务列表,请注意甄别\n" +
|
||||
"使用 reaccept [主任务ID] 可重新进行指定主任务,请浏览 handbook 来获取主任务ID";
|
||||
|
||||
public string Usage =>
|
||||
"用法:/mission pass\n\n用法:/mission finish [子任务ID]\n\n用法:/mission running\n\n用法:/mission reaccept [主任务ID]";
|
||||
"用法:/mission pass\n\n用法:/mission finish [子任务ID]\n\n用法:/mission running <-all>\n\n用法:/mission reaccept [主任务ID]\n\n用法:/mission finishmain [主任务ID]";
|
||||
|
||||
public string AllMissionsFinished => "所有任务已完成!";
|
||||
public string AllRunningMissionsFinished => "共 {0} 个进行中的任务已完成!";
|
||||
@@ -435,7 +437,7 @@ public class RaidTextCHS
|
||||
public class AccountTextCHS
|
||||
{
|
||||
public string Desc => "创建账号\n注意:此命令未经测试,请谨慎使用!";
|
||||
public string Usage => "用法:/account create <用户名>";
|
||||
public string Usage => "用法:/account create [用户名]";
|
||||
public string InvalidUid => "无效UID参数!";
|
||||
public string CreateError => "出现内部错误 {0} ";
|
||||
public string CreateSuccess => "新账号 {0} 创建成功!";
|
||||
@@ -450,7 +452,7 @@ public class AccountTextCHS
|
||||
public class UnstuckTextCHS
|
||||
{
|
||||
public string Desc => "将玩家传送回默认场景";
|
||||
public string Usage => "用法:/unstuck <UID>";
|
||||
public string Usage => "用法:/unstuck [UID]";
|
||||
public string UnstuckSuccess => "已成功将该玩家传送回默认场景";
|
||||
public string UidNotExist => "该UID不存在!";
|
||||
public string PlayerIsOnline => "该玩家目前在线上!";
|
||||
@@ -462,7 +464,7 @@ public class UnstuckTextCHS
|
||||
public class SetlevelTextCHS
|
||||
{
|
||||
public string Desc => "设定玩家等级";
|
||||
public string Usage => "用法:/setlevel <等级>";
|
||||
public string Usage => "用法:/setlevel [等级]";
|
||||
public string SetlevelSuccess => "等级设定成功!";
|
||||
}
|
||||
|
||||
|
||||
@@ -260,7 +260,7 @@ public class AvatarTextEN
|
||||
public class GiveTextEN
|
||||
{
|
||||
public string Desc => "Give player items, item id can be avatar id, but cant set level, talent, rank";
|
||||
public string Usage => "Usage: /give <item ID> l<level> x<amount> r<rank>";
|
||||
public string Usage => "Usage: /give [item ID] l<level> x<amount> r<rank>";
|
||||
public string ItemNotFound => "Item not found!";
|
||||
public string GiveItem => "Gave @{0} {1} item(s) {2}";
|
||||
}
|
||||
@@ -321,7 +321,9 @@ public class MissionTextEN
|
||||
public string Desc =>
|
||||
"Manage player's missions\n" +
|
||||
"Use 'pass' to finish all running mission, this command will cause severe lagging, please use '/mission finish' instead\n" +
|
||||
"Use 'running' to get the running mission and possible stuck missions, after use, a longer mission list may appear, please note that\n" +
|
||||
"Use 'finish [SubMissionID]' to finish certain sub-mission,please find sub-mission id in handbook\n" +
|
||||
"Use 'finishmain [MainMissionID]' to finish certain main mission,please find main mission id in handbook\n" +
|
||||
"Use 'running <-all>' to get the tracking mission, adding '-all' shows all running mission and possible stuck missions, after use, a longer mission list may appear, please note that\n" +
|
||||
"Use 'reaccept' to re-accept given main mission, please find main mission id in handbook";
|
||||
|
||||
public string Usage =>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
public static class GameConstants
|
||||
{
|
||||
public const int INVENTORY_MAX_EQUIPMENT = 1500;
|
||||
public const int INVENTORY_MAX_RELIC = 1500;
|
||||
public const int INVENTORY_MAX_RELIC = 2000;
|
||||
public const int INVENTORY_MAX_MATERIAL = 2000;
|
||||
|
||||
public const int MAX_LINEUP_COUNT = 9;
|
||||
|
||||
@@ -10,7 +10,7 @@ public static class UtilTools
|
||||
GameData.RelicMainAffixData.TryGetValue(groupId, out var affixes);
|
||||
if (affixes == null) return 0;
|
||||
List<int> affixList = [];
|
||||
affixList.AddRange(from affix in affixes.Values where affix.IsAvailable select affix.AffixID);
|
||||
affixList.AddRange(from affix in affixes.Values select affix.AffixID);
|
||||
return affixList.Count == 0 ? 0 : affixList.RandomElement();
|
||||
}
|
||||
|
||||
|
||||
@@ -296,7 +296,7 @@ public class ChallengeInstance
|
||||
if (monsters == 0) await AdvanceStage(req);
|
||||
|
||||
// Calculate rounds left
|
||||
if (IsStory()) RoundsLeft = (int)Math.Min(Math.Max(RoundsLeft - req.Stt.RoundCnt, 1), RoundsLeft);
|
||||
if (!(IsStory() && IsBoss())) RoundsLeft = (int)Math.Min(Math.Max(RoundsLeft - req.Stt.RoundCnt, 1), RoundsLeft);
|
||||
|
||||
// Set saved technique points (This will be restored if the player resets the challenge)
|
||||
SavedMp = Player.LineupManager!.GetCurLineup()!.Mp;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using EggLink.DanhengServer.Data;
|
||||
using System.Collections.Frozen;
|
||||
using EggLink.DanhengServer.Data;
|
||||
using EggLink.DanhengServer.Database;
|
||||
using EggLink.DanhengServer.Database.Inventory;
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
@@ -11,6 +12,8 @@ using EggLink.DanhengServer.GameServer.Server.Packet.Send.PlayerSync;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Scene;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
using Google.Protobuf.Collections;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Game.Inventory;
|
||||
|
||||
@@ -54,7 +57,7 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
switch (itemConfig.ItemMainType)
|
||||
{
|
||||
case ItemMainTypeEnum.Equipment:
|
||||
if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT) // get the max equipment
|
||||
if (Data.EquipmentItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT) // get the max equipment
|
||||
{
|
||||
await Player.SendPacket(new PacketRetcodeNotify(Retcode.RetEquipmentExceedLimit));
|
||||
break;
|
||||
@@ -88,9 +91,8 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
};
|
||||
break;
|
||||
case ItemMainTypeEnum.Relic:
|
||||
if (Data.RelicItems.Count + 1 >
|
||||
GameConstants
|
||||
.INVENTORY_MAX_RELIC) // get the max relic, i dont think one player can have more than max count of relic until i see a player get 50000 relic and the client crashed :(
|
||||
//I dont think one player can have more than max count of relic until i see a player get 50000 relic and the client crashed :(
|
||||
if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_RELIC) // get the max relic
|
||||
{
|
||||
await Player.SendPacket(new PacketRetcodeNotify(Retcode.RetRelicExceedLimit));
|
||||
break;
|
||||
@@ -98,7 +100,7 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
|
||||
var item = await PutItem(itemId, 1, 1, level: 0, uniqueId: ++Data.NextUniqueId);
|
||||
item.AddRandomRelicMainAffix();
|
||||
item.AddRandomRelicSubAffix(3);
|
||||
item.InitRandomRelicSubAffixesByRarity();
|
||||
Data.RelicItems.Find(x => x.UniqueId == item.UniqueId)!.SubAffixes = item.SubAffixes;
|
||||
itemData = item;
|
||||
break;
|
||||
@@ -219,7 +221,7 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
Data.MaterialItems.Add(item);
|
||||
break;
|
||||
case ItemMainTypeEnum.Equipment:
|
||||
if (Data.RelicItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT)
|
||||
if (Data.EquipmentItems.Count + 1 > GameConstants.INVENTORY_MAX_EQUIPMENT)
|
||||
{
|
||||
await Player.SendPacket(new PacketRetcodeNotify(Retcode.RetEquipmentExceedLimit));
|
||||
return item;
|
||||
@@ -458,43 +460,20 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
items.Add(new ItemData
|
||||
{
|
||||
ItemId = item.ItemID,
|
||||
Count = amount
|
||||
Count = amount * (item.ItemID == 22
|
||||
? 1
|
||||
: ConfigManager.Config.ServerOption.ValidFarmingDropRate())
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// randomize the order of the relics
|
||||
var relics = mapping.DropRelicItemList.OrderBy(x => Random.Shared.Next()).ToList();
|
||||
|
||||
var relic5Count = Random.Shared.Next(worldLevel - 4, worldLevel - 2);
|
||||
var relic4Count = worldLevel - 2;
|
||||
foreach (var relic in relics)
|
||||
{
|
||||
var random = Random.Shared.Next(0, 101);
|
||||
|
||||
if (random <= relic.Chance)
|
||||
{
|
||||
var amount = relic.ItemNum > 0
|
||||
? relic.ItemNum
|
||||
: Random.Shared.Next(relic.MinCount, relic.MaxCount + 1);
|
||||
|
||||
GameData.ItemConfigData.TryGetValue(relic.ItemID, out var itemData);
|
||||
if (itemData == null) continue;
|
||||
|
||||
if (itemData.Rarity == ItemRarityEnum.SuperRare && relic5Count > 0)
|
||||
relic5Count--;
|
||||
else if (itemData.Rarity == ItemRarityEnum.VeryRare && relic4Count > 0)
|
||||
relic4Count--;
|
||||
else
|
||||
continue;
|
||||
|
||||
items.Add(new ItemData
|
||||
{
|
||||
ItemId = relic.ItemID,
|
||||
Count = 1
|
||||
});
|
||||
}
|
||||
}
|
||||
// Generate relics
|
||||
var relicDrops = mapping.GenerateRelicDrops();
|
||||
|
||||
// Let AddItem notify relics count exceeding limit
|
||||
items.AddRange(Data.RelicItems.Count + relicDrops.Count - 1 > GameConstants.INVENTORY_MAX_RELIC
|
||||
? relicDrops[..(GameConstants.INVENTORY_MAX_RELIC - Data.RelicItems.Count + 1)]
|
||||
: relicDrops);
|
||||
|
||||
foreach (var item in items)
|
||||
{
|
||||
@@ -620,42 +599,73 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
|
||||
await RemoveItem(2, (int)(composeConfig.CoinCost * req.Count));
|
||||
|
||||
var relicId = (int)req.ComposeRelicId;
|
||||
GameData.RelicConfigData.TryGetValue(relicId, out var itemConfig);
|
||||
GameData.RelicSubAffixData.TryGetValue(itemConfig!.SubAffixGroup, out var subAffixConfig);
|
||||
|
||||
// Add relic
|
||||
var subAffixes = req.SubAffixIdList.Select(subId => ((int)subId, 1)).ToList();
|
||||
var mainAffix = (int)req.MainAffixId;
|
||||
var itemData = new ItemData
|
||||
{
|
||||
ItemId = relicId,
|
||||
Level = 0,
|
||||
UniqueId = ++Data.NextUniqueId,
|
||||
MainAffix = mainAffix,
|
||||
SubAffixes = req.SubAffixIdList.Select(subId => new ItemSubAffix(subAffixConfig![(int)subId], 1)).ToList(),
|
||||
Count = 1
|
||||
};
|
||||
if (mainAffix == 0) itemData.AddRandomRelicMainAffix();
|
||||
itemData.AddRandomRelicSubAffix(3 - itemData.SubAffixes.Count + itemData.LuckyRelicSubAffixCount());
|
||||
await AddItem(itemData, notify: false);
|
||||
|
||||
var (_, relic) = await HandleRelic(
|
||||
(int)req.ComposeRelicId, ++Data.NextUniqueId, 0, (int)req.MainAffixId, subAffixes);
|
||||
|
||||
return relic;
|
||||
return itemData;
|
||||
}
|
||||
|
||||
public async ValueTask ReforgeRelic(int uniqueId)
|
||||
{
|
||||
var relic = Data.RelicItems.FirstOrDefault(x => x.UniqueId == uniqueId);
|
||||
await RemoveItem(relic!.ItemId, 1, uniqueId, false);
|
||||
var relic = Data.RelicItems.First(x => x.UniqueId == uniqueId);
|
||||
|
||||
var totalCount = 0;
|
||||
var subAffixes = new List<(int, int)>();
|
||||
foreach (var sub in relic.SubAffixes)
|
||||
{
|
||||
totalCount += sub.Count;
|
||||
subAffixes.Add((sub.Id, 0));
|
||||
totalCount = totalCount + sub.Count - 1;
|
||||
subAffixes.Add((sub.Id, 1));
|
||||
}
|
||||
|
||||
var remainCount = totalCount;
|
||||
for (var i = 0; i < subAffixes.Count - 1; i++)
|
||||
while (totalCount > 0)
|
||||
{
|
||||
var count = new Random().Next(1, remainCount - (subAffixes.Count - i - 1));
|
||||
subAffixes[i] = (subAffixes[i].Item1, count);
|
||||
remainCount -= count;
|
||||
var idx = Random.Shared.Next(subAffixes.Count);
|
||||
var cur = subAffixes[idx];
|
||||
subAffixes[idx] = (cur.Item1, cur.Item2 + 1);
|
||||
totalCount--;
|
||||
}
|
||||
|
||||
GameData.RelicConfigData.TryGetValue(relic.ItemId, out var itemConfig);
|
||||
GameData.RelicSubAffixData.TryGetValue(itemConfig!.SubAffixGroup, out var subAffixConfig);
|
||||
|
||||
for (var i = 0; i < subAffixes.Count; i++)
|
||||
{
|
||||
var (subId, subLevel) = subAffixes[i];
|
||||
subAffixConfig!.TryGetValue(subId, out var subAffix);
|
||||
var aff = new ItemSubAffix(subAffix!, subLevel);
|
||||
relic.SubAffixes[i] = aff;
|
||||
}
|
||||
|
||||
if (relic.EquipAvatar > 0)
|
||||
{
|
||||
var avatar = Player.AvatarManager!.GetAvatar(relic.EquipAvatar);
|
||||
await Player.SendPacket(new PacketPlayerSyncScNotify(avatar!, relic));
|
||||
}
|
||||
else
|
||||
{
|
||||
await Player.SendPacket(new PacketPlayerSyncScNotify(relic));
|
||||
}
|
||||
subAffixes[^1] = (subAffixes[^1].Item1, remainCount);
|
||||
|
||||
await HandleRelic(relic.ItemId, uniqueId, relic.Level, relic.MainAffix, subAffixes);
|
||||
await RemoveItem(238, 1);
|
||||
}
|
||||
|
||||
public async ValueTask<List<ItemData>> SellItem(ItemCostData costData)
|
||||
public async ValueTask<List<ItemData>> SellItem(ItemCostData costData, bool toMaterial = false)
|
||||
{
|
||||
List<ItemData> items = [];
|
||||
Dictionary<int, int> itemMap = [];
|
||||
@@ -682,10 +692,46 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
removeItems.Add((itemData.ItemId, 1, (int)cost.RelicUniqueId));
|
||||
GameData.ItemConfigData.TryGetValue(itemData.ItemId, out var itemConfig);
|
||||
if (itemConfig == null) continue;
|
||||
foreach (var returnItem in itemConfig.ReturnItemIDList) // return items
|
||||
if (itemConfig.Rarity != ItemRarityEnum.SuperRare || toMaterial)
|
||||
{
|
||||
if (!itemMap.ContainsKey(returnItem.ItemID)) itemMap[returnItem.ItemID] = 0;
|
||||
itemMap[returnItem.ItemID] += returnItem.ItemNum;
|
||||
foreach (var returnItem in itemConfig.ReturnItemIDList) // basic return items
|
||||
{
|
||||
itemMap.TryAdd(returnItem.ItemID, 0);
|
||||
itemMap[returnItem.ItemID] += returnItem.ItemNum;
|
||||
}
|
||||
|
||||
var expReturned = (int)(itemData.CalcTotalExpGained() * 0.8);
|
||||
|
||||
var credit = (int)(expReturned * 1.5);
|
||||
if (credit > 0)
|
||||
{
|
||||
itemMap.TryAdd(2, 0);
|
||||
itemMap[2] += (int)(expReturned * 1.5);
|
||||
}
|
||||
|
||||
var lostGoldFragCnt = expReturned / 500;
|
||||
if (lostGoldFragCnt > 0)
|
||||
{
|
||||
itemMap.TryAdd(232, 0);
|
||||
itemMap[232] += lostGoldFragCnt;
|
||||
}
|
||||
|
||||
var lostGoldLightdust = expReturned % 500 / 100;
|
||||
if (lostGoldLightdust > 0)
|
||||
{
|
||||
itemMap.TryAdd(231, 0);
|
||||
itemMap[231] += lostGoldLightdust;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var expGained = itemData.CalcTotalExpGained();
|
||||
var remainsCnt = (int)(10 + expGained * 0.005144);
|
||||
if (remainsCnt > 0)
|
||||
{
|
||||
itemMap.TryAdd(235, 0);
|
||||
itemMap[235] += remainsCnt;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1294,4 +1340,80 @@ public class InventoryManager(PlayerInstance player) : BasePlayerManager(player)
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Mark
|
||||
public async ValueTask<bool> LockItems(RepeatedField<uint> ids, bool isLocked, ItemMainTypeEnum itemType = ItemMainTypeEnum.Unknown)
|
||||
{
|
||||
List<ItemData> targetItems;
|
||||
switch (itemType)
|
||||
{
|
||||
case ItemMainTypeEnum.Equipment:
|
||||
targetItems = Data.EquipmentItems;
|
||||
break;
|
||||
case ItemMainTypeEnum.Relic:
|
||||
targetItems = Data.RelicItems;
|
||||
break;
|
||||
case ItemMainTypeEnum.Unknown:
|
||||
case ItemMainTypeEnum.Virtual:
|
||||
case ItemMainTypeEnum.AvatarCard:
|
||||
case ItemMainTypeEnum.Usable:
|
||||
case ItemMainTypeEnum.Material:
|
||||
case ItemMainTypeEnum.Mission:
|
||||
case ItemMainTypeEnum.Display:
|
||||
case ItemMainTypeEnum.Pet:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (targetItems.Count == 0) return false;
|
||||
var idPool = ids.ToList().ConvertAll(x => (int)x).ToFrozenSet();
|
||||
var items = new List<ItemData>();
|
||||
foreach (var x in targetItems)
|
||||
{
|
||||
if (x.Discarded || !idPool.Contains(x.UniqueId)) continue;
|
||||
x.Locked = isLocked;
|
||||
items.Add(x);
|
||||
}
|
||||
|
||||
if (items.Count <= 0) return false;
|
||||
await player.SendPacket(new PacketPlayerSyncScNotify(items));
|
||||
return true;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> DiscardItems(RepeatedField<uint> ids, bool discarded, ItemMainTypeEnum itemType = ItemMainTypeEnum.Unknown)
|
||||
{
|
||||
List<ItemData> targetItems;
|
||||
switch (itemType)
|
||||
{
|
||||
case ItemMainTypeEnum.Equipment:
|
||||
targetItems = Data.EquipmentItems;
|
||||
break;
|
||||
case ItemMainTypeEnum.Relic:
|
||||
targetItems = Data.RelicItems;
|
||||
break;
|
||||
case ItemMainTypeEnum.Unknown:
|
||||
case ItemMainTypeEnum.Virtual:
|
||||
case ItemMainTypeEnum.AvatarCard:
|
||||
case ItemMainTypeEnum.Usable:
|
||||
case ItemMainTypeEnum.Material:
|
||||
case ItemMainTypeEnum.Mission:
|
||||
case ItemMainTypeEnum.Display:
|
||||
case ItemMainTypeEnum.Pet:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if (targetItems.Count == 0) return false;
|
||||
var idPool = ids.ToList().ConvertAll(x => (int)x).ToFrozenSet();
|
||||
var items = new List<ItemData>();
|
||||
foreach (var x in targetItems)
|
||||
{
|
||||
if (x.Locked || !idPool.Contains(x.UniqueId)) continue;
|
||||
x.Discarded = discarded;
|
||||
items.Add(x);
|
||||
}
|
||||
|
||||
if (items.Count <= 0) return false;
|
||||
await player.SendPacket(new PacketPlayerSyncScNotify(items));
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using EggLink.DanhengServer.Data.Config;
|
||||
using EggLink.DanhengServer.Data.Excel;
|
||||
using EggLink.DanhengServer.Enums.Mission;
|
||||
using EggLink.DanhengServer.GameServer.Game.Player;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Game.Mission.FinishType.Handler;
|
||||
|
||||
[MissionFinishType(MissionFinishTypeEnum.MatchThreeFinishLevel)]
|
||||
public class MissionHandlerMatchThreeFinishLevel : MissionFinishTypeHandler
|
||||
{
|
||||
public override async ValueTask HandleMissionFinishType(PlayerInstance player, SubMissionInfo info, object? arg)
|
||||
{
|
||||
if(arg is MatchThreeLevelEndCsReq req)
|
||||
if(req.LevelId == info.ParamInt1)
|
||||
await player.MissionManager!.FinishSubMission(info.ID);
|
||||
}
|
||||
|
||||
public override async ValueTask HandleQuestFinishType(PlayerInstance player, QuestDataExcel quest,
|
||||
FinishWayExcel excel, object? arg)
|
||||
{
|
||||
await ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,14 @@ public class PlayerInstance(PlayerData data)
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var relic in InventoryManager.Data.RelicItems)
|
||||
{
|
||||
if (relic.MainAffix != 0) continue; // fix relic main affix
|
||||
|
||||
var groupId = GameData.RelicConfigData.GetValueOrDefault(relic.ItemId)?.MainAffixGroup ?? 0;
|
||||
relic.MainAffix = UtilTools.GetRandomRelicMainAffix(groupId);
|
||||
}
|
||||
|
||||
foreach (var avatar in AvatarManager?.AvatarData.Avatars ?? [])
|
||||
foreach (var skill in avatar.GetSkillTree())
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
using EggLink.DanhengServer.Util;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Item;
|
||||
|
||||
@@ -11,10 +12,15 @@ public class HandlerComposeSelectedRelicCsReq : Handler
|
||||
{
|
||||
var req = ComposeSelectedRelicCsReq.Parser.ParseFrom(data);
|
||||
var player = connection.Player!;
|
||||
var item = await player.InventoryManager!.ComposeRelic(req);
|
||||
if (player.InventoryManager!.Data.RelicItems.Count >= GameConstants.INVENTORY_MAX_RELIC)
|
||||
{
|
||||
await connection.SendPacket(new PacketComposeSelectedRelicScRsp(req.ComposeId, Retcode.RetRelicExceedLimit));
|
||||
return;
|
||||
}
|
||||
var item = await player.InventoryManager.ComposeRelic(req);
|
||||
if (item == null)
|
||||
{
|
||||
await connection.SendPacket(new PacketComposeSelectedRelicScRsp());
|
||||
await connection.SendPacket(new PacketComposeSelectedRelicScRsp(req.ComposeId));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ public class HandlerDestroyItemCsReq : Handler
|
||||
{
|
||||
var req = DestroyItemCsReq.Parser.ParseFrom(data);
|
||||
|
||||
await connection.Player!.InventoryManager!.RemoveItem((int)req.ItemCount, (int)req.ItemCount);
|
||||
await connection.Player!.InventoryManager!.RemoveItem((int)req.ItemId, (int)req.ItemCount);
|
||||
await connection.SendPacket(CmdIds.DestroyItemScRsp);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Item;
|
||||
|
||||
[Opcode(CmdIds.DiscardRelicCsReq)]
|
||||
public class HandlerDiscardRelicCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = DiscardRelicCsReq.Parser.ParseFrom(data);
|
||||
var result =
|
||||
await connection.Player!.InventoryManager!.DiscardItems(req.RelicUniqueIdList, req.IsDiscard,
|
||||
ItemMainTypeEnum.Relic);
|
||||
await connection.SendPacket(new PacketDiscardRelicScRsp(result, req.IsDiscard));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Item;
|
||||
|
||||
[Opcode(CmdIds.LockEquipmentCsReq)]
|
||||
public class HandlerLockEquipmentCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = LockEquipmentCsReq.Parser.ParseFrom(data);
|
||||
var result =
|
||||
await connection.Player!.InventoryManager!.LockItems(req.EquipmentIdList, req.IsProtected,
|
||||
ItemMainTypeEnum.Equipment);
|
||||
await connection.SendPacket(new PacketLockEquipmentScRsp(result));
|
||||
}
|
||||
}
|
||||
19
GameServer/Server/Packet/Recv/Item/HandlerLockRelicCsReq.cs
Normal file
19
GameServer/Server/Packet/Recv/Item/HandlerLockRelicCsReq.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using EggLink.DanhengServer.Enums.Item;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Item;
|
||||
|
||||
[Opcode(CmdIds.LockRelicCsReq)]
|
||||
public class HandlerLockRelicCsReq : Handler
|
||||
{
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = LockRelicCsReq.Parser.ParseFrom(data);
|
||||
var result =
|
||||
await connection.Player!.InventoryManager!.LockItems(req.RelicUniqueIdList, req.IsProtected,
|
||||
ItemMainTypeEnum.Relic);
|
||||
await connection.SendPacket(new PacketLockRelicScRsp(result));
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public class HandlerSellItemCsReq : Handler
|
||||
public override async Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = SellItemCsReq.Parser.ParseFrom(data);
|
||||
var items = await connection.Player!.InventoryManager!.SellItem(req.CostData);
|
||||
var items = await connection.Player!.InventoryManager!.SellItem(req.CostData, req.ToMaterial);
|
||||
await connection.SendPacket(new PacketSellItemScRsp(items));
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.MatchThreeModule;
|
||||
using EggLink.DanhengServer.Enums.Mission;
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.MatchThreeModule;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
@@ -11,6 +12,8 @@ public class HandlerMatchThreeLevelEndCsReq : Handler
|
||||
{
|
||||
var req = MatchThreeLevelEndCsReq.Parser.ParseFrom(data);
|
||||
|
||||
await connection.Player!.MissionManager!.HandleFinishType(MissionFinishTypeEnum.MatchThreeFinishLevel, req);
|
||||
|
||||
await connection.SendPacket(new PacketMatchThreeLevelEndScRsp(req.LevelId, req.ModeId));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using EggLink.DanhengServer.GameServer.Server.Packet.Send.Player;
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Recv.Player;
|
||||
|
||||
[Opcode(CmdIds.ReserveStaminaExchangeCsReq)]
|
||||
public class HandlerReserveStaminaExchangeCsReq : Handler
|
||||
{
|
||||
public async override Task OnHandle(Connection connection, byte[] header, byte[] data)
|
||||
{
|
||||
var req = ReserveStaminaExchangeCsReq.Parser.ParseFrom(data);
|
||||
var player = connection.Player;
|
||||
if (player == null) return;
|
||||
var amount = req.Num;
|
||||
if (amount <= 0 || player.Data.StaminaReserve < amount)
|
||||
{
|
||||
await connection.SendPacket(new PacketReserveStaminaExchangeScRsp(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
player.Data.StaminaReserve -= amount;
|
||||
player.Data.Stamina += (int)amount;
|
||||
|
||||
await connection.SendPacket(new PacketStaminaInfoScNotify(player));
|
||||
await connection.SendPacket(new PacketReserveStaminaExchangeScRsp(amount));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,16 +6,28 @@ namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
|
||||
public class PacketComposeSelectedRelicScRsp : BasePacket
|
||||
{
|
||||
public PacketComposeSelectedRelicScRsp() : base(CmdIds.ComposeSelectedRelicScRsp)
|
||||
public PacketComposeSelectedRelicScRsp(uint composeId) : base(CmdIds.ComposeSelectedRelicScRsp)
|
||||
{
|
||||
var proto = new ComposeSelectedRelicScRsp
|
||||
{
|
||||
ComposeId = composeId,
|
||||
Retcode = 1
|
||||
};
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
|
||||
public PacketComposeSelectedRelicScRsp(uint composeId, Retcode retcode) : base(CmdIds.ComposeSelectedRelicScRsp)
|
||||
{
|
||||
var proto = new ComposeSelectedRelicScRsp
|
||||
{
|
||||
ComposeId = composeId,
|
||||
Retcode = (uint)retcode
|
||||
};
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
|
||||
public PacketComposeSelectedRelicScRsp(uint composeId, ItemData item)
|
||||
: base(CmdIds.ComposeSelectedRelicScRsp)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
|
||||
public class PacketDiscardRelicScRsp : BasePacket
|
||||
{
|
||||
public PacketDiscardRelicScRsp(bool success, bool isDiscard) : base(CmdIds.DiscardRelicScRsp)
|
||||
{
|
||||
DiscardRelicScRsp proto = new();
|
||||
|
||||
if (success) proto.IsDiscard = isDiscard;
|
||||
else proto.Retcode = (uint)Retcode.RetFail;
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
|
||||
public class PacketLockEquipmentScRsp : BasePacket
|
||||
{
|
||||
public PacketLockEquipmentScRsp(bool success) : base(CmdIds.LockEquipmentScRsp)
|
||||
{
|
||||
LockEquipmentScRsp proto = new();
|
||||
|
||||
if (!success) proto.Retcode = (uint)Retcode.RetFail;
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
16
GameServer/Server/Packet/Send/Item/PacketLockRecliScRsp.cs
Normal file
16
GameServer/Server/Packet/Send/Item/PacketLockRecliScRsp.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Item;
|
||||
|
||||
public class PacketLockRelicScRsp : BasePacket
|
||||
{
|
||||
public PacketLockRelicScRsp(bool success) : base(CmdIds.LockRelicScRsp)
|
||||
{
|
||||
LockRelicScRsp proto = new();
|
||||
|
||||
if (!success) proto.Retcode = (uint)Retcode.RetFail;
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using EggLink.DanhengServer.Kcp;
|
||||
using EggLink.DanhengServer.Proto;
|
||||
|
||||
namespace EggLink.DanhengServer.GameServer.Server.Packet.Send.Player;
|
||||
|
||||
public class PacketReserveStaminaExchangeScRsp : BasePacket
|
||||
{
|
||||
public PacketReserveStaminaExchangeScRsp(uint amount) : base(CmdIds.ReserveStaminaExchangeScRsp)
|
||||
{
|
||||
var proto = new ReserveStaminaExchangeScRsp();
|
||||
|
||||
if (amount > 0) proto.Num = amount;
|
||||
else proto.Retcode = (uint)Retcode.RetFail;
|
||||
|
||||
SetData(proto);
|
||||
}
|
||||
}
|
||||
@@ -12,17 +12,16 @@
|
||||
</div>
|
||||
|
||||
## 💡API Help
|
||||
- Since version 2.3, external APIs are supported
|
||||
- For example, your Dispatch is http://127.0.0.1:8080, and the request parameters and returns are in json format
|
||||
- (1) Authorization interface: http://127.0.0.1:8080/muip/auth_admin (support POST)
|
||||
- -Required parameter 1: admin_key (MuipServer/AdminKey configuration in config.php)
|
||||
- -Required parameter 2: key_type (type, e.g. PEM or XML)
|
||||
- -Return example:
|
||||
|
||||
- External API call interfaces are supported starting from version 2.3.
|
||||
- The main interface is the Dispatch interface with an entry point. For example, if your Dispatch is http://127.0.0.1:8080, the request parameters and responses are in JSON format.
|
||||
- (1) Create Session Interface: http://127.0.0.1:8080/muip/create_session (supports POST)
|
||||
- -Optional parameter: key_type (type, only supports PEM or default XML)
|
||||
- -Response example:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
//codeResponse: `code`: `0 -> Success` `1 -> Token incorrect or not enable`
|
||||
"message": "Authorized admin key successfully!",
|
||||
"message": "Created!",
|
||||
"data": {
|
||||
"rsaPublicKey": "***",
|
||||
"sessionId": "***",
|
||||
@@ -30,29 +29,41 @@
|
||||
}
|
||||
}
|
||||
```
|
||||
- (2)Submit command interface: http://127.0.0.1:8080/muip/exec_cmd (support POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after authorization API request)
|
||||
- -Required parameter 2: Command (the command to be executed is encrypted by RSA[pacs#1] under rsaPublicKey)
|
||||
- (2) Authorization Interface: http://127.0.0.1:8080/muip/auth_admin (supports POST)
|
||||
- -Required parameter 1: SessionId (obtained after requesting the Create Session Interface)
|
||||
- -Required parameter 2: admin_key (configured in config.json's MuipServer.AdminKey and encrypted under rsaPublicKey [obtained from Create Session Interface] using RSA [pacs#1])
|
||||
- -Response example:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Authorized admin key successfully!",
|
||||
"data": {
|
||||
"sessionId": "***",
|
||||
"expireTimeStamp": ***
|
||||
}
|
||||
}
|
||||
```
|
||||
- (3) Command Submission Interface: http://127.0.0.1:8080/muip/exec_cmd (supports POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after requesting the Create Session Interface)
|
||||
- -Required parameter 2: Command (the command to be executed, encrypted under rsaPublicKey [obtained from Create Session Interface] using RSA [pacs#1])
|
||||
- -Required parameter 3: TargetUid (UID of the player executing the command)
|
||||
- -Return example:
|
||||
- -Response example:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
//codeResponse: `code`: `0 -> Success` `1 -> Session expired` `2 -> session not found` `3 -> encryption error`
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"sessionId": "***",
|
||||
"message": "*** //base64
|
||||
"message": "*** //after base64 encoding
|
||||
}
|
||||
}
|
||||
```
|
||||
- (3)Interface to get server status: http://127.0.0.1:8080/muip/server_information (support POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after authorization API request)
|
||||
- -Return example:
|
||||
- (4) Get Server Status Interface: http://127.0.0.1:8080/muip/server_information (supports POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after requesting the Create Session Interface)
|
||||
- -Response example:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
//codeResponse: `code`: `0 -> Success` `1 -> Session expired` `2 -> session not found`
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"onlinePlayers": [
|
||||
@@ -70,14 +81,13 @@
|
||||
}
|
||||
}
|
||||
```
|
||||
- (4)Interface to get player information: http://127.0.0.1:8080/muip/player_information (support POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after authorization API request)
|
||||
- (5) Get Player Information Interface: http://127.0.0.1:8080/muip/player_information (supports POST/GET)
|
||||
- -Required parameter 1: SessionId (obtained after requesting the Create Session Interface)
|
||||
- -Required parameter 2: Uid (player UID)
|
||||
- -Return example:
|
||||
- -Response example:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
//Response: `code`: `0 -> Success` `1 -> Session expired` `2 -> player not exist` `3 -> session not found`
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"uid": 10001,
|
||||
@@ -97,4 +107,4 @@
|
||||
"acceptedSubMissionIdList": Array[169]
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -11,44 +11,57 @@
|
||||
</table>
|
||||
</div>
|
||||
|
||||
##💡API支援です
|
||||
## 💡APIヘルプ
|
||||
|
||||
-バージョン2.3から、外部API呼び出しインタフェースをサポートします。
|
||||
-全体のインタフェースはDispatchインタフェースに入口を加えます。例えば、Dispatchはhttp://127.0.0.1:8080、要求パラメータとリターンはjson形式です。
|
||||
-(1)ライセンスインタフェース:http://127.0.0.1:8080/muip/auth_admin(支持ポスト/ get)
|
||||
- -必須引数1:admin_key (config.phpでのMuipServer/AdminKey構成)
|
||||
- -必須パラメータ2:key_type(タイプ、例えばPEM)です。
|
||||
- -リターン例です:
|
||||
```json
|
||||
- バージョン2.3以降、外部API呼び出しをサポート
|
||||
- 総インターフェースはDispatchインターフェースにエントリを加えたもので、例えばあなたのDispatchが http://127.0.0.1:8080 の場合、リクエストパラメータと返り値はjson形式です
|
||||
- (1)セッション作成インターフェース: http://127.0.0.1:8080/muip/create_session (POSTサポート)
|
||||
- -オプションパラメータ:key_type (タイプ、PEMまたはデフォルトのXMLのみサポート)
|
||||
- -返り値の例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Authorized admin key successfully!",
|
||||
"message": "Created!",
|
||||
"data": {
|
||||
"rsaPublicKey": "***",
|
||||
"sessionId": "***",
|
||||
"expireTimeStamp": ***
|
||||
}
|
||||
}
|
||||
```
|
||||
—(2)提出命令インタフェース:http://127.0.0.1:8080/muip/exec_cmd(支持ポスト/ get)
|
||||
- -必伝パラメータ1:SessionId(ライセンスインターフェース要求後に取得します)
|
||||
- -必須引数2:Command(実行するコマンドをrsaPublicKey[ライセンスインターフェース取得]でRSA[pacs#1]で暗号化します)
|
||||
- -必伝パラメータ3:TargetUid(コマンドを実行するプレイヤーUID)です
|
||||
- -リターン例です:
|
||||
```json
|
||||
```
|
||||
- (2)認証インターフェース: http://127.0.0.1:8080/muip/auth_admin (POSTサポート)
|
||||
- -必須パラメータ1:SessionId (セッション作成インターフェースのリクエスト後に取得)
|
||||
- -必須パラメータ2:admin_key (config.jsonのMuipServer.AdminKey設定で、rsaPublicKey[セッション作成インターフェースで取得]下でRSA[pacs#1]暗号化)
|
||||
- -返り値の例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Authorized admin key successfully!",
|
||||
"data": {
|
||||
"sessionId": "***",
|
||||
"expireTimeStamp": ***
|
||||
}
|
||||
}
|
||||
```
|
||||
- (3)コマンド送信インターフェース: http://127.0.0.1:8080/muip/exec_cmd (POST/GETサポート)
|
||||
- -必須パラメータ1:SessionId (セッション作成インターフェースのリクエスト後に取得)
|
||||
- -必須パラメータ2:Command (実行するコマンドはrsaPublicKey[セッション作成インターフェースで取得]下でRSA[pacs#1]暗号化)
|
||||
- -必須パラメータ3:TargetUid (コマンドを実行するプレイヤーのUID)
|
||||
- -返り値の例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"sessionId": "***",
|
||||
"message": "*** //base64编码后
|
||||
"message": "*** //base64エンコード後
|
||||
}
|
||||
}
|
||||
```
|
||||
—(3)サーバーの状態をインタフェース:http://127.0.0.1:8080/muip/server_information(支持get)だけ
|
||||
- -必伝パラメータ1:SessionId(ライセンスインターフェース要求後に取得します)
|
||||
- -リターン例です:
|
||||
```json
|
||||
```
|
||||
- (4)サーバー状態取得インターフェース: http://127.0.0.1:8080/muip/server_information (POST/GETサポート)
|
||||
- -必須パラメータ1:SessionId (セッション作成インターフェースのリクエスト後に取得)
|
||||
- -返り値の例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
@@ -67,12 +80,12 @@
|
||||
"programUsedMemory": 323
|
||||
}
|
||||
}
|
||||
```
|
||||
—(4)プレイヤー情報を盗み出すインタフェース:http://127.0.0.1:8080/muip/player_information(支持get)だけ
|
||||
- -必伝パラメータ1:SessionId(ライセンスインターフェース要求後に取得します)
|
||||
- -必伝パラメーター2:Uid(プレイヤーUid)
|
||||
- -リターン例です:
|
||||
```json
|
||||
```
|
||||
- (5)プレイヤー情報取得インターフェース: http://127.0.0.1:8080/muip/player_information (POST/GETサポート)
|
||||
- -必須パラメータ1:SessionId (セッション作成インターフェースのリクエスト後に取得)
|
||||
- -必須パラメータ2:Uid (プレイヤーUID)
|
||||
- -返り値の例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
@@ -94,4 +107,4 @@
|
||||
"acceptedSubMissionIdList": Array[169]
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
@@ -15,14 +15,13 @@
|
||||
|
||||
- 自2.3版本開始,支持外部API調用接口
|
||||
- 總接口為Dispatch接口加上入口,比如你的Dispatch為 http://127.0.0.1:8080 ,請求參數和返回都為json格式
|
||||
- (1)授權接口: http://127.0.0.1:8080/muip/auth_admin (支持POST)
|
||||
- -必傳參數1:admin_key (在config.php的MuipServer/AdminKey配置)
|
||||
- -必傳參數2:key_type (類型,比如PEM)
|
||||
- (1)創建會話接口: http://127.0.0.1:8080/muip/create_session (支持POST)
|
||||
- -可選參數:key_type (類型,僅支持PEM或默認XML)
|
||||
- -返回示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Authorized admin key successfully!",
|
||||
"message": "Created!",
|
||||
"data": {
|
||||
"rsaPublicKey": "***",
|
||||
"sessionId": "***",
|
||||
@@ -30,9 +29,23 @@
|
||||
}
|
||||
}
|
||||
```
|
||||
- (2)提交命令接口: http://127.0.0.1:8080/muip/exec_cmd (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在授權接口請求後獲得)
|
||||
- -必傳參數2:Command (需要執行的命令經過rsaPublicKey[授權接口獲取]下RSA[pacs#1]加密)
|
||||
- (2)授權接口: http://127.0.0.1:8080/muip/auth_admin (支持POST)
|
||||
- -必傳參數1:SessionId (在創建會話接口請求後獲得)
|
||||
- -必傳參數2:admin_key (在config.json的MuipServer.AdminKey配置,並且經過rsaPublicKey[創建會話接口獲取]下RSA[pacs#1]加密)
|
||||
- -返回示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Authorized admin key successfully!",
|
||||
"data": {
|
||||
"sessionId": "***",
|
||||
"expireTimeStamp": ***
|
||||
}
|
||||
}
|
||||
```
|
||||
- (3)提交命令接口: http://127.0.0.1:8080/muip/exec_cmd (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在創建會話接口請求後獲得)
|
||||
- -必傳參數2:Command (需要執行的命令經過rsaPublicKey[創建會話接口獲取]下RSA[pacs#1]加密)
|
||||
- -必傳參數3:TargetUid (執行命令的玩家UID)
|
||||
- -返回示例:
|
||||
```json
|
||||
@@ -45,8 +58,8 @@
|
||||
}
|
||||
}
|
||||
```
|
||||
- (3)獲取服務器狀態接口: http://127.0.0.1:8080/muip/server_information (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在授權接口請求後獲得)
|
||||
- (4)獲取伺服器狀態接口: http://127.0.0.1:8080/muip/server_information (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在創建會話接口請求後獲得)
|
||||
- -返回示例:
|
||||
```json
|
||||
{
|
||||
@@ -68,10 +81,10 @@
|
||||
}
|
||||
}
|
||||
```
|
||||
- (4)獲取玩家信息接口: http://127.0.0.1:8080/muip/player_information (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在授權接口請求後獲得)
|
||||
- (5)獲取玩家信息接口: http://127.0.0.1:8080/muip/player_information (支持POST/GET)
|
||||
- -必傳參數1:SessionId (在創建會話接口請求後獲得)
|
||||
- -必傳參數2:Uid (玩家UID)
|
||||
- - -返回示例:
|
||||
- -返回示例:
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
@@ -94,4 +107,4 @@
|
||||
"acceptedSubMissionIdList": Array[169]
|
||||
}
|
||||
}
|
||||
```
|
||||
```
|
||||
Reference in New Issue
Block a user