无尽の咸羊
如题,需求是可以批量合成(如正常工作台),支持nbt和mod物品,可以无限制增加配方

奥利奥i
https://www.mcbbs.net/thread-840243-1-1.html
看看这个?

ecyber
[管理][SCT]iCraft —— 自定义矩阵合成系统,支持NBT物品以及MOD[1.9-1.15]
https://www.mcbbs.net/thread-840243-1-1.html
(出处: Minecraft(我的世界)中文论坛)

无敌三脚猫
既然是mod服,那为什么要用插件呢,明明有很好用的modcrt
不但功能特别多,还有一个特别的好处是可以配合CraftTweakerSync让客户端那边可以用jei看到新增的配方
如果只是为了让客户端少装mod,从而决定舍mod用插件,那也还有个办法,不用加东西,就在你服务端现成的mod里随便找一个加了配方的mod,以压缩软件的形式打开,找到assets\mod名字\recipes下面那一堆json文件,剩下的就是依葫芦画瓢了(其实配方json的格式到1.19也没变过,不过forge支持在"item"旁边写序列化的nbt)

无尽の咸羊
无敌三脚猫 发表于 2022-8-21 11:30
既然是mod服,那为什么要用插件呢,明明有很好用的modcrt
不但功能特别多,还有一个特别的好处是可以配合Cr ...

我可以接受写进我的mod中
但是我不清楚如何不用JSON注册配方

无敌三脚猫
无尽の咸羊 发表于 2022-8-21 13:07
我可以接受写进我的mod中
但是我不清楚如何不用JSON注册配方

跟注册物品、注册方块差不多
一个例子,泥土合成苹果的无序配方
  1. @SubscribeEvent
  2.         public void loadrecipe(RegistryEvent.Register<IRecipe> event) {
  3.                 event.getRegistry().register(new ShapelessRecipes("",ForgeRegistries.ITEMS.getValue(new ResourceLocation("minecraft:apple")).getDefaultInstance().setStackDisplayName("asdf"),NonNullList.from(null,CraftingHelper.getIngredient(ForgeRegistries.ITEMS.getValue(new ResourceLocation("minecraft:dirt"))))).setRegistryName("modid:testrecipe"));
  4.         }
复制代码
其实用ShapelessOreRecipe会简单些
啊,其实还是用json更简单些
最简单的还是crt,你想要gui操作的话可以用https://www.mcmod.cn/class/518.html

无尽の咸羊
无敌三脚猫 发表于 2022-8-21 20:27
跟注册物品、注册方块差不多
一个例子,泥土合成苹果的无序配方其实用ShapelessOreRecipe会简单些
啊,其 ...

我没能搞懂Ingredient的意义
已经使用NonNullList的情况下,Ingredient是什么,有什么用,又为什么支持多物品
假如我要新建一个多物品的有形配方,我该怎么处理NonNullList和Ingredient
比如摆成十字架的苹果合成一个泥土?

无敌三脚猫
本帖最后由 无敌三脚猫 于 2022-8-21 23:00 编辑
无尽の咸羊 发表于 2022-8-21 20:53
我没能搞懂Ingredient的意义
已经使用NonNullList的情况下,Ingredient是什么,有什么用,又为什么支持多 ...

我也不知道Ingredient是什么,有什么用,至于它为什么支持多物品……因为它包含了一个ItemStack数组啊,在比较物品是否符合Ingredient的时候,比较的是它的Item和metadata
想创建一个包含多个物品的Ingredient的话,还是用Ingredient.fromItems和Ingredient.fromStacks吧,CraftingHelper.getIngredient不能传多个参数(但是可以传入一个String作为矿辞)
原版的ShapedRecipes和ShapelessRecipes都需要传入NonNullList<Ingredient>,forge和ShapelessOreRecipe就简单很多,可以随意传入Item、ItemStack、Ingredient、String序列,而ShapedOreRecipe的写法和json里的类似,好处是配方里有多个相同物品的话,只用写一次
十字啊,那就是有序配方咯
  1.         @SubscribeEvent
  2.         public void loadrecipe(RegistryEvent.Register<IRecipe> event) {
  3.                 event.getRegistry().register(new ShapedOreRecipe(new ResourceLocation(""),ForgeRegistries.ITEMS.getValue(new ResourceLocation("minecraft:dirt")).getDefaultInstance().setStackDisplayName("asdf"),
  4.                                 " a ",
  5.                                 "aaa",
  6.                                 " a ",
  7.                                 'a',Ingredient.fromItem(ForgeRegistries.ITEMS.getValue(new ResourceLocation("minecraft:apple"))))
  8.                                 .setRegistryName("modid:testrecipe"));
  9.         }
