map_watch.dart 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import 'dart:collection';
  2. import 'package:common_pub/logger.dart';
  3. import 'package:common_pub/service/controller.dart';
  4. import 'package:common_pub/ui/map_view/map_view.dart';
  5. import 'package:common_pub/ui/map_view/view_map_trace.dart';
  6. import 'package:track_common/model.dart';
  7. import 'package:track_common/model/event_state.dart';
  8. class Flag {
  9. Flag(this.value);
  10. int value;
  11. Color get color => Color(value);
  12. @override
  13. bool operator ==(Object other) {
  14. if (other is Flag) {
  15. return value == other.value;
  16. }
  17. return false;
  18. }
  19. @override
  20. int get hashCode => value.hashCode;
  21. static final red = Flag(0xffff0000);
  22. static final yellow = Flag(0xffffcb00);
  23. static final blue = Flag(0xff00a0ff);
  24. static List<Flag> get values => [red, yellow, blue];
  25. }
  26. class PlayerInfo extends AppGameState {
  27. var id = 0;
  28. int heartRatePercent = 0;
  29. }
  30. class PlayerInfoExt {
  31. int id = 0;
  32. var name = '';
  33. var routeName = '';
  34. var cpListWant = <ControlPoint>[];
  35. }
  36. class EventInfo {
  37. var id = 0;
  38. var players = <PlayerInfo>[];
  39. }
  40. class EventInfoExt {
  41. var name = '';
  42. var cpAllCount = 0;
  43. String startAt = '';
  44. String endAt = '';
  45. EventState state = EventState.idle;
  46. }
  47. class PlayerOnMap {
  48. var info = PlayerInfo();
  49. var _ext = PlayerInfoExt();
  50. set ext(PlayerInfoExt v) {
  51. _ext = v;
  52. info.cpListWant = v.cpListWant;
  53. }
  54. int get id => info.id;
  55. String get name => _ext.name;
  56. List<ControlPoint> get cpList => info.cpListWant;
  57. final isHide = false.obs;
  58. var trace = <TracePoint>[].obs;
  59. var flag = Flag.red.obs;
  60. String get routeName => _ext.routeName;
  61. Distance get distance => info.distance;
  62. List<HeartRate> get hrInfo => info.hrHistory;
  63. List<Position> get positionList => info.positionHistory;
  64. DateTime watchAt = DateTime.now();
  65. int get heartRatePercent => info.heartRatePercent;
  66. Pace get pace => info.pace;
  67. Duration get duration => info.duration;
  68. ControlPoint? get cpNextWant => info.cpNextWant;
  69. Distance get nextDistance {
  70. final one = info.cpNextWant;
  71. if (one != null) {
  72. final p1 = one.position;
  73. final p22 = positionList.lastOrNull;
  74. if (p22 != null) {
  75. return p1.distance(p22);
  76. }
  77. }
  78. return const Distance(m: 1000);
  79. }
  80. String get nextCPSN {
  81. return info.cpNextWant?.snString ?? '';
  82. }
  83. }
  84. class EventOnMap {
  85. var info = EventInfo();
  86. var ext = EventInfoExt();
  87. var userList = <PlayerOnMap>[];
  88. int get id => info.id;
  89. String get name => ext.name;
  90. int get cpAllCount => ext.cpAllCount;
  91. final isHide = false.obs;
  92. PlayerOnMap? getUserById(int id) {
  93. for (final one in userList) {
  94. if (one.id == id) {
  95. return one;
  96. }
  97. }
  98. return null;
  99. }
  100. }
  101. abstract class MapWatchService extends GetxService {
  102. final Rx<MapWatch?> _instance = Rx(null);
  103. MapWatch? get instance => _instance.value;
  104. @protected
  105. Future<MapWatch> newInstanceByMap(MapInfo info);
  106. Future<void> setMap(MapInfo? mapInfo) async {
  107. _instance.value?.close();
  108. if (mapInfo != null) {
  109. final thisInstance = await newInstanceByMap(mapInfo);
  110. thisInstance.addPlugs([thisInstance.plugMap]);
  111. _instance.value = thisInstance;
  112. thisInstance.init();
  113. thisInstance.workFlushData();
  114. } else {
  115. _instance.value = null;
  116. }
  117. }
  118. }
  119. abstract class MapWatch extends PlugController {
  120. Future<void> workFlushData() async {
  121. while (isActive) {
  122. try {
  123. await flushData();
  124. } catch (e) {
  125. error(e);
  126. }
  127. await 1.seconds.delay();
  128. }
  129. }
  130. EventOnMap? getEventById(int id) {
  131. for (final one in eventList) {
  132. if (one.id == id) {
  133. return one;
  134. }
  135. }
  136. return null;
  137. }
  138. MapWatch({required this.id});
  139. final int id;
  140. String name = '';
  141. final plugMap = PlugMap();
  142. final eventList = <EventOnMap>[].obs;
  143. Future<void> flushData() async {
  144. final list = await getEventList(id);
  145. final newList = <EventOnMap>[];
  146. for (final one in list) {
  147. late EventOnMap event;
  148. final old = getEventById(one.id);
  149. if (old != null) {
  150. event = old;
  151. await updateEvent(event, one);
  152. } else {
  153. event = await initEvent(one);
  154. }
  155. newList.add(event);
  156. }
  157. eventList.value = newList;
  158. }
  159. Future<HashMap<int, PlayerInfoExt>> getPlayerInfoExtMap(
  160. int eventId, Iterable<int> userIdList) async {
  161. final playerExtList = await getPlayerInfoExt(eventId, userIdList);
  162. final playerExtMap = HashMap<int, PlayerInfoExt>();
  163. for (final one in playerExtList) {
  164. playerExtMap[one.id] = one;
  165. }
  166. return playerExtMap;
  167. }
  168. Future<EventOnMap> initEvent(EventInfo info) async {
  169. final ext = await getEventInfoExt(info.id);
  170. final one = EventOnMap()
  171. ..info = info
  172. ..ext = ext;
  173. final playerIdList = info.players.map((e) => e.id);
  174. final playerExtMap = await getPlayerInfoExtMap(info.id, playerIdList);
  175. for (var p in info.players) {
  176. one.userList.add(await initPlayer(info, p, playerExtMap));
  177. }
  178. return one;
  179. }
  180. Future<PlayerOnMap> initPlayer(EventInfo event, PlayerInfo playerInfo,
  181. HashMap<int, PlayerInfoExt> playerExtMap) async {
  182. final userId = playerInfo.id;
  183. final player = PlayerOnMap()..info = playerInfo;
  184. if (playerExtMap != null) {
  185. player.ext = playerExtMap[userId]!;
  186. } else {
  187. player.ext = (await getPlayerInfoExt(event.id, [userId])).first;
  188. }
  189. return player;
  190. }
  191. Future<void> updateEvent(EventOnMap old, EventInfo newOne) async {
  192. final newUserList = <PlayerOnMap>[];
  193. final ext = await getEventInfoExt(old.id);
  194. final needUserIdList = <int>[];
  195. for (final nUser in newOne.players) {
  196. final oUser = old.getUserById(nUser.id);
  197. if (oUser == null) {
  198. needUserIdList.add(nUser.id);
  199. }
  200. }
  201. final playerExtMap = await getPlayerInfoExtMap(old.id, needUserIdList);
  202. for (final nUser in newOne.players) {
  203. late PlayerOnMap user;
  204. final oUser = old.getUserById(nUser.id);
  205. if (oUser != null) {
  206. user = await updatePlayer(oUser, nUser);
  207. } else {
  208. user = await initPlayer(old.info, nUser, playerExtMap);
  209. }
  210. await playerUpdateMap(user);
  211. newUserList.add(user);
  212. }
  213. old.userList = newUserList;
  214. old.ext = ext;
  215. }
  216. Future<void> playerUpdateMap(PlayerOnMap info) async {
  217. for (var one in info.cpList) {
  218. one.onMap = await plugMap.gameMap.worldToPixel(one.position);
  219. }
  220. }
  221. Future<PlayerOnMap> updatePlayer(PlayerOnMap old, PlayerInfo newUser) async {
  222. final indexMap = <int, TracePoint>{};
  223. old.info = newUser;
  224. old.ext = old._ext;
  225. for (final one in old.trace) {
  226. indexMap[one.ts.inMilliseconds] = one;
  227. }
  228. for (final one in newUser.positionHistory) {
  229. final t = one.timestamp;
  230. final startAt = old.watchAt;
  231. final ts = t.difference(startAt);
  232. if (ts.inMilliseconds > 0 && !indexMap.containsKey(ts.inMilliseconds)) {
  233. final pos = one;
  234. final oneTrace = TracePoint()
  235. ..ts = ts
  236. ..position = pos;
  237. if (plugMap.isInitFinish) {
  238. oneTrace.onMap =
  239. await plugMap.gameMap.worldToPixel(oneTrace.position);
  240. }
  241. old.trace.add(oneTrace);
  242. } else if (old.trace.isEmpty) {
  243. final oneTrace = TracePoint()
  244. ..ts = Duration.zero
  245. ..position = one;
  246. if (plugMap.isInitFinish) {
  247. oneTrace.onMap =
  248. await plugMap.gameMap.worldToPixel(oneTrace.position);
  249. old.trace.add(oneTrace);
  250. }
  251. }
  252. }
  253. return old;
  254. }
  255. @protected
  256. Future<List<EventInfo>> getEventList(int mapId);
  257. @protected
  258. Future<EventInfoExt> getEventInfoExt(int id);
  259. @protected
  260. Future<Iterable<PlayerInfoExt>> getPlayerInfoExt(
  261. int eventId, Iterable<int> userIdList);
  262. }