Skip to content

Commit

Permalink
Refactor social events to allow deferred dispatch
Browse files Browse the repository at this point in the history
  • Loading branch information
ShiJbey committed Sep 24, 2024
1 parent 380178f commit bed5983
Show file tree
Hide file tree
Showing 11 changed files with 209 additions and 16 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.

The format is based on <https://common-changelog.org/>, and this project adheres mostly to Semantic Versioning. However, all releases before 1.0.0 have breaking changes between minor-version updates.

## [2.2.0] - 2024-09-24

### Added

- `SocialEventInstance` class that pairs a `SocialEventDef` instance with a set of parameters, allowing for deferred execution outside of `SocialEngine.DispatchEvent(...)`.
- Additional `SocialEngine.DispatchEvent(SocialEventInstance)` method overload.

### Changed

- `SocialEvent` class has been renamed `SocialEventType` to communicate its role as definition data

## [2.1.0] - 2024-07-06

### Added
Expand Down Expand Up @@ -71,3 +82,4 @@ _Initial release._
[1.1.0]: https://github.com/ShiJbey/TDRS/releases/tag/v1.1.0
[2.0.0]: https://github.com/ShiJbey/TDRS/releases/tag/v2.0.0
[2.1.0]: https://github.com/ShiJbey/TDRS/releases/tag/v2.1.0
[2.2.0]: https://github.com/ShiJbey/TDRS/releases/tag/v2.2.0
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ public SerializedSocialEvent()

#region Public Methods

public SocialEvent ToRuntimeInstance()
public SocialEventType ToRuntimeInstance()
{
return new SocialEvent(
return new SocialEventType(
name: name,
roles: roles,
description: description,
Expand Down
29 changes: 29 additions & 0 deletions Packages/com.shijbey.tdrs/Runtime/SocialEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,21 @@ public void Tick()
}
}

/// <summary>
/// Create a new SocialEventInstance
/// </summary>
/// <param name="eventName"></param>
/// <param name="agents"></param>
/// <returns></returns>
public SocialEventInstance InstantiateSocialEvent(string eventName, params string[] agents)
{
SocialEventType eventType = SocialEventLibrary.GetSocialEvent($"{eventName}/{agents.Length}");

var instance = new SocialEventInstance(this, eventType, agents);

return instance;
}

/// <summary>
/// Dispatch an event throughout the social network and apply effects
/// </summary>
Expand Down Expand Up @@ -520,6 +535,20 @@ public void DispatchEvent(string eventName, params string[] agents)
OnSocialEvent?.Invoke(this, new OnSocialEventArgs(eventName, ctx.Description, bindings));
}

public void DispatchEvent(SocialEventInstance eventInstance)
{
eventInstance.Execute();

OnSocialEvent?.Invoke(
this,
new OnSocialEventArgs(
eventInstance.EventType.Name,
eventInstance.Description,
eventInstance.Bindings
)
);
}

/// <summary>
/// Reevaluate all relationships against the available social rules.
/// </summary>
Expand Down
114 changes: 114 additions & 0 deletions Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using System.Linq;
using RePraxis;

namespace TDRS
{
/// <summary>
/// SocialEventDef data paired with parameters for deferred execution.
/// </summary>
public class SocialEventInstance
{
#region Fields

private SocialEngine m_engine;
private SocialEventType m_eventType;
private EffectContext m_baseContext;

#endregion

#region Properties

public SocialEngine Engine => m_engine;
public SocialEventType EventType => m_eventType;
public string Description => m_baseContext.Description;
public Dictionary<string, object> Bindings => m_baseContext.Bindings;

#endregion

#region Constructors

public SocialEventInstance(
SocialEngine engine,
SocialEventType eventType,
params string[] agents
)
{
m_engine = engine;
m_eventType = eventType;

var bindings = new Dictionary<string, object>();
for (int i = 0; i < eventType.Roles.Length; i++)
{
string role = eventType.Roles[i];
string agentID = agents[i];
bindings[role] = agentID;
}

// Create the base context for the events
m_baseContext = new EffectContext(engine, eventType.Description, bindings);
}

#endregion

#region Public Methods

/// <summary>
/// Execute the effects of this event and dispatch a C# event.
/// </summary>
public void Dispatch()
{
m_engine.DispatchEvent(this);
}

/// <summary>
/// Execute the effects of the event on the social engine.
/// </summary>
public void Execute()
{
foreach (var response in m_eventType.Responses)
{
var results = new DBQuery(response.Preconditions)
.Run(m_baseContext.Engine.DB, m_baseContext.Bindings);

// Skip this response because the query failed
if (!results.Success) continue;

// Create a new context for each binding result
foreach (var bindingSet in results.Bindings)
{
var scopedCtx = m_baseContext.WithBindings(bindingSet);

if (response.Description != "")
{
scopedCtx.DescriptionTemplate = response.Description;
}

try
{
var effects = response.Effects
.Select(effectString =>
{
return m_engine.EffectLibrary.CreateInstance(scopedCtx, effectString);
});

foreach (var effect in effects)
{
effect.Apply();
}
}
catch (ArgumentException ex)
{
throw new ArgumentException(
$"Error encountered while instantiating effects for '{m_eventType.Name}' event: "
+ ex.Message
);
}
}
}
}

#endregion
}
}
11 changes: 11 additions & 0 deletions Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions Packages/com.shijbey.tdrs/Runtime/SocialEventLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ public class SocialEventLibrary
/// <summary>
/// Event definitions sorted by name and cardinality.
/// </summary>
protected Dictionary<string, SocialEvent> m_events;
protected Dictionary<string, SocialEventType> m_events;

