diff --git a/pom.xml b/pom.xml
index 0b08ec8..9deddf1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,7 +24,7 @@
com.loohp
Limbo
Limbo
- 0.7.7-ALPHA
+ 0.7.8-ALPHA
Standalone Limbo Minecraft Server.
https://github.com/LOOHP/Limbo
@@ -260,31 +260,31 @@
net.kyori
adventure-text-serializer-gson
- 4.15.0-SNAPSHOT
+ 4.17.0-SNAPSHOT
compile
net.kyori
adventure-text-serializer-legacy
- 4.15.0-SNAPSHOT
+ 4.17.0-SNAPSHOT
compile
net.kyori
adventure-text-serializer-plain
- 4.15.0-SNAPSHOT
+ 4.17.0-SNAPSHOT
compile
net.kyori
adventure-api
- 4.15.0-SNAPSHOT
+ 4.17.0-SNAPSHOT
compile
net.kyori
adventure-nbt
- 4.15.0-SNAPSHOT
+ 4.17.0-SNAPSHOT
compile
diff --git a/src/main/java/com/loohp/limbo/Limbo.java b/src/main/java/com/loohp/limbo/Limbo.java
index 4ff2524..2c48383 100644
--- a/src/main/java/com/loohp/limbo/Limbo.java
+++ b/src/main/java/com/loohp/limbo/Limbo.java
@@ -98,566 +98,553 @@ import java.util.stream.Collectors;
public final class Limbo {
- public static final String LIMBO_BRAND = "Limbo";
+ public static final String LIMBO_BRAND = "Limbo";
- private static Limbo instance;
- public static boolean noGui = false;
-
- public static void main(String args[]) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
- for (String flag : args) {
- if (flag.equals("--nogui") || flag.equals("nogui")) {
- noGui = true;
- } else if (flag.equals("--help")) {
- System.out.println("Accepted flags:");
- System.out.println(" --nogui <- Disable the GUI");
- System.exit(0);
- } else {
- System.out.println("Unknown flag: \"" + flag + "\". Ignoring...");
- }
- }
- if (GraphicsEnvironment.isHeadless()) {
- noGui = true;
- }
- if (!noGui) {
- System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable");
- Thread t1 = new Thread(() -> {
- try {
- GUI.main();
- } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException |
- IllegalAccessException e) {
- e.printStackTrace();
- }
- });
- t1.start();
- }
-
- new Limbo();
- }
-
- public static Limbo getInstance() {
- return instance;
- }
-
- //===========================
-
- public final String SERVER_IMPLEMENTATION_VERSION = "1.20.4";
- public final int SERVER_IMPLEMENTATION_PROTOCOL = 765;
- public final String LIMBO_IMPLEMENTATION_VERSION;
-
- private final AtomicBoolean isRunning;
-
- private final ServerConnection server;
- private final Console console;
-
- private final List worlds = new CopyOnWriteArrayList<>();
- final Map playersByName = new ConcurrentHashMap<>();
- final Map playersByUUID = new ConcurrentHashMap<>();
- private final Map bossBars = new ConcurrentHashMap<>();
-
- private final ServerProperties properties;
-
- private final PluginManager pluginManager;
- private final EventsManager eventsManager;
- private final PermissionsManager permissionManager;
- private final File pluginFolder;
-
- private final File internalDataFolder;
-
- private final DimensionRegistry dimensionRegistry;
-
- private final Tick tick;
- private final LimboScheduler scheduler;
-
- private final Metrics metrics;
-
- public final AtomicInteger entityIdCount = new AtomicInteger();
-
- @SuppressWarnings("deprecation")
- private Unsafe unsafe;
-
- @SuppressWarnings("unchecked")
- public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
- instance = this;
- unsafe = new Unsafe(this);
- isRunning = new AtomicBoolean(true);
-
- if (!noGui) {
- while (!GUI.loadFinish) {
- TimeUnit.MILLISECONDS.sleep(500);
- }
- console = new Console(null, System.out, System.err);
- } else {
- console = new Console(System.in, System.out, System.err);
- }
-
- LIMBO_IMPLEMENTATION_VERSION = getLimboVersion();
- console.sendMessage("Loading Limbo Version " + LIMBO_IMPLEMENTATION_VERSION + " on Minecraft " + SERVER_IMPLEMENTATION_VERSION);
-
- String spName = "server.properties";
+ private static Limbo instance;
+ public static boolean noGui = false;
+
+ public static void main(String args[]) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
+ for (String flag : args) {
+ if (flag.equals("--nogui") || flag.equals("nogui")) {
+ noGui = true;
+ } else if (flag.equals("--help")) {
+ System.out.println("Accepted flags:");
+ System.out.println(" --nogui <- Disable the GUI");
+ System.exit(0);
+ } else {
+ System.out.println("Unknown flag: \"" + flag + "\". Ignoring...");
+ }
+ }
+ if (GraphicsEnvironment.isHeadless()) {
+ noGui = true;
+ }
+ if (!noGui) {
+ System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable");
+ Thread t1 = new Thread(() -> {
+ try {
+ GUI.main();
+ } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ });
+ t1.start();
+ }
+
+ new Limbo();
+ }
+
+ public static Limbo getInstance() {
+ return instance;
+ }
+
+ //===========================
+
+ public final String SERVER_IMPLEMENTATION_VERSION = "1.20.4";
+ public final int SERVER_IMPLEMENTATION_PROTOCOL = 765;
+ public final String LIMBO_IMPLEMENTATION_VERSION;
+
+ private final AtomicBoolean isRunning;
+
+ private final ServerConnection server;
+ private final Console console;
+
+ private final List worlds = new CopyOnWriteArrayList<>();
+ final Map playersByName = new ConcurrentHashMap<>();
+ final Map playersByUUID = new ConcurrentHashMap<>();
+ private final Map bossBars = new ConcurrentHashMap<>();
+
+ private final ServerProperties properties;
+
+ private final PluginManager pluginManager;
+ private final EventsManager eventsManager;
+ private final PermissionsManager permissionManager;
+ private final File pluginFolder;
+
+ private final DimensionRegistry dimensionRegistry;
+
+ private final Tick tick;
+ private final LimboScheduler scheduler;
+
+ private final Metrics metrics;
+
+ public final AtomicInteger entityIdCount = new AtomicInteger();
+
+ @SuppressWarnings("deprecation")
+ private Unsafe unsafe;
+
+ @SuppressWarnings("unchecked")
+ public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
+ instance = this;
+ unsafe = new Unsafe(this);
+ isRunning = new AtomicBoolean(true);
+
+ if (!noGui) {
+ while (!GUI.loadFinish) {
+ TimeUnit.MILLISECONDS.sleep(500);
+ }
+ console = new Console(null, System.out, System.err);
+ } else {
+ console = new Console(System.in, System.out, System.err);
+ }
+
+ LIMBO_IMPLEMENTATION_VERSION = getLimboVersion();
+ console.sendMessage("Loading Limbo Version " + LIMBO_IMPLEMENTATION_VERSION + " on Minecraft " + SERVER_IMPLEMENTATION_VERSION);
+
+ String spName = "server.properties";
File sp = new File(spName);
if (!sp.exists()) {
- try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) {
+ try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) {
Files.copy(in, sp.toPath());
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace();
}
}
properties = new ServerProperties(sp);
-
+
if (!properties.isBungeecord()) {
- console.sendMessage("If you are using bungeecord, consider turning that on in the settings!");
+ console.sendMessage("If you are using bungeecord, consider turning that on in the settings!");
} else {
- console.sendMessage("Starting Limbo server in bungeecord mode!");
+ console.sendMessage("Starting Limbo server in bungeecord mode!");
}
+
+ String mappingName = "mapping.json";
+ InputStream mappingStream = getClass().getClassLoader().getResourceAsStream(mappingName);
+ if (mappingStream == null) {
+ throw new RuntimeException("Failed to load " + mappingName + " from jar!");
+ }
+
+ console.sendMessage("Loading packet id mappings...");
- internalDataFolder = new File("internal_data");
- if (!internalDataFolder.exists()) {
- internalDataFolder.mkdirs();
- }
-
- console.sendMessage("Loading packet id mappings from mapping.json ...");
-
- InputStream mappingStream = getClass().getClassLoader().getResourceAsStream("mapping.json");
- if (mappingStream == null) {
- console.sendMessage("Failed to load mapping.json from jar!");
- System.exit(1);
- }
-
- InputStreamReader reader = new InputStreamReader(mappingStream, StandardCharsets.UTF_8);
+ InputStreamReader reader = new InputStreamReader(mappingStream, StandardCharsets.UTF_8);
JSONObject json = (JSONObject) new JSONParser().parse(reader);
reader.close();
-
+
String classPrefix = Packet.class.getName().substring(0, Packet.class.getName().lastIndexOf(".") + 1);
int mappingsCount = 0;
+
+ Map> HandshakeIn = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) {
+ int packetId = Integer.decode((String) key);
+ HandshakeIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("HandshakeIn")).get(key)));
+ }
+ Packet.setHandshakeIn(HandshakeIn);
+ mappingsCount += HandshakeIn.size();
+
+ Map> StatusIn = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) {
+ int packetId = Integer.decode((String) key);
+ StatusIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("StatusIn")).get(key)));
+ }
+ Packet.setStatusIn(StatusIn);
+ mappingsCount += StatusIn.size();
+
+ Map, Integer> StatusOut = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) {
+ Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
+ StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key)));
+ }
+ Packet.setStatusOut(StatusOut);
+ mappingsCount += StatusOut.size();
+
+ Map> LoginIn = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) {
+ int packetId = Integer.decode((String) key);
+ LoginIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("LoginIn")).get(key)));
+ }
+ Packet.setLoginIn(LoginIn);
+ mappingsCount += LoginIn.size();
+
+ Map, Integer> LoginOut = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) {
+ Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
+ LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key)));
+ }
+ Packet.setLoginOut(LoginOut);
+ mappingsCount += LoginOut.size();
- Map> HandshakeIn = new HashMap<>();
- for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) {
- int packetId = Integer.decode((String) key);
- HandshakeIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("HandshakeIn")).get(key)));
- }
- Packet.setHandshakeIn(HandshakeIn);
- mappingsCount += HandshakeIn.size();
+ Map> ConfigurationIn = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("ConfigurationIn")).keySet()) {
+ int packetId = Integer.decode((String) key);
+ ConfigurationIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("ConfigurationIn")).get(key)));
+ }
+ Packet.setConfigurationIn(ConfigurationIn);
+ mappingsCount += ConfigurationIn.size();
- Map> StatusIn = new HashMap<>();
- for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) {
- int packetId = Integer.decode((String) key);
- StatusIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("StatusIn")).get(key)));
- }
- Packet.setStatusIn(StatusIn);
- mappingsCount += StatusIn.size();
-
- Map, Integer> StatusOut = new HashMap<>();
- for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) {
- Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
- StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key)));
- }
- Packet.setStatusOut(StatusOut);
- mappingsCount += StatusOut.size();
-
- Map> LoginIn = new HashMap<>();
- for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) {
- int packetId = Integer.decode((String) key);
- LoginIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("LoginIn")).get(key)));
- }
- Packet.setLoginIn(LoginIn);
- mappingsCount += LoginIn.size();
-
- Map, Integer> LoginOut = new HashMap<>();
- for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) {
- Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
- LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key)));
- }
- Packet.setLoginOut(LoginOut);
- mappingsCount += LoginOut.size();
-
- Map> ConfigurationIn = new HashMap<>();
- for (Object key : ((JSONObject) json.get("ConfigurationIn")).keySet()) {
- int packetId = Integer.decode((String) key);
- ConfigurationIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("ConfigurationIn")).get(key)));
- }
- Packet.setConfigurationIn(ConfigurationIn);
- mappingsCount += ConfigurationIn.size();
-
- Map, Integer> ConfigurationOut = new HashMap<>();
- for (Object key : ((JSONObject) json.get("ConfigurationOut")).keySet()) {
- Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
- ConfigurationOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("ConfigurationOut")).get(key)));
- }
- Packet.setConfigurationOut(ConfigurationOut);
- mappingsCount += ConfigurationOut.size();
-
- Map> PlayIn = new HashMap<>();
- for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) {
- int packetId = Integer.decode((String) key);
- PlayIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("PlayIn")).get(key)));
- }
- Packet.setPlayIn(PlayIn);
- mappingsCount += PlayIn.size();
-
- Map, Integer> PlayOut = new HashMap<>();
- for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) {
- Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
- PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key)));
- }
- Packet.setPlayOut(PlayOut);
- mappingsCount += PlayOut.size();
-
- console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!");
-
- dimensionRegistry = new DimensionRegistry();
-
- worlds.add(loadDefaultWorld());
- Location spawn = properties.getWorldSpawn();
- properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().value()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch()));
-
- if (!NetworkUtils.available(properties.getServerPort())) {
- console.sendMessage("");
- console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****");
- console.sendMessage("*****PORT ALREADY IN USE*****");
- console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****");
- console.sendMessage("");
- System.exit(2);
- }
-
- String permissionName = "permission.yml";
+ Map, Integer> ConfigurationOut = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("ConfigurationOut")).keySet()) {
+ Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
+ ConfigurationOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("ConfigurationOut")).get(key)));
+ }
+ Packet.setConfigurationOut(ConfigurationOut);
+ mappingsCount += ConfigurationOut.size();
+
+ Map> PlayIn = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) {
+ int packetId = Integer.decode((String) key);
+ PlayIn.put(packetId, (Class extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("PlayIn")).get(key)));
+ }
+ Packet.setPlayIn(PlayIn);
+ mappingsCount += PlayIn.size();
+
+ Map, Integer> PlayOut = new HashMap<>();
+ for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) {
+ Class extends PacketOut> packetClass = (Class extends PacketOut>) Class.forName(classPrefix + key);
+ PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key)));
+ }
+ Packet.setPlayOut(PlayOut);
+ mappingsCount += PlayOut.size();
+
+ console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!");
+
+ dimensionRegistry = new DimensionRegistry();
+
+ worlds.add(loadDefaultWorld());
+ Location spawn = properties.getWorldSpawn();
+ properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().value()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch()));
+
+ if (!NetworkUtils.available(properties.getServerPort())) {
+ console.sendMessage("");
+ console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****");
+ console.sendMessage("*****PORT ALREADY IN USE*****");
+ console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****");
+ console.sendMessage("");
+ System.exit(2);
+ }
+
+ String permissionName = "permission.yml";
File permissionFile = new File(permissionName);
if (!permissionFile.exists()) {
- try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
+ try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
Files.copy(in, permissionFile.toPath());
} catch (IOException e) {
- e.printStackTrace();
+ e.printStackTrace();
}
}
scheduler = new LimboScheduler();
- tick = new Tick(this);
-
+ tick = new Tick(this);
+
permissionManager = new PermissionsManager();
- permissionManager.loadDefaultPermissionFile(permissionFile);
-
+ permissionManager.loadDefaultPermissionFile(permissionFile);
+
eventsManager = new EventsManager();
-
+
pluginFolder = new File("plugins");
pluginFolder.mkdirs();
+
+ pluginManager = new PluginManager(new DefaultCommands(), pluginFolder);
+ try {
+ Method loadPluginsMethod = PluginManager.class.getDeclaredMethod("loadPlugins");
+ loadPluginsMethod.setAccessible(true);
+ loadPluginsMethod.invoke(pluginManager);
+ loadPluginsMethod.setAccessible(false);
+ } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+ e.printStackTrace();
+ }
+
+ for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
+ try {
+ console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
+ plugin.onEnable();
+ } catch (Throwable e) {
+ new RuntimeException("Error while enabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
+ }
+ }
+
+ server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
+
+ metrics = new Metrics();
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ Limbo.getInstance().terminate();
+ }));
- pluginManager = new PluginManager(new DefaultCommands(), pluginFolder);
- try {
- Method loadPluginsMethod = PluginManager.class.getDeclaredMethod("loadPlugins");
- loadPluginsMethod.setAccessible(true);
- loadPluginsMethod.invoke(pluginManager);
- loadPluginsMethod.setAccessible(false);
- } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException |
- InvocationTargetException e) {
- e.printStackTrace();
- }
+ console.run();
+ }
- for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
- try {
- console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
- plugin.onEnable();
- } catch (Throwable e) {
- new RuntimeException("Error while enabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
- }
- }
+ @Deprecated
+ public Unsafe getUnsafe() {
+ return unsafe;
+ }
+
+ public Tick getHeartBeat() {
+ return tick;
+ }
+
+ public LimboScheduler getScheduler() {
+ return scheduler;
+ }
- server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
+ public DimensionRegistry getDimensionRegistry() {
+ return dimensionRegistry;
+ }
- metrics = new Metrics();
+ public PermissionsManager getPermissionsManager() {
+ return permissionManager;
+ }
- Runtime.getRuntime().addShutdownHook(new Thread(() -> {
- Limbo.getInstance().terminate();
- }));
+ public EventsManager getEventsManager() {
+ return eventsManager;
+ }
+
+ public File getPluginFolder() {
+ return pluginFolder;
+ }
+
+ public PluginManager getPluginManager() {
+ return pluginManager;
+ }
- console.run();
- }
+ private World loadDefaultWorld() throws IOException {
+ console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
+
+ File schem = new File(properties.getSchemFileName());
+
+ if (!schem.exists()) {
+ console.sendMessage("Schemetic file " + properties.getSchemFileName() + " for world " + properties.getLevelName() + " not found!");
+ console.sendMessage("Creating default world...");
+ try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream("spawn.schem")) {
+ Files.copy(in, schem.toPath());
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ try {
+ World world = Schematic.toWorld(properties.getLevelName().value(), Environment.fromKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag());
+ console.sendMessage("Loaded world " + properties.getLevelName() + "!");
+ return world;
+ } catch (Throwable e) {
+ console.sendMessage("Unable to load world " + properties.getSchemFileName() + "!");
+ e.printStackTrace();
+ console.sendMessage("Server will exit!");
+ System.exit(1);
+ return null;
+ }
+ }
+
+ public void registerWorld(World world) {
+ if (!worlds.contains(world)) {
+ worlds.add(world);
+ } else {
+ throw new RuntimeException("World already registered");
+ }
+ }
+
+ public void unregisterWorld(World world) {
+ if (worlds.indexOf(world) == 0) {
+ throw new RuntimeException("World already registered");
+ } else if (!worlds.contains(world)) {
+ throw new RuntimeException("World not registered");
+ } else {
+ for (Player player : world.getPlayers()) {
+ player.teleport(properties.getWorldSpawn());
+ }
+ worlds.remove(world);
+ }
+ }
- @Deprecated
- public Unsafe getUnsafe() {
- return unsafe;
- }
+ public KeyedBossBar createBossBar(Key Key, Component name, float progress, BossBar.Color color, BossBar.Overlay overlay, BossBar.Flag... flags) {
+ KeyedBossBar keyedBossBar = com.loohp.limbo.bossbar.Unsafe.a(Key, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags))));
+ bossBars.put(Key, keyedBossBar);
+ return keyedBossBar;
+ }
- public Tick getHeartBeat() {
- return tick;
- }
+ public void removeBossBar(Key Key) {
+ KeyedBossBar keyedBossBar = bossBars.remove(Key);
+ keyedBossBar.getProperties().removeListener(keyedBossBar.getUnsafe().a());
+ keyedBossBar.getUnsafe().b();
+ PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(keyedBossBar, PacketPlayOutBoss.BossBarAction.REMOVE);
+ for (Player player : keyedBossBar.getPlayers()) {
+ try {
+ player.clientConnection.sendPacket(packetPlayOutBoss);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
- public LimboScheduler getScheduler() {
- return scheduler;
- }
+ public Map getBossBars() {
+ return Collections.unmodifiableMap(bossBars);
+ }
- public DimensionRegistry getDimensionRegistry() {
- return dimensionRegistry;
- }
+ public ServerProperties getServerProperties() {
+ return properties;
+ }
+
+ public ServerConnection getServerConnection() {
+ return server;
+ }
- public PermissionsManager getPermissionsManager() {
- return permissionManager;
- }
+ public Console getConsole() {
+ return console;
+ }
+
+ public Metrics getMetrics() {
+ return metrics;
+ }
- public File getInternalDataFolder() {
- return internalDataFolder;
- }
+ public Set getPlayers() {
+ return new HashSet<>(playersByUUID.values());
+ }
+
+ public Player getPlayer(String name) {
+ return playersByName.get(name);
+ }
+
+ public Player getPlayer(UUID uuid) {
+ return playersByUUID.get(uuid);
+ }
+
+ public List getWorlds() {
+ return new ArrayList<>(worlds);
+ }
+
+ public World getWorld(String name) {
+ for (World world : worlds) {
+ if (world.getName().equalsIgnoreCase(name)) {
+ return world;
+ }
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ public String buildServerListResponseJson(String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
+ JSONObject json = new JSONObject();
- public EventsManager getEventsManager() {
- return eventsManager;
- }
+ JSONObject versionJson = new JSONObject();
+ versionJson.put("name", version);
+ versionJson.put("protocol", protocol);
+ json.put("version", versionJson);
+
+ JSONObject playersJson = new JSONObject();
+ playersJson.put("max", maxPlayers);
+ playersJson.put("online", playersOnline);
+ json.put("players", playersJson);
+
+ json.put("description", "%MOTD%");
+
+ if (favicon != null) {
+ if (favicon.getWidth() == 64 && favicon.getHeight() == 64) {
+ String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png");
+ json.put("favicon", base64);
+ } else {
+ console.sendMessage("Server List Favicon must be 64 x 64 in size!");
+ }
+ }
+
+ JSONObject modInfoJson = new JSONObject();
+ modInfoJson.put("type", "FML");
+ modInfoJson.put("modList", new JSONArray());
+ json.put("modinfo", modInfoJson);
+
+
+ TreeMap treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+ treeMap.putAll(json);
+
+ Gson g = new GsonBuilder().create();
- public File getPluginFolder() {
- return pluginFolder;
- }
+ return g.toJson(treeMap).replace("\"%MOTD%\"", GsonComponentSerializer.gson().serialize(motd));
+ }
+
+ public String buildLegacyPingResponse(String version, Component motd, int maxPlayers, int playersOnline) {
+ String begin = "�1";
+ return String.join("\00", begin, "127", version, String.join("", Arrays.asList(motd).stream().map(each -> LegacyComponentSerializer.legacySection().serialize(each)).collect(Collectors.toList())), String.valueOf(playersOnline), String.valueOf(maxPlayers));
+ }
+
+ protected void terminate() {
+ isRunning.set(false);
+ console.sendMessage("Stopping Server...");
+
+ for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
+ try {
+ console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
+ plugin.onDisable();
+ } catch (Throwable e) {
+ new RuntimeException("Error while disabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
+ }
+ }
+
+ tick.waitAndKillThreads(5000);
+
+ for (Player player : getPlayers()) {
+ player.disconnect("Server closed");
+ }
+ while (!getPlayers().isEmpty()) {
+ try {
+ TimeUnit.MILLISECONDS.sleep(500);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ console.sendMessage("Server closed");
+ console.logs.close();
+ }
+
+ public void stopServer() {
+ System.exit(0);
+ }
+
+ public boolean isRunning() {
+ return isRunning.get();
+ }
+
+ public int getNextEntityId() {
+ return entityIdCount.getAndUpdate(i -> i == Integer.MAX_VALUE ? 0 : ++i);
+ }
+
+ 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();
+ }
+ }
+
+ private String getLimboVersion() throws IOException {
+ Enumeration manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
+ while (manifests.hasMoreElements()) {
+ URL url = manifests.nextElement();
+ try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
+ Optional line = br.lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst();
+ if (line.isPresent()) {
+ return line.get().substring(14).trim();
+ }
+ }
+ }
+ return "Unknown";
+ }
- public PluginManager getPluginManager() {
- return pluginManager;
- }
+ public Inventory createInventory(Component title, int slots, InventoryHolder holder) {
+ return CustomInventory.create(title, slots, holder);
+ }
- private World loadDefaultWorld() throws IOException {
- console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
+ public Inventory createInventory(InventoryType type, InventoryHolder holder) {
+ return createInventory(null, type, holder);
+ }
- File schem = new File(properties.getSchemFileName());
-
- if (!schem.exists()) {
- console.sendMessage("Schemetic file " + properties.getSchemFileName() + " for world " + properties.getLevelName() + " not found!");
- console.sendMessage("Creating default world...");
- try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream("spawn.schem")) {
- Files.copy(in, schem.toPath());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- try {
- World world = Schematic.toWorld(properties.getLevelName().value(), Environment.fromKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag());
- console.sendMessage("Loaded world " + properties.getLevelName() + "!");
- return world;
- } catch (Throwable e) {
- console.sendMessage("Unable to load world " + properties.getSchemFileName() + "!");
- e.printStackTrace();
- console.sendMessage("Server will exit!");
- System.exit(1);
- return null;
- }
- }
-
- public void registerWorld(World world) {
- if (!worlds.contains(world)) {
- worlds.add(world);
- } else {
- throw new RuntimeException("World already registered");
- }
- }
-
- public void unregisterWorld(World world) {
- if (worlds.indexOf(world) == 0) {
- throw new RuntimeException("World already registered");
- } else if (!worlds.contains(world)) {
- throw new RuntimeException("World not registered");
- } else {
- for (Player player : world.getPlayers()) {
- player.teleport(properties.getWorldSpawn());
- }
- worlds.remove(world);
- }
- }
-
- public KeyedBossBar createBossBar(Key Key, Component name, float progress, BossBar.Color color, BossBar.Overlay overlay, BossBar.Flag... flags) {
- KeyedBossBar keyedBossBar = com.loohp.limbo.bossbar.Unsafe.a(Key, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags))));
- bossBars.put(Key, keyedBossBar);
- return keyedBossBar;
- }
-
- public void removeBossBar(Key Key) {
- KeyedBossBar keyedBossBar = bossBars.remove(Key);
- keyedBossBar.getProperties().removeListener(keyedBossBar.getUnsafe().a());
- keyedBossBar.getUnsafe().b();
- PacketPlayOutBoss packetPlayOutBoss = new PacketPlayOutBoss(keyedBossBar, PacketPlayOutBoss.BossBarAction.REMOVE);
- for (Player player : keyedBossBar.getPlayers()) {
- try {
- player.clientConnection.sendPacket(packetPlayOutBoss);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
-
- public Map getBossBars() {
- return Collections.unmodifiableMap(bossBars);
- }
-
- public ServerProperties getServerProperties() {
- return properties;
- }
-
- public ServerConnection getServerConnection() {
- return server;
- }
-
- public Console getConsole() {
- return console;
- }
-
- public Metrics getMetrics() {
- return metrics;
- }
-
- public Set getPlayers() {
- return new HashSet<>(playersByUUID.values());
- }
-
- public Player getPlayer(String name) {
- return playersByName.get(name);
- }
-
- public Player getPlayer(UUID uuid) {
- return playersByUUID.get(uuid);
- }
-
- public List getWorlds() {
- return new ArrayList<>(worlds);
- }
-
- public World getWorld(String name) {
- for (World world : worlds) {
- if (world.getName().equalsIgnoreCase(name)) {
- return world;
- }
- }
- return null;
- }
-
- @SuppressWarnings("unchecked")
- public String buildServerListResponseJson(String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
- JSONObject json = new JSONObject();
-
- JSONObject versionJson = new JSONObject();
- versionJson.put("name", version);
- versionJson.put("protocol", protocol);
- json.put("version", versionJson);
-
- JSONObject playersJson = new JSONObject();
- playersJson.put("max", maxPlayers);
- playersJson.put("online", playersOnline);
- json.put("players", playersJson);
-
- json.put("description", "%MOTD%");
-
- if (favicon != null) {
- if (favicon.getWidth() == 64 && favicon.getHeight() == 64) {
- String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png");
- json.put("favicon", base64);
- } else {
- console.sendMessage("Server List Favicon must be 64 x 64 in size!");
- }
- }
-
- JSONObject modInfoJson = new JSONObject();
- modInfoJson.put("type", "FML");
- modInfoJson.put("modList", new JSONArray());
- json.put("modinfo", modInfoJson);
-
-
- TreeMap treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
- treeMap.putAll(json);
-
- Gson g = new GsonBuilder().create();
-
- return g.toJson(treeMap).replace("\"%MOTD%\"", GsonComponentSerializer.gson().serialize(motd));
- }
-
- public String buildLegacyPingResponse(String version, Component motd, int maxPlayers, int playersOnline) {
- String begin = "�1";
- return String.join("\00", begin, "127", version, String.join("", Arrays.asList(motd).stream().map(each -> LegacyComponentSerializer.legacySection().serialize(each)).collect(Collectors.toList())), String.valueOf(playersOnline), String.valueOf(maxPlayers));
- }
-
- protected void terminate() {
- isRunning.set(false);
- console.sendMessage("Stopping Server...");
-
- for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
- try {
- console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
- plugin.onDisable();
- } catch (Throwable e) {
- new RuntimeException("Error while disabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
- }
- }
-
- tick.waitAndKillThreads(5000);
-
- for (Player player : getPlayers()) {
- player.disconnect("Server closed");
- }
- while (!getPlayers().isEmpty()) {
- try {
- TimeUnit.MILLISECONDS.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- console.sendMessage("Server closed");
- console.logs.close();
- }
-
- public void stopServer() {
- System.exit(0);
- }
-
- public boolean isRunning() {
- return isRunning.get();
- }
-
- public int getNextEntityId() {
- return entityIdCount.getAndUpdate(i -> i == Integer.MAX_VALUE ? 0 : ++i);
- }
-
- 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();
- }
- }
-
- private String getLimboVersion() throws IOException {
- Enumeration manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
- while (manifests.hasMoreElements()) {
- URL url = manifests.nextElement();
- try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
- Optional line = br.lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst();
- if (line.isPresent()) {
- return line.get().substring(14).trim();
- }
- }
- }
- return "Unknown";
- }
-
- public Inventory createInventory(Component title, int slots, InventoryHolder holder) {
- return CustomInventory.create(title, slots, holder);
- }
-
- public Inventory createInventory(InventoryType type, InventoryHolder holder) {
- return createInventory(null, type, holder);
- }
-
- public Inventory createInventory(Component title, InventoryType type, InventoryHolder holder) {
- if (!type.isCreatable()) {
- throw new UnsupportedOperationException("This InventoryType cannot be created.");
- }
- switch (type) {
- case ANVIL:
- return new AnvilInventory(title, holder);
- default:
- throw new UnsupportedOperationException("This InventoryType has not been implemented yet.");
- }
- }
+ public Inventory createInventory(Component title, InventoryType type, InventoryHolder holder) {
+ if (!type.isCreatable()) {
+ throw new UnsupportedOperationException("This InventoryType cannot be created.");
+ }
+ switch (type) {
+ case ANVIL:
+ return new AnvilInventory(title, holder);
+ default:
+ throw new UnsupportedOperationException("This InventoryType has not been implemented yet.");
+ }
+ }
}
diff --git a/src/main/java/com/loohp/limbo/network/ClientConnection.java b/src/main/java/com/loohp/limbo/network/ClientConnection.java
index 62c89e9..485b761 100644
--- a/src/main/java/com/loohp/limbo/network/ClientConnection.java
+++ b/src/main/java/com/loohp/limbo/network/ClientConnection.java
@@ -41,13 +41,61 @@ import com.loohp.limbo.inventory.AnvilInventory;
import com.loohp.limbo.inventory.Inventory;
import com.loohp.limbo.inventory.ItemStack;
import com.loohp.limbo.location.Location;
-import com.loohp.limbo.network.protocol.packets.*;
+import com.loohp.limbo.network.protocol.packets.ClientboundFinishConfigurationPacket;
+import com.loohp.limbo.network.protocol.packets.ClientboundRegistryDataPacket;
+import com.loohp.limbo.network.protocol.packets.Packet;
+import com.loohp.limbo.network.protocol.packets.PacketHandshakingIn;
+import com.loohp.limbo.network.protocol.packets.PacketIn;
+import com.loohp.limbo.network.protocol.packets.PacketLoginInLoginStart;
+import com.loohp.limbo.network.protocol.packets.PacketLoginInPluginMessaging;
+import com.loohp.limbo.network.protocol.packets.PacketLoginOutDisconnect;
+import com.loohp.limbo.network.protocol.packets.PacketLoginOutLoginSuccess;
+import com.loohp.limbo.network.protocol.packets.PacketLoginOutPluginMessaging;
+import com.loohp.limbo.network.protocol.packets.PacketOut;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInBlockDig;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInBlockPlace;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInChat;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInCloseWindow;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInHeldItemChange;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInItemName;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInKeepAlive;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInPickItem;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInPluginMessaging;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInPosition;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInPositionAndLook;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutGameStateChange;
+import com.loohp.limbo.network.protocol.packets.ServerboundResourcePackPacket;
import com.loohp.limbo.network.protocol.packets.ServerboundResourcePackPacket.Action;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInRotation;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInSetCreativeSlot;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInTabComplete;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInUseItem;
+import com.loohp.limbo.network.protocol.packets.PacketPlayInWindowClick;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutDeclareCommands;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutDisconnect;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityMetadata;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutHeldItemChange;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutKeepAlive;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutLogin;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerAbilities;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerAbilities.PlayerAbilityFlags;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerInfo;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerInfo.PlayerInfoAction;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerInfo.PlayerInfoData;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerInfo.PlayerInfoData.PlayerInfoDataAddPlayer.PlayerSkinProperty;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutPluginMessaging;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutPositionAndLook;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutSpawnPosition;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutTabComplete;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutTabComplete.TabCompleteMatches;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutUpdateViewPosition;
+import com.loohp.limbo.network.protocol.packets.PacketStatusInPing;
+import com.loohp.limbo.network.protocol.packets.PacketStatusInRequest;
+import com.loohp.limbo.network.protocol.packets.PacketStatusOutPong;
+import com.loohp.limbo.network.protocol.packets.PacketStatusOutResponse;
+import com.loohp.limbo.network.protocol.packets.ServerboundChatCommandPacket;
+import com.loohp.limbo.network.protocol.packets.ServerboundFinishConfigurationPacket;
+import com.loohp.limbo.network.protocol.packets.ServerboundLoginAcknowledgedPacket;
import com.loohp.limbo.player.Player;
import com.loohp.limbo.player.PlayerInteractManager;
import com.loohp.limbo.player.PlayerInventory;
@@ -565,6 +613,10 @@ public class ClientConnection extends Thread {
String str = (properties.isLogPlayerIPAddresses() ? inetAddress.getHostName() : "") + ":" + clientSocket.getPort() + "|" + player.getName() + "(" + player.getUniqueId() + ")";
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!");
+ PacketPlayOutGameStateChange gameEvent = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.GameStateChangeEvent.LEVEL_CHUNKS_LOAD_START, 0);
+ sendPacket(gameEvent);
+ player.playerInteractManager.update();
+
PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandsPacket(player);
if (declare != null) {
sendPacket(declare);
@@ -584,7 +636,7 @@ public class ClientConnection extends Thread {
Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player));
if (properties.isAllowFlight()) {
- PacketPlayOutGameState state = new PacketPlayOutGameState(3, player.getGamemode().getId());
+ PacketPlayOutGameStateChange state = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.GameStateChangeEvent.CHANGE_GAME_MODE, player.getGamemode().getId());
sendPacket(state);
}
@@ -603,13 +655,8 @@ public class ClientConnection extends Thread {
// PLAYER LIST HEADER AND FOOTER CODE CONRIBUTED BY GAMERDUCK123
player.sendPlayerListHeaderAndFooter(properties.getTabHeader(), properties.getTabFooter());
-
- // Start waiting for level chunks
- PacketPlayOutGameEvent gameEvent = new PacketPlayOutGameEvent((byte) 13, 0);
- sendPacket(gameEvent);
-
+
ready = true;
- player.playerInteractManager.update();
keepAliveTask = new TimerTask() {
@Override
diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameState.java b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameState.java
deleted file mode 100644
index ab61263..0000000
--- a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameState.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * This file is part of Limbo.
- *
- * Copyright (C) 2022. LoohpJames
- * Copyright (C) 2022. Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.loohp.limbo.network.protocol.packets;
-
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
-public class PacketPlayOutGameState extends PacketOut {
-
- private final int reason;
- private final float value;
-
- public PacketPlayOutGameState(int reason, float value) {
- this.reason = reason;
- this.value = value;
- }
-
- public int getReason() {
- return reason;
- }
-
- public float getValue() {
- return value;
- }
-
- @Override
- public byte[] serializePacket() throws IOException {
- ByteArrayOutputStream buffer = new ByteArrayOutputStream();
-
- DataOutputStream output = new DataOutputStream(buffer);
- output.writeByte(Packet.getPlayOut().get(getClass()));
- output.writeByte(reason);
- output.writeFloat(value);
-
- return buffer.toByteArray();
- }
-
-}
diff --git a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameEvent.java b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameStateChange.java
similarity index 55%
rename from src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameEvent.java
rename to src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameStateChange.java
index 276b414..74ab37b 100644
--- a/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameEvent.java
+++ b/src/main/java/com/loohp/limbo/network/protocol/packets/PacketPlayOutGameStateChange.java
@@ -1,8 +1,8 @@
/*
* This file is part of Limbo.
*
- * Copyright (C) 2022. LoohpJames
- * Copyright (C) 2022. Contributors
+ * Copyright (C) 2024. LoohpJames
+ * Copyright (C) 2024. Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -23,17 +23,44 @@ import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
-public class PacketPlayOutGameEvent extends PacketOut {
+public class PacketPlayOutGameStateChange extends PacketOut {
- private byte event;
+ public enum GameStateChangeEvent {
+ NO_RESPAWN_BLOCK_AVAILABLE(0),
+ START_RAINING(1),
+ STOP_RAINING(2),
+ CHANGE_GAME_MODE(3),
+ WIN_GAME(4),
+ DEMO_EVENT(5),
+ ARROW_HIT_PLAYER(6),
+ RAIN_LEVEL_CHANGE(7),
+ THUNDER_LEVEL_CHANGE(8),
+ PUFFER_FISH_STING(9),
+ GUARDIAN_ELDER_EFFECT(10),
+ IMMEDIATE_RESPAWN(11),
+ LIMITED_CRAFTING(12),
+ LEVEL_CHUNKS_LOAD_START(13);
+
+ private final int id;
+
+ GameStateChangeEvent(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return id;
+ }
+ }
+
+ private GameStateChangeEvent event;
private float value;
- public PacketPlayOutGameEvent(byte event, float value) {
+ public PacketPlayOutGameStateChange(GameStateChangeEvent event, float value) {
this.event = event;
this.value = value;
}
- public int getEvent() {
+ public GameStateChangeEvent getEvent() {
return event;
}
@@ -46,7 +73,7 @@ public class PacketPlayOutGameEvent extends PacketOut {
DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass()));
- output.writeByte(Byte.toUnsignedInt(event));
+ output.writeByte(event.getId());
output.writeFloat(value);
return buffer.toByteArray();
diff --git a/src/main/java/com/loohp/limbo/player/Player.java b/src/main/java/com/loohp/limbo/player/Player.java
index ce2a1c8..804e33a 100644
--- a/src/main/java/com/loohp/limbo/player/Player.java
+++ b/src/main/java/com/loohp/limbo/player/Player.java
@@ -45,7 +45,7 @@ import com.loohp.limbo.network.protocol.packets.ClientboundSetTitlesAnimationPac
import com.loohp.limbo.network.protocol.packets.ClientboundSystemChatPacket;
import com.loohp.limbo.network.protocol.packets.PacketOut;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutCloseWindow;
-import com.loohp.limbo.network.protocol.packets.PacketPlayOutGameState;
+import com.loohp.limbo.network.protocol.packets.PacketPlayOutGameStateChange;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutHeldItemChange;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutNamedSoundEffect;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutOpenWindow;
@@ -151,7 +151,7 @@ public class Player extends LivingEntity implements CommandSender, InventoryHold
public void setGamemode(GameMode gamemode) {
if (!this.gamemode.equals(gamemode)) {
try {
- PacketPlayOutGameState state = new PacketPlayOutGameState(3, gamemode.getId());
+ PacketPlayOutGameStateChange state = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.GameStateChangeEvent.CHANGE_GAME_MODE, gamemode.getId());
clientConnection.sendPacket(state);
} catch (IOException e) {
e.printStackTrace();
diff --git a/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java b/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java
index 9497770..9c57313 100644
--- a/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java
+++ b/src/main/java/com/loohp/limbo/player/PlayerInteractManager.java
@@ -30,7 +30,6 @@ import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityDestroy;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutEntityMetadata;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutSpawnEntity;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutUnloadChunk;
-import com.loohp.limbo.utils.GameMode;
import com.loohp.limbo.world.ChunkPosition;
import com.loohp.limbo.world.World;
import net.querz.mca.Chunk;
@@ -47,131 +46,118 @@ import java.util.Set;
import java.util.stream.Collectors;
public class PlayerInteractManager {
+
+ private Player player;
+
+ private Set entities;
+ private Map currentViewing;
+
+ public PlayerInteractManager() {
+ this.player = null;
+ this.entities = new HashSet<>();
+ this.currentViewing = new HashMap<>();
+ }
+
+ protected void setPlayer(Player player) {
+ if (this.player == null) {
+ this.player = player;
+ } else {
+ throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created");
+ }
+ }
+
+ public Player getPlayer() {
+ return player;
+ }
- private Player player;
+ public void update() throws IOException {
+ if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY) {
+ return;
+ }
- private Set entities;
- private Map currentViewing;
- private final Map chunkUpdates;
+ int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance();
+ int viewDistanceBlocks = viewDistanceChunks << 4;
+ Location location = player.getLocation();
+ Set entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet());
+ for (Entity entity : entitiesInRange) {
+ if (!entities.contains(entity)) {
+ PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch(), entity.getPitch(), 0, (short) 0, (short) 0, (short) 0);
+ player.clientConnection.sendPacket(packet);
- public PlayerInteractManager() {
- this.player = null;
- this.entities = new HashSet<>();
- this.currentViewing = new HashMap<>();
- this.chunkUpdates = new HashMap<>();
- }
+ PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity);
+ player.clientConnection.sendPacket(meta);
+ }
+ }
+ List ids = new ArrayList<>();
+ for (Entity entity : entities) {
+ if (!entitiesInRange.contains(entity)) {
+ ids.add(entity.getEntityId());
+ }
+ }
+ for (int id : ids) {
+ PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id);
+ player.clientConnection.sendPacket(packet);
+ }
- protected void setPlayer(Player player) {
- if (this.player == null) {
- this.player = player;
- } else {
- throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created");
- }
- }
+ entities = entitiesInRange;
- public Player getPlayer() {
- return player;
- }
+ int playerChunkX = (int) location.getX() >> 4;
+ int playerChunkZ = (int) location.getZ() >> 4;
+ World world = location.getWorld();
- public void update() throws IOException {
- if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY && !player.clientConnection.isReady()) {
- return;
- }
+ Map chunksInRange = new HashMap<>();
- int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance();
- int viewDistanceBlocks = viewDistanceChunks << 4;
- Location location = player.getLocation();
- Set entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet());
- for (Entity entity : entitiesInRange) {
- if (!entities.contains(entity)) {
- PacketPlayOutSpawnEntity packet = new PacketPlayOutSpawnEntity(entity.getEntityId(), entity.getUniqueId(), entity.getType(), entity.getX(), entity.getY(), entity.getZ(), entity.getYaw(), entity.getPitch(), entity.getPitch(), 0, (short) 0, (short) 0, (short) 0);
- player.clientConnection.sendPacket(packet);
+ for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) {
+ for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) {
+ Chunk chunk = world.getChunkAt(x, z);
+ if (chunk != null) {
+ chunksInRange.put(new ChunkPosition(world, x, z), chunk);
+ } else {
+ chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK);
+ }
+ }
+ }
- PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity);
- player.clientConnection.sendPacket(meta);
- }
- }
- List ids = new ArrayList<>();
- for (Entity entity : entities) {
- if (!entitiesInRange.contains(entity)) {
- ids.add(entity.getEntityId());
- }
- }
- for (int id : ids) {
- PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id);
- player.clientConnection.sendPacket(packet);
- }
+ for (Entry entry : currentViewing.entrySet()) {
+ ChunkPosition chunkPos = entry.getKey();
+ if (!chunksInRange.containsKey(chunkPos)) {
+ PacketPlayOutUnloadChunk packet = new PacketPlayOutUnloadChunk(chunkPos.getChunkX(), chunkPos.getChunkZ());
+ player.clientConnection.sendPacket(packet);
+ }
+ }
- entities = entitiesInRange;
-
- int playerChunkX = (int) location.getX() >> 4;
- int playerChunkZ = (int) location.getZ() >> 4;
- World world = location.getWorld();
-
- Map chunksInRange = new HashMap<>();
-
- for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) {
- for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) {
- Chunk chunk = world.getChunkAt(x, z);
- if (chunk != null) {
- chunksInRange.put(new ChunkPosition(world, x, z), chunk);
+ int counter = 0;
+ ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket();
+ player.clientConnection.sendPacket(chunkBatchStartPacket);
+ for (Entry entry : chunksInRange.entrySet()) {
+ ChunkPosition chunkPos = entry.getKey();
+ if (!currentViewing.containsKey(chunkPos)) {
+ Chunk chunk = chunkPos.getWorld().getChunkAt(chunkPos.getChunkX(), chunkPos.getChunkZ());
+ if (chunk == null) {
+ ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), entry.getValue(), world.getEnvironment(), Collections.emptyList(), Collections.emptyList());
+ player.clientConnection.sendPacket(chunkdata);
} else {
- chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK);
+ List blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
+ if (blockChunk == null) {
+ blockChunk = new ArrayList<>();
+ }
+ List skyChunk = null;
+ if (world.hasSkyLight()) {
+ skyChunk = world.getLightEngineSky().getSkyLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
+ }
+ if (skyChunk == null) {
+ skyChunk = new ArrayList<>();
+ }
+ ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), chunk, world.getEnvironment(), skyChunk, blockChunk);
+ player.clientConnection.sendPacket(chunkdata);
}
+ counter++;
}
- }
+ }
+ ClientboundChunkBatchFinishedPacket chunkBatchFinishedPacket = new ClientboundChunkBatchFinishedPacket(counter);
+ player.clientConnection.sendPacket(chunkBatchFinishedPacket);
- for (ChunkPosition chunkPos : currentViewing.keySet()) {
- if (!chunksInRange.containsKey(chunkPos)) {
- PacketPlayOutUnloadChunk packet = new PacketPlayOutUnloadChunk(chunkPos.getChunkX(), chunkPos.getChunkZ());
- player.clientConnection.sendPacket(packet);
- }
- }
-
- // add chunk candidates for updating
- chunkUpdates.clear();
- chunkUpdates.putAll(chunksInRange);
-
- // blocks cannot be broken, so once we've sent all of them, don't update them anymore
- if (getPlayer().getGamemode() == GameMode.ADVENTURE) {
- for (ChunkPosition chunkPos : currentViewing.keySet()) {
- chunkUpdates.remove(chunkPos);
- }
- }
-
- // if we don't have any chunk updates, don't send any packets
- if (chunkUpdates.isEmpty()) return;
-
- int counter = 0;
- ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket();
- player.clientConnection.sendPacket(chunkBatchStartPacket);
- for (Entry entry : chunkUpdates.entrySet()) {
- ChunkPosition chunkPos = entry.getKey();
- Chunk chunk = chunkPos.getWorld().getChunkAt(chunkPos.getChunkX(), chunkPos.getChunkZ());
- if (chunk == null) {
- ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), entry.getValue(), world.getEnvironment(), Collections.emptyList(), Collections.emptyList());
- player.clientConnection.sendPacket(chunkdata);
- } else {
- List blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
- if (blockChunk == null) {
- blockChunk = new ArrayList<>();
- }
- List skyChunk = null;
- if (world.hasSkyLight()) {
- skyChunk = world.getLightEngineSky().getSkyLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
- }
- if (skyChunk == null) {
- skyChunk = new ArrayList<>();
- }
- ClientboundLevelChunkWithLightPacket chunkdata = new ClientboundLevelChunkWithLightPacket(chunkPos.getChunkX(), chunkPos.getChunkZ(), chunk, world.getEnvironment(), skyChunk, blockChunk);
- player.clientConnection.sendPacket(chunkdata);
- }
- counter++;
- }
- ClientboundChunkBatchFinishedPacket chunkBatchFinishedPacket = new ClientboundChunkBatchFinishedPacket(counter);
- player.clientConnection.sendPacket(chunkBatchFinishedPacket);
-
- currentViewing = chunksInRange;
- }
+ currentViewing = chunksInRange;
+ }
}
diff --git a/src/main/java/com/loohp/limbo/registry/Registry.java b/src/main/java/com/loohp/limbo/registry/Registry.java
index a9086e5..72dab8a 100644
--- a/src/main/java/com/loohp/limbo/registry/Registry.java
+++ b/src/main/java/com/loohp/limbo/registry/Registry.java
@@ -48,20 +48,17 @@ public class Registry {
static {
String name = "registries.json";
- File file = new File(Limbo.getInstance().getInternalDataFolder(), name);
- if (!file.exists()) {
- try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(name)) {
- Files.copy(in, file.toPath());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
Map blockEntityType = new HashMap<>();
Key defaultItemKey = null;
BiMap itemIds = HashBiMap.create();
Map menuIds = new HashMap<>();
- try (InputStreamReader reader = new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)) {
+
+ InputStream inputStream = Limbo.class.getClassLoader().getResourceAsStream(name);
+ if (inputStream == null) {
+ throw new RuntimeException("Failed to load " + name + " from jar!");
+ }
+ try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
JSONObject json = (JSONObject) new JSONParser().parse(reader);
JSONObject blockEntityJson = (JSONObject) ((JSONObject) json.get("minecraft:block_entity_type")).get("entries");
diff --git a/src/main/java/com/loohp/limbo/world/DimensionRegistry.java b/src/main/java/com/loohp/limbo/world/DimensionRegistry.java
index 323bf7e..c1480a6 100644
--- a/src/main/java/com/loohp/limbo/world/DimensionRegistry.java
+++ b/src/main/java/com/loohp/limbo/world/DimensionRegistry.java
@@ -37,24 +37,16 @@ public class DimensionRegistry {
private CompoundTag defaultTag;
private CompoundTag codec;
- private File reg;
public DimensionRegistry() {
this.defaultTag = new CompoundTag();
-
String name = "dimension_registry.json";
- File file = new File(Limbo.getInstance().getInternalDataFolder(), name);
- if (!file.exists()) {
- try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(name)) {
- Files.copy(in, file.toPath());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- this.reg = file;
-
- try (InputStreamReader reader = new InputStreamReader(Files.newInputStream(reg.toPath()), StandardCharsets.UTF_8)) {
+
+ InputStream inputStream = Limbo.class.getClassLoader().getResourceAsStream(name);
+ if (inputStream == null) {
+ throw new RuntimeException("Failed to load " + name + " from jar!");
+ }
+ try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
JSONObject json = (JSONObject) new JSONParser().parse(reader);
CompoundTag tag = CustomNBTUtils.getCompoundTagFromJson((JSONObject) json.get("value"));
defaultTag = tag;
@@ -64,10 +56,6 @@ public class DimensionRegistry {
}
}
- public File getFile() {
- return reg;
- }
-
public void resetCodec() {
codec = defaultTag.clone();
}
diff --git a/src/main/java/com/loohp/limbo/world/GeneratedBlockDataMappings.java b/src/main/java/com/loohp/limbo/world/GeneratedBlockDataMappings.java
index 4375327..e9dd234 100644
--- a/src/main/java/com/loohp/limbo/world/GeneratedBlockDataMappings.java
+++ b/src/main/java/com/loohp/limbo/world/GeneratedBlockDataMappings.java
@@ -30,6 +30,8 @@ import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
@@ -41,17 +43,12 @@ public class GeneratedBlockDataMappings {
static {
String block = "blocks.json";
- File file = new File(Limbo.getInstance().getInternalDataFolder(), block);
- if (!file.exists()) {
- try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(block)) {
- Files.copy(in, file.toPath());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
-
- try {
- globalPalette = (JSONObject) new JSONParser().parse(new FileReader(file));
+ InputStream inputStream = Limbo.class.getClassLoader().getResourceAsStream(block);
+ if (inputStream == null) {
+ throw new RuntimeException("Failed to load " + block + " from jar!");
+ }
+ try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
+ globalPalette = (JSONObject) new JSONParser().parse(reader);
} catch (IOException | ParseException e) {
e.printStackTrace();
}
diff --git a/src/main/resources/mapping.json b/src/main/resources/mapping.json
index a9c649a..365a148 100644
--- a/src/main/resources/mapping.json
+++ b/src/main/resources/mapping.json
@@ -43,12 +43,12 @@
"PacketPlayOutLogin": "0x29",
"PacketPlayOutPositionAndLook": "0x3E",
"PacketPlayOutSpawnPosition": "0x54",
- "PacketPlayOutGameEvent": "0x20",
"ClientboundSystemChatPacket": "0x69",
"PacketPlayOutPlayerAbilities": "0x36",
"ClientboundLevelChunkWithLightPacket": "0x25",
"PacketPlayOutUnloadChunk": "0x1F",
"PacketPlayOutKeepAlive": "0x15",
+ "PacketPlayOutGameStateChange": "0x20",
"PacketPlayOutPlayerInfo": "0x3C",
"PacketPlayOutUpdateViewPosition": "0x52",
"PacketPlayOutDisconnect": "0x1B",
@@ -56,7 +56,6 @@
"PacketPlayOutTabComplete": "0x10",
"PacketPlayOutDeclareCommands": "0x11",
"PacketPlayOutRespawn": "0x45",
- "PacketPlayOutGameState": "0x20",
"PacketPlayOutEntityDestroy": "0x40",
"PacketPlayOutEntityMetadata": "0x56",
"PacketPlayOutSpawnEntity": "0x01",
@@ -87,4 +86,4 @@
"PacketStatusOutResponse": "0x00",
"PacketStatusOutPong": "0x01"
}
-}
+}
\ No newline at end of file