From 346263d31147af15a53e7c510d2853b3bea0cd4d Mon Sep 17 00:00:00 2001 From: Pascal Serrarens Date: Tue, 29 Apr 2025 11:46:57 +0200 Subject: [PATCH] Aligned Thing implementation --- src/Participants/SiteServer.cs | 2 +- src/Thing.cs | 406 ++++++++++++++++---------------- src/Things/DistanceSensor.cs | 4 +- src/Things/TemperatureSensor.cs | 2 +- 4 files changed, 203 insertions(+), 211 deletions(-) diff --git a/src/Participants/SiteServer.cs b/src/Participants/SiteServer.cs index 6dce552..7e830df 100644 --- a/src/Participants/SiteServer.cs +++ b/src/Participants/SiteServer.cs @@ -115,7 +115,7 @@ namespace RoboidControl { } if (thing == null) - thing = new Thing(sender, msg.networkId, msg.thingId, msg.thingType); + thing = new Thing(sender, msg.thingType, msg.thingId); if (msg.parentId != 0) { thing.parent = sender.Get(msg.parentId); diff --git a/src/Thing.cs b/src/Thing.cs index 1a90ebb..56f8ad7 100644 --- a/src/Thing.cs +++ b/src/Thing.cs @@ -10,90 +10,83 @@ namespace RoboidControl { [Serializable] public class Thing { - #region Types - /// /// Predefined thing types /// - public enum Type { - Undetermined, - // Sensor - Switch, - DistanceSensor, - DirectionalSensor, - TemperatureSensor, - TouchSensor, + public static class Type { + public const byte Undetermined = 0x00; + // sensor + public const byte Switch = 0x01; + public const byte DistanceSensor = 0x02; + public const byte DirectionalSensor = 0x03; + public const byte TemperatureSensor = 0x04; + public const byte TouchSensor = 0x05; // Motor - ControlledMotor, - UncontrolledMotor, - Servo, + public const byte ControlledMotor = 0x06; + public const byte UncontrolledMotor = 0x07; + public const byte Servo = 0x08; // Other - Roboid, - Humanoid, - ExternalSensor - }; - - public delegate void ChangeHandler(); - public delegate void SphericalHandler(Spherical v); - public delegate void ThingHandler(Thing t); - - #endregion Types + public const byte Roboid = 0x09; + public const byte HUmanoid = 0x010; + public const byte ExternalSensor = 0x11; + public const byte Animator = 0x40; + } #region Init + /// + /// Create a new thing without communication abilities + /// + /// The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type") + /// Invoke a OnNewThing event when the thing has been created + public Thing(byte thingType = Type.Undetermined, bool invokeEvent = true) : this(ParticipantUDP.Isolated(), thingType, 0, invokeEvent) { + } + /// /// Create a new thing for a participant /// - /// The participant owning the thing - /// The type of thing - public Thing(Participant owner, byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) { + /// The owning participant + /// The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type") + /// The ID of the thing, leave out or set to zero to generate an ID + /// Invoke a OnNewThing event when the thing has been created + public Thing(Participant owner, byte thingType = Type.Undetermined, byte thingId = 0, bool invokeEvent = true) { this.owner = owner; + this.id = thingId; this.type = thingType; if (this.owner != null) this.owner.Add(this); if (invokeEvent) InvokeNewThing(this); } - public Thing(Participant owner) : this(owner, Type.Undetermined) { } - /// - /// Create a new thing for a participant - /// - /// The participant owning the thing - /// The type of thing - public Thing(Participant owner, Type thingType = Type.Undetermined, bool invokeEvent = true) : this(owner, (byte)thingType, invokeEvent) { - } - /// - /// Create a new thing without communication abilities - /// - /// The type of thing - public Thing(byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) : this(ParticipantUDP.Isolated(), thingType, invokeEvent) { - } /// - /// Create a new thing as a child of another thing + /// Create a new child thing /// /// The parent thing - /// The type of thing - public Thing(Thing parent, byte thingType = (byte)Type.Undetermined, bool invokeEvent = true) : this(parent.owner, thingType, invokeEvent) { + /// The type of thing (can use \ref RoboidControl::Thing::Type "Thing.Type") + /// The ID of the thing, leave out or set to zero to generate an ID + /// Invoke a OnNewThing event when the thing has been created + /// The owner will be the same as the owner of the parent thing + public Thing(Thing parent, byte thingType = Type.Undetermined, bool invokeEvent = true) : this(parent.owner, thingType, 0, invokeEvent) { this.parent = parent; } - /// - /// Create a new thing for the given participant - /// - /// The participant owning the thing - /// The network ID of the thing - /// The ID of the thing - /// The type of thing - public Thing(Participant owner, byte networkId, byte thingId, byte thingType = 0) { - this.owner = owner; - this.id = thingId; - this.type = thingType; - this.networkId = networkId; - // Console.Write($"New thing added to {owner}"); - this.owner.Add(this); - InvokeNewThing(this); - } + // /// + // /// Create a new thing for the given participant + // /// + // /// The participant owning the thing + // /// The network ID of the thing + // /// The ID of the thing + // /// The type of thing + // public Thing(Participant owner, byte networkId, byte thingId, byte thingType = 0) { + // this.owner = owner; + // this.id = thingId; + // this.type = thingType; + // this.networkId = networkId; + // // Console.Write($"New thing added to {owner}"); + // this.owner.Add(this); + // InvokeNewThing(this); + // } /// /// Function which can be used to create components in external engines. @@ -108,6 +101,8 @@ namespace RoboidControl { #endregion Init + public bool terminate = false; + #region Properties /// @@ -115,11 +110,6 @@ namespace RoboidControl { /// public Participant owner = null; /// - /// The network ID of this thing. - /// - /// @note This field will likely disappear in future versions - public byte networkId = 0; - /// /// The ID of this thing /// public byte id = 0; @@ -127,105 +117,8 @@ namespace RoboidControl { /// /// The type of this thing. /// - /// This can be either a Thing::Type (needs casting) or a byte value for custom types. - public byte type = (byte)Type.Undetermined; - - private Thing _parent; - /// - /// The parent of this thing - /// - public Thing parent { - get => _parent; - set { - if (_parent == value) - return; - - if (value == null) { - _parent?.RemoveChild(this); - _parent = null; - } - else { - value.AddChild(this); - } - this.hierarchyChanged = true; - } - } - - /// - /// Add a child Thing to this Thing - /// - /// The Thing which should become a child - /// @remark When the Thing is already a child, it will not be added again - public void AddChild(Thing child) { - if (children.Find(thing => thing == child) != null) - return; - - child._parent = this; - children.Add(child); - } - /// - /// Remove the given thing as a child of this thing - /// - /// The child to remove - /// True when the child was present or false when it was not found - public bool RemoveChild(Thing child) { - return children.Remove(child); - } - - /// - /// Get a child by thing Id - /// - /// - /// - /// - Thing GetChild(byte thingId, bool recursively = false) { - foreach (Thing child in this.children) { - if (child == null) - continue; - - if (child.id == thingId) - return child; - if (recursively) { - Thing foundChild = child.GetChild(thingId, recursively); - if (foundChild != null) - return foundChild; - } - } - return null; - } - /// - /// Find a child by name - /// - /// The name of the child thing - /// If true, the name will be searched through descendants recursively - /// The found thing or null when nothing is found - Thing FindChild(string name, bool recursively = true) { - foreach (Thing child in this.children) { - if (child == null) - continue; - - if (child.name == name) - return child; - - if (recursively) { - Thing foundChild = child.FindChild(name, recursively); - if (foundChild != null) - return foundChild; - } - } - return null; - } - - /// - /// Indicator that the hierarchy of the thing has changed - /// - public bool hierarchyChanged = true; - - /// - /// The children of this thing - /// - [NonSerialized] - protected List children = new(); + /// This can be either a \ref RoboidControl::Thing::Type "Thing.Type" or a byte value for custom types. + public byte type = Type.Undetermined; private string _name = ""; /// @@ -252,6 +145,120 @@ namespace RoboidControl { /// public string modelUrl = ""; +#if UNITY_5_3_OR_NEWER + /// + /// A reference to the representation of the thing in Unity + /// + [NonSerialized] + public Unity.Thing component = null; +#endif + + #endregion Properties + + #region Hierarchy + + private Thing _parent; + /// + /// The parent of this thing + /// + public Thing parent { + get => _parent; + set { + if (_parent == value) + return; + + if (value == null) { + _parent?.RemoveChild(this); + _parent = null; + } + else { + value.AddChild(this); + } + this.hierarchyChanged = true; + } + } + + + /// + /// The children of this thing + /// + [NonSerialized] + protected List children = new(); + + /// + /// Add a child Thing to this Thing + /// + /// The Thing which should become a child + /// @remark When the Thing is already a child, it will not be added again + public void AddChild(Thing child) { + if (children.Find(thing => thing == child) != null) + return; + + child._parent = this; + children.Add(child); + } + /// + /// Remove the given thing as a child of this thing + /// + /// The child to remove + /// True when the child was present or false when it was not found + public bool RemoveChild(Thing child) { + return children.Remove(child); + } + + /// + /// Get a child by thing Id + /// + /// The thing ID to find + /// Look recursively through all descendants + /// + Thing GetChild(byte thingId, bool recurse = false) { + foreach (Thing child in this.children) { + if (child == null) + continue; + + if (child.id == thingId) + return child; + if (recurse) { + Thing foundChild = child.GetChild(thingId, recurse); + if (foundChild != null) + return foundChild; + } + } + return null; + } + /// + /// Find a child by name + /// + /// The name of the child thing + /// Look recursively through all descendants + /// The found thing or null when nothing is found + Thing FindChild(string name, bool recurse = true) { + foreach (Thing child in this.children) { + if (child == null) + continue; + + if (child.name == name) + return child; + + if (recurse) { + Thing foundChild = child.FindChild(name, recurse); + if (foundChild != null) + return foundChild; + } + } + return null; + } + + /// + /// Indicator that the hierarchy of the thing has changed + /// + public bool hierarchyChanged = true; + + #endregion Hierarchy + + #region Pose + private Spherical _position = Spherical.zero; /// /// The position of the thing in local space, in meters. @@ -340,20 +347,14 @@ namespace RoboidControl { /// public bool angularVelocityUpdated = false; -#if UNITY_5_3_OR_NEWER + #endregion Pose + + #region Update + /// - /// A reference to the representation of the thing in Unity + /// Get the current time in milliseconds /// - [NonSerialized] - public Unity.Thing component = null; -#endif - - public bool terminate = false; - - #endregion Properties - - #region Methods - + /// The current time in milliseconds public static ulong GetTimeMs() { #if UNITY_5_3_OR_NEWER return (ulong)(UnityEngine.Time.time * 1000); @@ -365,16 +366,17 @@ namespace RoboidControl { /// /// Update de state of the thing /// - /// When true, this will Update the descendants recursively - public void Update(bool recursively = false) { - Update(GetTimeMs(), recursively); + /// When true, this will Update the descendants recursively + public void Update(bool recurse = false) { + Update(GetTimeMs(), recurse); } // #endif /// /// Update this thing /// - /// The current time in milliseconds - public virtual void Update(ulong currentTimeMs, bool recursively = false) { + /// he current clock time in milliseconds; if this is zero, the current time is retrieved automatically + /// When true, this will Update the descendants recursively + public virtual void Update(ulong currentTimeMs, bool recurse = false) { if (this.positionUpdated || this.orientationUpdated) OnPoseChanged?.Invoke(); this.positionUpdated = false; @@ -384,31 +386,19 @@ namespace RoboidControl { //this.hierarchyChanged = false; // should recurse over children... - if (recursively) { + if (recurse) { for (byte childIx = 0; childIx < this.children.Count; childIx++) { Thing child = this.children[childIx]; if (child == null) continue; - child.Update(currentTimeMs, recursively); + child.Update(currentTimeMs, recurse); } } } - /// - /// Function used to generate binary data for this thing - /// - /// a byte array with the binary data - /// @sa Passer::RoboidControl::BinaryMsg - public virtual byte[] GenerateBinary() { return Array.Empty(); } - - /// - /// Function used to process binary data received for this thing - /// - /// The binary data - public virtual void ProcessBinary(byte[] bytes) { - } - - #endregion Methods + public delegate void ChangeHandler(); + public delegate void SphericalHandler(Spherical v); + public delegate void ThingHandler(Thing t); /// /// Event triggered when a new thing has been created @@ -422,18 +412,20 @@ namespace RoboidControl { OnNewThing?.Invoke(thing); } + #endregion Update + /// - /// Check if the thing has the given properaties + /// Function used to generate binary data for this thing /// - /// The thing to check - /// The network ID to compare to - /// The thing ID to compare to - /// True when the thing has the given properties - public static bool IsThing(Thing thing, byte networkId, byte thingId) { - if (thing == null) - return false; - return (thing.networkId == networkId) && (thing.id == thingId); - //return (thing.id == thingId); + /// A byte array with the binary data + /// @sa Passer::RoboidControl::BinaryMsg + public virtual byte[] GenerateBinary() { return Array.Empty(); } + + /// + /// Function used to process binary data received for this thing + /// + /// The binary data + public virtual void ProcessBinary(byte[] bytes) { } } diff --git a/src/Things/DistanceSensor.cs b/src/Things/DistanceSensor.cs index ed66ada..ad5f785 100644 --- a/src/Things/DistanceSensor.cs +++ b/src/Things/DistanceSensor.cs @@ -17,10 +17,10 @@ namespace RoboidControl { /// /// Create a distance sensor with the given ID /// - /// The participant for with the sensor is needed + /// The participant for with the sensor is needed /// The network ID of the sensor /// The ID of the thing - public DistanceSensor(Participant participant, byte networkId, byte thingId) : base(participant, networkId, thingId, (byte)Type.TemperatureSensor) { + public DistanceSensor(Participant owner, byte thingId) : base(owner, Type.TemperatureSensor, thingId) { } #if UNITY_5_3_OR_NEWER diff --git a/src/Things/TemperatureSensor.cs b/src/Things/TemperatureSensor.cs index 34a7233..aa3632a 100644 --- a/src/Things/TemperatureSensor.cs +++ b/src/Things/TemperatureSensor.cs @@ -17,7 +17,7 @@ namespace RoboidControl { /// The participant for with the sensor is needed /// The network ID of the sensor /// The ID of the thing - public TemperatureSensor(Participant participant, byte networkId, byte thingId) : base(participant, networkId, thingId, (byte)Type.TemperatureSensor) { } + public TemperatureSensor(Participant participant, byte thingId) : base(participant, Type.TemperatureSensor, thingId) { } /// /// Function to extract the temperature received in the binary message