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
182 changes: 100 additions & 82 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,100 @@
# AGENTS GUIDE — Assets/AirConsole Focus

The `airconsole-unity-plugin` project targets Unity 2022.3.x and ships the full AirConsole runtime, editor tooling, Android TV helpers, and WebGL controller templates. This guide is tailored to the contents under `Assets/AirConsole`.

## What Lives in Assets/AirConsole

- `scripts/Runtime`: Core API surface (`AirConsole.cs`), websocket/webview bridges (`WebsocketListener.cs`, `WebViewManager.cs`), runtime settings (`Settings.cs`, `AirconsoleRuntimeSettings.cs`, `NativeGameSizingSettings.cs`), logging (`AirConsoleLogger.cs`, `DebugLevel.cs`), platform runtime configurators, and Android plugin wrappers under `Runtime/Plugin/Android`.
- `scripts/Editor`: Custom inspectors/windows (`Inspector.cs`, `SettingWindow.cs`, `PlayMode.cs`, `SafeAreaTester.cs`, `WebListener.cs`), build automation (`BuildAutomation/*`), project maintenance checks (`ProjectMaintenance/*`), and plugin developer helpers (`PluginDevelopment/*`).
- `scripts/SupportCheck`: Unity version/platform validator ASMDEF used in-editor.
- `scripts/Tests`: ASMDEF-scoped EditMode, PlayMode, and Editor tests.
- `examples`: Sample scenes (`basic`, `pong`, `platformer`, `swipe`, `game-states`, `safe-area`, `translations`) for manual validation.
- `extras`: Controller template HTML and `HighScoreHelper.cs`.
- `plugins`: Managed dependencies (`Newtonsoft.Json.dll`, `websocket-sharp.dll`) plus Android native plugin payload under `plugins/Android`.
- `unity-webview`: Embedded WebView plugin with runtime/editor asmdefs and native binaries under `Plugins`.
- `unity-webview` is an imported external dependency. You are not allowed to alter it.
- Docs and misc: `Documentation_1.7.pdf`, `Documentation for AndroidTV.pdf`, `Upgrade_Plugin_Version.md`, `README.txt`, `airconsole.prefs`, and the distributable `airconsole-code.unitypackage`.

## Runtime Essentials

- **API + bridge**: `AirConsole.cs` exposes the public API; `WebsocketListener` routes JSON actions/events; `WebViewManager` coordinates the embedded webview. Add new events in both the listener and the API surface.
- **Config assets**: `AirconsoleRuntimeSettings.asset` and `NativeGameSizingSettings.asset` (in `scripts/Runtime/Resources`) hold defaults for ports, safe-area sizing, etc. Adjust via the editor UI instead of hardcoding.
- **Platform setup**: Implementations of `IRuntimeConfigurator` (`AndroidRuntimeConfigurator`, `WebGLRuntimeConfigurator`, `EditorRuntimeConfigurator`) handle platform-specific initialization. Extend these rather than branching deep in the API.
- **Android plugin wrappers**: `PluginManager`, `AndroidUnityUtils`, and callback helpers (`UnityPluginExecutionCallback`, `UnityPluginStringCallback`, `GenericUnityPluginCallback`, `UnityAndroidObjectProvider`) encapsulate Java bridge calls. Keep new native hooks consistent with these wrappers.
- **Logging & diagnostics**: Use `AirConsoleLogger` with `DebugLevel` enums to respect runtime debug settings.

## Editor & Build Tooling

- **UI/inspectors**: `SettingWindow`, `Inspector`, `PlayMode`, `SafeAreaTester`, and `WebListener` provide editor UI and simulator hooks. Prefer extending these instead of adding ad-hoc windows.
- **Build automation** (`scripts/Editor/BuildAutomation`):
- `PreBuildProcessing` and `PostBuildProcess` wrap pre/post hooks; post steps validate WebGL template AirConsole JS versions.
- `AndroidManifestProcessor`, `AndroidGradleProcessor`, `AndroidProjectProcessor`, `AndroidManifest`, and `AndroidXMLDocument` mutate generated Android projects/manifests. Use these helpers instead of manual IO.
- **Project maintenance** (`ProjectMaintenance`): `ProjectDependencyCheck`, `SemVerCheck`, and `ProjectConfigurationCheck` enforce Unity version and project settings; `ProjectPreferenceManager/ProjectPreferences` manage stored preferences; `ProjectUpgradeEditor` supports upgrade flows.
- **Plugin development helpers** (`PluginDevelopment`): `BuildHelper` hosts build/packaging entry points (Web/Android) and can auto-zip or auto-commit; `DevelopmentTools` includes additional packager utilities.

