@@ -4,31 +4,30 @@ import 'package:flutter/foundation.dart';
44import 'unity_controller.dart' ;
55
66/// Message batcher for high-frequency Unity communication.
7- ///
7+ ///
88/// Coalesces multiple messages into single batched transmissions
99/// to reduce overhead for high-frequency updates.
10- ///
10+ ///
1111/// Example:
1212/// ```dart
1313/// final batcher = UnityMessageBatcher(controller);
1414/// batcher.configure(maxBatchSize: 50, flushIntervalMs: 16);
15- ///
15+ ///
1616/// // In update loop - messages are batched automatically
1717/// batcher.queue('Player', 'position', {'x': 1.0, 'y': 2.0});
1818/// ```
1919class UnityMessageBatcher {
2020 final UnityController _controller;
21-
21+
2222 final List <_BatchedMessage > _pendingMessages = [];
2323 Timer ? _flushTimer;
24- DateTime ? _lastFlushTime;
25-
24+
2625 // Configuration
2726 int _maxBatchSize = 50 ;
2827 int _flushIntervalMs = 16 ; // ~60fps
2928 bool _enabled = true ;
3029 bool _enableCoalescing = true ;
31-
30+
3231 // Statistics
3332 int _messagesBatched = 0 ;
3433 int _batchesSent = 0 ;
@@ -47,7 +46,7 @@ class UnityMessageBatcher {
4746 if (flushIntervalMs != null ) _flushIntervalMs = flushIntervalMs;
4847 if (enabled != null ) _enabled = enabled;
4948 if (enableCoalescing != null ) _enableCoalescing = enableCoalescing;
50-
49+
5150 // Restart timer with new interval
5251 _startTimer ();
5352 }
@@ -105,7 +104,6 @@ class UnityMessageBatcher {
105104
106105 final messages = List <_BatchedMessage >.from (_pendingMessages);
107106 _pendingMessages.clear ();
108- _lastFlushTime = DateTime .now ();
109107
110108 if (messages.length == 1 ) {
111109 // Single message - send directly
@@ -119,7 +117,8 @@ class UnityMessageBatcher {
119117 _batchesSent++ ;
120118 }
121119
122- Future <void > _sendImmediate (String target, String method, dynamic data) async {
120+ Future <void > _sendImmediate (
121+ String target, String method, dynamic data) async {
123122 try {
124123 if (data is Map <String , dynamic >) {
125124 await _controller.sendJsonMessage (target, method, data);
@@ -138,18 +137,20 @@ class UnityMessageBatcher {
138137 final batchData = {
139138 'batch' : true ,
140139 'count' : messages.length,
141- 'messages' : messages.map ((m) => {
142- 't' : m.target,
143- 'm' : m.method,
144- 'd' : m.data is String ? m.data : jsonEncode (m.data),
145- 'dt' : m.data is String ? 's' : 'j' ,
146- }).toList (),
140+ 'messages' : messages
141+ .map ((m) => {
142+ 't' : m.target,
143+ 'm' : m.method,
144+ 'd' : m.data is String ? m.data : jsonEncode (m.data),
145+ 'dt' : m.data is String ? 's' : 'j' ,
146+ })
147+ .toList (),
147148 };
148149
149150 await _controller.sendJsonMessage ('_batch' , 'onBatch' , batchData);
150151 } catch (e) {
151152 debugPrint ('UnityMessageBatcher: Batch send failed: $e ' );
152-
153+
153154 // Fallback: send individually
154155 for (final msg in messages) {
155156 await _sendImmediate (msg.target, msg.method, msg.data);
@@ -169,11 +170,11 @@ class UnityMessageBatcher {
169170
170171 /// Get batching statistics.
171172 BatcherStatistics get statistics => BatcherStatistics (
172- messagesBatched: _messagesBatched,
173- batchesSent: _batchesSent,
174- messagesCoalesced: _messagesCoalesced,
175- pendingCount: _pendingMessages.length,
176- );
173+ messagesBatched: _messagesBatched,
174+ batchesSent: _batchesSent,
175+ messagesCoalesced: _messagesCoalesced,
176+ pendingCount: _pendingMessages.length,
177+ );
177178
178179 /// Reset statistics.
179180 void resetStatistics () {
@@ -217,43 +218,43 @@ class BatcherStatistics {
217218 required this .pendingCount,
218219 });
219220
220- double get averageMessagesPerBatch =>
221+ double get averageMessagesPerBatch =>
221222 batchesSent > 0 ? messagesBatched / batchesSent : 0 ;
222223
223224 @override
224- String toString () =>
225- 'Batched=$messagesBatched , Sent=$batchesSent , '
225+ String toString () => 'Batched=$messagesBatched , Sent=$batchesSent , '
226226 'Coalesced=$messagesCoalesced , Pending=$pendingCount , '
227227 'Avg/Batch=${averageMessagesPerBatch .toStringAsFixed (1 )}' ;
228228}
229229
230-
231230/// Message throttler for rate-limited communication.
232- ///
231+ ///
233232/// Limits the rate of messages sent to Unity to prevent overwhelming
234233/// the communication channel.
235- ///
234+ ///
236235/// Example:
237236/// ```dart
238237/// final throttler = UnityMessageThrottler(controller);
239- ///
238+ ///
240239/// // Configure rate limit (60 messages per second)
241240/// throttler.setRate('Player:position', 60);
242- ///
241+ ///
243242/// // Send throttled messages
244243/// throttler.send('Player', 'position', data); // Rate limited
245244/// ```
246245class UnityMessageThrottler {
247246 final UnityController _controller;
248-
247+
249248 final Map <String , _ThrottleConfig > _configs = {};
250249 final Map <String , DateTime > _lastSendTimes = {};
251250 final Map <String , dynamic > _pendingValues = {};
252251
253252 UnityMessageThrottler (this ._controller);
254253
255254 /// Set rate limit for a target:method combination.
256- void setRate (String key, int messagesPerSecond, {
255+ void setRate (
256+ String key,
257+ int messagesPerSecond, {
257258 ThrottleStrategy strategy = ThrottleStrategy .keepLatest,
258259 }) {
259260 _configs[key] = _ThrottleConfig (
@@ -277,7 +278,7 @@ class UnityMessageThrottler {
277278 final now = DateTime .now ();
278279 final lastSend = _lastSendTimes[key];
279280
280- if (lastSend == null ||
281+ if (lastSend == null ||
281282 now.difference (lastSend).inMilliseconds >= config.intervalMs) {
282283 // Allowed to send
283284 _lastSendTimes[key] = now;
@@ -295,7 +296,8 @@ class UnityMessageThrottler {
295296 break ;
296297 case ThrottleStrategy .keepFirst:
297298 // Only store if not already pending
298- _pendingValues.putIfAbsent (key, () => _PendingMessage (target, method, data));
299+ _pendingValues.putIfAbsent (
300+ key, () => _PendingMessage (target, method, data));
299301 break ;
300302 }
301303 }
@@ -313,7 +315,8 @@ class UnityMessageThrottler {
313315 }
314316 }
315317
316- Future <void > _sendImmediate (String target, String method, dynamic data) async {
318+ Future <void > _sendImmediate (
319+ String target, String method, dynamic data) async {
317320 try {
318321 if (data is Map <String , dynamic >) {
319322 await _controller.sendJsonMessage (target, method, data);
@@ -352,15 +355,14 @@ class _PendingMessage {
352355enum ThrottleStrategy {
353356 /// Drop excess messages entirely
354357 drop,
355-
358+
356359 /// Keep only the latest value (replace pending)
357360 keepLatest,
358-
361+
359362 /// Keep only the first value (ignore subsequent)
360363 keepFirst,
361364}
362365
363-
364366/// Extension methods for UnityController with performance utilities.
365367extension UnityControllerPerformance on UnityController {
366368 /// Create a message batcher for this controller.
0 commit comments