Skip to content

Commit 0bb49e2

Browse files
nattb8claude
andcommitted
feat(audience): auto-collect Steam user ID and detect Steam platform
When Steamworks.NET or Facepunch.Steamworks is present, the SDK now: - Calls Identify() with the logged-in SteamID64 automatically at Init - Sets distribution_platform = "steam" in game_launch properties Detection uses C# reflection so there is no hard compile-time dependency; games without Steamworks are completely unaffected. All four Steamworks install methods are supported: - UPM via OpenUPM (com.rlabrecque.steamworks.net) - Precompiled .dll plugin (assembly name Steamworks.NET) - Source files compiled into Assembly-CSharp - Facepunch.Steamworks DLL plugin (platform-specific assembly names) link.xml entries for all Steamworks assemblies ensure IL2CPP does not strip the types the SDK reaches via reflection. Entries for absent assemblies are silently ignored, so non-Steam games are unaffected. The sample app gains: - Steamworks.NET via OpenUPM for local Steam testing - MacOSBuilder editor script for command-line standalone builds - StandaloneAutoTest headless harness (--auto-test <key> CLI flag) - steam_appid.txt (Valve Spacewar app 480) for Steam overlay in dev Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 42e8f0b commit 0bb49e2

14 files changed

Lines changed: 367 additions & 244 deletions

File tree

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#nullable enable
2+
3+
using System;
4+
using UnityEditor;
5+
using UnityEngine;
6+
7+
namespace Immutable.Audience.Samples.SampleApp.Editor
8+
{
9+
// Invoked by CI / local debugging via:
10+
// Unity -batchmode -buildTarget StandaloneOSX \
11+
// -executeMethod Immutable.Audience.Samples.SampleApp.Editor.MacOSBuilder.Build \
12+
// -quit
13+
//
14+
// Optional CLI arg:
15+
// --buildPath <path> Output path for the .app (default: Builds/macOS/SampleApp.app)
16+
internal static class MacOSBuilder
17+
{
18+
private const string DefaultBuildPath = "Builds/macOS/SampleApp.app";
19+
20+
public static void Build()
21+
{
22+
string buildPath = GetArgValue("--buildPath") ?? DefaultBuildPath;
23+
24+
var options = new BuildPlayerOptions
25+
{
26+
scenes = new[] { "Assets/SampleApp/Scenes/SampleApp.unity" },
27+
locationPathName = buildPath,
28+
target = BuildTarget.StandaloneOSX,
29+
targetGroup = BuildTargetGroup.Standalone,
30+
options = BuildOptions.None,
31+
};
32+
33+
Debug.Log($"[MacOSBuilder] Building → {buildPath}");
34+
35+
var report = BuildPipeline.BuildPlayer(options);
36+
var summary = report.summary;
37+
38+
if (summary.result == UnityEditor.Build.Reporting.BuildResult.Succeeded)
39+
Debug.Log($"[MacOSBuilder] Build succeeded ({summary.totalSize / 1024 / 1024} MB).");
40+
else
41+
throw new Exception($"[MacOSBuilder] Build failed: {summary.result}");
42+
}
43+
44+
private static string? GetArgValue(string key)
45+
{
46+
var args = Environment.GetCommandLineArgs();
47+
for (int i = 0; i < args.Length - 1; i++)
48+
if (args[i] == key) return args[i + 1];
49+
return null;
50+
}
51+
}
52+
}

