Merge branch 'refs/heads/develop'

# Conflicts:
#	auto-solution-rule/src/main/resources/rules/README.md
This commit is contained in:
MHW
2026-03-30 16:43:45 +08:00

View File

@@ -149,6 +149,14 @@ function Map buildBusinessConfig() {
cfg.put("blueMissileRangeDefault", 220); // 蓝方导弹范围默认值
cfg.put("minBlueMissileCountForLinkage", 1); // 联动触发门槛
// ---------- 全组件数量匹配(可改) ----------
// 逻辑:按红方武器 targetId 找到对应蓝方装备equipmentId然后覆盖所有“非导弹组件”的数量
cfg.put("enableComponentQuantityMatch", Boolean.TRUE);
// 格式示例:蓝穿甲弹->红穿甲弹,蓝火控雷达->红火控雷达;为空则默认 deviceName 一致匹配
cfg.put("componentDeviceNameMappingCsv", "");
// 跳过覆盖:蓝方组件 deviceName 包含该关键词则不覆盖(默认用来保留导弹联动偏移)
cfg.put("skipMissileComponentsByNameContains", "导弹");
// ---------- 任务自动命名模板(可改) ----------
// 任务分类优先级:导弹突击 > 防空压制 > 反装甲打击 > 炮火压制 > 通用打击
cfg.put("taskName_missile_strike", "导弹突击打击任务");
@@ -219,6 +227,18 @@ then
applyMissileLinkage($fact, cfg);
end
//-------------------------------------------------------------------------------
// 全组件数量匹配:按 redWeapon.targetId 对应蓝方装备,覆盖“非导弹组件”的数量
rule "全组件数量匹配规则"
agenda-group "打击任务"
salience 53
when
$fact : FactTask(blueTask.side == "蓝方", redTask.side == "红方")
then
Map cfg = buildBusinessConfig();
applyAllComponentQuantities($fact, cfg);
end
//-------------------------------------------------------------------------------
rule "任务自动匹配规则"
agenda-group "打击任务"
@@ -582,6 +602,159 @@ function void bindTargetIdsForRedWeapons(List redWeapons, List blueWeapons, Map
}
}
//-------------------------------------------------------------------------------
// component 映射解析 + 全组件数量覆盖
function Map parseDeviceNameMapping(String csv) {
Map result = new java.util.HashMap();
if (csv == null) {
return result;
}
String text = csv.trim();
if (text.equals("")) {
return result;
}
String[] parts = text.split(",");
for (int i = 0; i < parts.length; i++) {
String one = parts[i];
if (one == null) {
continue;
}
String item = one.trim();
if (item.equals("")) {
continue;
}
int idx = item.indexOf("->");
if (idx <= 0 || idx >= item.length() - 2) {
continue;
}
String left = item.substring(0, idx).trim();
String right = item.substring(idx + 2).trim();
if (left.equals("") || right.equals("")) {
continue;
}
result.put(left, right);
}
return result;
}
function void applyAllComponentQuantities(FactTask fact, Map cfg) {
if (fact == null || fact.getBlueTask() == null || fact.getRedTask() == null) {
return;
}
if (!readBooleanCfg(cfg, "enableComponentQuantityMatch", true)) {
return;
}
Task blueTask = fact.getBlueTask();
Task redTask = fact.getRedTask();
List blueWeapons = blueTask.getTaskWeapons();
List redWeapons = redTask.getTaskWeapons();
if (blueWeapons == null || blueWeapons.isEmpty() || redWeapons == null || redWeapons.isEmpty()) {
return;
}
String mappingCsv = cfg == null ? null : (String) cfg.get("componentDeviceNameMappingCsv");
Map deviceNameMapping = parseDeviceNameMapping(mappingCsv);
String skipKeyword = cfg == null ? null : (String) cfg.get("skipMissileComponentsByNameContains");
if (skipKeyword != null) {
skipKeyword = skipKeyword.trim();
if (skipKeyword.equals("")) {
skipKeyword = null;
}
}
// 遍历红方每个武器:用 targetId 找蓝方装备equipmentId
for (Object objR : redWeapons) {
Weapon redWeapon = (Weapon) objR;
if (redWeapon == null) {
continue;
}
String targetId = redWeapon.getTargetId();
if (isBlank(targetId)) {
// 允许不匹配targetId 为空直接跳过
continue;
}
Weapon blueWeapon = null;
for (Object objB : blueWeapons) {
Weapon w = (Weapon) objB;
if (w == null) {
continue;
}
String eqId = w.getEquipmentId();
if (eqId != null && eqId.equals(targetId)) {
blueWeapon = w;
break;
}
}
if (blueWeapon == null) {
continue;
}
List blueComps = blueWeapon.getComponents();
List redComps = redWeapon.getComponents();
if (blueComps == null || blueComps.isEmpty() || redComps == null || redComps.isEmpty()) {
continue;
}
// 用蓝方组件驱动覆盖红方组件数量
for (Object objBC : blueComps) {
SubComponents blueComp = (SubComponents) objBC;
if (blueComp == null) {
continue;
}
String blueCompName = blueComp.getDeviceName();
if (isBlank(blueCompName)) {
continue;
}
// 跳过导弹组件覆盖,避免覆盖导弹联动偏移逻辑
if (skipKeyword != null && blueCompName.contains(skipKeyword)) {
continue;
}
String redCompName = (String) deviceNameMapping.get(blueCompName);
if (redCompName == null || redCompName.trim().equals("")) {
redCompName = blueCompName;
}
SubComponents redComp = null;
for (Object objRC : redComps) {
SubComponents rc = (SubComponents) objRC;
if (rc == null) {
continue;
}
if (redCompName.equals(rc.getDeviceName())) {
redComp = rc;
break;
}
}
if (redComp == null) {
// 允许不匹配:红方下没有该组件则跳过
continue;
}
List blueParams = blueComp.getComponentParams();
List redParams = redComp.getComponentParams();
if (blueParams == null || blueParams.isEmpty() || redParams == null || redParams.isEmpty()) {
continue;
}
ComponentParam blueFirst = (ComponentParam) blueParams.get(0);
ComponentParam redFirst = (ComponentParam) redParams.get(0);
if (blueFirst == null || redFirst == null) {
continue;
}
if (blueFirst.getNumber() == null) {
continue;
}
// 只覆盖数量componentParams[0].number
redFirst.setNumber(blueFirst.getNumber());
}
}
}
function void prepareDeploymentPools(FactTask fact, Map cfg, Map runtime) {
if (!readBooleanCfg(cfg, "enablePositionRules", true)) {
return;