将所有 "ImmutableMap/List" 构建工作卸载到编译时?

Offload all "ImmutableMap/List" build work to compile-time?

注意:这不是 Minecraft Fabric 特有的。我刚接触严格的运行前优化。

我正在为 Minecraft mod 编写一个 API 挂钩,允许将各种任务映射到村民的“职业”属性,允许其他 mod 添加自定义自定义职业的任务。我已经完成了所有后端代码,所以现在我担心优化。

我有一个 ImmutableMap.Builder<VillagerProfession, VillagerTask> 用于存储其他 mod 添加的任务。问题是,虽然 I 知道“put”方法永远不会在运行时调用,但我不知道 compiler 是否会调用。显然,由于这是一个游戏,modpacks 中的启动时间已经很长,我想尽可能优化它,因为它会被 every 使用mod 希望添加新的村民任务。

这是我当前的“任务注册表”源代码:

private static final ImmutableMap.Builder<VillagerProfession, ImmutableList<Pair<Task<? super VillagerEntity>, Integer>>> professionToVillagerTaskBuilder = ImmutableMap.builder();
    
    private static final ImmutableMap<VillagerProfession, ImmutableList<Pair<Task<? super VillagerEntity>, Integer>>> professionToVillagerTaskMap;
    
    // The hook that any mods will use in their source code
    public static void addVillagerTasks(VillagerProfession executingProfession, ImmutableList<Pair<Task<? super VillagerEntity>, Integer>> task)
    {
        professionToVillagerTaskBuilder.put(executingProfession, task);
    }
    
    //The tasklist retrieval method used at runtime
    static ImmutableList<Pair<Task<? super VillagerEntity>, Integer>> getVillagerRandomTasks(VillagerProfession profession)
    {
        return professionToVillagerTaskMap.get(profession);
    }
    
    static { // probably not the correct way to do this, but it lets me mark the map as final
        professionToVillagerTaskMap = professionToVillagerTaskBuilder.build();
    }

谢谢!

简短的回答是:你不能做你想做的事。

Problem is, while I know that the "put" method will never be called at runtime, I don't know if the compiler does.

必须在运行时调用 put 方法才能使您的 mod 有用。当您的代码以可以执行的形式加载时——这就是运行时。它可能是您 mod 的设置阶段,但它是 JVM 中的 运行。

如果源代码不包含注册表本身,则编译器无法将其翻译成可执行代码;它无法优化它不知道存在的东西。您(开发人员)不知道 mod 将加载什么,因此编译器无法知道,因此它无法优化或预先计算它。这就是您为动态加载代码付出的代价。


至于你贴的代码:不行。

static块在加载class时执行。将其视为 class 而不是对象的构造函数。当 mod 可以调用它的任何方法时,必须加载 class,并且它的静态块已经被执行。在从外部调用任何方法之前,您的地图将被设置为空。添加的所有任务将永远留在构建器中,未使用、看不见、不受欢迎。

保留生成器。让 mods 添加他们的条目。然后,当所有 mod 加载完成并且游戏开始时,调用 build() 并将结果用作注册表。 (使用您的 modding 框架提供的 'game is starting' 钩子。)