import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../facade_controller.dart'; import '../helpers/events.dart'; import 'device_method.dart'; import 'cocos_widget.dart'; import 'cocos_widget_platform.dart'; class MobileCocosWidgetController extends CocosWidgetController { final MobileCocosWidgetState _cocosWidgetState; /// The cocosId for this controller final int cocosId; /// used for cancel the subscription StreamSubscription? _onCocosMessageSub, _onCocosSceneLoadedSub, _onCocosUnloadedSub; MobileCocosWidgetController._(this._cocosWidgetState, {required this.cocosId}) { _connectStreams(cocosId); } /// Initialize [CocosWidgetController] with [id] /// Mainly for internal use when instantiating a [CocosWidgetController] passed /// in [CocosWidget.onCocosCreated] callback. static Future init( int id, MobileCocosWidgetState cocosWidgetState) async { await CocosWidgetPlatform.instance.init(id); return MobileCocosWidgetController._( cocosWidgetState, cocosId: id, ); } @visibleForTesting MethodChannel? get channel { if (CocosWidgetPlatform.instance is MethodChannelCocosWidget) { return (CocosWidgetPlatform.instance as MethodChannelCocosWidget) .channel(cocosId); } return null; } void _connectStreams(int cocosId) { if (_cocosWidgetState.widget.onCocosMessage != null) { _onCocosMessageSub = CocosWidgetPlatform.instance .onCocosMessage(cocosId: cocosId) .listen((CocosMessageEvent e) => _cocosWidgetState.widget.onCocosMessage!(e.value)); } if (_cocosWidgetState.widget.onCocosSceneLoaded != null) { _onCocosSceneLoadedSub = CocosWidgetPlatform.instance .onCocosSceneLoaded(cocosId: cocosId) .listen((CocosSceneLoadedEvent e) => _cocosWidgetState.widget.onCocosSceneLoaded!(e.value)); } if (_cocosWidgetState.widget.onCocosUnloaded != null) { _onCocosUnloadedSub = CocosWidgetPlatform.instance .onCocosUnloaded(cocosId: cocosId) .listen((_) => _cocosWidgetState.widget.onCocosUnloaded!()); } } /// Checks to see if cocos player is ready to be used /// Returns `true` if cocos player is ready. Future? isReady() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.isReady(cocosId: cocosId); } return null; } /// Get the current pause state of the cocos player /// Returns `true` if cocos player is paused. Future? isPaused() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.isPaused(cocosId: cocosId); } return null; } /// Get the current load state of the cocos player /// Returns `true` if cocos player is loaded. Future? isLoaded() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.isLoaded(cocosId: cocosId); } return null; } /// Helper method to know if Cocos has been put in background mode (WIP) unstable /// Returns `true` if cocos player is in background. Future? inBackground() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.inBackground(cocosId: cocosId); } return null; } /// Creates a cocos player if it's not already created. Please only call this if cocos is not ready, /// or is in unloaded state. Use [isLoaded] to check. /// Returns `true` if cocos player was created succesfully. Future? create() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.createCocosPlayer(cocosId: cocosId); } return null; } /// Post message to cocos from flutter. This method takes in a string [message]. /// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName], /// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method /// /// ```dart /// postMessage("GameManager", "openScene", "ThirdScene") /// ``` Future? postMessage(String gameObject, methodName, message) { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.postMessage( cocosId: cocosId, gameObject: gameObject, methodName: methodName, message: message, ); } return null; } /// Post message to cocos from flutter. This method takes in a Json or map structure as the [message]. /// The [gameObject] must match the name of an actual cocos game object in a scene at runtime, and the [methodName], /// must exist in a `MonoDevelop` `class` and also exposed as a method. [message] is an parameter taken by the method /// /// ```dart /// postJsonMessage("GameManager", "openScene", {"buildIndex": 3, "name": "ThirdScene"}) /// ``` Future? postJsonMessage( String gameObject, String methodName, Map message) { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.postJsonMessage( cocosId: cocosId, gameObject: gameObject, methodName: methodName, message: message, ); } return null; } /// Pause the cocos in-game player with this method Future? pause() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.pausePlayer(cocosId: cocosId); } return null; } /// Resume the cocos in-game player with this method idf it is in a paused state Future? resume() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.resumePlayer(cocosId: cocosId); } return null; } /// Sometimes you want to open cocos in it's own process and openInNativeProcess does just that. /// It works for Android and iOS is WIP Future? openInNativeProcess() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.openInNativeProcess(cocosId: cocosId); } return null; } /// Unloads cocos player from th current process (Works on Android only for now) /// iOS is WIP. For more information please read [Cocos Docs](https://docs.cocos3d.com/2020.2/Documentation/Manual/CocosasaLibrary.html) Future? unload() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.unloadPlayer(cocosId: cocosId); } return null; } /// Quits cocos player. Note that this kills the current flutter process, thus quiting the app Future? quit() { if (!_cocosWidgetState.widget.enablePlaceholder) { return CocosWidgetPlatform.instance.quitPlayer(cocosId: cocosId); } return null; } /// cancel the subscriptions when dispose called void _cancelSubscriptions() { _onCocosMessageSub?.cancel(); _onCocosSceneLoadedSub?.cancel(); _onCocosUnloadedSub?.cancel(); _onCocosMessageSub = null; _onCocosSceneLoadedSub = null; _onCocosUnloadedSub = null; } void dispose() { _cancelSubscriptions(); CocosWidgetPlatform.instance.dispose(cocosId: cocosId); } }