From 7deaed49616ced134162f3fb7d52f5555c830cce Mon Sep 17 00:00:00 2001 From: Lixfel Date: Sat, 22 Jun 2024 17:00:13 +0200 Subject: [PATCH] WIP Mods, Alpine Client support Signed-off-by: Lixfel --- build.gradle | 4 +- .../velocitycore/listeners/PluginMessage.java | 122 +++++++++++++++--- src/de/steamwar/velocitycore/mods/Alpine.java | 71 ++++++++++ 3 files changed, 179 insertions(+), 18 deletions(-) create mode 100644 src/de/steamwar/velocitycore/mods/Alpine.java diff --git a/build.gradle b/build.gradle index f779cf6d..76ad5709 100644 --- a/build.gradle +++ b/build.gradle @@ -92,7 +92,9 @@ dependencies { annotationProcessor 'com.velocitypowered:velocity-api:3.3.0-SNAPSHOT' compileOnly 'de.steamwar:velocity:RELEASE' + compileOnly project(":Persistent") + implementation project(":CommonCore") runtimeOnly 'org.xerial:sqlite-jdbc:3.36.0' //TODO native only linux implementation 'mysql:mysql-connector-java:8.0.33' @@ -101,7 +103,7 @@ dependencies { exclude module: 'opus-java' } - implementation project(":CommonCore") + implementation 'org.msgpack:msgpack-core:0.9.8' //AlpineClient implementation 'com.lunarclient:apollo-api:1.1.0' implementation 'com.lunarclient:apollo-common:1.1.0' diff --git a/src/de/steamwar/velocitycore/listeners/PluginMessage.java b/src/de/steamwar/velocitycore/listeners/PluginMessage.java index ae0c59f5..f5e6f323 100644 --- a/src/de/steamwar/velocitycore/listeners/PluginMessage.java +++ b/src/de/steamwar/velocitycore/listeners/PluginMessage.java @@ -105,12 +105,16 @@ public class PluginMessage extends BasicListener { "fabric:container/open", "fabric:registry/sync/direct", "fabric:registry/sync", "fabric-screen-handler-api-v1:open_screen", - FML.CHANNEL, "fml:loginwrapper", "fml:handshake", "fml:play", "forge:tier_sorting", "forge:split", - "forge:login", "forge:handshake", + FML.CHANNEL, "FML|MP", "FML", "FORGE", + "fml:loginwrapper", "fml:handshake", "fml:play", + "forge:tier_sorting", "forge:split", "forge:login", "forge:handshake", "labymod3:main", "labymod:neo", - "floodgate:skin", "floodgate:form", "floodgate:transfer", "floodgate:packet", + Alpine.HANDSHAKE, Alpine.PLAY, + + "sw:hotkeys", + "floodgate:form", "floodgate:transfer", "floodgate:packet", "Replay|Restrict", "replaymod:restrict", "WDL|CONTROL", "wdl:control", @@ -118,43 +122,98 @@ public class PluginMessage extends BasicListener { "methane_server:statepacket", //https://modrinth.com/mod/methane "servux:structures", //https://modrinth.com/mod/servux "architectury:spawn_entity_packet", //https://modrinth.com/mod/architectury-api - "jei:channel", //https://modrinth.com/mod/jei + "jei:channel", "jei:cheat_permission", //https://modrinth.com/mod/jei "shulkerboxtooltip:s2c_handshake", "shulkerboxtooltip:ec_update", //https://modrinth.com/mod/shulkerboxtooltip "owo:local_packet", "owo:sync_screen_handler_properties", //https://modrinth.com/mod/owo-lib - "essential:", //https://essential.gg/ "libgui:screen_message_s2c", //https://github.com/CottonMC/LibGui "minecraft:intave", //https://intave.ac seems to be a client side integration of intave with labymod 4 "midnightcontrols:feature", "midnightcontrols:controls_mode", //https://modrinth.com/mod/midnightcontrols "controlify:vibrate_from_origin", "controlify:vibration", "controlify:vibrate_from_entity", "carpet:structures", //https://modrinth.com/mod/carpet - "appleskin:exhaustion_sync", "appleskin:saturation_sync", //https://modrinth.com/mod/appleskin - "puzzleslib:1/1", //https://modrinth.com/mod/puzzles-lib "pickupnotifier:1/1", //https://modrinth.com/mod/pick-up-notifier - "plasmo:voice/v2/installed", "plasmo:voice/v2", //https://modrinth.com/plugin/plasmo-voice + "plasmo:voice/v2/installed", "plasmo:voice/v2", //https://modrinth.com/plugin/plasmo-voice (Voice chat) "whereisit:s2c_founditem", //https://modrinth.com/mod/where-is-it (needs server side component to work) "inventorysorter:sync_blacklist_packet", //https://github.com/cpw/inventorysorter (needs server side component to work) + "emi:ping", "emi:command", "emi:chess", //https://github.com/emilyploszaj/emi/ + "fancymenu:execute_command", "fancymenu:packet_bridge", //https://github.com/Keksuccino/FancyMenu (Custom menus) + "itemswapper:enableshulker", "itemswapper:enablerefill", //https://github.com/tr7zw/ItemSwapper/tree/main (Easier inventory item swapping) + "jade:show_overlay", "jade:receive_data", "jade:server_ping", //https://github.com/Snownee/Jade (Information over block/entity under crosshair) + "bclib:hello_client", "bclib:request_files", "bclib:send_files", "bclib:chunker", //https://github.com/quiqueck/BCLib (Library for additional dimensions) + "roughlyenoughitems:ci_msg", "roughlyenoughitems:request_tags_s2c", "roughlyenoughitems:og_not_enough", //https://github.com/shedaniel/RoughlyEnoughItems (Crafting recipe helper) + "essentialclient:chunkdebug", "essentialclient:clientscript", "essentialclient:gamerule", //https://github.com/senseiwells/EssentialClient (Carpet mod extension) + "couplings:server_config", //https://github.com/ChloeDawn/Couplings (Opens/closes double doors/gates simultaneously) + "yigd:grave_overview_s2c", "yigd:grave_selection_s2c", "yigd:player_selection_s2c", //https://github.com/B1n-ry/Youre-in-grave-danger (Adds new block - graves) + "kiwi:sync_cosmetic", //github.com/Snownee/Kiwi (General purpose library) + "fwaystones:void_totem_revive", "fwaystones:sync_player", "fwaystones:waystone_packet", //https://github.com/LordDeatHunter/FabricWaystones (Adds new block - waystone) + + //https://essential.gg/ + "essential:", "essential:game_rule_hello", "essential:game_rule_permissions", + "essential:game_rules_changed", + + //https://github.com/MehVahdJukaar/Supplementaries (Additional blocks) + "supplementaries:0", "supplementaries:1", "supplementaries:2", "supplementaries:3", "supplementaries:4", + "supplementaries:5", "supplementaries:6", "supplementaries:7", "supplementaries:8", "supplementaries:9", + "supplementaries:10", "supplementaries:11", "supplementaries:12", "supplementaries:13", + "supplementaries:14", "supplementaries:24", "supplementaries:25", + + //https://www.curseforge.com/minecraft/mc-mods/waila (Information over block/entity under crosshair) + "waila:data", "waila:blacklist", "waila:config", "waila:version", "waila:generate_client_dump", + + //https://modrinth.com/plugin/simple-voice-chat (Voice chat) + "voicechat:secret", "voicechat:joined_group", "voicechat:player_states", "voicechat:player_state", + "voicechat:remove_category", "voicechat:remove_group", "voicechat:add_category", + "voicechat:leave_group", "voicechat:create_group", "voicechat:request_secret", "voicechat:set_group", + "voicechat:update_state", "voicechat:add_group", + + //https://github.com/mim1q/MineCells (Additional dimensions and gamemodes) + "minecells:obelisk_activation", "minecells:connect", "minecells:crit", "minecells:explosion", + "minecells:elevator_destroyed", "minecells:spawn_rune_particles", "minecells:sync_minecells_data", + + //https://modrinth.com/mod/appleskin (Additional food bar information) + "appleskin:exhaustion_sync", "appleskin:saturation_sync", + "appleskin:saturation", "appleskin:exhaustion", + + //https://modrinth.com/mod/puzzles-lib (General purpose library) + "puzzleslib:1/0", "puzzleslib:1/1", "puzzleslib:1/2", + "puzzleslib.main:0", "puzzleslib.main:1", "puzzleslib:play/0", + //https://github.com/Fuzss/puzzlesapi (General purpose library extension) + "puzzlesapi:1/1", "puzzlesapi:1/2", "puzzlesapi:1/5", "puzzlesapi:2/1", "puzzlesapi:2/2", //https://github.com/bernie-g/geckolib "geckolib:block_entity_anim_trigger_sync", "geckolib:entity_anim_trigger_sync", "geckolib:block_entity_anim_data_sync", "geckolib:anim_data_sync", "geckolib:entity_anim_data_sync", "geckolib:anim_trigger_sync", - //https://github.com/Noxcrew/noxesium + //https://github.com/Noxcrew/noxesium (MC Championship helper) + "noxesium:server_rules", "noxesium-v1:reset", "noxesium-v1:change_server_rules", "noxesium-v1:server_info", "noxesium-v1:mcc_server", "noxesium-v1:mcc_game_state", "noxesium-v1:reset_server_rules", - "noxesium-v1:stop_sound", "noxesium-v1:start_sound", "noxesium-v1:modify_sound" + "noxesium-v1:stop_sound", "noxesium-v1:start_sound", "noxesium-v1:modify_sound", + "noxesium-v2:reset", "noxesium-v2:change_server_rules", "noxesium-v2:server_info", + "noxesium-v2:mcc_server", "noxesium-v2:mcc_game_state", "noxesium-v2:reset_server_rules", + "noxesium-v2:stop_sound", "noxesium-v2:start_sound", "noxesium-v2:modify_sound" )) channelRegisterHandlers.put(channel, player -> {}); channelRegisterHandlers.put(ApolloManager.PLUGIN_MESSAGE_CHANNEL, lunar::sendRestrictions); channelRegisterHandlers.put(Feather.CHANNEL, new Feather()::sendRestrictions); + channelRegisterHandlers.put("openboatutils:settings", player -> send(player, "openboatutils:settings", new byte[] { 0, 0 })); //https://github.com/o7Moon/OpenBoatUtils/wiki/Packets (Reset packet) + channelRegisterHandlers.put("itemswapper:disable", player -> send(player, "itemswapper:disable", new byte[]{ 0 })); //https://github.com/tr7zw/ItemSwapper/blob/main/src/main/java/dev/tr7zw/itemswapper/packets/DisableModPayload.java channelRegisterHandlers.put("xaerominimap:main", player -> player.sendMessage(Component.text("§n§o§m§i§n§i§m§a§p"))); //https://www.curseforge.com/minecraft/mc-mods/xaeros-minimap channelRegisterHandlers.put("litemoretica:init_easy_place", player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "litematica")); //https://github.com/Earthcomputer/litemoretica/tree/master + channelRegisterHandlers.put("litemoretica:init_ea", player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "litematica")); //https://github.com/Earthcomputer/litemoretica/tree/master channelRegisterHandlers.put("voxelmap:settings", player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "voxelmap")); //https://modrinth.com/mod/voxelmap-updated undocumented - channelRegisterHandlers.put("worldinfo:world_id", player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "minimap")); // JourneyMap and VoxelMap channelRegisterHandlers.put(Controlify.CHANNEL, new Controlify()::onRegister); - registerBiDirPassthrough("worldedit:cui"); + for(String channel : Arrays.asList( + "worldinfo:world_id", // JourneyMap and VoxelMap + "journeymap:version", "journeymap:admin_req", "journeymap:mp_options_req", "journeymap:waypoint", + "journeymap:player_loc", "journeymap:admin_save", "journeymap:teleport_req", "journeymap:common", + "journeymap:perm_req" + )) + channelRegisterHandlers.put(channel, player -> Chatter.disconnect(player).prefixless("MOD_YELLOW_SING", "minimap")); + + registerBiDirPassthrough("WECUI", "worldedit:cui", "worldedit:internal", "minecraft:wecui"); registerPassthroughToClient( "axiom:enable", "axiom:initialize_hotbars", @@ -163,12 +222,26 @@ public class PluginMessage extends BasicListener { "axiom:custom_blocks", "axiom:editor_warning", "axiom:blueprint_manifest", "axiom:response_blueprint" ); registerBiDirPassthrough("axiom:handle_big_payload", "axiom:set_editor_views"); - registerPassthroughToServer( + for(String channel : Arrays.asList( "axiom:hello", "axiom:set_gamemode", "axiom:set_fly_speed", "axiom:set_world_time", "axiom:set_world_property", "axiom:set_block", "axiom:set_hotbar_slot", "axiom:switch_active_hotbar", "axiom:teleport", "axiom:request_chunk_data", "axiom:spawn_entity", "axiom:manipulate_entity", "axiom:delete_entity", "axiom:marker_nbt_request", "axiom:set_buffer" - ); + )) { + channelRegisterHandlers.put(channel, player -> {}); + registerPassthroughToServer(channel); + } + + for(String channel : Arrays.asList( + "floodgate:skin", + "watut:nbt", //https://github.com/Corosauce/WATUT + "bclib:hello_server", + "vivecraft:data", //https://github.com/Vivecraft/VivecraftMod https://github.com/jrbudda/Vivecraft_Spigot_Extensions https://github.com/Techjar/Vivecraft_BungeeCord_Extensions (VR support) + "badpackets:channel_sync" //https://github.com/badasintended/badpackets (Forge fabric translation layer) + )) { + channelRegisterHandlers.put(channel, player -> {}); + register(channel, false, directional(UNKNOWN, DROP)); + } for(String channel : Arrays.asList( "UNREGISTER", "minecraft:unregister", // used by carpet and servux @@ -178,8 +251,22 @@ public class PluginMessage extends BasicListener { "lambdacontrols:hello", "midnightcontrols:controls_mode", "inventorysorter:sync_settings_packet", - "voicechat:request_secret", "voicechat:update_state", //https://modrinth.com/plugin/simple-voice-chat - "shulkerboxtooltip:c2s_handshake" + "voicechat:request_secret", "voicechat:update_state", + "shulkerboxtooltip:c2s_handshake", + "noxesium:client_information", "noxesium:client_settings", + "polymer:handshake", //https://github.com/Patbox/polymer + "minecells:request_sync_minecells_data", + "puzzlesapi:1/4", + "fancymenu:variable_cmd_sugg", "fancymenu:packet_bridge", + "jade:request_entity", "jade:request_tile", + "tiscm:network/v1", //https://github.com/gnembon/fabric-carpet + "couplings:client_config", + "yigd:config_update_c2s", + "kiwi:set_cosmetic", + "fwaystones:request_player_waystone_update", + "openboatutils:settings", //https://github.com/o7Moon/OpenBoatUtils + "block-event-separator:handshake", //https://github.com/SpaceWalkerRS/block-event-separator (Separating block events) + "oth3r-sit:settings_v1.1" //https://github.com/Oth3r/Sit (Sitting mod) )) register(channel, false, directional(UNKNOWN, DROP)); @@ -191,13 +278,14 @@ public class PluginMessage extends BasicListener { //Needs to be registered cause paper refuses to send PluginMessages on unregistered channels... register("sw:bridge", true, directional(onlySWSource(async(event -> NetworkPacket.handle(new ServerMetaInfo((ServerConnection) event.getSource()), event.getData()))), UNKNOWN)); - register("sw:hotkeys", false, directional(UNKNOWN, PASS_THROUGH)); + registerPassthroughToServer("sw:hotkeys"); register("fabricmodsender:mods", true, directional(UNKNOWN, async(new FabricModSender()::handlePluginMessage))); register("WDL|INIT", true, directional(UNKNOWN, wdl::handlePluginMessage)); register("wdl:init", true, directional(UNKNOWN, wdl::handlePluginMessage)); register(ApolloManager.PLUGIN_MESSAGE_CHANNEL, true, async(lunar::handlePluginMessage)); + register(Alpine.HANDSHAKE, false, directional(UNKNOWN, new Alpine()::handleHandshakeMessage)); register("LMC", true, directional(UNKNOWN, async(labyMod::handlePluginMessage))); register("labymod3:main", true, directional(UNKNOWN, async(labyMod::handlePluginMessage))); register("labymod:neo", false, directional(UNKNOWN, DROP)); //undocumented, JSON format "0" byte, packetlängen byte, {"version":"4.1.25"} diff --git a/src/de/steamwar/velocitycore/mods/Alpine.java b/src/de/steamwar/velocitycore/mods/Alpine.java new file mode 100644 index 00000000..82271dc9 --- /dev/null +++ b/src/de/steamwar/velocitycore/mods/Alpine.java @@ -0,0 +1,71 @@ +/* + * This file is a part of the SteamWar software. + * + * Copyright (C) 2024 SteamWar.de-Serverteam + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package de.steamwar.velocitycore.mods; + +import com.velocitypowered.api.event.connection.PluginMessageEvent; +import com.velocitypowered.api.proxy.Player; +import de.steamwar.velocitycore.listeners.PluginMessage; +import org.msgpack.core.MessagePack; +import org.msgpack.core.MessagePacker; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public class Alpine { + //https://github.com/alpine-client/alpine-client-api + + public static final String HANDSHAKE = "ac:handshake"; + public static final String PLAY = "ac:play"; + + private final byte[] magicHandshakeResponse = new byte[] {0x3A, 0x3D}; //https://github.com/alpine-client/alpine-client-api/blob/master/src/main/java/com/alpineclient/plugin/listener/plugin/HandshakeListener.java#L19 + private final byte[] modulesPacket; + + public Alpine() { + //https://github.com/alpine-client/alpine-client-api/blob/master/MODULES.md + String[] disabledModules = new String[] { + "armor_status", "cannon_playback", "cannon_view", "clear_water", "explosion_boxes", "fullbright", + "hit_color", "inventory_tweaks", "low_hp_tint", "minimap", "perspective_mod", "potion_status", + "reach_display", "schematica", "tnt_timer", "toggle_sneak_sprint" + }; + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + try (MessagePacker packer = MessagePack.newDefaultPacker(stream)) { + //https://github.com/alpine-client/alpine-client-api/blob/master/src/main/java/com/alpineclient/plugin/network/Packet.java#L103 + packer.packInt(0xB0); + + //https://github.com/alpine-client/alpine-client-api/blob/master/src/main/java/com/alpineclient/plugin/network/packet/PacketModules.java + packer.packArrayHeader(disabledModules.length); + for (String module : disabledModules) { + packer.packString(module); + packer.packBoolean(false); //https://github.com/alpine-client/alpine-client-api/blob/master/src/main/java/com/alpineclient/plugin/config/impl/GeneralConfig.java + } + } catch (IOException e) { + throw new SecurityException(e); + } + + modulesPacket = stream.toByteArray(); + } + + public void handleHandshakeMessage(PluginMessageEvent event) { + Player player = (Player) event.getSource(); + PluginMessage.send(player, HANDSHAKE, magicHandshakeResponse); + PluginMessage.send(player, PLAY, modulesPacket); + } +}