Skip to content

Commit

Permalink
ipc: add custom serializer for IGameObject
Browse files Browse the repository at this point in the history
fixes #1924
  • Loading branch information
goaaats committed Jul 18, 2024
1 parent 40624c0 commit 604d1b2
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 4 deletions.
44 changes: 42 additions & 2 deletions Dalamud/Interface/Internal/Windows/Data/Widgets/PluginIpcWidget.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using Dalamud.Plugin.Ipc;
using Dalamud.Game.ClientState;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Ipc;
using Dalamud.Plugin.Ipc.Internal;
using Dalamud.Utility;
using ImGuiNET;
Expand All @@ -14,6 +17,11 @@ internal class PluginIpcWidget : IDataWindowWidget
// IPC
private ICallGateProvider<string, string>? ipcPub;
private ICallGateSubscriber<string, string>? ipcSub;

// IPC
private ICallGateProvider<ICharacter?, string>? ipcPubGo;
private ICallGateSubscriber<ICharacter?, string>? ipcSubGo;

private string callGateResponse = string.Empty;

/// <inheritdoc/>
Expand Down Expand Up @@ -64,6 +72,28 @@ public void Draw()
this.ipcSub.Subscribe(_ => throw new Exception("PONG3"));
}

if (this.ipcPubGo == null)
{
this.ipcPubGo = new CallGatePubSub<ICharacter?, string>("dataDemo2");

this.ipcPubGo.RegisterAction(go =>
{
Log.Information("Data action was called: {Name}", go?.Name);
});

this.ipcPubGo.RegisterFunc(go =>
{
Log.Information("Data func was called: {Name}", go?.Name);
return "test";
});
}

if (this.ipcSubGo == null)
{
this.ipcSubGo = new CallGatePubSub<ICharacter?, string>("dataDemo2");
this.ipcSubGo.Subscribe(go => { Log.Information("GO: {Name}", go.Name); });
}

if (ImGui.Button("PING"))
{
this.ipcPub.SendMessage("PING");
Expand All @@ -78,7 +108,17 @@ public void Draw()
{
this.callGateResponse = this.ipcSub.InvokeFunc("button2");
}


if (ImGui.Button("Action GO"))
{
this.ipcSubGo.InvokeAction(Service<ClientState>.Get().LocalPlayer);
}

if (ImGui.Button("Func GO"))
{
this.callGateResponse = this.ipcSubGo.InvokeFunc(Service<ClientState>.Get().LocalPlayer);
}

if (!this.callGateResponse.IsNullOrEmpty())
ImGui.Text($"Response: {this.callGateResponse}");
}
Expand Down
9 changes: 7 additions & 2 deletions Dalamud/Plugin/Ipc/Internal/CallGateChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Reflection;

using Dalamud.Plugin.Ipc.Exceptions;
using Dalamud.Plugin.Ipc.Internal.Converters;

using Newtonsoft.Json;
using Serilog;

Expand Down Expand Up @@ -206,7 +208,10 @@ private IEnumerable<Type> GenerateTypes(Type? type)
if (obj is null)
return null;

var json = JsonConvert.SerializeObject(obj);
var settings = new JsonSerializerSettings();
settings.Converters.Add(new GameObjectConverter());

var json = JsonConvert.SerializeObject(obj, settings);

try
{
Expand Down Expand Up @@ -241,7 +246,7 @@ private IEnumerable<Type> GenerateTypes(Type? type)

try
{
return JsonConvert.DeserializeObject(json, type);
return JsonConvert.DeserializeObject(json, type, settings);
}
catch (Exception ex)
{
Expand Down
49 changes: 49 additions & 0 deletions Dalamud/Plugin/Ipc/Internal/Converters/GameObjectConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using System.IO;

using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Utility;

using Newtonsoft.Json;

namespace Dalamud.Plugin.Ipc.Internal.Converters;

/// <summary>
/// JSON converter for IGameObject and its derived types.
/// </summary>
internal sealed class GameObjectConverter : JsonConverter<IGameObject>
{
/// <inheritdoc/>
public override void WriteJson(JsonWriter writer, IGameObject? value, JsonSerializer serializer) =>
writer.WriteValue(value?.Address.ToString());

/// <inheritdoc/>
public override IGameObject? ReadJson(
JsonReader reader,
Type objectType,
IGameObject? existingValue,
bool hasExistingValue,
JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;

if (reader.TokenType != JsonToken.String)
throw new InvalidDataException("String is expected.");

if (!nint.TryParse(reader.Value as string, out var v))
throw new InvalidDataException("Could not parse address.");

if (!ThreadSafety.IsMainThread)
throw new InvalidOperationException("Cannot send GameObjects from non-main thread over IPC.");

var ot = Service<ObjectTable>.Get();
foreach (var go in ot)
{
if (go.Address == v)
return go;
}

return ot.CreateObjectReference(v);
}
}

0 comments on commit 604d1b2

Please sign in to comment.