sync: main repo

This commit is contained in:
StopWuyu
2025-03-01 18:00:46 +08:00
33 changed files with 737 additions and 153 deletions

View File

@@ -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))
{

View File

@@ -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")]

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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()
});
}

View File

@@ -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()

View File

@@ -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()

View File

@@ -5,6 +5,7 @@ public enum MultiPathAvatarTypeEnum
Warrior = 8001,
Knight = 8003,
Shaman = 8005,
Memory = 8007,
Mar_7thKnight = 1001,
Mar_7thRogue = 1224
}
}

View File

@@ -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 => "等级设定成功!";
}

View File

@@ -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-missionplease find sub-mission id in handbook\n" +
"Use 'finishmain [MainMissionID]' to finish certain main missionplease 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 =>

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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;
}
}

View File

@@ -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())
{

View File

@@ -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;
}

View File

@@ -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);
}
}

View 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.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));
}
}

View 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.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));
}
}

View 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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}

View File

@@ -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));
}
}
}

View File

@@ -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)
{

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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);
}
}

View File

@@ -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);
}
}

View File

@@ -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]
}
}
```
```

View File

@@ -11,44 +11,57 @@
</table>
</div>
##💡API支援です
## 💡APIヘルプ
-バージョン2.3から、外部API呼び出しインタフェースをサポートします。
-全体のインタフェースはDispatchインタフェースに入口を加えます。例えば、Dispatchhttp://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インタフェースにエントリを加えたもので、例えばあなたのDispatchhttp://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サポート)
- -必パラメータ1SessionId (セッション作成インターフェースのリクエスト後に取得)
- -必須パラメータ2admin_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サポート)
- -必須パラメータ1SessionId (セッション作成インターフェースのリクエスト後に取得)
- -必須パラメータ2Command (実行するコマンドはrsaPublicKey[セッション作成インターフェースで取得]下でRSA[pacs#1]暗号化)
- -必須パラメータ3TargetUid (コマンドを実行するプレイヤーの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サポート)
- -必パラメータ1SessionId (セッション作成インターフェースのリクエスト後に取得)
- -返り値の例:
```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サポート)
- -必パラメータ1SessionId (セッション作成インターフェースのリクエスト後に取得)
- -必パラメータ2Uid (プレイヤーUID)
- -返り値の例:
```json
{
"code": 0,
"message": "Success",
@@ -94,4 +107,4 @@
"acceptedSubMissionIdList": Array[169]
}
}
```
```

View File

@@ -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)
- -必傳參數1admin_key (在config.php的MuipServer/AdminKey配置)
- -必傳參數2key_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)
- -必傳參數1SessionId (在授權接口請求後獲得)
- -必傳參數2Command (需要執行的命令經過rsaPublicKey[授權接口獲取]下RSA[pacs#1]加密)
- (2)授權接口: http://127.0.0.1:8080/muip/auth_admin (支持POST)
- -必傳參數1SessionId (在創建會話接口請求後獲得)
- -必傳參數2admin_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)
- -必傳參數1SessionId (在創建會話接口請求後獲得)
- -必傳參數2Command (需要執行的命令經過rsaPublicKey[創建會話接口獲取]下RSA[pacs#1]加密)
- -必傳參數3TargetUid (執行命令的玩家UID)
- -返回示例:
```json
@@ -45,8 +58,8 @@
}
}
```
- (3)獲取服器狀態接口: http://127.0.0.1:8080/muip/server_information (支持POST/GET)
- -必傳參數1SessionId (在授權接口請求後獲得)
- (4)獲取服器狀態接口: http://127.0.0.1:8080/muip/server_information (支持POST/GET)
- -必傳參數1SessionId (在創建會話接口請求後獲得)
- -返回示例:
```json
{
@@ -68,10 +81,10 @@
}
}
```
- (4)獲取玩家信息接口: http://127.0.0.1:8080/muip/player_information (支持POST/GET)
- -必傳參數1SessionId (在授權接口請求後獲得)
- (5)獲取玩家信息接口: http://127.0.0.1:8080/muip/player_information (支持POST/GET)
- -必傳參數1SessionId (在創建會話接口請求後獲得)
- -必傳參數2Uid (玩家UID)
- - -返回示例:
- -返回示例:
```json
{
"code": 0,
@@ -94,4 +107,4 @@
"acceptedSubMissionIdList": Array[169]
}
}
```
```