Skip to content

Commit

Permalink
Merge pull request #511 from UnrealMultiple/cai_dev
Browse files Browse the repository at this point in the history
更新: CaiBot支持Economic数据查询
  • Loading branch information
ACaiCat authored Oct 4, 2024
2 parents b6da5c4 + 39244e6 commit 9360032
Show file tree
Hide file tree
Showing 6 changed files with 241 additions and 18 deletions.
5 changes: 5 additions & 0 deletions src/CaiBot/CaiBot.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,10 @@
<HintPath>SixLabors.ImageSharp.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Economics.RPG\Economics.RPG.csproj" />
<ProjectReference Include="..\Economics.Skill\Economics.Skill.csproj" />
<ProjectReference Include="..\EconomicsAPI\EconomicsAPI.csproj" />
</ItemGroup>

</Project>
31 changes: 31 additions & 0 deletions src/CaiBot/EconomicData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System.Text.Json.Serialization;

namespace CaiBot;

public class EconomicData
{
[JsonPropertyOrder(1)]
public string Coins = "";
[JsonPropertyOrder(2)]
public string LevelName = "";
[JsonPropertyOrder(3)]
public string Skill = "";

public static EconomicData GetEconomicData(string name)
{
EconomicData economicData = new();
if (EconomicSupport.GetCoinsSupport)
{
economicData.Coins = EconomicSupport.GetCoins(name);
}
if (EconomicSupport.GetLevelNameSupport)
{
economicData.LevelName = EconomicSupport.GetLevelName(name);
}
if (EconomicSupport.GetSkillSupport)
{
economicData.Skill = EconomicSupport.GetSkill(name);
}
return economicData;
}
}
175 changes: 175 additions & 0 deletions src/CaiBot/EconomicSupport.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using TerrariaApi.Server;
using TShockAPI;

namespace CaiBot;