## Tests, Samples, Validation

- Tests live under `scripts/Tests` (EditMode/PlayMode/Editor asmdefs). Run via Unity Test Runner; some PlayMode tests expect Android as the active build target.
- Manual checks: leverage sample scenes in `examples` to verify controller flows, safe-area behavior, translations, and Android TV input.
- WebGL validation: keep `PostBuildProcess` version checks aligned with the AirConsole JS used in `Assets/WebGLTemplates/AirConsole-*`.

## Dependencies & Third-Party

- Managed DLLs: `Newtonsoft.Json.dll` and `websocket-sharp.dll` are under `plugins/` and referenced by runtime asmdefs.
- Embedded webview: `unity-webview` includes runtime/editor code plus native libs under `unity-webview/Plugins`.
- Android native pieces are under `plugins/Android`; ensure gradle/manifest processors remain compatible when updating them.

## Common Workflows

- **Add/extend an API event**: Update `WebsocketListener` to parse/route the action, expose it in `AirConsole`, and wire through logging; add tests where possible.
- **Adjust runtime defaults**: Modify `AirconsoleRuntimeSettings.asset` or `NativeGameSizingSettings.asset` (via editor windows). Avoid hardcoded constants in code.
- **Android manifest/Gradle edits**: Implement changes in `AndroidManifestProcessor`/`AndroidGradleProcessor`/`AndroidProjectProcessor`; ensure `useCustomMainManifest` stays enabled.
- **WebGL template/JS version bumps**: Update constants/regex in `PostBuildProcess`, refresh `Settings.RequiredMinimumVersion` if needed, and sync HTML in `Assets/WebGLTemplates/AirConsole-*`.
- **Packaging/exports**: Use `BuildHelper.BuildWeb()`, `BuildHelper.BuildAndroid()`, or `BuildHelper.BuildAndroidInternal()`; they run configuration checks and can zip outputs.

## Guardrails & Gotchas

- Conditional compilation is heavily used: `#if !DISABLE_AIRCONSOLE`, `UNITY_ANDROID`, `UNITY_EDITOR`, `UNITY_WEBGL`. Keep new code behind appropriate defines and asmdefs.
- Respect asmdef boundaries (`AirConsole.Runtime`, `AirConsole.Editor`, `AirConsole.SupportCheck`, `AirConsole.Examples`, `unity-webview`); place new files in matching folders.
- Embedded websocket/webview server underpins editor play; avoid breaking `WebsocketListener`/`WebViewManager` interactions (ports come from runtime settings).
- Safe-area handling is central for Android TV/Automotive—maintain `OnSafeAreaChanged` flows and avoid state changes before safe-area readiness.
- Build helper may auto-commit with `build: TIMESTAMP` when uncommitted changes exist; be mindful when running locally.

## Event Queue Architecture (Thread-Safe Callbacks)

The WebView plugin uses a thread-safe event queue to handle callbacks from native code (Android only at this point):

### Event Processing Lifecycle

Events are processed at multiple points to ensure timely delivery:

1. **`Update()`**: Primary drain point (every frame)
2. **`LateUpdate()`**: Secondary drain (end of frame)
3. **`FixedUpdate()`**: Tertiary drain (physics frame / fixed timestep / before rendering)
4. **`OnApplicationPause(false)`**: Flush on resume
5. **`OnDisable()`**: Flush before component teardown
6. **`OnApplicationQuit()`**: Final flush before app exit

## Additional References

