将所有 "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' 钩子。)
注意:这不是 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' 钩子。)