本篇教程由作者设定未经允许禁止转载。

由于目前 [QωQ Library] 并没有传到像 Curseforge 或者 Modrinth 这样的网站上,所以要使用本库较好的方法是从本地引用。

在你的 build.gradle 中找到 dependencies ,并添加以下代码:

modImplementation fileTree(dir: 'src/main/libs', includes: ['*.jar'])

并且把你下载到的 jar 文件(使用开发版和发布版均可)放在 src/main/libs 文件夹下。

重新构建后,你应该已经发现 QωQ 成功导入了。


QωQ 提供了一套较为简单注册像物品这样对象的方法,如下所示:

public class ItemInit {
    public static final Registration<Item> ITEMS = new Registration<>(Registry.ITEM, MOD_ID);
    public static final Item EXAMPLE_ITEM = ITEMS.register("example_item", () -> new Item(new Item.Settings()));
}

方块之类的对象与这类似。

当然别忘了将下面这条语句加到你的主类中去:

@Override
public void onInitialize() {
    ItemInit.ITEMS.register();
}


当然,QωQ 还添加了一套类似于 Forge 的事件订阅系统,如果你想要订阅一个事件,你像下面这么做:

@ModEvent
public class OnEventHandle {
    @SubscribeEvent
    public static void onEvent(IEvent event) {
        //todo
    }
    
    // 如果入参不等于1个,QωQ 会抛出警告并不会订阅这个方法
    @SubscribeEvent
    public static void onEvent(IEvent event1, IEvent event2) {
        //todo
    }
    
    // 未添加 @SubscribeEvent 的注解的方法不会被 QωQ 加载
    public static void onEvent() {
        //todo
    }
}

请不要忘记了在事件中检查客户端,当然你也不应该使用@Environment()注解,这都有可能使程序出问题!


由于 QωQ 一些机制的问题,它并不能完全地自动订阅事件,你必须告诉程序,你到底把你的事件放在了哪个文件夹里,像这样:

@Override
public void onInitialize() {
    ItemInit.ITEMS.register();
    EventLoader.initEvent("org.abstruck.qwq.init.event");
}

当然,如果你把你的事件放在了 std.init.event 文件夹下,你可以不必告诉程序你存放事件的位置,因为该文件夹中的类 QωQ 会自动读取。

注意,不要把带有 @Mixin 注释的类和放在被订阅的文件夹下,它会报错的!!!


如果你想使用某个事件,但你发现 QωQ 并没有实现它时,你可以选择自己添加,下面这个例子实现了 Block 中的 afterBreak 事件:

// 记得继承 IEvent 的接口!
public class AfterBreakEvent implements IEvent{
        private World world;
        private PlayerEntity player;
        private BlockPos pos;
        private BlockState state;
        private BlockEntity blockEntity;
        private ItemStack stack;
        
        public AfterBreakEvent(World world, PlayerEntity player, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity, ItemStack stack) {
            this.world = world;
            this.player = player;
            this.pos = pos;
            this.state = state;
            this.blockEntity = blockEntity;
            this.stack = stack;
        }

        public PlayerEntity getPlayer() {
            return player;
        }

        public BlockPos getPos() {
            return pos;
        }
        
        public BlockState getState(){
            reutrn state;
        }

        public World getWorld() {
            return world;
        }

        public BlockEntity getBlockEntity() {
            return blockEntity;
        }

        public ItemStack getStack() {
            return stack;
        }
    }


当然,仅添加这一代码并不能实现添加新的事件,我们不得不使用 Mixin 来完成这一操作,如下所示:

@Mixin(Block.class)
public abstract class BlockMixin {
    @Inject(method = "afterBreak", at = @At("RETURN"))
    public void afterBreak(World world, PlayerEntity player, BlockPos pos, BlockState state, BlockEntity blockEntity, ItemStack stack, CallbackInfo ci) {
        Block self = (Block) (Object) this;
        EventManager.onEventAction(() -> new AfterBreakEvent(world, player, pos, state, blockEntity, stack));
    }
}

我们喜欢 Mixin ,但它越少越好对吧?

像这样,就可以简单地新建一个事件了。

当然还有个更简单的方法,就是往发 Issue ,我会尽可能的添加 Issue 中的所有事件请求。


Q&A

Q:为什么 QωQ 一定要告诉程序事件所在的文件夹?

A:QωQ 订阅事件的原理是扫描某个文件夹下的所有类文件,但如果扫描到了像带有 @Mixin 这种特殊类,便会报很奇怪的错误,目前并没有想到什么解决方法。


Q:QωQ 自带的事件太少了,我可以 Pull Requests 吗?

A:当然,非常欢迎。


Q:QωQ 可以加入 XXX 么?

A:可在评论区或者 Issue 里告诉我