|
|
@@ -4,74 +4,44 @@ import 'package:flutter/cupertino.dart';
|
|
|
import 'package:get/get.dart';
|
|
|
import 'package:fixnum/fixnum.dart';
|
|
|
import 'package:grpc/grpc.dart';
|
|
|
-import 'package:mobile_app/model/game_map.dart';
|
|
|
-import 'package:mobile_app/model/settlement.dart';
|
|
|
-import 'package:mobile_app/pb.dart' as pb;
|
|
|
-import 'package:mobile_app/service/app_map.dart';
|
|
|
-import 'package:mobile_app/service/game/game_model.dart';
|
|
|
-import 'package:mobile_app/service/game/plug.dart';
|
|
|
-import 'package:mobile_app/service/game/plug_location.dart';
|
|
|
-import 'package:mobile_app/service/game/plug_sport_wear.dart';
|
|
|
-import 'package:mobile_app/service/game/rule_in_order.dart';
|
|
|
-import 'package:mobile_app/service/game/show_position_controller.dart';
|
|
|
-import 'package:mobile_app/utils.dart';
|
|
|
-import 'package:mobile_app/view/ingame/settlement_view.dart';
|
|
|
+import 'package:trackoffical_app/model/game_map.dart';
|
|
|
+// import 'package:trackoffical_app/model/settlement.dart';
|
|
|
+import 'package:trackoffical_app/pb.dart' as pb;
|
|
|
+import 'package:trackoffical_app/service/app_map.dart';
|
|
|
+import 'package:trackoffical_app/service/game/game_model.dart';
|
|
|
+import 'package:trackoffical_app/service/game/plug.dart';
|
|
|
+// import 'package:trackoffical_app/service/game/plug_location.dart';
|
|
|
+// import 'package:trackoffical_app/service/game/plug_sport_wear.dart';
|
|
|
+// import 'package:trackoffical_app/service/game/rule_in_order.dart';
|
|
|
+import 'package:trackoffical_app/service/game/show_position_controller.dart';
|
|
|
+import 'package:trackoffical_app/utils.dart';
|
|
|
+// import 'package:trackoffical_app/view/ingame/settlement_view.dart';
|
|
|
import 'package:vibration/vibration.dart';
|
|
|
import 'package:wakelock/wakelock.dart';
|
|
|
import '../../logger.dart';
|
|
|
+import '../../model/m_control_point.dart';
|
|
|
import '../api.dart';
|
|
|
import '../../model.dart';
|
|
|
import '../app.dart';
|
|
|
import '../database.dart';
|
|
|
import 'map_status.dart';
|
|
|
import 'plug_orientation.dart';
|
|
|
-import 'rule.dart';
|
|
|
-import '../image.dart';
|
|
|
+// import 'rule.dart';
|
|
|
+// import '../image.dart';
|
|
|
|
|
|
-enum GameStatus {
|
|
|
- idle,
|
|
|
- // 准备进入游戏
|
|
|
- preparing,
|
|
|
- loading,
|
|
|
- playing,
|
|
|
- settlement,
|
|
|
-}
|
|
|
-
|
|
|
-class GameService extends GetxService {
|
|
|
- static GameService get to => Get.find();
|
|
|
+class MapService extends GetxService {
|
|
|
+ static MapService get to => Get.find();
|
|
|
final DatabaseService _database = Get.find();
|
|
|
final GameModel _model = Get.find();
|
|
|
final App _app = Get.find();
|
|
|
+ final mapStatus = MapStatus();
|
|
|
final errorMsg = ''.obs;
|
|
|
final name = "".obs;
|
|
|
- var activityId = 0;
|
|
|
- var mapRouteId = Int64(0);
|
|
|
- var _status = GameStatus.idle;
|
|
|
- Rule rule = RuleMock();
|
|
|
- GameStatus get status => _status;
|
|
|
-
|
|
|
- set status(GameStatus v) {
|
|
|
- info('游戏状态:[$v]');
|
|
|
- _status = v;
|
|
|
- }
|
|
|
-
|
|
|
- pb.GameSettlement _lastGameSettlement = pb.GameDetailReply();
|
|
|
-
|
|
|
- pb.GameSettlement get lastGameSettlement => _lastGameSettlement;
|
|
|
-
|
|
|
- MPosition? get myPosition => _model.myPosition.value;
|
|
|
-
|
|
|
+ var mapId = 0;
|
|
|
Offset? get positionOnMap => _model.myPositionOnMap.value;
|
|
|
|
|
|
- double get myPositionHistoryLenKm => _model.myPositionHistoryLen.value.km;
|
|
|
-
|
|
|
- final _plugs = <Plug>[];
|
|
|
-
|
|
|
- GameState get gameState => _model.gameSrcState.value;
|
|
|
- var isShowCompass = true.obs;
|
|
|
- static const _progressMap = 0.6;
|
|
|
- static const _progressApi = 0.2;
|
|
|
- static const _progressFinal = 0.2;
|
|
|
+ // static const _progressMap = 0.6;
|
|
|
+ // static const _progressApi = 0.2;
|
|
|
final _loadProgress = 0.0.obs;
|
|
|
|
|
|
double get loadProgress => _loadProgress.value;
|
|
|
@@ -79,454 +49,17 @@ class GameService extends GetxService {
|
|
|
List<MControlPoint> get controlPointWantSequence =>
|
|
|
_model.controlPointWantSequence;
|
|
|
|
|
|
- bool get isNfcScanUseDialog {
|
|
|
- final platform = _app.platformInfo;
|
|
|
- if (platform is PlatformInfoIOS) {
|
|
|
- if (platform.deviceVersion >= 8) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 创建时间
|
|
|
- DateTime get createTime => gameState.createTime;
|
|
|
-
|
|
|
- // 关门时间
|
|
|
- Duration get maxPassDuration => gameState.pbGameData.maxDuration.toDuration();
|
|
|
-
|
|
|
- // 强制结束时间
|
|
|
- Duration get maxForcedEndDuration =>
|
|
|
- gameState.pbGameData.maxForcedEndDuration.toDuration();
|
|
|
-
|
|
|
- DateTime get now => _app.now;
|
|
|
-
|
|
|
- // 打开始点的时间
|
|
|
- DateTime? get startAt => _model.startAt;
|
|
|
-
|
|
|
- DateTime? get endAt => _model.endAt;
|
|
|
-
|
|
|
- List<pb.ControlPoint> get _controlPointWantSequence =>
|
|
|
- gameState.pbGameData.controlPointSortedList;
|
|
|
-
|
|
|
- List<pb.ControlPointSimple> get _controlPointAll =>
|
|
|
- gameState.pbGameData.controlPointAll;
|
|
|
-
|
|
|
- var _lastCheckedPoint = Int64(0);
|
|
|
- var _lastCheckedPointTime = DateTime(0);
|
|
|
-
|
|
|
- List<MControlPoint> get checkedPointsHistory => _model.checkedPointsHistory;
|
|
|
- final beginDuration = 0.seconds.obs;
|
|
|
- final mapStatus = MapStatus();
|
|
|
- Timer? _beginDurationTicker;
|
|
|
- Timer? _checkStopTicker;
|
|
|
-
|
|
|
- int get checkedCount => _model.checkedCount;
|
|
|
-
|
|
|
- // 所有计分点数量
|
|
|
- int get controlPointAllNum => _model.validCPAllNum;
|
|
|
-
|
|
|
- // 打卡进度
|
|
|
- double get checkProgress => _model.checkProgress;
|
|
|
-
|
|
|
- bool get isOutBoundary {
|
|
|
- final p = _model.myPositionOnMap.value;
|
|
|
-
|
|
|
- if (p != null) {
|
|
|
- final mapWidth = mapStatus.gameMapData.width;
|
|
|
- final mapHeight = mapStatus.gameMapData.height;
|
|
|
-
|
|
|
- if (p.dx <= 0 || p.dx >= mapWidth || p.dy <= 0 || p.dy >= mapHeight) {
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- AnimationController? showLocationController;
|
|
|
-
|
|
|
- showLocation() {
|
|
|
- final p = positionOnMap;
|
|
|
- if (p != null) {
|
|
|
- final dst = _model.mapRotateCenter;
|
|
|
-
|
|
|
- if (_model.isEnableUserLocation && !_model.isAlwaysShowMyLocation) {
|
|
|
- Get.find<ShowPositionController>().show();
|
|
|
- }
|
|
|
-
|
|
|
- if (dst != null) {
|
|
|
- mapStatus.movePicPointTo(p, dst);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _setStartAt(DateTime? time) {
|
|
|
- if (time != null) {
|
|
|
- gameState.pbGameSave.startAt = time.toPb();
|
|
|
- } else {
|
|
|
- gameState.pbGameSave.clearStartAt();
|
|
|
- }
|
|
|
- _model.gameSrcState.refresh();
|
|
|
- }
|
|
|
-
|
|
|
- _setEndAt(DateTime? time) {
|
|
|
- if (time != null) {
|
|
|
- gameState.pbGameSave.stopAt = time.toPb();
|
|
|
- } else {
|
|
|
- gameState.pbGameSave.clearStopAt();
|
|
|
- }
|
|
|
- _model.gameSrcState.refresh();
|
|
|
- }
|
|
|
-
|
|
|
- _recordLastPoint(Int64 id) {
|
|
|
- _lastCheckedPoint = id;
|
|
|
- _lastCheckedPointTime = now;
|
|
|
- }
|
|
|
-
|
|
|
- bool _isCheckTooFast(Int64 id) {
|
|
|
- return _lastCheckedPoint == id &&
|
|
|
- now.difference(_lastCheckedPointTime) <= 10.seconds;
|
|
|
- }
|
|
|
-
|
|
|
- bool isPointStart(pb.GameSaveControlPoint p) {
|
|
|
- final seq = _controlPointWantSequence;
|
|
|
- if (seq.isNotEmpty) {
|
|
|
- return p.controlPointId == seq.first.id;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- bool isPointFinish(pb.GameSaveControlPoint p) {
|
|
|
- final seq = _controlPointWantSequence;
|
|
|
- if (seq.isNotEmpty) {
|
|
|
- return p.controlPointId == seq.last.id;
|
|
|
- }
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- void setBeginMatrix() {
|
|
|
- if (mapStatus.isSetBeginMatrix) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- final next = _model.nextPlanPoint;
|
|
|
- final f = _model.mapRotateCenter;
|
|
|
- if (next != null && f != null) {
|
|
|
- mapStatus.movePicPointTo(next.onMap, f);
|
|
|
- mapStatus.isSetBeginMatrix = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- pb.ControlPointSimple gameSaveControlPointFindInProject(
|
|
|
- pb.GameSaveControlPoint p) {
|
|
|
- final all = gameState.pbGameData.controlPointAll;
|
|
|
- for (final one in all) {
|
|
|
- if (one.id == p.controlPointId) {
|
|
|
- return one;
|
|
|
- }
|
|
|
- }
|
|
|
- return pb.ControlPointSimple();
|
|
|
- }
|
|
|
-
|
|
|
- Future<List<MControlPoint>> _getControlPointWantSequence() async {
|
|
|
- final out = <MControlPoint>[];
|
|
|
- final checkedIndex = checkedCount;
|
|
|
-
|
|
|
- for (var i = 0; i < _controlPointWantSequence.length; i++) {
|
|
|
- final value = _controlPointWantSequence[i];
|
|
|
- final one = value.toModel();
|
|
|
- one.sn = '$i';
|
|
|
- if (i == 0) {
|
|
|
- one.isStart = true;
|
|
|
- }
|
|
|
- if (i == _controlPointWantSequence.length - 1) {
|
|
|
- one.isFinish = true;
|
|
|
- }
|
|
|
-
|
|
|
- one.isSuccess = i < checkedIndex;
|
|
|
- one.isNext = i == checkedIndex;
|
|
|
- one.onMap =
|
|
|
- await mapStatus.gameMapData.worldToPixel(value.mapPosition.toModel());
|
|
|
-
|
|
|
- final extraInfo = one.extraInfo;
|
|
|
- if(extraInfo is CPExtraInfoChoiceQuestion){
|
|
|
- extraInfo.beanCount = gameState.pbGameData.answerSysPoint;
|
|
|
- await extraInfo.image?.loadMemory();
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- out.add(one);
|
|
|
- }
|
|
|
-
|
|
|
- return out;
|
|
|
- }
|
|
|
-
|
|
|
- MControlPoint? getNextWantPoint(int offset) =>
|
|
|
- _model.getNextWantPoint(offset);
|
|
|
-
|
|
|
- MControlPoint? getLastCheckedPoint() {
|
|
|
- if (checkedPointsHistory.isNotEmpty) {
|
|
|
- return checkedPointsHistory.last;
|
|
|
- } else {
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void _checkGameStop({bool willToSettlementView = false}) {
|
|
|
- if ([
|
|
|
- GameStatus.preparing,
|
|
|
- GameStatus.playing,
|
|
|
- ].contains(status)) {
|
|
|
- if (now.difference(createTime) > maxForcedEndDuration) {
|
|
|
- gameGiveUp(willToSettlementView: willToSettlementView);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> _saveToDatabase() async {
|
|
|
- await DatabaseService.to.saveGameState(gameState);
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> _saveToServer() async {
|
|
|
- while (!isClosed) {
|
|
|
- try {
|
|
|
- final save = gameState.pbGameSave;
|
|
|
- await ApiService.to
|
|
|
- .gameSaveUpload(pb.GameSaveUploadRequest()..gameSave= save);
|
|
|
-
|
|
|
- return;
|
|
|
- } on GrpcError catch (e) {
|
|
|
- warn('上传失败:', e);
|
|
|
- if (e.code != StatusCode.unavailable) {
|
|
|
- return;
|
|
|
- }
|
|
|
- } catch (e) {
|
|
|
- warn('上传失败:', e);
|
|
|
- return;
|
|
|
- }
|
|
|
+ Future<void> mapLoad() async {
|
|
|
+ info('载入地图[$mapId]');
|
|
|
+ // await _plugsClear();
|
|
|
|
|
|
- await Future.delayed(500.milliseconds);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void _checkHistoryAdd(MControlPoint cp) {
|
|
|
- checkedPointsHistory.add(cp);
|
|
|
- gameState.pbGameSave.checkedSortedList.add(cp.toPbSave());
|
|
|
- }
|
|
|
-
|
|
|
- void _updateCheckHistory(){
|
|
|
- gameState.pbGameSave.checkedSortedList.clear();
|
|
|
- gameState.pbGameSave.checkedSortedList.addAll(checkedPointsHistory.map((e) => e.toPbSave()).toList());
|
|
|
- }
|
|
|
-
|
|
|
- void save() {
|
|
|
- _updateCheckHistory();
|
|
|
- _saveToDatabase().then((value) => info('本地存档完成'));
|
|
|
- _saveToServer().then((value) => info('上传存档完成'));
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> gameGiveUp({bool willToSettlementView = false}) async {
|
|
|
- // if(status == GameStatus.idle || status == GameStatus.settlement){
|
|
|
- // return;
|
|
|
- // }
|
|
|
- _gameStopSetValues();
|
|
|
- _updateCheckHistory();
|
|
|
- _saveToDatabase().then((value) => info('本地存档完成'));
|
|
|
- _settlement(isGiveUp: true, willToSettlementView: willToSettlementView);
|
|
|
- }
|
|
|
-
|
|
|
- void _gameStopSetValues({DateTime? now}) {
|
|
|
- info('游戏结束');
|
|
|
- if (now != null) {
|
|
|
- _setEndAt(now);
|
|
|
- } else {
|
|
|
- _setEndAt(this.now);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void _updateNewCPState(MControlPoint point, {DateTime? now}) {
|
|
|
- now = now ?? this.now;
|
|
|
- point.checkAfterStart = now.difference(startAt ?? now);
|
|
|
- point.checkAfterPrev = point.checkAfterStart;
|
|
|
- point.checkDistanceAfterStart = _model.myPositionHistoryLen.value;
|
|
|
- point.checkDistanceAfterPrev = point.checkDistanceAfterStart;
|
|
|
- final last = getLastCheckedPoint();
|
|
|
- if (last != null) {
|
|
|
- point.checkAfterPrev = point.checkAfterStart - last.checkAfterStart;
|
|
|
- point.checkDistanceAfterPrev = point.checkDistanceAfterStart - last.checkDistanceAfterStart;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- checkPointNFC(
|
|
|
- String identifier,
|
|
|
- void Function(MControlPoint cp) onChecked,
|
|
|
- Future<bool> Function () onConfirmFinish,
|
|
|
- void Function(pb.ControlPointSimple point) onProjectPoint,
|
|
|
- VoidCallback onNoPoint,
|
|
|
- ) {
|
|
|
- final checkedPoint = _findControlPointInRouteByNfcId(identifier);
|
|
|
- if (checkedPoint != null) {
|
|
|
- checkPoint(checkedPoint, onChecked, onConfirmFinish);
|
|
|
- } else {
|
|
|
- final point = _findControlPointInProjectByNfcId(identifier);
|
|
|
- if (point != null) {
|
|
|
- if (_isCheckTooFast(point.id)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- final result = point.toModel();
|
|
|
- _updateNewCPState(result);
|
|
|
- result.isSuccess = false;
|
|
|
- _checkHistoryAdd(result);
|
|
|
- save();
|
|
|
- _recordLastPoint(point.id);
|
|
|
- onProjectPoint(point);
|
|
|
- } else {
|
|
|
- onNoPoint();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- checkPointGps(
|
|
|
- void Function(MControlPoint cp) onChecked,
|
|
|
- Future<bool> Function () onConfirmFinish,
|
|
|
- ) {
|
|
|
-
|
|
|
- if(_model.isInPlanControlPointArea){
|
|
|
- pb.ControlPoint? checkedPoint;
|
|
|
- final point = _model.nextPlanPoint;
|
|
|
- if (point != null) {
|
|
|
- checkedPoint = _findControlPointInRouteByM(point);
|
|
|
- }
|
|
|
- checkPoint(checkedPoint!, onChecked, onConfirmFinish);
|
|
|
- }else if (_model.isInWantControlPointArea) {
|
|
|
- pb.ControlPoint? checkedPoint;
|
|
|
- final point = _model.getNextWantPoint(0);
|
|
|
- if (point != null) {
|
|
|
- checkedPoint = _findControlPointInRouteByM(point);
|
|
|
- }
|
|
|
- checkPoint(checkedPoint!, onChecked, onConfirmFinish);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- Future<void> checkPoint(
|
|
|
- pb.ControlPoint checkedPoint,
|
|
|
- void Function (MControlPoint cp) onChecked,
|
|
|
- /// 打了结束点,询问是否结束
|
|
|
- Future<bool> Function () onConfirmFinish,
|
|
|
- ) async{
|
|
|
- final cp = checkedPoint.toModel();
|
|
|
-
|
|
|
- if (rule.checkNeedReturn(cp)){
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- final now = this.now;
|
|
|
-
|
|
|
- final result = rule.checkPoint(checkedPoint.toModel());
|
|
|
-
|
|
|
-
|
|
|
- var isFinish = result.isSuccess && result.isFinish;
|
|
|
-
|
|
|
- if(!result.isSuccess && result.isFinish){
|
|
|
- isFinish = await onConfirmFinish();
|
|
|
- if(!isFinish){
|
|
|
- return;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _updateNewCPState(result, now: now);
|
|
|
-
|
|
|
- if(result.isStart && result.isSuccess){
|
|
|
- _setStartAt(now);
|
|
|
- }
|
|
|
-
|
|
|
- if(isFinish){
|
|
|
- _gameStopSetValues(now: now);
|
|
|
- }
|
|
|
-
|
|
|
- _checkHistoryAdd(result);
|
|
|
-
|
|
|
- if(startAt!=null){
|
|
|
- gameState.pbGameSave.duration = now.difference(startAt!).toPb();
|
|
|
-
|
|
|
- if(endAt != null){
|
|
|
- gameState.pbGameSave.duration = endAt!.difference(startAt!).toPb();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- _model.gameSrcState.refresh();
|
|
|
-
|
|
|
- if(isFinish){
|
|
|
- _settlement();
|
|
|
- }else{
|
|
|
- save();
|
|
|
- }
|
|
|
- rule.recordLastPoint(cp);
|
|
|
- onChecked(result);
|
|
|
- }
|
|
|
-
|
|
|
- void showNextPoint() {
|
|
|
- final next = _model.nextPlanPoint;
|
|
|
- final focalPoint = _model.mapRotateCenter;
|
|
|
- if (next != null && focalPoint != null) {
|
|
|
- mapStatus.movePicPointTo(next.onMap, focalPoint);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> gameGiveUpAndToFinishView({GameState? state}) async {
|
|
|
- if (state != null) {
|
|
|
- _model.gameSrcState.value = state;
|
|
|
- }
|
|
|
-
|
|
|
- gameGiveUp();
|
|
|
- SettlementView.show();
|
|
|
- // Get.offAll(() => const GameFinishView(),
|
|
|
- // binding: GameFinishView.bindings());
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> _gameReset() async {
|
|
|
- errorMsg.value = '';
|
|
|
- _model.clear();
|
|
|
- await _plugsClear();
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> gameStart() async {
|
|
|
- info('项目Id[$activityId]准备开始');
|
|
|
- await _gameReset();
|
|
|
-
|
|
|
- final data = await ApiService.to.gameStart(activityId, mapRouteId);
|
|
|
- _model.gameSrcState.value = data.toGameState();
|
|
|
- status = GameStatus.preparing;
|
|
|
- _saveToDatabase();
|
|
|
- info('活动Id[$activityId],游戏Id[${gameState.pbGameData.gameId}]已开始');
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> gameLoad() async {
|
|
|
- info('载入项目[$activityId], Id[${gameState.pbGameData.gameId}]');
|
|
|
- await _plugsClear();
|
|
|
-
|
|
|
- _loadProgress.value = 0;
|
|
|
- status = GameStatus.loading;
|
|
|
- _app.userProfile.cleanGameSettingsLock();
|
|
|
- _app.userProfile.gameSettingsLoadLock(gameState.pbGameData.ruleList);
|
|
|
-
|
|
|
- /// 游戏规则
|
|
|
- // rule = RuleInOrder();
|
|
|
- _model.compassRealNorthOffset = gameState.pbGameData.declination * pi / 180;
|
|
|
-
|
|
|
- _loadProgress.value = _progressApi;
|
|
|
-
|
|
|
- final gameMap = gameState.pbGameData.mapZip.toGameMap();
|
|
|
+ final gameMap = pb.ToMapInfoV2().zipImage.toGameMap();
|
|
|
mapStatus.gameMapData = gameMap;
|
|
|
|
|
|
- await gameMap.loadMemory(onReceiveProgress: (c, a) {
|
|
|
- if (a > 0) {
|
|
|
- var p = c.toDouble() / a;
|
|
|
- p = p * _progressMap + _progressApi;
|
|
|
+ await gameMap.loadMemory(onReceiveProgress: (count, total) {
|
|
|
+ if (total > 0) {
|
|
|
+ var p = count.toDouble() / total;
|
|
|
+ // p = p * _progressMap + _progressApi;
|
|
|
_loadProgress.value = p;
|
|
|
}
|
|
|
});
|
|
|
@@ -546,293 +79,49 @@ class GameService extends GetxService {
|
|
|
Offset(screenSize.width / 2, screenSize.height / 2);
|
|
|
await mapStatus.resetMatrix();
|
|
|
|
|
|
- _model.controlPointWantSequence.value =
|
|
|
- await _getControlPointWantSequence();
|
|
|
- _gameLoadCheckedCP();
|
|
|
-
|
|
|
- final plugLocation = PlugLocation(
|
|
|
- gameMap: gameMap,
|
|
|
- lastInfo: _model.gameSrcState.value.pbGameSave.gameGpsInfos);
|
|
|
+ // _model.controlPointWantSequence.value =
|
|
|
+ // await _getControlPointWantSequence();
|
|
|
+ // _gameLoadCheckedCP();
|
|
|
+
|
|
|
+ // final plugLocation = PlugLocation(
|
|
|
+ // gameMap: gameMap,
|
|
|
+ // lastInfo: _model.gameSrcState.value.pbGameSave.gameGpsInfos);
|
|
|
+ //
|
|
|
+ // _plugs.add(plugLocation);
|
|
|
+ // _plugs.add(PlugSportWear(
|
|
|
+ // lastHr: _model.gameSrcState.value.pbGameSave.gameHrInfos));
|
|
|
+ // _plugs.add(PlugOrientation(mapStatus: mapStatus));
|
|
|
+ //
|
|
|
+ // await _plugsAllInit();
|
|
|
|
|
|
- _plugs.add(plugLocation);
|
|
|
- _plugs.add(PlugSportWear(
|
|
|
- lastHr: _model.gameSrcState.value.pbGameSave.gameHrInfos));
|
|
|
- _plugs.add(PlugOrientation(mapStatus: mapStatus));
|
|
|
-
|
|
|
- await _plugsAllInit();
|
|
|
- _loadProgress.value = 1;
|
|
|
- status = GameStatus.playing;
|
|
|
- Wakelock.enable();
|
|
|
info('载入完成');
|
|
|
}
|
|
|
|
|
|
- void _gameLoadCheckedCP() {
|
|
|
- final controlPointWantIdValueMap = <Int64, MControlPoint>{};
|
|
|
- final controlPointAllIdValueMap = <Int64, pb.ControlPointSimple>{};
|
|
|
-
|
|
|
- for (var one in _model.controlPointWantSequence) {
|
|
|
- controlPointWantIdValueMap[one.intId] = one;
|
|
|
- }
|
|
|
- for (var one in gameState.pbGameData.controlPointAll) {
|
|
|
- controlPointAllIdValueMap[one.id] = one;
|
|
|
- }
|
|
|
- for (var i = 0; i < gameState.pbGameSave.checkedSortedList.length; i++) {
|
|
|
- final one = gameState.pbGameSave.checkedSortedList[i];
|
|
|
- final his = one.toModel();
|
|
|
- final hisInfo1 = controlPointWantIdValueMap[his.intId];
|
|
|
- final hisInfo2 = controlPointAllIdValueMap[his.intId];
|
|
|
- if (hisInfo2 != null) {
|
|
|
- his.updateBySimple(hisInfo2);
|
|
|
- }
|
|
|
- if (hisInfo1 != null) {
|
|
|
- his.updateBy(hisInfo1);
|
|
|
- his.type = hisInfo1.type;
|
|
|
- }
|
|
|
- checkedPointsHistory.add(his);
|
|
|
- }
|
|
|
-
|
|
|
- for (var i = 0; i < checkedPointsHistory.length; i++) {
|
|
|
- final his = checkedPointsHistory[i];
|
|
|
- if (i > 0) {
|
|
|
- final last = checkedPointsHistory[i - 1];
|
|
|
- his.checkAfterPrev = his.checkAfterStart - last.checkAfterStart;
|
|
|
- his.checkDistanceAfterPrev = his.checkDistanceAfterStart - last.checkDistanceAfterStart;
|
|
|
- } else {
|
|
|
- his.checkAfterPrev = his.checkAfterStart;
|
|
|
- his.checkDistanceAfterPrev = his.checkDistanceAfterStart;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> _plugsAllInit() async {
|
|
|
- for (var one in _plugs) {
|
|
|
- await one.init();
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Future<void> _plugsClear() async {
|
|
|
- for (var one in _plugs) {
|
|
|
- one.close();
|
|
|
- }
|
|
|
- for (var one in _plugs) {
|
|
|
- await one.join();
|
|
|
- }
|
|
|
- _plugs.clear();
|
|
|
- }
|
|
|
-
|
|
|
- Settlement getSettlement() {
|
|
|
- return Settlement(
|
|
|
- data: gameState.pbGameData,
|
|
|
- save: gameState.pbGameSave,
|
|
|
- durationAfterStartCheck: beginDuration.value);
|
|
|
- }
|
|
|
-
|
|
|
- pb.ControlPoint? _findControlPointInRouteByNfcId(String identifier) {
|
|
|
- pb.ControlPoint? found;
|
|
|
- for (var one in _controlPointWantSequence) {
|
|
|
- for (var nfcId in one.nfcIdList) {
|
|
|
- if (nfcId.toUpperCase() == identifier.toUpperCase()) {
|
|
|
- found = one;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return found;
|
|
|
- }
|
|
|
-
|
|
|
- pb.ControlPoint? _findControlPointInRouteByM(MControlPoint point) {
|
|
|
- pb.ControlPoint? found;
|
|
|
- for (var one in _controlPointWantSequence) {
|
|
|
- if (one.id == point.intId) {
|
|
|
- found = one;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- return found;
|
|
|
- }
|
|
|
-
|
|
|
- pb.ControlPointSimple? _findControlPointInProjectByNfcId(String identifier) {
|
|
|
- for (var one in _controlPointAll) {
|
|
|
- for (var nfcId in one.nfcIdList) {
|
|
|
- if (nfcId.toUpperCase() == identifier.toUpperCase()) {
|
|
|
- return one;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- return null;
|
|
|
- }
|
|
|
+ showLocation() {
|
|
|
+ final p = positionOnMap;
|
|
|
+ if (p != null) {
|
|
|
+ final dst = _model.mapRotateCenter;
|
|
|
|
|
|
- Future<void> _settlementDeal(bool isGiveUp) async {
|
|
|
- while (!isClosed) {
|
|
|
- try {
|
|
|
- final save = gameState.pbGameSave;
|
|
|
- await ApiService.to
|
|
|
- .gameSaveUpload(pb.GameSaveUploadRequest()..gameSave= save);
|
|
|
- info('进度已上传');
|
|
|
- break;
|
|
|
- } on GrpcError catch (e) {
|
|
|
- if (e.code == StatusCode.unavailable) {
|
|
|
- errorMsg.value = '无法连接至服务器,正在重试';
|
|
|
- } else {
|
|
|
- break;
|
|
|
- }
|
|
|
- error(e);
|
|
|
- } catch (e) {
|
|
|
- error(e);
|
|
|
- break;
|
|
|
+ if (_model.isEnableUserLocation && !_model.isAlwaysShowMyLocation) {
|
|
|
+ Get.find<ShowPositionController>().show();
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- await _plugsClear();
|
|
|
-
|
|
|
- while (!isClosed) {
|
|
|
- try {
|
|
|
- info('正在结算');
|
|
|
- _lastGameSettlement = await ApiService.to
|
|
|
- .gameFinish(gameState.pbGameData.gameId, isGiveUp);
|
|
|
- info('结算完成');
|
|
|
- break;
|
|
|
- } on GrpcError catch (e) {
|
|
|
- if (e.code == StatusCode.unavailable) {
|
|
|
- errorMsg.value = '网络错误,正在重试';
|
|
|
- } else {
|
|
|
- break;
|
|
|
- }
|
|
|
- error(e);
|
|
|
- Future.delayed(500.milliseconds);
|
|
|
- } catch (e) {
|
|
|
- error(e);
|
|
|
- break;
|
|
|
+ if (dst != null) {
|
|
|
+ mapStatus.movePicPointTo(p, dst);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- await _saveToDatabase();
|
|
|
- status = GameStatus.idle;
|
|
|
- }
|
|
|
-
|
|
|
- _settlement({bool isGiveUp = false, bool willToSettlementView = false}) {
|
|
|
- _updateCheckHistory();
|
|
|
- status = GameStatus.settlement;
|
|
|
- errorMsg.value = '';
|
|
|
- _settlementDeal(isGiveUp).then((value) => info('结算完成'));
|
|
|
- if (willToSettlementView) {
|
|
|
- SettlementView.show();
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
@override
|
|
|
void onReady() {
|
|
|
- _beginDurationTicker = Timer.periodic(100.milliseconds, (timer) {
|
|
|
- final startAt = this.startAt;
|
|
|
- if (startAt != null) {
|
|
|
- final end = endAt ?? now;
|
|
|
- beginDuration.value = end.difference(startAt);
|
|
|
- } else {
|
|
|
- beginDuration.value = 0.seconds;
|
|
|
- }
|
|
|
- });
|
|
|
}
|
|
|
|
|
|
@override
|
|
|
void onClose() {
|
|
|
- _checkStopTicker?.cancel();
|
|
|
- _beginDurationTicker?.cancel();
|
|
|
- }
|
|
|
-
|
|
|
- Future<bool> loadOnlineUnFinishGame() async {
|
|
|
- try {
|
|
|
- final online = await ApiService.to.getInGameData();
|
|
|
- info('存在线上未完成游戏');
|
|
|
- status = GameStatus.preparing;
|
|
|
- _model.gameSrcState.value = GameState()
|
|
|
- ..pbGameData = online.data
|
|
|
- ..pbGameSave = online.save;
|
|
|
- _checkGameStop();
|
|
|
- return true;
|
|
|
- } on GrpcError catch (e) {
|
|
|
- if (e.code != StatusCode.notFound) {
|
|
|
- warn(e);
|
|
|
- }
|
|
|
- return false;
|
|
|
- } catch (e) {
|
|
|
- warn(e);
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void workAutoSave() async {
|
|
|
- while (!isClosed) {
|
|
|
- await Future.delayed(500.milliseconds);
|
|
|
-
|
|
|
- if (_model.gameSrcState.value.pbGameData.gameId > 0 &&
|
|
|
- _model.isStarted &&
|
|
|
- !_model.isFinish) {
|
|
|
- await _saveToDatabase();
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void workTrajectory() async {
|
|
|
- while (!isClosed) {
|
|
|
- await Future.delayed(1000.milliseconds);
|
|
|
- final duration = _app.userProfile.inGameTrajectorySeconds.val.seconds;
|
|
|
-
|
|
|
- var out = <Offset>[];
|
|
|
- for (var i = _model.myPositionHistory.length - 1; i >= 0; i--) {
|
|
|
- var one = _model.myPositionHistory[i];
|
|
|
- if (now.difference(one.timestamp) > duration) {
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- out.add(await mapStatus.gameMapData.worldToPixel(one));
|
|
|
- }
|
|
|
- _model.trajectoryPoints.clear();
|
|
|
- _model.trajectoryPoints.addAll(out);
|
|
|
- }
|
|
|
}
|
|
|
|
|
|
- void workPace() async {
|
|
|
- while (!isClosed) {
|
|
|
- await Future.delayed(1000.milliseconds);
|
|
|
- final startDuration = _model.startedDuration;
|
|
|
- if (startDuration.inMilliseconds == 0) {
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- _model.paceSecondKm.value =
|
|
|
- pacePerKm(myPositionHistoryLenKm.km, startDuration);
|
|
|
- if (checkedPointsHistory.isEmpty) {
|
|
|
- _model.paceSecondKmFromLastCP.value = _model.paceSecondKm.value;
|
|
|
- } else {
|
|
|
- final cp = checkedPointsHistory.last;
|
|
|
- _model.paceSecondKmFromLastCP.value = pacePerKm(
|
|
|
- _model.myPositionHistoryLenFromLastCP,
|
|
|
- startDuration - cp.checkAfterStart);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- static Future<GameService> init() async {
|
|
|
- final gs = GameService();
|
|
|
-
|
|
|
- gs.mapStatus.canVibrate = await Vibration.hasVibrator() ?? false;
|
|
|
- final save = await gs._database.getExistGameData();
|
|
|
- if (save != null) {
|
|
|
- info('存在本地未完成游戏');
|
|
|
- gs.status = GameStatus.preparing;
|
|
|
- gs._model.gameSrcState.value = save.toState();
|
|
|
- gs._checkGameStop();
|
|
|
- } else {
|
|
|
- gs.loadOnlineUnFinishGame();
|
|
|
- }
|
|
|
-
|
|
|
- gs._checkStopTicker = Timer.periodic(100.milliseconds, (timer) {
|
|
|
- gs._checkGameStop(willToSettlementView: true);
|
|
|
- });
|
|
|
-
|
|
|
- gs.workAutoSave();
|
|
|
- gs.workTrajectory();
|
|
|
- gs.workPace();
|
|
|
+ static Future<MapService> init() async {
|
|
|
+ final gs = MapService();
|
|
|
return gs;
|
|
|
}
|
|
|
}
|