From 0f3747f4c3ae2344ef662433d4b232f8e3e0f4b2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fa=E9=B8=BD?= <43724908+Akarinnnnn@users.noreply.github.com>
Date: Tue, 15 Jul 2025 17:41:34 +0800
Subject: [PATCH 1/3] Generate callback info on async interface methods
---
CodeGen/src/interfaces.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/CodeGen/src/interfaces.py b/CodeGen/src/interfaces.py
index a007b5d2..f6c2a440 100644
--- a/CodeGen/src/interfaces.py
+++ b/CodeGen/src/interfaces.py
@@ -850,6 +850,23 @@ def parse_func(f, interface, func):
if c:
g_Output.append("\t\t/// " + c + "")
g_Output.append("\t\t/// ")
+
+ strAsyncType: str = None
+ strAsyncStruct: str = None
+
+ for attr in func.attributes:
+ if attr.name in ("STEAM_CALL_RESULT", "STEAM_CALL_BACK"):
+ if attr.name == "STEAM_CALL_RESULT":
+ strAsyncType = "CallResult"
+ elif attr.name == "STEAM_CALL_BACK":
+ strAsyncType = "Callback"
+ strAsyncStruct = attr.value
+
+
+ if strAsyncType is not None:
+ g_Output.append(f"\t\t[SteamHasAsync{strAsyncType}(typeof({strAsyncStruct}))]")
+
+
g_Output.append("\t\tpublic static " + wrapperreturntype + " " + func.name.rstrip("0") + "(" + wrapperargs + ") {")
g_Output.extend(functionBody)
From aefcd4682ea572e2f3ac7f52c868f60a301be986 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fa=E9=B8=BD?= <43724908+Akarinnnnn@users.noreply.github.com>
Date: Tue, 15 Jul 2025 17:43:36 +0800
Subject: [PATCH 2/3] Add callback type attribute for async methods
---
.../Runtime/SteamHasAsyncResultAttributes.cs | 56 +++++++++++++++++++
1 file changed, 56 insertions(+)
create mode 100644 com.rlabrecque.steamworks.net/Runtime/SteamHasAsyncResultAttributes.cs
diff --git a/com.rlabrecque.steamworks.net/Runtime/SteamHasAsyncResultAttributes.cs b/com.rlabrecque.steamworks.net/Runtime/SteamHasAsyncResultAttributes.cs
new file mode 100644
index 00000000..3e244367
--- /dev/null
+++ b/com.rlabrecque.steamworks.net/Runtime/SteamHasAsyncResultAttributes.cs
@@ -0,0 +1,56 @@
+// This file is provided under The MIT License as part of Steamworks.NET.
+// Copyright (c) 2013-2022 Riley Labrecque
+// Please see the included LICENSE.txt for additional information.
+
+// This file is automatically generated.
+// Changes to this file will be reverted when you update Steamworks.NET
+
+#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
+#define DISABLESTEAMWORKS
+#endif
+
+#if !DISABLESTEAMWORKS
+
+namespace Steamworks {
+ ///
+ /// Inform invokers use to receive async result.
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
+ public sealed class SteamHasAsyncCallResultAttribute : System.Attribute {
+ private System.Type callbackType; // for vs project ignore suggestion IDE0044, I'm not sure if Unity supports readonly field
+
+ // See the attribute guidelines at
+ // http://go.microsoft.com/fwlink/?LinkId=85236
+
+ internal SteamHasAsyncCallResultAttribute(System.Type callbackType) {
+ this.callbackType = callbackType;
+ }
+
+ ///
+ /// Result type of the async operation.
+ ///
+ public System.Type CallbackType { get { return callbackType; } }
+ }
+
+ ///
+ /// Inform invokers use to receive async result.
+ ///
+ [System.AttributeUsage(System.AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
+ public sealed class SteamHasAsyncCallbackAttribute : System.Attribute {
+ private System.Type callbackType; // for vs project ignore suggestion IDE0044, I'm not sure if Unity supports readonly field
+
+ // See the attribute guidelines at
+ // http://go.microsoft.com/fwlink/?LinkId=85236
+
+ internal SteamHasAsyncCallbackAttribute(System.Type callbackType) {
+ this.callbackType = callbackType;
+ }
+
+ ///
+ /// Result type of the async operation.
+ ///
+ public System.Type CallbackType { get { return callbackType; } }
+ }
+}
+
+#endif // !DISABLESTEAMWORKS
From 6324e6142d9840e34f8d48ff191ca8b062bc1514 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fa=E9=B8=BD?= <43724908+Akarinnnnn@users.noreply.github.com>
Date: Wed, 16 Jul 2025 20:25:29 +0800
Subject: [PATCH 3/3] Generate callback type marker on callback struct
After this change, inteface gen should run before struct gen. This is mentioned in CodeGen entrypoint to avoid accidently reordered.
---
CodeGen/Steamworks.NET_CodeGen.py | 1 +
CodeGen/src/interfaces.py | 7 ++++++-
CodeGen/src/structs.py | 8 +++++++-
.../Runtime/CallbackMarkers.cs | 20 +++++++++++++++++++
4 files changed, 34 insertions(+), 2 deletions(-)
create mode 100644 com.rlabrecque.steamworks.net/Runtime/CallbackMarkers.cs
diff --git a/CodeGen/Steamworks.NET_CodeGen.py b/CodeGen/Steamworks.NET_CodeGen.py
index 660dcd35..f6575153 100644
--- a/CodeGen/Steamworks.NET_CodeGen.py
+++ b/CodeGen/Steamworks.NET_CodeGen.py
@@ -11,6 +11,7 @@ def main():
steamworksparser.Settings.fake_gameserver_interfaces = True
___parser = steamworksparser.parse(steam_path)
+ # interface gen must run before struct, see parse_func() in interface.py
interfaces.main(___parser)
constants.main(___parser)
enums.main(___parser)
diff --git a/CodeGen/src/interfaces.py b/CodeGen/src/interfaces.py
index f6c2a440..2d2950b3 100644
--- a/CodeGen/src/interfaces.py
+++ b/CodeGen/src/interfaces.py
@@ -861,7 +861,12 @@ def parse_func(f, interface, func):
elif attr.name == "STEAM_CALL_BACK":
strAsyncType = "Callback"
strAsyncStruct = attr.value
-
+
+ # attach async marker to struct definiation
+ # this requires interface gen runs before struct gen to behave correctly
+ for callback in f.callbacks:
+ if callback.name == strAsyncStruct:
+ callback.asyncMarkerInterfaceName = f"I{strAsyncType}Struct"
if strAsyncType is not None:
g_Output.append(f"\t\t[SteamHasAsync{strAsyncType}(typeof({strAsyncStruct}))]")
diff --git a/CodeGen/src/structs.py b/CodeGen/src/structs.py
index 6fb5cb46..e248bbd6 100644
--- a/CodeGen/src/structs.py
+++ b/CodeGen/src/structs.py
@@ -155,7 +155,13 @@ def parse(struct):
lines.append("\t[StructLayout(LayoutKind.Sequential)]")
break
- lines.append("\tpublic struct " + structname + " {")
+ # make struct implement an "ICallResultStruct" or something simliar, if
+ # this is a callback struct
+ strPotentialAsyncMarker = ""
+ if struct.asyncMarkerInterfaceName:
+ strPotentialAsyncMarker = f": {struct.asyncMarkerInterfaceName}"
+
+ lines.append("\tpublic struct " + structname + strPotentialAsyncMarker + " {")
lines.extend(insert_constructors(structname))
diff --git a/com.rlabrecque.steamworks.net/Runtime/CallbackMarkers.cs b/com.rlabrecque.steamworks.net/Runtime/CallbackMarkers.cs
new file mode 100644
index 00000000..b4514ae4
--- /dev/null
+++ b/com.rlabrecque.steamworks.net/Runtime/CallbackMarkers.cs
@@ -0,0 +1,20 @@
+// This file is provided under The MIT License as part of Steamworks.NET.
+// Copyright (c) 2013-2022 Riley Labrecque
+// Please see the included LICENSE.txt for additional information.
+
+// This file is automatically generated.
+// Changes to this file will be reverted when you update Steamworks.NET
+
+#if !(UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX || UNITY_STANDALONE_OSX || STEAMWORKS_WIN || STEAMWORKS_LIN_OSX)
+#define DISABLESTEAMWORKS
+#endif
+
+#if !DISABLESTEAMWORKS
+
+namespace Steamworks {
+ public interface ICallResultStruct { }
+
+ public interface ICallbackStruct { }
+}
+
+#endif // !DISABLESTEAMWORKS