- `Documentation_1.7.pdf` (setup/examples), `Documentation for AndroidTV.pdf`, and `Upgrade_Plugin_Version.md` for upgrade flows.
- Controller HTML template: `extras/controller-template.html`.
- Quick intro: `Assets/AirConsole/README.txt`; preferences file `airconsole.prefs`.
# airconsole-unity-plugin
## OVERVIEW
AirConsole SDK for Unity.
C# wrapper around the AirConsole browser API.
Android native bridge for Android builds.
WebGL JavaScript generation for browser builds.
Main targets: Android and WebGL.
Bridge languages: C#, Java or Kotlin, JavaScript.
Two message patterns exist.
Old pattern: polling through `GetMessage()`.
New pattern: queue based event delivery.
Prefer queue based delivery for new Android bridge behavior.
## ENTRY POINT
Main SDK entry: `Assets/AirConsole/AirConsole.cs`.
`AirConsole.cs` owns the singleton.
The singleton is the main public API surface.
Comment on lines +13 to +16
Unity scenes call this API for connection state, messages, device data, and platform actions.
Android bridge entry uses `AndroidJavaProxy`.
Native callbacks enter Unity through proxy handlers.
WebGL entry uses generated JavaScript.
Generated JS exposes the runtime browser interface for Unity WebGL builds.
## ARCHITECTURE
Old Android message path:
1. Native side stores incoming messages.
2. Unity polls with `GetMessage()`.
3. `UnitySendMessageDispatcher` forwards payloads into Unity.
4. C# parses payloads and raises SDK callbacks.
New Android message path:
1. Native side calls an `AndroidJavaProxy` callback.
2. Proxy receives payloads off the Unity main thread.
3. Proxy writes work items into a `ConcurrentQueue`.
4. Unity main thread drains the queue.
5. SDK events fire during main thread processing.
WebGL message path:
1. Build postprocess generates JS from C# reflection.
2. Runtime JS binds Unity calls to AirConsole browser API calls.
3. Browser callbacks route back into Unity.
## ANDROID BRIDGE
Android bridge code lives under `Assets/AirConsole/Plugins/Android/`.
`PluginManager` initializes native bridge state.
Comment on lines +38 to +40
`PluginManager` connects Unity runtime and Android plugin code.
`AndroidJavaProxy` handles messages from native code.
Proxy handlers must stay small.
Proxy handlers must not call Unity APIs directly from background threads.
Use the main thread queue for message delivery.
Use `ConcurrentQueue` for thread safe handoff.
Drain queued actions or messages from Unity main thread update flow.
Preserve payload shape when moving between native and C#.
## WEBGL EXPORT
Build postprocess generates `airconsole-unity-plugin.js`.
Generation uses C# reflection.
Generated JS mirrors the callable SDK surface needed by WebGL builds.
Runtime JS interface talks to the AirConsole browser API.
Unity WebGL calls route through generated JS functions.
Browser events route back into Unity objects.
Change the generator or C# source instead of hand editing generated JS.
## STRUCTURE
`Assets/AirConsole/` contains the main SDK.
`Assets/AirConsole/AirConsole.cs` contains the singleton and main public API.
`Assets/AirConsole/Plugins/Android/` contains native bridge code and Android plugin assets.
`Assets/AirConsole/Editor/` contains editor tooling and build postprocessing.
`Assets/AirConsole/Editor/PostprocessBuild` is the build generation area.
Sample scenes live under the AirConsole assets tree.
Comment on lines +60 to +63
## WHERE TO LOOK
Main SDK: `Assets/AirConsole/AirConsole.cs`.
Android bridge: `Assets/AirConsole/Plugins/Android/`.
Build generation: `Assets/AirConsole/Editor/PostprocessBuild`.
Generated WebGL interface and sample integration: `airconsole-unity-plugin.js`, sample scenes.
## BUILD POSTPROCESSING
Unity build postprocess auto runs after supported builds.
It generates Android manifests when needed.
It handles AndroidX setup.
It copies Android AAR files into the build output.
It links iOS frameworks for supported exports.
It generates WebGL JavaScript interface files.
It can export `.unitypackage` distribution packages.
## TESTING
Automated tests are limited.
Use Unity Test Runner when relevant.
Most confidence comes from integration testing.
Run sample scenes for message flow checks.
Test Android bridge behavior on Android builds.
Test WebGL behavior in exported WebGL builds.
Verify old polling behavior when touching legacy paths.
Verify queue based behavior when touching new bridge paths.
## EXPORTS
Distribution output is a `.unitypackage`.
The package includes AirConsole `Assets` and all required `Plugins` content.
The package must include Android bridge assets and WebGL runtime generation support.
## COMMANDS
Unity build: run from Unity Editor or configured Unity batchmode build.
PostprocessBuild auto runs during Unity build.
Export package: use Unity export package workflow for `.unitypackage`.
Run tests: use Unity Test Runner for EditMode and PlayMode suites.
## FORBIDDEN
NEVER hardcode device IDs.
NO platform specific code outside `Plugins/`.
Do not bypass the main thread queue for Android callbacks.
Do not call Unity APIs directly from Android background callbacks.
Do not edit generated WebGL JS when generator changes are required.
26 changes: 26 additions & 0 deletions Assets/AirConsole/AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Assets/AirConsole

This subtree contains the shipped Unity runtime, editor tooling, examples, and native wrappers.

## Local Focus Areas

- Runtime API and bridges: `scripts/Runtime/`
- Editor tooling and build processors: `scripts/Editor/`
- Automated tests: `scripts/Tests/`
- Examples and manual smoke scenes: `examples/`

## Local Invariants