#endregion

public Dictionary<string, SocialEvent> Events => m_events;
public Dictionary<string, SocialEventType> Events => m_events;

#region Constructors

public SocialEventLibrary()
{
m_events = new Dictionary<string, SocialEvent>();
m_events = new Dictionary<string, SocialEventType>();
}

#endregion
Expand All @@ -33,7 +33,7 @@ public SocialEventLibrary()
/// Add a social event to the library.
/// </summary>
/// <param name="socialEvent"></param>
public void AddSocialEvent(SocialEvent socialEvent)
public void AddSocialEvent(SocialEventType socialEvent)
{
m_events[socialEvent.Symbol] = socialEvent;
}
Expand All @@ -43,7 +43,7 @@ public void AddSocialEvent(SocialEvent socialEvent)
/// </summary>
/// <param name="symbol"></param>
/// <returns></returns>
public SocialEvent GetSocialEvent(string symbol)
public SocialEventType GetSocialEvent(string symbol)
{
return m_events[symbol];
}
Expand Down
4 changes: 2 additions & 2 deletions Packages/com.shijbey.tdrs/Runtime/SocialEventSO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public class SocialEventSO : ScriptableObject
[SerializeField]
private TriggerRuleData[] m_triggerRules;

public SocialEvent GetSocialEvent()
public SocialEventType GetSocialEvent()
{
if (m_eventName == "")
{
Expand Down Expand Up @@ -65,7 +65,7 @@ public SocialEvent GetSocialEvent()
};
}

var socialEvent = new SocialEvent(
var socialEvent = new SocialEventType(
name,
m_roles,
m_description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ namespace TDRS
/// <summary>
/// Definition information for creating SocialEvent instances
/// </summary>
public class SocialEvent
public class SocialEventType
{
#region Fields

Expand All @@ -31,7 +31,7 @@ public class SocialEvent

#region Constructors

public SocialEvent(
public SocialEventType(
string name,
string[] roles,
string description,
Expand Down
8 changes: 4 additions & 4 deletions Packages/com.shijbey.tdrs/Runtime/SocialEventYamlLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ public class SocialEventYamlLoader
/// </summary>
/// <param name="yamlString"></param>
/// <returns></returns>
public SocialEvent LoadSocialEvent(string yamlString)
public SocialEventType LoadSocialEvent(string yamlString)
{
var deserializer = new DeserializerBuilder().Build();

SocialEvent socialEvent = deserializer
SocialEventType socialEvent = deserializer
.Deserialize<SerializedSocialEvent>(yamlString)
.ToRuntimeInstance();

Expand All @@ -31,11 +31,11 @@ public SocialEvent LoadSocialEvent(string yamlString)
/// </summary>
/// <param name="yamlString"></param>
/// <returns></returns>
public List<SocialEvent> LoadSocialEvents(string yamlString)
public List<SocialEventType> LoadSocialEvents(string yamlString)
{
var deserializer = new DeserializerBuilder().Build();

List<SocialEvent> socialEvent = deserializer
List<SocialEventType> socialEvent = deserializer
.Deserialize<List<SerializedSocialEvent>>(yamlString)
.Select(e => { return e.ToRuntimeInstance(); })
.ToList();
Expand Down
29 changes: 28 additions & 1 deletion Packages/com.shijbey.tdrs/Tests/Editor/TestSocialEngine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public void SetUp()
);

_engine.SocialEventLibrary.AddSocialEvent(
new SocialEvent(
new SocialEventType(
name: "compliment",
roles: new string[]
{
Expand Down Expand Up @@ -305,6 +305,33 @@ public void TestDispatchEvent()
Assert.That(lisa.Traits.HasTrait("recently-complimented"), Is.False);
}

/// <summary>
/// Test that you can create social event instances and dispatch them.
/// </summary>
[Test]
public void TestCreateAndDispatchSocialEvent()
{
var jose = _engine.AddAgent("agent", "jose");
var lisa = _engine.AddAgent("agent", "lisa");
var sara = _engine.AddAgent("agent", "sara");

Assert.That(lisa.Traits.HasTrait("recently-complimented"), Is.False);

SocialEventInstance complimentEventInstance =
_engine.InstantiateSocialEvent("compliment", "jose", "lisa");

complimentEventInstance.Dispatch();

Assert.That(lisa.Traits.HasTrait("recently-complimented"), Is.True);

_engine.Tick();
_engine.Tick();
_engine.Tick();
_engine.Tick();

Assert.That(lisa.Traits.HasTrait("recently-complimented"), Is.False);
}

/// <summary>
/// Ensure all agents and relationships are removed from the state.
/// </summary>
Expand Down

0 comments on commit bed5983

Please # to comment.