add: MessageBus
This commit is contained in:
@@ -6,15 +6,12 @@ namespace Polonium.Agents;
|
|||||||
|
|
||||||
public abstract partial class Agent : Node
|
public abstract partial class Agent : Node
|
||||||
{
|
{
|
||||||
[Signal]
|
public Knowledge Knowledge { get; set; }
|
||||||
public delegate void ActionExecutedEventHandler(SignalHeader header, ActionBody actionBody);
|
|
||||||
protected Knowledge Knowledge { get; set; }
|
|
||||||
public ActionSet ActionSet { get; set; }
|
public ActionSet ActionSet { get; set; }
|
||||||
|
|
||||||
public virtual void __Ready()
|
public virtual void __Ready()
|
||||||
{
|
{
|
||||||
Knowledge = GetNode<Knowledge>("Knowledge");
|
|
||||||
ActionSet = GetNode<ActionSet>("ActionSet");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed override void _Ready()
|
public sealed override void _Ready()
|
||||||
@@ -25,21 +22,16 @@ public abstract partial class Agent : Node
|
|||||||
base._Ready();
|
base._Ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateKnowledge(KnowledgePatch update) => update.Patch(Knowledge);
|
|
||||||
|
|
||||||
public virtual void ExecuteAction(ActionBody actionBody)
|
|
||||||
{
|
|
||||||
SignalHeader header = PoloniumRegistry.Instance.PoloniumFactory.CreateSignalHeader();
|
|
||||||
header.SetSender(this);
|
|
||||||
EmitSignalActionExecuted(header, actionBody);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Act<TAction>(AgentAction.Parameter parameter)
|
public void Act<TAction>(AgentAction.Parameter parameter)
|
||||||
where TAction : AgentAction
|
where TAction : AgentAction
|
||||||
{
|
{
|
||||||
AgentAction.Template template = ActionSet.Templates
|
AgentAction.Template template = ActionSet.Templates
|
||||||
.FirstOrDefault(t => t.ActionName == PoloniumRegistry.Action<TAction>.Name);
|
.FirstOrDefault(t => t.ActionName == PoloniumRegistry.Action<TAction>.Name);
|
||||||
|
if(template is null)
|
||||||
|
return;
|
||||||
|
AgentAction act = template.Get;
|
||||||
|
act.SetParameter(parameter);
|
||||||
|
act.Execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,22 @@
|
|||||||
using Godot;
|
using Godot;
|
||||||
|
using Polonium.Interfaces;
|
||||||
|
using Polonium.MessageManager;
|
||||||
using Polonium.Resources;
|
using Polonium.Resources;
|
||||||
|
|
||||||
namespace Polonium.Agents;
|
namespace Polonium.Agents;
|
||||||
|
|
||||||
public abstract partial class Knowledge : Node
|
public abstract partial class Knowledge : Node, IMessageClient
|
||||||
{
|
{
|
||||||
[Signal]
|
|
||||||
public delegate void KnowledgeUpdatedEventHandler(KnowledgePatch update);
|
|
||||||
public abstract void UpdateKnowledge(KnowledgePatch update);
|
public abstract void UpdateKnowledge(KnowledgePatch update);
|
||||||
|
|
||||||
|
public string PostCode { get; set; }
|
||||||
|
public virtual void ReceiveMessage(PoloniumMessage msg)
|
||||||
|
{
|
||||||
|
if(msg is KnowledgePatch update)
|
||||||
|
UpdateKnowledge(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event IMessageClient.MessageSentEventHandler MessageSent;
|
||||||
|
public void SendMessage(PoloniumMessage msg) => MessageSent?.Invoke(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
src/Agents/KnowledgeRender.cs
Normal file
22
src/Agents/KnowledgeRender.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using Godot;
|
||||||
|
using Polonium.Interfaces;
|
||||||
|
using Polonium.MessageManager;
|
||||||
|
using Polonium.Resources;
|
||||||
|
|
||||||
|
namespace Polonium.Agents;
|
||||||
|
|
||||||
|
public abstract partial class KnowledgeRender : Node, IMessageClient
|
||||||
|
{
|
||||||
|
public abstract void RenderKnowledgePatch(KnowledgePatch update);
|
||||||
|
public string PostCode { get; set; }
|
||||||
|
public virtual void ReceiveMessage(PoloniumMessage msg)
|
||||||
|
{
|
||||||
|
if(msg is KnowledgePatch p)
|
||||||
|
RenderKnowledgePatch(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event IMessageClient.MessageSentEventHandler MessageSent;
|
||||||
|
public void SendMessage(PoloniumMessage msg) => MessageSent?.Invoke(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +1,27 @@
|
|||||||
using Godot;
|
using Polonium.MessageManager;
|
||||||
using Polonium.Resources;
|
|
||||||
|
|
||||||
namespace Polonium.Agents;
|
namespace Polonium.Agents;
|
||||||
|
|
||||||
public abstract partial class World : Node
|
public abstract partial class World : MessageBus
|
||||||
{
|
{
|
||||||
protected WorldModel Model { get; set; }
|
protected WorldModel Model { get; set; }
|
||||||
public HashSet<Agent> Agents { get; } = new();
|
|
||||||
public Knowledge CommonKnowledge { get; set; }
|
public Knowledge CommonKnowledge { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
Model = GetNode<WorldModel>("WorldModel");
|
Model = GetNode<WorldModel>("WorldModel");
|
||||||
|
Model.WorldKnowledge.PostCode = "WorldKnowledge";
|
||||||
|
Register(Model.WorldKnowledge);
|
||||||
CommonKnowledge = GetNode<Knowledge>("CommonKnowledge");
|
CommonKnowledge = GetNode<Knowledge>("CommonKnowledge");
|
||||||
Model.CommonKnowledgeUpdated += CommonKnowledgeUpdated;
|
CommonKnowledge.PostCode = "CommonKnowledge";
|
||||||
Model.PrivateKnowledgeUpdated += ForwardPrivateKnowledgeUpdated;
|
Register(CommonKnowledge);
|
||||||
base._Ready();
|
base._Ready();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterAgent(Agent agent)
|
public void Register(Agent agent)
|
||||||
{
|
{
|
||||||
Agents.Add(agent);
|
Register(agent.Knowledge);
|
||||||
agent.ActionExecuted += Model.ActionExecuted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Enter()
|
public virtual void Enter()
|
||||||
@@ -34,12 +34,4 @@ public abstract partial class World : Node
|
|||||||
PoloniumRegistry.Instance.CurrentWorld = null;
|
PoloniumRegistry.Instance.CurrentWorld = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void CommonKnowledgeUpdated(KnowledgePatch update) => update.Patch(CommonKnowledge);
|
|
||||||
|
|
||||||
public void ForwardPrivateKnowledgeUpdated(SignalHeader header, KnowledgePatch update)
|
|
||||||
{
|
|
||||||
foreach (Agent receiver in header.ResolveReceivers())
|
|
||||||
receiver.UpdateKnowledge(update);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -5,18 +5,13 @@ namespace Polonium.Agents;
|
|||||||
|
|
||||||
public abstract partial class WorldModel : Node
|
public abstract partial class WorldModel : Node
|
||||||
{
|
{
|
||||||
|
public Knowledge WorldKnowledge { get; set; }
|
||||||
[Signal]
|
|
||||||
public delegate void CommonKnowledgeUpdatedEventHandler(KnowledgePatch update);
|
|
||||||
[Signal]
|
|
||||||
public delegate void PrivateKnowledgeUpdatedEventHandler(SignalHeader header, KnowledgePatch update);
|
|
||||||
|
|
||||||
protected Knowledge WorldKnowledge { get; set; }
|
|
||||||
|
|
||||||
public override void _Ready()
|
public override void _Ready()
|
||||||
{
|
{
|
||||||
WorldKnowledge = GetNode<Knowledge>("WorldKnowledge");
|
WorldKnowledge = GetNode<Knowledge>("WorldKnowledge");
|
||||||
base._Ready();
|
base._Ready();
|
||||||
}
|
}
|
||||||
public abstract void ActionExecuted(SignalHeader header, ActionBody actionBody);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
42
src/DataStructures/EventDictionary.cs
Normal file
42
src/DataStructures/EventDictionary.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
namespace Polonium.DataStructures;
|
||||||
|
|
||||||
|
public class EventDictionary<TKey, TValue> : Dictionary<TKey, TValue>
|
||||||
|
{
|
||||||
|
public new TValue this[TKey a]
|
||||||
|
{
|
||||||
|
get => base[a];
|
||||||
|
set
|
||||||
|
{
|
||||||
|
base[a] = value;
|
||||||
|
Edited?.Invoke(a, value);
|
||||||
|
Updated?.Invoke(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Remove(TKey key)
|
||||||
|
{
|
||||||
|
base.Remove(key);
|
||||||
|
Removed?.Invoke(key);
|
||||||
|
Updated?.Invoke(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public new void Clear()
|
||||||
|
{
|
||||||
|
base.Clear();
|
||||||
|
Cleared?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public delegate void EditedEventHandler(TKey key, TValue value);
|
||||||
|
public event EditedEventHandler Edited;
|
||||||
|
|
||||||
|
public delegate void RemovedEventHandler(TKey key);
|
||||||
|
public event RemovedEventHandler Removed;
|
||||||
|
|
||||||
|
public delegate void ClearedEventHandler();
|
||||||
|
public event ClearedEventHandler Cleared;
|
||||||
|
|
||||||
|
public delegate void UpdatedEventHandler(TKey key);
|
||||||
|
public event UpdatedEventHandler Updated;
|
||||||
|
|
||||||
|
}
|
||||||
12
src/Extensions/MessageClientExtension.cs
Normal file
12
src/Extensions/MessageClientExtension.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Polonium.Interfaces;
|
||||||
|
using Polonium.MessageManager;
|
||||||
|
|
||||||
|
namespace Polonium.Extensions;
|
||||||
|
|
||||||
|
public static class MessageClientExtension
|
||||||
|
{
|
||||||
|
public static void SendMessage(this IMessageClient client, PoloniumMessage msg)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/Interfaces/IMessageClient.cs
Normal file
15
src/Interfaces/IMessageClient.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using Godot;
|
||||||
|
using Polonium.MessageManager;
|
||||||
|
|
||||||
|
namespace Polonium.Interfaces;
|
||||||
|
|
||||||
|
public interface IMessageClient
|
||||||
|
{
|
||||||
|
string PostCode { get; set; }
|
||||||
|
void ReceiveMessage(PoloniumMessage msg);
|
||||||
|
|
||||||
|
delegate void MessageSentEventHandler(PoloniumMessage msg);
|
||||||
|
event MessageSentEventHandler MessageSent;
|
||||||
|
|
||||||
|
public void SendMessage(PoloniumMessage msg);
|
||||||
|
}
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
|
using Polonium.MessageManager;
|
||||||
using Polonium.Resources;
|
using Polonium.Resources;
|
||||||
|
|
||||||
namespace Polonium.Interfaces;
|
namespace Polonium.Interfaces;
|
||||||
|
|
||||||
public interface IPoloniumFactory
|
public interface IPoloniumFactory
|
||||||
{
|
{
|
||||||
public SignalHeader CreateSignalHeader();
|
public MessageHeader CreateMessageHeader();
|
||||||
}
|
}
|
||||||
61
src/MessageManager/MessageBus.cs
Normal file
61
src/MessageManager/MessageBus.cs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
using Godot;
|
||||||
|
using Polonium.Interfaces;
|
||||||
|
|
||||||
|
namespace Polonium.MessageManager;
|
||||||
|
|
||||||
|
public abstract partial class MessageBus : Node
|
||||||
|
{
|
||||||
|
public Dictionary<string, HashSet<IMessageClient>> Clients { get; } = new();
|
||||||
|
|
||||||
|
public abstract string NewPostCode();
|
||||||
|
|
||||||
|
public void Register(IMessageClient client)
|
||||||
|
{
|
||||||
|
if(!Clients.ContainsKey(client.PostCode))
|
||||||
|
Clients[client.PostCode] = new HashSet<IMessageClient>();
|
||||||
|
Clients[client.PostCode].Add(client);
|
||||||
|
client.MessageSent += Collect;
|
||||||
|
}
|
||||||
|
public Queue<PoloniumMessage> Messages { get; } = new();
|
||||||
|
public Queue<PoloniumMessage> DeadMessages { get; } = new();
|
||||||
|
public void Collect(PoloniumMessage message) => Messages.Enqueue(message);
|
||||||
|
|
||||||
|
public override void _Ready()
|
||||||
|
{
|
||||||
|
PoloniumRegistry.Instance.MessageBus = this;
|
||||||
|
base._Ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void _Process(double delta)
|
||||||
|
{
|
||||||
|
if(DeadMessages.Count > 0)
|
||||||
|
Messages.Enqueue(DeadMessages.Dequeue());
|
||||||
|
if (Messages.Count == 0)
|
||||||
|
return;
|
||||||
|
PoloniumMessage msg = Messages.Dequeue();
|
||||||
|
HashSet<string> errored = new();
|
||||||
|
foreach (string postcode in msg.Header.Receivers)
|
||||||
|
{
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach(IMessageClient client in Clients[postcode])
|
||||||
|
client.ReceiveMessage(msg);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
errored.Add(postcode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (errored.Count > 0)
|
||||||
|
{
|
||||||
|
msg.Header.Retried++;
|
||||||
|
if(msg.Header.Retried <= msg.Header.MaxRetries)
|
||||||
|
{
|
||||||
|
msg.Header.Receivers = errored;
|
||||||
|
DeadMessages.Enqueue(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
12
src/MessageManager/MessageHeader.cs
Normal file
12
src/MessageManager/MessageHeader.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Polonium.MessageManager;
|
||||||
|
|
||||||
|
public abstract partial class MessageHeader : Resource
|
||||||
|
{
|
||||||
|
public HashSet<string> Receivers { get; set; }
|
||||||
|
public string Sender { get; set; }
|
||||||
|
|
||||||
|
public int Retried { get; set; } = 0;
|
||||||
|
public int MaxRetries { get; set; } = 0;
|
||||||
|
}
|
||||||
8
src/MessageManager/PoloniumMessage.cs
Normal file
8
src/MessageManager/PoloniumMessage.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
using Godot;
|
||||||
|
|
||||||
|
namespace Polonium.MessageManager;
|
||||||
|
|
||||||
|
public abstract partial class PoloniumMessage : Resource
|
||||||
|
{
|
||||||
|
public MessageHeader Header { get; set; }
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using Godot;
|
|||||||
using Polonium.Agents;
|
using Polonium.Agents;
|
||||||
using Polonium.Attributes;
|
using Polonium.Attributes;
|
||||||
using Polonium.Interfaces;
|
using Polonium.Interfaces;
|
||||||
|
using Polonium.MessageManager;
|
||||||
using Polonium.Resources;
|
using Polonium.Resources;
|
||||||
|
|
||||||
namespace Polonium;
|
namespace Polonium;
|
||||||
@@ -19,6 +20,8 @@ public class PoloniumRegistry
|
|||||||
|
|
||||||
[RegistryPassThrough]
|
[RegistryPassThrough]
|
||||||
public IPoloniumFactory PoloniumFactory { get; set; }
|
public IPoloniumFactory PoloniumFactory { get; set; }
|
||||||
|
[RegistryPassThrough]
|
||||||
|
public MessageBus MessageBus { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public static void Prepare()
|
public static void Prepare()
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
using Godot;
|
using Polonium.MessageManager;
|
||||||
using Polonium.Agents;
|
|
||||||
|
|
||||||
namespace Polonium.Resources;
|
namespace Polonium.Resources;
|
||||||
|
|
||||||
public abstract partial class KnowledgePatch : Resource
|
public abstract partial class KnowledgePatch : PoloniumMessage
|
||||||
{
|
{
|
||||||
public SignalHeader Header { get; set; }
|
|
||||||
public abstract void Patch(Knowledge knowledge);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using Godot;
|
|
||||||
using Polonium.Agents;
|
|
||||||
|
|
||||||
namespace Polonium.Resources;
|
|
||||||
|
|
||||||
public abstract partial class SignalHeader : Resource
|
|
||||||
{
|
|
||||||
|
|
||||||
public abstract IEnumerable<Agent> ResolveReceivers();
|
|
||||||
public abstract Agent ResolveSender();
|
|
||||||
|
|
||||||
public abstract void SetSender(Agent agent);
|
|
||||||
public abstract void AddReceiver(Agent agent);
|
|
||||||
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user