diff --git a/.classpath b/.classpath
deleted file mode 100644
index ef141e6..0000000
--- a/.classpath
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.project b/.project
deleted file mode 100644
index 5c6b9c0..0000000
--- a/.project
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
- Limbo
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.m2e.core.maven2Nature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/modules/LimboDefaultCmd.jar b/modules/LimboDefaultCmd.jar
new file mode 100644
index 0000000..df82086
Binary files /dev/null and b/modules/LimboDefaultCmd.jar differ
diff --git a/src/com/loohp/limbo/Commands/CommandExecutor.java b/src/com/loohp/limbo/Commands/CommandExecutor.java
new file mode 100644
index 0000000..37b5579
--- /dev/null
+++ b/src/com/loohp/limbo/Commands/CommandExecutor.java
@@ -0,0 +1,7 @@
+package com.loohp.limbo.Commands;
+
+public interface CommandExecutor {
+
+ public void execute(CommandSender sender, String[] args);
+
+}
diff --git a/src/com/loohp/limbo/Commands/CommandSender.java b/src/com/loohp/limbo/Commands/CommandSender.java
new file mode 100644
index 0000000..ef5256e
--- /dev/null
+++ b/src/com/loohp/limbo/Commands/CommandSender.java
@@ -0,0 +1,17 @@
+package com.loohp.limbo.Commands;
+
+import net.md_5.bungee.api.chat.BaseComponent;
+
+public interface CommandSender {
+
+ public void sendMessage(BaseComponent[] component);
+
+ public void sendMessage(BaseComponent component);
+
+ public void sendMessage(String message);
+
+ public boolean hasPermission(String permission);
+
+ public String getName();
+
+}
diff --git a/src/com/loohp/limbo/Commands/TabCompletor.java b/src/com/loohp/limbo/Commands/TabCompletor.java
new file mode 100644
index 0000000..477da50
--- /dev/null
+++ b/src/com/loohp/limbo/Commands/TabCompletor.java
@@ -0,0 +1,9 @@
+package com.loohp.limbo.Commands;
+
+import java.util.List;
+
+public interface TabCompletor {
+
+ public List tabComplete(CommandSender sender, String[] args);
+
+}
diff --git a/src/com/loohp/limbo/Console.java b/src/com/loohp/limbo/Console.java
index 4436eb1..d5c9851 100644
--- a/src/com/loohp/limbo/Console.java
+++ b/src/com/loohp/limbo/Console.java
@@ -1,6 +1,8 @@
package com.loohp.limbo;
import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -10,19 +12,54 @@ import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
+import java.util.stream.Collectors;
-import com.loohp.limbo.Player.Player;
+import com.loohp.limbo.Commands.CommandSender;
import com.loohp.limbo.Utils.CustomStringUtils;
-public class Console {
+import net.md_5.bungee.api.chat.BaseComponent;
+
+public class Console implements CommandSender {
private InputStream in;
private PrintStream out;
+ @SuppressWarnings("unused")
+ private PrintStream err;
+ protected PrintStream logs;
- public Console(InputStream in, PrintStream out) {
+ private final String CONSOLE = "CONSOLE";
+
+ public Console(InputStream in, PrintStream out, PrintStream err) throws FileNotFoundException {
+ String fileName = new SimpleDateFormat("yyyy'-'MM'-'dd'_'HH'-'mm'-'ss'_'zzz'.log'").format(new Date());
+ File dir = new File("logs");
+ dir.mkdirs();
+ File logs = new File(dir, fileName);
+ this.logs = new PrintStream(logs);
+
+ System.setIn(in);
this.in = in;
- System.setOut(new ConsoleOutputStream(out));
+ System.setOut(new ConsoleOutputStream(out, this.logs));
this.out = System.out;
+ System.setErr(new ConsoleErrorStream(err, this.logs));
+ this.err = System.err;
+ }
+
+ public String getName() {
+ return CONSOLE;
+ }
+
+ @Override
+ public void sendMessage(BaseComponent component) {
+ sendMessage(new BaseComponent[] {component});
+ }
+
+ @Override
+ public void sendMessage(BaseComponent[] component) {
+ sendMessage(String.join("", Arrays.asList(component).stream().map(each -> each.toLegacyText()).collect(Collectors.toList())));
+ }
+
+ public boolean hasPermission(String permission) {
+ return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
}
public void sendMessage(String message) {
@@ -33,115 +70,199 @@ public class Console {
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
while (true) {
try {
- String[] input = CustomStringUtils.splitStringToArgs(reader.readLine());
-
- if (input[0].equalsIgnoreCase("stop")) {
- Limbo.getInstance().stopServer();
- } else if (input[0].equalsIgnoreCase("say")) {
- if (input.length > 1) {
- String message = "[Server] " + String.join(" ", Arrays.copyOfRange(input, 1, input.length));
- sendMessage(message);
- for (Player each : Limbo.getInstance().getPlayers()) {
- each.sendMessage(message);
- }
- }
- } else if (input[0].equalsIgnoreCase("kick")) {
- String reason = "Disconnected!";
- Player player = input.length > 1 ? Limbo.getInstance().getPlayer(input[1]) : null;
- if (player != null) {
- if (input.length < 2) {
- player.disconnect();
- } else {
- reason = String.join(" ", Arrays.copyOfRange(input, 2, input.length));
- player.disconnect(reason);
- }
- sendMessage("Kicked the player " + input[1] + " for the reason: " + reason);
- } else {
- sendMessage("Player is not online!");
- }
- }
+ String[] input = CustomStringUtils.splitStringToArgs(reader.readLine());
+ Limbo.getInstance().dispatchCommand(this, input);
} catch (IOException e) {
e.printStackTrace();
}
}
}
- public class ConsoleOutputStream extends PrintStream {
+ public static class ConsoleOutputStream extends PrintStream {
- public ConsoleOutputStream(OutputStream out) {
+ private PrintStream logs;
+
+ public ConsoleOutputStream(OutputStream out, PrintStream logs) {
super(out);
+ this.logs = logs;
}
@Override
public PrintStream printf(Locale l, String format, Object... args) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- return super.printf(l, "[" + date + "] " + format, args);
+ logs.printf(l, "[" + date + " INFO]" + format, args);
+ return super.printf(l, "[" + date + " INFO]" + format, args);
}
@Override
public PrintStream printf(String format, Object... args) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- return super.printf("[" + date + "] " + format, args);
+ logs.printf("[" + date + " INFO]" + format, args);
+ return super.printf("[" + date + " INFO]" + format, args);
}
@Override
public void println() {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] ");
+ logs.println("[" + date + " INFO]");
+ super.println("[" + date + " INFO]");
}
@Override
public void println(boolean x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(char x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(char[] x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + String.valueOf(x));
+ logs.println("[" + date + " INFO]" + String.valueOf(x));
+ super.println("[" + date + " INFO]" + String.valueOf(x));
}
@Override
public void println(double x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(float x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(int x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(long x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(Object x) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + x);
+ logs.println("[" + date + " INFO]" + x);
+ super.println("[" + date + " INFO]" + x);
}
@Override
public void println(String string) {
String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
- super.println("[" + date + "] " + string);
+ logs.println("[" + date + " INFO] " + string);
+ super.println("[" + date + " INFO] " + string);
+ }
+ }
+
+ public static class ConsoleErrorStream extends PrintStream {
+
+ private PrintStream logs;
+
+ public ConsoleErrorStream(OutputStream out, PrintStream logs) {
+ super(out);
+ this.logs = logs;
+ }
+
+ @Override
+ public PrintStream printf(Locale l, String format, Object... args) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.printf(l, "[" + date + " Error]" + format, args);
+ return super.printf(l, "[" + date + " Error]" + format, args);
+ }
+
+ @Override
+ public PrintStream printf(String format, Object... args) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.printf("[" + date + " Error]" + format, args);
+ return super.printf("[" + date + " Error]" + format, args);
+ }
+
+ @Override
+ public void println() {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]");
+ super.println("[" + date + " Error]");
+ }
+
+ @Override
+ public void println(boolean x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(char x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(char[] x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + String.valueOf(x));
+ super.println("[" + date + " Error]" + String.valueOf(x));
+ }
+
+ @Override
+ public void println(double x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(float x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(int x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(long x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(Object x) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error]" + x);
+ super.println("[" + date + " Error]" + x);
+ }
+
+ @Override
+ public void println(String string) {
+ String date = new SimpleDateFormat("HH':'mm':'ss").format(new Date());
+ logs.println("[" + date + " Error] " + string);
+ super.println("[" + date + " Error] " + string);
}
}
diff --git a/src/com/loohp/limbo/DeclareCommands.java b/src/com/loohp/limbo/DeclareCommands.java
index 5eed47f..c2553f6 100644
--- a/src/com/loohp/limbo/DeclareCommands.java
+++ b/src/com/loohp/limbo/DeclareCommands.java
@@ -2,27 +2,50 @@ package com.loohp.limbo;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
-import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.List;
+import com.loohp.limbo.Commands.CommandSender;
import com.loohp.limbo.Server.Packets.PacketPlayOutDeclareCommands;
import com.loohp.limbo.Utils.DataTypeIO;
public class DeclareCommands {
- public static PacketPlayOutDeclareCommands getDeclareCommandPacket() throws IOException {
+ public static PacketPlayOutDeclareCommands getDeclareCommandsPacket(CommandSender sender) throws Exception {
+ List commands = Limbo.getInstance().getPluginManager().getTabOptions(sender, new String[0]);
+
+ if (commands.isEmpty()) {
+ return null;
+ }
+
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream output = new DataOutputStream(buffer);
- DataTypeIO.writeVarInt(output, 2);
+ DataTypeIO.writeVarInt(output, commands.size() * 2 + 1);
output.writeByte(0);
- DataTypeIO.writeVarInt(output, 1);
- DataTypeIO.writeVarInt(output, 1);
+ DataTypeIO.writeVarInt(output, commands.size());
+ for (int i = 1; i <= commands.size() * 2; i++) {
+ DataTypeIO.writeVarInt(output, i++);
+ }
- output.writeByte(1 | 0x04);
- DataTypeIO.writeVarInt(output, 0);
- DataTypeIO.writeString(output, "spawn", StandardCharsets.UTF_8);
+ int i = 1;
+ for (String label : commands) {
+ output.writeByte(1 | 0x04);
+ DataTypeIO.writeVarInt(output, 1);
+ DataTypeIO.writeVarInt(output, i + 1);
+ DataTypeIO.writeString(output, label, StandardCharsets.UTF_8);
+ i++;
+
+ output.writeByte(2 | 0x04 | 0x10);
+ DataTypeIO.writeVarInt(output, 1);
+ DataTypeIO.writeVarInt(output, i);
+ DataTypeIO.writeString(output, "arg", StandardCharsets.UTF_8);
+ DataTypeIO.writeString(output, "brigadier:string", StandardCharsets.UTF_8);
+ DataTypeIO.writeVarInt(output, 0);
+ DataTypeIO.writeString(output, "minecraft:ask_server", StandardCharsets.UTF_8);
+ i++;
+ }
DataTypeIO.writeVarInt(output, 0);
diff --git a/src/com/loohp/limbo/Events/Cancellable.java b/src/com/loohp/limbo/Events/Cancellable.java
new file mode 100644
index 0000000..4dbb8fd
--- /dev/null
+++ b/src/com/loohp/limbo/Events/Cancellable.java
@@ -0,0 +1,9 @@
+package com.loohp.limbo.Events;
+
+public interface Cancellable {
+
+ public void setCancelled(boolean cancelled);
+
+ public boolean isCancelled();
+
+}
diff --git a/src/com/loohp/limbo/Events/Event.java b/src/com/loohp/limbo/Events/Event.java
new file mode 100644
index 0000000..f5086fd
--- /dev/null
+++ b/src/com/loohp/limbo/Events/Event.java
@@ -0,0 +1,5 @@
+package com.loohp.limbo.Events;
+
+public abstract class Event {
+
+}
diff --git a/src/com/loohp/limbo/Events/EventHandler.java b/src/com/loohp/limbo/Events/EventHandler.java
new file mode 100644
index 0000000..02bf719
--- /dev/null
+++ b/src/com/loohp/limbo/Events/EventHandler.java
@@ -0,0 +1,14 @@
+package com.loohp.limbo.Events;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Documented
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EventHandler {
+ EventPriority priority() default EventPriority.NORMAL;
+}
\ No newline at end of file
diff --git a/src/com/loohp/limbo/Events/EventPriority.java b/src/com/loohp/limbo/Events/EventPriority.java
new file mode 100644
index 0000000..77a31e0
--- /dev/null
+++ b/src/com/loohp/limbo/Events/EventPriority.java
@@ -0,0 +1,37 @@
+package com.loohp.limbo.Events;
+
+public enum EventPriority {
+ LOWEST(0),
+ LOW(1),
+ NORMAL(2),
+ HIGH(3),
+ HIGHEST(4),
+ MONITOR(5);
+
+ int order;
+
+ EventPriority(int order) {
+ this.order = order;
+ }
+
+ public int getOrder() {
+ return order;
+ }
+
+ public static EventPriority getByOrder(int order) {
+ for (EventPriority each : EventPriority.values()) {
+ if (each.getOrder() == order) {
+ return each;
+ }
+ }
+ return null;
+ }
+
+ public static EventPriority[] getPrioritiesInOrder() {
+ EventPriority[] array = new EventPriority[EventPriority.values().length];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = EventPriority.getByOrder(i);
+ }
+ return array;
+ }
+}
\ No newline at end of file
diff --git a/src/com/loohp/limbo/Events/EventsManager.java b/src/com/loohp/limbo/Events/EventsManager.java
new file mode 100644
index 0000000..e3ed46d
--- /dev/null
+++ b/src/com/loohp/limbo/Events/EventsManager.java
@@ -0,0 +1,58 @@
+package com.loohp.limbo.Events;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.loohp.limbo.Plugins.LimboPlugin;
+
+public class EventsManager {
+
+ private List listeners;
+
+ public EventsManager() {
+ listeners = new ArrayList<>();
+ }
+
+ public Event callEvent(Event event) {
+ for (EventPriority priority : EventPriority.getPrioritiesInOrder()) {
+ for (ListenerPair entry : listeners) {
+ Listener listener = entry.listener;
+ for (Method method : listener.getClass().getMethods()) {
+ if (method.isAnnotationPresent(EventHandler.class)) {
+ if (method.getAnnotation(EventHandler.class).priority().equals(priority)) {
+ if (method.getParameterCount() == 1 && method.getParameterTypes()[0].equals(event.getClass())) {
+ try {
+ method.invoke(listener, event);
+ } catch (Exception e) {
+ System.err.println("Error while passing " + event.getClass().getCanonicalName() + " to the plugin \"" + entry.plugin.getName() + "\"");
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return event;
+ }
+
+ public void registerEvents(LimboPlugin plugin, Listener listener) {
+ listeners.add(new ListenerPair(plugin, listener));
+ }
+
+ public void unregisterAllListeners(LimboPlugin plugin) {
+ listeners.removeIf(each -> each.plugin.equals(plugin));
+ }
+
+ protected static class ListenerPair {
+ public LimboPlugin plugin;
+ public Listener listener;
+
+ public ListenerPair(LimboPlugin plugin, Listener listener) {
+ this.plugin = plugin;
+ this.listener = listener;
+ }
+ }
+
+}
diff --git a/src/com/loohp/limbo/Events/Listener.java b/src/com/loohp/limbo/Events/Listener.java
new file mode 100644
index 0000000..030230b
--- /dev/null
+++ b/src/com/loohp/limbo/Events/Listener.java
@@ -0,0 +1,5 @@
+package com.loohp.limbo.Events;
+
+public interface Listener {
+
+}
diff --git a/src/com/loohp/limbo/Events/PlayerChatEvent.java b/src/com/loohp/limbo/Events/PlayerChatEvent.java
new file mode 100644
index 0000000..2b28017
--- /dev/null
+++ b/src/com/loohp/limbo/Events/PlayerChatEvent.java
@@ -0,0 +1,49 @@
+package com.loohp.limbo.Events;
+
+import com.loohp.limbo.Player.Player;
+
+public class PlayerChatEvent extends PlayerEvent implements Cancellable {
+
+ private String prefix;
+ private String message;
+ private boolean cancelled;
+
+ public PlayerChatEvent(Player player, String prefix, String message, boolean cancelled) {
+ this.player = player;
+ this.prefix = prefix;
+ this.message = message;
+ this.cancelled = cancelled;
+ }
+
+ @Override
+ public Player getPlayer() {
+ return player;
+ }
+
+ public String getPrefix() {
+ return prefix;
+ }
+
+ public void setPrefix(String prefix) {
+ this.prefix = prefix;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+}
diff --git a/src/com/loohp/limbo/Events/PlayerEvent.java b/src/com/loohp/limbo/Events/PlayerEvent.java
new file mode 100644
index 0000000..888dd3d
--- /dev/null
+++ b/src/com/loohp/limbo/Events/PlayerEvent.java
@@ -0,0 +1,11 @@
+package com.loohp.limbo.Events;
+
+import com.loohp.limbo.Player.Player;
+
+public abstract class PlayerEvent extends Event {
+
+ protected Player player;
+
+ public abstract Player getPlayer();
+
+}
diff --git a/src/com/loohp/limbo/Events/PlayerJoinEvent.java b/src/com/loohp/limbo/Events/PlayerJoinEvent.java
new file mode 100644
index 0000000..5698234
--- /dev/null
+++ b/src/com/loohp/limbo/Events/PlayerJoinEvent.java
@@ -0,0 +1,16 @@
+package com.loohp.limbo.Events;
+
+import com.loohp.limbo.Player.Player;
+
+public class PlayerJoinEvent extends PlayerEvent {
+
+ public PlayerJoinEvent(Player player) {
+ this.player = player;
+ }
+
+ @Override
+ public Player getPlayer() {
+ return player;
+ }
+
+}
diff --git a/src/com/loohp/limbo/Events/PlayerLoginEvent.java b/src/com/loohp/limbo/Events/PlayerLoginEvent.java
new file mode 100644
index 0000000..781c8d4
--- /dev/null
+++ b/src/com/loohp/limbo/Events/PlayerLoginEvent.java
@@ -0,0 +1,41 @@
+package com.loohp.limbo.Events;
+
+import com.loohp.limbo.Server.ClientConnection;
+
+import net.md_5.bungee.api.chat.BaseComponent;
+
+public class PlayerLoginEvent extends Event implements Cancellable {
+
+ private ClientConnection connection;
+ private boolean cancelled;
+ private BaseComponent[] cancelReason;
+
+ public PlayerLoginEvent(ClientConnection connection, boolean cancelled, BaseComponent... cancelReason) {
+ this.connection = connection;
+ this.cancelled = cancelled;
+ this.cancelReason = cancelReason;
+ }
+
+ public ClientConnection getConnection() {
+ return connection;
+ }
+
+ public BaseComponent[] getCancelReason() {
+ return cancelReason;
+ }
+
+ public void setCancelReason(BaseComponent... cancelReason) {
+ this.cancelReason = cancelReason;
+ }
+
+ @Override
+ public void setCancelled(boolean cancelled) {
+ this.cancelled = cancelled;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return cancelled;
+ }
+
+}
diff --git a/src/com/loohp/limbo/Events/PlayerQuitEvent.java b/src/com/loohp/limbo/Events/PlayerQuitEvent.java
new file mode 100644
index 0000000..26760c8
--- /dev/null
+++ b/src/com/loohp/limbo/Events/PlayerQuitEvent.java
@@ -0,0 +1,16 @@
+package com.loohp.limbo.Events;
+
+import com.loohp.limbo.Player.Player;
+
+public class PlayerQuitEvent extends PlayerEvent {
+
+ public PlayerQuitEvent(Player player) {
+ this.player = player;
+ }
+
+ @Override
+ public Player getPlayer() {
+ return player;
+ }
+
+}
diff --git a/src/com/loohp/limbo/File/FileConfiguration.java b/src/com/loohp/limbo/File/FileConfiguration.java
index b9e0a46..66949ad 100644
--- a/src/com/loohp/limbo/File/FileConfiguration.java
+++ b/src/com/loohp/limbo/File/FileConfiguration.java
@@ -3,27 +3,26 @@ package com.loohp.limbo.File;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
+import java.io.InputStream;
import java.util.Map;
import org.yaml.snakeyaml.Yaml;
public class FileConfiguration {
- File file;
Map mapping;
public FileConfiguration(File file) throws FileNotFoundException {
- this.file = file;
- reloadConfig();
+ reloadConfig(new FileInputStream(file));
}
- public FileConfiguration reloadConfig() {
- try {
- Yaml yml = new Yaml();
- mapping = yml.load(new FileInputStream(file));
- } catch (FileNotFoundException e) {
- e.printStackTrace();
- }
+ public FileConfiguration(InputStream input){
+ reloadConfig(input);
+ }
+
+ public FileConfiguration reloadConfig(InputStream input) {
+ Yaml yml = new Yaml();
+ mapping = yml.load(input);
return this;
}
@@ -35,6 +34,9 @@ public class FileConfiguration {
for (int i = 0; i < tree.length - 1; i++) {
map = (Map) map.get(tree[i]);
}
+ if (returnType.equals(String.class)) {
+ return (T) map.get(tree[tree.length - 1]).toString();
+ }
return returnType.cast(map.get(tree[tree.length - 1]));
} catch (Exception e) {
return null;
diff --git a/src/com/loohp/limbo/Limbo.java b/src/com/loohp/limbo/Limbo.java
index 311a9cf..51f86ea 100644
--- a/src/com/loohp/limbo/Limbo.java
+++ b/src/com/loohp/limbo/Limbo.java
@@ -19,13 +19,19 @@ import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
+import com.loohp.limbo.Commands.CommandSender;
+import com.loohp.limbo.Events.EventsManager;
import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location;
+import com.loohp.limbo.Permissions.PermissionsManager;
import com.loohp.limbo.Player.Player;
+import com.loohp.limbo.Plugins.LimboPlugin;
+import com.loohp.limbo.Plugins.PluginManager;
import com.loohp.limbo.Server.ServerConnection;
import com.loohp.limbo.Server.Packets.Packet;
import com.loohp.limbo.Server.Packets.PacketIn;
import com.loohp.limbo.Server.Packets.PacketOut;
+import com.loohp.limbo.Utils.CustomStringUtils;
import com.loohp.limbo.Utils.ImageUtils;
import com.loohp.limbo.Utils.NetworkUtils;
import com.loohp.limbo.World.Schematic;
@@ -57,13 +63,18 @@ public class Limbo {
private ServerProperties properties;
- public AtomicInteger entityCount = new AtomicInteger();
+ private PluginManager pluginManager;
+ private EventsManager eventsManager;
+ private PermissionsManager permissionManager;
+ private File pluginFolder;
+
+ public AtomicInteger entityIdCount = new AtomicInteger();
@SuppressWarnings("unchecked")
public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException {
instance = this;
- console = new Console(System.in, System.out);
+ console = new Console(System.in, System.out, System.err);
String spName = "server.properties";
File sp = new File(spName);
@@ -170,11 +181,52 @@ public class Limbo {
System.exit(2);
}
+ String permissionName = "permission.yml";
+ File permissionFile = new File(permissionName);
+ if (!permissionFile.exists()) {
+ try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
+ Files.copy(in, permissionFile.toPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ permissionManager = new PermissionsManager();
+ permissionManager.loadDefaultPermissionFile(permissionFile);
+
+ eventsManager = new EventsManager();
+
+ pluginFolder = new File("plugins");
+ pluginFolder.mkdirs();
+
+ pluginManager = new PluginManager(pluginFolder);
+
+ for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
+ console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
+ plugin.onEnable();
+ }
+
server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
console.run();
}
+ public EventsManager getEventsManager() {
+ return eventsManager;
+ }
+
+ public PermissionsManager getPermissionsManager() {
+ return permissionManager;
+ }
+
+ public File getPluginFolder() {
+ return pluginFolder;
+ }
+
+ public PluginManager getPluginManager() {
+ return pluginManager;
+ }
+
private World loadDefaultWorld() throws IOException {
console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
@@ -260,7 +312,13 @@ public class Limbo {
}
public void stopServer() {
- Limbo.getInstance().getConsole().sendMessage("Stopping Server...");
+ console.sendMessage("Stopping Server...");
+
+ for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
+ console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
+ plugin.onDisable();
+ }
+
for (Player player : getPlayers()) {
player.disconnect("Server closed");
}
@@ -271,7 +329,34 @@ public class Limbo {
e.printStackTrace();
}
}
+ console.logs.close();
System.exit(0);
}
+
+ public int getNextEntityId() {
+ if (entityIdCount.get() == Integer.MAX_VALUE) {
+ return entityIdCount.getAndSet(0);
+ } else {
+ return entityIdCount.getAndIncrement();
+ }
+ }
+
+ public void dispatchCommand(CommandSender sender, String str) {
+ String[] command;
+ if (str.startsWith("/")) {
+ command = CustomStringUtils.splitStringToArgs(str.substring(1));
+ } else {
+ command = CustomStringUtils.splitStringToArgs(str);
+ }
+ dispatchCommand(sender, command);
+ }
+
+ public void dispatchCommand(CommandSender sender, String... args) {
+ try {
+ Limbo.getInstance().getPluginManager().fireExecutors(sender, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/com/loohp/limbo/Permissions/PermissionsManager.java b/src/com/loohp/limbo/Permissions/PermissionsManager.java
new file mode 100644
index 0000000..0378bda
--- /dev/null
+++ b/src/com/loohp/limbo/Permissions/PermissionsManager.java
@@ -0,0 +1,64 @@
+package com.loohp.limbo.Permissions;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.loohp.limbo.Console;
+import com.loohp.limbo.Commands.CommandSender;
+import com.loohp.limbo.File.FileConfiguration;
+import com.loohp.limbo.Player.Player;
+
+public class PermissionsManager {
+
+ private Map> users;
+ private Map> permissions;
+
+ public PermissionsManager() {
+ users = new HashMap<>();
+ permissions = new HashMap<>();
+ }
+
+ @SuppressWarnings("unchecked")
+ public void loadDefaultPermissionFile(File file) throws FileNotFoundException {
+ FileConfiguration config = new FileConfiguration(file);
+ for (Object obj : config.get("groups", Map.class).keySet()) {
+ String key = (String) obj;
+ List nodes = new ArrayList<>();
+ nodes.addAll(config.get("groups." + key, List.class));
+ permissions.put(key, nodes);
+ }
+ for (Object obj : config.get("players", Map.class).keySet()) {
+ String key = (String) obj;
+ List groups = new ArrayList<>();
+ groups.addAll(config.get("players." + key, List.class));
+ users.put(key, groups);
+ }
+ }
+
+ public boolean hasPermission(CommandSender sender, String permission) {
+ if (sender instanceof Console) {
+ return true;
+ } else if (sender instanceof Player) {
+ Player player = (Player) sender;
+ if (users.get(player.getName()).stream().anyMatch(each -> permissions.get(each).stream().anyMatch(node -> node.equalsIgnoreCase(permission)))) {
+ return true;
+ } else {
+ return permissions.get("default").stream().anyMatch(node -> node.equalsIgnoreCase(permission));
+ }
+ }
+ return false;
+ }
+
+ public Map> getUsers() {
+ return users;
+ }
+
+ public Map> getPermissions() {
+ return permissions;
+ }
+
+}
diff --git a/src/com/loohp/limbo/Player/Player.java b/src/com/loohp/limbo/Player/Player.java
index 51a25c5..920fc4b 100644
--- a/src/com/loohp/limbo/Player/Player.java
+++ b/src/com/loohp/limbo/Player/Player.java
@@ -3,6 +3,9 @@ package com.loohp.limbo.Player;
import java.io.IOException;
import java.util.UUID;
+import com.loohp.limbo.Limbo;
+import com.loohp.limbo.Commands.CommandSender;
+import com.loohp.limbo.Events.PlayerChatEvent;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Server.ClientConnection;
import com.loohp.limbo.Server.Packets.PacketPlayOutChat;
@@ -13,7 +16,7 @@ import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.chat.ComponentSerializer;
-public class Player {
+public class Player implements CommandSender {
public final ClientConnection clientConnection;
@@ -59,6 +62,10 @@ public class Player {
public UUID getUUID() {
return uuid;
}
+
+ public boolean hasPermission(String permission) {
+ return Limbo.getInstance().getPermissionsManager().hasPermission(this, permission);
+ }
public void sendMessage(String message) {
sendMessage(TextComponent.fromLegacyText(message));
@@ -78,6 +85,7 @@ public class Player {
}
}
+ @Override
public void sendMessage(BaseComponent[] component) {
try {
PacketPlayOutChat chat = new PacketPlayOutChat(ComponentSerializer.toString(component), 0, new UUID(0, 0));
@@ -102,5 +110,17 @@ public class Player {
public void disconnect(BaseComponent[] reason) {
clientConnection.disconnect(reason);
}
+
+ public void chat(String message) {
+ String prefix = "<" + username + "> ";
+ PlayerChatEvent event = (PlayerChatEvent) Limbo.getInstance().getEventsManager().callEvent(new PlayerChatEvent(this, prefix, message, false));
+ if (!event.isCancelled()) {
+ String chat = event.getPrefix() + event.getMessage();
+ Limbo.getInstance().getConsole().sendMessage(chat);
+ for (Player each : Limbo.getInstance().getPlayers()) {
+ each.sendMessage(chat);
+ }
+ }
+ }
}
diff --git a/src/com/loohp/limbo/Plugins/LimboPlugin.java b/src/com/loohp/limbo/Plugins/LimboPlugin.java
new file mode 100644
index 0000000..3216233
--- /dev/null
+++ b/src/com/loohp/limbo/Plugins/LimboPlugin.java
@@ -0,0 +1,48 @@
+package com.loohp.limbo.Plugins;
+
+import java.io.File;
+
+import com.loohp.limbo.Limbo;
+import com.loohp.limbo.File.FileConfiguration;
+
+public class LimboPlugin {
+
+ private String name;
+ private File dataFolder;
+ private PluginInfo info;
+
+ public final void setInfo(FileConfiguration file) {
+ info = new PluginInfo(file);
+ name = info.getName();
+ dataFolder = new File(Limbo.getInstance().getPluginFolder(), name);
+ }
+
+ public void onLoad() {
+
+ }
+
+ public void onEnable() {
+
+ }
+
+ public void onDisable() {
+
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public File getDataFolder() {
+ return new File(dataFolder.getAbsolutePath());
+ }
+
+ public PluginInfo getInfo() {
+ return info;
+ }
+
+ public Limbo getServer() {
+ return Limbo.getInstance();
+ }
+
+}
diff --git a/src/com/loohp/limbo/Plugins/PluginInfo.java b/src/com/loohp/limbo/Plugins/PluginInfo.java
new file mode 100644
index 0000000..e27c163
--- /dev/null
+++ b/src/com/loohp/limbo/Plugins/PluginInfo.java
@@ -0,0 +1,41 @@
+package com.loohp.limbo.Plugins;
+
+import com.loohp.limbo.File.FileConfiguration;
+
+public class PluginInfo {
+
+ private String name;
+ private String description;
+ private String author;
+ private String version;
+ private String main;
+
+ public PluginInfo(FileConfiguration file) {
+ name = file.get("name", String.class);
+ description = file.get("description", String.class) == null ? "" : file.get("description", String.class);
+ author = file.get("author", String.class);
+ version = file.get("version", String.class);
+ main = file.get("main", String.class);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public String getAuthor() {
+ return author;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public String getMainClass() {
+ return main;
+ }
+
+}
diff --git a/src/com/loohp/limbo/Plugins/PluginManager.java b/src/com/loohp/limbo/Plugins/PluginManager.java
new file mode 100644
index 0000000..b52e1a7
--- /dev/null
+++ b/src/com/loohp/limbo/Plugins/PluginManager.java
@@ -0,0 +1,140 @@
+package com.loohp.limbo.Plugins;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import com.loohp.limbo.Limbo;
+import com.loohp.limbo.Commands.CommandExecutor;
+import com.loohp.limbo.Commands.CommandSender;
+import com.loohp.limbo.Commands.TabCompletor;
+import com.loohp.limbo.File.FileConfiguration;
+
+public class PluginManager {
+
+ private Map plugins;
+ private List executors;
+ private File pluginFolder;
+
+ public PluginManager(File pluginFolder) {
+ this.pluginFolder = pluginFolder;
+ this.executors = new ArrayList<>();
+
+ this.plugins = new LinkedHashMap<>();
+
+ for (File file : pluginFolder.listFiles()) {
+ if (file.isFile() && file.getName().endsWith(".jar")) {
+ boolean found = false;
+ try (ZipInputStream zip = new ZipInputStream(new FileInputStream(file))) {
+ while (true) {
+ ZipEntry entry = zip.getNextEntry();
+ if (entry == null) {
+ break;
+ }
+ String name = entry.getName();
+ if (name.endsWith("plugin.yml")) {
+ found = true;
+
+ FileConfiguration pluginYaml = new FileConfiguration(zip);
+ String main = pluginYaml.get("main", String.class);
+ String pluginName = pluginYaml.get("name", String.class);
+
+ if (plugins.containsKey(pluginName)) {
+ System.err.println("Ambiguous plugin name in " + file.getName() + " with the plugin \"" + plugins.get(pluginName).getClass().getName() + "\"");
+ break;
+ }
+
+ URLClassLoader url = new URLClassLoader(new URL[] {file.toURI().toURL()});
+ Class> plugin = url.loadClass(main);
+ LimboPlugin clazz = (LimboPlugin) plugin.getDeclaredConstructor().newInstance();
+ clazz.setInfo(pluginYaml);
+ plugins.put(clazz.getName(), clazz);
+ clazz.onLoad();
+ System.out.println("Loading plugin " + file.getName() + " " + clazz.getInfo().getVersion() + " by " + clazz.getInfo().getAuthor());
+ url.close();
+ break;
+ }
+ }
+ } catch (Exception e) {
+ System.err.println("Unable to load plugin \"" + file.getName() + "\"");
+ e.printStackTrace();
+ }
+ if (!found) {
+ System.err.println("Jar file " + file.getName() + " has no plugin.yml!");
+ }
+ }
+ }
+ }
+
+ public List getPlugins() {
+ return new ArrayList<>(plugins.values());
+ }
+
+ public LimboPlugin getPlugin(String name) {
+ return plugins.get(name);
+ }
+
+ public void fireExecutors(CommandSender sender, String[] args) throws Exception {
+ Limbo.getInstance().getConsole().sendMessage(sender.getName() + " executed server command: /" + String.join(" ", args));
+ for (Executor entry : executors) {
+ try {
+ entry.executor.execute(sender, args);
+ } catch (Exception e) {
+ System.err.println("Error while passing command \"" + args[0] + "\" to the plugin \"" + entry.plugin.getName() + "\"");
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public List getTabOptions(CommandSender sender, String[] args) throws Exception {
+ List options = new ArrayList<>();
+ for (Executor entry : executors) {
+ if (entry.tab.isPresent()) {
+ try {
+ options.addAll(entry.tab.get().tabComplete(sender, args));
+ } catch (Exception e) {
+ System.err.println("Error while passing tab completion \"" + args[0] + "\" to the plugin \"" + entry.plugin.getName() + "\"");
+ e.printStackTrace();
+ }
+ }
+ }
+ return options;
+ }
+
+ public void registerCommands(LimboPlugin plugin, CommandExecutor executor) {
+ executors.add(new Executor(plugin, executor));
+ }
+
+ public void unregsiterAllCommands(LimboPlugin plugin) {
+ executors.removeIf(each -> each.plugin.equals(plugin));
+ }
+
+ public File getPluginFolder() {
+ return new File(pluginFolder.getAbsolutePath());
+ }
+
+ protected static class Executor {
+ public LimboPlugin plugin;
+ public CommandExecutor executor;
+ public Optional tab;
+
+ public Executor(LimboPlugin plugin, CommandExecutor executor) {
+ this.plugin = plugin;
+ this.executor = executor;
+ if (executor instanceof TabCompletor) {
+ this.tab = Optional.of((TabCompletor) executor);
+ } else {
+ this.tab = Optional.empty();
+ }
+ }
+ }
+
+}
diff --git a/src/com/loohp/limbo/Server/ClientConnection.java b/src/com/loohp/limbo/Server/ClientConnection.java
index 336eff6..f5243cc 100644
--- a/src/com/loohp/limbo/Server/ClientConnection.java
+++ b/src/com/loohp/limbo/Server/ClientConnection.java
@@ -11,9 +11,13 @@ import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
import com.loohp.limbo.DeclareCommands;
import com.loohp.limbo.Limbo;
+import com.loohp.limbo.Events.PlayerJoinEvent;
+import com.loohp.limbo.Events.PlayerLoginEvent;
+import com.loohp.limbo.Events.PlayerQuitEvent;
import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player;
@@ -73,7 +77,7 @@ public class ClientConnection extends Thread {
DISCONNECTED;
}
- private Socket client_socket;
+ private final Socket client_socket;
private boolean running;
private ClientState state;
@@ -83,15 +87,15 @@ public class ClientConnection extends Thread {
protected DataOutputStream output;
protected DataInputStream input;
- private InetAddress iNetAddress;
+ private InetAddress inetAddress;
public ClientConnection(Socket client_socket) {
this.client_socket = client_socket;
- this.iNetAddress = client_socket.getInetAddress();
+ this.inetAddress = client_socket.getInetAddress();
}
- public InetAddress getiNetAddress() {
- return iNetAddress;
+ public InetAddress getInetAddress() {
+ return inetAddress;
}
public long getLastKeepAlivePayLoad() {
@@ -131,14 +135,10 @@ public class ClientConnection extends Thread {
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
output.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) {}
try {
client_socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) {}
}
public void disconnectDuringLogin(BaseComponent[] reason) {
@@ -148,14 +148,10 @@ public class ClientConnection extends Thread {
DataTypeIO.writeVarInt(output, packetByte.length);
output.write(packetByte);
output.flush();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) {}
try {
client_socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
+ } catch (IOException e) {}
}
@Override
@@ -210,7 +206,7 @@ public class ClientConnection extends Thread {
String ip = data[1];
bungeeUUID = UUID.fromString(data[2].replaceFirst("([0-9a-fA-F]{8})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]{4})([0-9a-fA-F]+)", "$1-$2-$3-$4-$5"));
- iNetAddress = InetAddress.getByName(ip);
+ inetAddress = InetAddress.getByName(ip);
String skinJson = data[3];
@@ -240,7 +236,7 @@ public class ClientConnection extends Thread {
state = ClientState.PLAY;
- player = new Player(this, username, uuid, Limbo.getInstance().entityCount.getAndIncrement(), Limbo.getInstance().getServerProperties().getWorldSpawn());
+ player = new Player(this, username, uuid, Limbo.getInstance().getNextEntityId(), Limbo.getInstance().getServerProperties().getWorldSpawn());
Limbo.getInstance().addPlayer(player);
break;
@@ -248,6 +244,12 @@ public class ClientConnection extends Thread {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
}
}
+
+ PlayerLoginEvent event = (PlayerLoginEvent) Limbo.getInstance().getEventsManager().callEvent(new PlayerLoginEvent(this, false));
+ if (event.isCancelled()) {
+ disconnectDuringLogin(event.getCancelReason());
+ }
+
break;
}
@@ -276,13 +278,6 @@ public class ClientConnection extends Thread {
}
}
- PacketPlayOutSpawnPosition spawnPos = new PacketPlayOutSpawnPosition(BlockPosition.from(s));
- sendPacket(spawnPos);
-
- PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch(), 1);
- player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
- sendPacket(positionLook);
-
SkinResponse skinresponce = isBungeecord ? bungeeSkin : MojangAPIUtils.getSkinFromMojangServer(player.getName());
PlayerSkinProperty skin = skinresponce != null ? new PlayerSkinProperty(skinresponce.getSkin(), skinresponce.getSignature()) : null;
PacketPlayOutPlayerInfo info = new PacketPlayOutPlayerInfo(PlayerInfoAction.ADD_PLAYER, player.getUUID(), new PlayerInfoData.PlayerInfoDataAddPlayer(player.getName(), Optional.ofNullable(skin), p.getDefaultGamemode(), 0, false, Optional.empty()));
@@ -309,15 +304,26 @@ public class ClientConnection extends Thread {
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!");
- PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandPacket();
- sendPacket(declare);
+ PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandsPacket(player);
+ if (declare != null) {
+ sendPacket(declare);
+ }
+
+ Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player));
+
+ PacketPlayOutSpawnPosition spawnPos = new PacketPlayOutSpawnPosition(BlockPosition.from(s));
+ sendPacket(spawnPos);
+
+ PacketPlayOutPositionAndLook positionLook = new PacketPlayOutPositionAndLook(s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch(), 1);
+ player.setLocation(new Location(world, s.getX(), s.getY(), s.getZ(), s.getYaw(), s.getPitch()));
+ sendPacket(positionLook);
while (client_socket.isConnected()) {
try {
int size = DataTypeIO.readVarInt(input);
int packetId = DataTypeIO.readVarInt(input);
Class extends Packet> packetType = Packet.getPlayIn().get(packetId);
- //System.out.println(packetType);
+ //System.out.println(packetId + " -> " + packetType);
if (packetType == null) {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
} else if (packetType.equals(PacketPlayInPositionAndLook.class)) {
@@ -346,24 +352,13 @@ public class ClientConnection extends Thread {
}
} else if (packetType.equals(PacketPlayInTabComplete.class)) {
PacketPlayInTabComplete request = new PacketPlayInTabComplete(input);
- String[] command = CustomStringUtils.splitStringToArgs(request.getText());
- System.out.println(request.getText());
+ String[] command = CustomStringUtils.splitStringToArgs(request.getText().substring(1));
+
List matches = new ArrayList();
- TabCompleteMatches spawn = new TabCompleteMatches("spawn", new TextComponent(ChatColor.GOLD + "Teleports you back to the Limbo spawn!"));
+ matches.addAll(Limbo.getInstance().getPluginManager().getTabOptions(player, command).stream().map(each -> new TabCompleteMatches(each)).collect(Collectors.toList()));
- switch (command.length) {
- case 0:
- matches.add(spawn);
- break;
- case 1:
- if ("spawn".startsWith(command[0])) {
- matches.add(spawn);
- }
- break;
- }
-
- int start = CustomStringUtils.getIndexOfArg(request.getText(), command.length - 1);
+ int start = CustomStringUtils.getIndexOfArg(request.getText(), command.length - 1) + 1;
int length = command[command.length - 1].length();
PacketPlayOutTabComplete response = new PacketPlayOutTabComplete(request.getId(), start, length, matches.toArray(new TabCompleteMatches[matches.size()]));
@@ -371,19 +366,9 @@ public class ClientConnection extends Thread {
} else if (packetType.equals(PacketPlayInChat.class)) {
PacketPlayInChat chat = new PacketPlayInChat(input);
if (chat.getMessage().startsWith("/")) {
- //TO-DO COMMANDS
- String[] command = CustomStringUtils.splitStringToArgs(chat.getMessage().substring(1));
- if (command[0].equalsIgnoreCase("spawn")) {
- player.teleport(p.getWorldSpawn());
- Limbo.getInstance().getConsole().sendMessage(player.getName() + " executed server command: /spawn");
- player.sendMessage(new TextComponent(ChatColor.GOLD + "Teleporting you to spawn!"));
- }
+ Limbo.getInstance().dispatchCommand(player, chat.getMessage());
} else {
- String message = "<" + player.getName() + "> " + chat.getMessage();
- Limbo.getInstance().getConsole().sendMessage(message);
- for (Player each : Limbo.getInstance().getPlayers()) {
- each.sendMessage(message);
- }
+ player.chat(chat.getMessage());
}
} else {
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
@@ -393,8 +378,12 @@ public class ClientConnection extends Thread {
break;
}
}
- str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
- Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had disconnected!");
+
+ Limbo.getInstance().getEventsManager().callEvent(new PlayerQuitEvent(player));
+
+ str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
+ Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had disconnected!");
+
}
} catch (Exception e) {}
@@ -403,6 +392,7 @@ public class ClientConnection extends Thread {
client_socket.close();
} catch (IOException e) {}
state = ClientState.DISCONNECTED;
+
if (player != null) {
Limbo.getInstance().removePlayer(player);
}
diff --git a/src/com/loohp/limbo/Server/Packets/PacketPlayOutTabComplete.java b/src/com/loohp/limbo/Server/Packets/PacketPlayOutTabComplete.java
index 1ebf700..d0fea22 100644
--- a/src/com/loohp/limbo/Server/Packets/PacketPlayOutTabComplete.java
+++ b/src/com/loohp/limbo/Server/Packets/PacketPlayOutTabComplete.java
@@ -22,6 +22,7 @@ public class PacketPlayOutTabComplete extends PacketOut {
this.id = id;
this.start = start;
this.length = length;
+ this.matches = matches;
}
public int getId() {
diff --git a/src/permission.yml b/src/permission.yml
new file mode 100644
index 0000000..88d2981
--- /dev/null
+++ b/src/permission.yml
@@ -0,0 +1,11 @@
+groups:
+ admin:
+ - limboserver.stop
+ - limboserver.kick
+ - limboserver.say
+ default:
+ - limboserver.spawn
+
+players:
+ LOOHP:
+ - admin
\ No newline at end of file