Skip to content
Merged

Sync #27

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ loader_version_range=[4,)
mod_id=the_trackers
mod_name=The Trackers
mod_license=LGPLv3
mod_version=1.21.1-0.2.5
mod_version=1.21.1-0.2.6
mod_group_id=nowebsite.makertechno.the_trackers
mod_authors=MakerTechno
mod_description=To follow the light to where all shadows begin.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// 1.21.1 2025-12-30T03:29:47.8263854 Languages: en_us for mod: the_trackers
03304c51a90c9d9e2adcfc7f6ef3e7fe53f69a2a assets/the_trackers/lang/en_us.json
// 1.21.1 2026-06-12T19:48:54.9381165 Languages: en_us for mod: the_trackers
476f1b815154e366147c84048f930b12afa4cef6 assets/the_trackers/lang/en_us.json
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// 1.21.1 2025-12-30T03:29:47.8323821 Languages: zh_cn for mod: the_trackers
1abacc820d2baf494f695dc25ede351aeb2a290c assets/the_trackers/lang/zh_cn.json
// 1.21.1 2026-06-12T19:48:54.9401096 Languages: zh_cn for mod: the_trackers
983695bff3328e6f641c51536ee109256f22010b assets/the_trackers/lang/zh_cn.json
7 changes: 6 additions & 1 deletion src/generated/resources/assets/the_trackers/lang/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"the_trackers.configuration.center_relative_tracking": "Tracking settings for center-relative cursors",
"the_trackers.configuration.center_relative_tracking.button": "Settings for tracking entities",
"the_trackers.configuration.center_relative_tracking.tooltip": "List of entity types with cursor types, separated with \"|\"",
"the_trackers.configuration.center_relative_tracking_secondary": "Secondary tracking settings for center-relative cursors",
"the_trackers.configuration.center_relative_tracking_secondary.button": "Settings for tracking entities",
"the_trackers.configuration.center_relative_tracking_secondary.tooltip": "List of entity types with cursor types, separated with \"|\"",
"the_trackers.configuration.gui_scale": "The scale of tracking cursors",
"the_trackers.configuration.gui_scale.tooltip": "Usually 0.6 on 1080p monitors",
"the_trackers.configuration.head_flat_available": "Longitude hud available",
Expand All @@ -23,5 +26,7 @@
"the_trackers.configuration.track_full_available.tooltip": "Enable or disable full screen tag cursors",
"the_trackers.configuration.track_full_tracking": "Tracking settings for full-track cursors",
"the_trackers.configuration.track_full_tracking.button": "Settings for tracking entities",
"the_trackers.configuration.track_full_tracking.tooltip": "List of entity types with cursor types, separated with \"|\""
"the_trackers.configuration.track_full_tracking.tooltip": "List of entity types with cursor types, separated with \"|\"",
"the_trackers.configuration.track_secondary_enemies": "Secondary tracking available",
"the_trackers.configuration.track_secondary_enemies.tooltip": "Enable or disable tracking secondary targets"
}
7 changes: 6 additions & 1 deletion src/generated/resources/assets/the_trackers/lang/zh_cn.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
"the_trackers.configuration.center_relative_tracking": "中心环绕式跟踪清单",
"the_trackers.configuration.center_relative_tracking.button": "跟踪实体的设置",
"the_trackers.configuration.center_relative_tracking.tooltip": "带有光标类型的实体类型列表,用\"|\"分隔",
"the_trackers.configuration.center_relative_tracking_secondary": "中心环绕式次要跟踪清单",
"the_trackers.configuration.center_relative_tracking_secondary.button": "跟踪实体的设置",
"the_trackers.configuration.center_relative_tracking_secondary.tooltip": "带有光标类型的实体类型列表,用\"|\"分隔",
"the_trackers.configuration.gui_scale": "追踪指针大小",
"the_trackers.configuration.gui_scale.tooltip": "默认值0.6,这在一般1080p设备上表现很好",
"the_trackers.configuration.head_flat_available": "经度轴开关",
Expand All @@ -23,5 +26,7 @@
"the_trackers.configuration.track_full_available.tooltip": "启用或禁用锁定定位式指针",
"the_trackers.configuration.track_full_tracking": "绑定定位式跟踪清单",
"the_trackers.configuration.track_full_tracking.button": "跟踪实体的设置",
"the_trackers.configuration.track_full_tracking.tooltip": "带有光标类型的实体类型列表,用\"|\"分隔"
"the_trackers.configuration.track_full_tracking.tooltip": "带有光标类型的实体类型列表,用\"|\"分隔",
"the_trackers.configuration.track_secondary_enemies": "次要追踪开关",
"the_trackers.configuration.track_secondary_enemies.tooltip": "启用或禁用追踪次要目标"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@

