Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,13 @@ public static List<string> GenerateSingleAction(string inPath, string outPath, s
actionWrapper.WrapActionSections(types[i]);
}

// Generate action wrapper
// Generate action wrapper (ROS1-style)
actionWrapper.WrapAction();

// Generate ROS2 FeedbackMessage class (UUID + Feedback body).
// This is needed for Action client feedback routing.
actionWrapper.GenerateFeedbackMessage();

Comment on lines +100 to +103
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that GenerateSingleAction always generates an additional *FeedbackMessage.cs, GetActionClassPaths() (used by MessageGenBrowser to determine whether an action is “built”) should be updated to include that new output. Otherwise the UI can report a .action as built even when the FeedbackMessage file is missing/out-of-date.

Copilot uses AI. Check for mistakes.
return warnings;
}

Expand Down Expand Up @@ -364,6 +368,80 @@ public void WrapActionSections(string type)
}
}

/// <summary>
/// Generate a ROS2-style FeedbackMessage class that contains
/// goal_id (byte[16] UUID) + Feedback body. This is the wire-level
/// message type for the /_action/feedback topic. Registers both
/// the short name (pkg/Action_FeedbackMessage) and the full
/// /action/ path so it works across __subscribe and __topic_list.
/// </summary>
public void GenerateFeedbackMessage()
{
string feedbackClassName = inFileName + "Feedback" + MsgAutoGenUtilities.ActionClassSuffix;
string className = inFileName + "FeedbackMessage";
string resolvedPackage = MsgAutoGenUtilities.ResolvePackageName(rosPackageName);
string shortRosName = rosPackageName + "/" + inFileName + "_FeedbackMessage";
string altRosName = rosPackageName + "/action/" + inFileName + "_FeedbackMessage";

string filePath = Path.Combine(this.outPath, className + ".cs");

using (StreamWriter writer = new StreamWriter(filePath, false))
{
writer.Write("//Do not edit! This file was generated by Unity-ROS MessageGeneration.\n");
writer.Write("using System;\n");
writer.Write("using Unity.Robotics.ROSTCPConnector.MessageGeneration;\n\n");
writer.Write("namespace RosMessageTypes." + resolvedPackage + "\n{\n");
writer.Write(ONE_TAB + "[Serializable]\n");
writer.Write(ONE_TAB + "public class " + className + " : Message\n");
writer.Write(ONE_TAB + "{\n");

// ROS message name (dual registration)
writer.Write(TWO_TABS + "public const string k_RosMessageName = \"" + shortRosName + "\";\n");
writer.Write(TWO_TABS + "public const string k_RosMessageNameAlt = \"" + altRosName + "\";\n");
writer.Write(TWO_TABS + "public override string RosMessageName => k_RosMessageName;\n\n");

// Fields
writer.Write(TWO_TABS + "public byte[] goal_id = new byte[16];\n");
writer.Write(TWO_TABS + "public " + feedbackClassName + " feedback = new " + feedbackClassName + "();\n\n");

// Default constructor
writer.Write(TWO_TABS + "public " + className + "() { }\n\n");

// Deserialize
writer.Write(TWO_TABS + "public static " + className + " Deserialize(MessageDeserializer deserializer) => new " + className + "(deserializer);\n\n");
writer.Write(TWO_TABS + "private " + className + "(MessageDeserializer deserializer)\n");
writer.Write(TWO_TABS + "{\n");
writer.Write(THREE_TABS + "goal_id = new byte[16];\n");
writer.Write(THREE_TABS + "for (int i = 0; i < 16; i++)\n");
writer.Write(THREE_TABS + ONE_TAB + "deserializer.Read(out goal_id[i]);\n");
writer.Write(THREE_TABS + "feedback = " + feedbackClassName + ".Deserialize(deserializer);\n");
writer.Write(TWO_TABS + "}\n\n");

// SerializeTo
writer.Write(TWO_TABS + "public override void SerializeTo(MessageSerializer serializer)\n");
writer.Write(TWO_TABS + "{\n");
writer.Write(THREE_TABS + "serializer.Write(goal_id);\n");
writer.Write(THREE_TABS + "feedback.SerializeTo(serializer);\n");
writer.Write(TWO_TABS + "}\n\n");

// Register (dual)
writer.Write("#if UNITY_EDITOR\n");
writer.Write(TWO_TABS + "[UnityEditor.InitializeOnLoadMethod]\n");
writer.Write("#else\n");
writer.Write(TWO_TABS + "[UnityEngine.RuntimeInitializeOnLoadMethod]\n");
writer.Write("#endif\n");
writer.Write(TWO_TABS + "public static void Register()\n");
writer.Write(TWO_TABS + "{\n");
writer.Write(THREE_TABS + "MessageRegistry.Register(k_RosMessageName, Deserialize);\n");
writer.Write(THREE_TABS + "MessageRegistry.Register(k_RosMessageNameAlt, Deserialize);\n");
writer.Write(TWO_TABS + "}\n");

// Close class + namespace
writer.Write(ONE_TAB + "}\n");
writer.Write("}\n");
}
}

