v1.1.8: 刷新地图时核对已占领区块,丢弃地图未确认的超期假占领,修复高地空洞
这个提交包含在:
@@ -24,6 +24,7 @@ import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
@@ -65,6 +66,16 @@ public final class TerritoryDataService {
|
||||
private volatile long lastSuccessfulFetchMillis;
|
||||
/** 最近一次尝试拉取的时间戳(毫秒) */
|
||||
private volatile long lastAttemptMillis;
|
||||
/** 会话内新占领区块的本地记录时间(毫秒),用于刷新时判断该占领是否已被地图数据确认 */
|
||||
private final Map<ChunkPos, Long> sessionClaimTimes = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 会话占领"确认宽限"时长(毫秒)。
|
||||
*
|
||||
* <p>占领成功后,服务器动态地图(Dynmap/markers.json)可能尚未同步该区块,
|
||||
* 因此在宽限期内即使地图未确认也先保留"会话占领"标记,避免刚占领的区块被误判为假占领。
|
||||
* 超过宽限期仍未在地图中确认的,视为未真正占领并丢弃,使空洞区块能重新进入规划。
|
||||
*/
|
||||
private static final long CLAIM_CONFIRM_GRACE_MS = 120_000L;
|
||||
|
||||
public TerritoryDataService() {
|
||||
this.executor = TerritoryDataService.newExecutor();
|
||||
@@ -111,8 +122,8 @@ public final class TerritoryDataService {
|
||||
|
||||
/**
|
||||
* 异步刷新领土数据(在调度线程中执行)。
|
||||
* 拉取成功后解析 JSON,并把上一份模型中的"会话新占领区块"合并进新模型,
|
||||
* 避免刷新覆盖掉本次会话的占领记录。
|
||||
* 拉取成功后解析 JSON,并把上一份模型中的"会话新占领区块"与刚拉取的最新地图数据仔细核对,
|
||||
* 只保留"已被地图确认"或"刚占领未超宽限期"的占领记录,避免刷新时把假占领永久留在模型里。
|
||||
*/
|
||||
public void refreshAsync() {
|
||||
this.executor.execute(() -> {
|
||||
@@ -127,8 +138,25 @@ public final class TerritoryDataService {
|
||||
TerritoryModel parsed = TerritoryDataService.parse(response.body());
|
||||
TerritoryModel previous = this.model;
|
||||
if (previous != null) {
|
||||
long now = System.currentTimeMillis();
|
||||
// 本次拉取到的己方领土区块(地图数据即最终依据,无需缓存旧数据)
|
||||
Set<ChunkPos> freshOwn = new HashSet<>();
|
||||
TerritoryState freshSelf = parsed.state(this.selectedStateName);
|
||||
if (freshSelf != null) {
|
||||
freshOwn.addAll(freshSelf.chunks());
|
||||
}
|
||||
for (ChunkPos sessionClaim : previous.sessionClaims()) {
|
||||
parsed.addSessionClaim(sessionClaim);
|
||||
Long claimTime = this.sessionClaimTimes.get(sessionClaim);
|
||||
boolean confirmed = freshOwn.contains(sessionClaim);
|
||||
boolean withinGrace = claimTime != null && now - claimTime < CLAIM_CONFIRM_GRACE_MS;
|
||||
if (confirmed || withinGrace) {
|
||||
// 地图已确认,或尚在宽限期(Dynmap 可能还没同步):保留会话占领标记
|
||||
parsed.addSessionClaim(sessionClaim);
|
||||
} else if (claimTime != null) {
|
||||
// 地图始终未确认且超时:判定为假占领并移除,使空洞区块重新进入规划
|
||||
this.sessionClaimTimes.remove(sessionClaim);
|
||||
}
|
||||
// claimTime 为 null(从未在本服务记录)也视为未确认:不保留
|
||||
}
|
||||
}
|
||||
parsed.setSelfStateName(this.selectedStateName);
|
||||
@@ -163,6 +191,7 @@ public final class TerritoryDataService {
|
||||
}
|
||||
|
||||
public void addSessionClaim(ChunkPos chunk) {
|
||||
this.sessionClaimTimes.put(chunk, System.currentTimeMillis());
|
||||
TerritoryModel current = this.model;
|
||||
if (current != null) {
|
||||
current.addSessionClaim(chunk);
|
||||
|
||||
在新工单中引用
屏蔽一个用户