examples/audience/Assets/Editor/MacOSBuilder.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#nullable enable
2+
3+
#if UNITY_STANDALONE_OSX || UNITY_STANDALONE_WIN || UNITY_STANDALONE_LINUX
4+
5+
using System;
6+
using System.Threading.Tasks;
7+
using UnityEngine;
8+
9+
namespace Immutable.Audience.Samples.SampleApp
10+
{
11+
// Headless auto-test for standalone builds only. Activated by passing:
12+
// --auto-test <publishableKey>
13+
// on the command line. Injects itself at runtime; no scene changes needed.
14+
// Runs Init (Full consent) → Track → Flush → Quit.
15+
public class StandaloneAutoTest : MonoBehaviour
16+
{
17+
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
18+
private static void Bootstrap()
19+
{
20+
if (string.IsNullOrEmpty(GetArgValue("--auto-test"))) return;
21+
var go = new GameObject("[AutoTest]");
22+
DontDestroyOnLoad(go);
23+
go.AddComponent<StandaloneAutoTest>();
24+
}
25+
26+
private async void Start()
27+
{
28+
var key = GetArgValue("--auto-test")!;
29+
Debug.Log("[AutoTest] Starting headless test run");
30+
31+
// If Facepunch.Steamworks is present, call SteamClient.Init before the SDK runs.
32+
// Games do this themselves; the SDK cannot call it because the appId is unknown.
33+
TryInitFacepunch();
34+
35+
var config = new AudienceConfig
36+
{
37+
PublishableKey = key,
38+
Consent = ConsentLevel.Full,
39+
Debug = true,
40+
TestMode = true,
41+
};
42+
43+
ImmutableAudience.Init(config);
44+
Debug.Log("[AutoTest] Init done, consent=Full");
45+
46+
ImmutableAudience.Track("auto_test_steam_detection");
47+
Debug.Log("[AutoTest] Track sent");
48+
49+
await Task.Delay(2000);
50+
51+
try
52+
{
53+
await ImmutableAudience.FlushAsync();
54+
Debug.Log("[AutoTest] Flush done");
55+
}
56+
catch (Exception ex)
57+
{
58+
Debug.LogError("[AutoTest] Flush failed: " + ex.Message);
59+
}
60+
61+
await Task.Delay(1000);
62+
Debug.Log("[AutoTest] Done. Check BQ for auto_test_steam_detection + identify.");
63+
Application.Quit();
64+
}
65+
66+
// Initialises Facepunch.Steamworks via reflection so the test harness works
67+
// without a direct compile-time dependency. No-ops if Facepunch is not present.
68+
private static void TryInitFacepunch()
69+
{
70+
var steamClientType =
71+
System.Type.GetType("Steamworks.SteamClient, Facepunch.Steamworks.Posix")
72+
?? System.Type.GetType("Steamworks.SteamClient, Facepunch.Steamworks.Win64")
73+
?? System.Type.GetType("Steamworks.SteamClient, Facepunch.Steamworks.Win32");
74+
75+
if (steamClientType == null) return;
76+
77+
try
78+
{
79+
var initMethod = steamClientType.GetMethod("Init", new Type[] { typeof(uint), typeof(bool) });
80+
initMethod?.Invoke(null, new object[] { (uint)480, false });
81+
Debug.Log("[AutoTest] Facepunch SteamClient.Init(480) called");
82+
}
83+
catch (Exception ex)
84+
{
85+
Debug.LogWarning("[AutoTest] Facepunch SteamClient.Init failed: " + ex.Message);
86+
}
87+
}
88+
89+
private static string? GetArgValue(string key)
90+
{
91+
var args = Environment.GetCommandLineArgs();
92+
for (int i = 0; i < args.Length - 1; i++)
93+
if (args[i] == key) return args[i + 1];
94+
return null;
95+
}
96+
}
97+
}
98+
99+
#endif

examples/audience/Assets/SampleApp/Scripts/StandaloneAutoTest.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/audience/Assets/SteamworksNET.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

examples/audience/Assets/link.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,11 @@ hooks fire under IL2CPP with stripping High.
2727
<type fullname="System.IO.Compression.GZipStream" preserve="all" />
2828
<type fullname="System.IO.Compression.CompressionLevel" preserve="all" />
2929
</assembly>
30+
31+
<!-- Steam auto-detection; mirrors SDK link.xml. Ignored if Steamworks is not present. -->
32+
<assembly fullname="com.rlabrecque.steamworks.net" preserve="all" />
33+
<assembly fullname="Steamworks.NET" preserve="all" />
34+
<assembly fullname="Facepunch.Steamworks.Posix" preserve="all" />
35+
<assembly fullname="Facepunch.Steamworks.Win64" preserve="all" />
36+
<assembly fullname="Facepunch.Steamworks.Win32" preserve="all" />
3037
</linker>

examples/audience/Packages/manifest.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
{
2+
"scopedRegistries": [
3+
{
4+
"name": "OpenUPM",
5+
"url": "https://package.openupm.com",
6+
"scopes": ["com.rlabrecque"]
7+
}
8+
],
29
"dependencies": {
310
"com.immutable.audience": "file:../../../src/Packages/Audience",
11+
"com.rlabrecque.steamworks.net": "20.2.0",
412
"com.unity.test-framework": "1.4.5",
513
"com.unity.modules.androidjni": "1.0.0",
614
"com.unity.modules.audio": "1.0.0",

0 commit comments

Comments
 (0)