@uptimizr/unreal 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,103 @@
1
+ // Uptimizr — Unreal Engine (web export) telemetry bridge shim (copy-in asset).
2
+ //
3
+ // This is the engine-side half of the `@uptimizr/unreal` connector (ADR 0045). It is a
4
+ // thin, dumb Emscripten shim: each frame it reads the active `APlayerCameraManager` pose
5
+ // and FPS, and (on demand) a raycast pick, then pushes the RAW values across the JS
6
+ // interop boundary to the browser-side connector exposed on `window.__uptimizr_unreal__`.
7
+ //
8
+ // It carries NO analytics logic, NO identifiers, and NO schema knowledge. It performs NO
9
+ // coordinate math: it pushes Unreal's native world-space values (left-handed, z-up,
10
+ // centimeters) unchanged. The JS connector owns the single normalization path
11
+ // (z-up -> y-up rebase, cm -> m scale) so every engine stays consistent.
12
+ //
13
+ // Feasibility (ADR 0045 / issue #112): Epic has no official UE5 HTML5/WASM target (it was
14
+ // deprecated after UE 4.24) and Pixel Streaming is server-side. This shim therefore targets
15
+ // the real, Emscripten-based, client-side web exports that DO exist and render into a
16
+ // `<canvas>`: the community UE4.24-4.27 HTML5 forks (ufna/UE-HTML5,
17
+ // SpeculativeCoder/UnrealEngine-HTML5-ES3) and the experimental Wonder Interactive /
18
+ // SimplyStream UE5.1-5.4 WASM+WebGPU toolchain. All are Emscripten, so the EM_JS / cwrap
19
+ // interop this shim relies on is available by construction. Outside Emscripten (e.g. the
20
+ // desktop editor) every entry point compiles to a no-op so it is safe to leave wired in.
21
+ //
22
+ // Privacy (ADR 0003): only low-cardinality, non-PII telemetry crosses the bridge — poses,
23
+ // FPS, and developer-assigned object names. The shim MUST NOT invent identifiers or forward
24
+ // raw input text.
25
+
26
+ #pragma once
27
+
28
+ #include "CoreMinimal.h"
29
+
30
+ class UWorld;
31
+
32
+ /**
33
+ * Wire-protocol version this shim was authored against. It MUST match the JS connector's
34
+ * `BRIDGE_PROTOCOL_VERSION` (see `@uptimizr/web-export`). `FUptimizrTelemetry::Initialize`
35
+ * asserts the live bridge reports the same value before pushing anything.
36
+ */
37
+ #define UPTIMIZR_BRIDGE_PROTOCOL_VERSION 1
38
+
39
+ /**
40
+ * Per-frame telemetry sampler for an Unreal web export. Construct one (or use the global
41
+ * accessed by the `extern "C"` entry points below), `Initialize()` once the export's host
42
+ * page and the `@uptimizr/unreal` connector are up, then call `Tick()` every frame from any
43
+ * actor/component tick. Push picks from your own click/interaction handler via `ReportPick`
44
+ * or the convenience `TraceAndReportPick`.
45
+ */
46
+ class FUptimizrTelemetry
47
+ {
48
+ public:
49
+ /**
50
+ * Read the live bridge's `protocolVersion` and assert it equals
51
+ * `UPTIMIZR_BRIDGE_PROTOCOL_VERSION`. Returns false (and stays disabled) on mismatch or
52
+ * when no bridge is present, so a stale shim never pushes against an incompatible API.
53
+ */
54
+ bool Initialize();
55
+
56
+ /** True once `Initialize()` has succeeded against a compatible bridge. */
57
+ bool IsInitialized() const { return bInitialized; }
58
+
59
+ /**
60
+ * Sample the active camera pose and accumulate FPS, pushing a pose every frame and a
61
+ * perf sample roughly once per second. Pass the world your gameplay runs in and the
62
+ * frame's delta seconds. No-op until `Initialize()` succeeds.
63
+ */
64
+ void Tick(UWorld* World, float DeltaSeconds);
65
+
66
+ /**
67
+ * Push a developer-named object and the RAW world-space hit point (cm, z-up,
68
+ * left-handed). Call this from your own interaction code when a pick resolves.
69
+ */
70
+ void ReportPick(const FString& ObjectName, const FVector& WorldHitPoint);
71
+
72
+ /**
73
+ * Convenience: line-trace forward from the active camera and, on a hit, report the hit
74
+ * actor's name + impact point via {@link ReportPick}. Returns true if something was hit.
75
+ */
76
+ bool TraceAndReportPick(UWorld* World, float MaxDistanceCm = 1.0e5f);
77
+
78
+ /** Stop pushing; safe to call repeatedly. */
79
+ void Shutdown();
80
+
81
+ private:
82
+ bool bInitialized = false;
83
+
84
+ // FPS / long-frame accumulation across a ~1s reporting window.
85
+ float PerfWindowSeconds = 0.0f;
86
+ int32 PerfWindowFrames = 0;
87
+ int32 PerfWindowLongFrames = 0;
88
+ };
89
+
90
+ /** Access the process-wide telemetry instance the `extern "C"` entry points drive. */
91
+ FUptimizrTelemetry& UptimizrTelemetry();
92
+
93
+ // cwrap / ccall entry points — let the JS host drive init/teardown by symbol name if it
94
+ // prefers (e.g. `Module.cwrap('UptimizrBridge_Init', 'number', [])`). The per-frame Tick is
95
+ // intentionally NOT exported: drive it from C++ where the world/delta are already in hand.
96
+ extern "C"
97
+ {
98
+ /** Initialize the global sampler. Returns 1 on success, 0 on protocol mismatch / no bridge. */
99
+ int UptimizrBridge_Init();
100
+
101
+ /** Shut the global sampler down. */
102
+ void UptimizrBridge_Shutdown();
103
+ }
@@ -0,0 +1,26 @@
1
+ import type { EngineBridge, NativeFrame, TrackWebExportOptions, WebExportCollectorOptions, WebExportSession } from "@uptimizr/web-export";
2
+ import type { Collector } from "@uptimizr/sdk-core";
3
+ /**
4
+ * Unreal's native world coordinate frame: left-handed, **z-up**, **centimeters**
5
+ * (`unitScale: 100` = 100 world units per meter).
6
+ */
7
+ export declare const UNREAL_FRAME: NativeFrame;
8
+ /** The engine id used for connector provenance and the collector name. */
9
+ export declare const UNREAL_CONNECTOR_NAME = "unreal";
10
+ export type UnrealCollectorOptions = Omit<WebExportCollectorOptions, "name" | "frame">;
11
+ export type TrackUnrealOptions = Omit<TrackWebExportOptions, "name" | "frame">;
12
+ /**
13
+ * The Unreal collector — register it with an sdk-core client via `client.use(...)`.
14
+ * Wires the JS-only tier and exposes the engine bridge (default global
15
+ * `window.__uptimizr_unreal__`) for the engine-side shim. See the package docs for
16
+ * the web-target feasibility caveat.
17
+ */
18
+ export declare function unrealCollector(options?: UnrealCollectorOptions): Collector;
19
+ /**
20
+ * One-call Unreal integration: create a client, register {@link unrealCollector},
21
+ * and start the session with Unreal's connector provenance (ADR 0018). Returns the
22
+ * client and the {@link EngineBridge} the Unreal shim pushes through.
23
+ */
24
+ export declare function trackUnreal(options: TrackUnrealOptions): WebExportSession;
25
+ export type { EngineBridge };
26
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EACX,qBAAqB,EACrB,yBAAyB,EACzB,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,YAAY,EAAE,WAAiE,CAAC;AAE7F,0EAA0E;AAC1E,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAE9C,MAAM,MAAM,sBAAsB,GAAG,IAAI,CAAC,yBAAyB,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AACvF,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,qBAAqB,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;AAE/E;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,SAAS,CAE/E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,gBAAgB,CAEzE;AAED,YAAY,EAAE,YAAY,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,50 @@
1
+ /**
2
+ * `@uptimizr/unreal` — the Unreal Engine (web export) connector for Uptimizr
3
+ * (ADR 0045). **Best-effort, pending a viable WASM/HTML5 target.**
4
+ *
5
+ * Epic deprecated the official HTML5/Emscripten target after UE 4.24, and Pixel
6
+ * Streaming renders server-side (no client WASM scene to read), so the bridged tier
7
+ * does not fit a stock modern Unreal build today. The package and bridge contract
8
+ * are defined now so they drop in cleanly if a community HTML5 fork or a future
9
+ * official web target appears. The **JS-only tier works on any web export** that
10
+ * renders into a `<canvas>`.
11
+ *
12
+ * This connector is **two-part**:
13
+ *
14
+ * - a **JS-only tier** (this package, no engine code) — pointer heatmaps, rAF FPS,
15
+ * and error capture straight from the canvas DOM; and
16
+ * - a **bridged tier** — a thin engine-side shim (an Emscripten `EM_JS` / `cwrap`
17
+ * shim from the C++ web target, see `bridge/`) pushes camera pose / picks / perf
18
+ * over the versioned {@link EngineBridge}.
19
+ *
20
+ * Unreal's native world frame is **left-handed, z-up, centimeters**. It is the only
21
+ * engine that exercises the non-`y` up-axis and non-1 unit-scale paths: world-space
22
+ * payloads are rebased z-up → y-up **and** scaled cm → m before reaching the
23
+ * canonical wire frame (ADR 0018 / ADR 0045 §5).
24
+ */
25
+ import { trackWebExport, webExportCollector } from "@uptimizr/web-export";
26
+ /**
27
+ * Unreal's native world coordinate frame: left-handed, **z-up**, **centimeters**
28
+ * (`unitScale: 100` = 100 world units per meter).
29
+ */
30
+ export const UNREAL_FRAME = { handedness: "left", upAxis: "z", unitScale: 100 };
31
+ /** The engine id used for connector provenance and the collector name. */
32
+ export const UNREAL_CONNECTOR_NAME = "unreal";
33
+ /**
34
+ * The Unreal collector — register it with an sdk-core client via `client.use(...)`.
35
+ * Wires the JS-only tier and exposes the engine bridge (default global
36
+ * `window.__uptimizr_unreal__`) for the engine-side shim. See the package docs for
37
+ * the web-target feasibility caveat.
38
+ */
39
+ export function unrealCollector(options = {}) {
40
+ return webExportCollector({ ...options, name: UNREAL_CONNECTOR_NAME, frame: UNREAL_FRAME });
41
+ }
42
+ /**
43
+ * One-call Unreal integration: create a client, register {@link unrealCollector},
44
+ * and start the session with Unreal's connector provenance (ADR 0018). Returns the
45
+ * client and the {@link EngineBridge} the Unreal shim pushes through.
46
+ */
47
+ export function trackUnreal(options) {
48
+ return trackWebExport({ ...options, name: UNREAL_CONNECTOR_NAME, frame: UNREAL_FRAME });
49
+ }
50
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAU1E;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAgB,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,CAAC;AAE7F,0EAA0E;AAC1E,MAAM,CAAC,MAAM,qBAAqB,GAAG,QAAQ,CAAC;AAK9C;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkC,EAAE;IAClE,OAAO,kBAAkB,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAA2B;IACrD,OAAO,cAAc,CAAC,EAAE,GAAG,OAAO,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;AAC1F,CAAC"}