From f38efce42f11a68519b410b0c7c73f2ecfa9e821 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=8E=89=E4=B8=9C?= <129883742+liyudong2018@users.noreply.github.com> Date: Fri, 19 Sep 2025 11:17:49 +0800 Subject: [PATCH 1/3] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hivekion/room/bean/AbtParentTask.java | 20 +++- .../com/hivekion/room/bean/MoveRootTask.java | 109 ++++++++++++++++-- .../resources/application-rule.properties | 4 +- 3 files changed, 118 insertions(+), 15 deletions(-) diff --git a/src/main/java/com/hivekion/room/bean/AbtParentTask.java b/src/main/java/com/hivekion/room/bean/AbtParentTask.java index 7b804d1..c60c04e 100644 --- a/src/main/java/com/hivekion/room/bean/AbtParentTask.java +++ b/src/main/java/com/hivekion/room/bean/AbtParentTask.java @@ -3,8 +3,13 @@ package com.hivekion.room.bean; import com.hivekion.room.RoomManager; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.ScenarioTask; - -import java.util.concurrent.*; +import com.hivekion.statistic.bean.StatisticBean; +import java.util.concurrent.Executors; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import org.springframework.web.reactive.function.client.WebClient; @@ -68,14 +73,15 @@ public abstract class AbtParentTask implements TaskAction { public long getDuringTime() { return RoomManager.getRoomDuringTime(this.roomId); } + //获取房间状态 public boolean getRoomStatus() { return RoomManager.isRunning(roomId); } - public void createBattleTaskOnTimingHandle(BizTaskOnTiming bizTaskOnTiming){ + public void createBattleTaskOnTimingHandle(BizTaskOnTiming bizTaskOnTiming) { ScheduledExecutorService schedule = Executors.newScheduledThreadPool( - 1); + 1); schedule.scheduleWithFixedDelay(() -> { bizTaskOnTiming.execTask(); }, 0, 10, TimeUnit.SECONDS); @@ -83,9 +89,13 @@ public abstract class AbtParentTask implements TaskAction { addScheduledExecutorServiceRefenceToRoom(schedule); } + protected void pushStatistic() { + StatisticBean statisticBean = new StatisticBean(); + //获取分队信息 + } } - interface BizTaskOnTiming{ +interface BizTaskOnTiming { public void execTask(); } diff --git a/src/main/java/com/hivekion/room/bean/MoveRootTask.java b/src/main/java/com/hivekion/room/bean/MoveRootTask.java index 052bf82..0f9a9b2 100644 --- a/src/main/java/com/hivekion/room/bean/MoveRootTask.java +++ b/src/main/java/com/hivekion/room/bean/MoveRootTask.java @@ -5,11 +5,17 @@ import com.alibaba.fastjson2.JSON; import com.alibaba.fastjson2.JSONArray; import com.alibaba.fastjson2.JSONObject; import com.hivekion.Global; +import com.hivekion.baseData.entity.Scenario; +import com.hivekion.baseData.service.ScenarioService; import com.hivekion.common.MultiPointGeoPosition; import com.hivekion.common.entity.ResponseCmdInfo; +import com.hivekion.common.redis.RedisUtil; import com.hivekion.enums.WsCmdTypeEnum; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.ScenarioTask; +import com.hivekion.statistic.bean.StatisticBean; +import com.hivekion.statistic.service.impl.StatisticServiceImpl; +import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -49,6 +55,23 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { * 开始点坐标 */ private final AtomicReference startPoint = new AtomicReference<>(); + /** + * 任务相对与想定的开始时间 + */ + private long taskRelativeStartTime = 0; + /** + * 油料消耗速率 + */ + private double fuelConsumption = 0; + /** + * 消耗任务间隔 + */ + private final int consumptionTaskInterval = 5; + /** + * redis 服务类 + */ + private final RedisUtil redis = SpringUtil.getBean(RedisUtil.class); + private StatisticBean statisticBean; public MoveRootTask(ScenarioTask scenarioTask, String roomId) { @@ -59,8 +82,28 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { @Override public void doSomeThing() { log.info("move task running"); + + initEnv(); //初始化环境 initPath(); //初始化路径 updatePath(); //更新路径 + fuelConsumption();//油品消耗 + } + + /** + * 初始化环境 + */ + private void initEnv() { + //获取任务相对于想定的开始时间 + Scenario scenario = SpringUtil.getBean(ScenarioService.class) + .getScenarioById(scenarioTask.getScenarioId()); + taskRelativeStartTime = Math.abs( + Duration.between(scenario.getStartTime(), scenarioTask.getStartTime()).getSeconds()); + //获取油品消耗规则 + String fuelConsumptionStr = SpringUtil.getBean(Environment.class) + .getProperty("vehicle.fuel.consumption.per.km"); + fuelConsumption = Double.parseDouble(fuelConsumptionStr == null ? "0" : fuelConsumptionStr); + + statisticBean = SpringUtil.getBean(StatisticServiceImpl.class).statistic(scenarioTask.getResourceId()); } /** @@ -98,7 +141,11 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { Global.sendCmdInfoQueue.add( ResponseCmdInfo.create(WsCmdTypeEnum.PATH_INIT.getCode(), roomId, scenarioTask.getScenarioId(), dataMap)); - log.info("init::{}", JSON.toJSONString(coordinates)); + + redis.hset( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "init_path", JSON.toJSONString(coordinates)); + //计算各个点的累计距离和坐标的对应关系 double beforeLng = Double.parseDouble(scenarioTask.getFromLng()); double beforeLat = Double.parseDouble(scenarioTask.getFromLat()); @@ -142,7 +189,8 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { try { if (this.getRoomStatus()) { - long duringTime = getDuringTime(); + long duringTime = getDuringTime() - taskRelativeStartTime; + log.info("duringTime::{}", duringTime); //跑动距离 double distance = duringTime * SPEED; @@ -157,7 +205,7 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { if (Double.compare(distance, endPoint.getKey()) < 0) { //获取小于最大值的第一个key Double lowerKey = distanceInfoMap.lowerKey(endPoint.getKey()); - // log.info("distance::{},lowerKey::{},endPoint{}",distance,lowerKey,endPoint.getKey()); + // log.info("distance::{},lowerKey::{},endPoint{}",distance,lowerKey,endPoint.getKey()); //获取从上一个开始节点到lowKey的数据 NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), true, lowerKey, true); @@ -165,23 +213,23 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { Coordinate coordinate = subPathMap.get(key); dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); } - double diff =distance - lowerKey ; + double diff = distance - lowerKey; //插入值 double[] insertPoints = MultiPointGeoPosition.pointAlong( distanceInfoMap.get(lowerKey).getLat(), distanceInfoMap.get(lowerKey).getLng(), endPoint.getValue().getLat(), endPoint.getValue().getLng(), diff); - - dataList.add(new double[]{insertPoints[1], insertPoints[0]}); - Coordinate coordinate = new Coordinate(); + Coordinate coordinate = new Coordinate(); coordinate.setLat(insertPoints[0]); coordinate.setLng(insertPoints[1]); distanceInfoMap.put(distance, coordinate); startPoint.set(distance); - + redis.hset( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "position", JSON.toJSONString(coordinate)); Global.sendCmdInfoQueue.add( ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, @@ -208,7 +256,6 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { } - } } catch (Exception e) { log.error("error::", e); @@ -221,7 +268,51 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { addScheduledExecutorServiceRefenceToRoom(schedule); } + private void fuelConsumption() { + ScheduledExecutorService schedule = Executors.newScheduledThreadPool( + 1); + schedule.scheduleWithFixedDelay(() -> { + if (getRoomStatus()) { + double total = consumptionTaskInterval * SPEED / 1000 * fuelConsumption; + //更新redis中油品的消耗 + Object currentFuelObj = redis.hget( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "fuel"); + if (currentFuelObj != null) { + double fuel = Double.parseDouble(currentFuelObj.toString()); + if (fuel > 0) { + fuel = fuel - total < 0 ? 0 : fuel - total; + //更新值 + redis.hset( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "fuel", fuel); + //推送前端 + + } + } + } + + + }, 0, consumptionTaskInterval, TimeUnit.SECONDS); + + } + + private void statistic() { + + Object positionObj = redis.hget( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "position"); + if (positionObj != null) { + Coordinate coordinate = JSONObject.parseObject(positionObj.toString(), Coordinate.class); + statisticBean.getTeam().setLat(coordinate.lat+""); + statisticBean.getTeam().setLng(coordinate.lng+""); + + } + //设置人员受伤信息 + + + } } @Data diff --git a/src/main/resources/application-rule.properties b/src/main/resources/application-rule.properties index 094db2a..f302868 100644 --- a/src/main/resources/application-rule.properties +++ b/src/main/resources/application-rule.properties @@ -3,4 +3,6 @@ battle.ammunition.warn = 3 battle.food.warn = 3 battle.water.warn = 3 battle.fuel.warn = 2 -battle.medical.warn = 1 \ No newline at end of file +battle.medical.warn = 1 +## ?????????????? +vehicle.fuel.consumption.per.km: 0.08 \ No newline at end of file From cdfa6e3a8a2f1757f3244ba043ebf9ed40e699d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E7=8E=89=E4=B8=9C?= <129883742+liyudong2018@users.noreply.github.com> Date: Fri, 19 Sep 2025 12:14:09 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hivekion/enums/WsCmdTypeEnum.java | 1 + .../com/hivekion/room/bean/AbtParentTask.java | 203 +++++++++++- .../hivekion/room/bean/BattleRootTask.java | 6 +- .../com/hivekion/room/bean/Coordinate.java | 19 ++ .../com/hivekion/room/bean/MoveRootTask.java | 312 ++++++------------ .../com/hivekion/room/bean/SupplierTask.java | 7 +- 6 files changed, 326 insertions(+), 222 deletions(-) create mode 100644 src/main/java/com/hivekion/room/bean/Coordinate.java diff --git a/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java b/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java index 1b00d81..257bc33 100644 --- a/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java +++ b/src/main/java/com/hivekion/enums/WsCmdTypeEnum.java @@ -14,6 +14,7 @@ import lombok.Getter; public enum WsCmdTypeEnum { PATH_UPDATE("path_update"), PATH_FINISHED("path_finished"), + STATISTIC("statistic"), PATH_INIT("path_init"); @Getter private final String code; diff --git a/src/main/java/com/hivekion/room/bean/AbtParentTask.java b/src/main/java/com/hivekion/room/bean/AbtParentTask.java index c60c04e..8016256 100644 --- a/src/main/java/com/hivekion/room/bean/AbtParentTask.java +++ b/src/main/java/com/hivekion/room/bean/AbtParentTask.java @@ -1,9 +1,28 @@ package com.hivekion.room.bean; +import cn.hutool.extra.spring.SpringUtil; +import com.alibaba.fastjson2.JSON; +import com.alibaba.fastjson2.JSONArray; +import com.alibaba.fastjson2.JSONObject; +import com.hivekion.Global; +import com.hivekion.baseData.entity.Scenario; +import com.hivekion.baseData.service.ScenarioService; +import com.hivekion.common.MultiPointGeoPosition; +import com.hivekion.common.entity.ResponseCmdInfo; +import com.hivekion.common.redis.RedisUtil; +import com.hivekion.enums.WsCmdTypeEnum; import com.hivekion.room.RoomManager; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.ScenarioTask; import com.hivekion.statistic.bean.StatisticBean; +import java.time.Duration; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.NavigableMap; +import java.util.TreeMap; import java.util.concurrent.Executors; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ScheduledExecutorService; @@ -11,6 +30,9 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; +import lombok.extern.slf4j.Slf4j; +import org.springframework.core.env.Environment; import org.springframework.web.reactive.function.client.WebClient; /** @@ -22,16 +44,26 @@ import org.springframework.web.reactive.function.client.WebClient; * @author LiDongYU * @since 2025/7/22 */ - +@Slf4j public abstract class AbtParentTask implements TaskAction { - - + /** + * 开始点坐标 + */ + private final AtomicReference startPoint = new AtomicReference<>(); + /** + * 距离和坐标的对应关系 + */ + protected final TreeMap distanceInfoMap = new TreeMap<>(); //任务数据 protected final ScenarioTask scenarioTask; //房间ID protected final String roomId; //http请求 protected WebClient webClient = WebClient.create(); + /** + * 任务相对与想定的开始时间 + */ + private long taskRelativeTime = 0; //线程池 protected ThreadPoolExecutor executor = new ThreadPoolExecutor( 5, // 核心线程数 @@ -46,7 +78,10 @@ public abstract class AbtParentTask implements TaskAction { public AbtParentTask(ScenarioTask scenarioTask, String roomId) { this.scenarioTask = scenarioTask; this.roomId = roomId; - + Scenario scenario = SpringUtil.getBean(ScenarioService.class) + .getScenarioById(scenarioTask.getScenarioId()); + taskRelativeTime = Math.abs( + Duration.between(scenario.getStartTime(), scenarioTask.getStartTime()).getSeconds()); } public void addScheduledExecutorServiceRefenceToRoom( @@ -89,9 +124,163 @@ public abstract class AbtParentTask implements TaskAction { addScheduledExecutorServiceRefenceToRoom(schedule); } - protected void pushStatistic() { - StatisticBean statisticBean = new StatisticBean(); - //获取分队信息 + + protected void initPath(){ + try { + + String url = SpringUtil.getBean(Environment.class).getProperty("path.planning.url"); + String params = url + "?" + + "profile=car" + + "&point=" + scenarioTask.getFromLat() + "," + + scenarioTask.getFromLng() + + "&point=" + scenarioTask.getToLat() + "," + + scenarioTask.getToLng() + + "&points_encoded=false" + + "&algorithm=alternative_route&alternative_route.max_paths=3"; + //获取路线信息 + String result = webClient.get().uri(params) + .retrieve() + .bodyToMono(String.class) + .block(); + + JSONObject pointJson = JSON.parseObject(result); + //获取路径点 + if (pointJson != null) { + JSONObject pointsObj = pointJson.getJSONArray("paths").getJSONObject(0) + .getJSONObject("points"); + JSONArray coordinates = pointsObj.getJSONArray("coordinates"); + //组装信息 + Map dataMap = new HashMap<>(); + dataMap.put("resourceId", scenarioTask.getResourceId()); + dataMap.put("points", coordinates); + //推送路径任务 + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_INIT.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + + SpringUtil.getBean(RedisUtil.class).hset( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "init_path", JSON.toJSONString(coordinates)); + + //计算各个点的累计距离和坐标的对应关系 + double beforeLng = Double.parseDouble(scenarioTask.getFromLng()); + double beforeLat = Double.parseDouble(scenarioTask.getFromLat()); + double total = 0; + for (int i = 0; i < coordinates.size(); i++) { + JSONArray coordinate = coordinates.getJSONArray(i); + Double lng = coordinate.getDouble(0); + + Double lat = coordinate.getDouble(1); + + double distance = MultiPointGeoPosition.haversine(beforeLat, beforeLng, lat, lng); + //当前总距离 + total = total + distance; + //定义坐标对象 + Coordinate coordinateInfo = new Coordinate(); + coordinateInfo.setLat(lat); + coordinateInfo.setLng(lng); + + //记录距离和数组列表直接的索引关系 + distanceInfoMap.put(total, coordinateInfo); + + beforeLng = lng; + beforeLat = lat; + + } + //设置第一个开始位置 + startPoint.set(distanceInfoMap.firstKey()); + } + + } catch (Exception e) { + log.error("error::", e); + } + } + protected void updatePath(double speed) { + + ScheduledExecutorService schedule = Executors.newScheduledThreadPool( + 1); + schedule.scheduleWithFixedDelay(() -> { + + try { + if (this.getRoomStatus()) { + + long duringTime = getDuringTime() - taskRelativeTime; + + log.info("duringTime::{}", duringTime); + //跑动距离 + double distance = duringTime * speed; + //获取大与此距离的第一个路线点key + Entry endPoint = distanceInfoMap.ceilingEntry(distance); + //ws数据 + List dataList = new ArrayList<>(); + HashMap dataMap = new HashMap<>(); + dataMap.put("resourceId", scenarioTask.getResourceId()); + dataMap.put("points", dataList); + + if (Double.compare(distance, endPoint.getKey()) < 0) { + //获取小于最大值的第一个key + Double lowerKey = distanceInfoMap.lowerKey(endPoint.getKey()); + // log.info("distance::{},lowerKey::{},endPoint{}",distance,lowerKey,endPoint.getKey()); + //获取从上一个开始节点到lowKey的数据 + NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), + true, lowerKey, true); + for (Double key : subPathMap.keySet()) { + Coordinate coordinate = subPathMap.get(key); + dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); + } + double diff = distance - lowerKey; + + //插入值 + double[] insertPoints = MultiPointGeoPosition.pointAlong( + distanceInfoMap.get(lowerKey).getLat(), distanceInfoMap.get(lowerKey).getLng(), + endPoint.getValue().getLat(), endPoint.getValue().getLng(), diff); + + dataList.add(new double[]{insertPoints[1], insertPoints[0]}); + + Coordinate coordinate = new Coordinate(); + coordinate.setLat(insertPoints[0]); + coordinate.setLng(insertPoints[1]); + distanceInfoMap.put(distance, coordinate); + startPoint.set(distance); + SpringUtil.getBean(RedisUtil.class).hset( + scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), + "position", JSON.toJSONString(coordinate)); + + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + + } else if (Double.compare(distance, endPoint.getKey()) == 0) { + NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), + true, endPoint.getKey(), true); + for (Double key : subPathMap.keySet()) { + Coordinate coordinate = subPathMap.get(key); + dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); + } + + startPoint.set(endPoint.getKey()); + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + + } else { + //完成路径 + Global.sendCmdInfoQueue.add( + ResponseCmdInfo.create(WsCmdTypeEnum.PATH_FINISHED.getCode(), roomId, + scenarioTask.getScenarioId(), dataMap)); + } + + + } + } catch (Exception e) { + log.error("error::", e); + } + + + }, 0, 1, TimeUnit.SECONDS); + + //房间统一管理定时器;房间关闭后,定时器销毁 + addScheduledExecutorServiceRefenceToRoom(schedule); } } diff --git a/src/main/java/com/hivekion/room/bean/BattleRootTask.java b/src/main/java/com/hivekion/room/bean/BattleRootTask.java index b14dae1..d83d400 100644 --- a/src/main/java/com/hivekion/room/bean/BattleRootTask.java +++ b/src/main/java/com/hivekion/room/bean/BattleRootTask.java @@ -189,7 +189,7 @@ public class BattleRootTask extends AbtParentTask { SupplierRequest supplierRequest = new SupplierRequest(); supplierRequest.setId(IdUtils.simpleUUID()); supplierRequest.setFromResourceId(scenarioTask.getResourceId()); - supplierRequest.setSupplierNum(String.valueOf(suppleAmount)); + supplierRequest.setSupplierNum(Double.valueOf(String.valueOf(suppleAmount))); supplierRequest.setSupplierType("ammunition"); supplierRequest.setGeneralTime(currentDateTime); supplierRequest.setLat(jsonObject.get("teamLat").toString()); @@ -201,7 +201,7 @@ public class BattleRootTask extends AbtParentTask { SupplierRequest supplierRequest = new SupplierRequest(); supplierRequest.setId(IdUtils.simpleUUID()); supplierRequest.setFromResourceId(scenarioTask.getResourceId()); - supplierRequest.setSupplierNum(String.valueOf(suppleDeath)); + supplierRequest.setSupplierNum(Double.valueOf(String.valueOf(suppleDeath))); supplierRequest.setSupplierType("death"); supplierRequest.setGeneralTime(currentDateTime); supplierRequest.setLat(jsonObject.get("teamLat").toString()); @@ -213,7 +213,7 @@ public class BattleRootTask extends AbtParentTask { SupplierRequest supplierRequest = new SupplierRequest(); supplierRequest.setId(IdUtils.simpleUUID()); supplierRequest.setFromResourceId(scenarioTask.getResourceId()); - supplierRequest.setSupplierNum(String.valueOf(suppleInjured)); + supplierRequest.setSupplierNum(Double.valueOf(String.valueOf(suppleInjured))); supplierRequest.setSupplierType("injured"); supplierRequest.setGeneralTime(currentDateTime); supplierRequest.setLat(jsonObject.get("teamLat").toString()); diff --git a/src/main/java/com/hivekion/room/bean/Coordinate.java b/src/main/java/com/hivekion/room/bean/Coordinate.java new file mode 100644 index 0000000..bf656df --- /dev/null +++ b/src/main/java/com/hivekion/room/bean/Coordinate.java @@ -0,0 +1,19 @@ +package com.hivekion.room.bean; + +import lombok.Data; + +/** + * [类的简要说明] + *

+ * [详细描述,可选] + *

+ * + * @author LiDongYU + * @since 2025/7/22 + */ +@Data +public class Coordinate { + + private double lng; + private double lat; +} diff --git a/src/main/java/com/hivekion/room/bean/MoveRootTask.java b/src/main/java/com/hivekion/room/bean/MoveRootTask.java index 0f9a9b2..79c4f27 100644 --- a/src/main/java/com/hivekion/room/bean/MoveRootTask.java +++ b/src/main/java/com/hivekion/room/bean/MoveRootTask.java @@ -47,22 +47,12 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { * 速度 换算为100Km/小时 */ private final double SPEED = 27; - /** - * 距离和坐标的对应关系 - */ - private final TreeMap distanceInfoMap = new TreeMap<>(); - /** - * 开始点坐标 - */ - private final AtomicReference startPoint = new AtomicReference<>(); - /** - * 任务相对与想定的开始时间 - */ - private long taskRelativeStartTime = 0; + /** * 油料消耗速率 */ private double fuelConsumption = 0; + private double fuelThreshold = 0; /** * 消耗任务间隔 */ @@ -85,7 +75,7 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { initEnv(); //初始化环境 initPath(); //初始化路径 - updatePath(); //更新路径 + updatePath(SPEED); //更新路径 fuelConsumption();//油品消耗 } @@ -93,204 +83,52 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { * 初始化环境 */ private void initEnv() { - //获取任务相对于想定的开始时间 - Scenario scenario = SpringUtil.getBean(ScenarioService.class) - .getScenarioById(scenarioTask.getScenarioId()); - taskRelativeStartTime = Math.abs( - Duration.between(scenario.getStartTime(), scenarioTask.getStartTime()).getSeconds()); + + //获取油品消耗规则 String fuelConsumptionStr = SpringUtil.getBean(Environment.class) - .getProperty("vehicle.fuel.consumption.per.km"); + .getProperty("fuel_spreed"); fuelConsumption = Double.parseDouble(fuelConsumptionStr == null ? "0" : fuelConsumptionStr); - - statisticBean = SpringUtil.getBean(StatisticServiceImpl.class).statistic(scenarioTask.getResourceId()); + fuelThreshold = Double.parseDouble(SpringUtil.getBean(Environment.class) + .getProperty("fuel.warn ","0")); + statisticBean = SpringUtil.getBean(StatisticServiceImpl.class) + .statistic(scenarioTask.getResourceId()); } - /** - * 初始化路径 - */ - private void initPath() { - try { - - String url = SpringUtil.getBean(Environment.class).getProperty("path.planning.url"); - String params = url + "?" - + "profile=car" - + "&point=" + scenarioTask.getFromLat() + "," - + scenarioTask.getFromLng() - + "&point=" + scenarioTask.getToLat() + "," - + scenarioTask.getToLng() - + "&points_encoded=false" - + "&algorithm=alternative_route&alternative_route.max_paths=3"; - //获取路线信息 - String result = webClient.get().uri(params) - .retrieve() - .bodyToMono(String.class) - .block(); - - JSONObject pointJson = JSON.parseObject(result); - //获取路径点 - if (pointJson != null) { - JSONObject pointsObj = pointJson.getJSONArray("paths").getJSONObject(0) - .getJSONObject("points"); - JSONArray coordinates = pointsObj.getJSONArray("coordinates"); - //组装信息 - Map dataMap = new HashMap<>(); - dataMap.put("resourceId", scenarioTask.getResourceId()); - dataMap.put("points", coordinates); - //推送路径任务 - Global.sendCmdInfoQueue.add( - ResponseCmdInfo.create(WsCmdTypeEnum.PATH_INIT.getCode(), roomId, - scenarioTask.getScenarioId(), dataMap)); - - redis.hset( - scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), - "init_path", JSON.toJSONString(coordinates)); - - //计算各个点的累计距离和坐标的对应关系 - double beforeLng = Double.parseDouble(scenarioTask.getFromLng()); - double beforeLat = Double.parseDouble(scenarioTask.getFromLat()); - double total = 0; - for (int i = 0; i < coordinates.size(); i++) { - JSONArray coordinate = coordinates.getJSONArray(i); - Double lng = coordinate.getDouble(0); - - Double lat = coordinate.getDouble(1); - - double distance = MultiPointGeoPosition.haversine(beforeLat, beforeLng, lat, lng); - //当前总距离 - total = total + distance; - //定义坐标对象 - Coordinate coordinateInfo = new Coordinate(); - coordinateInfo.setLat(lat); - coordinateInfo.setLng(lng); - - //记录距离和数组列表直接的索引关系 - distanceInfoMap.put(total, coordinateInfo); - - beforeLng = lng; - beforeLat = lat; - - } - //设置第一个开始位置 - startPoint.set(distanceInfoMap.firstKey()); - } - - } catch (Exception e) { - log.error("error::", e); - } - } - - private void updatePath() { - - ScheduledExecutorService schedule = Executors.newScheduledThreadPool( - 1); - schedule.scheduleWithFixedDelay(() -> { - - try { - if (this.getRoomStatus()) { - - long duringTime = getDuringTime() - taskRelativeStartTime; - - log.info("duringTime::{}", duringTime); - //跑动距离 - double distance = duringTime * SPEED; - //获取大与此距离的第一个路线点key - Entry endPoint = distanceInfoMap.ceilingEntry(distance); - //ws数据 - List dataList = new ArrayList<>(); - HashMap dataMap = new HashMap<>(); - dataMap.put("resourceId", scenarioTask.getResourceId()); - dataMap.put("points", dataList); - - if (Double.compare(distance, endPoint.getKey()) < 0) { - //获取小于最大值的第一个key - Double lowerKey = distanceInfoMap.lowerKey(endPoint.getKey()); - // log.info("distance::{},lowerKey::{},endPoint{}",distance,lowerKey,endPoint.getKey()); - //获取从上一个开始节点到lowKey的数据 - NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), - true, lowerKey, true); - for (Double key : subPathMap.keySet()) { - Coordinate coordinate = subPathMap.get(key); - dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); - } - double diff = distance - lowerKey; - - //插入值 - double[] insertPoints = MultiPointGeoPosition.pointAlong( - distanceInfoMap.get(lowerKey).getLat(), distanceInfoMap.get(lowerKey).getLng(), - endPoint.getValue().getLat(), endPoint.getValue().getLng(), diff); - - dataList.add(new double[]{insertPoints[1], insertPoints[0]}); - - Coordinate coordinate = new Coordinate(); - coordinate.setLat(insertPoints[0]); - coordinate.setLng(insertPoints[1]); - distanceInfoMap.put(distance, coordinate); - startPoint.set(distance); - redis.hset( - scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), - "position", JSON.toJSONString(coordinate)); - - Global.sendCmdInfoQueue.add( - ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, - scenarioTask.getScenarioId(), dataMap)); - - } else if (Double.compare(distance, endPoint.getKey()) == 0) { - NavigableMap subPathMap = distanceInfoMap.subMap(startPoint.get(), - true, endPoint.getKey(), true); - for (Double key : subPathMap.keySet()) { - Coordinate coordinate = subPathMap.get(key); - dataList.add(new double[]{coordinate.getLng(), coordinate.getLat()}); - } - - startPoint.set(endPoint.getKey()); - Global.sendCmdInfoQueue.add( - ResponseCmdInfo.create(WsCmdTypeEnum.PATH_UPDATE.getCode(), roomId, - scenarioTask.getScenarioId(), dataMap)); - - } else { - //完成路径 - Global.sendCmdInfoQueue.add( - ResponseCmdInfo.create(WsCmdTypeEnum.PATH_FINISHED.getCode(), roomId, - scenarioTask.getScenarioId(), dataMap)); - } - } - } catch (Exception e) { - log.error("error::", e); - } - }, 0, 1, TimeUnit.SECONDS); - - //房间统一管理定时器;房间关闭后,定时器销毁 - addScheduledExecutorServiceRefenceToRoom(schedule); - } - private void fuelConsumption() { ScheduledExecutorService schedule = Executors.newScheduledThreadPool( 1); schedule.scheduleWithFixedDelay(() -> { if (getRoomStatus()) { - double total = consumptionTaskInterval * SPEED / 1000 * fuelConsumption; + double currentUseUp = consumptionTaskInterval * SPEED / 1000 * fuelConsumption; + + + //更新redis中油品的消耗 Object currentFuelObj = redis.hget( scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), - "fuel"); + "fuelConsume"); if (currentFuelObj != null) { double fuel = Double.parseDouble(currentFuelObj.toString()); - if (fuel > 0) { - fuel = fuel - total < 0 ? 0 : fuel - total; + fuel = fuel + currentUseUp; //更新值 redis.hset( scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), - "fuel", fuel); - //推送前端 + "fuelConsume", fuel); + + double totalFuel = statisticBean.getFuel().getTotal(); + if(fuel*100/totalFuel Date: Fri, 19 Sep 2025 12:16:49 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E4=BB=BB=E5=8A=A1=E7=9B=B8=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hivekion/room/bean/AbtParentTask.java | 10 +++++++--- src/main/java/com/hivekion/room/bean/MoveRootTask.java | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/hivekion/room/bean/AbtParentTask.java b/src/main/java/com/hivekion/room/bean/AbtParentTask.java index 8016256..73c94da 100644 --- a/src/main/java/com/hivekion/room/bean/AbtParentTask.java +++ b/src/main/java/com/hivekion/room/bean/AbtParentTask.java @@ -14,7 +14,6 @@ import com.hivekion.enums.WsCmdTypeEnum; import com.hivekion.room.RoomManager; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.ScenarioTask; -import com.hivekion.statistic.bean.StatisticBean; import java.time.Duration; import java.util.ArrayList; import java.util.HashMap; @@ -46,6 +45,7 @@ import org.springframework.web.reactive.function.client.WebClient; */ @Slf4j public abstract class AbtParentTask implements TaskAction { + /** * 开始点坐标 */ @@ -125,7 +125,7 @@ public abstract class AbtParentTask implements TaskAction { } - protected void initPath(){ + protected void initPath() { try { String url = SpringUtil.getBean(Environment.class).getProperty("path.planning.url"); @@ -195,7 +195,8 @@ public abstract class AbtParentTask implements TaskAction { log.error("error::", e); } } - protected void updatePath(double speed) { + + protected void updatePath(double speed, TaskAction action) { ScheduledExecutorService schedule = Executors.newScheduledThreadPool( 1); @@ -264,6 +265,9 @@ public abstract class AbtParentTask implements TaskAction { scenarioTask.getScenarioId(), dataMap)); } else { + if (action != null) { + action.doSomeThing(); + } //完成路径 Global.sendCmdInfoQueue.add( ResponseCmdInfo.create(WsCmdTypeEnum.PATH_FINISHED.getCode(), roomId, diff --git a/src/main/java/com/hivekion/room/bean/MoveRootTask.java b/src/main/java/com/hivekion/room/bean/MoveRootTask.java index 79c4f27..f6d7b45 100644 --- a/src/main/java/com/hivekion/room/bean/MoveRootTask.java +++ b/src/main/java/com/hivekion/room/bean/MoveRootTask.java @@ -75,7 +75,7 @@ public class MoveRootTask extends AbtParentTask implements TaskAction { initEnv(); //初始化环境 initPath(); //初始化路径 - updatePath(SPEED); //更新路径 + updatePath(SPEED,null); //更新路径 fuelConsumption();//油品消耗 }