diff --git a/Components/Network/ART-NET/ARTNETCLIENT.cs b/Components/Network/ART-NET/ARTNETCLIENT.cs new file mode 100644 index 0000000..91677ad --- /dev/null +++ b/Components/Network/ART-NET/ARTNETCLIENT.cs @@ -0,0 +1,152 @@ +using System; +using System.Net; +using System.Net.Sockets; +using System.Threading.Tasks; +using Elements.Core; +using FrooxEngine; + +namespace Obsidian +{ + + [Category(new string[] { "Obsidian/Network/ArtNet" })] + public class ArtNetClient : Component + { + public readonly Sync URL; + public readonly UserRef HandlingUser; + public readonly Sync AccessReason; + public readonly Sync ConnectRetryInterval; + public readonly Sync IsConnected; + + private Uri _currentURL; + private UdpClient _udpClient; + + public event Action Connected; + public event Action Closed; + public event Action Error; + public event Action PacketReceived; // For ArtNet packets + public event Action DMXDataReceived; // For DMX512 data + + protected override void OnAwake() + { + ConnectRetryInterval.Value = 10f; + } + + protected override void OnChanges() + { + Uri uri = (Enabled ? URL.Value : null); + if (HandlingUser.Target != LocalUser) + { + uri = null; + } + + if (uri != _currentURL) + { + _currentURL = uri; + CloseCurrent(); + IsConnected.Value = false; + if (_currentURL != null) + { + StartTask(async delegate + { + await ConnectTo(_currentURL); + }); + } + } + } + + private async Task ConnectTo(Uri target) + { + if (target.Scheme != "artnet") + { + Error?.Invoke(this, "Invalid URL scheme. Expected 'artnet://'."); + return; + } + + if (await Engine.Security.RequestAccessPermission(target.Host, target.Port, AccessReason.Value ?? "ArtNet Client") == HostAccessPermission.Allowed && !(target != _currentURL) && !IsRemoved) + { + _udpClient = new UdpClient(target.Port); + IsConnected.Value = true; + Connected?.Invoke(this); + StartTask(ReceiveLoop); + } + } + + private async Task ReceiveLoop() + { + var remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); + while (IsConnected.Value && _udpClient != null) + { + try + { + UdpReceiveResult result = await _udpClient.ReceiveAsync(); + byte[] receivedData = result.Buffer; + + // Check if the data is an ArtNet packet or DMX512 data + if (IsArtNetPacket(receivedData)) + { + PacketReceived?.Invoke(this, receivedData); + } + else + { + DMXDataReceived?.Invoke(this, receivedData); + } + } + catch (Exception ex) + { + Error?.Invoke(this, ex.Message); + break; + } + } + } + + private bool IsArtNetPacket(byte[] data) + { + // Art-Net packets start with the ASCII sequence for "Art-Net" followed by a null byte. + byte[] artNetHeader = new byte[] { 65, 114, 116, 45, 78, 101, 116, 0 }; + + if (data.Length < artNetHeader.Length) + { + return false; + } + + for (int i = 0; i < artNetHeader.Length; i++) + { + if (data[i] != artNetHeader[i]) + { + return false; + } + } + + return true; + } + + protected override void OnDispose() + { + CloseCurrent(); + base.OnDispose(); + } + + private void CloseCurrent() + { + if (_udpClient != null) + { + UdpClient udpClient = _udpClient; + _udpClient = null; + try + { + Closed?.Invoke(this); + } + catch (Exception ex) + { + UniLog.Error("Exception in running Closed event on ArtNetClient:\n" + ex); + } + udpClient.Close(); + } + } + + public static implicit operator ArtNetClient(ProtoFlux.Runtimes.Execution.Nodes.FrooxEngine.Network.WebsocketConnect v) + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/ProjectObsidian.csproj b/ProjectObsidian.csproj index 49fecf8..98059f8 100644 --- a/ProjectObsidian.csproj +++ b/ProjectObsidian.csproj @@ -41,4 +41,7 @@ $(ResonitePath)Resonite_Data/Managed/Elements.Assets.dll + + + diff --git a/ProtoFlux/Bindings/Math/Physics/CentipetalForceBinding.cs b/ProtoFlux/Bindings/Math/Physics/CentipetalForceBinding.cs index dc45d56..909be9e 100644 --- a/ProtoFlux/Bindings/Math/Physics/CentipetalForceBinding.cs +++ b/ProtoFlux/Bindings/Math/Physics/CentipetalForceBinding.cs @@ -13,34 +13,42 @@ public class CentripetalForceCalculation : FrooxEngine.ProtoFlux.Runtimes.Execut public readonly SyncRef> Velocity; public readonly SyncRef> Radius; - public override Type NodeType => typeof(CentripetalForceCalculation); + public override Type NodeType => typeof(ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode); - public CentripetalForceCalculationNode TypedNodeInstance { get; private set; } + public ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode TypedNodeInstance { get; private set; } public override INode NodeInstance => TypedNodeInstance; public override int NodeInputCount => base.NodeInputCount + 3; - public override TN Instantiate() + public override N Instantiate() { if (TypedNodeInstance != null) + { throw new InvalidOperationException("Node has already been instantiated"); - var instance = (TypedNodeInstance = new CentripetalForceCalculationNode()); - return instance as TN; + } + ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode centripetalForceCalculationNode2 = (TypedNodeInstance = new ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode()); + return centripetalForceCalculationNode2 as N; } protected override void AssociateInstanceInternal(INode node) { - if (node is not CentripetalForceCalculationNode typedNodeInstance) - throw new ArgumentException("Node instance is not of type " + typeof(CentripetalForceCalculationNode)); - TypedNodeInstance = typedNodeInstance; + if (node is ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode typedNodeInstance) + { + TypedNodeInstance = typedNodeInstance; + return; + } + throw new ArgumentException("Node instance is not of type " + typeof(ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics.CentripetalForceCalculationNode)); } - public override void ClearInstance() => TypedNodeInstance = null; + public override void ClearInstance() + { + TypedNodeInstance = null; + } protected override ISyncRef GetInputInternal(ref int index) { - var inputInternal = base.GetInputInternal(ref index); + ISyncRef inputInternal = base.GetInputInternal(ref index); if (inputInternal != null) { return inputInternal; diff --git a/ProtoFlux/Bindings/Math/Physics/DragCalculationBinding.cs b/ProtoFlux/Bindings/Math/Physics/DragCalculationBinding.cs index 685d0a8..0412d45 100644 --- a/ProtoFlux/Bindings/Math/Physics/DragCalculationBinding.cs +++ b/ProtoFlux/Bindings/Math/Physics/DragCalculationBinding.cs @@ -6,8 +6,8 @@ using ProtoFlux.Runtimes.Execution; using ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics; -[Category("ProtoFlux/Runtimes/Execution/Nodes/Obsidian/Math/Physics")] -public class DragCalculation : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode +[Category(new string[] { "ProtoFlux/Runtimes/Execution/Nodes/Obsidian/Math/Physics" })] +public class DragCalculationNodeBinding : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode { public readonly SyncRef> FluidDensity; public readonly SyncRef> ObjectVelocity; @@ -20,64 +20,37 @@ public class DragCalculation : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFun public override INode NodeInstance => TypedNodeInstance; - public override int NodeInputCount => base.NodeInputCount + 4; + public override int NodeInputCount => 4; - public override TN Instantiate() + public override N Instantiate() { - try + if (TypedNodeInstance != null) { - if (TypedNodeInstance != null) - throw new InvalidOperationException("Node has already been instantiated"); - var dragCalculationInstance = (TypedNodeInstance = new DragCalculationNode()); - return dragCalculationInstance as TN; - } - catch (Exception ex) - { - UniLog.Log($"Error in DragCalculationBinding.Instantiate: {ex.Message}"); - throw; + throw new InvalidOperationException("Node has already been instantiated"); } + TypedNodeInstance = new DragCalculationNode(); + return TypedNodeInstance as N; } protected override void AssociateInstanceInternal(INode node) { - try - { - if (node is not DragCalculationNode typedNodeInstance) - throw new ArgumentException("Node instance is not of type " + typeof(DragCalculationNode)); - TypedNodeInstance = typedNodeInstance; - } - catch (Exception ex) - { - UniLog.Log($"Error in DragCalculationBinding.AssociateInstanceInternal: {ex.Message}"); - throw; - } + TypedNodeInstance = node as DragCalculationNode ?? throw new ArgumentException("Node instance is not of type DragCalculationNode"); } - public override void ClearInstance() => TypedNodeInstance = null; + public override void ClearInstance() + { + TypedNodeInstance = null; + } - //without this it crashes i hate it protected override ISyncRef GetInputInternal(ref int index) { - var inputInternal = base.GetInputInternal(ref index); - if (inputInternal != null) - { - return inputInternal; - } switch (index) { - case 0: - return FluidDensity; - case 1: - return ObjectVelocity; - case 2: - return DragCoefficient; - case 3: - return CrossSectionalArea; - default: - index -= 4; - return null; + case 0: return FluidDensity; + case 1: return ObjectVelocity; + case 2: return DragCoefficient; + case 3: return CrossSectionalArea; + default: index -= 4; return null; } } - - } diff --git a/ProtoFlux/Bindings/Math/Physics/KineticFrictionBinding.cs b/ProtoFlux/Bindings/Math/Physics/KineticFrictionBinding.cs index 5d54d63..5331208 100644 --- a/ProtoFlux/Bindings/Math/Physics/KineticFrictionBinding.cs +++ b/ProtoFlux/Bindings/Math/Physics/KineticFrictionBinding.cs @@ -7,7 +7,7 @@ using ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics; [Category(new string[] { "ProtoFlux/Runtimes/Execution/Nodes/Obsidian/Math/Physics" })] -public class KineticFrictionCalculation : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode +public class KineticFrictionNodeBinding : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode { public readonly SyncRef> NormalForce; public readonly SyncRef> KineticFrictionCoefficient; @@ -18,41 +18,35 @@ public class KineticFrictionCalculation : FrooxEngine.ProtoFlux.Runtimes.Executi public override INode NodeInstance => TypedNodeInstance; - public override int NodeInputCount => base.NodeInputCount + 2; + public override int NodeInputCount => 2; - public override TN Instantiate() + public override N Instantiate() { if (TypedNodeInstance != null) + { throw new InvalidOperationException("Node has already been instantiated"); - var instance = (TypedNodeInstance = new KineticFrictionNode()); - return instance as TN; + } + TypedNodeInstance = new KineticFrictionNode(); + return TypedNodeInstance as N; } protected override void AssociateInstanceInternal(INode node) { - if (node is not KineticFrictionNode typedNodeInstance) - throw new ArgumentException("Node instance is not of type " + typeof(KineticFrictionNode)); - TypedNodeInstance = typedNodeInstance; + TypedNodeInstance = node as KineticFrictionNode ?? throw new ArgumentException("Node instance is not of type KineticFrictionNode"); } - public override void ClearInstance() => TypedNodeInstance = null; + public override void ClearInstance() + { + TypedNodeInstance = null; + } protected override ISyncRef GetInputInternal(ref int index) { - var inputInternal = base.GetInputInternal(ref index); - if (inputInternal != null) - { - return inputInternal; - } switch (index) { - case 0: - return NormalForce; - case 1: - return KineticFrictionCoefficient; - default: - index -= 2; - return null; + case 0: return NormalForce; + case 1: return KineticFrictionCoefficient; + default: index -= 2; return null; } } } diff --git a/ProtoFlux/Bindings/Math/Physics/RefractNodeBinding.cs b/ProtoFlux/Bindings/Math/Physics/RefractNodeBinding.cs index a7e97f4..84c3fbf 100644 --- a/ProtoFlux/Bindings/Math/Physics/RefractNodeBinding.cs +++ b/ProtoFlux/Bindings/Math/Physics/RefractNodeBinding.cs @@ -1,77 +1,54 @@ using System; +using Elements.Core; using FrooxEngine; using FrooxEngine.ProtoFlux; using ProtoFlux.Core; using ProtoFlux.Runtimes.Execution; using ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics; -using Elements.Core; [Category(new string[] { "ProtoFlux/Runtimes/Execution/Nodes/Obsidian/Math/Physics" })] -public class RefractionCalculation : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode +public class RefractionNodeBinding : FrooxEngine.ProtoFlux.Runtimes.Execution.ValueFunctionNode { public readonly SyncRef> RefractiveIndex1; public readonly SyncRef> RefractiveIndex2; public readonly SyncRef> AngleOfIncidence; public override Type NodeType => typeof(RefractionNode); - + public RefractionNode TypedNodeInstance { get; private set; } public override INode NodeInstance => TypedNodeInstance; - public override int NodeInputCount => base.NodeInputCount + 3; + public override int NodeInputCount => 3; - public override TN Instantiate() + public override N Instantiate() { - try + if (TypedNodeInstance != null) { - if (TypedNodeInstance != null) - throw new InvalidOperationException("Node has already been instantiated"); - var refractionInstance = (TypedNodeInstance = new RefractionNode()); - return refractionInstance as TN; - } - catch (Exception ex) - { - UniLog.Log($"Error in RefractionCalculation.Instantiate: {ex.Message}"); - throw; + throw new InvalidOperationException("Node has already been instantiated"); } + TypedNodeInstance = new RefractionNode(); + return TypedNodeInstance as N; } protected override void AssociateInstanceInternal(INode node) { - try - { - if (node is not RefractionNode typedNodeInstance) - throw new ArgumentException("Node instance is not of type " + typeof(RefractionNode)); - TypedNodeInstance = typedNodeInstance; - } - catch (Exception ex) - { - UniLog.Log($"Error in RefractionCalculation.AssociateInstanceInternal: {ex.Message}"); - throw; - } + TypedNodeInstance = node as RefractionNode ?? throw new ArgumentException("Node instance is not of type RefractionNode"); } - public override void ClearInstance() => TypedNodeInstance = null; + public override void ClearInstance() + { + TypedNodeInstance = null; + } protected override ISyncRef GetInputInternal(ref int index) { - var inputInternal = base.GetInputInternal(ref index); - if (inputInternal != null) - { - return inputInternal; - } switch (index) { - case 0: - return RefractiveIndex1; - case 1: - return RefractiveIndex2; - case 2: - return AngleOfIncidence; - default: - index -= 3; - return null; + case 0: return RefractiveIndex1; + case 1: return RefractiveIndex2; + case 2: return AngleOfIncidence; + default: index -= 3; return null; } } } diff --git a/ProtoFlux/Bindings/Network/Art-Net/ArtNetConnectNode.cs b/ProtoFlux/Bindings/Network/Art-Net/ArtNetConnectNode.cs new file mode 100644 index 0000000..3ee84d1 --- /dev/null +++ b/ProtoFlux/Bindings/Network/Art-Net/ArtNetConnectNode.cs @@ -0,0 +1,53 @@ +using System; +using FrooxEngine; +using FrooxEngine.ProtoFlux; +using ProtoFlux.Core; +using ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Network.ArtNet; +using Obsidian; + +[Category(new string[] { "ProtoFlux/Runtimes/Execution/Nodes/Obsidian/Network/ArtNet" })] +public class ArtNetClientConnectNode : FrooxEngine.ProtoFlux.Runtimes.Execution.ActionBreakableFlowNode +{ + public readonly SyncRef> Client; + public readonly SyncRef> URL; + public readonly SyncRef> HandlingUser; + + public override Type NodeType => typeof(ArtNetClientConnect); + + public ArtNetClientConnect TypedNodeInstance { get; private set; } + + public override INode NodeInstance => TypedNodeInstance; + + public override int NodeInputCount => 3; + + public override N Instantiate() + { + if (TypedNodeInstance != null) + { + throw new InvalidOperationException("Node has already been instantiated"); + } + TypedNodeInstance = new ArtNetClientConnect(); + return TypedNodeInstance as N; + } + + protected override void AssociateInstanceInternal(INode node) + { + TypedNodeInstance = node as ArtNetClientConnect ?? throw new ArgumentException("Node instance is not of type ArtNetClientConnect"); + } + + public override void ClearInstance() + { + TypedNodeInstance = null; + } + + protected override ISyncRef GetInputInternal(ref int index) + { + switch (index) + { + case 0: return Client; + case 1: return URL; + case 2: return HandlingUser; + default: index -= 3; return null; + } + } +} diff --git a/ProtoFlux/Math/Physics/CentripetalForceCalculationNode.cs b/ProtoFlux/Math/Physics/CentripetalForceCalculationNode.cs index c7d9a75..ca10a98 100644 --- a/ProtoFlux/Math/Physics/CentripetalForceCalculationNode.cs +++ b/ProtoFlux/Math/Physics/CentripetalForceCalculationNode.cs @@ -5,28 +5,32 @@ using ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics; using System; -public class CentripetalForceCalculationNode : ValueFunctionNode +namespace ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics { - public ValueInput Mass; - public ValueInput Velocity; - public ValueInput Radius; - - protected override float Compute(ExecutionContext context) + public class CentripetalForceCalculationNode : ValueFunctionNode { - try + public ValueInput Mass; + public ValueInput Velocity; + public ValueInput Radius; + + protected override float Compute(ExecutionContext context) { - float m = Mass.Evaluate(context); - float v = Velocity.Evaluate(context); - float r = Radius.Evaluate(context); + try + { + float m = Mass.Evaluate(context); + float v = Velocity.Evaluate(context); + float r = Radius.Evaluate(context); - float result = (m * v * v) / r; + float result = (m * v * v) / r; - return result; - } - catch (Exception ex) - { - // Log any exceptions if needed - throw new Exception($"Error in CentripetalForceCalculationNode.Compute: {ex.Message}"); + return result; + } + catch (Exception ex) + { + // Log any exceptions if needed + throw new Exception($"Error in CentripetalForceCalculationNode.Compute: {ex.Message}"); + } } } -} \ No newline at end of file +} + diff --git a/ProtoFlux/Math/Physics/DragCalculationNode.cs b/ProtoFlux/Math/Physics/DragCalculationNode.cs index 6ee5bb7..79b9616 100644 --- a/ProtoFlux/Math/Physics/DragCalculationNode.cs +++ b/ProtoFlux/Math/Physics/DragCalculationNode.cs @@ -13,38 +13,25 @@ public class DragCalculationNode : ValueFunctionNode public ValueInput ObjectVelocity; // v public ValueInput DragCoefficient; // Cd public ValueInput CrossSectionalArea; // A - + protected override float3 Compute(ExecutionContext context) { - try - { - float rho = FluidDensity.Evaluate(context); - float3 v = ObjectVelocity.Evaluate(context); - float Cd = DragCoefficient.Evaluate(context); - float A = CrossSectionalArea.Evaluate(context); - - float vMagnitudeSquared = MathX.Dot(v, v); - float3 dragDirection = Normalize(v); - float3 dragForce = -0.5f * rho * vMagnitudeSquared * Cd * A * dragDirection; + float rho = FluidDensity.Evaluate(context); + float3 v = ObjectVelocity.Evaluate(context); + float Cd = DragCoefficient.Evaluate(context); + float A = CrossSectionalArea.Evaluate(context); - return dragForce; - } - catch (Exception ex) - { - // Log any exceptions without throwing them - UniLog.Log($"Error in DragCalculationNode.Compute: {ex.Message}"); - } + float vMagnitudeSquared = MathX.Dot(v, v); + float3 dragDirection = Normalize(v); + float3 dragForce = -0.5f * rho * vMagnitudeSquared * Cd * A * dragDirection; - return float3.Zero; + return dragForce; } - // Define Normalize function since MathX doesn't have one private float3 Normalize(float3 vector) { - float magnitude = MathX.Sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z); - if (magnitude == 0) - return float3.Zero; // Handle zero magnitude case - return new float3(vector.x / magnitude, vector.y / magnitude, vector.z / magnitude); + float magnitude = MathX.Sqrt(MathX.Dot(vector, vector)); + return magnitude > 0 ? vector / magnitude : float3.Zero; } } } diff --git a/ProtoFlux/Math/Physics/KinecticFrictionNode.cs b/ProtoFlux/Math/Physics/KinecticFrictionNode.cs index e364a24..091a480 100644 --- a/ProtoFlux/Math/Physics/KinecticFrictionNode.cs +++ b/ProtoFlux/Math/Physics/KinecticFrictionNode.cs @@ -9,9 +9,8 @@ namespace ProtoFlux.Runtimes.Execution.Nodes.Obsidian.Math.Physics [NodeCategory("Obsidian/Math/Physics")] public class KineticFrictionNode : ValueFunctionNode { - public ValueInput NormalForce; // Assuming it's a 3D force, change as needed + public ValueInput NormalForce; public ValueInput KineticFrictionCoefficient; - public ValueOutput KineticFrictionalForce; protected override float3 Compute(ExecutionContext context) { @@ -20,7 +19,6 @@ protected override float3 Compute(ExecutionContext context) // Kinetic friction formula: f_kinetic = mu_kinetic * N float3 kineticFrictionalForce = coefficient * normal; - return kineticFrictionalForce; } } diff --git a/ProtoFlux/Network/Art-Net/ArtNetConnect.cs b/ProtoFlux/Network/Art-Net/ArtNetConnect.cs new file mode 100644 index 0000000..dfa3e61 --- /dev/null +++ b/ProtoFlux/Network/Art-Net/ArtNetConnect.cs @@ -0,0 +1,32 @@ +using System; +using FrooxEngine; +using FrooxEngine.ProtoFlux; +using Obsidian; +using ProtoFlux.Core; +using ProtoFlux.Runtimes.Execution; + +[NodeCategory("Obsidian/Network/Websockets")] +public class ArtNetConnect : ActionBreakableFlowNode +{ + public ObjectInput Client; + + public ObjectInput URL; + + public ObjectInput HandlingUser; + + protected override bool Do(FrooxEngineContext context) + { + ArtNetClient ArtnetClient = Client.Evaluate(context); + if (ArtnetClient == null) + { + return false; + } + Uri uri = URL.Evaluate(context); + if (uri != null) + { + ArtnetClient.URL.Value = uri; + } + ArtnetClient.HandlingUser.Target = HandlingUser.Evaluate(context, context.LocalUser); + return true; + } +}