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 a007b5d2..2d2950b3 100644
--- a/CodeGen/src/interfaces.py
+++ b/CodeGen/src/interfaces.py
@@ -850,6 +850,28 @@ 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
+
+ # 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}))]")
+
+
g_Output.append("\t\tpublic static " + wrapperreturntype + " " + func.name.rstrip("0") + "(" + wrapperargs + ") {")
g_Output.extend(functionBody)
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
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