Skip to content

Commit

Permalink
Add client commands
Browse files Browse the repository at this point in the history
  • Loading branch information
shedaniel committed Aug 12, 2022
1 parent 77b109e commit 6ff381d
Show file tree
Hide file tree
Showing 8 changed files with 228 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package dev.architectury.event.events.client;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import dev.architectury.event.Event;
import dev.architectury.event.EventFactory;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.commands.SharedSuggestionProvider;
import net.minecraft.network.chat.Component;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;

public interface ClientCommandRegistrationEvent {
/**
* @see ClientCommandRegistrationEvent#register(CommandDispatcher)
*/
Event<ClientCommandRegistrationEvent> EVENT = EventFactory.createLoop();

/**
* This event is invoked after the client initializes.
* Equivalent to Forge's {@code RegisterClientCommandsEvent} and Fabric's {@code ClientCommandManager}.
*
* @param dispatcher The command dispatcher to register commands to.
*/
void register(CommandDispatcher<ClientCommandSourceStack> dispatcher);

static LiteralArgumentBuilder<ClientCommandSourceStack> literal(String name) {
return LiteralArgumentBuilder.literal(name);
}

static <T> RequiredArgumentBuilder<ClientCommandSourceStack, T> argument(String name, ArgumentType<T> type) {
return RequiredArgumentBuilder.argument(name, type);
}

interface ClientCommandSourceStack extends SharedSuggestionProvider {
void arch$sendSuccess(Component message, boolean broadcastToAdmins);

void arch$sendFailure(Component message);

LocalPlayer arch$getPlayer();

Vec3 arch$getPosition();

Vec2 arch$getRotation();

ClientLevel arch$getLevel();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,12 @@

package dev.architectury.event.fabric;

import dev.architectury.event.events.client.ClientGuiEvent;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.event.events.client.ClientTickEvent;
import dev.architectury.event.events.client.ClientTooltipEvent;
import com.mojang.brigadier.CommandDispatcher;
import dev.architectury.event.events.client.*;
import dev.architectury.event.events.common.*;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.fabricmc.fabric.api.client.command.v1.ClientCommandManager;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientLifecycleEvents;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback;
Expand Down Expand Up @@ -53,6 +52,11 @@ public static void registerClient() {

ItemTooltipCallback.EVENT.register((itemStack, tooltipFlag, list) -> ClientTooltipEvent.ITEM.invoker().append(itemStack, list, tooltipFlag));
HudRenderCallback.EVENT.register((matrices, tickDelta) -> ClientGuiEvent.RENDER_HUD.invoker().renderHud(matrices, tickDelta));

ClientLifecycleEvent.CLIENT_STARTED.register(instance -> {
ClientCommandRegistrationEvent.EVENT.invoker().register((CommandDispatcher<ClientCommandRegistrationEvent.ClientCommandSourceStack>)
(CommandDispatcher<?>) ClientCommandManager.DISPATCHER);
});
}

public static void registerCommon() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package dev.architectury.mixin.fabric.client;

import dev.architectury.event.events.client.ClientCommandRegistrationEvent;
import net.fabricmc.fabric.api.client.command.v1.FabricClientCommandSource;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.network.chat.Component;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;

@Mixin(FabricClientCommandSource.class)
public interface MixinFabricClientCommandSource extends ClientCommandRegistrationEvent.ClientCommandSourceStack {
@Override
default void arch$sendSuccess(Component message, boolean broadcastToAdmins) {
((FabricClientCommandSource) this).sendFeedback(message);
}

@Override
default void arch$sendFailure(Component message) {
((FabricClientCommandSource) this).sendError(message);
}

@Override
default LocalPlayer arch$getPlayer() {
return ((FabricClientCommandSource) this).getPlayer();
}

@Override
default Vec3 arch$getPosition() {
return ((FabricClientCommandSource) this).getPosition();
}

@Override
default Vec2 arch$getRotation() {
return ((FabricClientCommandSource) this).getRotation();
}

@Override
default ClientLevel arch$getLevel() {
return ((FabricClientCommandSource) this).getWorld();
}
}
1 change: 1 addition & 0 deletions fabric/src/main/resources/architectury.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"client.MixinClientPacketListener",
"client.MixinDebugScreenOverlay",
"client.MixinEffectInstance",
"client.MixinFabricClientCommandSource",
"client.MixinGameRenderer",
"client.MixinIntegratedServer",
"client.MixinKeyboardHandler",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package dev.architectury.event.forge;

import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.brigadier.CommandDispatcher;
import dev.architectury.event.CompoundEventResult;
import dev.architectury.event.events.client.ClientChatEvent;
import dev.architectury.event.events.client.*;
Expand Down Expand Up @@ -327,6 +328,12 @@ public static void event(InputEvent.KeyInputEvent event) {
ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(Minecraft.getInstance(), event.getKey(), event.getScanCode(), event.getAction(), event.getModifiers());
}

@SubscribeEvent(priority = EventPriority.HIGH)
public static void event(RegisterClientCommandsEvent event) {
ClientCommandRegistrationEvent.EVENT.invoker().register((CommandDispatcher<ClientCommandRegistrationEvent.ClientCommandSourceStack>)
(CommandDispatcher<?>) event.getDispatcher());
}

@OnlyIn(Dist.CLIENT)
public static class ModBasedEventHandler {
@SubscribeEvent(priority = EventPriority.HIGH)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* This file is part of architectury.
* Copyright (C) 2020, 2021, 2022 architectury
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package dev.architectury.mixin.forge.client;

import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.architectury.event.events.client.ClientCommandRegistrationEvent;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.LocalPlayer;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.network.chat.Component;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;

@Mixin(CommandSourceStack.class)
public abstract class MixinCommandSourceStack implements ClientCommandRegistrationEvent.ClientCommandSourceStack {
@Override
public void arch$sendSuccess(Component message, boolean broadcastToAdmins) {
((CommandSourceStack) (Object) this).sendSuccess(message, broadcastToAdmins);
}

@Override
public void arch$sendFailure(Component message) {
((CommandSourceStack) (Object) this).sendFailure(message);
}

@Override
public LocalPlayer arch$getPlayer() {
try {
return (LocalPlayer) ((CommandSourceStack) (Object) this).getEntityOrException();
} catch (CommandSyntaxException e) {
throw new RuntimeException(e);
}
}

@Override
public Vec3 arch$getPosition() {
return ((CommandSourceStack) (Object) this).getPosition();
}

@Override
public Vec2 arch$getRotation() {
return ((CommandSourceStack) (Object) this).getRotation();
}

@Override
public ClientLevel arch$getLevel() {
return (ClientLevel) ((CommandSourceStack) (Object) this).getUnsidedLevel();
}
}
1 change: 1 addition & 0 deletions forge/src/main/resources/architectury.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"compatibilityLevel": "JAVA_16",
"minVersion": "0.8",
"client": [
"client.MixinCommandSourceStack",
"MixinClientLevel",
"MixinMinecraft"
],
Expand Down
14 changes: 11 additions & 3 deletions testmod-common/src/main/java/dev/architectury/test/TestMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@

package dev.architectury.test;

import com.mojang.brigadier.arguments.StringArgumentType;
import dev.architectury.event.events.client.ClientCommandRegistrationEvent;
import dev.architectury.event.events.client.ClientLifecycleEvent;
import dev.architectury.registry.client.level.entity.EntityRendererRegistry;
import dev.architectury.test.debug.ConsoleMessageSink;
import dev.architectury.test.debug.MessageSink;
import dev.architectury.test.debug.client.ClientOverlayMessageSink;
import dev.architectury.test.entity.TestEntity;
import dev.architectury.test.events.DebugEvents;
import dev.architectury.test.gamerule.TestGameRules;
import dev.architectury.test.item.TestBlockInteractions;
Expand All @@ -41,8 +42,6 @@
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.renderer.entity.CowRenderer;
import net.minecraft.client.renderer.entity.PigRenderer;
import net.minecraft.world.entity.animal.Cow;

public class TestMod {
public static final MessageSink SINK = EnvExecutor.getEnvSpecific(() -> ClientOverlayMessageSink::new, () -> ConsoleMessageSink::new);
Expand Down Expand Up @@ -72,6 +71,15 @@ public static void initializeClient() {
TestModNet.initializeClient();
EntityRendererRegistry.register(TestRegistries.TEST_ENTITY, CowRenderer::new);
EntityRendererRegistry.register(TestRegistries.TEST_ENTITY_2, CowRenderer::new);
ClientCommandRegistrationEvent.EVENT.register(dispatcher -> {
dispatcher.register(ClientCommandRegistrationEvent.literal("cool_client")
.then(ClientCommandRegistrationEvent.argument("string", StringArgumentType.string())
.executes(context -> {
String string = StringArgumentType.getString(context, "string");
SINK.accept("Cool client command for " + string);
return 0;
})));
});
}
}
}

0 comments on commit 6ff381d

Please sign in to comment.