From 698762e379412ff62691d3cec11a94c553ca1bf4 Mon Sep 17 00:00:00 2001 From: Redstonneur1256 Date: Sun, 19 May 2024 21:42:03 +0200 Subject: [PATCH] v1.6 --- .github/workflows/validate-gradle-wrapper.yml | 10 ++ .../examplemod/ExampleKeyBinds.java | 1 + .../redstonneur1256/examplemod/MainMod.java | 8 +- .../examplemod/net/CustomCallExample.java | 26 +-- .../packet/direct/CustomPacketExample.java | 15 -- .../modlib/launcher/ModLibLauncher.java | 2 + .../modlib/launcher/mixins/VarsMixin.java | 24 ++- .../modlib/launcher/util/ArcSettings.java | 1 - Mod/build.gradle.kts | 2 +- Mod/src/fr/redstonneur1256/modlib/ModLib.java | 6 + .../net/server/ServerListPingEvent.java | 27 +-- .../modlib/key/KeyBindManager.java | 5 +- .../modlib/launcher/LauncherInitializer.java | 6 +- .../modlib/mixins/arc/EventsMixin.java | 31 ---- .../modlib/mixins/arc/TimerMixin.java | 24 --- .../modlib/mixins/entity/PlayerMixin.java | 3 +- .../modlib/mixins/gen/SoundsMixin.java | 6 +- .../modlib/mixins/net/NetMixin.java | 37 +--- .../mixins/net/arc/ArcConnectionMixin.java | 10 +- .../net/arc/ArcPacketSerializerMixin.java | 14 +- .../mixins/net/packets/StreamBeginMixin.java | 14 +- .../net/packets/StreamBuilderMixin.java | 7 +- .../modlib/mixins/ui/JoinDialogMixin.java | 51 ------ .../modlib/mixins/ui/KeyBindDialogMixin.java | 2 +- .../modlib/mixins/ui/ModsDialogMixin.java | 15 +- .../fr/redstonneur1256/modlib/net/MNet.java | 15 +- .../modlib/net/ServerPing.java | 78 -------- .../modlib/net/call/CallClass.java | 6 +- .../modlib/net/call/CallManager.java | 63 +++++-- .../modlib/net/call/CallMethod.java | 50 +++--- .../modlib/net/io/FunctionSerializer.java | 1 - .../modlib/net/io/MTypeIO.java | 6 +- .../modlib/net/packet/PacketManager.java | 5 +- .../modlib/net/udp/UdpConnectionManager.java | 3 +- Mod/src/fr/redstonneur1256/modlib/ui/MUI.java | 1 + .../modlib/util/NetworkUtil.java | 18 +- .../modlib/util/dns/ARecord.java | 28 --- .../modlib/util/dns/DnsRecord.java | 13 -- .../modlib/util/dns/SimpleDns.java | 166 ------------------ .../modlib/util/dns/SrvRecord.java | 46 ----- README.md | 20 +-- assets/!mod-library.mixins.json | 3 - assets/bundles/bundle.properties | 2 + build.gradle.kts | 13 +- gradle.properties | 2 + gradle/libs.versions.toml | 9 +- settings.gradle.kts | 14 ++ 47 files changed, 238 insertions(+), 671 deletions(-) create mode 100644 .github/workflows/validate-gradle-wrapper.yml delete mode 100644 Mod/src/fr/redstonneur1256/modlib/mixins/arc/EventsMixin.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/mixins/arc/TimerMixin.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/mixins/ui/JoinDialogMixin.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/net/ServerPing.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/util/dns/ARecord.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/util/dns/DnsRecord.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/util/dns/SimpleDns.java delete mode 100644 Mod/src/fr/redstonneur1256/modlib/util/dns/SrvRecord.java create mode 100644 gradle.properties diff --git a/.github/workflows/validate-gradle-wrapper.yml b/.github/workflows/validate-gradle-wrapper.yml new file mode 100644 index 0000000..2e581e6 --- /dev/null +++ b/.github/workflows/validate-gradle-wrapper.yml @@ -0,0 +1,10 @@ +name: "Validate Gradle Wrapper" +on: [push, pull_request] + +jobs: + validation: + name: "Validation" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: gradle/actions/wrapper-validation@v3 diff --git a/Example/src/fr/redstonneur1256/examplemod/ExampleKeyBinds.java b/Example/src/fr/redstonneur1256/examplemod/ExampleKeyBinds.java index 4d7eab0..a252c15 100644 --- a/Example/src/fr/redstonneur1256/examplemod/ExampleKeyBinds.java +++ b/Example/src/fr/redstonneur1256/examplemod/ExampleKeyBinds.java @@ -5,6 +5,7 @@ import arc.input.KeyCode; import fr.redstonneur1256.modlib.key.KeyBindManager; +// This class is defined as an enum similarly to the base game, it doesn't need to be public enum ExampleKeyBinds implements KeyBinds.KeyBind { demo(KeyCode.j, "example-mod"); diff --git a/Example/src/fr/redstonneur1256/examplemod/MainMod.java b/Example/src/fr/redstonneur1256/examplemod/MainMod.java index 86b6034..7ed6c9e 100644 --- a/Example/src/fr/redstonneur1256/examplemod/MainMod.java +++ b/Example/src/fr/redstonneur1256/examplemod/MainMod.java @@ -3,6 +3,8 @@ import arc.util.CommandHandler; import arc.util.Log; import fr.redstonneur1256.examplemod.net.CustomCallExample; +import fr.redstonneur1256.examplemod.net.packet.direct.CustomPacketExample; +import fr.redstonneur1256.examplemod.net.packet.reply.CustomReplyPacketExample; import fr.redstonneur1256.modlib.net.NetworkDebuggable; import mindustry.gen.Groups; import mindustry.gen.Player; @@ -15,13 +17,11 @@ public void init() { // Register custom keybindings (needed by all the examples, do not comment) ExampleKeyBinds.register(); - // Uncomment the demo you want to test - // Send custom packets to the server/client - // CustomPacketExample.init(); + CustomPacketExample.init(); // Send custom packet and wait for reply, client/server example - // CustomReplyPacketExample.init(); + CustomReplyPacketExample.init(); // Test if a String is foo using a custom Call implementation CustomCallExample.init(); diff --git a/Example/src/fr/redstonneur1256/examplemod/net/CustomCallExample.java b/Example/src/fr/redstonneur1256/examplemod/net/CustomCallExample.java index b748ae1..38f6eda 100644 --- a/Example/src/fr/redstonneur1256/examplemod/net/CustomCallExample.java +++ b/Example/src/fr/redstonneur1256/examplemod/net/CustomCallExample.java @@ -38,18 +38,22 @@ public interface CustomCall { } - public static void init() { - MVars.net.registerCall(CustomCall.class, new CustomCall() { - @Override - public CallResult isFoo(Player player, String text) { - System.out.println("isFoo() got called from player " + player.name + " with text " + text); - if ("foo".equals(text)) { - return CallResult.of(true); - } - // Exceptions can either be thrown directly or by returning CallResult#failed(Throwable) - throw new RuntimeException("it's not foo"); + public static class CustomCallImplementation implements CustomCall { + + @Override + public CallResult isFoo(Player player, String text) { + System.out.println("isFoo() got called from player " + player.name + " with text " + text); + if ("foo".equals(text)) { + return CallResult.of(true); } - }); + // Exceptions can either be thrown directly or by returning CallResult#failed(Throwable) + throw new RuntimeException("it's not foo"); + } + + } + + public static void init() { + MVars.net.registerCall(CustomCall.class, new CustomCallImplementation()); // For the client side, every game tick: Events.run(EventType.Trigger.update, () -> { diff --git a/Example/src/fr/redstonneur1256/examplemod/net/packet/direct/CustomPacketExample.java b/Example/src/fr/redstonneur1256/examplemod/net/packet/direct/CustomPacketExample.java index e14fd40..039d6aa 100644 --- a/Example/src/fr/redstonneur1256/examplemod/net/packet/direct/CustomPacketExample.java +++ b/Example/src/fr/redstonneur1256/examplemod/net/packet/direct/CustomPacketExample.java @@ -17,21 +17,6 @@ public static void init() { // Register a custom packet, for this example a simple packet containing a String PacketManager.registerPacket(MessagePacket.class, MessagePacket::new); - /* - * You can either unregister packet handlers by doing - * 1: - * - MVars.net.unregisterClient(Class, Cons) - * - MVars.net.unregisterServer(Class, Cons2) - * 2: - * By registering your listener with - * - MVars.net.registerClient(Class, Cons) - * - MVars.net.registerServer(Class, Cons2) - * instead of Vars.net.handleClient/Server - * and then calling unregister() - * - * Note that you can also register multiple listeners per packet type - */ - // Handle that packet on the server side, here its just printing the packet content and the sender name Vars.net.handleServer(MessagePacket.class, (connection, packet) -> Log.info("Received custom message '@' from @", packet.message, connection.player.name)); diff --git a/Launcher/src/fr/redstonneur1256/modlib/launcher/ModLibLauncher.java b/Launcher/src/fr/redstonneur1256/modlib/launcher/ModLibLauncher.java index ce1dc01..6f7e064 100644 --- a/Launcher/src/fr/redstonneur1256/modlib/launcher/ModLibLauncher.java +++ b/Launcher/src/fr/redstonneur1256/modlib/launcher/ModLibLauncher.java @@ -146,6 +146,8 @@ private void openGame() throws Exception { initMixin(); initAccessWidener(); + System.setProperty("modlib.disableLogger", String.valueOf(!settings.get(Boolean.class, "modlib.logger", false))); + Mixins.addConfiguration("launcher.mixins.json"); loadModModifiers(); diff --git a/Launcher/src/fr/redstonneur1256/modlib/launcher/mixins/VarsMixin.java b/Launcher/src/fr/redstonneur1256/modlib/launcher/mixins/VarsMixin.java index 6dde901..a5fbd3a 100644 --- a/Launcher/src/fr/redstonneur1256/modlib/launcher/mixins/VarsMixin.java +++ b/Launcher/src/fr/redstonneur1256/modlib/launcher/mixins/VarsMixin.java @@ -1,6 +1,7 @@ package fr.redstonneur1256.modlib.launcher.mixins; import arc.Events; +import arc.struct.ObjectSet; import arc.struct.Seq; import arc.struct.StringMap; import arc.util.Log; @@ -8,8 +9,10 @@ import mindustry.Vars; import mindustry.game.EventType; import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -17,22 +20,17 @@ @Mixin(Vars.class) public class VarsMixin { - @Shadow - public static boolean loadedLogger; + public static @Shadow boolean loadedLogger; + public static @Shadow boolean headless; - @Shadow - public static boolean headless; + @Inject(method = "loadLogger", at = @At("HEAD"), cancellable = true) + private static void loadCustomLogger(CallbackInfo ci) { + if (loadedLogger || Boolean.getBoolean("modlib.disableLogger")) return; - /** - * @author Redstonneur1256 - * @reason fully replace the built-in logger by our custom one - */ - @Overwrite - public static void loadLogger() { - if (loadedLogger) return; + ci.cancel(); StringMap simpleClassNames = new StringMap(); - Seq hiddenClasses = Seq.with("arc.util.Log"); + ObjectSet hiddenClasses = ObjectSet.with("arc.util.Log"); String[] levels = { "DEBUG", "INFO", "WARN", "ERROR", "NONE" }; String[] colors = { "royal", "green", "yellow", "scarlet", "gray" }; diff --git a/Launcher/src/fr/redstonneur1256/modlib/launcher/util/ArcSettings.java b/Launcher/src/fr/redstonneur1256/modlib/launcher/util/ArcSettings.java index c404f8f..2f50a46 100644 --- a/Launcher/src/fr/redstonneur1256/modlib/launcher/util/ArcSettings.java +++ b/Launcher/src/fr/redstonneur1256/modlib/launcher/util/ArcSettings.java @@ -19,7 +19,6 @@ public class ArcSettings { public static final byte TYPE_STRING = 4; public static final byte TYPE_BINARY = 5; - private Map values; public ArcSettings() { diff --git a/Mod/build.gradle.kts b/Mod/build.gradle.kts index 3871ae7..f5f3c08 100644 --- a/Mod/build.gradle.kts +++ b/Mod/build.gradle.kts @@ -1,7 +1,7 @@ dependencies { - // compileOnly because common and launcher classes are provided by the launcher compileOnlyApi(project(":Launcher")) compileOnly(libs.bundles.mindustry) + api(libs.bundles.mindustry) } tasks.register("packJar", Jar::class.java) { diff --git a/Mod/src/fr/redstonneur1256/modlib/ModLib.java b/Mod/src/fr/redstonneur1256/modlib/ModLib.java index 86ef350..210e059 100644 --- a/Mod/src/fr/redstonneur1256/modlib/ModLib.java +++ b/Mod/src/fr/redstonneur1256/modlib/ModLib.java @@ -1,6 +1,7 @@ package fr.redstonneur1256.modlib; import fr.redstonneur1256.modlib.launcher.LauncherInitializer; +import fr.redstonneur1256.modlib.launcher.ModLibLauncher; import fr.redstonneur1256.modlib.net.MNet; import fr.redstonneur1256.modlib.ui.MUI; import mindustry.Vars; @@ -28,4 +29,9 @@ public static String getVersion() { return Vars.mods.getMod(ModLib.class).meta.version; } + public static void restartOnExit(boolean reloadLauncher) { + ModLibLauncher.launcher.restartGame = true; + ModLibLauncher.launcher.fastRestart = !reloadLauncher; + } + } diff --git a/Mod/src/fr/redstonneur1256/modlib/events/net/server/ServerListPingEvent.java b/Mod/src/fr/redstonneur1256/modlib/events/net/server/ServerListPingEvent.java index 7fee272..4cd0cfd 100644 --- a/Mod/src/fr/redstonneur1256/modlib/events/net/server/ServerListPingEvent.java +++ b/Mod/src/fr/redstonneur1256/modlib/events/net/server/ServerListPingEvent.java @@ -9,13 +9,13 @@ import java.net.InetAddress; import java.nio.ByteBuffer; +import java.util.Arrays; -import static mindustry.Vars.charset; +import static mindustry.Vars.*; /** - * Event called when a user ping the Mindustry server, all fields lengths limit have been removed however - * it will break if the combined length of the fields versionType, name, description, map and custom gamemode - * exceeds 478 bytes or if a single string is more than 256 bytes + * Event called when a user ping the Mindustry server, vanilla field length limits does not apply. it is however recommended + * to respect them as going over might cause string values to be trimmed. */ public class ServerListPingEvent { @@ -100,30 +100,35 @@ public void setDefaults() { * @return the encoded server data */ public ByteBuffer writeServerData() { - ByteBuffer buffer = ByteBuffer.allocate(500); + ByteBuffer buffer = ByteBuffer.allocate(512); - writeString(buffer, name); - writeString(buffer, map); + int reservedSpace = 1 + 1 + 4 + 4 + 4 + 1 + 1 + 4 + 1 + (customGamemode != null ? 1 : 0); + + writeString(buffer, name, buffer.remaining() - reservedSpace); + writeString(buffer, map, buffer.remaining() - reservedSpace); buffer.putInt(playerCount); buffer.putInt(wave); buffer.putInt(versionBuild); - writeString(buffer, versionType); + writeString(buffer, versionType, buffer.remaining() - reservedSpace); buffer.put((byte) gamemode.ordinal()); buffer.putInt(playerLimit); - writeString(buffer, description); + writeString(buffer, description, buffer.remaining() - reservedSpace); if (customGamemode != null) { - writeString(buffer, customGamemode); + writeString(buffer, customGamemode, buffer.remaining() - reservedSpace); } return buffer; } - private static void writeString(ByteBuffer buffer, String string) { + private static void writeString(ByteBuffer buffer, String string, int maxLength) { byte[] bytes = string.getBytes(charset); + if (bytes.length > maxLength) { + bytes = Arrays.copyOf(bytes, Math.max(maxLength, 0)); + } buffer.put((byte) bytes.length); buffer.put(bytes); } diff --git a/Mod/src/fr/redstonneur1256/modlib/key/KeyBindManager.java b/Mod/src/fr/redstonneur1256/modlib/key/KeyBindManager.java index 75bd1ac..349779e 100644 --- a/Mod/src/fr/redstonneur1256/modlib/key/KeyBindManager.java +++ b/Mod/src/fr/redstonneur1256/modlib/key/KeyBindManager.java @@ -10,7 +10,10 @@ public class KeyBindManager { public static void registerKeyBinds(KeyBinds.KeyBind... binds) { - ((KeyBindAccessor) Core.keybinds).registerKeyBinds(binds); + // silently fail instead of crashing if a mod calls the method before the game is restarted + if (Core.keybinds instanceof KeyBindAccessor) { + ((KeyBindAccessor) Core.keybinds).registerKeyBinds(binds); + } } } diff --git a/Mod/src/fr/redstonneur1256/modlib/launcher/LauncherInitializer.java b/Mod/src/fr/redstonneur1256/modlib/launcher/LauncherInitializer.java index 245ae6e..6ef8137 100644 --- a/Mod/src/fr/redstonneur1256/modlib/launcher/LauncherInitializer.java +++ b/Mod/src/fr/redstonneur1256/modlib/launcher/LauncherInitializer.java @@ -23,7 +23,7 @@ public class LauncherInitializer { public static boolean isInitialized() { - return doesClassExist("fr.redstonneur1256.modlib.launcher.ModLibLauncher"); + return doesClassExist("fr.redstonneur1256.modlib.launcher.ModLibLauncher") || Boolean.getBoolean("modlib.android-launcher-loaded"); } public static boolean isBundledJVM() { @@ -119,10 +119,8 @@ public static void initialize() { Core.settings.load(); } - if (Vars.headless) { - System.exit(0); - } Core.app.exit(); + System.exit(process.exitValue()); } catch (Throwable throwable) { // Startup failed, revert changes that could cause problems Core.settings.setAutosave(true); diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/arc/EventsMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/arc/EventsMixin.java deleted file mode 100644 index 2910ca7..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/arc/EventsMixin.java +++ /dev/null @@ -1,31 +0,0 @@ -package fr.redstonneur1256.modlib.mixins.arc; - -import arc.Events; -import arc.func.Cons; -import arc.util.Log; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Events.class) -public class EventsMixin { - - @Redirect(method = "fire(Ljava/lang/Enum;)V", at = @At(value = "INVOKE", target = "Larc/func/Cons;get(Ljava/lang/Object;)V"), require = 0) - private static void redirectFireEnum(Cons instance, T t) { - try { - instance.get(t); - } catch (Throwable throwable) { - Log.err("Failed to dispatch event listener " + instance, throwable); - } - } - - @Redirect(method = "fire(Ljava/lang/Class;Ljava/lang/Object;)V", at = @At(value = "INVOKE", target = "Larc/func/Cons;get(Ljava/lang/Object;)V"), require = 0) - private static void redirectFire(Cons instance, T t) { - try { - instance.get(t); - } catch (Throwable throwable) { - Log.err("Failed to dispatch event listener " + instance, throwable); - } - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/arc/TimerMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/arc/TimerMixin.java deleted file mode 100644 index a337a25..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/arc/TimerMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -package fr.redstonneur1256.modlib.mixins.arc; - -import arc.Application; -import arc.util.Log; -import arc.util.Timer; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Redirect; - -@Mixin(Timer.class) -public class TimerMixin { - - @Redirect(method = "update", at = @At(value = "INVOKE", target = "Larc/Application;post(Ljava/lang/Runnable;)V"), require = 0) - private void redirectUpdatePost(Application instance, Runnable runnable) { - instance.post(() -> { - try { - runnable.run(); - } catch (Throwable throwable) { - Log.err("Failed to dispatch timer task " + runnable, throwable); - } - }); - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/entity/PlayerMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/entity/PlayerMixin.java index c39742d..d43874c 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/entity/PlayerMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/entity/PlayerMixin.java @@ -9,8 +9,7 @@ @Mixin(Player.class) public class PlayerMixin implements NetworkDebuggable { - @Shadow - public transient NetConnection con; + public transient @Shadow NetConnection con; @Override public long getPing() { diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/gen/SoundsMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/gen/SoundsMixin.java index 673980b..68519ba 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/gen/SoundsMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/gen/SoundsMixin.java @@ -13,10 +13,8 @@ @Mixin(Sounds.class) public class SoundsMixin { - @Shadow - private static IntMap idToSound; - @Shadow - private static ObjectIntMap soundToId; + private static @Shadow IntMap idToSound; + private static @Shadow ObjectIntMap soundToId; @Inject(method = "", at = @At("TAIL")) private static void init(CallbackInfo ci) { diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/net/NetMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/net/NetMixin.java index 1362b06..1d48914 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/net/NetMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/net/NetMixin.java @@ -1,7 +1,6 @@ package fr.redstonneur1256.modlib.mixins.net; import arc.Events; -import arc.func.Cons; import arc.func.Prov; import arc.struct.IntMap; import fr.redstonneur1256.modlib.MVars; @@ -12,7 +11,11 @@ import fr.redstonneur1256.modlib.net.packet.MPacket; import fr.redstonneur1256.modlib.net.packet.PacketManager; import fr.redstonneur1256.modlib.net.packet.PacketTypeAccessor; -import mindustry.net.*; +import mindustry.net.Net; +import mindustry.net.NetConnection; +import mindustry.net.Packet; +import mindustry.net.Packets; +import mindustry.net.Streamable; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -20,42 +23,18 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import java.util.concurrent.ExecutorService; - @Mixin(Net.class) public class NetMixin { - @Final - @Shadow - private ExecutorService pingExecutor; - @Shadow - private boolean active; - @Shadow - private Streamable.StreamBuilder currentStream; - @Final - @Shadow - private IntMap streams; + private @Shadow boolean active; + private @Shadow Streamable.StreamBuilder currentStream; + private @Shadow @Final IntMap streams; @Inject(method = "handleException", at = @At("RETURN")) public void handleException(Throwable throwable, CallbackInfo ci) { Events.fire(new NetExceptionEvent(throwable)); } - @Inject(method = "", at = @At("RETURN")) - private void init(Net.NetProvider provider, CallbackInfo ci) { - // Foo's client moved the pingExecutor initialisation inside the pingHost method causing this to crash the game - if (pingExecutor != null) { - pingExecutor.shutdown(); - } - } - - @Inject(method = "pingHost", at = @At("HEAD"), cancellable = true) - public void pingHost(String address, int port, Cons valid, Cons failed, CallbackInfo ci) { - ci.cancel(); - - MVars.net.getPing().ping(address, port, valid, failed); - } - @Inject(method = "connect", at = @At("HEAD")) public void connect(String ip, int port, Runnable success, CallbackInfo ci) { if (!active) { diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcConnectionMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcConnectionMixin.java index 32dfb27..d35cce0 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcConnectionMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcConnectionMixin.java @@ -20,7 +20,11 @@ import mindustry.net.Streamable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.spongepowered.asm.mixin.*; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; @@ -31,9 +35,7 @@ @Mixin(targets = "mindustry.net.ArcNetProvider$ArcConnection") public abstract class ArcConnectionMixin implements MPlayerConnection, MConnection, NetworkDebuggable { - @Shadow - @Final - public Connection connection; + public @Shadow @Final Connection connection; private @Unique int nonce = 1; private @Unique IntMap> listeners = new IntMap<>(); diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcPacketSerializerMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcPacketSerializerMixin.java index 4c6b89b..31605dd 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcPacketSerializerMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/net/arc/ArcPacketSerializerMixin.java @@ -20,12 +20,9 @@ @Mixin(ArcNetProvider.PacketSerializer.class) public abstract class ArcPacketSerializerMixin { - @Shadow - ThreadLocal decompressBuffer; - @Shadow - ThreadLocal reads; - @Shadow - ThreadLocal writes; + @Shadow ThreadLocal decompressBuffer; + @Shadow ThreadLocal reads; + @Shadow ThreadLocal writes; /** * @author Redstonneur1256 @@ -57,7 +54,7 @@ public void write(ByteBuffer buffer, Object object) { return; } - NetworkUtil.writeExtendedByte(buffer, id); + NetworkUtil.writeVarInt(buffer, id); ByteBuffer packetBuffer = decompressBuffer.get(); packetBuffer.position(0); @@ -98,7 +95,7 @@ public Object read(ByteBuffer buffer) { } buffer.position(buffer.position() - 1); - id = NetworkUtil.readExtendedByte(buffer::get); + id = NetworkUtil.readVarInt(buffer::get); ByteBuffer packetBuffer = decompressBuffer.get(); int length = buffer.getShort() & 0xffff; @@ -115,7 +112,6 @@ public Object read(ByteBuffer buffer) { ClassEntry entry = PacketManager.getEntry(id); if (entry == null) { - Log.warn("Received unknown packet with id @", id); return null; } diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBeginMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBeginMixin.java index fc600ae..2076093 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBeginMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBeginMixin.java @@ -8,16 +8,14 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; @Mixin(Packets.StreamBegin.class) public class StreamBeginMixin implements PacketTypeAccessor { - @Shadow - public int id; - @Shadow - public int total; - - private int intType; + public @Shadow int id; + public @Shadow int total; + private @Unique int intType; /** * @author Redstonneur1256 @@ -27,7 +25,7 @@ public class StreamBeginMixin implements PacketTypeAccessor { public void read(Reads reads) { id = reads.i(); total = reads.i(); - intType = NetworkUtil.readExtendedByte(reads::b); + intType = NetworkUtil.readVarInt(reads::b); } /** @@ -38,7 +36,7 @@ public void read(Reads reads) { public void write(Writes writes) { writes.i(id); writes.i(total); - NetworkUtil.writeExtendedByte(writes::b, intType); + NetworkUtil.writeVarInt(writes::b, intType); } @Override diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBuilderMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBuilderMixin.java index 8692db4..8b3c318 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBuilderMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/net/packets/StreamBuilderMixin.java @@ -9,6 +9,7 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Overwrite; import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -16,11 +17,9 @@ @Mixin(Streamable.StreamBuilder.class) public class StreamBuilderMixin implements PacketTypeAccessor { - @Shadow - @Final - public ByteArrayOutputStream stream; + public @Shadow @Final ByteArrayOutputStream stream; - private int extendedType; + private @Unique int extendedType; /** * @author Redstonneur1256 diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/JoinDialogMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/ui/JoinDialogMixin.java deleted file mode 100644 index b9b97e2..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/JoinDialogMixin.java +++ /dev/null @@ -1,51 +0,0 @@ -package fr.redstonneur1256.modlib.mixins.ui; - -import arc.scene.ui.layout.Collapser; -import arc.scene.ui.layout.Table; -import mindustry.gen.Icon; -import mindustry.ui.Styles; -import mindustry.ui.dialogs.JoinDialog; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -@Mixin(JoinDialog.class) -public abstract class JoinDialogMixin { - - @Inject( - method = "*(Ljava/lang/String;ZLarc/scene/ui/layout/Collapser;Larc/scene/ui/layout/Table;)V", - at = @At( - value = "INVOKE", - target = "Larc/scene/ui/layout/Table;button(Larc/scene/style/Drawable;Larc/scene/ui/ImageButton$ImageButtonStyle;Ljava/lang/Runnable;)Larc/scene/ui/layout/Cell;", - ordinal = 1 - ) - ) - private void injectRefreshButton(String label, boolean eye, Collapser coll, Table name, CallbackInfo ci) { - name.button(Icon.refresh, Styles.emptyi, () -> { - switch (label) { - case "@servers.local.steam": - case "@servers.local": - refreshLocal(); - break; - case "@servers.remote": - refreshRemote(); - break; - case "@servers.global": - refreshCommunity(); - break; - } - }).size(40f).right().padRight(3).tooltip("@modlib.servers.refresh"); - } - - @Shadow - abstract void refreshLocal(); - - @Shadow - abstract void refreshRemote(); - - @Shadow - abstract void refreshCommunity(); - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/KeyBindDialogMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/ui/KeyBindDialogMixin.java index 4a59bce..d19cc93 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/KeyBindDialogMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/ui/KeyBindDialogMixin.java @@ -8,12 +8,12 @@ import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - @Mixin(KeybindDialog.class) public abstract class KeyBindDialogMixin extends Dialog { @Inject(method = "", at = @At("RETURN")) private void init(CallbackInfo ci) { + // we need to re-create the UI as new keybindings might have been added after it has been created shown(this::setup); } diff --git a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/ModsDialogMixin.java b/Mod/src/fr/redstonneur1256/modlib/mixins/ui/ModsDialogMixin.java index 0d43689..50c5649 100644 --- a/Mod/src/fr/redstonneur1256/modlib/mixins/ui/ModsDialogMixin.java +++ b/Mod/src/fr/redstonneur1256/modlib/mixins/ui/ModsDialogMixin.java @@ -1,8 +1,10 @@ package fr.redstonneur1256.modlib.mixins.ui; +import arc.Core; import arc.graphics.Color; import arc.scene.ui.layout.Table; -import fr.redstonneur1256.modlib.launcher.ModLibLauncher; +import fr.redstonneur1256.modlib.ModLib; +import mindustry.Vars; import mindustry.mod.Mods; import mindustry.ui.dialogs.BaseDialog; import mindustry.ui.dialogs.ModsDialog; @@ -18,10 +20,15 @@ public ModsDialogMixin(String title) { super(title); } - @Inject(method = "reload", at = @At("HEAD")) + @Inject(method = "reload", at = @At("HEAD"), cancellable = true) public void reload(CallbackInfo ci) { - ModLibLauncher.launcher.restartGame = true; - ModLibLauncher.launcher.fastRestart = false; + // Foo's client has a restart that prevents this from working + ci.cancel(); + + Vars.ui.showInfoOnHidden("@mods.reloadexit", () -> { + ModLib.restartOnExit(true); + Core.app.exit(); + }); } @Inject( diff --git a/Mod/src/fr/redstonneur1256/modlib/net/MNet.java b/Mod/src/fr/redstonneur1256/modlib/net/MNet.java index ba7d37f..e63e798 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/MNet.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/MNet.java @@ -19,7 +19,6 @@ import fr.redstonneur1256.modlib.net.packet.PacketManager; import fr.redstonneur1256.modlib.net.packets.DataAckPacket; import fr.redstonneur1256.modlib.net.udp.UdpConnectionManager; -import fr.redstonneur1256.modlib.util.dns.SimpleDns; import mindustry.Vars; import mindustry.io.SaveVersion; import mindustry.net.ArcNetProvider; @@ -42,8 +41,6 @@ public class MNet implements MConnection { public static final LZ4Compressor compressor = Reflect.get(ArcNetProvider.class, "compressor"); private UdpConnectionManager udpConnectionManager; - private SimpleDns dns; - private ServerPing ping; /** * Scheduler used for player pings on server side and packet timeouts */ @@ -55,8 +52,6 @@ public class MNet implements MConnection { public MNet() { this.udpConnectionManager = new UdpConnectionManager(); - this.dns = new SimpleDns(udpConnectionManager); - this.ping = new ServerPing(udpConnectionManager, dns); this.scheduler = Executors.newSingleThreadScheduledExecutor(runnable -> { Thread thread = new Thread(runnable); thread.setDaemon(true); @@ -85,7 +80,7 @@ public MNet() { if (!event.offline) { ByteBuffer buffer = event.writeServerData(); - buffer.position(0); + buffer.flip(); handler.respond(buffer); } @@ -174,14 +169,6 @@ public UdpConnectionManager getUdpConnectionManager() { return udpConnectionManager; } - public SimpleDns getDns() { - return dns; - } - - public ServerPing getPing() { - return ping; - } - public ScheduledExecutorService getScheduler() { return scheduler; } diff --git a/Mod/src/fr/redstonneur1256/modlib/net/ServerPing.java b/Mod/src/fr/redstonneur1256/modlib/net/ServerPing.java deleted file mode 100644 index ca6855a..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/net/ServerPing.java +++ /dev/null @@ -1,78 +0,0 @@ -package fr.redstonneur1256.modlib.net; - -import arc.Core; -import arc.func.Cons; -import arc.util.Time; -import fr.redstonneur1256.modlib.net.udp.UdpConnectionManager; -import fr.redstonneur1256.modlib.util.dns.ARecord; -import fr.redstonneur1256.modlib.util.dns.SimpleDns; -import fr.redstonneur1256.modlib.util.dns.SrvRecord; -import mindustry.net.Host; -import mindustry.net.NetworkIO; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.util.concurrent.TimeoutException; -import java.util.regex.Pattern; - -public class ServerPing { - - private static final ByteBuffer PING_HEADER = ByteBuffer.wrap(new byte[] { -2, 1 }); - private static final Pattern IP_PATTERN = Pattern.compile("^((\\b25[0-5]|\\b2[0-4][0-9]|\\b[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3})|(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))$"); - - private UdpConnectionManager connectionManager; - private SimpleDns dns; - private ByteBuffer buffer; - - public ServerPing(UdpConnectionManager connectionManager, SimpleDns dns) { - this.connectionManager = connectionManager; - this.dns = dns; - this.buffer = ByteBuffer.allocate(512); - } - - public void ping(String address, int port, Cons callback, Cons failure) { - pingInternal(address, port, callback, () -> dns.resolveSRV("_mindustry._tcp." + address, records -> { - if (records.isEmpty()) { - Core.app.post(() -> failure.get(new TimeoutException())); - return; - } - SrvRecord record = records.min(SrvRecord::compareTo); // Do not sort the whole list, just get the best one - pingInternal(record.target, record.port, callback, () -> Core.app.post(() -> failure.get(new TimeoutException()))); - })); - } - - private void pingInternal(String address, int port, Cons callback, Runnable failure) { - long start = Time.millis(); - - if (!IP_PATTERN.matcher(address).matches()) { - dns.resolveA(address, records -> { - if (records.isEmpty()) { - failure.run(); - return; - } - ARecord record = records.get(0); - pingInternal(record.getAddressAsString(), port, callback, failure); - }); - return; - } - - // Safe to create, no resolution since it has to be an IP - InetSocketAddress socketAddress = new InetSocketAddress(address, port); - - connectionManager.connect(socketAddress, 2000, buffer, connection -> { - connection.setTimeoutHandler(failure); - connection.setPacketHandler(buffer -> { - connection.close(); - - int ping = (int) Time.timeSinceMillis(start); - - Host host = NetworkIO.readServerData(ping, address, buffer); - host.port = port; - Core.app.post(() -> callback.get(host)); - }); - PING_HEADER.position(0); - connection.send(PING_HEADER); - }, exception -> failure.run()); - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/net/call/CallClass.java b/Mod/src/fr/redstonneur1256/modlib/net/call/CallClass.java index 8754254..713186c 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/call/CallClass.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/call/CallClass.java @@ -4,9 +4,9 @@ public class CallClass { - private Class type; - private T implementation; - private Seq methods; + private final Class type; + private final T implementation; + private final Seq methods; public CallClass(Class type, T implementation, Seq methods) { this.type = type; diff --git a/Mod/src/fr/redstonneur1256/modlib/net/call/CallManager.java b/Mod/src/fr/redstonneur1256/modlib/net/call/CallManager.java index 89420b3..a6da761 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/call/CallManager.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/call/CallManager.java @@ -60,24 +60,26 @@ public void registerCall(Class type, T implementation) { if (Vars.net.active()) { throw new IllegalStateException("Cannot register new call classes while connected to a server or hosting a server"); } + if (!type.isInterface()) { + throw new RuntimeException("Expected interface but got " + type); + } Seq methods = new Seq<>(); - CallClass callClass = new CallClass<>(type, implementation, methods); + CallClass clazz = new CallClass<>(type, implementation, methods); for (Method method : type.getDeclaredMethods()) { - Class returnType = method.getReturnType(); - if (!returnType.equals(CallResult.class) && !returnType.equals(void.class)) { - Log.warn("The method @#@ does not return CallResult or void and will be ignored", type.getName(), method.getName()); + if (!method.isAnnotationPresent(Remote.class)) { + Log.warn("Found method @ on @ but method is lacking @Remote annotation and will be ignored", method.getName(), type); continue; } + Remote remote = method.getAnnotation(Remote.class); + Class returnType = method.getReturnType(); - Side side = Side.BOTH; - Execution execution = Execution.MAIN; + Side side = remote.side(); + Execution execution = remote.execution(); - Remote remote = method.getAnnotation(Remote.class); - if (remote != null) { - side = remote.side(); - execution = remote.execution(); + if (!returnType.equals(CallResult.class) && !returnType.equals(void.class)) { + throw new RuntimeException(String.format("Expected method to return CallResult or void but got %s for %s", method.getReturnType(), getMethodSignature(method))); } Class[] parameters = method.getParameterTypes(); @@ -86,10 +88,13 @@ public void registerCall(Class type, T implementation) { continue; } - methods.add(new CallMethod(callClass, side, execution, method)); + methods.add(new CallMethod(clazz, method, execution, side)); } - registeredClasses.put(type.getName(), callClass); + if (registeredClasses.containsKey(type.getName())) { + Log.err("Remote Call class with type @ is already registered, overriding", type.getName()); + } + registeredClasses.put(type.getName(), clazz); } public boolean isCallAvailable(Class type) { @@ -117,10 +122,10 @@ private void resetMethods() { methodIds.ensureCapacity(callClass.getMethodCount()); for (CallMethod method : callClass.getMethods()) { - method.setId(i++); + method.setNetworkId(i++); activeMethods.add(method); - methodIds.put(method.getMethod(), method.getId()); + methodIds.put(method.getMethod(), method.getNetworkId()); } } } @@ -134,7 +139,7 @@ public void writeMethods(DataOutput stream) throws IOException { stream.writeInt(callClass.getMethods().size); for (CallMethod method : callClass.getMethods()) { - stream.writeInt(method.getId()); + stream.writeInt(method.getNetworkId()); stream.writeUTF(method.getName()); stream.writeInt(method.getParameters().length); for (Class parameter : method.getParameters()) { @@ -169,7 +174,6 @@ public void readMethods(DataInput stream) throws IOException { CallClass callClass = registeredClasses.get(className); if (callClass == null) { - Log.warn("Call class @ is present on server but not on client", className); continue; } @@ -187,14 +191,14 @@ public void readMethods(DataInput stream) throws IOException { CallMethod method = callClass.getMethods().find(m -> m.getName().equals(signature.getName()) && Arrays.equals(m.getParameters(), parameters)); if (method == null) { activeMethods.add((CallMethod) null); - Log.warn("Could not resolve method @ with parameters @ in class @", signature.getName(), Arrays.toString(parameters), className); + Log.warn("Could not resolve method @(%s) with parameters @ in class @", signature.getName(), Arrays.toString(parameters), className); continue; } - method.setId(signature.getId()); + method.setNetworkId(signature.getId()); activeMethods.add(method); - methodIds.put(method.getMethod(), method.getId()); + methodIds.put(method.getMethod(), method.getNetworkId()); } catch (ClassNotFoundException exception) { activeMethods.add((CallMethod) null); Log.warn("Method @ in class @ contains invalid type @", signature.getName(), className, name); @@ -270,4 +274,25 @@ public ObjectIntMap getMethodIds() { return methodIds; } + private static String getMethodSignature(Method method) { + StringBuilder builder = new StringBuilder(); + + builder.append(method.getDeclaringClass().getName()); + builder.append("#"); + builder.append(method.getName()); + builder.append("("); + + Class[] types = method.getParameterTypes(); + for (int i = 0; i < types.length; i++) { + if (i != 0) { + builder.append(", "); + } + builder.append(types[i]); + } + + builder.append(")"); + + return builder.toString(); + } + } diff --git a/Mod/src/fr/redstonneur1256/modlib/net/call/CallMethod.java b/Mod/src/fr/redstonneur1256/modlib/net/call/CallMethod.java index 4ce2f3b..c101e06 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/call/CallMethod.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/call/CallMethod.java @@ -5,29 +5,21 @@ public class CallMethod { - private CallClass callClass; - private Side side; - private Execution execution; - private Method method; - private int id; - - public CallMethod(CallClass callClass, Side side, Execution execution, Method method) { - this.callClass = callClass; - this.side = side; - this.execution = execution; + private final CallClass owner; + private final Method method; + private final Execution execution; + private final Side side; + private int networkId; + + public CallMethod(CallClass owner, Method method, Execution execution, Side side) { + this.owner = owner; this.method = method; + this.execution = execution; + this.side = side; } public Object invoke(Object[] arguments) throws InvocationTargetException, IllegalAccessException { - return method.invoke(callClass.getImplementation(), arguments); - } - - public Side getSide() { - return side; - } - - public Execution getExecution() { - return execution; + return method.invoke(owner.getImplementation(), arguments); } public String getName() { @@ -38,16 +30,28 @@ public Class[] getParameters() { return method.getParameterTypes(); } + public CallClass getOwner() { + return owner; + } + public Method getMethod() { return method; } - public int getId() { - return id; + public Execution getExecution() { + return execution; + } + + public Side getSide() { + return side; + } + + public int getNetworkId() { + return networkId; } - public void setId(int id) { - this.id = id; + public void setNetworkId(int networkId) { + this.networkId = networkId; } } diff --git a/Mod/src/fr/redstonneur1256/modlib/net/io/FunctionSerializer.java b/Mod/src/fr/redstonneur1256/modlib/net/io/FunctionSerializer.java index 57259a2..63cfaed 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/io/FunctionSerializer.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/io/FunctionSerializer.java @@ -15,7 +15,6 @@ public FunctionSerializer(Func reader, Cons2 writer) { this.writer = writer; } - @Override public T read(Reads reads) { return reader.get(reads); diff --git a/Mod/src/fr/redstonneur1256/modlib/net/io/MTypeIO.java b/Mod/src/fr/redstonneur1256/modlib/net/io/MTypeIO.java index 115e5e8..f58e7ef 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/io/MTypeIO.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/io/MTypeIO.java @@ -162,7 +162,7 @@ public static void readSerializers(DataInput stream) throws IOException { } public static Object readObject(Reads reads) { - int id = NetworkUtil.readExtendedByte(reads::b); + int id = NetworkUtil.readVarInt(reads::b); if (id == 0) { return null; } @@ -177,7 +177,7 @@ public static Object readObject(Reads reads) { @SuppressWarnings("unchecked") public static void writeObject(Writes writes, Object object) { if (object == null) { - NetworkUtil.writeExtendedByte(writes::b, 0); + NetworkUtil.writeVarInt(writes::b, 0); return; } @@ -191,7 +191,7 @@ public static void writeObject(Writes writes, Object object) { throw new SerializationException("Could not find a type serializer for the object " + object + " (" + object.getClass().getName() + ")"); } - NetworkUtil.writeExtendedByte(writes::b, serializer.getId()); + NetworkUtil.writeVarInt(writes::b, serializer.getId()); ((ObjectSerializer) serializer).write(writes, object); } diff --git a/Mod/src/fr/redstonneur1256/modlib/net/packet/PacketManager.java b/Mod/src/fr/redstonneur1256/modlib/net/packet/PacketManager.java index dadc6ce..f4af315 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/packet/PacketManager.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/packet/PacketManager.java @@ -135,10 +135,9 @@ public static void readAvailablePackets(DataInput stream) throws IOException { String name = stream.readUTF(); ClassEntry entry = registeredPackets.find(e -> e.type.getName().equals(name)); activePackets.add(entry); - if (entry == null) { - continue; + if (entry != null) { + packetIds.put(entry.type, i); } - packetIds.put(entry.type, i); } } diff --git a/Mod/src/fr/redstonneur1256/modlib/net/udp/UdpConnectionManager.java b/Mod/src/fr/redstonneur1256/modlib/net/udp/UdpConnectionManager.java index 21626e8..55c6ab3 100644 --- a/Mod/src/fr/redstonneur1256/modlib/net/udp/UdpConnectionManager.java +++ b/Mod/src/fr/redstonneur1256/modlib/net/udp/UdpConnectionManager.java @@ -4,7 +4,6 @@ import arc.util.Log; import arc.util.Threads; import arc.util.UnsafeRunnable; -import fr.redstonneur1256.modlib.util.NetworkUtil; import java.io.IOException; import java.net.InetSocketAddress; @@ -122,7 +121,7 @@ private void run() { try { ByteBuffer buffer = connection.getReceiveBuffer(); - NetworkUtil.clear(buffer); + buffer.clear(); channel.receive(buffer); buffer.flip(); diff --git a/Mod/src/fr/redstonneur1256/modlib/ui/MUI.java b/Mod/src/fr/redstonneur1256/modlib/ui/MUI.java index 6988c0b..1dc0a3d 100644 --- a/Mod/src/fr/redstonneur1256/modlib/ui/MUI.java +++ b/Mod/src/fr/redstonneur1256/modlib/ui/MUI.java @@ -27,6 +27,7 @@ public MUI() { Core.app.exit(); }))); table.checkPref("modlib.debug", false, checked -> Log.level = checked ? Log.LogLevel.debug : Log.LogLevel.info); + table.checkPref("modlib.logger", true); table.checkPref("modlib.versionWarning", true); }); } diff --git a/Mod/src/fr/redstonneur1256/modlib/util/NetworkUtil.java b/Mod/src/fr/redstonneur1256/modlib/util/NetworkUtil.java index 8928012..26319cd 100644 --- a/Mod/src/fr/redstonneur1256/modlib/util/NetworkUtil.java +++ b/Mod/src/fr/redstonneur1256/modlib/util/NetworkUtil.java @@ -7,7 +7,6 @@ import arc.util.io.Reads; import arc.util.io.Writes; -import java.nio.Buffer; import java.nio.ByteBuffer; public class NetworkUtil { @@ -25,7 +24,7 @@ public static Writes writes(ByteBuffer buffer) { return Writes.get(output); } - public static int readExtendedByte(Intp byteReader) { + public static int readVarInt(Intp byteReader) { int value = 0; int shift = 0; int read; @@ -39,7 +38,7 @@ public static int readExtendedByte(Intp byteReader) { return value; } - public static void writeExtendedByte(Intc byteWriter, int value) { + public static void writeVarInt(Intc byteWriter, int value) { while ((value & ~0x7F) != 0) { byteWriter.get((value & 0x7F) | 0x80); value >>>= 7; @@ -47,17 +46,8 @@ public static void writeExtendedByte(Intc byteWriter, int value) { byteWriter.get(value); } - public static void writeExtendedByte(ByteBuffer buffer, int value) { - writeExtendedByte(i -> buffer.put((byte) i), value); - } - - /** - * Utility method to call {@link Buffer}'s clear method directly because it's being overridden by the classes extending - * {@link Buffer} in new Java versions and compiling in a new version would result in wrong signatures causing a - * {@link NoSuchMethodException} - */ - public static void clear(Buffer buffer) { - buffer.clear(); + public static void writeVarInt(ByteBuffer buffer, int value) { + writeVarInt(i -> buffer.put((byte) i), value); } } diff --git a/Mod/src/fr/redstonneur1256/modlib/util/dns/ARecord.java b/Mod/src/fr/redstonneur1256/modlib/util/dns/ARecord.java deleted file mode 100644 index 09c7cb6..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/util/dns/ARecord.java +++ /dev/null @@ -1,28 +0,0 @@ -package fr.redstonneur1256.modlib.util.dns; - -import java.nio.ByteBuffer; - -public class ARecord extends DnsRecord { - - public final byte[] address; - - public ARecord(long ttl, ByteBuffer buffer) { - this(ttl, new byte[4]); - buffer.get(address); - } - - public ARecord(long ttl, byte[] address) { - super(SimpleDns.TYPE_A, ttl); - this.address = address; - } - - public String getAddressAsString() { - return (address[0] & 0xFF) + "." + (address[1] & 0xFF) + "." + (address[2] & 0xFF) + "." + (address[3] & 0xFF); - } - - @Override - public String toString() { - return "ARecord{" + getAddressAsString() + "}"; - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/util/dns/DnsRecord.java b/Mod/src/fr/redstonneur1256/modlib/util/dns/DnsRecord.java deleted file mode 100644 index 35c6e0f..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/util/dns/DnsRecord.java +++ /dev/null @@ -1,13 +0,0 @@ -package fr.redstonneur1256.modlib.util.dns; - -public class DnsRecord { - - public final int type; - public final long ttl; - - public DnsRecord(int type, long ttl) { - this.type = type; - this.ttl = ttl; - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/util/dns/SimpleDns.java b/Mod/src/fr/redstonneur1256/modlib/util/dns/SimpleDns.java deleted file mode 100644 index ac8bf30..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/util/dns/SimpleDns.java +++ /dev/null @@ -1,166 +0,0 @@ -package fr.redstonneur1256.modlib.util.dns; - -import arc.func.Cons; -import arc.math.Rand; -import arc.net.dns.ArcDns; -import arc.struct.IntMap; -import arc.struct.Seq; -import arc.util.Log; -import fr.redstonneur1256.modlib.net.udp.UdpConnectionManager; -import fr.redstonneur1256.modlib.util.NetworkUtil; -import fr.redstonneur1256.modlib.util.VariableCache; - -import java.net.InetSocketAddress; -import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; -import java.time.Duration; - -/** - * Non-blocking DNS Resolution utility class like {@link ArcDns} - */ -public class SimpleDns { - - public static final int TYPE_A = 1; - public static final int TYPE_SRV = 33; - - private UdpConnectionManager manager; - private Rand random; - /** - * ByteBuffer used for all the operations, it is safe to reuse it for all operations as they are all done on the - * connection manager thread - */ - private ByteBuffer buffer; - private IntMap>> caches; - private Seq nameServers; - - public SimpleDns(UdpConnectionManager manager) { - this.manager = manager; - this.random = new Rand(); - this.buffer = ByteBuffer.allocate(512); - this.caches = new IntMap<>(); - this.nameServers = ArcDns.getNameservers(); // cache nameservers because arc makes a copy of the list every time - - Log.debug("Using nameservers @", nameServers); - } - - public void resolveA(String domain, Cons> callback) { - resolve(TYPE_A, domain, ARecord::new, callback); - } - - public void resolveSRV(String domain, Cons> callback) { - resolve(TYPE_SRV, domain, SrvRecord::new, callback); - } - - @SuppressWarnings("unchecked") - private void resolve(int type, String domain, RecordReader reader, Cons> callback) { - manager.submit(() -> { - VariableCache> cache = caches.get(type, VariableCache::new); - Seq cachedValues = cache.get(domain); - if (cachedValues != null) { - callback.get((Seq) cachedValues); - return; - } - - resolveInternal(nameServers, 0, type, domain, reader, records -> { - if (records.any()) { - // little race condition but not very important, checking for another current query of the same type - // on the same domain and adding the callback would add much more complexity than it's worth. - // It would also be very rare that the same domain would be looked up twice at the same time - cache.put(domain, (Seq) records, Duration.ofSeconds(records.min(record -> (float) record.ttl).ttl)); - } - callback.get(records); - }); - }); - } - - private void resolveInternal(Seq servers, int serverIndex, int type, String domain, - RecordReader reader, Cons> callback) { - if (serverIndex >= servers.size) { - return; - } - Runnable failureHandler = () -> resolveInternal(servers, serverIndex + 1, type, domain, reader, callback); - - manager.connect(servers.get(serverIndex), 2000, buffer, connection -> { - connection.setTimeoutHandler(failureHandler); - - short id = (short) random.nextInt(Short.MAX_VALUE); - - connection.setPacketHandler(buffer -> { - connection.close(); - - short responseId = buffer.getShort(); - if (responseId != id) { - resolveInternal(servers, serverIndex + 1, type, domain, reader, callback); - Log.warn("Invalid response from DNS server @", servers.get(serverIndex)); - return; - } - - buffer.getShort(); - buffer.getShort(); - int answers = buffer.getShort() & 0xFFFF; - buffer.getShort(); - buffer.getShort(); - - byte len; - while ((len = buffer.get()) != 0) { - buffer.position(buffer.position() + len); - } - - buffer.getShort(); - buffer.getShort(); - - Seq records = new Seq<>(answers); - - for (int i = 0; i < answers; i++) { - buffer.getShort(); // OFFSET - int answerType = buffer.getShort() & 0xFFFF; // Type - buffer.getShort(); // Class - long ttl = buffer.getInt() & 0xFFFFFFFFL; // TTL - int length = buffer.getShort() & 0xFFFF; // Data length - - // Optionally CNAME results will be returned with the A results, skip those - if (answerType != type) { - buffer.position(buffer.position() + length); - continue; - } - - int position = buffer.position(); - - records.add(reader.read(ttl, buffer)); - - buffer.position(position + length); - } - - callback.get(records); - }); - - NetworkUtil.clear(buffer); - buffer.putShort(id); // Id - buffer.putShort((short) 0x0100); // Flags (recursion enabled) - buffer.putShort((short) 1); // Questions - buffer.putShort((short) 0); // Answers - buffer.putShort((short) 0); // Authority - buffer.putShort((short) 0); // Additional - - // Domain - for (String part : domain.split("\\.")) { - buffer.put((byte) part.length()); - buffer.put(part.getBytes(StandardCharsets.UTF_8)); - } - buffer.put((byte) 0); - - buffer.putShort((short) type); // Type - buffer.putShort((short) 1); // Class (Internet) - - buffer.flip(); - connection.send(buffer); - }, exception -> failureHandler.run()); - } - - public interface RecordReader { - - R read(long ttl, ByteBuffer buffer); - - } - -} diff --git a/Mod/src/fr/redstonneur1256/modlib/util/dns/SrvRecord.java b/Mod/src/fr/redstonneur1256/modlib/util/dns/SrvRecord.java deleted file mode 100644 index c8015cd..0000000 --- a/Mod/src/fr/redstonneur1256/modlib/util/dns/SrvRecord.java +++ /dev/null @@ -1,46 +0,0 @@ -package fr.redstonneur1256.modlib.util.dns; - -import java.nio.ByteBuffer; - -public class SrvRecord extends DnsRecord implements Comparable { - - public final int priority; - public final int weight; - public final int port; - public final String target; - - public SrvRecord(long ttl, ByteBuffer buffer) { - this(ttl, buffer.getShort(), buffer.getShort(), buffer.getShort(), readTarget(buffer)); - } - - public SrvRecord(long ttl, int priority, int weight, int port, String target) { - super(SimpleDns.TYPE_SRV, ttl); - this.priority = priority; - this.weight = weight; - this.port = port; - this.target = target; - } - - @Override - public int compareTo(SrvRecord o) { - if (this.priority != o.priority) { - return Integer.compare(this.priority, o.priority); - } else { - return Integer.compare(this.weight, o.weight); - } - } - - private static String readTarget(ByteBuffer buffer) { - byte len; - StringBuilder builder = new StringBuilder(); - while ((len = buffer.get()) != 0) { - for (int j = 0; j < len; j++) { - builder.append((char) buffer.get()); - } - builder.append('.'); - } - builder.setLength(builder.length() - 1); - return builder.toString(); - } - -} diff --git a/README.md b/README.md index 801b1b9..0493c3a 100644 --- a/README.md +++ b/README.md @@ -19,14 +19,12 @@ Current development tools: * `Call` like classes supporting custom parameters and return values * Synchronized registrable types in TypeIO * Custom keybind registration +* Improved logger -Current game utilities/optimizations: ------ - -* 📃 Logger showing calling class name -* 📶 Optimized server ping & dns lookup, no longer creating a billion threads -* 📶 Button to refresh the server list -* 💥 Handled `Events` and `Timer` exceptions +Mod Installation: +---- +Desktop/Steam you can download the mod from the mod browser or from the releases page (ModLib). +Android: Coming soon ~~Download the mod launcher from the [releases pages](https://github.com/Redstonneur1256/Mindustry-ModLib/releases/), install the application and follow the steps from the application.~~ Using the library: ----- @@ -35,13 +33,13 @@ Using the library: ```groovy repositories { mavenCentral() - maven { url 'https://raw.githubusercontent.com/Zelaux/MindustryRepo/master/repository' } - maven { url 'https://jitpack.io/' } - maven { url 'https://repo.mc-skyplex.net/releases' } + maven { url "https://raw.githubusercontent.com/Anuken/MindustryMaven/master/repository" } + maven { url "https://jitpack.io/" } + maven { url "https://repo.mc-skyplex.net/releases" } } dependencies { - compileOnly 'com.github.Redstonneur1256.Mindustry-ModLib:Mod:VERSION' + compileOnly("com.github.Redstonneur1256.Mindustry-ModLib:Mod:VERSION") } ``` - Update your `mod.json`/`plugin.json` to add the library as a dependency. diff --git a/assets/!mod-library.mixins.json b/assets/!mod-library.mixins.json index 469ae95..62101ba 100644 --- a/assets/!mod-library.mixins.json +++ b/assets/!mod-library.mixins.json @@ -5,8 +5,6 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "KeyBindsMixin", - "arc.EventsMixin", - "arc.TimerMixin", "entity.PlayerMixin", "gen.SoundsMixin", "net.CallMixin", @@ -15,7 +13,6 @@ "net.arc.ArcPacketSerializerMixin", "net.packets.StreamBeginMixin", "net.packets.StreamBuilderMixin", - "ui.JoinDialogMixin", "ui.KeyBindDialogMixin", "ui.ModsDialogMixin" ], diff --git a/assets/bundles/bundle.properties b/assets/bundles/bundle.properties index 4887284..9b8b554 100644 --- a/assets/bundles/bundle.properties +++ b/assets/bundles/bundle.properties @@ -7,6 +7,8 @@ setting.modlib.antialiasing.name=MSAA x16 setting.modlib.antialiasing.description=Enables built in MSAA x16. Requires game restart setting.modlib.debug.name=Debug logging setting.modlib.debug.description=Enables or disable debug logger. +setting.modlib.logger.name=Improved logger +setting.modlib.logger.description=Enables an improved version of the game's logger that show origin of the log (restart required) setting.modlib.versionWarning.name=Show version warning setting.modlib.versionWarning.description=Show a warning when connecting to a server which have a different version installed diff --git a/build.gradle.kts b/build.gradle.kts index 9222592..a6bdb9b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,18 +1,19 @@ -import io.github.redstonneur1256.gaw.AccessWidenerExtension import java.time.Instant plugins { `java-library` `maven-publish` id("com.github.johnrengelman.shadow") version ("8.1.1") apply (false) - id("io.github.redstonneur1256.gradle-access-widener") version ("0.2") apply (false) } subprojects { + if (project.name.contains("Android")) { + return@subprojects + } + apply(plugin = "java-library") apply(plugin = "maven-publish") apply(plugin = "com.github.johnrengelman.shadow") - apply(plugin = "io.github.redstonneur1256.gradle-access-widener") group = "fr.redstonneur1256" version = System.getenv("GITHUB_VERSION") ?: "dev" @@ -25,17 +26,13 @@ subprojects { } } - configure { - paths.set(rootProject.files("assets/!mod-library.accessWidener")) - } - tasks.withType(JavaCompile::class.java).configureEach { options.encoding = "UTF-8" } repositories { mavenCentral() - maven("https://raw.githubusercontent.com/Zelaux/MindustryRepo/master/repository") + maven("https://raw.githubusercontent.com/Anuken/MindustryMaven/master/repository") maven("https://jitpack.io") maven("https://repo.mc-skyplex.net/releases") } diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..b837d82 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +android.useAndroidX=true +android.useDeprecatedNdk=true diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 1c5c695..9df1757 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,10 +1,11 @@ [versions] -asm = "9.2" +asm = "9.6" mindustry = "v146" [libraries] -annotations = "org.jetbrains:annotations:24.0.0" -anuken-arc = { module = "com.github.Anuken.Arc:arc-core", version.ref = "mindustry" } +annotations = "org.jetbrains:annotations:24.0.1" +anuken-arc-core = { module = "com.github.Anuken.Arc:arc-core", version.ref = "mindustry" } +anuken-arc-android = { module = "com.github.Anuken.Arc:backend-android", version.ref = "mindustry" } anuken-mindustry = { module = "com.github.Anuken.Mindustry:core", version.ref = "mindustry" } asm-tree = { module = "org.ow2.asm:asm-tree", version.ref = "asm" } asm-commons = { module = "org.ow2.asm:asm-commons", version.ref = "asm" } @@ -15,5 +16,5 @@ gson = "com.google.code.gson:gson:2.10.1" hjson = "org.hjson:hjson:3.0.0" [bundles] -mindustry = ["anuken-arc", "anuken-mindustry"] +mindustry = ["anuken-arc-core", "anuken-mindustry"] asm = ["asm-tree", "asm-commons", "asm-util"] diff --git a/settings.gradle.kts b/settings.gradle.kts index c418cce..6ec096f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1,18 @@ rootProject.name = "Mindustry-ModLib" + +val androidSdkPath: String? = System.getenv("ANDROID_HOME") +if(androidSdkPath != null && file(androidSdkPath).isDirectory && file("Android").isDirectory) { + pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } + } + + include("Android") +} + include("Common") include("Example") include("Launcher")