跳转至

Accessors

IConfiguratorAccessor<T> 是 Java 类型和 configurator UI 之间的桥梁。当 ConfiguratorParser 找到普通的 @Configurable 字段时,会执行类似下面的流程:

IConfiguratorAccessor accessor = ConfiguratorAccessors.findByType(field.getGenericType());
Configurator configurator = accessor.create(name, getter, setter, forceUpdate, field, owner);

Accessor 决定自己是否支持该字段类型,提供默认值,并创建具体的 Configurator

内置类型支持

LDLib2 在 ldlib2:configurator_accessor 中注册了许多客户端 accessor。

类型族 Java 类型 说明
Boolean boolean, Boolean 使用 toggle。
Numbers int, long, float, double, short, byte 以及 boxed 类型 支持 @ConfigNumber@DefaultValue@ConfigColor
String String, String[] String[] 会作为多行字符串编辑。
Enum 任意 enum 类型 支持 @ConfigSelector;实现 StringRepresentable 时使用 serialized name。
Text Component Component 文本 configurator。
Minecraft registry values Block, Item, Fluid, EntityType<?> 通常使用 registry search/selector UI。
Resource IDs ResourceLocation 支持 @ConfigRL 的 font 和 tag-key 模式。
Item/fluid stacks ItemStack, FluidStack 面向物品/流体的 configurator。
NBT Tag 编辑原始 NBT/tag 数据。
Position/shape BlockPos, AABB, Range 使用数值 group。
LDLib UI data Position, Size, Pivot, LengthPercent, Translate2D 常见 UI layout/style 数据类型。
JOML math Vector2f, Vector2i, Vector3f, Vector3i, Vector4f, Vector4i, Quaternionf 使用组合数值 configurator。
Scene refs TransformRef Scene editor 相关的 transform reference。
Render/UI resources IGuiTexture, IRenderer 选择注册过的实现,并编辑该实现自己的 configurable 数据。
Arrays T[] 基于子类型 accessor 的动态 wrapper。
Collections Collection<T>,通常是 List<T>Set<T> 基于子类型 accessor 的动态 wrapper;支持 @ConfigList

数组和集合是动态处理的。LDLib2 会先找到子类型 accessor,然后用 ArrayConfiguratorAccessorCollectionConfiguratorAccessor 包起来。

如果类型不在表中,仍可以通过这些方式支持:

  • 字段使用 @Configurable(subConfigurable = true)
  • 注册自定义 IConfiguratorAccessor
  • buildConfigurator(...) 中手动构建 UI;
  • list 使用 @ConfigList(configuratorMethod = "...") 提供 item UI。

自定义 Accessor

当某个领域类型总是应该使用同一种编辑控件时,创建 accessor。

@LDLRegisterClient(name = "shop_currency", registry = "ldlib2:configurator_accessor")
public class CurrencyAccessor implements IConfiguratorAccessor<Currency> {
    @Override
    public boolean test(Class<?> type) {
        return type == Currency.class;
    }

    @Override
    public Currency defaultValue(@Nullable Field field, @Nullable Class<?> type) {
        return Currency.EMPTY;
    }

    @Override
    public Configurator create(
            String name,
            Supplier<Currency> supplier,
            Consumer<Currency> consumer,
            boolean forceUpdate,
            @Nullable Field field,
            @Nullable Object owner
    ) {
        return new SelectorConfigurator<>(
                name,
                supplier,
                consumer,
                Currency.EMPTY,
                forceUpdate,
                CurrencyRegistry.getAll(),
                Currency::id
        );
    }
}

@LDLRegisterClient 会让这个 accessor 在客户端可被 ConfiguratorAccessors.findByType(...) 找到。

如何选择扩展点

如果映射是类型级别的,比如所有 Currency 都应该用同一个 selector,就使用自定义 accessor。

如果 UI 依赖某个 owner 对象或某个具体字段,优先使用 @ConfigList(configuratorMethod = "...")@ConfigSearch 或手动 buildConfigurator(...)

如果默认 UI 足够,但写入值时需要校验或副作用,使用 @ConfigSetter