import com.mojang.datafixers.util.Pair;
import net.minecraft.world.entity.EntityType;
import nowebsite.makertechno.the_trackers.client.gui.cursors.TDir3BodyCursor;
import nowebsite.makertechno.the_trackers.client.gui.cursors.TDirectProjCursor;
import nowebsite.makertechno.the_trackers.client.gui.cursors.TRelativeCursor;
import nowebsite.makertechno.the_trackers.client.gui.cursors.TRenderCursor;
import nowebsite.makertechno.the_trackers.client.gui.cursors.*;
import nowebsite.makertechno.the_trackers.client.gui.components.Icon;
import nowebsite.makertechno.the_trackers.client.gui.components.BasicComponentFactory;
import nowebsite.makertechno.the_trackers.client.gui.components.BaseComponent;
Expand All @@ -21,131 +18,215 @@

public final class ConfigProcessor {

private static final Pair<EntityType<?>, Supplier<? extends TRenderCursor>> OF_EMPTY =new Pair<>(null, TRenderCursor::ofNull);

// 格式: entityType|pointer|entityIcon(|optionalPatterns)
public static boolean isValidEntityBindCRCursor(Object o) {
/* entityType|pointer|entityIcon(|optionalPatterns) */
CRCursorParseData data = parseCRCursorData(o);
return validateCRCursorData(data);
}

/**
* 通过配置表处理CenterRelative指针数据
*/
@NotNull
public static Set<Pair<EntityType<?>, Supplier<? extends TRenderCursor>>> collectCREntityBindCursor(@NotNull List<? extends String> list) {
return list.stream()
.map(ConfigProcessor::parseCRCursorData) // 处理为中间数据件
.filter(ConfigProcessor::validateCRCursorData) // 验证配置完整性
.map(ConfigProcessor::buildCRCursorPair) // 构造指针
.collect(Collectors.toSet());
}

// 格式: entityType|type:icon(|optionalPattern)
public static boolean isValidCREntityBindDTCursor(Object o) {
DTCursorParseData data = parseDTCursorData(o);
return validateDTCursorData(data);
}

/**
* 通过配置表处理DirectProj指针数据
*/
@NotNull
public static Set<Pair<EntityType<?>, Supplier<? extends TRenderCursor>>> collectDTEntityBindCursor(@NotNull List<? extends String> list) {
return list.stream()
.map(ConfigProcessor::parseDTCursorData)
.filter(ConfigProcessor::validateDTCursorData)
.map(ConfigProcessor::buildDTCursorPair)
.collect(Collectors.toSet());
}
/**
* 处理CenterRelative配置
*/
private static CRCursorParseData parseCRCursorData(Object o) {
CRCursorParseData data = new CRCursorParseData();

// 步骤1: 类型检查
if (!(o instanceof String config)) return data.invalid();

// 步骤2: 分割验证
data.parts = config.split("\\|");
if (data.parts.length < 3 || data.parts.length > 4) return data.invalid();

// 步骤3: 解析实体类型
Optional<EntityType<?>> entityType = EntityType.byString(data.parts[0]);
if (entityType.isEmpty()) return data.invalid();
data.entityType = entityType.get();

// 步骤4: 读取图标键名
data.pointerKey = data.parts[1];
data.iconKey = data.parts[2];

// 步骤5: 处理可选模式
if (data.parts.length == 4) {
String[] patterns = data.parts[3].split("&");
if (patterns.length != 2) return data.invalid();
data.pattern1 = patterns[0];
data.pattern2 = patterns[1];
data.hasPatterns = true;
}

if (!(o instanceof String s)) return false;
String[] split = s.split("\\|");
if (split.length < 3 || split.length > 4) return false;
return data.valid();
}

Optional<EntityType<?>> typeOpt = EntityType.byString(split[0]);
if (typeOpt.isEmpty()) return false;
private static boolean validateCRCursorData(CRCursorParseData data) {
if (!data.valid) return false;

if (TModClient.isLoaded && !split[1].equals("none") && TextureCache.getIcon(split[1]).equals(Icon.NONE)) return false;
if (TModClient.isLoaded && !split[2].equals("none") && TextureCache.getIcon(split[2]).equals(Icon.NONE)) return false;
// 验证图标有效性(仅在客户端加载时)
if (TModClient.isLoaded) {
if (!data.pointerKey.equals("none") && TextureCache.getIcon(data.pointerKey).equals(Icon.NONE))
return false;
if (!data.iconKey.equals("none") && TextureCache.getIcon(data.iconKey).equals(Icon.NONE))
return false;
}

if (split.length == 4) {
String[] patterns = split[3].split("&");
if (patterns.length != 2) return false;
return BasicComponentFactory.hasElementPattern(patterns[0]) && BasicComponentFactory.hasElementPattern(patterns[1]);
// 验证模式有效性(如果有)
if (data.hasPatterns) {
if (!BasicComponentFactory.hasElementPattern(data.pattern1)) return false;
return BasicComponentFactory.hasElementPattern(data.pattern2);
}

return true;
}

@NotNull
public static Set<Pair<EntityType<?>, Supplier<? extends TRenderCursor>>> collectCREntityBindCursor(@NotNull List<? extends String> list) {
return list.stream()
.map(s -> {
String[] split = s.split("\\|");
if (split.length < 3 || split.length > 4) return OF_EMPTY;

Optional<EntityType<?>> typeOpt = EntityType.byString(split[0]);
if (typeOpt.isEmpty()) return OF_EMPTY;
EntityType<?> entityType = typeOpt.get();

Icon pointerIcon = TextureCache.getIcon(split[1]);
if (!split[1].equals("none") && pointerIcon.equals(Icon.NONE)) return OF_EMPTY;

Icon icon = TextureCache.getIcon(split[2]);
if (!split[2].equals("none") && icon.equals(Icon.NONE)) return OF_EMPTY;

Supplier<? extends TRenderCursor> supplier;

if (split.length == 4) {
String[] patterns = split[3].split("&");
if (patterns.length == 2 &&
BasicComponentFactory.hasElementPattern(patterns[0]) &&
BasicComponentFactory.hasElementPattern(patterns[1])) {
supplier = () -> new TRelativeCursor(
BasicComponentFactory.getElementComponent(pointerIcon, patterns[0]).get(),
BasicComponentFactory.getElementComponent(icon, patterns[1]).get()
);
return new Pair<EntityType<?>, Supplier<? extends TRenderCursor>>(entityType, supplier);
}
}

supplier = () -> new TRelativeCursor(
BasicComponentFactory.getDefault(pointerIcon).get(),
BasicComponentFactory.getDefault(icon).get()
);
return new Pair<EntityType<?>, Supplier<? extends TRenderCursor>>(entityType, supplier);
})
.filter(p -> p != OF_EMPTY)
.collect(Collectors.toSet());
private static Pair<EntityType<?>, Supplier<? extends TRenderCursor>> buildCRCursorPair(CRCursorParseData data) {
Icon pointerIcon = TextureCache.getIcon(data.pointerKey);
Icon icon = TextureCache.getIcon(data.iconKey);

Supplier<? extends TRenderCursor> supplier;

if (data.hasPatterns) {
supplier = () -> new TRelativeCursor(
BasicComponentFactory.getElementComponent(pointerIcon, data.pattern1).get(),
BasicComponentFactory.getElementComponent(icon, data.pattern2).get()
);
} else {
supplier = () -> new TRelativeCursor(
BasicComponentFactory.getDefault(pointerIcon).get(),
BasicComponentFactory.getDefault(icon).get()
);
}

return new Pair<>(data.entityType, supplier);
}

public static boolean isValidCREntityBindDTCursor(Object o) {
/* entityType|type:icon(|optionalPattern) */
/* optionalPattern = opt:type */
private static DTCursorParseData parseDTCursorData(Object o) {
DTCursorParseData data = new DTCursorParseData();

if (!(o instanceof String s)) return false;
String[] split = s.split("\\|");
if (split.length < 2 || split.length > 3) return false;
// 步骤1: 类型检查
if (!(o instanceof String config)) return data.invalid();

Optional<EntityType<?>> typeOpt = EntityType.byString(split[0]);
if (typeOpt.isEmpty()) return false;
// 步骤2: 分割验证
data.parts = config.split("\\|");
if (data.parts.length < 2 || data.parts.length > 3) return data.invalid();

String[] style = split[1].split(":");
if (style.length != 2) return false;
// 步骤3: 解析实体类型
Optional<EntityType<?>> typeOpt = EntityType.byString(data.parts[0]);
if (typeOpt.isEmpty()) return data.invalid();
data.entityType = typeOpt.get();

if (TModClient.isLoaded) {
if (!style[1].equals("none") && TextureCache.getIcon(style[1]).equals(Icon.NONE))
if (TextureCache.getIcon(style[1]).equals(Icon.NONE)) return false;
// 步骤4: 解析样式和图标
String[] styleParts = data.parts[1].split(":");
if (styleParts.length != 2) return data.invalid();
data.style = styleParts[0];
data.iconKey = styleParts[1];

// 步骤5: 处理可选模式
if (data.parts.length == 3) {
data.optionalPattern = data.parts[2];
data.hasOptionalPattern = true;
}

if (!(style[0].equals("normal") || style[0].equals("3body"))) return false;
return data.valid();
}

private static boolean validateDTCursorData(DTCursorParseData data) {
if (!data.valid) return false;

// 验证样式类型
if (!data.style.equals("normal") && !data.style.equals("3body")) return false;

if (split.length == 3) return BasicComponentFactory.hasElementPattern(split[2]);
// 验证图标有效性
if (TModClient.isLoaded && !data.iconKey.equals("none")) {
if (TextureCache.getIcon(data.iconKey).equals(Icon.NONE)) return false;
}

// 验证可选模式(如果有)
if (data.hasOptionalPattern) {
return BasicComponentFactory.hasElementPattern(data.optionalPattern);
}

return true;
}
@NotNull
public static Set<Pair<EntityType<?>, Supplier<? extends TRenderCursor>>> collectDTEntityBindCursor(@NotNull List<? extends String> list) {
return list.stream()
.map(s -> {
String[] split = s.split("\\|");
if (split.length < 2 || split.length > 3) return OF_EMPTY;

Optional<EntityType<?>> typeOpt = EntityType.byString(split[0]);
if (typeOpt.isEmpty()) return OF_EMPTY;
EntityType<?> entityType = typeOpt.get();

String[] style = split[1].split(":");
if (style.length != 2) return OF_EMPTY;

Icon icon = TextureCache.getIcon(style[1]);
if (!style[1].equals("none") && icon.equals(Icon.NONE)) {
icon = TextureCache.getIcon(style[1]);
if (icon.equals(Icon.NONE)) return OF_EMPTY;
}
Supplier<BaseComponent> cps;
if (split.length == 3) cps = BasicComponentFactory.getElementComponent(icon, split[2]);
else cps = BasicComponentFactory.getDefault(icon);

Supplier<? extends TRenderCursor> supplier;
if (style[0].equals("3body")){
supplier = () -> new TDir3BodyCursor(cps.get(), cps.get(), cps.get());
} else if (style[0].equals("normal")){
supplier = () -> new TDirectProjCursor(cps.get());
} else return OF_EMPTY;

return new Pair<EntityType<?>, Supplier<? extends TRenderCursor>>(entityType, supplier);
})
.filter(p -> p != OF_EMPTY)
.collect(Collectors.toSet());

private static Pair<EntityType<?>, Supplier<? extends TRenderCursor>> buildDTCursorPair(DTCursorParseData data) {
Icon icon = TextureCache.getIcon(data.iconKey);

Supplier<BaseComponent> componentSupplier;
if (data.hasOptionalPattern) {
componentSupplier = BasicComponentFactory.getElementComponent(icon, data.optionalPattern);
} else {
componentSupplier = BasicComponentFactory.getDefault(icon);
}

Supplier<? extends TRenderCursor> supplier;
if (data.style.equals("3body")) {
supplier = () -> new TDir3BodyCursor(
componentSupplier.get(),
componentSupplier.get(),
componentSupplier.get()
);
} else { // "normal"
supplier = () -> new TDirectProjCursor(componentSupplier.get());
}

return new Pair<>(data.entityType, supplier);
}

}
// ==================== 内部数据结构 ====================

private static class CRCursorParseData {
private boolean valid = false;
private String[] parts;
private EntityType<?> entityType;
private String pointerKey;
private String iconKey;
private boolean hasPatterns = false;
private String pattern1;
private String pattern2;

private CRCursorParseData valid() { this.valid = true; return this; }
private CRCursorParseData invalid() { this.valid = false; return this; }
}

private static class DTCursorParseData {
private boolean valid = false;
private String[] parts;
private EntityType<?> entityType;
private String style;
private String iconKey;
private boolean hasOptionalPattern = false;
private String optionalPattern;

private DTCursorParseData valid() { this.valid = true; return this; }
private DTCursorParseData invalid() { this.valid = false; return this; }
}
}
Loading
Loading