diff --git a/CHANGELOG.md b/CHANGELOG.md index 983d7fb..93fc90c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file. The format is based on , 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 @@ -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 diff --git a/Packages/com.shijbey.tdrs/Runtime/Serialization/SerializedSocialEvent.cs b/Packages/com.shijbey.tdrs/Runtime/Serialization/SerializedSocialEvent.cs index 7f4fb23..600f958 100644 --- a/Packages/com.shijbey.tdrs/Runtime/Serialization/SerializedSocialEvent.cs +++ b/Packages/com.shijbey.tdrs/Runtime/Serialization/SerializedSocialEvent.cs @@ -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, diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEngine.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEngine.cs index 4a74d61..43cae04 100644 --- a/Packages/com.shijbey.tdrs/Runtime/SocialEngine.cs +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEngine.cs @@ -455,6 +455,21 @@ public void Tick() } } + /// + /// Create a new SocialEventInstance + /// + /// + /// + /// + public SocialEventInstance InstantiateSocialEvent(string eventName, params string[] agents) + { + SocialEventType eventType = SocialEventLibrary.GetSocialEvent($"{eventName}/{agents.Length}"); + + var instance = new SocialEventInstance(this, eventType, agents); + + return instance; + } + /// /// Dispatch an event throughout the social network and apply effects /// @@ -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 + ) + ); + } + /// /// Reevaluate all relationships against the available social rules. /// diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs new file mode 100644 index 0000000..49c22f4 --- /dev/null +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using RePraxis; + +namespace TDRS +{ + /// + /// SocialEventDef data paired with parameters for deferred execution. + /// + 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 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(); + 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 + + /// + /// Execute the effects of this event and dispatch a C# event. + /// + public void Dispatch() + { + m_engine.DispatchEvent(this); + } + + /// + /// Execute the effects of the event on the social engine. + /// + 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 + } +} diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs.meta b/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs.meta new file mode 100644 index 0000000..5f71cfc --- /dev/null +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventInstance.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f34dc02abe5349fb98c22c41c35a19c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEventLibrary.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEventLibrary.cs index aa8c27c..130c8ba 100644 --- a/Packages/com.shijbey.tdrs/Runtime/SocialEventLibrary.cs +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventLibrary.cs @@ -12,17 +12,17 @@ public class SocialEventLibrary /// /// Event definitions sorted by name and cardinality. /// - protected Dictionary m_events; + protected Dictionary m_events; #endregion - public Dictionary Events => m_events; + public Dictionary Events => m_events; #region Constructors public SocialEventLibrary() { - m_events = new Dictionary(); + m_events = new Dictionary(); } #endregion @@ -33,7 +33,7 @@ public SocialEventLibrary() /// Add a social event to the library. /// /// - public void AddSocialEvent(SocialEvent socialEvent) + public void AddSocialEvent(SocialEventType socialEvent) { m_events[socialEvent.Symbol] = socialEvent; } @@ -43,7 +43,7 @@ public void AddSocialEvent(SocialEvent socialEvent) /// /// /// - public SocialEvent GetSocialEvent(string symbol) + public SocialEventType GetSocialEvent(string symbol) { return m_events[symbol]; } diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEventSO.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEventSO.cs index 217d01f..9023b70 100644 --- a/Packages/com.shijbey.tdrs/Runtime/SocialEventSO.cs +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventSO.cs @@ -25,7 +25,7 @@ public class SocialEventSO : ScriptableObject [SerializeField] private TriggerRuleData[] m_triggerRules; - public SocialEvent GetSocialEvent() + public SocialEventType GetSocialEvent() { if (m_eventName == "") { @@ -65,7 +65,7 @@ public SocialEvent GetSocialEvent() }; } - var socialEvent = new SocialEvent( + var socialEvent = new SocialEventType( name, m_roles, m_description, diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEvent.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEventType.cs similarity index 95% rename from Packages/com.shijbey.tdrs/Runtime/SocialEvent.cs rename to Packages/com.shijbey.tdrs/Runtime/SocialEventType.cs index 6cb28b4..79f1abd 100644 --- a/Packages/com.shijbey.tdrs/Runtime/SocialEvent.cs +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventType.cs @@ -5,7 +5,7 @@ namespace TDRS /// /// Definition information for creating SocialEvent instances /// - public class SocialEvent + public class SocialEventType { #region Fields @@ -31,7 +31,7 @@ public class SocialEvent #region Constructors - public SocialEvent( + public SocialEventType( string name, string[] roles, string description, diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEvent.cs.meta b/Packages/com.shijbey.tdrs/Runtime/SocialEventType.cs.meta similarity index 100% rename from Packages/com.shijbey.tdrs/Runtime/SocialEvent.cs.meta rename to Packages/com.shijbey.tdrs/Runtime/SocialEventType.cs.meta diff --git a/Packages/com.shijbey.tdrs/Runtime/SocialEventYamlLoader.cs b/Packages/com.shijbey.tdrs/Runtime/SocialEventYamlLoader.cs index 81f9975..5d01d1a 100644 --- a/Packages/com.shijbey.tdrs/Runtime/SocialEventYamlLoader.cs +++ b/Packages/com.shijbey.tdrs/Runtime/SocialEventYamlLoader.cs @@ -15,11 +15,11 @@ public class SocialEventYamlLoader /// /// /// - public SocialEvent LoadSocialEvent(string yamlString) + public SocialEventType LoadSocialEvent(string yamlString) { var deserializer = new DeserializerBuilder().Build(); - SocialEvent socialEvent = deserializer + SocialEventType socialEvent = deserializer .Deserialize(yamlString) .ToRuntimeInstance(); @@ -31,11 +31,11 @@ public SocialEvent LoadSocialEvent(string yamlString) /// /// /// - public List LoadSocialEvents(string yamlString) + public List LoadSocialEvents(string yamlString) { var deserializer = new DeserializerBuilder().Build(); - List socialEvent = deserializer + List socialEvent = deserializer .Deserialize>(yamlString) .Select(e => { return e.ToRuntimeInstance(); }) .ToList(); diff --git a/Packages/com.shijbey.tdrs/Tests/Editor/TestSocialEngine.cs b/Packages/com.shijbey.tdrs/Tests/Editor/TestSocialEngine.cs index 4ebec84..3fd1c09 100644 --- a/Packages/com.shijbey.tdrs/Tests/Editor/TestSocialEngine.cs +++ b/Packages/com.shijbey.tdrs/Tests/Editor/TestSocialEngine.cs @@ -121,7 +121,7 @@ public void SetUp() ); _engine.SocialEventLibrary.AddSocialEvent( - new SocialEvent( + new SocialEventType( name: "compliment", roles: new string[] { @@ -305,6 +305,33 @@ public void TestDispatchEvent() Assert.That(lisa.Traits.HasTrait("recently-complimented"), Is.False); } + /// + /// Test that you can create social event instances and dispatch them. + /// + [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); + } + /// /// Ensure all agents and relationships are removed from the state. ///