Merge branch 'master' of http://101.43.238.71:3000/zouju/auto-solution
This commit is contained in:
@@ -97,6 +97,19 @@ public class BehaviortreeController extends BaseController
|
|||||||
return toAjax(behaviortreeProcessor.create(behaviortree));
|
return toAjax(behaviortreeProcessor.create(behaviortree));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制行为树
|
||||||
|
*/
|
||||||
|
@ApiOperation("复制行为树")
|
||||||
|
@PreAuthorize("@ss.hasPermi('system:behaviortree:add')")
|
||||||
|
@Log(title = "行为树主", businessType = BusinessType.INSERT)
|
||||||
|
@PostMapping("/copy")
|
||||||
|
public AjaxResult copy(@RequestBody Behaviortree behaviortree)
|
||||||
|
{
|
||||||
|
//return toAjax(behaviortreeService.copy(behaviortree));
|
||||||
|
return toAjax(behaviortreeProcessor.copy(behaviortree));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改行为树主
|
* 修改行为树主
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ package com.solution.web.core;
|
|||||||
* that was distributed with this source code.
|
* that was distributed with this source code.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import cn.hutool.core.util.ObjectUtil;
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import com.solution.common.constant.ExceptionConstants;
|
||||||
import com.solution.system.domain.*;
|
import com.solution.system.domain.*;
|
||||||
import com.solution.system.service.IBehaviortreeService;
|
import com.solution.system.service.IBehaviortreeService;
|
||||||
import com.solution.system.service.INodeconnectionService;
|
import com.solution.system.service.INodeconnectionService;
|
||||||
@@ -20,6 +22,7 @@ import com.solution.web.core.graph.GraphEdge;
|
|||||||
import com.solution.web.core.graph.GraphNode;
|
import com.solution.web.core.graph.GraphNode;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -56,6 +59,7 @@ public class BehaviortreeProcessor {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int update(Behaviortree behaviortree) {
|
public int update(Behaviortree behaviortree) {
|
||||||
int result = behaviortreeService.updateBehaviortree(behaviortree);
|
int result = behaviortreeService.updateBehaviortree(behaviortree);
|
||||||
|
|
||||||
@@ -74,7 +78,7 @@ public class BehaviortreeProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void processGraph(Behaviortree behaviortree) {
|
private void processGraph(Behaviortree behaviortree) {
|
||||||
|
//代码丢失 原:libertyspy 改:MHW
|
||||||
Graph graph = null;
|
Graph graph = null;
|
||||||
try {
|
try {
|
||||||
graph = objectMapper.readValue(behaviortree.getXmlContent(), Graph.class);
|
graph = objectMapper.readValue(behaviortree.getXmlContent(), Graph.class);
|
||||||
@@ -223,4 +227,23 @@ public class BehaviortreeProcessor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 复制行为树
|
||||||
|
* @param behaviortree
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public int copy(Behaviortree behaviortree) {
|
||||||
|
if(ObjectUtil.isEmpty(behaviortree)){
|
||||||
|
throw new RuntimeException(ExceptionConstants.PARAMETER_EXCEPTION);
|
||||||
|
}
|
||||||
|
String name = behaviortree.getName();
|
||||||
|
String newName = name + "_" + behaviortree.getId();
|
||||||
|
|
||||||
|
String englishName = behaviortree.getEnglishName();
|
||||||
|
String newEnglishName = englishName + "_" + behaviortree.getId();
|
||||||
|
behaviortree.setEnglishName(newEnglishName);
|
||||||
|
behaviortree.setName(newName);
|
||||||
|
|
||||||
|
return this.create(behaviortree);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,16 +20,21 @@ import com.solution.rule.domain.ultimately.vo.FireRuleRedPlatformSlotVO;
|
|||||||
import com.solution.rule.domain.ultimately.vo.FireRuleRedWeaponSlotVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleRedWeaponSlotVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleOutputVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleOutputVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleRouteTrackPointVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleRouteTrackPointVO;
|
||||||
|
import com.solution.rule.domain.ultimately.vo.FireRuleSceneGroupNodeVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleSceneTaskNodeVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleSceneTaskNodeVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleSceneTaskPayloadVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleSceneTaskPayloadVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleTrackParamVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleTrackParamVO;
|
||||||
import com.solution.rule.domain.ultimately.vo.FireRuleTrackRouteVO;
|
import com.solution.rule.domain.ultimately.vo.FireRuleTrackRouteVO;
|
||||||
|
import com.solution.rule.domain.ultimately.vo.FireRuleWingmanDataVO;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
@@ -231,6 +236,241 @@ public final class FireRuleRedWeaponOutputFillHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编组规则:按红方装备列表分组,写入 {@link FireRuleTrackParamVO#getGroups}(JSON 键 Groups),
|
||||||
|
* groupType=addGroup,drawName=领队装备名+后缀;僚机 wingmanData 中 name 为红方 equipmentId。
|
||||||
|
* 多蓝方任务循环时与航迹一致:在已有 Groups 上追加,且 group id 与已有项冲突时自动加后缀。
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static void fillTrackParamGroups(FireRuleOutputVO out, FireRuleTaskInputDTO blueTask, Map params) {
|
||||||
|
if (out == null || blueTask == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
boolean enabled = Boolean.parseBoolean(String.valueOf(params.getOrDefault("groupRuleEnabled", true)));
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<FireRuleRedWeaponEquipmentVO> reds = out.getRedWeapons();
|
||||||
|
if (reds == null || reds.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ensureTrackParam(out);
|
||||||
|
|
||||||
|
String dirMode = str(params, "trackPointDirectionMode", "head2next");
|
||||||
|
double fallbackBrg = readDouble(params, "trackFallbackBearingDeg", readDouble(params, "fallbackBearingDeg", 0d));
|
||||||
|
double mainBearing = computeTrackBearingDeg(blueTask, dirMode, fallbackBrg);
|
||||||
|
|
||||||
|
String mode = str(params, "groupFormationMode", "onePerRed");
|
||||||
|
int clusterSize = readInt(params, "groupClusterSize", 3);
|
||||||
|
if (clusterSize < 1) {
|
||||||
|
clusterSize = 1;
|
||||||
|
}
|
||||||
|
int minWing = readInt(params, "groupMinMembersForWingman", 2);
|
||||||
|
|
||||||
|
List<List<FireRuleRedWeaponEquipmentVO>> buckets = splitRedsIntoGroups(reds, mode, clusterSize);
|
||||||
|
List<FireRuleSceneGroupNodeVO> batch = new ArrayList<>();
|
||||||
|
String blueSeg = sanitizeRouteIdSegment(nz(blueTask.getId()));
|
||||||
|
int gidx = 0;
|
||||||
|
for (List<FireRuleRedWeaponEquipmentVO> bucket : buckets) {
|
||||||
|
if (bucket == null || bucket.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
FireRuleRedWeaponEquipmentVO leader = pickGroupLeader(bucket, params);
|
||||||
|
if (leader == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
FireRuleSceneGroupNodeVO node = new FireRuleSceneGroupNodeVO();
|
||||||
|
String baseId = "group_" + blueSeg + "_" + gidx;
|
||||||
|
node.setId(ensureUniqueGroupId(out.getTrackParam(), baseId));
|
||||||
|
String suffix = str(params, "groupDrawNameSuffix", "编组");
|
||||||
|
boolean withIndex = Boolean.parseBoolean(String.valueOf(params.getOrDefault("groupDrawNameWithIndex", false)));
|
||||||
|
String drawName = nz(leader.getName()) + suffix;
|
||||||
|
if (withIndex) {
|
||||||
|
drawName += (gidx + 1);
|
||||||
|
}
|
||||||
|
node.setDrawName(drawName);
|
||||||
|
node.setGroupType("addGroup");
|
||||||
|
node.setName("addGroup");
|
||||||
|
node.setLeader(nz(leader.getEquipmentId()));
|
||||||
|
node.setSort(System.currentTimeMillis() + gidx);
|
||||||
|
node.setWingmanData(buildWingmanData(bucket, leader, mainBearing, params, minWing));
|
||||||
|
batch.add(node);
|
||||||
|
gidx++;
|
||||||
|
}
|
||||||
|
mergeGroupsIntoTrackParam(out.getTrackParam(), batch);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<List<FireRuleRedWeaponEquipmentVO>> splitRedsIntoGroups(
|
||||||
|
List<FireRuleRedWeaponEquipmentVO> reds, String mode, int clusterSize) {
|
||||||
|
List<FireRuleRedWeaponEquipmentVO> clean = new ArrayList<>();
|
||||||
|
for (FireRuleRedWeaponEquipmentVO r : reds) {
|
||||||
|
if (r != null) {
|
||||||
|
clean.add(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<List<FireRuleRedWeaponEquipmentVO>> out = new ArrayList<>();
|
||||||
|
if (clean.isEmpty()) {
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if ("singleGroup".equalsIgnoreCase(mode)) {
|
||||||
|
out.add(clean);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
if ("clusterByCount".equalsIgnoreCase(mode)) {
|
||||||
|
for (int i = 0; i < clean.size(); i += clusterSize) {
|
||||||
|
int end = Math.min(i + clusterSize, clean.size());
|
||||||
|
out.add(new ArrayList<>(clean.subList(i, end)));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
for (FireRuleRedWeaponEquipmentVO r : clean) {
|
||||||
|
out.add(Collections.singletonList(r));
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FireRuleRedWeaponEquipmentVO pickGroupLeader(List<FireRuleRedWeaponEquipmentVO> bucket, Map params) {
|
||||||
|
if (bucket == null || bucket.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String mode = str(params, "groupLeaderPickMode", "byHitRateThenId");
|
||||||
|
FireRuleRedWeaponEquipmentVO best = bucket.get(0);
|
||||||
|
for (int i = 1; i < bucket.size(); i++) {
|
||||||
|
FireRuleRedWeaponEquipmentVO cur = bucket.get(i);
|
||||||
|
if ("byId".equalsIgnoreCase(mode)) {
|
||||||
|
if (compareEquipmentId(cur, best) < 0) {
|
||||||
|
best = cur;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isBetterLeaderByHitRateThenId(cur, best)) {
|
||||||
|
best = cur;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isBetterLeaderByHitRateThenId(FireRuleRedWeaponEquipmentVO cand, FireRuleRedWeaponEquipmentVO inc) {
|
||||||
|
double rc = leaderRad(cand);
|
||||||
|
double ri = leaderRad(inc);
|
||||||
|
int c = Double.compare(rc, ri);
|
||||||
|
if (c > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (c < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return compareEquipmentId(cand, inc) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double leaderRad(FireRuleRedWeaponEquipmentVO w) {
|
||||||
|
if (w == null || w.getSuccessTargetRad() == null) {
|
||||||
|
return -1d;
|
||||||
|
}
|
||||||
|
return w.getSuccessTargetRad().doubleValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int compareEquipmentId(FireRuleRedWeaponEquipmentVO a, FireRuleRedWeaponEquipmentVO b) {
|
||||||
|
String sa = a != null ? nz(a.getEquipmentId()) : "";
|
||||||
|
String sb = b != null ? nz(b.getEquipmentId()) : "";
|
||||||
|
return sa.compareTo(sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<FireRuleWingmanDataVO> buildWingmanData(
|
||||||
|
List<FireRuleRedWeaponEquipmentVO> bucket,
|
||||||
|
FireRuleRedWeaponEquipmentVO leader,
|
||||||
|
double mainBearing,
|
||||||
|
Map params,
|
||||||
|
int minMembersForWingman) {
|
||||||
|
if (bucket == null || leader == null || bucket.size() < minMembersForWingman) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
double distBase = readDouble(params, "wingmanDistanceBaseMeters", 100);
|
||||||
|
double distStep = readDouble(params, "wingmanDistanceStepMeters", 50);
|
||||||
|
double angBase = readDouble(params, "wingmanAngleBaseDeg", 50);
|
||||||
|
double angStep = readDouble(params, "wingmanAngleStepDeg", 15);
|
||||||
|
double altBase = readDouble(params, "wingmanAltBaseMeters", 40);
|
||||||
|
double altScale = readDouble(params, "wingmanAltScale", 1.0);
|
||||||
|
|
||||||
|
List<FireRuleWingmanDataVO> list = new ArrayList<>();
|
||||||
|
int wmIdx = 0;
|
||||||
|
for (FireRuleRedWeaponEquipmentVO r : bucket) {
|
||||||
|
if (r == null || r == leader) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
FireRuleWingmanDataVO w = new FireRuleWingmanDataVO();
|
||||||
|
w.setKey(wmIdx);
|
||||||
|
w.setName(nz(r.getEquipmentId()));
|
||||||
|
w.setDistance((int) Math.round(distBase + wmIdx * distStep));
|
||||||
|
double deg = normDeg(mainBearing + angBase + wmIdx * angStep);
|
||||||
|
w.setAngle(String.format(Locale.US, "%.1f", deg));
|
||||||
|
Double lh = extractFirstPlatformHeight(leader);
|
||||||
|
Double wh = extractFirstPlatformHeight(r);
|
||||||
|
double delta = 0d;
|
||||||
|
if (lh != null && wh != null) {
|
||||||
|
delta = wh - lh;
|
||||||
|
}
|
||||||
|
w.setAlt((int) Math.round(altBase + altScale * delta));
|
||||||
|
list.add(w);
|
||||||
|
wmIdx++;
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Double extractFirstPlatformHeight(FireRuleRedWeaponEquipmentVO red) {
|
||||||
|
if (red == null || red.getSubComponents() == null || red.getSubComponents().getPlatform() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (FireRuleRedPlatformSlotVO pl : red.getSubComponents().getPlatform()) {
|
||||||
|
if (pl == null || pl.getPositions() == null || pl.getPositions().size() < 3) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return pl.getPositions().get(2);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double normDeg(double deg) {
|
||||||
|
double a = deg % 360d;
|
||||||
|
if (a < 0) {
|
||||||
|
a += 360d;
|
||||||
|
}
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String ensureUniqueGroupId(FireRuleTrackParamVO tp, String baseId) {
|
||||||
|
Set<String> seen = new HashSet<>();
|
||||||
|
if (tp.getGroups() != null) {
|
||||||
|
for (FireRuleSceneGroupNodeVO g : tp.getGroups()) {
|
||||||
|
if (g != null && !isBlank(g.getId())) {
|
||||||
|
seen.add(g.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!seen.contains(baseId)) {
|
||||||
|
return baseId;
|
||||||
|
}
|
||||||
|
int k = 1;
|
||||||
|
while (seen.contains(baseId + "_" + k)) {
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
return baseId + "_" + k;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void mergeGroupsIntoTrackParam(FireRuleTrackParamVO tp, List<FireRuleSceneGroupNodeVO> batch) {
|
||||||
|
if (tp == null || batch == null || batch.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<FireRuleSceneGroupNodeVO> cur = tp.getGroups();
|
||||||
|
if (cur == null) {
|
||||||
|
cur = new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
cur = new ArrayList<>(cur);
|
||||||
|
}
|
||||||
|
cur.addAll(batch);
|
||||||
|
tp.setGroups(cur);
|
||||||
|
}
|
||||||
|
|
||||||
private static void ensureTrackParam(FireRuleOutputVO out) {
|
private static void ensureTrackParam(FireRuleOutputVO out) {
|
||||||
if (out.getTrackParam() == null) {
|
if (out.getTrackParam() == null) {
|
||||||
out.setTrackParam(new FireRuleTrackParamVO());
|
out.setTrackParam(new FireRuleTrackParamVO());
|
||||||
|
|||||||
@@ -245,6 +245,22 @@ public final class RuleFunction {
|
|||||||
FireRuleRedWeaponOutputFillHelper.fillTrackParamAndBindMoveRoute(out, fact.getTask(), p);
|
FireRuleRedWeaponOutputFillHelper.fillTrackParamAndBindMoveRoute(out, fact.getTask(), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编组规则:填充 {@link com.solution.rule.domain.ultimately.vo.FireRuleTrackParamVO#getGroups}(groupType=addGroup)与僚机 wingmanData。
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
public static void groupFormation(DroolsFact fact, Map globalParams) {
|
||||||
|
if (fact == null || fact.getTask() == null || fact.getFireRuleOutputVO() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Map<String, Object> p = castParams(globalParams);
|
||||||
|
boolean enabled = Boolean.parseBoolean(String.valueOf(p.getOrDefault("groupRuleEnabled", true)));
|
||||||
|
if (!enabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
FireRuleRedWeaponOutputFillHelper.fillTrackParamGroups(fact.getFireRuleOutputVO(), fact.getTask(), p);
|
||||||
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private static Map<String, Object> castParams(Map raw) {
|
private static Map<String, Object> castParams(Map raw) {
|
||||||
return raw == null ? new java.util.HashMap<>() : (Map<String, Object>) raw;
|
return raw == null ? new java.util.HashMap<>() : (Map<String, Object>) raw;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import static com.solution.rule.utils.RuleFunction.equipmentRule;
|
|||||||
import static com.solution.rule.utils.RuleFunction.target;
|
import static com.solution.rule.utils.RuleFunction.target;
|
||||||
import static com.solution.rule.utils.RuleFunction.position;
|
import static com.solution.rule.utils.RuleFunction.position;
|
||||||
import static com.solution.rule.utils.RuleFunction.trackRoute;
|
import static com.solution.rule.utils.RuleFunction.trackRoute;
|
||||||
|
import static com.solution.rule.utils.RuleFunction.groupFormation;
|
||||||
|
|
||||||
|
|
||||||
global java.util.Map globalParams;
|
global java.util.Map globalParams;
|
||||||
@@ -176,6 +177,29 @@ function Map buildParam(){
|
|||||||
param.put("trackJamWobbleMeters", 400);
|
param.put("trackJamWobbleMeters", 400);
|
||||||
param.put("trackJamSegments", 4);
|
param.put("trackJamSegments", 4);
|
||||||
|
|
||||||
|
// ===================== 编组规则参数(写入 TrackParam.Groups + wingmanData) =====================
|
||||||
|
// groupRuleEnabled:是否生成编组节点。
|
||||||
|
param.put("groupRuleEnabled", true);
|
||||||
|
// groupDrawNameSuffix:drawName = 领队装备 Name + 此后缀(默认「编组」)
|
||||||
|
param.put("groupDrawNameSuffix", "编组");
|
||||||
|
// groupDrawNameWithIndex:是否在 drawName 末尾追加序号(避免多组同名),如 J15编组1
|
||||||
|
param.put("groupDrawNameWithIndex", false);
|
||||||
|
// groupFormationMode:onePerRed(每件红装一组) / clusterByCount(按固定人数分组) / singleGroup(全部一组)
|
||||||
|
param.put("groupFormationMode", "onePerRed");
|
||||||
|
// groupClusterSize:clusterByCount 模式下每组人数上限(>=1)
|
||||||
|
param.put("groupClusterSize", 3);
|
||||||
|
// groupLeaderPickMode:byHitRateThenId(命中率高优先,平手 equipmentId 小) / byId(equipmentId 字典序最小)
|
||||||
|
param.put("groupLeaderPickMode", "byHitRateThenId");
|
||||||
|
// groupMinMembersForWingman:组内人数达到该值才生成 wingmanData(否则仅 leader 壳,僚机列表为空)
|
||||||
|
param.put("groupMinMembersForWingman", 2);
|
||||||
|
// wingman 几何参数(相对蓝方主航向 mainBearing 叠加)
|
||||||
|
param.put("wingmanDistanceBaseMeters", 100);
|
||||||
|
param.put("wingmanDistanceStepMeters", 50);
|
||||||
|
param.put("wingmanAngleBaseDeg", 50);
|
||||||
|
param.put("wingmanAngleStepDeg", 15);
|
||||||
|
param.put("wingmanAltBaseMeters", 40);
|
||||||
|
param.put("wingmanAltScale", 1.0);
|
||||||
|
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,3 +242,13 @@ then
|
|||||||
globalParams.putAll(buildParam());
|
globalParams.putAll(buildParam());
|
||||||
trackRoute($fact, globalParams);
|
trackRoute($fact, globalParams);
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rule "编组匹配"
|
||||||
|
salience 60
|
||||||
|
when
|
||||||
|
$fact : DroolsFact(task != null)
|
||||||
|
then
|
||||||
|
// 显式编组规则:填充 TrackParam.Groups(groupType=addGroup)与 wingmanData
|
||||||
|
globalParams.putAll(buildParam());
|
||||||
|
groupFormation($fact, globalParams);
|
||||||
|
end
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
image: mysql:8.0
|
image: autosolution-mysql-preloaded:latest
|
||||||
container_name: autosolution-mysql
|
container_name: autosolution-mysql
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
environment:
|
environment:
|
||||||
@@ -27,7 +27,7 @@ services:
|
|||||||
test:
|
test:
|
||||||
[
|
[
|
||||||
"CMD-SHELL",
|
"CMD-SHELL",
|
||||||
"mysql -h 127.0.0.1 -uroot -p$${MYSQL_ROOT_PASSWORD:-root} -Nse \"SELECT 1 FROM information_schema.tables WHERE table_schema='$${MYSQL_DATABASE:-autosolution_db}' AND table_name='sys_config' LIMIT 1\" | grep -q 1",
|
"mysql -h 127.0.0.1 -uroot -p$MYSQL_ROOT_PASSWORD -Nse 'SELECT 1 FROM information_schema.tables WHERE table_schema=\"$MYSQL_DATABASE\" AND table_name=\"sys_config\" LIMIT 1' | grep -q 1",
|
||||||
]
|
]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
|
|||||||
@@ -29,6 +29,12 @@
|
|||||||
</a-tooltip>
|
</a-tooltip>
|
||||||
<a-flex class="ks-tree-actions">
|
<a-flex class="ks-tree-actions">
|
||||||
<!-- <span style="margin-right: 10px"><EditFilled /></span>-->
|
<!-- <span style="margin-right: 10px"><EditFilled /></span>-->
|
||||||
|
<a-popconfirm
|
||||||
|
title="确定复制?"
|
||||||
|
@confirm="()=> handleCopy(item)"
|
||||||
|
>
|
||||||
|
<span class="ks-tree-action ks-tree-action-copy" @click.stop style="margin-right: 10px"><CopyOutlined /></span>
|
||||||
|
</a-popconfirm>
|
||||||
<a-popconfirm
|
<a-popconfirm
|
||||||
title="确定删除?"
|
title="确定删除?"
|
||||||
@confirm="()=> handleDelete(item)"
|
@confirm="()=> handleDelete(item)"
|
||||||
@@ -51,15 +57,16 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { defineComponent, onMounted, ref } from 'vue';
|
import { defineComponent, onMounted, ref } from 'vue';
|
||||||
import { CheckOutlined, DeleteOutlined, EditFilled, PlusOutlined } from '@ant-design/icons-vue';
|
import { CheckOutlined, CopyOutlined, DeleteOutlined, EditFilled, PlusOutlined } from '@ant-design/icons-vue';
|
||||||
import type { BehaviorTree, BehaviorTreeRequest } from './tree';
|
import type { BehaviorTree, BehaviorTreeRequest } from './tree';
|
||||||
import { deleteOneTreeById, findTreesByQuery } from './api';
|
import { copyTree, deleteOneTreeById, findTreesByQuery } from './api';
|
||||||
import { substring } from '@/utils/strings';
|
import { substring } from '@/utils/strings';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
emits: ['select-tree', 'create-tree'],
|
emits: ['select-tree', 'create-tree'],
|
||||||
components: {
|
components: {
|
||||||
CheckOutlined,
|
CheckOutlined,
|
||||||
|
CopyOutlined,
|
||||||
PlusOutlined,
|
PlusOutlined,
|
||||||
DeleteOutlined,
|
DeleteOutlined,
|
||||||
EditFilled,
|
EditFilled,
|
||||||
@@ -95,6 +102,14 @@ export default defineComponent({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCopy = (item: BehaviorTree) => {
|
||||||
|
copyTree({ id: item.id }).then(r => {
|
||||||
|
if (r.code === 200) {
|
||||||
|
loadTress();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
@@ -133,6 +148,7 @@ export default defineComponent({
|
|||||||
handleSelect,
|
handleSelect,
|
||||||
handleChange,
|
handleChange,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
|
handleCopy,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ export const createGraphConnectingAttributes = (): Partial<Connecting> => {
|
|||||||
export const createGraphCanvas = (container: HTMLDivElement, readonly: boolean = false): Graph => {
|
export const createGraphCanvas = (container: HTMLDivElement, readonly: boolean = false): Graph => {
|
||||||
const graph = new Graph({
|
const graph = new Graph({
|
||||||
container: container,
|
container: container,
|
||||||
|
autoResize: true,
|
||||||
grid: {
|
grid: {
|
||||||
size: 20,
|
size: 20,
|
||||||
visible: true,
|
visible: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user