public static class EconomicSupport
{
public static bool GetCoinsSupport = false;
public static bool GetLevelNameSupport = false;
public static bool GetSkillSupport = false;
private static Func<string> _getCurrencyNameFunc = null!;
private static Func<string, long> _getUserCurrencyFunc = null!;
private static Func<string, string> _getLevelNameFunc = null!;
private static Func<string, dynamic> _querySkillFunc = null!;
public static void Init()
{
var pluginContainer = ServerApi.Plugins.Where(x => x.Plugin.Name == "EconomicsAPI").FirstOrDefault();
if (pluginContainer is not null)
{
do
{
var economicsType = pluginContainer.Plugin.GetType();

var settingProperty = economicsType.GetProperty(nameof(EconomicsAPI.Economics.Setting));
if (settingProperty is null)
{
break;
}
var currencyNameField = settingProperty.PropertyType.GetField(nameof(EconomicsAPI.Economics.Setting.CurrencyName));
if (currencyNameField is null)
{
break;
}

var func = new DynamicMethod("GetCurrencyName", typeof(string), Type.EmptyTypes);
var iL = func.GetILGenerator();
iL.Emit(OpCodes.Call, settingProperty.GetMethod!);
iL.Emit(OpCodes.Ldfld, currencyNameField);
iL.Emit(OpCodes.Ret);
_getCurrencyNameFunc = func.CreateDelegate<Func<string>>();
var currencyManagerProperty = economicsType.GetProperty(nameof(EconomicsAPI.Economics.CurrencyManager));
if (currencyManagerProperty is null)
{
break;
}
var paramTypes = new Type[] { typeof(string) };
var getUserCurrencyMethod = currencyManagerProperty.PropertyType.GetMethod(nameof(EconomicsAPI.Economics.CurrencyManager.GetUserCurrency), paramTypes);
if (getUserCurrencyMethod is null)
{
break;
}
func = new DynamicMethod("GetUserCurrency", typeof(long), paramTypes);
iL = func.GetILGenerator();
iL.Emit(OpCodes.Call, currencyManagerProperty.GetMethod!);
iL.Emit(OpCodes.Ldarg_0);
iL.Emit(OpCodes.Callvirt, getUserCurrencyMethod);
iL.Emit(OpCodes.Ret);
_getUserCurrencyFunc = func.CreateDelegate<Func<string, long>>();

GetCoinsSupport = true;
} while (false);
}

pluginContainer = ServerApi.Plugins.Where(x => x.Plugin.Name == "Economics.RPG").FirstOrDefault();
if (pluginContainer is not null)
{
do
{
var economicsRPGType = pluginContainer.Plugin.GetType();

var playerLevelManagerProperty = economicsRPGType.GetProperty(nameof(Economics.RPG.RPG.PlayerLevelManager));
if (playerLevelManagerProperty is null)
{
break;
}
var paramTypes = new Type[] { typeof(string) };
var getLevelMethod = playerLevelManagerProperty.PropertyType.GetMethod(nameof(Economics.RPG.RPG.PlayerLevelManager.GetLevel), paramTypes);
if (getLevelMethod is null)
{
break;
}
var nameProperty = getLevelMethod.ReturnType.GetProperty(nameof(Economics.RPG.Model.Level.Name));
if (nameProperty is null)
{
break;
}
var func = new DynamicMethod("GetLevelName", typeof(string), paramTypes);
var iL = func.GetILGenerator();
iL.Emit(OpCodes.Call, playerLevelManagerProperty.GetMethod!);
iL.Emit(OpCodes.Ldarg_0);
iL.Emit(OpCodes.Callvirt, getLevelMethod);
iL.Emit(OpCodes.Callvirt, nameProperty.GetMethod!);
iL.Emit(OpCodes.Ret);
_getLevelNameFunc = func.CreateDelegate<Func<string, string>>();

GetLevelNameSupport = true;
}
while (false);
}

pluginContainer = ServerApi.Plugins.Where(x => x.Plugin.Name == "Economics.Skill").FirstOrDefault();
if (pluginContainer is not null)
{
do
{
var economicsSkillType = pluginContainer.Plugin.GetType();
var playerSkillManagerProperty = economicsSkillType.GetProperty("PlayerSKillManager", BindingFlags.NonPublic | BindingFlags.Static);
if (playerSkillManagerProperty is null)
{
break;
}
var paramTypes = new Type[] { typeof(string) };
var querySkillMethod = playerSkillManagerProperty.PropertyType.GetMethod("QuerySkill", paramTypes);
if (querySkillMethod is null)
{
break;
}
var func = new DynamicMethod("QuerySkill", typeof(object), paramTypes);
var iL = func.GetILGenerator();
iL.Emit(OpCodes.Call, playerSkillManagerProperty.GetMethod!);
iL.Emit(OpCodes.Ldarg_0);
iL.Emit(OpCodes.Callvirt, querySkillMethod);
iL.Emit(OpCodes.Ret);
_querySkillFunc = func.CreateDelegate<Func<string, dynamic>>();

GetSkillSupport = true;
}
while (false);
}
}

public static bool IsSupported(string feature)
{
return feature switch
{
nameof(GetCoins) => GetCoinsSupport,
nameof(GetLevelName) => GetLevelNameSupport,
nameof(GetSkill) => GetSkillSupport,
_ => false,
};
}

public static string GetCoins(string name)
{
ThrowIfNotSupported();
return $"{_getCurrencyNameFunc()}:{_getUserCurrencyFunc(name)}";
}

public static string GetLevelName(string name)
{
ThrowIfNotSupported();
var levelName = _getLevelNameFunc(name);
return $"职业:{(string.IsNullOrEmpty(levelName)?"":levelName)}";
}

public static string GetSkill(string name)
{
ThrowIfNotSupported();
var obj = _querySkillFunc(name);
IEnumerable<dynamic> skill = Enumerable.Cast<dynamic>(obj);
var msg = skill.Any() ? string.Join(',', Enumerable.Select(skill, obj => obj.Skill is null ? "无效技能" : (string)obj.Skill.Name)) : "";
return $"技能:{msg}";
}

private static void ThrowIfNotSupported([CallerMemberName] string memberName = "")
{
if (!IsSupported(memberName))
{
throw new NotSupportedException(memberName);
}
}
}
2 changes: 2 additions & 0 deletions src/CaiBot/MessageHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ public static async Task HandleMessageAsync(string receivedData)
{ "inventory", itemList },
{ "buffs", buffs },
{ "enhances", enhance },
{ "economic", EconomicData.GetEconomicData(plr.name) },
{ "group", (long) jsonObject["group"]! }
};
await SendDateAsync(JsonConvert.SerializeObject(result));
Expand Down Expand Up @@ -578,6 +579,7 @@ public static async Task HandleMessageAsync(string receivedData)
{ "inventory", itemList },
{ "buffs", buffs },
{ "enhances", enhance },
{ "economic", EconomicData.GetEconomicData(acc.Name) },
{ "group", (long) jsonObject["group"]! }
};
await SendDateAsync(JsonConvert.SerializeObject(result));
Expand Down
45 changes: 27 additions & 18 deletions src/CaiBot/Plugin.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Rests;
using System.Net;
using System.Net.WebSockets;
using System.Reflection;
Expand All @@ -15,10 +16,10 @@ namespace CaiBot;
[ApiVersion(2, 1)]
public class Plugin : TerrariaPlugin
{
public override string Author => "Cai,羽学";
public override string Author => "Cai,羽学,西江";
public override string Description => "CaiBot机器人的适配插件";
public override string Name => "CaiBotPlugin";
public static readonly Version VersionNum = new(2024, 10, 4, 0); //日期+版本号(0,1,2...)
public static readonly Version VersionNum = new(2024, 10, 4, 1); //日期+版本号(0,1,2...)
public override Version Version => VersionNum;

//插件的构造器
Expand All @@ -29,7 +30,8 @@ public Plugin(Main game) : base(game)
public static int InitCode = -1;

public static ClientWebSocket WebSocket = new();

public static Task WebSocketTask = Task.CompletedTask;
public static readonly CancellationTokenSource TokenSource = new ();
public Task WsTask;
public Task HeartBeat;

Expand All @@ -53,6 +55,7 @@ public Plugin(Main game) : base(game)

public override void Initialize()
{
// Commands.ChatCommands.Add(new Command( TestCommand,"test"));
Config.Read();
AppDomain.CurrentDomain.AssemblyResolve += this.CurrentDomain_AssemblyResolve;
On.OTAPI.Hooks.MessageBuffer.InvokeGetData += this.MessageBuffer_InvokeGetData;
Expand Down Expand Up @@ -127,7 +130,7 @@ await WebSocket.ConnectAsync(new Uri("ws://api.terraria.ink:22334/bot/" + Config
await Task.Delay(5000);
}
});
},TokenSource.Token);
this.HeartBeat = Task.Run(async () =>
{
while (true)
Expand All @@ -149,9 +152,26 @@ await WebSocket.ConnectAsync(new Uri("ws://api.terraria.ink:22334/bot/" + Config
TShock.Log.ConsoleInfo("[CaiBot]心跳包发送失败!");
}
}
});
},TokenSource.Token);
EconomicSupport.Init();
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
AppDomain.CurrentDomain.AssemblyResolve -= this.CurrentDomain_AssemblyResolve;
On.OTAPI.Hooks.MessageBuffer.InvokeGetData -= this.MessageBuffer_InvokeGetData;
ServerApi.Hooks.NetGetData.Deregister(this, Login.OnGetData);
ServerApi.Hooks.GamePostInitialize.Deregister(this, this.GenCode);
if (!WebSocketTask.IsCompleted)
{
TokenSource.Cancel();
TokenSource.Dispose();
}
}
base.Dispose(disposing);
}

private void GenCode(EventArgs args)
{
if (!string.IsNullOrEmpty(Config.config.Token))
Expand Down Expand Up @@ -198,16 +218,5 @@ private bool MessageBuffer_InvokeGetData(On.OTAPI.Hooks.MessageBuffer.orig_Invok
return orig(instance, ref packetId, ref readOffset, ref start, ref length, ref messageType, maxPackets);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
AppDomain.CurrentDomain.AssemblyResolve -= this.CurrentDomain_AssemblyResolve;
On.OTAPI.Hooks.MessageBuffer.InvokeGetData -= this.MessageBuffer_InvokeGetData;
ServerApi.Hooks.NetGetData.Deregister(this, Login.OnGetData);
ServerApi.Hooks.GamePostInitialize.Deregister(this, this.GenCode);
}

base.Dispose(disposing);
}

}
1 change: 1 addition & 0 deletions src/CaiBot/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
## 更新日志

```
v2024.10.4.1 查背包支持Economic数据查询
v2024.10.4.0 查背包支持更多数据
v2024.9.17.1 修复查背包模糊搜索名字显示不完整
v2024.9.16.1 远程指令日志记录执行群和执行者
Expand Down

0 comments on commit 9360032

Please sign in to comment.