Skip to content

feat: Unity client SDK (continuation of #1105)#1516

Open
ChiragAgg5k wants to merge 139 commits intomasterfrom
unity-client-sdk-continued
Open

feat: Unity client SDK (continuation of #1105)#1516
ChiragAgg5k wants to merge 139 commits intomasterfrom
unity-client-sdk-continued

Conversation

@ChiragAgg5k
Copy link
Copy Markdown
Member

Summary

This PR continues the work started by @Fellmonkey in #1105 to add comprehensive Unity SDK support to the SDK generator.

What was done

  • Rebased/fetched the original unity-client-sdk branch from Unity client sdk #1105
  • Created a new branch unity-client-sdk-continued preserving all original commits from the community PR
  • Merged latest master and resolved conflicts (notably in templates/dotnet/Package/Models/Model.cs.twig)

Original PR content (from #1105)

  • Unity Language Implementation: Introduces a new Unity language class (src/SDK/Language/Unity.php) that extends the base Language class, providing Unity-specific type mappings, keywords, and code generation logic for C# in Unity environment.
  • Unity Template System: Adds a complete set of Unity-specific templates under templates/unity/Assets/ including:
    • Runtime components (Client, Services, Models, Enums, etc.)
    • Editor tools (Setup Assistant, Setup Window)
    • Unity project files (assembly definitions, project settings)
    • Required .NET libraries for Unity compatibility
  • Automated Testing Integration: Introduces Unity2021 test support with:
    • Unity2021Test.php test class that integrates with the existing test framework
    • Unity test source files (Tests.cs, Tests.asmdef) for comprehensive SDK testing
    • Docker-based Unity CI testing using unityci/editor:ubuntu-2021.3.45f1-base-3.1.0
  • CI/CD Integration: Updates the GitHub Actions workflow to:
    • Include Unity2021 in the test matrix alongside other SDK platforms
    • Set up the UNITY_LICENSE environment variable for Unity Editor automation
    • Enable automated testing of the Unity SDK in the CI pipeline
  • Unity Project Structure: Implements proper Unity package structure with:
    • Assets organized under Assets/Runtime/ and Assets/Editor/
    • Required Unity project settings and manifest files

Changes from original PR

  • Resolved merge conflicts with current master
  • Preserved all original author commits and attribution

Closes #1105

Moved Unity SDK template files from 'templates/unity/Runtime' and 'templates/unity/Editor' to 'templates/unity/Assets/Runtime' and 'templates/unity/Assets/Editor' for better alignment with Unity project conventions. Updated getFiles() in Unity.php to reflect new paths and added support for copying plugin DLLs and project settings. Improved file upload logic in Client.cs.twig to handle streams and byte arrays more robustly, and removed Unity-specific logging from Exception.cs.twig. Minor fixes in Realtime.cs.twig and Role.cs.twig for namespace and async handling.
Introduces Unity2021 test support by adding a Unity2021Test.php, Unity test source files, and updating the GitHub Actions workflow to include Unity2021 in the test matrix and set the UNITY_LICENSE environment variable. This enables automated testing for the Unity SDK within the CI pipeline.
Fellmonkey and others added 19 commits January 18, 2026 14:34
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Introduce centralized property conversion and mapping helpers for the .NET SDK generator and update model template to use them.

Changes:
- Add Twig filters: propertyAssignment and toMapValue.
- Make getPropertyType optionally return non-fully-qualified names.
- Replace inline parsing logic with new methods: getPropertyName, getResolvedPropertyName, getPropertyAssignment, convertValue, getToMapExpression. These handle enums, sub-schemas, arrays, primitive conversions and null-safety in a unified way.
- Simplify getFunctions() implementation to delegate to the new helpers.
- Update templates/dotnet/Package/Models/Model.cs.twig to use the new filters (propertyAssignment, toMapValue) and clean up From/ToMap generation.

Reason: centralizes and standardizes property (de)serialization logic, improves null handling, supports property overrides, and simplifies the model template.
Add query support and improve realtime subscription handling; refactor Channel API to use nullable IDs and introduce IChannelValue.

- Realtime: support per-subscription queries, normalize channel/query inputs, track subscription slot ↔ id mappings, route messages by subscription id when present, and include queries in websocket URL. Handle pending socket rebuilds and populate subscription maps on connect.
- Channel: change Normalize to accept null, use null as default for ID parameters instead of "*", add IChannelValue interface and make IActionable inherit it, remove old Function.Execution pattern and expose Function/Execution as channel values. Add Account/Documents/Rows/Files/Executions/Teams/Memberships helpers.
- Tests: add helper WaitForRealtimeMessage and update realtime and Channel-related test calls to match the new APIs.

These changes enable more flexible realtime queries and simplify channel construction semantics.
# Conflicts:
#	templates/dotnet/Package/Models/Model.cs.twig
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 8, 2026

Greptile Summary

This PR continues and merges community PR #1105, adding a complete Unity client SDK to the generator — including a Unity language class, ~30 Unity-specific C# templates, a full Unity project scaffold, CI integration, and test infrastructure (~7,274 lines added).

  • Unity language class and templates: Unity.php extends DotNet, overriding file mappings for Unity's asset layout; templates cover the HTTP client, realtime WebSocket, cookie management, editor setup tools, and service generation.
  • DotNet.php refactoring: Extracts getPropertyAssignment / getToMapExpression / getPropertyName helpers and exposes them as Twig filters (propertyAssignment, toMapValue), now used in RequestModel.cs.twig.
  • CI and testing: Adds Unity2021 to the test matrix using a Docker-based Unity Editor image, with UNITY_LICENSE supplied via GitHub secrets.

Confidence Score: 3/5

Several open defects across the core HTTP client and realtime templates would cause data corruption or silent auth failures in production.

The chunked-upload bytes path sends one byte fewer than the Content-Range header declares, corrupting every multi-chunk upload for that source type. The stream ReadAsync is not guarded against partial reads, padding the final chunk with stale buffer bytes. The realtime connected-message handler accesses data.User without a null guard after using data?.Subscriptions one line above, silently skipping fallback authentication when data is null. The cookie header is written to Debug.Log in plain text on every non-WebGL request. The UNITY_TEST_MODE global leaks across tests, and getPropertyAssignment defaults required to false while the surrounding helpers default to true, producing mismatched nullability in generated model code.

templates/unity/Assets/Runtime/Core/Client.cs.twig (chunked upload and cookie logging), templates/unity/Assets/Runtime/Realtime.cs.twig (null guard on connected data), and src/SDK/Language/DotNet.php (inconsistent required default in getPropertyAssignment).

Important Files Changed

Filename Overview
src/SDK/Language/Unity.php New Unity language class extending DotNet; uses a $GLOBALS['UNITY_TEST_MODE'] flag to exclude files during testing — the global is never reset after the test method returns, risking cross-test contamination.
src/SDK/Language/DotNet.php Adds propertyAssignment / toMapValue Twig filters and refactors type helpers; getPropertyAssignment defaults required to false while getToMapExpression and sub_schema default to true, producing mismatched nullability between the generated From and ToMap paths.
templates/unity/Assets/Runtime/Core/Client.cs.twig Core HTTP client for Unity; contains a cookie-header debug log that exposes session tokens in plain text, a chunked-upload bytes path that sends one byte fewer than the declared Content-Range, a stream ReadAsync that doesn't handle partial reads on the last chunk, and a dead null-check after a pattern-match guard.
templates/unity/Assets/Runtime/Realtime.cs.twig Realtime WebSocket client; HandleConnectedMessage accesses data.User directly without a null guard on data despite using data?.Subscriptions one block above, causing a silent failure of SendFallbackAuthentication when data is null.
tests/Unity2021Test.php Test class for Unity SDK; sets $GLOBALS['UNITY_TEST_MODE'] in testHTTPSuccess but never unsets it, allowing the flag to leak to subsequent test runs in the same process.
.github/workflows/tests.yml Adds Unity2021 to the CI test matrix; places UNITY_LICENSE in the top-level env block, exposing the secret to all jobs in the workflow rather than scoping it to the Unity step alone.
templates/unity/Packages/manifest.json Unity package manifest; references UniTask and NativeWebSocket via unpinned git URLs — reproducible on initial install due to the accompanying lock file, but lock-file regeneration can silently advance either dependency to a breaking version.
templates/unity/Assets/Runtime/Core/CookieContainer.cs.twig Custom cookie container implementation for Unity; handles domain/path matching, expiry via Max-Age and Expires, and platform-specific persistence — logic looks correct.
templates/unity/Assets/Runtime/Core/Services/ServiceTemplate.cs.twig Unity-specific service template wrapping standard API, file upload, and webAuth flows; correctly gates OAuth behind platform preprocessor macros.

Reviews (4): Last reviewed commit: "Merge remote-tracking branch 'origin/mas..." | Re-trigger Greptile

Comment on lines +659 to +662
buffer = ((byte[])input.Data)
.Skip((int)offset)
.Take((int)Math.Min(size - offset, ChunkSize - 1))
.ToArray();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Off-by-one in chunked upload byte-array path

.Take((int)Math.Min(size - offset, ChunkSize - 1)) takes one byte fewer than the Content-Range header advertises. The header at line 669 uses offset + ChunkSize - 1 as the inclusive end, meaning the server expects exactly ChunkSize bytes, but only ChunkSize - 1 are sent. For every chunk except the last, the uploaded content will be 1 byte short, causing the server to reject or silently misalign the upload. The stream and path cases read the full ChunkSize via ReadAsync, so only the bytes source type is affected.

Comment thread src/SDK/Language/DotNet.php
Comment on lines +350 to +352
Debug.Log($"[Client] Setting cookie header: {cookieHeader}");
request.SetRequestHeader("Cookie", cookieHeader);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Session cookie values written to Unity log in plain text

cookieHeader contains the full Cookie header value, which includes session tokens and other authentication credentials. Passing it to Debug.Log writes it in plain text to Unity's console output and any log file on disk. Anyone with access to the device's log files (or Unity console captures) can extract and replay the session. This block runs on all non-WebGL platforms (desktop, mobile, editor).

Comment on lines +651 to +657
case "stream":
var stream = input.Data as Stream;
if (stream == null)
throw new InvalidOperationException("Stream data is null");
stream.Seek(offset, SeekOrigin.Begin);
await stream.ReadAsync(buffer, 0, ChunkSize);
break;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 ReadAsync partial-read not handled for the last chunk

stream.ReadAsync(buffer, 0, ChunkSize) is not guaranteed to fill the entire buffer — it may return fewer than ChunkSize bytes, especially on the last chunk. The buffer is sized to ChunkSize at allocation time, so unread tail bytes retain the values from the previous iteration (or zeros on the first pass). Combined with the Content-Range header that declares the full chunk range, this means the final chunk can contain stale/zero-padded bytes, corrupting the uploaded file. The bytes path already handles this correctly with Take(…), so the stream path needs the same treatment.

Comment thread tests/Unity2021Test.php
Comment on lines +22 to +28
public function testHTTPSuccess(): void
{
// Set Unity test mode to exclude problematic files
$GLOBALS['UNITY_TEST_MODE'] = true;

parent::testHTTPSuccess();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 $GLOBALS['UNITY_TEST_MODE'] is never reset, leaking across tests

$GLOBALS['UNITY_TEST_MODE'] is set to true at the start of testHTTPSuccess but is never cleared afterwards. PHP globals persist for the entire test-runner process lifetime, so any subsequent call to Unity::getFiles() — from another test method in the same class or from a follow-up run in the same process — will silently apply the file-exclusion filter even when that wasn't intended. A tearDown that unsets the key, or better yet, an injectable flag rather than a global, would prevent this leakage.

Comment on lines 8 to +9

env:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 UNITY_LICENSE exposed to every job in the workflow

Declaring UNITY_LICENSE in the top-level env: block makes it available to all jobs, including those that have nothing to do with Unity (Rust, Swift, Web, etc.). Keeping sensitive secrets scoped to the single matrix step or job that actually needs them is a standard least-privilege practice. Consider moving the env entry to the specific step that runs the Unity test command, or gate it with if: matrix.sdk == 'Unity2021'.

Comment thread templates/unity/Assets/Runtime/Realtime.cs.twig
Comment thread .github/workflows/sdk-build-validation.yml
…ntinued

# Conflicts:
#	.github/workflows/sdk-build-validation.yml
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants