使用一个 class 从任何元区块命名子区块?

Naming subblocks from any metablock using one single class?

我正在尝试只需要一个 class 来命名使用此 class 注册的任何元区块的子区块,即,将它们命名为参数值, 但不使用一个。

尽管这是围绕 API(Minecraft Forge)展开的,但我认为这是一个 Java 问题,所以我在这里快速解释一下我打算如何工作。

元区块由子块组成,子块是同一块的变体(例如,同一块,但仅纹理和名称发生变化)。每个子块都需要一个名称来标识它。这些名称列在class ExampleItemBlock中一个String[],然后以MetablockName.SubBlockName的格式命名(例如:ExampleMetablock.blueExampleMetablock.green等), 使用

// ExampleItemBlock Class

public static final String[] SUBNAMES = new String[] {"blue", "green", "yellow"};

@Override
public String getUnlocalizedName(ItemStack itemStack) 
{
    int i = itemStack.getItemDamage();
    return getUnlocalizedName() + "." + SUBNAMES[i];
}

然后,使用

实例化并注册元区块 ExampleMetablock
// Class where the registrations are made  

public static Block ExampleMetablock = new ExampleMetablock(); 

GameRegistry.registerBlock(ExampleMetablock, ExampleItemBlock.class, "ExampleMetablock");

在此之后,一切正常,但是我必须为我制作的每个新元块创建一个新的 *ItemBlock class,我认为这不是一件好事或不合适的事情,而且我认为最好创建一个单独的 class 供未来任何元区块使用。

值得注意的是,GameRegistry.registerBlock() 方法(即来自 API 的方法)的第二个参数需要类型为 Class 的值。这就是问题所在:如何在不使用实例的情况下将 ExampleItemBlock class 动态化?

我什至尝试在 ExampleItemBlock 构造函数中添加一个 String[] 参数,然后使用名称代替 class 的实例,但正如预期的那样,它表明类型不匹配。

我到处寻找实现它的方法,但我只找到了两种方法:

1. 为每个新元区块创建一个 ItemBlock class;
2.getUnlocalizedName()中的SUBNAMES[i]改成iitemStack.getItemDamage(),这样子块的名称就会变成数字而不是名称(例如:ExampleMetablock.0ExampleMetablock.1 等),不需要使用 String[] 或任何东西,并使其成为通用的 class。但是,这种方式也很不切实际,因为这在识别哪个子块是哪个时变得非常复杂。

我也在 GitHub 上搜索了一些模组,但在代码中没有发现任何与此相关的内容(据我所知)。

所以我的问题是:有没有办法制作一个通用的 *ItemBlock class,但仍然用名称(单词)命名子块?

类内容:ExampleMetablock, ExampleItemBlock.

我的建议是制作一个基础 class 来完成您的所有功能。

public class BaseItemMetaBlock {
    .....
}

这个有你所有的元块渲染功能,但没有分配给任何块。

然后,有一个块

public class MySuperAwesomeBlockItem extends BaseItemMetaBlock {
    public MySuperAwesomeBlockItem(Block block) {
       super(block);
    }
}

因为 ItemBlock 与方块本身相关联,所以您可以通过一些编程魔术来获取定义方块状态的枚举 return 您想要的名称。

我所做的是为我的块提供一个特殊的接口,这样我就可以在将它们转换为通用接口后调用我自己的方法

 @Override
 public String getUnlocalizedName(ItemStack stack) {
    return super.getUnlocalizedName(stack) + "." + ((IMetaBlockName)this.block).getSpecialName(stack);
  }

反正就是这样。

我最终发现解决方案就在 Forge 本身,正如可以看到的那样 here

但为了提供信息,我将解释解决方案。


我不知道,方法 GameRegistry.registerBlock() 还接受第四个参数,类型为 Object[]。所以只需要将名称列表放在 Object[] 中,只需从 ExampleMetablock 创建 String[] 字段,并将定义的 Object[] 参数的值传递给 String[]场地。像这样:

public static String[] SUBNAMES;
private IIcon[] icon;

public ExampleMetaBlock(Material material, String name, CreativeTabs tab, String[] subnames)
{
    super(material, name, tab);
    SUBNAMES = subnames;
}

建议您在 Class 参数中使用单独创建的 class class ExampleItemBlock,而不是使用已经存在的 [=75] =] 在 Minecraft 代码中做与 ExampleItemBlock 几乎相同的事情,即 ItemMultiTexture class(这是为了防止 ItemMultiTexture class).看注册是这样的:

public static final String[] SubNames = new String[] {"blue", "green", "yellow", "red"}; 
public static Block ExampleMetablock = new ExampleMetablock(Material.rock, "ExampleMetablock", Tabs.ExampleModTab, SubNames); 

GameRegistry.registerBlock(ExampleMetablock, ItemMultiTexture.class, "ExampleMetablock", new Object[]{SubNames});

但是,这不会编译。错误 NoSuchMethodException 将出现在注册行 (GameRegistry.registerBlock ....)。

ItemMultiTexture class 构造函数在 registerBlock() 方法参数中获取与其构造函数参数类型匹配的设置值,即 Block, Block, String[]

是否提供了 String[]?是的。是否提供了 Block?是的。是否提供了第二个 Block?号 "There is no such method",ItemMultiTexture 中没有参数为 Block, String[] 的构造函数。

发生这种情况是因为,如前所述,来自 ItemMultiTexture 的构造函数需要两个 Block 值。

要解决这个问题,只需创建一个新的 class(或编辑 ExemploItemBlock)扩展 ItemMultiTexture,其中 super 是两个 Block 参数。像这样:

public class ItemMultiTextureHelper extends ItemMultiTexture
{
    public ItemMultiTextureHelper(Block block, String[] names)
    {
        super(block, block, names);
    }
}

registerBlock() 像这样:

GameRegistry.registerBlock(ExampleMetablock, ItemMultiTextureHelper.class, "ExampleMetablock", new Object[]{SubNames});

还有最后一件事,但同样重要:SUBNAMES 中删除 修饰符 static,否则这将导致您的新设备一团糟元区块,就像所有元区块的子区块都被命名为与创建的第一个元区块、重复的子区块等相同的名称。
(我刚才遇到了这些问题,并修复了删除static。)所以正确的是:

public String[] SUBNAMES;