Skip to content
This repository was archived by the owner on Feb 19, 2019. It is now read-only.

Commit d2f7c56

Browse files
committed
Command System Functionality!
1 parent efa2913 commit d2f7c56

File tree

10 files changed

+356
-6
lines changed

10 files changed

+356
-6
lines changed

src/main/java/me/zero/client/api/command/ICommand.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package me.zero.client.api.command;
1818

1919
import me.zero.client.api.command.exception.CommandException;
20+
import me.zero.client.api.command.executor.sender.CommandSender;
2021
import me.zero.client.api.util.interfaces.Helper;
2122
import net.minecraft.client.network.NetworkPlayerInfo;
2223

@@ -31,14 +32,13 @@
3132
interface ICommand extends Helper {
3233

3334
/**
34-
* Executes this command from the specified player
35-
* represented by its {@code NetworkPlayerInfo}. This
36-
* can be used to allow other players to execute commands.
35+
* Executes this command from the specified sender with
36+
* the specified arguments, represented as a {@code String} array
3737
*
38-
* @param sender The NetworkPlayerInfo that executed this command
38+
* @param sender The Sender that executed this command
3939
* @param arguments The arguments that
4040
*/
41-
void execute(NetworkPlayerInfo sender, String[] arguments) throws CommandException;
41+
void execute(CommandSender sender, String[] arguments) throws CommandException;
4242

4343
/**
4444
* Returns the array of possible command "headers"
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package me.zero.client.api.command.exception;
2+
3+
/**
4+
* Thrown when a command was expected, but no command headers
5+
* matched the specified command.
6+
*
7+
* @author Brady
8+
* @since 6/11/2017 3:26 PM
9+
*/
10+
public final class UnknownCommandException extends CommandException {
11+
12+
public UnknownCommandException() {
13+
super(null);
14+
}
15+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Copyright 2017 ZeroMemes
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package me.zero.client.api.command.executor;
18+
19+
import me.zero.client.api.command.Command;
20+
import me.zero.client.api.command.exception.CommandException;
21+
import me.zero.client.api.command.executor.sender.CommandSender;
22+
23+
/**
24+
* @author Brady
25+
* @since 6/11/2017 9:26 AM
26+
*/
27+
public interface CommandExecutor {
28+
29+
void execute(Command command, CommandSender sender, String[] arguments) throws CommandException;
30+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2017 ZeroMemes
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package me.zero.client.api.command.executor;
18+
19+
import me.zero.client.api.command.Command;
20+
import me.zero.client.api.command.exception.CommandException;
21+
import me.zero.client.api.command.executor.sender.CommandSender;
22+
23+
/**
24+
* @author Brady
25+
* @since 6/11/2017 9:27 AM
26+
*/
27+
public final class DirectExecutor implements CommandExecutor {
28+
29+
@Override
30+
public void execute(Command command, CommandSender sender, String[] arguments) throws CommandException {
31+
command.execute(sender, arguments);
32+
}
33+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package me.zero.client.api.command.executor.sender;
2+
3+
import net.minecraft.entity.player.EntityPlayer;
4+
5+
/**
6+
* Represents a
7+
*
8+
* @author Brady
9+
* @since 6/11/2017 6:41 PM
10+
*/
11+
public interface CommandSender {
12+
13+
String getName();
14+
15+
static CommandSender from(EntityPlayer player) {
16+
return player::getName;
17+
}
18+
}

src/main/java/me/zero/client/api/command/handler/CommandHandler.java

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,115 @@
1616

1717
package me.zero.client.api.command.handler;
1818

19+
import me.zero.alpine.listener.EventHandler;
20+
import me.zero.alpine.listener.Listener;
21+
import me.zero.client.api.Client;
22+
import me.zero.client.api.command.exception.CommandException;
23+
import me.zero.client.api.command.exception.UnknownCommandException;
24+
import me.zero.client.api.command.exception.handler.ExceptionHandler;
25+
import me.zero.client.api.command.executor.CommandExecutor;
26+
import me.zero.client.api.command.executor.DirectExecutor;
27+
import me.zero.client.api.event.defaults.internal.CommandExecutionEvent;
28+
29+
import java.util.ArrayList;
30+
import java.util.List;
31+
import java.util.stream.Collectors;
32+
1933
/**
2034
* @author Brady
2135
* @since 6/1/2017 3:03 PM
2236
*/
23-
public class CommandHandler {
37+
public final class CommandHandler {
38+
39+
/**
40+
* Handlers to process command exceptions
41+
*/
42+
private final List<ExceptionHandler> handlers = new ArrayList<>();
43+
44+
/**
45+
* Executor that is called to execute commands. The default executor
46+
* is set to a {@code DirectExecutor}
47+
*/
48+
private CommandExecutor executor = new DirectExecutor();
49+
50+
/**
51+
* Client that is using this command handler
52+
*/
53+
private final Client client;
54+
55+
/**
56+
* Prefix used to indicate command input. The default
57+
* prefix is "."
58+
*/
59+
private String prefix = ".";
60+
61+
public CommandHandler(Client client) {
62+
this.client = client;
63+
}
64+
65+
@EventHandler
66+
private final Listener<CommandExecutionEvent> commandExecutionListener = new Listener<>(event -> {
67+
try {
68+
if (event.getCommand() != null)
69+
executor.execute(event.getCommand(), event.getSender(), event.getArguments());
70+
else
71+
throw new UnknownCommandException();
72+
} catch (CommandException e) {
73+
List<ExceptionHandler> handlers = findHandlers(e);
74+
handlers.forEach(handler -> handler.accept(e));
75+
}
76+
});
77+
78+
/**
79+
* Finds handlers that target the specified CommandException
80+
*
81+
* @param exception The command exception
82+
* @return The list of handlers, empty if none
83+
*/
84+
private List<ExceptionHandler> findHandlers(CommandException exception) {
85+
return handlers.stream().filter(handler -> handler.getType() == exception.getClass()).collect(Collectors.toList());
86+
}
87+
88+
/**
89+
* Registers an {@code ExceptionHandler} to the handlers list.
90+
*/
91+
public final void registerHandler(ExceptionHandler handler) {
92+
if (!handlers.contains(handler))
93+
handlers.add(handler);
94+
}
95+
96+
/**
97+
* @return The client that is using this handler
98+
*/
99+
public final Client getClient() {
100+
return this.client;
101+
}
102+
103+
/**
104+
* Sets the command executor
105+
*/
106+
public final void setExecutor(CommandExecutor executor) {
107+
this.executor = executor;
108+
}
109+
110+
/**
111+
* @return The command executor in use
112+
*/
113+
public final CommandExecutor getExecutor() {
114+
return this.executor;
115+
}
116+
117+
/**
118+
* Sets the chat command prefix
119+
*/
120+
public final void setPrefix(String prefix) {
121+
this.prefix = prefix;
122+
}
123+
124+
/**
125+
* @return The chat command prefix
126+
*/
127+
public final String getPrefix() {
128+
return this.prefix;
129+
}
24130
}
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
package me.zero.client.api.command.handler.listener;
2+
3+
import me.zero.alpine.listener.EventHandler;
4+
import me.zero.alpine.listener.Listener;
5+
import me.zero.client.api.ClientAPI;
6+
import me.zero.client.api.command.Command;
7+
import me.zero.client.api.command.handler.CommandHandler;
8+
import me.zero.client.api.command.executor.sender.CommandSender;
9+
import me.zero.client.api.event.defaults.ChatEvent;
10+
import me.zero.client.api.event.defaults.internal.CommandExecutionEvent;
11+
import me.zero.client.api.util.interfaces.Helper;
12+
import net.minecraft.util.text.TextComponentString;
13+
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
import java.util.regex.Matcher;
17+
import java.util.regex.Pattern;
18+
19+
/**
20+
* @author Brady
21+
* @since 6/11/2017 1:47 PM
22+
*/
23+
public final class ChatCommandListener extends CommandListener implements Helper {
24+
25+
private static final Pattern REGEX = Pattern.compile("\"([^\"]+)\"|'([^']+)'|([^\\s]+)");
26+
27+
public ChatCommandListener(CommandHandler handler) {
28+
super(handler);
29+
}
30+
31+
@EventHandler
32+
private final Listener<ChatEvent.Send> chatListener = new Listener<>(event -> {
33+
String raw = event.getRawMessage();
34+
35+
// If the user sends a message starting with a backslash, then we'll send whatever follows it.
36+
if (raw.startsWith("\\") && raw.length() > 1) {
37+
event.setMessage(new TextComponentString(raw.substring(1)));
38+
return;
39+
}
40+
41+
if (raw.startsWith(handler.getPrefix())) {
42+
try {
43+
// No matter what, always cancel the message if it starts with the command prefix
44+
event.cancel();
45+
46+
// Removed the prefix from the message
47+
raw = raw.substring(handler.getPrefix().length());
48+
49+
// Create a matcher to parse the message
50+
Matcher matcher = REGEX.matcher(raw);
51+
52+
List<String> matches = new ArrayList<>();
53+
while (matcher.find()) {
54+
matches.add(matcher.group());
55+
}
56+
57+
// Only handle the command if there is at least 1 argument group
58+
if (matches.size() > 0) {
59+
Command command = handler.getClient().getCommandManager().getData().stream().filter(cmd -> {
60+
for (String header : cmd.headers()) {
61+
if (header.equalsIgnoreCase(matches.get(0))) {
62+
return true;
63+
}
64+
}
65+
return false;
66+
}).findFirst().orElse(null);
67+
68+
// Only handle the command if it's found
69+
if (command != null) {
70+
// Get all matches after the first one, these are treated as arguments
71+
String[] args = new String[matches.size() - 1];
72+
for (int i = 1; i < matches.size(); i++)
73+
args[i - 1] = matches.get(i).replace("\"", "").replace("\'", "");
74+
75+
ClientAPI.EVENT_BUS.post(new CommandExecutionEvent(command, CommandSender.from(mc.player), args));
76+
}
77+
}
78+
79+
// This will be interpreted as an unknown command
80+
ClientAPI.EVENT_BUS.post(new CommandExecutionEvent(null, null, null));
81+
} catch (Exception e) {
82+
e.printStackTrace();
83+
}
84+
}
85+
});
86+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package me.zero.client.api.command.handler.listener;
2+
3+
import me.zero.client.api.command.handler.CommandHandler;
4+
5+
/**
6+
* @author Brady
7+
* @since 6/11/2017 1:47 PM
8+
*/
9+
public class CommandListener {
10+
11+
protected final CommandHandler handler;
12+
13+
public CommandListener(CommandHandler handler) {
14+
this.handler = handler;
15+
}
16+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package me.zero.client.api.event.defaults.internal;
2+
3+
import me.zero.client.api.command.Command;
4+
import me.zero.client.api.command.executor.sender.CommandSender;
5+
6+
/**
7+
* @author Brady
8+
* @since 6/11/2017 9:42 AM
9+
*/
10+
public final class CommandExecutionEvent {
11+
12+
/**
13+
* The command being executed
14+
*/
15+
private final Command command;
16+
17+
/**
18+
* Sender that executed the command
19+
*/
20+
private final CommandSender sender;
21+
22+
/**
23+
* Arguments to be passed to the command
24+
*/
25+
private final String[] arguments;
26+
27+
public CommandExecutionEvent(Command command, CommandSender sender, String[] arguments) {
28+
this.command = command;
29+
this.sender = sender;
30+
this.arguments = arguments;
31+
}
32+
33+
public final Command getCommand() {
34+
return this.command;
35+
}
36+
37+
public final CommandSender getSender() {
38+
return this.sender;
39+
}
40+
41+
public final String[] getArguments() {
42+
return this.arguments;
43+
}
44+
}

0 commit comments

Comments
 (0)