- Extend platform-specific behavior through the existing configurators and Android wrapper classes instead of scattering `#if UNITY_*` checks.
- Keep asmdef boundaries intact (`AirConsole.Runtime`, `AirConsole.Editor`, `AirConsole.SupportCheck`, examples/tests).
- Preserve safe-area and main-thread callback behavior when touching Android or WebView flows.
- Treat `unity-webview/` as vendored unless the task explicitly belongs there.

## Common Checks

- Add matching runtime/editor tests where feasible.
- For manifest or Gradle output changes, use the existing build processors in `scripts/Editor/BuildAutomation/`.

## Learnings

- _None yet._
45 changes: 23 additions & 22 deletions Assets/AirConsole/examples/AirConsole.Examples.asmdef
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
{
"name": "AirConsole.Examples",
"rootNamespace": "NDream.AirConsole.Examples",
"references": [
"AirConsole.Runtime"
],
"includePlatforms": [
"Android",
"Editor",
"WebGL"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll"
],
"autoReferenced": true,
"defineConstraints": [
"UNITY_2022_3_OR_NEWER"
],
"versionDefines": [],
"noEngineReferences": false
"name": "AirConsole.Examples",
"rootNamespace": "NDream.AirConsole.Examples",
"references": [
"AirConsole.Runtime",
"Unity.TextMeshPro"
],
"includePlatforms": [
"Android",
"Editor",
"WebGL"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll"
],
"autoReferenced": true,
"defineConstraints": [
"UNITY_2022_3_OR_NEWER"
],
"versionDefines": [],
"noEngineReferences": false
}
2 changes: 1 addition & 1 deletion Assets/AirConsole/examples/basic/controller.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<script src="https://www.airconsole.com/api/airconsole-1.10.0.js"></script>
<script src="https://www.airconsole.com/api/airconsole-1.11.0.js"></script>

<style type=text/css>

Expand Down
8 changes: 8 additions & 0 deletions Assets/AirConsole/examples/configuration.meta

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,66 @@
namespace NDream.AirConsole.Examples {
using UnityEngine;
using Newtonsoft.Json.Linq;

public class ExampleConfigurationLogic : MonoBehaviour {
public TMPro.TMP_Text logWindow;

#if !DISABLE_AIRCONSOLE
private void Awake() {
AirConsole.instance.onReady += OnReady;
AirConsole.instance.onConnect += OnConnect;
logWindow.text = "Waiting for AirConsole...\n";
}

private void OnReady(string code) {
logWindow.text = "AirConsole ready!\n\n";

JToken config = AirConsole.instance.GetConfiguration();
if (config == null) {
logWindow.text += "Configuration: not provided by platform\n";
return;
}

logWindow.text += "=== Platform Configuration ===\n";

// Video format support
JToken formats = config["supportedVideoFormats"];
if (formats != null) {
logWindow.text += "Video Formats: " + formats + "\n";
}

// Graphics quality tier
JToken tier = config["graphicsQualityTier"];
if (tier != null) {
logWindow.text += "Graphics Tier: " + (string)tier + "\n";
}

// Video capability flags
JToken transparent = config["transparentVideoSupported"];
if (transparent != null) {
logWindow.text += "Transparent Video: " + (bool)transparent + "\n";
}

JToken unityVideo = config["unityVideoSupported"];
if (unityVideo != null) {
logWindow.text += "Unity Video: " + (bool)unityVideo + "\n";
}

// Demonstrate safe access for future/optional fields
JToken touchScreen = config["touchScreen"];
logWindow.text += "Touch Screen: " + (touchScreen != null ? touchScreen.ToString() : "N/A") + "\n";
}

private void OnConnect(int deviceId) {
logWindow.text += "Device " + deviceId + " connected\n";
}

private void OnDestroy() {
if (AirConsole.instance != null) {
AirConsole.instance.onReady -= OnReady;
AirConsole.instance.onConnect -= OnConnect;
}
}
#endif
}
}

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,41 @@

<html>
<head>
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1.0, maximum-scale=1.0"/>
<script src="https://www.airconsole.com/api/airconsole-1.11.0.js"></script>

<style type=text/css>
html, body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
background: #1a1a1a;
}

#content {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
font-family: Arial, sans-serif;
font-size: 24px;
color: white;
text-align: center;
padding: 20px;
box-sizing: border-box;
}
</style>

<script type="text/javascript">
function App() {
var me = this;
me.airconsole = new AirConsole({"orientation": "portrait"});
}
</script>

</head>
<body onload="window.app = new App()">
<div id="content">Look at the screen!</div>
</body>
</html>
Loading
Loading