package com.hivekion.room.bean; import cn.hutool.extra.spring.SpringUtil; import com.alibaba.fastjson2.JSON; import com.hivekion.Global; import com.hivekion.common.entity.ResponseCmdInfo; import com.hivekion.common.redis.RedisUtil; import com.hivekion.common.uuid.IdUtils; import com.hivekion.room.RoomManager; import com.hivekion.room.func.TaskAction; import com.hivekion.scenario.entity.BattleConsume; import com.hivekion.scenario.entity.ScenarioResource; import com.hivekion.scenario.entity.ScenarioTask; import com.hivekion.scenario.service.impl.BattleConsumeServiceImpl; import com.hivekion.scenario.service.impl.BattleSupplierServiceImpl; import com.hivekion.scenario.service.impl.ScenarioTaskServiceImpl; import com.hivekion.statistic.bean.ScenarioInfo; import com.hivekion.statistic.bean.StatisticBean; import com.hivekion.statistic.service.impl.StatisticServiceImpl; import com.hivekion.supplier.entity.SupplierRequest; import com.hivekion.supplier.service.impl.SupplierRequestServiceImpl; import java.time.LocalDateTime; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import lombok.extern.slf4j.Slf4j; import org.springframework.core.env.Environment; /** * [类的简要说明] *

* [详细描述,可选] *

* * @author LiDongYU * @since 2025/7/22 */ @Slf4j public class MoveTask extends AbtParentTask implements TaskAction { /** * 速度 换算为100Km/小时 */ private final double SPEED = 27; /** * 需求产生标志 */ private final AtomicBoolean requestFlag = new AtomicBoolean(false); /** * 油料消耗速率 */ private double fuelConsumption = 0; private double fuelThreshold = 0; /** * 消耗任务间隔 */ private final int consumptionTaskInterval = 10; /** * redis 服务类 */ private final RedisUtil redis = SpringUtil.getBean(RedisUtil.class); private StatisticBean statisticBean; public MoveTask(ScenarioTask scenarioTask, String roomId) { super(scenarioTask, roomId); } @Override public void doSomeThing() { log.info("move task running:{},fuel::{}", scenarioTask.getResourceId(), getCurrentFuel()); initEnv(); //初始化环境 initPath(); //初始化路径 updatePath(SPEED, new TaskAction() { @Override public void doSomeThing() { //推送移动任务 Map map = new HashMap<>(); map.put("duringTime", getDuringTime()); map.put("id", scenarioTask.getResourceId()); map.put("roomStatus", true); map.put("type", scenarioTask.getType()); Global.sendCmdInfoQueue.add( ResponseCmdInfo.create("moveTask", roomId, scenarioTask.getScenarioId(), map)); } @Override public String getId() { return ""; } @Override public String getType() { return ""; } }, null); //更新路径 fuelConsumption();//油品消耗 } /** * 初始化环境 */ private void initEnv() { try { //获取油品消耗规则 String fuelConsumptionStr = SpringUtil.getBean(Environment.class) .getProperty("fuel.spreed"); fuelConsumption = Double.parseDouble(fuelConsumptionStr == null ? "0" : fuelConsumptionStr); fuelThreshold = Double.parseDouble(SpringUtil.getBean(Environment.class) .getProperty("fuel.warn", "0")); log.info("初始化::{}-油料消耗速度::{},油料最低阈值::{},当前油料::{}", this.scenarioTask.getResourceId(), fuelConsumptionStr, fuelThreshold,getCurrentFuel()); statisticBean = SpringUtil.getBean(StatisticServiceImpl.class) .statistic(scenarioTask.getResourceId()); } catch (Exception e) { log.error("init env exception", e); } } private void fuelConsumption() { try { ScheduledExecutorService schedule = Executors.newScheduledThreadPool( 1); schedule.scheduleWithFixedDelay(() -> { if (getRoomStatus() && this.canMoved.get()) { double currentUseUp = consumptionTaskInterval*RoomManager.getMag(roomId) * SPEED / 1000 * fuelConsumption; double fuel = getCurrentFuel(); log.info("{}-当前消耗油料::{},当前剩余油料::{}", scenarioTask.getResourceId(), currentUseUp, fuel); fuel = fuel - currentUseUp; if (fuel <= 0) { log.error("{}-油料为空", scenarioTask.getResourceId()); this.canMoved.set(false); log.info("{},can:{}", scenarioTask.getResourceId(), this.canMoved.get()); return; } setCurrentFuel(currentUseUp); double totalFuel = statisticBean.getFuel().getTotal(); log.info("{}-当前比值{},阈值{}", scenarioTask.getResourceId(), fuel * 100 / totalFuel, fuelThreshold); if (fuel * 100 / totalFuel < fuelThreshold && !requestFlag.get()) { log.info("{}-油料不足,需要补充,新建需求和任务", scenarioTask.getResourceId()); this.canMoved.set(false); requestFlag.set(true); //需要产生需求 produceFuelRequest(); //产生任务 produceTask(); } //插入消耗表 insertConsumption(currentUseUp); pushStatus(scenarioTask.getResourceId()); } if (!this.canMoved.get()) { //判断油料是否满足 double totalFuel = statisticBean.getFuel().getTotal(); if (Double.compare(this.getCurrentFuel(), totalFuel) >= 0) { this.canMoved.set(true); } } }, 0, consumptionTaskInterval, TimeUnit.SECONDS); } catch (Exception e) { log.error("fuel consumption exception", e); } } private void produceFuelRequest() { log.info("{}-产生油料保障需求", this.scenarioTask.getResourceId()); SupplierRequest supplierRequest = new SupplierRequest(); supplierRequest.setId(IdUtils.simpleUUID()); supplierRequest.setFromResourceId(scenarioTask.getResourceId()); supplierRequest.setSupplierNum(String.valueOf(statisticBean.getFuel().getTotal())); supplierRequest.setSupplierType("fuel"); supplierRequest.setGeneralTime(LocalDateTime.now()); supplierRequest.setLat(scenarioTask.getToLat()); supplierRequest.setLng(scenarioTask.getToLng()); supplierRequest.setHandleFlag(1); SpringUtil.getBean(SupplierRequestServiceImpl.class).save(supplierRequest); } private void produceTask() { try { log.info("{}-产生自动保障任务", this.scenarioTask.getResourceId()); List resourceList = SpringUtil.getBean(BattleSupplierServiceImpl.class) .selectSupplierResource(scenarioTask.getResourceId()); log.info("{}-可选保障分队长度{}", scenarioTask.getResourceId(), resourceList.size()); if (!resourceList.isEmpty()) { ScenarioTask task = new ScenarioTask(); task.setId(IdUtils.simpleUUID()); task.setScenarioId(scenarioTask.getScenarioId()); task.setResourceId(resourceList.get(0).getId()); task.setTaskType("6"); task.setInsureResourceId(scenarioTask.getResourceId()); task.setSupplierNum(statisticBean.getFuel().getTotal()); task.setToLat(this.coordinateReference.get().getLat() + ""); task.setToLng(this.coordinateReference.get().getLng() + ""); task.setStartTime(LocalDateTime.now()); task.setFromLat(resourceList.get(0).getLat()); task.setFromLng(resourceList.get(0).getLng()); task.setFromSource("general"); log.info("{}-保障分队id::{},from::{},to::{}", this.scenarioTask.getInsureResourceId(), task.getResourceId(), task.getFromLat() + "," + task.getFromLng(), task.getToLat() + "," + task.getToLng()); SpringUtil.getBean(ScenarioTaskServiceImpl.class).save(task); //增加到房间任务 SupplierTask supplierTask = new SupplierTask(task, roomId); //立即执行 RoomManager.addAction(roomId, 0, supplierTask); } else { log.error("{}-没有保障分队可以选择", scenarioTask.getResourceId()); } } catch (Exception e) { log.error("produceTask exception", e); } } private void insertConsumption(double num) { try{ log.info("{}-插入油料消耗::{}", this.scenarioTask.getResourceId(), num); BattleConsume battleConsume = new BattleConsume(); battleConsume.setId(IdUtils.simpleUUID()); battleConsume.setResourceId(scenarioTask.getResourceId()); battleConsume.setFuel(num); battleConsume.setConsumeDate(LocalDateTime.now()); SpringUtil.getBean(BattleConsumeServiceImpl.class).save(battleConsume); }catch (Exception e){ log.error("insertConsumption exception", e); } } private double getCurrentFuel() { Object statisticObj = redis.hget( scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), "scenarioInfo"); if (statisticObj != null) { ScenarioInfo scenarioInfo = JSON.parseObject(statisticObj.toString(), ScenarioInfo.class); return scenarioInfo.getFuel().getCurrent(); } return 0; } private void setCurrentFuel(double num) { Object statisticObj = redis.hget( scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), "scenarioInfo"); if (statisticObj != null) { ScenarioInfo scenarioInfo = JSON.parseObject(statisticObj.toString(), ScenarioInfo.class); scenarioInfo.getFuel().setCurrent(scenarioInfo.getFuel().getCurrent() - num); redis.hset(scenarioTask.getScenarioId() + "-" + roomId + "-" + scenarioTask.getResourceId(), "scenarioInfo", JSON.toJSONString(scenarioInfo)); } } }