Added Events, Commands and Plugins

This commit is contained in:
LOOHP 2020-08-07 22:26:00 +08:00
parent 94bb1e4e45
commit 3c85ef439f
29 changed files with 965 additions and 168 deletions

View File

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/classes" path="src">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Limbo</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

BIN
modules/LimboDefaultCmd.jar Normal file

Binary file not shown.

View File

@ -0,0 +1,7 @@
package com.loohp.limbo.Commands;
public interface CommandExecutor {
public void execute(CommandSender sender, String[] args);
}

View File

@ -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();
}

View File

@ -0,0 +1,9 @@
package com.loohp.limbo.Commands;
import java.util.List;
public interface TabCompletor {
public List<String> tabComplete(CommandSender sender, String[] args);
}

View File

@ -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);
}
}

View File

@ -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<String> 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);

View File

@ -0,0 +1,9 @@
package com.loohp.limbo.Events;
public interface Cancellable {
public void setCancelled(boolean cancelled);
public boolean isCancelled();
}

View File

@ -0,0 +1,5 @@
package com.loohp.limbo.Events;
public abstract class Event {
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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<ListenerPair> 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;
}
}
}

View File

@ -0,0 +1,5 @@
package com.loohp.limbo.Events;
public interface Listener {
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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<String, Object> 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<String, Object>) 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;

View File

@ -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();
}
}
}

View File

@ -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<String, List<String>> users;
private Map<String, List<String>> 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<String> 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<String> 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<String, List<String>> getUsers() {
return users;
}
public Map<String, List<String>> getPermissions() {
return permissions;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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<String, LimboPlugin> plugins;
private List<Executor> 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<LimboPlugin> 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<String> getTabOptions(CommandSender sender, String[] args) throws Exception {
List<String> 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<TabCompletor> 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();
}
}
}
}

View File

@ -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<TabCompleteMatches> matches = new ArrayList<TabCompleteMatches>();
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);
}

View File

@ -22,6 +22,7 @@ public class PacketPlayOutTabComplete extends PacketOut {
this.id = id;
this.start = start;
this.length = length;
this.matches = matches;
}
public int getId() {

11
src/permission.yml Normal file
View File

@ -0,0 +1,11 @@
groups:
admin:
- limboserver.stop
- limboserver.kick
- limboserver.say
default:
- limboserver.spawn
players:
LOOHP:
- admin