Skip to content

Commit

Permalink
Add custom command listening
Browse files Browse the repository at this point in the history
  • Loading branch information
IotaBread committed Jul 15, 2021
1 parent 63f46b7 commit 0022505
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 30 deletions.
24 changes: 22 additions & 2 deletions README.md
Expand Up @@ -52,7 +52,23 @@ The config file is located in the config directory (`config/player_events.json`)
"/say Hope to see you soon ${player}"
],
"broadcast_to_everyone": true
}
},
"custom_commands": [
{
"command": "/plugins",
"actions": [
"Hey! We don't use plugins"
],
"broadcast_to_everyone": false
},
{
"command": "/spawn",
"actions": [
"/tp ${player} 0 64 0 0 0"
],
"broadcast_to_everyone": true
}
]
}
```

Expand Down Expand Up @@ -80,7 +96,7 @@ Use `/pe reload` or `/player_events reload` to reload the mod config.
You can use `/pe test <event>` or `/player_events test <event>` to test the actions on a specific
event, or use `/pe test *` to test every event.

### 2.1.2 supported events
### 2.1.3 supported events
* `death` - Executed when a player dies.
* `first_join` - Executed when a player joins for first time.
* `join` - Executed when a player joins.
Expand All @@ -90,6 +106,9 @@ event, or use `/pe test *` to test every event.
* `${killedPlayer}` - the killed player.
* `leave` - Executed when a player leaves.

Additionally, you can create simple commands (if you want a more complex command, this mod isn't what you
are looking for) or listen to existing ones.

### Troubleshooting
If you get an error when initializing the server or when an action should be executed, here are
steps on how to solve it.
Expand Down Expand Up @@ -150,6 +169,7 @@ Also, add this snippet to your `fabric.mod.json` if you want your mod to depend
* `kill_entity` - `me.bymartrixx.playerevents.api.event.PlayerKillEntityCallback.EVENT`
* `kill_player` - `me.bymartrixx.playerevents.api.event.PlayerKillPlayerCallback.EVENT`
* `leave` - `me.bymartrixx.playerevents.api.event.PlayerLeaveCallback.EVENT`
* Command executed - `me.bymartrixx.playerevents.api.event.CommandExecutionCallback.EVENT`

#### Note
The package `io.github.bymartrixx.playerevents.api` has been moved to `me.bymartrixx.playerevents.api`,
Expand Down
@@ -0,0 +1,15 @@
package me.bymartrixx.playerevents.api.event;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.server.command.ServerCommandSource;

public interface CommandExecutionCallback {
Event<CommandExecutionCallback> EVENT = EventFactory.createArrayBacked(CommandExecutionCallback.class, listeners -> (command, source) -> {
for (CommandExecutionCallback listener : listeners) {
listener.onExecuted(command, source);
}
});

void onExecuted(String command, ServerCommandSource source);
}
@@ -0,0 +1,20 @@
package me.bymartrixx.playerevents.api.mixin;

import me.bymartrixx.playerevents.api.event.CommandExecutionCallback;
import net.minecraft.server.network.ServerPlayNetworkHandler;
import net.minecraft.server.network.ServerPlayerEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(ServerPlayNetworkHandler.class)
public class CommandExecutionMixin {
@Shadow public ServerPlayerEntity player;

@Inject(at = @At(value = "TAIL"), method = "executeCommand")
private void onCommandExecuted(String input, CallbackInfo ci) {
CommandExecutionCallback.EVENT.invoker().onExecuted(input, this.player.getCommandSource());
}
}
1 change: 1 addition & 0 deletions api/src/main/resources/player_events_api.mixins.json
Expand Up @@ -3,6 +3,7 @@
"package": "me.bymartrixx.playerevents.api.mixin",
"compatibilityLevel": "JAVA_8",
"mixins": [
"CommandExecutionMixin",
"PlayerDeathMixin",
"PlayerJoinMixin",
"PlayerLeaveMixin",
Expand Down
5 changes: 4 additions & 1 deletion build.gradle
Expand Up @@ -151,7 +151,8 @@ task modrinth (type: TaskModrinthUpload, dependsOn: build) {
addGameVersion('1.16.3')
addGameVersion('1.16.4')
addGameVersion('1.16.5')
addGameVersion('1.17-pre1') // TODO: Change to 1.17 when available
addGameVersion('1.17')
addGameVersion('1.17.1')
addLoader('fabric')
addFile(project(':api').remapJar)
}
Expand All @@ -170,6 +171,8 @@ curseforge {
addGameVersion '1.16.3'
addGameVersion '1.16.4'
addGameVersion '1.16.5'
addGameVersion '1.17'
addGameVersion '1.17.1'
addGameVersion 'Fabric'
mainArtifact(remapJar) {
displayName = "Player Events ${version}"
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Expand Up @@ -6,7 +6,7 @@ yarn_mappings = 1.16.5+build.9
loader_version = 0.11.3

#Mod properties
mod_version = 2.1.2
mod_version = 2.1.3
maven_group = me.bymartrixx
archives_base_name = player-events

Expand Down
8 changes: 7 additions & 1 deletion src/main/java/me/bymartrixx/playerevents/PlayerEvents.java
Expand Up @@ -4,6 +4,7 @@
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonSyntaxException;
import me.bymartrixx.playerevents.api.event.CommandExecutionCallback;
import me.bymartrixx.playerevents.api.event.PlayerDeathCallback;
import me.bymartrixx.playerevents.api.event.PlayerFirstJoinCallback;
import me.bymartrixx.playerevents.api.event.PlayerJoinCallback;
Expand Down Expand Up @@ -34,7 +35,10 @@ public void onInitializeServer() {
LOGGER.error("Invalid JSON syntax in the config file", e);
}

CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> PlayerEventsCommand.register(dispatcher));
CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> {
PlayerEventsCommand.register(dispatcher);
CONFIG.registerCustomCommands(dispatcher);
});

PlayerDeathCallback.EVENT.register((player, source) -> CONFIG.doDeathActions(player));

Expand All @@ -47,6 +51,8 @@ public void onInitializeServer() {
PlayerKillEntityCallback.EVENT.register(CONFIG::doKillEntityActions);

PlayerKillPlayerCallback.EVENT.register(CONFIG::doKillPlayerActions);

CommandExecutionCallback.EVENT.register(CONFIG::doCustomCommandsActions);
}

public static boolean isPlaceholderApiLoaded() {
Expand Down
@@ -1,13 +1,16 @@
package me.bymartrixx.playerevents.config;

import com.google.common.collect.Maps;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.tree.CommandNode;
import eu.pb4.placeholders.PlaceholderAPI;
import me.bymartrixx.playerevents.PlayerEvents;
import me.bymartrixx.playerevents.Utils;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.entity.Entity;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.command.CommandManager;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.text.LiteralText;
Expand Down Expand Up @@ -71,40 +74,42 @@ public static void loadConfig() {
}
}

private final Actions death;
private final Actions firstJoin;
private final Actions join;
private final Actions killEntity;
private final Actions killPlayer;
private final Actions leave;
private final ActionList death;
private final ActionList firstJoin;
private final ActionList join;
private final ActionList killEntity;
private final ActionList killPlayer;
private final ActionList leave;
private final CustomCommandActionList[] customCommands;

public PlayerEventsConfig() {
this.death = new Actions();
this.firstJoin = new Actions();
this.join = new Actions();
this.killPlayer = new Actions();
this.killEntity = new Actions();
this.leave = new Actions();
this.death = new ActionList();
this.firstJoin = new ActionList();
this.join = new ActionList();
this.killPlayer = new ActionList();
this.killEntity = new ActionList();
this.leave = new ActionList();
this.customCommands = new CustomCommandActionList[]{};
}

private static void doSimpleAction(Actions actions, ServerPlayerEntity player) {
private static void doSimpleAction(ActionList actionList, ServerPlayerEntity player) {
Map<String, String> stringPlaceholders = Maps.newHashMap();
Utils.addEntityPlaceholders(stringPlaceholders, player, "player");
Map<String, Text> textPlaceholders = Maps.newHashMap();
Utils.addEntityTextPlaceholders(textPlaceholders, player, "player");
for (String action : actions.actions) {
doAction(action, player, stringPlaceholders, textPlaceholders, actions.broadcastToEveryone);
for (String action : actionList.actions) {
doAction(action, player, stringPlaceholders, textPlaceholders, actionList.broadcastToEveryone);
}
}

private static void doSimpleAction(Actions actions, ServerPlayerEntity player,
private static void doSimpleAction(ActionList actionList, ServerPlayerEntity player,
MinecraftServer server) {
Map<String, String> stringPlaceholders = Maps.newHashMap();
Utils.addEntityPlaceholders(stringPlaceholders, player, "player");
Map<String, Text> textPlaceholders = Maps.newHashMap();
Utils.addEntityTextPlaceholders(textPlaceholders, player, "player");
for (String action : actions.actions) {
doAction(action, player, server, stringPlaceholders, textPlaceholders, actions.broadcastToEveryone);
for (String action : actionList.actions) {
doAction(action, player, server, stringPlaceholders, textPlaceholders, actionList.broadcastToEveryone);
}
}

Expand Down Expand Up @@ -137,15 +142,15 @@ private static void doAction(String action, ServerPlayerEntity player, Minecraft
}
}

public static void testSimpleAction(Actions actions, ServerCommandSource source, String title) {
String message = String.format(title, actions.broadcastToEveryone ? "Send to everyone" : "Send only to the player");
public static void testSimpleAction(ActionList actionList, ServerCommandSource source, String title) {
String message = String.format(title, actionList.broadcastToEveryone ? "Send to everyone" : "Send only to the player");
source.sendFeedback(new LiteralText("" + Formatting.GRAY + Formatting.ITALIC + message), false);

Map<String, String> stringPlaceholders = Maps.newHashMap();
Utils.addCommandSourcePlaceholders(stringPlaceholders, source, "player");
Map<String, Text> textPlaceholders = Maps.newHashMap();
Utils.addCommandSourceTextPlaceholders(textPlaceholders, source, "player");
for (String action : actions.actions) {
for (String action : actionList.actions) {
testAction(action, source, stringPlaceholders, textPlaceholders);
}
}
Expand Down Expand Up @@ -245,6 +250,18 @@ public void doKillPlayerActions(ServerPlayerEntity player, ServerPlayerEntity ki
}
}

public void doCustomCommandsActions(String command, ServerCommandSource source) {
for (CustomCommandActionList actionList : this.customCommands) {
if (actionList.getCommandStr().matches(command)) {
try {
doSimpleAction(actionList, source.getPlayer());
} catch (CommandSyntaxException e) {
PlayerEvents.LOGGER.error("This should not happen, please report it to the mod author, attaching the logs", e);
}
}
}
}

public void testDeathActions(ServerCommandSource source) {
testSimpleAction(this.death, source, "Death actions (%s):");
}
Expand Down Expand Up @@ -304,22 +321,66 @@ public void testKillPlayerActions(ServerCommandSource source) {
}
}

public void testCustomCommandsActions(ServerCommandSource source) {
Map<String, String> stringPlaceholders = Maps.newHashMap();
Utils.addCommandSourcePlaceholders(stringPlaceholders, source, "player");
Map<String, Text> textPlaceholders = Maps.newHashMap();
Utils.addCommandSourceTextPlaceholders(textPlaceholders, source, "player");

for (CustomCommandActionList actionList : this.customCommands) {
String message = String.format("'%s' actions ('%s'):", actionList.getCommandStr(), actionList.broadcastToEveryone ? "Send to everyone" : "Send only to the player");
source.sendFeedback(new LiteralText("§7§o" + message), false);

for (String action : actionList.actions) {
testAction(action, source, stringPlaceholders, textPlaceholders);
}
}
}

public void testEveryActionGroup(ServerCommandSource source) {
this.testDeathActions(source);
this.testFirstJoinActions(source);
this.testJoinActions(source);
this.testKillEntityActions(source);
this.testKillPlayerActions(source);
this.testLeaveActions(source);
this.testCustomCommandsActions(source);
}

public static class Actions {
private final String[] actions;
private final boolean broadcastToEveryone;
public void registerCustomCommands(CommandDispatcher<ServerCommandSource> dispatcher) {
CommandNode<ServerCommandSource> root = dispatcher.getRoot();
for (CustomCommandActionList actionList : this.customCommands) {
CommandNode<ServerCommandSource> node = root.getChild(actionList.getCommand());
if (node == null) {
dispatcher.register(CommandManager.literal(actionList.getCommand()));
}
}
}

public static class ActionList {
protected final String[] actions;
protected final boolean broadcastToEveryone;

public Actions() {
public ActionList() {
this.actions = new String[] {};
this.broadcastToEveryone = true;
}
}

public static class CustomCommandActionList extends ActionList {
protected final String command;

public CustomCommandActionList() {
super();
this.command = "";
}

public String getCommandStr() {
return this.command.startsWith("/") ? this.command : "/" + this.command;
}

public String getCommand() {
return !this.command.startsWith("/") ? this.command : this.command.substring(1);
}
}
}

0 comments on commit 0022505

Please sign in to comment.