复制代码
这个十字配方我要是用ShapedRecipes写的话,要传5个Ingredient进去,其实要传9个,其中5个包含苹果的Ingredient,以及4个Ingredient.EMPTY
等等,我为什么要用Ingredient.fromItem,我可以直接传个Item进去的
以及我为什么要用ForgeRegistries.ITEMS.getValue,明明Item.getByNameOrId都封装好了
  1.         @SubscribeEvent
  2.         public void loadrecipe(RegistryEvent.Register<IRecipe> event) {
  3.                 event.getRegistry().register(new ShapedOreRecipe(new ResourceLocation(""),
  4.                                 Item.getByNameOrId("minecraft:dirt").getDefaultInstance().setStackDisplayName("asdf"),
  5.                                 " a ",
  6.                                 "aaa",
  7.                                 " a ",
  8.                                 'a',Item.getByNameOrId("minecraft:apple"))
  9.                                 .setRegistryName("modid:testrecipe"));
  10.         }
复制代码
这样就简洁点儿了

无尽の咸羊
本帖最后由 无尽の咸羊 于 2022-8-21 23:13 编辑
无敌三脚猫 发表于 2022-8-21 22:46
我也不知道Ingredient是什么,有什么用,至于它为什么支持多物品……因为它包含了一个ItemStack数组啊,在 ...

我去看了一下,我想Ingredient大概是同一材料的多物品判断?
但是其似乎并不支持NBT的判断。
像是CTR是如何实现的呢?

————————————————
ps:不使用CTR是因为以前在使用ctr的时候发现,直接游戏内用gui编辑的nbt配方并不起效
需要在游戏外另外编辑。


无敌三脚猫
本帖最后由 无敌三脚猫 于 2022-8-22 10:30 编辑
无尽の咸羊 发表于 2022-8-21 23:05
我去看了一下,我想Ingredient大概是同一材料的多物品判断?
但是其似乎并不支持NBT的判断。
像是CTR是如 ...

我不知道,不过我个人的想法是继承并实现一个新的Ingredient,覆写apply方法让它比较物品的nbt
其实不用了,因为我发现forge已经实现了,也就是IngredientNBT,不过缺点是不能包含多种ItemStack
不对,还是要自己写,因为IngredientNBT的构造函数不是公有的(为什么!)
比如像这么写
  1. public class NbtIngredient extends Ingredient {
  2.         
  3.         public NbtIngredient(ItemStack... stacks) {
  4.                 super(stacks);
  5.         }
  6.         
  7.         @Override
  8.         public boolean apply(@Nullable ItemStack input) {
  9.                 if (input == null) {
  10.                         return false;
  11.                 } else {
  12.                         for (ItemStack itemstack : this.getMatchingStacks()) {
  13.                                 if (itemstack.getItem() == input.getItem() && itemstack.getItemDamage() == input.getItemDamage() && ItemStack.areItemStackShareTagsEqual(itemstack, input)) {
  14.                                         return true;
  15.                                 }
  16.                         }
  17.                         return false;
  18.                 }
  19.         }
  20. }
复制代码
就能限制合成材料的nbt了
  1. new NbtIngredient(Item.getByNameOrId("minecraft:apple").getDefaultInstance().setStackDisplayName("qwer"))
复制代码
不过按现在这种写法,只有名字叫qwer的苹果能参与合成,那些名字叫qwer但是带其它多余nbt(比如RepairCost)的苹果不能参与合成,这个就看你具体需求了,如果想实现“合成材料必须包含某个nbt”而不是“合成材料必须是某个nbt”,那你就要换种写法(我记得crt就同时支持这两种nbt限制)
再比如说你要是只想以lore来判断合成材料,那你就可以在你的apply方法里只比较lore,不比较其它的nbt
我没用过crt的可视化编辑器,不过我觉得“直接游戏内用gui编辑的nbt配方并不起效”多半是误会,有两点需要注意,1是写完的合成配方不会马上生效,要重启游戏才能生效,2是客户端用jei看不到服务端设置的配方,只能看到客户端的配方,所以需要那个CraftTweakerSync把脚本复制到客户端,而且同样是重启之后生效

无尽の咸羊
无敌三脚猫 发表于 2022-8-22 10:28
我不知道,不过我个人的想法是继承并实现一个新的Ingredient,覆写apply方法让它比较物品的nbt
其实不 ...

今天一直在外面,有想到继承的方法,但是由于理解错误卡住了。
原来我一直错误理解了多态,一直以为用父类引用时会调用父类方法。
感谢解答。

无尽の咸羊
无敌三脚猫 发表于 2022-8-21 10:01
我不知道,不过我个人的想法是继承并实现一个新的Ingredient,覆写apply方法让它比较物品的nbt
其实不 ...

出了点问题,我发现订阅的注册事件并没有执行
包括使用你前文发的两段"loadrecipe"也没有执行
尝试发送日志没有消息。

无敌三脚猫
无尽の咸羊 发表于 2022-8-23 09:42
出了点问题,我发现订阅的注册事件并没有执行
包括使用你前文发的两段"loadrecipe"也没有执行
尝试发送日 ...

只是个例子并不是要你一定这么写啊
你其它事件是怎么注册的,这个事件就怎么注册啊
我的写法是把所有带@SubscribeEvent注解的函数写在一个类里,再在mod主类的public void preInit(FMLPreInitializationEvent event)里注册这个类
你也可以写在一个有@Mod.EventBusSubscriber注解的类里,然后把所有带@SubscribeEvent注解的函数加上static,这样就是自动注册
好像就只有这两种注册方式吧https://harbinger.covertdragon.team/chapter-03/