game_instance_guardian.dart 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import 'dart:async';
  2. import 'package:grpc/grpc.dart';
  3. import 'package:trackoffical_app/exception/exception.dart';
  4. import 'package:trackoffical_app/logger.dart';
  5. import 'package:trackoffical_app/model.dart';
  6. import 'package:trackoffical_app/service/api.dart';
  7. import 'package:trackoffical_app/service/app.dart';
  8. import 'package:trackoffical_app/service/app_map.dart';
  9. import 'package:trackoffical_app/service/game/game_instance.dart';
  10. import 'package:trackoffical_app/service/image.dart';
  11. import 'package:trackoffical_app/utils.dart';
  12. import 'package:protobuf/protobuf.dart';
  13. import '../../model/game_map.dart';
  14. import '../../model/game_person_data.dart';
  15. import 'package:flutter/material.dart';
  16. import 'package:get/get.dart';
  17. import 'package:trackoffical_app/pb.dart' as pb;
  18. class GameInstanceGuardian extends GameInstance {
  19. GameInstanceGuardian({required this.underGuardianId});
  20. @override
  21. Future<void> onInit() async {
  22. if (underGuardianId >= 0) {
  23. _workWatch();
  24. } else {
  25. // 测试
  26. _gameMapInitState = 'ok';
  27. }
  28. await _waitGameMapOk();
  29. if (!isActive) {
  30. throw FutureCancel();
  31. }
  32. await gameMapData.loadMemory(onReceiveProgress: (int count, int total) {});
  33. if (!isActive) {
  34. throw FutureCancel();
  35. }
  36. for(var p in gamePersonData){
  37. await p.initControlPointWantSequence(gameMapData);
  38. }
  39. addTimer(100.milliseconds, () {
  40. for (var one in gamePersonData) {
  41. final startAt = one.startAt;
  42. final endAt = one.endAt ?? App.to.now;
  43. var duration = startAt != null ? endAt.difference(startAt) : 0.seconds;
  44. one.duration.value = duration;
  45. }
  46. });
  47. }
  48. void _workWatch() async {
  49. debug('watch: 开始');
  50. while (isActive) {
  51. try {
  52. _watchStream = ApiService.to.guardianWatch(underGuardianId);
  53. await for (var msg in _watchStream!.stream) {
  54. debug('rcv: ${msg.meta.typeUrl}');
  55. msg.handleType(pb.GetInGameDataReply(), (userId, data) {
  56. onPersonInit(userId, data);
  57. onMapInit(data.data);
  58. });
  59. msg.handleType(pb.GameGpsUploadRequest(), onGameGpsUploadRequest);
  60. msg.handleType(pb.GameFinishRequest(), onGameFinish);
  61. msg.handleType(pb.GameSaveUploadRequest(), onGameSaveUploadRequest);
  62. msg.handleType(pb.GameHrUploadRequest(), onGameHrUploadRequest);
  63. msg.handleType(pb.GameCleUploadRequest(), onGameCleUploadRequest);
  64. msg.handleType(pb.PupilInGameInfoOther(), onPupilInGameInfoOther);
  65. }
  66. } on GrpcError catch (e) {
  67. if (e.code == StatusCode.unavailable) {
  68. warn('watch: 断线:$e');
  69. await 3.seconds.delay();
  70. }else if (e.code == StatusCode.cancelled) {
  71. break;
  72. } else {
  73. warn('watch: GrpcError:$e');
  74. _gameMapInitState = e;
  75. break;
  76. }
  77. } catch (e) {
  78. debug('watch: err:$e');
  79. _gameMapInitState = e;
  80. break;
  81. }
  82. }
  83. if (Get.currentRoute == '/GuardianWatchGameView') {
  84. Get.back();
  85. }
  86. debug('watch: 结束');
  87. }
  88. void onGameSaveUploadRequest(int userId, pb.GameSaveUploadRequest data) {
  89. final old = _gamePersonDataGetByUserId(userId);
  90. if (old != null) {
  91. old.gameSrcState.update((val) {
  92. val?.pbGameSave = data.gameSave;
  93. });
  94. old.cpWantSequenceRefresh(gameMapData);
  95. }
  96. }
  97. void onPersonInit(int userId, pb.GetInGameDataReply data) {
  98. final old = _gamePersonDataGetByUserId(userId);
  99. if (old == null) {
  100. final headImage = data.data.image.toModel();
  101. final state = data.data.toGameState();
  102. state.pbGameSave = data.save;
  103. final person = GamePersonData()
  104. ..userId = userId
  105. ..userHead.value = headImage
  106. ..userName = data.data.name
  107. ..gameSrcState.value = state;
  108. headImage.loadMemory().then((value) => person.userHead.update((val) {}));
  109. gamePersonData.add(person);
  110. person.initControlPointWantSequence(gameMapData);
  111. }
  112. }
  113. Future<void> onMapInit(pb.GameData data) async {
  114. if (_gameMapInitState == 'ok') {
  115. return;
  116. }
  117. gameMapData = data.mapZip.toGameMap();
  118. _gameMapInitState = 'ok';
  119. }
  120. void onGameGpsUploadRequest(int userId, pb.GameGpsUploadRequest data) async {
  121. final p = _gamePersonDataGetByUserId(userId);
  122. if (p != null) {
  123. final gpsList = data.gameGpsInfos.map((e) => e.toModel()).toList();
  124. p.myPositionHistory.addAll(gpsList);
  125. final onMapList = <Offset>[];
  126. for (var one in gpsList) {
  127. onMapList.add(await gameMapData.worldToPixel(one));
  128. }
  129. p.myPositionOnMapHistory.addAll(onMapList);
  130. p.pacePerKm.value = data.pace.seconds;
  131. p.myPositionHistoryLen.value = data.distance.meter;
  132. }
  133. }
  134. void onGameHrUploadRequest(int userId, pb.GameHrUploadRequest data)async {
  135. final p = _gamePersonDataGetByUserId(userId);
  136. if (p != null) {
  137. if(data.gameHrInfos.isNotEmpty){
  138. final hr = data.gameHrInfos.last;
  139. p.heartRate.value = hr.hr;
  140. }
  141. }
  142. }
  143. void onGameCleUploadRequest(int userId, pb.GameCleUploadRequest data)async {
  144. final p = _gamePersonDataGetByUserId(userId);
  145. if (p != null) {
  146. p.ck.value = data.ck.toDouble();
  147. p.kCal.value = data.cle.toDouble()/1000;
  148. p.hrMean.value = data.avgHr;
  149. p.hrMax.value = data.maxHr;
  150. p.stepCount.value = data.stepNum;
  151. p.heartRatePercent.value = data.heartRatePercent.toDouble();
  152. }
  153. }
  154. void onPupilInGameInfoOther(int userId, pb.PupilInGameInfoOther data)async {
  155. final p = _gamePersonDataGetByUserId(userId);
  156. if (p != null) {
  157. p.beanCount.value = data.sysPoint;
  158. }
  159. }
  160. void onGameFinish(int userId, pb.GameFinishRequest data) async {
  161. _gamePersonDataRemoveByUserId(userId);
  162. }
  163. GamePersonData? _gamePersonDataGetByUserId(int userId) {
  164. for (var one in gamePersonData) {
  165. if (one.userId == userId) {
  166. return one;
  167. }
  168. }
  169. return null;
  170. }
  171. void _gamePersonDataRemoveByUserId(int userId) {
  172. var index = -1;
  173. for (var i = 0; i < gamePersonData.length; i++) {
  174. if (gamePersonData[i].userId == userId) {
  175. index = i;
  176. break;
  177. }
  178. }
  179. if (index >= 0) {
  180. gamePersonData.removeAt(index);
  181. }
  182. }
  183. Future<void> _waitGameMapOk() async {
  184. while (isActive && _gameMapInitState == null) {
  185. await 10.milliseconds.delay();
  186. }
  187. if (_gameMapInitState == 'ok') {
  188. return;
  189. }
  190. throw _gameMapInitState;
  191. }
  192. @override
  193. Future<void> onClose() async {
  194. _watchStream?.stream.cancel();
  195. _watchStream?.channel.terminate();
  196. }
  197. final gamePersonData = <GamePersonData>[].obs;
  198. var gameMapData = GameMap();
  199. final int underGuardianId;
  200. StreamGuardianWatch? _watchStream;
  201. dynamic _gameMapInitState;
  202. }
  203. extension MsgHandle on pb.PupilInGameWatchReply {
  204. void handleType<T extends GeneratedMessage>(
  205. T instance, void Function(int userId, T data) handler) {
  206. if (meta.canUnpackInto(instance)) {
  207. final data = meta.unpackInto(instance);
  208. handler(oId, data);
  209. }
  210. }
  211. }