import 'dart:async'; import 'package:get/get.dart'; import 'package:grpc/grpc.dart'; import 'package:trackoffical_app/service/api.dart'; import 'package:trackoffical_app/service/app.dart'; import 'package:trackoffical_app/utils.dart'; import '../../../logger.dart'; import '../plug.dart'; import 'game_instance_std.dart'; class PlugLocation extends Plug{ PlugLocation(GameInstanceStd ins){ instance=ins; final lastInfo = ins.model.gameSrcState.value.pbGameSave.gameGpsInfos; if(lastInfo.isNotEmpty){ for(var one in lastInfo){ var p = MPosition(); p.latitude = one.latitude; p.longitude = one.longitude; p.directionRadian = one.directionRadian; p.timestamp = one.gpsTime.toModel(); _addOnePosition(p, false); } } } GameInstanceStd? instance; final _app = App.to; final _api = ApiService.to; final _toUpload = []; bool get isEnableGPSTrack => _app.userProfile.gameSettingsGpsTrack.value; Future uploadPosition() async { final ins = instance; if(ins!= null && isEnableGPSTrack){ final model = ins.model; final gameId = model.gameSrcState.value.pbGameData.gameId; final data = []; final distanceMeter = model.myPositionHistoryLen.value.m; final paceSecondKm = model.paceSecondKm; if(_toUpload.isNotEmpty){ data.addAll(_toUpload); try { await _api.gameGpsUpload( gameId, data, distanceMeter.round(), paceSecondKm.value.inSeconds); _toUpload.clear(); } catch (e) { warn('GameId[$gameId]上传位置失败: $e'); } } } } void onRcvPosition(MPosition p, GameInstanceStd ins) { p.directionRadian = -ins.compassRadiansFused.value; _toUpload.add(p); _addOnePosition(p, true); } void _addOnePosition(MPosition p, bool isSaveToDB){ final ins = instance; if(ins==null){ return; } MPosition? last; if (ins.model.myPositionHistory.isNotEmpty) { last = ins.model.myPositionHistory.last; } ins.model.myPositionHistory.add(p); ins.gameMapData.worldToPixel(p).then((offset){ ins.model.myPositionOnMapHistory.add(offset); }); ins.gameMapData.mapPackage?.isInHotZone(p).then((value) => ins.model.zone.value=value ); final startAt=ins.model.startAt; if(startAt==null){ return; } final endAt = ins.model.endAt; if(endAt != null){ if(p.timestamp.isAfter(endAt)){ return; } } if(p.timestamp.isBefore(startAt)){ return; } // 只记录开始点后 if (last!=null) { final dis = p.distance(last); ins.model.myPositionHistoryLen.value += dis; } if(isSaveToDB){ ins.model.gameSrcState.value.pbGameSave.gameGpsInfos.add(p.toPb2()); } } Future loopUploadPosition() async { while (isActive) { await Future.delayed(1.seconds); await uploadPosition(); } } Future _makeSureUploadAll() async { while (true) { try { await uploadPosition(); return; } on GrpcError catch (e) { if (e.code != StatusCode.unavailable) { return; } error(e); } catch (e) { error(e); return; } await Future.delayed(100.milliseconds); } } @override Future init() async{ final locationStream = _app.locationStream; listenStream(locationStream, (p) { final ins = instance; if(ins!= null){ onRcvPosition(p, ins); } }); _app.locationStart(500.milliseconds, 1); _app.getPosition(timeout: 5.seconds).then((p) { final ins = instance; if(ins!= null){ onRcvPosition(p, ins); } }); loopUploadPosition(); } @override Future onClose() async{ _app.locationStop(); await _makeSureUploadAll(); instance=null; } }