Skip to content

Commit 1d5f197

Browse files
Allow2CEOruvnet
andcommitted
Allow2 Unity SDK v2 — full UPM package implementation
Complete rewrite of the Unity SDK as a UPM package (com.allow2.sdk). Pure C# core with MonoBehaviour bridge pattern, porting the gold standard Device Operational Lifecycle from the C# SDK. 27 files, 5,108 lines: - 11 core modules (Daemon, Api, Checker, ChildShield, Warnings, Offline, Pairing, Request, Updates, Feedback, VoiceCode) - UnityWebRequest-based API client with built-in MiniJson - PlayerPrefs credential store with XOR device-key obfuscation - Allow2Manager singleton (DontDestroyOnLoad) with Inspector config - Coroutine wrappers for WebGL compatibility - UnityEvent<T> bindings for all 14 lifecycle events - Progressive warnings: 15min→5min→1min→30sec→BLOCKED - Offline: cache + 5min grace + deny-by-default - HMAC-SHA256 voice code challenge-response Co-Authored-By: claude-flow <ruv@ruv.net>
1 parent d639949 commit 1d5f197

28 files changed

+5542
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "Allow2.Runtime",
3+
"rootNamespace": "Allow2",
4+
"references": [],
5+
"includePlatforms": [],
6+
"excludePlatforms": [],
7+
"allowUnsafeCode": false,
8+
"overrideReferences": false,
9+
"precompiledReferences": [],
10+
"autoReferenced": true,
11+
"defineConstraints": [],
12+
"versionDefines": [],
13+
"noEngineReferences": false
14+
}
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
// Allow2 Unity SDK v2
2+
// Copyright (c) 2026 Allow2 Pty Ltd. All rights reserved.
3+
4+
using System;
5+
using System.Collections;
6+
using System.Collections.Generic;
7+
using UnityEngine;
8+
9+
namespace Allow2
10+
{
11+
/// <summary>
12+
/// Coroutine wrappers for async operations.
13+
/// Provides WebGL-compatible alternatives to async/await.
14+
///
15+
/// All coroutines run on the Allow2Manager MonoBehaviour.
16+
/// </summary>
17+
public class Allow2Coroutines
18+
{
19+
private readonly MonoBehaviour _runner;
20+
private readonly Allow2Api _api;
21+
22+
public Allow2Coroutines(MonoBehaviour runner, Allow2Api api)
23+
{
24+
_runner = runner;
25+
_api = api;
26+
}
27+
28+
/// <summary>
29+
/// Start a coroutine on the runner MonoBehaviour.
30+
/// </summary>
31+
public Coroutine Run(IEnumerator routine)
32+
{
33+
if (_runner == null || !_runner.gameObject.activeInHierarchy)
34+
{
35+
return null;
36+
}
37+
return _runner.StartCoroutine(routine);
38+
}
39+
40+
/// <summary>
41+
/// Stop a coroutine.
42+
/// </summary>
43+
public void Cancel(Coroutine coroutine)
44+
{
45+
if (_runner != null && coroutine != null)
46+
{
47+
_runner.StopCoroutine(coroutine);
48+
}
49+
}
50+
51+
// ----------------------------------------------------------------
52+
// API coroutine wrappers
53+
// ----------------------------------------------------------------
54+
55+
/// <summary>
56+
/// Run a permission check against the API.
57+
/// </summary>
58+
public Coroutine RunCheck(int userId, int pairId, string pairToken,
59+
int childId, Dictionary<int, int> activities, string tz,
60+
Action<Allow2ApiResponse> callback)
61+
{
62+
return Run(_api.Check(userId, pairId, pairToken, childId, activities, tz, true, callback));
63+
}
64+
65+
/// <summary>
66+
/// Initialize PIN pairing.
67+
/// </summary>
68+
public Coroutine RunInitPairing(string uuid, string deviceName, string platform,
69+
Action<Allow2ApiResponse> callback)
70+
{
71+
return Run(_api.InitPINPairing(uuid, deviceName, platform, callback));
72+
}
73+
74+
/// <summary>
75+
/// Poll pairing status.
76+
/// </summary>
77+
public Coroutine RunCheckPairingStatus(string sessionId, Action<Allow2ApiResponse> callback)
78+
{
79+
return Run(_api.CheckPairingStatus(sessionId, callback));
80+
}
81+
82+
/// <summary>
83+
/// Poll for updates.
84+
/// </summary>
85+
public Coroutine RunGetUpdates(int userId, int pairId, string pairToken,
86+
long timestampMillis, Action<Allow2ApiResponse> callback)
87+
{
88+
return Run(_api.GetUpdates(userId, pairId, pairToken, timestampMillis, callback));
89+
}
90+
91+
/// <summary>
92+
/// Create a request (more time, etc.).
93+
/// </summary>
94+
public Coroutine RunCreateRequest(int userId, int pairId, string pairToken,
95+
int childId, int duration, int activityId, string message,
96+
Action<Allow2ApiResponse> callback)
97+
{
98+
return Run(_api.CreateRequest(userId, pairId, pairToken, childId,
99+
duration, activityId, message, callback));
100+
}
101+
102+
/// <summary>
103+
/// Poll request status.
104+
/// </summary>
105+
public Coroutine RunGetRequestStatus(string requestId, string statusSecret,
106+
Action<Allow2ApiResponse> callback)
107+
{
108+
return Run(_api.GetRequestStatus(requestId, statusSecret, callback));
109+
}
110+
111+
/// <summary>
112+
/// Submit feedback.
113+
/// </summary>
114+
public Coroutine RunSubmitFeedback(int userId, int pairId, string pairToken,
115+
int childId, string category, string message,
116+
Dictionary<string, string> deviceContext, Action<Allow2ApiResponse> callback)
117+
{
118+
return Run(_api.SubmitFeedback(userId, pairId, pairToken, childId,
119+
category, message, deviceContext, callback));
120+
}
121+
122+
/// <summary>
123+
/// Load feedback.
124+
/// </summary>
125+
public Coroutine RunLoadFeedback(int userId, int pairId, string pairToken,
126+
Action<Allow2ApiResponse> callback)
127+
{
128+
return Run(_api.LoadFeedback(userId, pairId, pairToken, callback));
129+
}
130+
131+
/// <summary>
132+
/// Reply to feedback.
133+
/// </summary>
134+
public Coroutine RunFeedbackReply(int userId, int pairId, string pairToken,
135+
string discussionId, string message, Action<Allow2ApiResponse> callback)
136+
{
137+
return Run(_api.FeedbackReply(userId, pairId, pairToken,
138+
discussionId, message, callback));
139+
}
140+
141+
// ----------------------------------------------------------------
142+
// Utility coroutines
143+
// ----------------------------------------------------------------
144+
145+
/// <summary>
146+
/// Wait for a number of seconds, then invoke the callback.
147+
/// </summary>
148+
public Coroutine Delay(float seconds, Action callback)
149+
{
150+
return Run(DelayCoroutine(seconds, callback));
151+
}
152+
153+
private IEnumerator DelayCoroutine(float seconds, Action callback)
154+
{
155+
yield return new WaitForSecondsRealtime(seconds);
156+
if (callback != null) callback();
157+
}
158+
159+
/// <summary>
160+
/// Repeat an action at a fixed interval.
161+
/// Stops when the action returns true.
162+
/// </summary>
163+
public Coroutine RepeatUntil(float intervalSeconds, Func<bool> action)
164+
{
165+
return Run(RepeatCoroutine(intervalSeconds, action));
166+
}
167+
168+
private IEnumerator RepeatCoroutine(float intervalSeconds, Func<bool> action)
169+
{
170+
while (true)
171+
{
172+
bool done = action();
173+
if (done) yield break;
174+
yield return new WaitForSecondsRealtime(intervalSeconds);
175+
}
176+
}
177+
}
178+
}

0 commit comments

Comments
 (0)