Clean up & Format

This commit is contained in:
LOOHP 2024-03-25 22:03:24 +00:00
parent 01d2a3e528
commit 8ec7d322d8
11 changed files with 720 additions and 748 deletions

12
pom.xml
View File

@ -24,7 +24,7 @@
<groupId>com.loohp</groupId> <groupId>com.loohp</groupId>
<artifactId>Limbo</artifactId> <artifactId>Limbo</artifactId>
<name>Limbo</name> <name>Limbo</name>
<version>0.7.7-ALPHA</version> <version>0.7.8-ALPHA</version>
<description>Standalone Limbo Minecraft Server.</description> <description>Standalone Limbo Minecraft Server.</description>
<url>https://github.com/LOOHP/Limbo</url> <url>https://github.com/LOOHP/Limbo</url>
@ -260,31 +260,31 @@
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-gson</artifactId> <artifactId>adventure-text-serializer-gson</artifactId>
<version>4.15.0-SNAPSHOT</version> <version>4.17.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-legacy</artifactId> <artifactId>adventure-text-serializer-legacy</artifactId>
<version>4.15.0-SNAPSHOT</version> <version>4.17.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-text-serializer-plain</artifactId> <artifactId>adventure-text-serializer-plain</artifactId>
<version>4.15.0-SNAPSHOT</version> <version>4.17.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-api</artifactId> <artifactId>adventure-api</artifactId>
<version>4.15.0-SNAPSHOT</version> <version>4.17.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>net.kyori</groupId> <groupId>net.kyori</groupId>
<artifactId>adventure-nbt</artifactId> <artifactId>adventure-nbt</artifactId>
<version>4.15.0-SNAPSHOT</version> <version>4.17.0-SNAPSHOT</version>
<scope>compile</scope> <scope>compile</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@ -98,239 +98,231 @@ import java.util.stream.Collectors;
public final class Limbo { public final class Limbo {
public static final String LIMBO_BRAND = "Limbo"; public static final String LIMBO_BRAND = "Limbo";
private static Limbo instance; private static Limbo instance;
public static boolean noGui = false; public static boolean noGui = false;
public static void main(String args[]) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException { public static void main(String args[]) throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
for (String flag : args) { for (String flag : args) {
if (flag.equals("--nogui") || flag.equals("nogui")) { if (flag.equals("--nogui") || flag.equals("nogui")) {
noGui = true; noGui = true;
} else if (flag.equals("--help")) { } else if (flag.equals("--help")) {
System.out.println("Accepted flags:"); System.out.println("Accepted flags:");
System.out.println(" --nogui <- Disable the GUI"); System.out.println(" --nogui <- Disable the GUI");
System.exit(0); System.exit(0);
} else { } else {
System.out.println("Unknown flag: \"" + flag + "\". Ignoring..."); System.out.println("Unknown flag: \"" + flag + "\". Ignoring...");
} }
} }
if (GraphicsEnvironment.isHeadless()) { if (GraphicsEnvironment.isHeadless()) {
noGui = true; noGui = true;
} }
if (!noGui) { if (!noGui) {
System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable"); System.out.println("Launching Server GUI.. Add \"--nogui\" in launch arguments to disable");
Thread t1 = new Thread(() -> { Thread t1 = new Thread(() -> {
try { try {
GUI.main(); GUI.main();
} catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | } catch (UnsupportedLookAndFeelException | ClassNotFoundException | InstantiationException | IllegalAccessException e) {
IllegalAccessException e) { e.printStackTrace();
e.printStackTrace(); }
} });
}); t1.start();
t1.start(); }
}
new Limbo(); new Limbo();
} }
public static Limbo getInstance() { public static Limbo getInstance() {
return instance; return instance;
} }
//=========================== //===========================
public final String SERVER_IMPLEMENTATION_VERSION = "1.20.4"; public final String SERVER_IMPLEMENTATION_VERSION = "1.20.4";
public final int SERVER_IMPLEMENTATION_PROTOCOL = 765; public final int SERVER_IMPLEMENTATION_PROTOCOL = 765;
public final String LIMBO_IMPLEMENTATION_VERSION; public final String LIMBO_IMPLEMENTATION_VERSION;
private final AtomicBoolean isRunning; private final AtomicBoolean isRunning;
private final ServerConnection server; private final ServerConnection server;
private final Console console; private final Console console;
private final List<World> worlds = new CopyOnWriteArrayList<>(); private final List<World> worlds = new CopyOnWriteArrayList<>();
final Map<String, Player> playersByName = new ConcurrentHashMap<>(); final Map<String, Player> playersByName = new ConcurrentHashMap<>();
final Map<UUID, Player> playersByUUID = new ConcurrentHashMap<>(); final Map<UUID, Player> playersByUUID = new ConcurrentHashMap<>();
private final Map<Key, KeyedBossBar> bossBars = new ConcurrentHashMap<>(); private final Map<Key, KeyedBossBar> bossBars = new ConcurrentHashMap<>();
private final ServerProperties properties; private final ServerProperties properties;
private final PluginManager pluginManager; private final PluginManager pluginManager;
private final EventsManager eventsManager; private final EventsManager eventsManager;
private final PermissionsManager permissionManager; private final PermissionsManager permissionManager;
private final File pluginFolder; private final File pluginFolder;
private final File internalDataFolder; private final DimensionRegistry dimensionRegistry;
private final DimensionRegistry dimensionRegistry; private final Tick tick;
private final LimboScheduler scheduler;
private final Tick tick; private final Metrics metrics;
private final LimboScheduler scheduler;
private final Metrics metrics; public final AtomicInteger entityIdCount = new AtomicInteger();
public final AtomicInteger entityIdCount = new AtomicInteger(); @SuppressWarnings("deprecation")
private Unsafe unsafe;
@SuppressWarnings("deprecation") @SuppressWarnings("unchecked")
private Unsafe unsafe; public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException {
instance = this;
unsafe = new Unsafe(this);
isRunning = new AtomicBoolean(true);
@SuppressWarnings("unchecked") if (!noGui) {
public Limbo() throws IOException, ParseException, NumberFormatException, ClassNotFoundException, InterruptedException { while (!GUI.loadFinish) {
instance = this; TimeUnit.MILLISECONDS.sleep(500);
unsafe = new Unsafe(this); }
isRunning = new AtomicBoolean(true); console = new Console(null, System.out, System.err);
} else {
console = new Console(System.in, System.out, System.err);
}
if (!noGui) { LIMBO_IMPLEMENTATION_VERSION = getLimboVersion();
while (!GUI.loadFinish) { console.sendMessage("Loading Limbo Version " + LIMBO_IMPLEMENTATION_VERSION + " on Minecraft " + SERVER_IMPLEMENTATION_VERSION);
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(); String spName = "server.properties";
console.sendMessage("Loading Limbo Version " + LIMBO_IMPLEMENTATION_VERSION + " on Minecraft " + SERVER_IMPLEMENTATION_VERSION);
String spName = "server.properties";
File sp = new File(spName); File sp = new File(spName);
if (!sp.exists()) { if (!sp.exists()) {
try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) { try (InputStream in = getClass().getClassLoader().getResourceAsStream(spName)) {
Files.copy(in, sp.toPath()); Files.copy(in, sp.toPath());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
properties = new ServerProperties(sp); properties = new ServerProperties(sp);
if (!properties.isBungeecord()) { 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 { } else {
console.sendMessage("Starting Limbo server in bungeecord mode!"); console.sendMessage("Starting Limbo server in bungeecord mode!");
} }
internalDataFolder = new File("internal_data"); String mappingName = "mapping.json";
if (!internalDataFolder.exists()) { InputStream mappingStream = getClass().getClassLoader().getResourceAsStream(mappingName);
internalDataFolder.mkdirs(); if (mappingStream == null) {
} throw new RuntimeException("Failed to load " + mappingName + " from jar!");
}
console.sendMessage("Loading packet id mappings from mapping.json ..."); console.sendMessage("Loading packet id mappings...");
InputStream mappingStream = getClass().getClassLoader().getResourceAsStream("mapping.json"); InputStreamReader reader = new InputStreamReader(mappingStream, StandardCharsets.UTF_8);
if (mappingStream == null) {
console.sendMessage("Failed to load mapping.json from jar!");
System.exit(1);
}
InputStreamReader reader = new InputStreamReader(mappingStream, StandardCharsets.UTF_8);
JSONObject json = (JSONObject) new JSONParser().parse(reader); JSONObject json = (JSONObject) new JSONParser().parse(reader);
reader.close(); reader.close();
String classPrefix = Packet.class.getName().substring(0, Packet.class.getName().lastIndexOf(".") + 1); String classPrefix = Packet.class.getName().substring(0, Packet.class.getName().lastIndexOf(".") + 1);
int mappingsCount = 0; int mappingsCount = 0;
Map<Integer, Class<? extends PacketIn>> HandshakeIn = new HashMap<>(); Map<Integer, Class<? extends PacketIn>> HandshakeIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) { for (Object key : ((JSONObject) json.get("HandshakeIn")).keySet()) {
int packetId = Integer.decode((String) key); int packetId = Integer.decode((String) key);
HandshakeIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("HandshakeIn")).get(key))); HandshakeIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("HandshakeIn")).get(key)));
} }
Packet.setHandshakeIn(HandshakeIn); Packet.setHandshakeIn(HandshakeIn);
mappingsCount += HandshakeIn.size(); mappingsCount += HandshakeIn.size();
Map<Integer, Class<? extends PacketIn>> StatusIn = new HashMap<>(); Map<Integer, Class<? extends PacketIn>> StatusIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) { for (Object key : ((JSONObject) json.get("StatusIn")).keySet()) {
int packetId = Integer.decode((String) key); int packetId = Integer.decode((String) key);
StatusIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("StatusIn")).get(key))); StatusIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("StatusIn")).get(key)));
} }
Packet.setStatusIn(StatusIn); Packet.setStatusIn(StatusIn);
mappingsCount += StatusIn.size(); mappingsCount += StatusIn.size();
Map<Class<? extends PacketOut>, Integer> StatusOut = new HashMap<>(); Map<Class<? extends PacketOut>, Integer> StatusOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) { for (Object key : ((JSONObject) json.get("StatusOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key); Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key))); StatusOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("StatusOut")).get(key)));
} }
Packet.setStatusOut(StatusOut); Packet.setStatusOut(StatusOut);
mappingsCount += StatusOut.size(); mappingsCount += StatusOut.size();
Map<Integer, Class<? extends PacketIn>> LoginIn = new HashMap<>(); Map<Integer, Class<? extends PacketIn>> LoginIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) { for (Object key : ((JSONObject) json.get("LoginIn")).keySet()) {
int packetId = Integer.decode((String) key); int packetId = Integer.decode((String) key);
LoginIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("LoginIn")).get(key))); LoginIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("LoginIn")).get(key)));
} }
Packet.setLoginIn(LoginIn); Packet.setLoginIn(LoginIn);
mappingsCount += LoginIn.size(); mappingsCount += LoginIn.size();
Map<Class<? extends PacketOut>, Integer> LoginOut = new HashMap<>(); Map<Class<? extends PacketOut>, Integer> LoginOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) { for (Object key : ((JSONObject) json.get("LoginOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key); Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key))); LoginOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("LoginOut")).get(key)));
} }
Packet.setLoginOut(LoginOut); Packet.setLoginOut(LoginOut);
mappingsCount += LoginOut.size(); mappingsCount += LoginOut.size();
Map<Integer, Class<? extends PacketIn>> ConfigurationIn = new HashMap<>(); Map<Integer, Class<? extends PacketIn>> ConfigurationIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("ConfigurationIn")).keySet()) { for (Object key : ((JSONObject) json.get("ConfigurationIn")).keySet()) {
int packetId = Integer.decode((String) key); int packetId = Integer.decode((String) key);
ConfigurationIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("ConfigurationIn")).get(key))); ConfigurationIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("ConfigurationIn")).get(key)));
} }
Packet.setConfigurationIn(ConfigurationIn); Packet.setConfigurationIn(ConfigurationIn);
mappingsCount += ConfigurationIn.size(); mappingsCount += ConfigurationIn.size();
Map<Class<? extends PacketOut>, Integer> ConfigurationOut = new HashMap<>(); Map<Class<? extends PacketOut>, Integer> ConfigurationOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("ConfigurationOut")).keySet()) { for (Object key : ((JSONObject) json.get("ConfigurationOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key); Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
ConfigurationOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("ConfigurationOut")).get(key))); ConfigurationOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("ConfigurationOut")).get(key)));
} }
Packet.setConfigurationOut(ConfigurationOut); Packet.setConfigurationOut(ConfigurationOut);
mappingsCount += ConfigurationOut.size(); mappingsCount += ConfigurationOut.size();
Map<Integer, Class<? extends PacketIn>> PlayIn = new HashMap<>(); Map<Integer, Class<? extends PacketIn>> PlayIn = new HashMap<>();
for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) { for (Object key : ((JSONObject) json.get("PlayIn")).keySet()) {
int packetId = Integer.decode((String) key); int packetId = Integer.decode((String) key);
PlayIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("PlayIn")).get(key))); PlayIn.put(packetId, (Class<? extends PacketIn>) Class.forName(classPrefix + ((JSONObject) json.get("PlayIn")).get(key)));
} }
Packet.setPlayIn(PlayIn); Packet.setPlayIn(PlayIn);
mappingsCount += PlayIn.size(); mappingsCount += PlayIn.size();
Map<Class<? extends PacketOut>, Integer> PlayOut = new HashMap<>(); Map<Class<? extends PacketOut>, Integer> PlayOut = new HashMap<>();
for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) { for (Object key : ((JSONObject) json.get("PlayOut")).keySet()) {
Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key); Class<? extends PacketOut> packetClass = (Class<? extends PacketOut>) Class.forName(classPrefix + key);
PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key))); PlayOut.put(packetClass, Integer.decode((String) ((JSONObject) json.get("PlayOut")).get(key)));
} }
Packet.setPlayOut(PlayOut); Packet.setPlayOut(PlayOut);
mappingsCount += PlayOut.size(); mappingsCount += PlayOut.size();
console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!"); console.sendMessage("Loaded all " + mappingsCount + " packet id mappings!");
dimensionRegistry = new DimensionRegistry(); dimensionRegistry = new DimensionRegistry();
worlds.add(loadDefaultWorld()); worlds.add(loadDefaultWorld());
Location spawn = properties.getWorldSpawn(); Location spawn = properties.getWorldSpawn();
properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().value()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch())); properties.setWorldSpawn(new Location(getWorld(properties.getLevelName().value()), spawn.getX(), spawn.getY(), spawn.getZ(), spawn.getYaw(), spawn.getPitch()));
if (!NetworkUtils.available(properties.getServerPort())) { if (!NetworkUtils.available(properties.getServerPort())) {
console.sendMessage(""); console.sendMessage("");
console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****"); console.sendMessage("*****FAILED TO BIND PORT [" + properties.getServerPort() + "]*****");
console.sendMessage("*****PORT ALREADY IN USE*****"); console.sendMessage("*****PORT ALREADY IN USE*****");
console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****"); console.sendMessage("*****PERHAPS ANOTHER INSTANCE OF THE SERVER IS ALREADY RUNNING?*****");
console.sendMessage(""); console.sendMessage("");
System.exit(2); System.exit(2);
} }
String permissionName = "permission.yml"; String permissionName = "permission.yml";
File permissionFile = new File(permissionName); File permissionFile = new File(permissionName);
if (!permissionFile.exists()) { if (!permissionFile.exists()) {
try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) { try (InputStream in = getClass().getClassLoader().getResourceAsStream(permissionName)) {
Files.copy(in, permissionFile.toPath()); Files.copy(in, permissionFile.toPath());
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
scheduler = new LimboScheduler(); scheduler = new LimboScheduler();
tick = new Tick(this); tick = new Tick(this);
permissionManager = new PermissionsManager(); permissionManager = new PermissionsManager();
permissionManager.loadDefaultPermissionFile(permissionFile); permissionManager.loadDefaultPermissionFile(permissionFile);
@ -340,324 +332,319 @@ public final class Limbo {
pluginFolder = new File("plugins"); pluginFolder = new File("plugins");
pluginFolder.mkdirs(); pluginFolder.mkdirs();
pluginManager = new PluginManager(new DefaultCommands(), pluginFolder); pluginManager = new PluginManager(new DefaultCommands(), pluginFolder);
try { try {
Method loadPluginsMethod = PluginManager.class.getDeclaredMethod("loadPlugins"); Method loadPluginsMethod = PluginManager.class.getDeclaredMethod("loadPlugins");
loadPluginsMethod.setAccessible(true); loadPluginsMethod.setAccessible(true);
loadPluginsMethod.invoke(pluginManager); loadPluginsMethod.invoke(pluginManager);
loadPluginsMethod.setAccessible(false); loadPluginsMethod.setAccessible(false);
} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
InvocationTargetException e) { e.printStackTrace();
e.printStackTrace(); }
}
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) { for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
try { try {
console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion()); console.sendMessage("Enabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
plugin.onEnable(); plugin.onEnable();
} catch (Throwable e) { } catch (Throwable e) {
new RuntimeException("Error while enabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace(); new RuntimeException("Error while enabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
} }
} }
server = new ServerConnection(properties.getServerIp(), properties.getServerPort()); server = new ServerConnection(properties.getServerIp(), properties.getServerPort());
metrics = new Metrics(); metrics = new Metrics();
Runtime.getRuntime().addShutdownHook(new Thread(() -> { Runtime.getRuntime().addShutdownHook(new Thread(() -> {
Limbo.getInstance().terminate(); Limbo.getInstance().terminate();
})); }));
console.run(); console.run();
} }
@Deprecated @Deprecated
public Unsafe getUnsafe() { public Unsafe getUnsafe() {
return unsafe; return unsafe;
} }
public Tick getHeartBeat() { public Tick getHeartBeat() {
return tick; return tick;
} }
public LimboScheduler getScheduler() { public LimboScheduler getScheduler() {
return scheduler; return scheduler;
} }
public DimensionRegistry getDimensionRegistry() { public DimensionRegistry getDimensionRegistry() {
return dimensionRegistry; return dimensionRegistry;
} }
public PermissionsManager getPermissionsManager() { public PermissionsManager getPermissionsManager() {
return permissionManager; return permissionManager;
} }
public File getInternalDataFolder() { public EventsManager getEventsManager() {
return internalDataFolder; return eventsManager;
} }
public EventsManager getEventsManager() { public File getPluginFolder() {
return eventsManager; return pluginFolder;
} }
public File getPluginFolder() { public PluginManager getPluginManager() {
return pluginFolder; return pluginManager;
} }
public PluginManager getPluginManager() { private World loadDefaultWorld() throws IOException {
return pluginManager; console.sendMessage("Loading world " + properties.getLevelName() + " with the schematic file " + properties.getSchemFileName() + " ...");
}
private World loadDefaultWorld() throws IOException { File schem = new File(properties.getSchemFileName());
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();
}
}
if (!schem.exists()) { try {
console.sendMessage("Schemetic file " + properties.getSchemFileName() + " for world " + properties.getLevelName() + " not found!"); World world = Schematic.toWorld(properties.getLevelName().value(), Environment.fromKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag());
console.sendMessage("Creating default world..."); console.sendMessage("Loaded world " + properties.getLevelName() + "!");
try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream("spawn.schem")) { return world;
Files.copy(in, schem.toPath()); } catch (Throwable e) {
} catch (IOException e) { console.sendMessage("Unable to load world " + properties.getSchemFileName() + "!");
e.printStackTrace(); e.printStackTrace();
} console.sendMessage("Server will exit!");
} System.exit(1);
return null;
}
}
try { public void registerWorld(World world) {
World world = Schematic.toWorld(properties.getLevelName().value(), Environment.fromKey(properties.getLevelDimension()), (CompoundTag) NBTUtil.read(schem).getTag()); if (!worlds.contains(world)) {
console.sendMessage("Loaded world " + properties.getLevelName() + "!"); worlds.add(world);
return world; } else {
} catch (Throwable e) { throw new RuntimeException("World already registered");
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) { public void unregisterWorld(World world) {
if (!worlds.contains(world)) { if (worlds.indexOf(world) == 0) {
worlds.add(world); throw new RuntimeException("World already registered");
} else { } else if (!worlds.contains(world)) {
throw new RuntimeException("World already registered"); throw new RuntimeException("World not registered");
} } else {
} for (Player player : world.getPlayers()) {
player.teleport(properties.getWorldSpawn());
}
worlds.remove(world);
}
}
public void unregisterWorld(World world) { public KeyedBossBar createBossBar(Key Key, Component name, float progress, BossBar.Color color, BossBar.Overlay overlay, BossBar.Flag... flags) {
if (worlds.indexOf(world) == 0) { KeyedBossBar keyedBossBar = com.loohp.limbo.bossbar.Unsafe.a(Key, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags))));
throw new RuntimeException("World already registered"); bossBars.put(Key, keyedBossBar);
} else if (!worlds.contains(world)) { return keyedBossBar;
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) { public void removeBossBar(Key Key) {
KeyedBossBar keyedBossBar = com.loohp.limbo.bossbar.Unsafe.a(Key, BossBar.bossBar(name, progress, color, overlay, new HashSet<>(Arrays.asList(flags)))); KeyedBossBar keyedBossBar = bossBars.remove(Key);
bossBars.put(Key, keyedBossBar); keyedBossBar.getProperties().removeListener(keyedBossBar.getUnsafe().a());
return keyedBossBar; 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 void removeBossBar(Key Key) { public Map<Key, KeyedBossBar> getBossBars() {
KeyedBossBar keyedBossBar = bossBars.remove(Key); return Collections.unmodifiableMap(bossBars);
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<Key, KeyedBossBar> getBossBars() { public ServerProperties getServerProperties() {
return Collections.unmodifiableMap(bossBars); return properties;
} }
public ServerProperties getServerProperties() { public ServerConnection getServerConnection() {
return properties; return server;
} }
public ServerConnection getServerConnection() { public Console getConsole() {
return server; return console;
} }
public Console getConsole() { public Metrics getMetrics() {
return console; return metrics;
} }
public Metrics getMetrics() { public Set<Player> getPlayers() {
return metrics; return new HashSet<>(playersByUUID.values());
} }
public Set<Player> getPlayers() { public Player getPlayer(String name) {
return new HashSet<>(playersByUUID.values()); return playersByName.get(name);
} }
public Player getPlayer(String name) { public Player getPlayer(UUID uuid) {
return playersByName.get(name); return playersByUUID.get(uuid);
} }
public Player getPlayer(UUID uuid) { public List<World> getWorlds() {
return playersByUUID.get(uuid); return new ArrayList<>(worlds);
} }
public List<World> getWorlds() { public World getWorld(String name) {
return new ArrayList<>(worlds); for (World world : worlds) {
} if (world.getName().equalsIgnoreCase(name)) {
return world;
}
}
return null;
}
public World getWorld(String name) { @SuppressWarnings("unchecked")
for (World world : worlds) { public String buildServerListResponseJson(String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
if (world.getName().equalsIgnoreCase(name)) { JSONObject json = new JSONObject();
return world;
}
}
return null;
}
@SuppressWarnings("unchecked") JSONObject versionJson = new JSONObject();
public String buildServerListResponseJson(String version, int protocol, Component motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException { versionJson.put("name", version);
JSONObject json = new JSONObject(); versionJson.put("protocol", protocol);
json.put("version", versionJson);
JSONObject versionJson = new JSONObject(); JSONObject playersJson = new JSONObject();
versionJson.put("name", version); playersJson.put("max", maxPlayers);
versionJson.put("protocol", protocol); playersJson.put("online", playersOnline);
json.put("version", versionJson); json.put("players", playersJson);
JSONObject playersJson = new JSONObject(); json.put("description", "%MOTD%");
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!");
}
}
if (favicon != null) { JSONObject modInfoJson = new JSONObject();
if (favicon.getWidth() == 64 && favicon.getHeight() == 64) { modInfoJson.put("type", "FML");
String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png"); modInfoJson.put("modList", new JSONArray());
json.put("favicon", base64); json.put("modinfo", modInfoJson);
} 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<String, Object> treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER); TreeMap<String, Object> treeMap = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
treeMap.putAll(json); treeMap.putAll(json);
Gson g = new GsonBuilder().create(); Gson g = new GsonBuilder().create();
return g.toJson(treeMap).replace("\"%MOTD%\"", GsonComponentSerializer.gson().serialize(motd)); return g.toJson(treeMap).replace("\"%MOTD%\"", GsonComponentSerializer.gson().serialize(motd));
} }
public String buildLegacyPingResponse(String version, Component motd, int maxPlayers, int playersOnline) { public String buildLegacyPingResponse(String version, Component motd, int maxPlayers, int playersOnline) {
String begin = "<EFBFBD>1"; String begin = "<EFBFBD>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)); 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() { protected void terminate() {
isRunning.set(false); isRunning.set(false);
console.sendMessage("Stopping Server..."); console.sendMessage("Stopping Server...");
for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) { for (LimboPlugin plugin : Limbo.getInstance().getPluginManager().getPlugins()) {
try { try {
console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion()); console.sendMessage("Disabling plugin " + plugin.getName() + " " + plugin.getInfo().getVersion());
plugin.onDisable(); plugin.onDisable();
} catch (Throwable e) { } catch (Throwable e) {
new RuntimeException("Error while disabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace(); new RuntimeException("Error while disabling " + plugin.getName() + " " + plugin.getInfo().getVersion(), e).printStackTrace();
} }
} }
tick.waitAndKillThreads(5000); tick.waitAndKillThreads(5000);
for (Player player : getPlayers()) { for (Player player : getPlayers()) {
player.disconnect("Server closed"); player.disconnect("Server closed");
} }
while (!getPlayers().isEmpty()) { while (!getPlayers().isEmpty()) {
try { try {
TimeUnit.MILLISECONDS.sleep(500); TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
console.sendMessage("Server closed"); console.sendMessage("Server closed");
console.logs.close(); console.logs.close();
} }
public void stopServer() { public void stopServer() {
System.exit(0); System.exit(0);
} }
public boolean isRunning() { public boolean isRunning() {
return isRunning.get(); return isRunning.get();
} }
public int getNextEntityId() { public int getNextEntityId() {
return entityIdCount.getAndUpdate(i -> i == Integer.MAX_VALUE ? 0 : ++i); return entityIdCount.getAndUpdate(i -> i == Integer.MAX_VALUE ? 0 : ++i);
} }
public void dispatchCommand(CommandSender sender, String str) { public void dispatchCommand(CommandSender sender, String str) {
String[] command; String[] command;
if (str.startsWith("/")) { if (str.startsWith("/")) {
command = CustomStringUtils.splitStringToArgs(str.substring(1)); command = CustomStringUtils.splitStringToArgs(str.substring(1));
} else { } else {
command = CustomStringUtils.splitStringToArgs(str); command = CustomStringUtils.splitStringToArgs(str);
} }
dispatchCommand(sender, command); dispatchCommand(sender, command);
} }
public void dispatchCommand(CommandSender sender, String... args) { public void dispatchCommand(CommandSender sender, String... args) {
try { try {
Limbo.getInstance().getPluginManager().fireExecutors(sender, args); Limbo.getInstance().getPluginManager().fireExecutors(sender, args);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private String getLimboVersion() throws IOException { private String getLimboVersion() throws IOException {
Enumeration<URL> manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF"); Enumeration<URL> manifests = getClass().getClassLoader().getResources("META-INF/MANIFEST.MF");
while (manifests.hasMoreElements()) { while (manifests.hasMoreElements()) {
URL url = manifests.nextElement(); URL url = manifests.nextElement();
try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) { try (BufferedReader br = new BufferedReader(new InputStreamReader(url.openStream()))) {
Optional<String> line = br.lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst(); Optional<String> line = br.lines().filter(each -> each.startsWith("Limbo-Version:")).findFirst();
if (line.isPresent()) { if (line.isPresent()) {
return line.get().substring(14).trim(); return line.get().substring(14).trim();
} }
} }
} }
return "Unknown"; return "Unknown";
} }
public Inventory createInventory(Component title, int slots, InventoryHolder holder) { public Inventory createInventory(Component title, int slots, InventoryHolder holder) {
return CustomInventory.create(title, slots, holder); return CustomInventory.create(title, slots, holder);
} }
public Inventory createInventory(InventoryType type, InventoryHolder holder) { public Inventory createInventory(InventoryType type, InventoryHolder holder) {
return createInventory(null, type, holder); return createInventory(null, type, holder);
} }
public Inventory createInventory(Component title, InventoryType type, InventoryHolder holder) { public Inventory createInventory(Component title, InventoryType type, InventoryHolder holder) {
if (!type.isCreatable()) { if (!type.isCreatable()) {
throw new UnsupportedOperationException("This InventoryType cannot be created."); throw new UnsupportedOperationException("This InventoryType cannot be created.");
} }
switch (type) { switch (type) {
case ANVIL: case ANVIL:
return new AnvilInventory(title, holder); return new AnvilInventory(title, holder);
default: default:
throw new UnsupportedOperationException("This InventoryType has not been implemented yet."); throw new UnsupportedOperationException("This InventoryType has not been implemented yet.");
} }
} }
} }

View File

@ -41,13 +41,61 @@ import com.loohp.limbo.inventory.AnvilInventory;
import com.loohp.limbo.inventory.Inventory; import com.loohp.limbo.inventory.Inventory;
import com.loohp.limbo.inventory.ItemStack; import com.loohp.limbo.inventory.ItemStack;
import com.loohp.limbo.location.Location; 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.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.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.PlayerInfoAction;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutPlayerInfo.PlayerInfoData; 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.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.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.Player;
import com.loohp.limbo.player.PlayerInteractManager; import com.loohp.limbo.player.PlayerInteractManager;
import com.loohp.limbo.player.PlayerInventory; import com.loohp.limbo.player.PlayerInventory;
@ -565,6 +613,10 @@ public class ClientConnection extends Thread {
String str = (properties.isLogPlayerIPAddresses() ? inetAddress.getHostName() : "<ip address withheld>") + ":" + clientSocket.getPort() + "|" + player.getName() + "(" + player.getUniqueId() + ")"; String str = (properties.isLogPlayerIPAddresses() ? inetAddress.getHostName() : "<ip address withheld>") + ":" + clientSocket.getPort() + "|" + player.getName() + "(" + player.getUniqueId() + ")";
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!"); 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); PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandsPacket(player);
if (declare != null) { if (declare != null) {
sendPacket(declare); sendPacket(declare);
@ -584,7 +636,7 @@ public class ClientConnection extends Thread {
Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player)); Limbo.getInstance().getEventsManager().callEvent(new PlayerJoinEvent(player));
if (properties.isAllowFlight()) { 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); sendPacket(state);
} }
@ -604,12 +656,7 @@ public class ClientConnection extends Thread {
// PLAYER LIST HEADER AND FOOTER CODE CONRIBUTED BY GAMERDUCK123 // PLAYER LIST HEADER AND FOOTER CODE CONRIBUTED BY GAMERDUCK123
player.sendPlayerListHeaderAndFooter(properties.getTabHeader(), properties.getTabFooter()); player.sendPlayerListHeaderAndFooter(properties.getTabHeader(), properties.getTabFooter());
// Start waiting for level chunks
PacketPlayOutGameEvent gameEvent = new PacketPlayOutGameEvent((byte) 13, 0);
sendPacket(gameEvent);
ready = true; ready = true;
player.playerInteractManager.update();
keepAliveTask = new TimerTask() { keepAliveTask = new TimerTask() {
@Override @Override

View File

@ -1,56 +0,0 @@
/*
* This file is part of Limbo.
*
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com>
* 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();
}
}

View File

@ -1,8 +1,8 @@
/* /*
* This file is part of Limbo. * This file is part of Limbo.
* *
* Copyright (C) 2022. LoohpJames <jamesloohp@gmail.com> * Copyright (C) 2024. LoohpJames <jamesloohp@gmail.com>
* Copyright (C) 2022. Contributors * Copyright (C) 2024. Contributors
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with 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.DataOutputStream;
import java.io.IOException; 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; private float value;
public PacketPlayOutGameEvent(byte event, float value) { public PacketPlayOutGameStateChange(GameStateChangeEvent event, float value) {
this.event = event; this.event = event;
this.value = value; this.value = value;
} }
public int getEvent() { public GameStateChangeEvent getEvent() {
return event; return event;
} }
@ -46,7 +73,7 @@ public class PacketPlayOutGameEvent extends PacketOut {
DataOutputStream output = new DataOutputStream(buffer); DataOutputStream output = new DataOutputStream(buffer);
output.writeByte(Packet.getPlayOut().get(getClass())); output.writeByte(Packet.getPlayOut().get(getClass()));
output.writeByte(Byte.toUnsignedInt(event)); output.writeByte(event.getId());
output.writeFloat(value); output.writeFloat(value);
return buffer.toByteArray(); return buffer.toByteArray();

View File

@ -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.ClientboundSystemChatPacket;
import com.loohp.limbo.network.protocol.packets.PacketOut; import com.loohp.limbo.network.protocol.packets.PacketOut;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutCloseWindow; 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.PacketPlayOutHeldItemChange;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutNamedSoundEffect; import com.loohp.limbo.network.protocol.packets.PacketPlayOutNamedSoundEffect;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutOpenWindow; 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) { public void setGamemode(GameMode gamemode) {
if (!this.gamemode.equals(gamemode)) { if (!this.gamemode.equals(gamemode)) {
try { try {
PacketPlayOutGameState state = new PacketPlayOutGameState(3, gamemode.getId()); PacketPlayOutGameStateChange state = new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.GameStateChangeEvent.CHANGE_GAME_MODE, gamemode.getId());
clientConnection.sendPacket(state); clientConnection.sendPacket(state);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -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.PacketPlayOutEntityMetadata;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutSpawnEntity; import com.loohp.limbo.network.protocol.packets.PacketPlayOutSpawnEntity;
import com.loohp.limbo.network.protocol.packets.PacketPlayOutUnloadChunk; 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.ChunkPosition;
import com.loohp.limbo.world.World; import com.loohp.limbo.world.World;
import net.querz.mca.Chunk; import net.querz.mca.Chunk;
@ -48,130 +47,117 @@ import java.util.stream.Collectors;
public class PlayerInteractManager { public class PlayerInteractManager {
private Player player; private Player player;
private Set<Entity> entities; private Set<Entity> entities;
private Map<ChunkPosition, Chunk> currentViewing; private Map<ChunkPosition, Chunk> currentViewing;
private final Map<ChunkPosition, Chunk> chunkUpdates;
public PlayerInteractManager() { public PlayerInteractManager() {
this.player = null; this.player = null;
this.entities = new HashSet<>(); this.entities = new HashSet<>();
this.currentViewing = new HashMap<>(); this.currentViewing = new HashMap<>();
this.chunkUpdates = new HashMap<>(); }
}
protected void setPlayer(Player player) { protected void setPlayer(Player player) {
if (this.player == null) { if (this.player == null) {
this.player = player; this.player = player;
} else { } else {
throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created"); throw new RuntimeException("Player in PlayerInteractManager cannot be changed once created");
} }
} }
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
public void update() throws IOException { public void update() throws IOException {
if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY && !player.clientConnection.isReady()) { if (player.clientConnection.getClientState() != ClientConnection.ClientState.PLAY) {
return; return;
} }
int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance(); int viewDistanceChunks = Limbo.getInstance().getServerProperties().getViewDistance();
int viewDistanceBlocks = viewDistanceChunks << 4; int viewDistanceBlocks = viewDistanceChunks << 4;
Location location = player.getLocation(); Location location = player.getLocation();
Set<Entity> entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet()); Set<Entity> entitiesInRange = player.getWorld().getEntities().stream().filter(each -> each.getLocation().distanceSquared(location) < viewDistanceBlocks * viewDistanceBlocks).collect(Collectors.toSet());
for (Entity entity : entitiesInRange) { for (Entity entity : entitiesInRange) {
if (!entities.contains(entity)) { 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); 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); player.clientConnection.sendPacket(packet);
PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity); PacketPlayOutEntityMetadata meta = new PacketPlayOutEntityMetadata(entity);
player.clientConnection.sendPacket(meta); player.clientConnection.sendPacket(meta);
} }
} }
List<Integer> ids = new ArrayList<>(); List<Integer> ids = new ArrayList<>();
for (Entity entity : entities) { for (Entity entity : entities) {
if (!entitiesInRange.contains(entity)) { if (!entitiesInRange.contains(entity)) {
ids.add(entity.getEntityId()); ids.add(entity.getEntityId());
} }
} }
for (int id : ids) { for (int id : ids) {
PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id); PacketPlayOutEntityDestroy packet = new PacketPlayOutEntityDestroy(id);
player.clientConnection.sendPacket(packet); player.clientConnection.sendPacket(packet);
} }
entities = entitiesInRange; entities = entitiesInRange;
int playerChunkX = (int) location.getX() >> 4; int playerChunkX = (int) location.getX() >> 4;
int playerChunkZ = (int) location.getZ() >> 4; int playerChunkZ = (int) location.getZ() >> 4;
World world = location.getWorld(); World world = location.getWorld();
Map<ChunkPosition, Chunk> chunksInRange = new HashMap<>(); Map<ChunkPosition, Chunk> chunksInRange = new HashMap<>();
for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) { for (int x = playerChunkX - viewDistanceChunks; x < playerChunkX + viewDistanceChunks; x++) {
for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) { for (int z = playerChunkZ - viewDistanceChunks; z < playerChunkZ + viewDistanceChunks; z++) {
Chunk chunk = world.getChunkAt(x, z); Chunk chunk = world.getChunkAt(x, z);
if (chunk != null) { if (chunk != null) {
chunksInRange.put(new ChunkPosition(world, x, z), chunk); chunksInRange.put(new ChunkPosition(world, x, z), chunk);
} else {
chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK);
}
}
}
for (Entry<ChunkPosition, Chunk> entry : currentViewing.entrySet()) {
ChunkPosition chunkPos = entry.getKey();
if (!chunksInRange.containsKey(chunkPos)) {
PacketPlayOutUnloadChunk packet = new PacketPlayOutUnloadChunk(chunkPos.getChunkX(), chunkPos.getChunkZ());
player.clientConnection.sendPacket(packet);
}
}
int counter = 0;
ClientboundChunkBatchStartPacket chunkBatchStartPacket = new ClientboundChunkBatchStartPacket();
player.clientConnection.sendPacket(chunkBatchStartPacket);
for (Entry<ChunkPosition, Chunk> 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 { } else {
chunksInRange.put(new ChunkPosition(world, x, z), World.EMPTY_CHUNK); List<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
if (blockChunk == null) {
blockChunk = new ArrayList<>();
}
List<Byte[]> 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()) { currentViewing = chunksInRange;
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<ChunkPosition, Chunk> 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<Byte[]> blockChunk = world.getLightEngineBlock().getBlockLightBitMask(chunkPos.getChunkX(), chunkPos.getChunkZ());
if (blockChunk == null) {
blockChunk = new ArrayList<>();
}
List<Byte[]> 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;
}
} }

View File

@ -48,20 +48,17 @@ public class Registry {
static { static {
String name = "registries.json"; 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<Key, Integer> blockEntityType = new HashMap<>(); Map<Key, Integer> blockEntityType = new HashMap<>();
Key defaultItemKey = null; Key defaultItemKey = null;
BiMap<Key, Integer> itemIds = HashBiMap.create(); BiMap<Key, Integer> itemIds = HashBiMap.create();
Map<Key, Integer> menuIds = new HashMap<>(); Map<Key, Integer> 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 json = (JSONObject) new JSONParser().parse(reader);
JSONObject blockEntityJson = (JSONObject) ((JSONObject) json.get("minecraft:block_entity_type")).get("entries"); JSONObject blockEntityJson = (JSONObject) ((JSONObject) json.get("minecraft:block_entity_type")).get("entries");

View File

@ -37,24 +37,16 @@ public class DimensionRegistry {
private CompoundTag defaultTag; private CompoundTag defaultTag;
private CompoundTag codec; private CompoundTag codec;
private File reg;
public DimensionRegistry() { public DimensionRegistry() {
this.defaultTag = new CompoundTag(); this.defaultTag = new CompoundTag();
String name = "dimension_registry.json"; 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; InputStream inputStream = Limbo.class.getClassLoader().getResourceAsStream(name);
if (inputStream == null) {
try (InputStreamReader reader = new InputStreamReader(Files.newInputStream(reg.toPath()), StandardCharsets.UTF_8)) { 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 json = (JSONObject) new JSONParser().parse(reader);
CompoundTag tag = CustomNBTUtils.getCompoundTagFromJson((JSONObject) json.get("value")); CompoundTag tag = CustomNBTUtils.getCompoundTagFromJson((JSONObject) json.get("value"));
defaultTag = tag; defaultTag = tag;
@ -64,10 +56,6 @@ public class DimensionRegistry {
} }
} }
public File getFile() {
return reg;
}
public void resetCodec() { public void resetCodec() {
codec = defaultTag.clone(); codec = defaultTag.clone();
} }

View File

@ -30,6 +30,8 @@ import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -41,17 +43,12 @@ public class GeneratedBlockDataMappings {
static { static {
String block = "blocks.json"; String block = "blocks.json";
File file = new File(Limbo.getInstance().getInternalDataFolder(), block); InputStream inputStream = Limbo.class.getClassLoader().getResourceAsStream(block);
if (!file.exists()) { if (inputStream == null) {
try (InputStream in = Limbo.class.getClassLoader().getResourceAsStream(block)) { throw new RuntimeException("Failed to load " + block + " from jar!");
Files.copy(in, file.toPath()); }
} catch (IOException e) { try (InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) {
e.printStackTrace(); globalPalette = (JSONObject) new JSONParser().parse(reader);
}
}
try {
globalPalette = (JSONObject) new JSONParser().parse(new FileReader(file));
} catch (IOException | ParseException e) { } catch (IOException | ParseException e) {
e.printStackTrace(); e.printStackTrace();
} }

View File

@ -43,12 +43,12 @@
"PacketPlayOutLogin": "0x29", "PacketPlayOutLogin": "0x29",
"PacketPlayOutPositionAndLook": "0x3E", "PacketPlayOutPositionAndLook": "0x3E",
"PacketPlayOutSpawnPosition": "0x54", "PacketPlayOutSpawnPosition": "0x54",
"PacketPlayOutGameEvent": "0x20",
"ClientboundSystemChatPacket": "0x69", "ClientboundSystemChatPacket": "0x69",
"PacketPlayOutPlayerAbilities": "0x36", "PacketPlayOutPlayerAbilities": "0x36",
"ClientboundLevelChunkWithLightPacket": "0x25", "ClientboundLevelChunkWithLightPacket": "0x25",
"PacketPlayOutUnloadChunk": "0x1F", "PacketPlayOutUnloadChunk": "0x1F",
"PacketPlayOutKeepAlive": "0x15", "PacketPlayOutKeepAlive": "0x15",
"PacketPlayOutGameStateChange": "0x20",
"PacketPlayOutPlayerInfo": "0x3C", "PacketPlayOutPlayerInfo": "0x3C",
"PacketPlayOutUpdateViewPosition": "0x52", "PacketPlayOutUpdateViewPosition": "0x52",
"PacketPlayOutDisconnect": "0x1B", "PacketPlayOutDisconnect": "0x1B",
@ -56,7 +56,6 @@
"PacketPlayOutTabComplete": "0x10", "PacketPlayOutTabComplete": "0x10",
"PacketPlayOutDeclareCommands": "0x11", "PacketPlayOutDeclareCommands": "0x11",
"PacketPlayOutRespawn": "0x45", "PacketPlayOutRespawn": "0x45",
"PacketPlayOutGameState": "0x20",
"PacketPlayOutEntityDestroy": "0x40", "PacketPlayOutEntityDestroy": "0x40",
"PacketPlayOutEntityMetadata": "0x56", "PacketPlayOutEntityMetadata": "0x56",
"PacketPlayOutSpawnEntity": "0x01", "PacketPlayOutSpawnEntity": "0x01",