public void WrapAction()
{
string msgNamePrefix = inFileName + MsgAutoGenUtilities.ActionClassSuffix;
Expand Down

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

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Unity.Robotics.ROSTCPConnector.MessageGeneration;

namespace RosMessageTypes.ActionTutorialsInterfaces
{
[Serializable]
public class FibonacciFeedback : Message
{
public const string k_RosMessageName = "action_tutorials_interfaces/Fibonacci_Feedback";
public override string RosMessageName => k_RosMessageName;

public int[] partial_sequence;

public FibonacciFeedback()
{
this.partial_sequence = new int[0];
}

public FibonacciFeedback(int[] partial_sequence)
{
this.partial_sequence = partial_sequence;
}

public static FibonacciFeedback Deserialize(MessageDeserializer deserializer) => new FibonacciFeedback(deserializer);

private FibonacciFeedback(MessageDeserializer deserializer)
{
deserializer.Read(out this.partial_sequence, sizeof(int), deserializer.ReadLength());
}

public override void SerializeTo(MessageSerializer serializer)
{
serializer.WriteLength(this.partial_sequence);
serializer.Write(this.partial_sequence);
}

#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[UnityEngine.RuntimeInitializeOnLoadMethod]
#endif
public static void Register()
{
MessageRegistry.Register(k_RosMessageName, Deserialize);
}
}
}

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
using System;
using Unity.Robotics.ROSTCPConnector.MessageGeneration;

namespace RosMessageTypes.ActionTutorialsInterfaces
{
/// <summary>
/// The wire-level FeedbackMessage for Fibonacci actions.
/// Layout: unique_identifier_msgs/UUID goal_id + Fibonacci_Feedback feedback.
/// </summary>
[Serializable]
public class FibonacciFeedbackMessage : Message
{
public const string k_RosMessageName = "action_tutorials_interfaces/Fibonacci_FeedbackMessage";
// The endpoint may also report this type with /action/ in the path
// when it refreshes the topic list from the ROS2 graph.
public const string k_RosMessageNameAlt = "action_tutorials_interfaces/action/Fibonacci_FeedbackMessage";
public override string RosMessageName => k_RosMessageName;

public byte[] goal_id = new byte[16];
public FibonacciFeedback feedback = new FibonacciFeedback();

public FibonacciFeedbackMessage() { }

public static FibonacciFeedbackMessage Deserialize(MessageDeserializer deserializer)
=> new FibonacciFeedbackMessage(deserializer);

private FibonacciFeedbackMessage(MessageDeserializer deserializer)
{
// UUID is uint8[16] — 16 raw bytes, no length prefix.
goal_id = new byte[16];
for (int i = 0; i < 16; i++)
deserializer.Read(out goal_id[i]);

// Feedback body follows inline.
feedback = FibonacciFeedback.Deserialize(deserializer);
}

public override void SerializeTo(MessageSerializer serializer)
{
serializer.Write(goal_id);
feedback.SerializeTo(serializer);
}

#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[UnityEngine.RuntimeInitializeOnLoadMethod]
#endif
public static void Register()
{
MessageRegistry.Register(k_RosMessageName, Deserialize);
MessageRegistry.Register(k_RosMessageNameAlt, Deserialize);
}
}
}

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using Unity.Robotics.ROSTCPConnector.MessageGeneration;

namespace RosMessageTypes.ActionTutorialsInterfaces
{
[Serializable]
public class FibonacciGoal : Message
{
public const string k_RosMessageName = "action_tutorials_interfaces/Fibonacci_Goal";
public override string RosMessageName => k_RosMessageName;

public int order;

public FibonacciGoal()
{
this.order = 0;
}

public FibonacciGoal(int order)
{
this.order = order;
}

public static FibonacciGoal Deserialize(MessageDeserializer deserializer) => new FibonacciGoal(deserializer);

private FibonacciGoal(MessageDeserializer deserializer)
{
deserializer.Read(out this.order);
}

public override void SerializeTo(MessageSerializer serializer)
{
serializer.Write(this.order);
}

#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[UnityEngine.RuntimeInitializeOnLoadMethod]
#endif
public static void Register()
{
MessageRegistry.Register(k_RosMessageName, Deserialize);
}
}
}

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Unity.Robotics.ROSTCPConnector.MessageGeneration;

namespace RosMessageTypes.ActionTutorialsInterfaces
{
[Serializable]
public class FibonacciResult : Message
{
public const string k_RosMessageName = "action_tutorials_interfaces/Fibonacci_Result";
public override string RosMessageName => k_RosMessageName;

public int[] sequence;

public FibonacciResult()
{
this.sequence = new int[0];
}

public FibonacciResult(int[] sequence)
{
this.sequence = sequence;
}

public static FibonacciResult Deserialize(MessageDeserializer deserializer) => new FibonacciResult(deserializer);

private FibonacciResult(MessageDeserializer deserializer)
{
deserializer.Read(out this.sequence, sizeof(int), deserializer.ReadLength());
}

public override void SerializeTo(MessageSerializer serializer)
{
serializer.WriteLength(this.sequence);
serializer.Write(this.sequence);
}

#if UNITY_EDITOR
[UnityEditor.InitializeOnLoadMethod]
#else
[UnityEngine.RuntimeInitializeOnLoadMethod]
#endif
public static void Register()
{
MessageRegistry.Register(k_RosMessageName, Deserialize);
}
}
}

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

Loading
Loading