diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 99dc37247..e827c664c 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -154,7 +154,7 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.18.2 --remapped # Build 1.19.2 NMS - wild_1_19: + wild_1_19_2: runs-on: ubuntu-latest steps: - name: Set up JDK 17 # 1.19.2 can only be built with Java 17 @@ -163,7 +163,7 @@ jobs: distribution: 'temurin' java-version: '17' - name: Cache 1.19.2 Maven package - id: cacheWild + id: cacheWild_r1 uses: actions/cache@v2 with: path: | @@ -195,78 +195,130 @@ jobs: if: steps.wild.outputs.sucess != 'true' || steps.wildMojang.outputs.sucess != 'true' || steps.wildObf.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.19.2 --remapped + # Build 1.19.3 NMS + wild_1_19_3: + runs-on: ubuntu-latest + steps: + - name: Set up JDK 17 # 1.19.3 can only be built with Java 17 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + - name: Cache 1.19.3 Maven package + id: cacheWild_r2 + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.19.3-all + restore-keys: ${{ runner.os }}-spigot-1.19.3-all + - name: Cache Maven packages + id: cacheMain + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2_1.19.3 + restore-keys: ${{ runner.os }}-m2_1.19.3 + + - name: Setup BuildTools + run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + - name: Check 1.19.3 Spigot + id: wild + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Check 1.19.3 Spigot (Mojang) + id: wildMojang + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT-remapped-mojang.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Check 1.19.3 Spigot (Obf) + id: wildObf + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT-remapped-obf.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.19.3 + if: steps.wild.outputs.sucess != 'true' || steps.wildMojang.outputs.sucess != 'true' || steps.wildObf.outputs.sucess != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.19.3 --remapped + # Build Movecraft build: runs-on: ubuntu-latest - needs: [pillage_1_14, nether_1_16, goats_1_17, caves_1_18, wild_1_19] + needs: [pillage_1_14, nether_1_16, goats_1_17, caves_1_18, wild_1_19_2, wild_1_19_3] steps: - - name: Checkout Movecraft - uses: actions/checkout@v1 - - name: Set up JDK 17 - uses: actions/setup-java@v2 - with: - distribution: 'temurin' - java-version: '17' - - name: Cache Maven packages - id: cacheMain - uses: actions/cache@v2 - with: - path: ~/.m2 - key: ${{ runner.os }}-m2 - restore-keys: ${{ runner.os }}-m2 - - name: Cache 1.14.4 Maven package - id: cachePillage - uses: actions/cache@v2 - with: - path: ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/ - key: ${{ runner.os }}-1.14.4 - restore-keys: ${{ runner.os }}-1.14.4 - - name: Cache 1.16.5 Maven package - id: cacheNether - uses: actions/cache@v2 - with: - path: ~/.m2/repository/org/bukkit/craftbukkit/1.16.5-R0.1-SNAPSHOT/ - key: ${{ runner.os }}-1.16.5 - restore-keys: ${{ runner.os }}-1.16.5 - - name: Cache 1.17.1 Maven package - id: cacheGoats - uses: actions/cache@v2 - with: - path: | - ~/.m2/repository/org/spigotmc/spigot/1.17.1-R0.1-SNAPSHOT/ - ~/.m2/repository/org/spigotmc/spigot-parent/ - ~/.m2/repository/org/spigotmc/minecraft-server/ - key: ${{ runner.os }}-spigot-1.17.1-all - restore-keys: ${{ runner.os }}-spigot-1.17.1-all - - name: Cache 1.18.2 Maven package - id: cacheCaves - uses: actions/cache@v2 - with: - path: | - ~/.m2/repository/org/spigotmc/spigot/1.18.2-R0.1-SNAPSHOT/ - ~/.m2/repository/org/spigotmc/spigot-parent/ - ~/.m2/repository/org/spigotmc/minecraft-server/ - key: ${{ runner.os }}-spigot-1.18.2-all - restore-keys: ${{ runner.os }}-spigot-1.18.2-all - - name: Cache 1.19.2 Maven package - id: cacheWild - uses: actions/cache@v2 - with: - path: | - ~/.m2/repository/org/spigotmc/spigot/1.19.2-R0.1-SNAPSHOT/ - ~/.m2/repository/org/spigotmc/spigot-parent/ - ~/.m2/repository/org/spigotmc/minecraft-server/ - key: ${{ runner.os }}-spigot-1.19.2-all - restore-keys: ${{ runner.os }}-spigot-1.19.2-all + - name: Checkout Movecraft + uses: actions/checkout@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + - name: Cache Maven packages + id: cacheMain + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2 + restore-keys: ${{ runner.os }}-m2 + - name: Cache 1.14.4 Maven package + id: cachePillage + uses: actions/cache@v2 + with: + path: ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/ + key: ${{ runner.os }}-1.14.4 + restore-keys: ${{ runner.os }}-1.14.4 + - name: Cache 1.16.5 Maven package + id: cacheNether + uses: actions/cache@v2 + with: + path: ~/.m2/repository/org/bukkit/craftbukkit/1.16.5-R0.1-SNAPSHOT/ + key: ${{ runner.os }}-1.16.5 + restore-keys: ${{ runner.os }}-1.16.5 + - name: Cache 1.17.1 Maven package + id: cacheGoats + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.17.1-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.17.1-all + restore-keys: ${{ runner.os }}-spigot-1.17.1-all + - name: Cache 1.18.2 Maven package + id: cacheCaves + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.18.2-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.18.2-all + restore-keys: ${{ runner.os }}-spigot-1.18.2-all + - name: Cache 1.19.2 Maven package + id: cacheWild_r1 + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.19.2-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.19.2-all + restore-keys: ${{ runner.os }}-spigot-1.19.2-all + - name: Cache 1.19.3 Maven package + id: cacheWild_r2 + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.19.3-all + restore-keys: ${{ runner.os }}-spigot-1.19.3-all - - name: Build with Maven - run: mvn -T 1C -B package --file pom.xml + - name: Build with Maven + run: mvn -T 1C -B package --file pom.xml - - name: Stage jar - run: mkdir staging && cp target/Movecraft.jar staging && mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar - - name: Upload jar - uses: actions/upload-artifact@v2 - with: - name: Movecraft_Dev-Build - path: staging/Movecraft_*.jar + - name: Stage jar + run: mkdir staging && cp target/Movecraft.jar staging && mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar + - name: Upload jar + uses: actions/upload-artifact@v2 + with: + name: Movecraft_Dev-Build + path: staging/Movecraft_*.jar diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 0fc825ace..1e39add12 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -157,7 +157,7 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.18.2 --remapped # Build 1.19.2 NMS - wild_1_19: + wild_1_19_2: runs-on: ubuntu-latest steps: - name: Set up JDK 17 # 1.19.2 can only be built with Java 17 @@ -166,7 +166,7 @@ jobs: distribution: 'temurin' java-version: '17' - name: Cache 1.19.2 Maven package - id: cacheWild + id: cacheWild_r1 uses: actions/cache@v2 with: path: | @@ -198,10 +198,52 @@ jobs: if: steps.wild.outputs.sucess != 'true' || steps.wildMojang.outputs.sucess != 'true' || steps.wildObf.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.19.2 --remapped + # Build 1.19.3 NMS + wild_1_19_3: + runs-on: ubuntu-latest + steps: + - name: Set up JDK 17 # 1.19.3 can only be built with Java 17 + uses: actions/setup-java@v2 + with: + distribution: 'temurin' + java-version: '17' + - name: Cache 1.19.3 Maven package + id: cacheWild_r2 + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.19.3-all + restore-keys: ${{ runner.os }}-spigot-1.19.3-all + - name: Cache Maven packages + id: cacheMain + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2_1.19.3 + restore-keys: ${{ runner.os }}-m2_1.19.3 + + - name: Setup BuildTools + run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + - name: Check 1.19.3 Spigot + id: wild + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Check 1.19.3 Spigot (Mojang) + id: wildMojang + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT-remapped-mojang.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Check 1.19.3 Spigot (Obf) + id: wildObf + run: test -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT-remapped-obf.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.19.3 + if: steps.wild.outputs.sucess != 'true' || steps.wildMojang.outputs.sucess != 'true' || steps.wildObf.outputs.sucess != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.19.3 --remapped + # Build Movecraft publish: runs-on: ubuntu-latest - needs: [pillage_1_14, nether_1_16, goats_1_17, caves_1_18, wild_1_19] + needs: [pillage_1_14, nether_1_16, goats_1_17, caves_1_18, wild_1_19_2, wild_1_19_3] permissions: contents: read packages: write @@ -256,7 +298,7 @@ jobs: key: ${{ runner.os }}-spigot-1.18.2-all restore-keys: ${{ runner.os }}-spigot-1.18.2-all - name: Cache 1.19.2 Maven package - id: cacheWild + id: cacheWild_r1 uses: actions/cache@v2 with: path: | @@ -265,6 +307,16 @@ jobs: ~/.m2/repository/org/spigotmc/minecraft-server/ key: ${{ runner.os }}-spigot-1.19.2-all restore-keys: ${{ runner.os }}-spigot-1.19.2-all + - name: Cache 1.19.3 Maven package + id: cacheWild_r2 + uses: actions/cache@v2 + with: + path: | + ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/ + ~/.m2/repository/org/spigotmc/spigot-parent/ + ~/.m2/repository/org/spigotmc/minecraft-server/ + key: ${{ runner.os }}-spigot-1.19.3-all + restore-keys: ${{ runner.os }}-spigot-1.19.3-all - name: Build with Maven run: mvn -T 1C -B package --file pom.xml diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 2ee267887..af49fdd1e 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -68,6 +68,12 @@ ${revision} jar + + net.countercraft + movecraft-v1_19_r2 + ${revision} + jar + net.countercraft movecraft-api @@ -83,18 +89,7 @@ org.yaml snakeyaml - 1.32 - - - org.jetbrains - annotations-java5 - 22.0.0 - - - it.unimi.dsi - fastutil - 8.5.8 - compile + 1.33 @@ -188,6 +183,10 @@ net.kyori net.countercraft.movecraft.libs.net.kyori + + org.roaringbitmap + net.countercraft.movecraft.libs.org.roaringbitmap + true false @@ -222,6 +221,12 @@ ** + + net.countercraft:movecraft-v1_19_r2 + + ** + + net.countercraft:datapack diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 9e2407397..0a911405f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -55,6 +55,8 @@ import net.countercraft.movecraft.sign.StatusSign; import net.countercraft.movecraft.sign.SubcraftRotateSign; import net.countercraft.movecraft.sign.TeleportSign; +import net.countercraft.movecraft.util.BukkitTeleport; +import net.countercraft.movecraft.util.Tags; import net.kyori.adventure.platform.bukkit.BukkitAudiences; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -67,6 +69,7 @@ import java.util.EnumSet; import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.logging.Logger; public class Movecraft extends JavaPlugin { @@ -76,6 +79,7 @@ public class Movecraft extends JavaPlugin { private Logger logger; private boolean shuttingDown; private WorldHandler worldHandler; + private SmoothTeleport smoothTeleport; private AsyncManager asyncManager; public static synchronized Movecraft getInstance() { @@ -84,7 +88,7 @@ public static synchronized Movecraft getInstance() { @NotNull public static BukkitAudiences getAdventure() { - if(adventure == null) + if (adventure == null) throw new IllegalStateException("Tried to access Adventure when the plugin was disabled!"); return adventure; @@ -93,7 +97,7 @@ public static BukkitAudiences getAdventure() { @Override public void onDisable() { shuttingDown = true; - if(adventure != null) { + if (adventure != null) { adventure.close(); adventure = null; } @@ -108,39 +112,58 @@ public void onEnable() { Settings.DisableIceForm = getConfig().getBoolean("DisableIceForm", true); String[] localisations = {"en", "cz", "nl", "fr"}; - for(String s : localisations) { - if(!new File(getDataFolder() + for (String s : localisations) { + if (!new File(getDataFolder() + "/localisation/movecraftlang_" + s + ".properties").exists()) { saveResource("localisation/movecraftlang_" + s + ".properties", false); } } I18nSupport.init(); - - + + // if the PilotTool is specified in the config.yml file, use it String pilotTool = getConfig().getString("PilotTool"); - if(pilotTool != null) { + if (pilotTool != null) { Material material = Material.getMaterial(pilotTool); - if(material != null) { + if (material != null) { logger.info(I18nSupport.getInternationalisedString("Startup - Recognized Pilot Tool") + pilotTool); Settings.PilotTool = material; } - else + else { logger.info(I18nSupport.getInternationalisedString("Startup - No Pilot Tool")); + } } - else + else { logger.info(I18nSupport.getInternationalisedString("Startup - No Pilot Tool")); + } String packageName = getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); try { - final Class clazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IWorldHandler"); + final Class worldHandlerClazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IWorldHandler"); // Check if we have a NMSHandler class at that location. - if (WorldHandler.class.isAssignableFrom(clazz)) // Make sure it actually implements NMS - worldHandler = (WorldHandler) clazz.getConstructor().newInstance(); // Set our handler + if (WorldHandler.class.isAssignableFrom(worldHandlerClazz)) { // Make sure it actually implements NMS + worldHandler = (WorldHandler) worldHandlerClazz.getConstructor().newInstance(); // Set our handler + + // Try to setup the smooth teleport handler + try { + final Class smoothTeleportClazz = Class.forName("net.countercraft.movecraft.support." + version + ".ISmoothTeleport"); + if (SmoothTeleport.class.isAssignableFrom(smoothTeleportClazz)) { + smoothTeleport = (SmoothTeleport) smoothTeleportClazz.getConstructor().newInstance(); + } + else { + smoothTeleport = new BukkitTeleport(); // Fall back to bukkit teleportation + getLogger().warning("Falling back to bukkit teleportation provider."); + } + } + catch (ReflectiveOperationException ignored) { + smoothTeleport = new BukkitTeleport(); // Fall back to bukkit teleportation + getLogger().warning("Falling back to bukkit teleportation provider."); + } + } } - catch(final Exception e) { + catch (final Exception e) { e.printStackTrace(); getLogger().severe(I18nSupport.getInternationalisedString("Startup - Version Not Supported")); setEnabled(false); @@ -162,17 +185,13 @@ public void onEnable() { Settings.FadeWrecksAfter = getConfig().getInt("FadeWrecksAfter", 0); Settings.FadeTickCooldown = getConfig().getInt("FadeTickCooldown", 20); Settings.FadePercentageOfWreckPerCycle = getConfig().getDouble("FadePercentageOfWreckPerCycle", 10.0); - if(getConfig().contains("ExtraFadeTimePerBlock")) { + if (getConfig().contains("ExtraFadeTimePerBlock")) { Map temp = getConfig().getConfigurationSection("ExtraFadeTimePerBlock").getValues(false); - for(String str : temp.keySet()) { - Material type; - try { - type = Material.getMaterial(str); - } - catch(NumberFormatException e) { - type = Material.getMaterial(str); + for (String str : temp.keySet()) { + Set materials = Tags.parseMaterials(str); + for (Material m : materials) { + Settings.ExtraFadeTimePerBlock.put(m, (Integer) temp.get(str)); } - Settings.ExtraFadeTimePerBlock.put(type, (Integer) temp.get(str)); } } @@ -331,6 +350,9 @@ public WorldHandler getWorldHandler(){ return worldHandler; } + public SmoothTeleport getSmoothTeleport() { + return smoothTeleport; + } + public AsyncManager getAsyncManager(){return asyncManager;} } - diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java index b06e93dcd..e3118c255 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java @@ -1,14 +1,14 @@ package net.countercraft.movecraft.commands; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.craft.PilotedCraft; import net.countercraft.movecraft.craft.SinkingCraft; import net.countercraft.movecraft.events.ManOverboardEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.util.MathUtils; -import net.countercraft.movecraft.util.teleport.TeleportUtils; +import net.countercraft.movecraft.util.ReflectUtils; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.command.Command; @@ -73,7 +73,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, player.setVelocity(new Vector(0, 0, 0)); player.setFallDistance(0); - TeleportUtils.teleport(player, telPoint, 0, 0); + Movecraft.getInstance().getSmoothTeleport().teleport(player, telPoint, 0, 0); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 853fde2f1..c334f4e5b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -17,7 +17,8 @@ package net.countercraft.movecraft.mapUpdater.update; -import net.countercraft.movecraft.util.teleport.TeleportUtils; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.util.ReflectUtils; import org.bukkit.Location; import org.bukkit.Sound; import org.bukkit.World; @@ -89,7 +90,7 @@ public void doUpdate() { return; } Location location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); - TeleportUtils.teleport((Player) entity, location, yaw, pitch); + Movecraft.getInstance().getSmoothTeleport().teleport((Player) entity, location, yaw, pitch); if (sound != null) { ((Player) entity).playSound(location, sound, volume, 1.0f); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/AbstractTeleport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/AbstractTeleport.java deleted file mode 100644 index 90c15055f..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/AbstractTeleport.java +++ /dev/null @@ -1,14 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -public abstract class AbstractTeleport { - - public static boolean initialize() { - return false; - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/SpigotMappedTeleport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/SpigotMappedTeleport.java deleted file mode 100644 index 855a62cee..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/SpigotMappedTeleport.java +++ /dev/null @@ -1,119 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Set; - -/** - * Code taken with permission from MicleBrick - * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ - * Used for 1.14.4 to 1.16.5 - */ -public class SpigotMappedTeleport extends AbstractTeleport { - private static Set teleportFlags; - - private static Constructor packetConstructor; - private static Constructor vec3D; - - private static Method position; - private static Method sendMethod; - - private static Field connectionField; - private static Field justTeleportedField; - private static Field teleportPosField; - private static Field lastPosXField; - private static Field lastPosYField; - private static Field lastPosZField; - private static Field teleportAwaitField; - private static Field AField; - private static Field eField; - private static Field yaw; - private static Field pitch; - - private static @NotNull Class getNmsClass(String name) throws ClassNotFoundException { - return Class.forName("net.minecraft.server." + TeleportUtils.getVersion() + "." + name); - } - - private static void sendPacket(Object packet, Player p) { - try { - Object handle = TeleportUtils.getHandle(p); - Object pConnection = connectionField.get(handle); - sendMethod.invoke(pConnection, packet); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public static boolean initialize() { - boolean success = false; - try { - Class packet = getNmsClass("Packet"); - Class entity = getNmsClass("Entity"); - Class entityPlayer = getNmsClass("EntityPlayer"); - Class connectionClass = getNmsClass("PlayerConnection"); - Class packetClass = getNmsClass("PacketPlayOutPosition"); - Class vecClass = getNmsClass("Vec3D"); - sendMethod = connectionClass.getMethod("sendPacket", packet); - - position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); - - yaw = TeleportUtils.getField(entity, "yaw"); - pitch = TeleportUtils.getField(entity, "pitch"); - connectionField = TeleportUtils.getField(entityPlayer, "playerConnection"); - - packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); - vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); - - Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); - teleportFlags = Set.of(enumObjects[4], enumObjects[3]); - - justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported"); - teleportPosField = TeleportUtils.getField(connectionClass, "teleportPos"); - lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX"); - lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY"); - lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ"); - teleportAwaitField = TeleportUtils.getField(connectionClass, "teleportAwait"); - AField = TeleportUtils.getField(connectionClass, "A"); - eField = TeleportUtils.getField(connectionClass, "e"); - success = true; - } - catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException | SecurityException e) { - e.printStackTrace(); - } - return success; - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - Object handle = TeleportUtils.getHandle(player); - try { - position.invoke(handle, x, y, z, yaw.get(handle), pitch.get(handle)); - Object connection = connectionField.get(handle); - justTeleportedField.set(connection, true); - teleportPosField.set(connection, vec3D.newInstance(x, y, z)); - lastPosXField.set(connection, x); - lastPosYField.set(connection, y); - lastPosZField.set(connection, z); - int teleportAwait = teleportAwaitField.getInt(connection) + 1; - if (teleportAwait == Integer.MAX_VALUE) - teleportAwait = 0; - teleportAwaitField.set(connection, teleportAwait); - AField.set(connection, eField.get(connection)); - - Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait); - sendPacket(packet, player); - } - catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) { - e.printStackTrace(); - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/TeleportUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/TeleportUtils.java deleted file mode 100644 index 877715084..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/TeleportUtils.java +++ /dev/null @@ -1,101 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import net.countercraft.movecraft.Movecraft; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -/** - * Code taken with permission from MicleBrick - * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ - */ -public class TeleportUtils { - protected static @Nullable Object getHandle(Entity entity) { - try { - Method entity_getHandle = entity.getClass().getMethod("getHandle"); - return entity_getHandle.invoke(entity); - } - catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - protected static @NotNull Field getField(@NotNull Class clazz, String name) throws NoSuchFieldException { - Field field = clazz.getDeclaredField(name); - field.setAccessible(true); - return field; - } - - protected static @NotNull String getVersion() { - return Bukkit.getServer().getClass().getPackage().getName().substring(23); - } - - - private enum Mode { - UNINITIALIZED, - FALLBACK, - SPIGOT_MAPPED, - V1_17, - V1_18, - V1_19 - } - - private static Mode mode = Mode.UNINITIALIZED; - - private static void initialize() { - int version = Integer.parseInt(getVersion().split("_")[1]); - if (version < 17 && SpigotMappedTeleport.initialize()) { - mode = Mode.SPIGOT_MAPPED; - } - else if (version <= 17 && V1_17Teleport.initialize()) { - mode = Mode.V1_17; - } - else if (version <= 18 && V1_18Teleport.initialize()) { - mode = Mode.V1_18; - } - else if (version <= 19 && V1_19Teleport.initialize()) { - mode = Mode.V1_19; - } - else { - Bukkit.getLogger().warning("Failed to access internal teleportation handle, switching to fallback"); - mode = Mode.FALLBACK; - } - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { - if (mode == Mode.UNINITIALIZED) - initialize(); - - switch (mode) { - case SPIGOT_MAPPED: - SpigotMappedTeleport.teleport(player, location, yawChange, pitchChange); - break; - case V1_17: - V1_17Teleport.teleport(player, location, yawChange, pitchChange); - break; - case V1_18: - V1_18Teleport.teleport(player, location, yawChange, pitchChange); - break; - case V1_19: - V1_19Teleport.teleport(player, location, yawChange, pitchChange); - break; - case FALLBACK: - Movecraft.getInstance().getWorldHandler().addPlayerLocation(player, - location.getX() - player.getLocation().getX(), - location.getY() - player.getLocation().getY(), - location.getZ() - player.getLocation().getZ(), - yawChange, pitchChange - ); - break; - default: - throw new IllegalStateException("Unknown mode: " + mode); - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_17Teleport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_17Teleport.java deleted file mode 100644 index 0900c1c1d..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_17Teleport.java +++ /dev/null @@ -1,118 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Set; - -/** - * Code derived from code taken with permission from MicleBrick - * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ - * Used for 1.17.1 - */ -public class V1_17Teleport extends AbstractTeleport { - private static Set teleportFlags; - - private static Method positionMethod; - private static Method sendMethod; - - private static Constructor vec3Constructor; - private static Constructor packetConstructor; - - private static Field connectionField; - //private static Field justTeleportedField; - private static Field teleportPosField; - //private static Field lastPosXField; - //private static Field lastPosYField; - //private static Field lastPosZField; - private static Field teleportAwaitField; - private static Field awaitingTeleportTimeField; - private static Field tickCountField; - private static Field yawField; - private static Field pitchField; - - private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { - return Class.forName("net.minecraft." + name); - } - - private static void sendPacket(Object packet, Player p) { - try { - Object handle = TeleportUtils.getHandle(p); - Object pConnection = connectionField.get(handle); - sendMethod.invoke(pConnection, packet); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public static boolean initialize() { - boolean success = false; - try { - Class packetClass = getNmClass("network.protocol.Packet"); - Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket - Class entityClass = getNmClass("world.entity.Entity"); - Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer - Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl - Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 - - Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument - teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT - - positionMethod = entityClass.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo - sendMethod = connectionClass.getMethod("sendPacket", packetClass); // send - - vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); - packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); - - connectionField = TeleportUtils.getField(playerClass, "b"); // connection - //justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported"); - teleportPosField = TeleportUtils.getField(connectionClass, "y"); // awaitingPositionFromClient - //lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX"); - //lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY"); - //lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ"); - teleportAwaitField = TeleportUtils.getField(connectionClass, "z"); // awaitingTeleport - awaitingTeleportTimeField = TeleportUtils.getField(connectionClass, "A"); // awaitingTeleportTime - tickCountField = TeleportUtils.getField(connectionClass, "f"); // tickCount - yawField = TeleportUtils.getField(entityClass, "az"); // xRot - pitchField = TeleportUtils.getField(entityClass, "ay"); // yRot - success = true; - } - catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) { - e.printStackTrace(); - } - return success; - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - Object handle = TeleportUtils.getHandle(player); - try { - positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); - Object connection = connectionField.get(handle); - //justTeleportedField.set(connection, true); - teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); - //lastPosXField.set(connection, x); - //lastPosYField.set(connection, y); - //lastPosZField.set(connection, z); - int teleportAwait = teleportAwaitField.getInt(connection) + 1; - if (teleportAwait == Integer.MAX_VALUE) - teleportAwait = 0; - teleportAwaitField.setInt(connection, teleportAwait); - awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); - - Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); - sendPacket(packet, player); - } - catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - e.printStackTrace(); - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_18Teleport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_18Teleport.java deleted file mode 100644 index 5255d6eea..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_18Teleport.java +++ /dev/null @@ -1,118 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Set; - -/** - * Code derived from code taken with permission from MicleBrick - * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ - * Used for 1.18.2 - */ -public class V1_18Teleport extends AbstractTeleport { - private static Set teleportFlags; - - private static Method positionMethod; - private static Method sendMethod; - - private static Constructor vec3Constructor; - private static Constructor packetConstructor; - - private static Field connectionField; - //private static Field justTeleportedField; - private static Field teleportPosField; - //private static Field lastPosXField; - //private static Field lastPosYField; - //private static Field lastPosZField; - private static Field teleportAwaitField; - private static Field awaitingTeleportTimeField; - private static Field tickCountField; - private static Field yawField; - private static Field pitchField; - - private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { - return Class.forName("net.minecraft." + name); - } - - private static void sendPacket(Object packet, Player p) { - try { - Object handle = TeleportUtils.getHandle(p); - Object pConnection = connectionField.get(handle); - sendMethod.invoke(pConnection, packet); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public static boolean initialize() { - boolean success = false; - try { - Class packetClass = getNmClass("network.protocol.Packet"); - Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket - Class entityClass = getNmClass("world.entity.Entity"); - Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer - Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl - Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 - - Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument - teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT - - positionMethod = entityClass.getDeclaredMethod("a", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo - sendMethod = connectionClass.getMethod("a", packetClass); // send - - vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); - packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); - - connectionField = TeleportUtils.getField(playerClass, "b"); // connection - //justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported"); // justTeleported - teleportPosField = TeleportUtils.getField(connectionClass, "y"); // awaitingPositionFromClient - //lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX"); // lastPosX - //lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY"); // lastPosY - //lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ"); // lastPosZ - teleportAwaitField = TeleportUtils.getField(connectionClass, "z"); // awaitingTeleport - awaitingTeleportTimeField = TeleportUtils.getField(connectionClass, "A"); // awaitingTeleportTime - tickCountField = TeleportUtils.getField(connectionClass, "f"); // tickCount - yawField = TeleportUtils.getField(entityClass, "aB"); // xRot - pitchField = TeleportUtils.getField(entityClass, "aA"); // yRot - success = true; - } - catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) { - e.printStackTrace(); - } - return success; - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - Object handle = TeleportUtils.getHandle(player); - try { - positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); - Object connection = connectionField.get(handle); - //justTeleportedField.set(connection, true); - teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); - //lastPosXField.set(connection, x); - //lastPosYField.set(connection, y); - //lastPosZField.set(connection, z); - int teleportAwait = teleportAwaitField.getInt(connection) + 1; - if (teleportAwait == Integer.MAX_VALUE) - teleportAwait = 0; - teleportAwaitField.setInt(connection, teleportAwait); - awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); - - Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); - sendPacket(packet, player); - } - catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - e.printStackTrace(); - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_19Teleport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_19Teleport.java deleted file mode 100644 index 67e3eabd5..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/util/teleport/V1_19Teleport.java +++ /dev/null @@ -1,118 +0,0 @@ -package net.countercraft.movecraft.util.teleport; - -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Set; - -/** - * Code derived from code taken with permission from MicleBrick - * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ - * Used for 1.19.1 - */ -public class V1_19Teleport extends AbstractTeleport { - private static Set teleportFlags; - - private static Method positionMethod; - private static Method sendMethod; - - private static Constructor vec3Constructor; - private static Constructor packetConstructor; - - private static Field connectionField; - //private static Field justTeleportedField; - private static Field teleportPosField; - //private static Field lastPosXField; - //private static Field lastPosYField; - //private static Field lastPosZField; - private static Field teleportAwaitField; - private static Field awaitingTeleportTimeField; - private static Field tickCountField; - private static Field yawField; - private static Field pitchField; - - private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { - return Class.forName("net.minecraft." + name); - } - - private static void sendPacket(Object packet, Player p) { - try { - Object handle = TeleportUtils.getHandle(p); - Object pConnection = connectionField.get(handle); - sendMethod.invoke(pConnection, packet); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - public static boolean initialize() { - boolean success = false; - try { - Class packetClass = getNmClass("network.protocol.Packet"); - Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket - Class entityClass = getNmClass("world.entity.Entity"); - Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer - Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl - Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 - - Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument - teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT - - positionMethod = entityClass.getDeclaredMethod("a", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo - sendMethod = connectionClass.getMethod("a", packetClass); // send - - vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); - packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); - - connectionField = TeleportUtils.getField(playerClass, "b"); // connection - //justTeleportedField = TeleportUtils.getField(connectionClass, "justTeleported"); // justTeleported - teleportPosField = TeleportUtils.getField(connectionClass, "C"); // awaitingPositionFromClient - //lastPosXField = TeleportUtils.getField(connectionClass, "lastPosX"); // lastPosX - //lastPosYField = TeleportUtils.getField(connectionClass, "lastPosY"); // lastPosY - //lastPosZField = TeleportUtils.getField(connectionClass, "lastPosZ"); // lastPosZ - teleportAwaitField = TeleportUtils.getField(connectionClass, "D"); // awaitingTeleport - awaitingTeleportTimeField = TeleportUtils.getField(connectionClass, "E"); // awaitingTeleportTime - tickCountField = TeleportUtils.getField(connectionClass, "i"); // tickCount - yawField = TeleportUtils.getField(entityClass, "aB"); // xRot - pitchField = TeleportUtils.getField(entityClass, "aA"); // yRot - success = true; - } - catch (ClassNotFoundException | NoSuchFieldException | NoSuchMethodException e) { - e.printStackTrace(); - } - return success; - } - - public static void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - Object handle = TeleportUtils.getHandle(player); - try { - positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); - Object connection = connectionField.get(handle); - //justTeleportedField.set(connection, true); - teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); - //lastPosXField.set(connection, x); - //lastPosYField.set(connection, y); - //lastPosZField.set(connection, z); - int teleportAwait = teleportAwaitField.getInt(connection) + 1; - if (teleportAwait == Integer.MAX_VALUE) - teleportAwait = 0; - teleportAwaitField.setInt(connection, teleportAwait); - awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); - - Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); - sendPacket(packet, player); - } - catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { - e.printStackTrace(); - } - } -} diff --git a/modules/api/pom.xml b/modules/api/pom.xml index be302e2d7..8dab7d303 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -7,7 +7,7 @@ UTF-8 - 5.8.2 + 5.9.0 ${junit.jupiter.version} 1.2.0 4.13.2 @@ -80,24 +80,24 @@ org.roaringbitmap RoaringBitmap - 0.9.27 + 0.9.32 compile it.unimi.dsi fastutil - 8.5.8 + 8.5.9 compile net.kyori adventure-api - 4.10.1 + 4.12.0 net.kyori adventure-platform-bukkit - 4.1.0 + 4.1.2 @@ -185,4 +185,4 @@ - \ No newline at end of file + diff --git a/modules/api/src/main/java/net/countercraft/movecraft/SmoothTeleport.java b/modules/api/src/main/java/net/countercraft/movecraft/SmoothTeleport.java new file mode 100644 index 000000000..f6e9e898c --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/SmoothTeleport.java @@ -0,0 +1,9 @@ +package net.countercraft.movecraft; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public abstract class SmoothTeleport { + public abstract void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange); +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java index e5c110e53..6957f4d35 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -14,8 +14,4 @@ public abstract class WorldHandler { public abstract void setBlockFast(@NotNull Location location, @NotNull BlockData data); public abstract void setBlockFast(@NotNull Location location, @NotNull MovecraftRotation rotation, @NotNull BlockData data); public abstract void disableShadow(@NotNull Material type); - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - Location playerLoc = player.getLocation(); - player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java b/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java deleted file mode 100644 index d920db274..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.config; - -import org.bukkit.configuration.file.FileConfiguration; - -import java.util.ArrayList; -import java.util.List; - -class ConfigManager { - private final FileConfiguration configFile; - - public ConfigManager(FileConfiguration configFile) { - this.configFile = configFile; - } - - public void loadConfig() { - setupDefaults(); - Settings.DATA_BLOCKS = configFile.getIntegerList("dataBlocks"); - Settings.THREAD_POOL_SIZE = configFile.getInt("ThreadPoolSize"); - Settings.IGNORE_RESET = configFile.getBoolean("safeReload"); - - } - - private void setupDefaults() { - configFile.addDefault("ThreadPoolSize", 5); - configFile.addDefault("safeReload", false); - List dataBlockList = new ArrayList<>(); - dataBlockList.add(23); - dataBlockList.add(25); - dataBlockList.add(33); - dataBlockList.add(44); - dataBlockList.add(50); - dataBlockList.add(53); - dataBlockList.add(54); - dataBlockList.add(55); - dataBlockList.add(61); - dataBlockList.add(62); - dataBlockList.add(63); - dataBlockList.add(64); - dataBlockList.add(65); - configFile.addDefault("dataBlocks", dataBlockList); - configFile.options().copyDefaults(true); - //Movecraft.getInstance().saveConfig(); - } -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/util/BukkitTeleport.java b/modules/api/src/main/java/net/countercraft/movecraft/util/BukkitTeleport.java new file mode 100644 index 000000000..7bc69dc9e --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/util/BukkitTeleport.java @@ -0,0 +1,15 @@ +package net.countercraft.movecraft.util; + +import net.countercraft.movecraft.SmoothTeleport; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class BukkitTeleport extends SmoothTeleport { + @Override + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + location.setYaw(player.getLocation().getYaw() + yawChange); + location.setPitch(player.getLocation().getPitch() + pitchChange); + player.teleport(location); + } +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/util/ReflectUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/util/ReflectUtils.java new file mode 100644 index 000000000..e3c519a07 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/util/ReflectUtils.java @@ -0,0 +1,36 @@ +package net.countercraft.movecraft.util; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Entity; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +/** + * Code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + */ +public class ReflectUtils { + public static @Nullable Object getHandle(Entity entity) { + try { + Method entity_getHandle = entity.getClass().getMethod("getHandle"); + return entity_getHandle.invoke(entity); + } + catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + public static @NotNull Field getField(@NotNull Class clazz, String name) throws NoSuchFieldException { + Field field = clazz.getDeclaredField(name); + field.setAccessible(true); + return field; + } + + public static @NotNull String getVersion() { + return Bukkit.getServer().getClass().getPackage().getName().substring(23); + } +} diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index b5aa74d8f..ff64a02d2 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -55,39 +55,10 @@ public class IWorldHandler extends WorldHandler { ROTATION[MovecraftRotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; } - private MethodHandle internalTeleportMH; - public IWorldHandler() { String mappings = ((CraftMagicNumbers) CraftMagicNumbers.INSTANCE).getMappingsVersion(); if (!mappings.equals("11ae498d9cf909730659b6357e7c2afa")) throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft 1.14: " + mappings); - - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Method teleport; - try { - teleport = PlayerConnection.class.getDeclaredMethod("a", double.class, double.class, double.class, float.class, float.class, Set.class); - teleport.setAccessible(true); - internalTeleportMH = lookup.unreflect(teleport); - } - catch (NoSuchMethodException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch) { - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if (internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; - } - try { - internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); - } - catch (Throwable throwable) { - throwable.printStackTrace(); - } } @Override diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/support/v1_14_R1/ISmoothTeleport.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/support/v1_14_R1/ISmoothTeleport.java new file mode 100644 index 000000000..f69e195e3 --- /dev/null +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/support/v1_14_R1/ISmoothTeleport.java @@ -0,0 +1,113 @@ +package net.countercraft.movecraft.support.v1_14_R1; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.14.4 to 1.16.5 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Constructor packetConstructor; + private final Constructor vec3D; + + private final Method position; + private final Method sendMethod; + + private final Field connectionField; + private final Field justTeleportedField; + private final Field teleportPosField; + private final Field lastPosXField; + private final Field lastPosYField; + private final Field lastPosZField; + private final Field teleportAwaitField; + private final Field AField; + private final Field eField; + private final Field yaw; + private final Field pitch; + + private static @NotNull Class getNmsClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft.server." + ReflectUtils.getVersion() + "." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { + Class packet = getNmsClass("Packet"); + Class entity = getNmsClass("Entity"); + Class entityPlayer = getNmsClass("EntityPlayer"); + Class connectionClass = getNmsClass("PlayerConnection"); + Class packetClass = getNmsClass("PacketPlayOutPosition"); + Class vecClass = getNmsClass("Vec3D"); + sendMethod = connectionClass.getMethod("sendPacket", packet); + + position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); + + yaw = ReflectUtils.getField(entity, "yaw"); + pitch = ReflectUtils.getField(entity, "pitch"); + connectionField = ReflectUtils.getField(entityPlayer, "playerConnection"); + + packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); + vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + + Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); + teleportFlags = Set.of(enumObjects[4], enumObjects[3]); + + justTeleportedField = ReflectUtils.getField(connectionClass, "justTeleported"); + teleportPosField = ReflectUtils.getField(connectionClass, "teleportPos"); + lastPosXField = ReflectUtils.getField(connectionClass, "lastPosX"); + lastPosYField = ReflectUtils.getField(connectionClass, "lastPosY"); + lastPosZField = ReflectUtils.getField(connectionClass, "lastPosZ"); + teleportAwaitField = ReflectUtils.getField(connectionClass, "teleportAwait"); + AField = ReflectUtils.getField(connectionClass, "A"); + eField = ReflectUtils.getField(connectionClass, "e"); + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + position.invoke(handle, x, y, z, yaw.get(handle), pitch.get(handle)); + Object connection = connectionField.get(handle); + justTeleportedField.set(connection, true); + teleportPosField.set(connection, vec3D.newInstance(x, y, z)); + lastPosXField.set(connection, x); + lastPosYField.set(connection, y); + lastPosZField.set(connection, z); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.set(connection, teleportAwait); + AField.set(connection, eField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait); + sendPacket(packet, player); + } + catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) { + e.printStackTrace(); + } + } +} diff --git a/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java index 3e6d871b9..bc68a831f 100644 --- a/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java +++ b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java @@ -55,40 +55,10 @@ public class IWorldHandler extends WorldHandler { ROTATION[MovecraftRotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; } - private MethodHandle internalTeleportMH; - public IWorldHandler() { String mappings = ((CraftMagicNumbers) CraftMagicNumbers.INSTANCE).getMappingsVersion(); if (!mappings.equals("d4b392244df170796f8779ef0fc1f2e9")) throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft 1.16: " + mappings); - - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Method teleport = null; - try { - teleport = PlayerConnection.class.getDeclaredMethod("a", double.class, double.class, double.class, float.class, float.class, Set.class); - teleport.setAccessible(true); - internalTeleportMH = lookup.unreflect(teleport); - - } - catch (NoSuchMethodException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch) { - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if (internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; - } - try { - internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); - } - catch (Throwable throwable) { - throwable.printStackTrace(); - } } @Override diff --git a/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/support/v1_16_R3/ISmoothTeleport.java b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/support/v1_16_R3/ISmoothTeleport.java new file mode 100644 index 000000000..ef6e4d848 --- /dev/null +++ b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/support/v1_16_R3/ISmoothTeleport.java @@ -0,0 +1,113 @@ +package net.countercraft.movecraft.support.v1_16_R3; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.14.4 to 1.16.5 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Constructor packetConstructor; + private final Constructor vec3D; + + private final Method position; + private final Method sendMethod; + + private final Field connectionField; + private final Field justTeleportedField; + private final Field teleportPosField; + private final Field lastPosXField; + private final Field lastPosYField; + private final Field lastPosZField; + private final Field teleportAwaitField; + private final Field AField; + private final Field eField; + private final Field yaw; + private final Field pitch; + + private static @NotNull Class getNmsClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft.server." + ReflectUtils.getVersion() + "." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { + Class packet = getNmsClass("Packet"); + Class entity = getNmsClass("Entity"); + Class entityPlayer = getNmsClass("EntityPlayer"); + Class connectionClass = getNmsClass("PlayerConnection"); + Class packetClass = getNmsClass("PacketPlayOutPosition"); + Class vecClass = getNmsClass("Vec3D"); + sendMethod = connectionClass.getMethod("sendPacket", packet); + + position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); + + yaw = ReflectUtils.getField(entity, "yaw"); + pitch = ReflectUtils.getField(entity, "pitch"); + connectionField = ReflectUtils.getField(entityPlayer, "playerConnection"); + + packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); + vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + + Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); + teleportFlags = Set.of(enumObjects[4], enumObjects[3]); + + justTeleportedField = ReflectUtils.getField(connectionClass, "justTeleported"); + teleportPosField = ReflectUtils.getField(connectionClass, "teleportPos"); + lastPosXField = ReflectUtils.getField(connectionClass, "lastPosX"); + lastPosYField = ReflectUtils.getField(connectionClass, "lastPosY"); + lastPosZField = ReflectUtils.getField(connectionClass, "lastPosZ"); + teleportAwaitField = ReflectUtils.getField(connectionClass, "teleportAwait"); + AField = ReflectUtils.getField(connectionClass, "A"); + eField = ReflectUtils.getField(connectionClass, "e"); + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + position.invoke(handle, x, y, z, yaw.get(handle), pitch.get(handle)); + Object connection = connectionField.get(handle); + justTeleportedField.set(connection, true); + teleportPosField.set(connection, vec3D.newInstance(x, y, z)); + lastPosXField.set(connection, x); + lastPosYField.set(connection, y); + lastPosZField.set(connection, z); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.set(connection, teleportAwait); + AField.set(connection, eField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait); + sendPacket(packet, player); + } + catch (IllegalAccessException | IllegalArgumentException | InstantiationException | InvocationTargetException e) { + e.printStackTrace(); + } + } +} diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/support/v1_17_R1/ISmoothTeleport.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/support/v1_17_R1/ISmoothTeleport.java new file mode 100644 index 000000000..5b0903668 --- /dev/null +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/support/v1_17_R1/ISmoothTeleport.java @@ -0,0 +1,100 @@ +package net.countercraft.movecraft.support.v1_17_R1; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code derived from code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.17.1 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Method positionMethod; + private final Method sendMethod; + + private final Constructor vec3Constructor; + private final Constructor packetConstructor; + + private final Field connectionField; + private final Field teleportPosField; + private final Field teleportAwaitField; + private final Field awaitingTeleportTimeField; + private final Field tickCountField; + private final Field yawField; + private final Field pitchField; + + private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException { + Class packetClass = getNmClass("network.protocol.Packet"); + Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket + Class entityClass = getNmClass("world.entity.Entity"); + Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer + Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl + Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 + + Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument + teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT + + positionMethod = entityClass.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo + sendMethod = connectionClass.getMethod("sendPacket", packetClass); // send + + vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); + + connectionField = ReflectUtils.getField(playerClass, "b"); // connection + teleportPosField = ReflectUtils.getField(connectionClass, "y"); // awaitingPositionFromClient + teleportAwaitField = ReflectUtils.getField(connectionClass, "z"); // awaitingTeleport + awaitingTeleportTimeField = ReflectUtils.getField(connectionClass, "A"); // awaitingTeleportTime + tickCountField = ReflectUtils.getField(connectionClass, "f"); // tickCount + yawField = ReflectUtils.getField(entityClass, "az"); // xRot + pitchField = ReflectUtils.getField(entityClass, "ay"); // yRot + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); + Object connection = connectionField.get(handle); + teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.setInt(connection, teleportAwait); + awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); + sendPacket(packet, player); + } + catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + e.printStackTrace(); + } + } +} diff --git a/modules/v1_18_R2/pom.xml b/modules/v1_18_R2/pom.xml index d896c8c11..ce1947274 100644 --- a/modules/v1_18_R2/pom.xml +++ b/modules/v1_18_R2/pom.xml @@ -20,6 +20,7 @@ 1.18.2-R0.1-SNAPSHOT remapped-mojang provided + net.countercraft diff --git a/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/compat/v1_18_R2/IWorldHandler.java b/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/compat/v1_18_R2/IWorldHandler.java index 505833525..1d70ba93a 100644 --- a/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/compat/v1_18_R2/IWorldHandler.java +++ b/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/compat/v1_18_R2/IWorldHandler.java @@ -52,12 +52,6 @@ public IWorldHandler() { throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft 1.18: " + mappings); } -// @Override -// public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ -// ServerPlayer ePlayer = ((CraftPlayer) player).getHandle(); -// ePlayer.connection.teleport(x, y, z, yaw, pitch, EnumSet.allOf(ClientboundPlayerPositionPacket.RelativeArgument.class)); -// } - @Override public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull MovecraftRotation rotation) { //******************************************* diff --git a/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/support/v1_18_R2/ISmoothTeleport.java b/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/support/v1_18_R2/ISmoothTeleport.java new file mode 100644 index 000000000..3f123aec3 --- /dev/null +++ b/modules/v1_18_R2/src/main/java/net/countercraft/movecraft/support/v1_18_R2/ISmoothTeleport.java @@ -0,0 +1,100 @@ +package net.countercraft.movecraft.support.v1_18_R2; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code derived from code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.18.2 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Method positionMethod; + private final Method sendMethod; + + private final Constructor vec3Constructor; + private final Constructor packetConstructor; + + private final Field connectionField; + private final Field teleportPosField; + private final Field teleportAwaitField; + private final Field awaitingTeleportTimeField; + private final Field tickCountField; + private final Field yawField; + private final Field pitchField; + + private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { + Class packetClass = getNmClass("network.protocol.Packet"); + Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket + Class entityClass = getNmClass("world.entity.Entity"); + Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer + Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl + Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 + + Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument + teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT + + positionMethod = entityClass.getDeclaredMethod("a", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo + sendMethod = connectionClass.getMethod("a", packetClass); // send + + vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); + + connectionField = ReflectUtils.getField(playerClass, "b"); // connection + teleportPosField = ReflectUtils.getField(connectionClass, "y"); // awaitingPositionFromClient + teleportAwaitField = ReflectUtils.getField(connectionClass, "z"); // awaitingTeleport + awaitingTeleportTimeField = ReflectUtils.getField(connectionClass, "A"); // awaitingTeleportTime + tickCountField = ReflectUtils.getField(connectionClass, "f"); // tickCount + yawField = ReflectUtils.getField(entityClass, "aB"); // xRot + pitchField = ReflectUtils.getField(entityClass, "aA"); // yRot + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); + Object connection = connectionField.get(handle); + teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.setInt(connection, teleportAwait); + awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); + sendPacket(packet, player); + } + catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + e.printStackTrace(); + } + } +} diff --git a/modules/v1_19_R1/pom.xml b/modules/v1_19_R1/pom.xml index 2bc1384a7..faea18a95 100644 --- a/modules/v1_19_R1/pom.xml +++ b/modules/v1_19_R1/pom.xml @@ -20,6 +20,7 @@ 1.19.2-R0.1-SNAPSHOT remapped-mojang provided + net.countercraft diff --git a/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/compat/v1_19_R1/IWorldHandler.java b/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/compat/v1_19_R1/IWorldHandler.java index 1530bf7aa..e8dcad3df 100644 --- a/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/compat/v1_19_R1/IWorldHandler.java +++ b/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/compat/v1_19_R1/IWorldHandler.java @@ -52,12 +52,6 @@ public IWorldHandler() { throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft 1.19: " + mappings); } -// @Override -// public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ -// ServerPlayer ePlayer = ((CraftPlayer) player).getHandle(); -// ePlayer.connection.teleport(x, y, z, yaw, pitch, EnumSet.allOf(ClientboundPlayerPositionPacket.RelativeArgument.class)); -// } - @Override public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull MovecraftRotation rotation) { //******************************************* diff --git a/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/support/v1_19_R1/ISmoothTeleport.java b/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/support/v1_19_R1/ISmoothTeleport.java new file mode 100644 index 000000000..20345a457 --- /dev/null +++ b/modules/v1_19_R1/src/main/java/net/countercraft/movecraft/support/v1_19_R1/ISmoothTeleport.java @@ -0,0 +1,100 @@ +package net.countercraft.movecraft.support.v1_19_R1; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code derived from code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.19.2 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Method positionMethod; + private final Method sendMethod; + + private final Constructor vec3Constructor; + private final Constructor packetConstructor; + + private final Field connectionField; + private final Field teleportPosField; + private final Field teleportAwaitField; + private final Field awaitingTeleportTimeField; + private final Field tickCountField; + private final Field yawField; + private final Field pitchField; + + private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws ClassNotFoundException, NoSuchMethodException, NoSuchFieldException { + Class packetClass = getNmClass("network.protocol.Packet"); + Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket + Class entityClass = getNmClass("world.entity.Entity"); + Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer + Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl + Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 + + Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument + teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT + + positionMethod = entityClass.getDeclaredMethod("a", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo + sendMethod = connectionClass.getMethod("a", packetClass); // send + + vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); + + connectionField = ReflectUtils.getField(playerClass, "b"); // connection + teleportPosField = ReflectUtils.getField(connectionClass, "C"); // awaitingPositionFromClient + teleportAwaitField = ReflectUtils.getField(connectionClass, "D"); // awaitingTeleport + awaitingTeleportTimeField = ReflectUtils.getField(connectionClass, "E"); // awaitingTeleportTime + tickCountField = ReflectUtils.getField(connectionClass, "i"); // tickCount + yawField = ReflectUtils.getField(entityClass, "aB"); // xRot + pitchField = ReflectUtils.getField(entityClass, "aA"); // yRot + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); + Object connection = connectionField.get(handle); + teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.setInt(connection, teleportAwait); + awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); + sendPacket(packet, player); + } + catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + e.printStackTrace(); + } + } +} diff --git a/modules/v1_19_R2/pom.xml b/modules/v1_19_R2/pom.xml new file mode 100644 index 000000000..10bd81f4e --- /dev/null +++ b/modules/v1_19_R2/pom.xml @@ -0,0 +1,95 @@ + + + + movecraft-parent + net.countercraft + ${revision} + ../../pom.xml + + 4.0.0 + + movecraft-v1_19_r2 + Movecraft-v1_19_R2 + jar + + + org.spigotmc + spigot + 1.19.3-R0.1-SNAPSHOT + remapped-mojang + provided + + + + net.countercraft + movecraft-api + ${revision} + jar + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + + net/countercraft/movecraft/compat/v1_19_R2/** + net/countercraft/movecraft/support/v1_19_R2/** + + 13 + 13 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_19_R2/** + net/countercraft/movecraft/support/v1_19_R2/** + + + + + net.md-5 + specialsource-maven-plugin + 1.2.2 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.19.3-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.19.3-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + + + \ No newline at end of file diff --git a/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/IWorldHandler.java b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/IWorldHandler.java new file mode 100644 index 000000000..fdaaf94d6 --- /dev/null +++ b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/IWorldHandler.java @@ -0,0 +1,299 @@ +package net.countercraft.movecraft.compat.v1_19_R2; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.util.CollectionUtils; +import net.countercraft.movecraft.util.MathUtils; +import net.countercraft.movecraft.util.UnsafeUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.Rotation; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.ticks.ScheduledTick; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_19_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_19_R2.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unused") +public class IWorldHandler extends WorldHandler { + private static final Rotation ROTATION[]; + + static { + ROTATION = new Rotation[3]; + ROTATION[MovecraftRotation.NONE.ordinal()] = Rotation.NONE; + ROTATION[MovecraftRotation.CLOCKWISE.ordinal()] = Rotation.CLOCKWISE_90; + ROTATION[MovecraftRotation.ANTICLOCKWISE.ordinal()] = Rotation.COUNTERCLOCKWISE_90; + } + + private final NextTickProvider tickProvider = new NextTickProvider(); + + public IWorldHandler() { + String mappings = ((CraftMagicNumbers) CraftMagicNumbers.INSTANCE).getMappingsVersion(); + if (!mappings.equals("1afe2ffe8a9d7fc510442a168b3d4338")) + throw new IllegalStateException("Movecraft is not compatible with this version of Minecraft 1.19: " + mappings); + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull MovecraftRotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + MovecraftRotation counterRotation = rotation == MovecraftRotation.CLOCKWISE ? MovecraftRotation.ANTICLOCKWISE : MovecraftRotation.CLOCKWISE; + for (MovecraftLocation newLocation : craft.getHitBox()) { + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)), locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + ServerLevel nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for (BlockPos position : rotatedPositions.keySet()) { + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(nativeWorld, position); + if (tile == null) + continue; +// tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for (BlockPos position : rotatedPositions.keySet()) { + blockData.put(position, nativeWorld.getBlockState(position).rotate(ROTATION[rotation.ordinal()])); + } + //create the new block + for (Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for (TileHolder tileHolder : tiles) { + moveBlockEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()), tileHolder.getTile()); + if (tileHolder.getNextTick() == null) + continue; + final long currentTime = nativeWorld.N.getGameTime(); // N is obfuscated serverLevelData + nativeWorld.getBlockTicks().schedule(new ScheduledTick<>((Block) tileHolder.getNextTick().type(), rotatedPositions.get(tileHolder.getNextTick().pos()), tileHolder.getNextTick().triggerTick() - currentTime, tileHolder.getNextTick().priority(), tileHolder.getNextTick().subTickOrder())); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(), rotatedPositions.values()); + for (BlockPos position : deletePositions) { + setBlockFast(nativeWorld, position, Blocks.AIR.defaultBlockState()); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add support for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPos translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(craft.getHitBox().size()); + craft.getHitBox().forEach((movecraftLocation) -> positions.add(locationToPosition((movecraftLocation)).subtract(translateVector))); + ServerLevel oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + ServerLevel nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = new ArrayList<>(); + //get the tiles + for (int i = 0, positionsSize = positions.size(); i < positionsSize; i++) { + BlockPos position = positions.get(i); + if (oldNativeWorld.getBlockState(position) == Blocks.AIR.defaultBlockState()) + continue; + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(oldNativeWorld, position); + if (tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(oldNativeWorld, position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for (int i = 0, positionsSize = positions.size(); i < positionsSize; i++) { + BlockPos position = positions.get(i); + blockData.add(oldNativeWorld.getBlockState(position)); + newPositions.add(position.offset(translateVector)); + } + //create the new block + for (int i = 0, positionSize = newPositions.size(); i < positionSize; i++) { + setBlockFast(nativeWorld, newPositions.get(i), blockData.get(i)); + } + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for (int i = 0, tilesSize = tiles.size(); i < tilesSize; i++) { + TileHolder tileHolder = tiles.get(i); + moveBlockEntity(nativeWorld, tileHolder.getTilePosition().offset(translateVector), tileHolder.getTile()); + if (tileHolder.getNextTick() == null) + continue; + final long currentTime = nativeWorld.getGameTime(); + nativeWorld.getBlockTicks().schedule(new ScheduledTick<>((Block) tileHolder.getNextTick().type(), tileHolder.getTilePosition().offset(translateVector), tileHolder.getNextTick().triggerTick() - currentTime, tileHolder.getNextTick().priority(), tileHolder.getNextTick().subTickOrder())); + } + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + List deletePositions = positions; + if (oldNativeWorld == nativeWorld) + deletePositions = CollectionUtils.filter(positions, newPositions); + for (int i = 0, deletePositionsSize = deletePositions.size(); i < deletePositionsSize; i++) { + BlockPos position = deletePositions.get(i); + setBlockFast(oldNativeWorld, position, Blocks.AIR.defaultBlockState()); + } + } + + @Nullable + private BlockEntity removeBlockEntity(@NotNull Level world, @NotNull BlockPos position) { + return world.getChunkAt(position).blockEntities.remove(position); + } + + @NotNull + private BlockPos locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPos(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull Level world, @NotNull BlockPos position, @NotNull BlockState data) { + LevelChunk chunk = world.getChunkAt(position); + int chunkSection = (position.getY() >> 4) - chunk.getMinSection(); + LevelChunkSection section = chunk.getSections()[chunkSection]; + if (section == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + section = chunk.getSections()[chunkSection]; + } + if (section.getBlockState(position.getX() & 15, position.getY() & 15, position.getZ() & 15).equals(data)) { + //Block is already of correct type and data, don't overwrite + return; + } + section.setBlockState(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + world.sendBlockUpdated(position, data, data, 3); + world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.setUnsaved(true); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull BlockData data) { + setBlockFast(location, MovecraftRotation.NONE, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull MovecraftRotation rotation, @NotNull BlockData data) { + BlockState blockData; + if (data instanceof CraftBlockData) { + blockData = ((CraftBlockData) data).getState(); + } + else { + blockData = (BlockState) data; + } + blockData = blockData.rotate(ROTATION[rotation.ordinal()]); + Level world = ((CraftWorld) (location.getWorld())).getHandle(); + BlockPos BlockPos = locationToPosition(MathUtils.bukkit2MovecraftLoc(location)); + setBlockFast(world, BlockPos, blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + // Disabled + } + + private void moveBlockEntity(@NotNull Level nativeWorld, @NotNull BlockPos newPosition, @NotNull BlockEntity tile) { + LevelChunk chunk = nativeWorld.getChunkAt(newPosition); + try { + var positionField = BlockEntity.class.getDeclaredField("o"); // o is obfuscated worldPosition + UnsafeUtils.setField(positionField, tile, newPosition); + } + catch (NoSuchFieldException e) { + e.printStackTrace(); + } + tile.setLevel(nativeWorld); + tile.clearRemoved(); + if (nativeWorld.captureBlockStates) { + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + chunk.setBlockEntity(tile); + chunk.blockEntities.put(newPosition, tile); + } + + private static class TileHolder { + @NotNull + private final BlockEntity tile; + @Nullable + private final ScheduledTick nextTick; + @NotNull + private final BlockPos tilePosition; + + public TileHolder(@NotNull BlockEntity tile, @Nullable ScheduledTick nextTick, @NotNull BlockPos tilePosition) { + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public BlockEntity getTile() { + return tile; + } + + @Nullable + public ScheduledTick getNextTick() { + return nextTick; + } + + @NotNull + public BlockPos getTilePosition() { + return tilePosition; + } + } +} \ No newline at end of file diff --git a/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/NextTickProvider.java b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/NextTickProvider.java new file mode 100644 index 000000000..06f40c453 --- /dev/null +++ b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/compat/v1_19_R2/NextTickProvider.java @@ -0,0 +1,44 @@ +package net.countercraft.movecraft.compat.v1_19_R2; + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.ticks.LevelTicks; +import net.minecraft.world.ticks.ScheduledTick; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Queue; + +public class NextTickProvider { + + @Nullable + public ScheduledTick getNextTick(@NotNull ServerLevel world, @NotNull BlockPos position){ + LevelTicks tickList = world.getBlockTicks(); + var box = BoundingBox.encapsulatingPositions(List.of(position)); + if(box.isEmpty()){ + return null; + } + Queue> toRunThisTick; + try { + Field toRunThisTickField = LevelTicks.class.getDeclaredField("g"); + toRunThisTickField.setAccessible(true); + toRunThisTick = (Queue>) toRunThisTickField.get(tickList); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + return null; + } + for (var iter = toRunThisTick.iterator(); iter.hasNext(); ) { + var next = iter.next(); + if (!next.pos().equals(position)) { + continue; + } + iter.remove(); + return next; + } + return null; + } +} diff --git a/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/IAsyncChunk.java b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/IAsyncChunk.java new file mode 100644 index 000000000..d6cc3a737 --- /dev/null +++ b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/IAsyncChunk.java @@ -0,0 +1,57 @@ +package net.countercraft.movecraft.support.v1_19_R2; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.processing.WorldManager; +import net.countercraft.movecraft.support.AsyncChunk; +import net.minecraft.core.BlockPos; +import org.bukkit.Chunk; +import org.bukkit.Material; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_19_R2.CraftChunk; +import org.bukkit.craftbukkit.v1_19_R2.block.data.CraftBlockData; +import org.jetbrains.annotations.NotNull; + +@SuppressWarnings("unused") +public class IAsyncChunk extends AsyncChunk { + + private final @NotNull LoadingCache stateCache = CacheBuilder.newBuilder().maximumSize(1000).build(new CacheLoader<>() { + @Override + public BlockState load(@NotNull MovecraftLocation movecraftLocation) { + var block = chunk.getBlock(movecraftLocation.getX(), movecraftLocation.getY(), movecraftLocation.getZ()); + return WorldManager.INSTANCE.executeMain(block::getState); + } + }); + + public IAsyncChunk(@NotNull Chunk chunk) { + super(chunk); + } + + @NotNull + @Override + protected CraftChunk adapt(@NotNull org.bukkit.Chunk chunk) { + return (CraftChunk) chunk; + } + + @NotNull + @Override + public BlockState getState(@NotNull MovecraftLocation location) { + return stateCache.getUnchecked(location); + } + + @Override + @NotNull + public Material getType(@NotNull MovecraftLocation location){ + return this.getData(location).getMaterial(); + } + + @Override + @NotNull + public BlockData getData(@NotNull MovecraftLocation location){ + return CraftBlockData.fromData(chunk.getHandle().getBlockState(new BlockPos(location.getX(), location.getY(), location.getZ()))); + } + +} diff --git a/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/ISmoothTeleport.java b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/ISmoothTeleport.java new file mode 100644 index 000000000..9b82d8ec8 --- /dev/null +++ b/modules/v1_19_R2/src/main/java/net/countercraft/movecraft/support/v1_19_R2/ISmoothTeleport.java @@ -0,0 +1,100 @@ +package net.countercraft.movecraft.support.v1_19_R2; + +import net.countercraft.movecraft.SmoothTeleport; +import net.countercraft.movecraft.util.ReflectUtils; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * Code derived from code taken with permission from MicleBrick + * https://www.spigotmc.org/threads/teleport-player-smoothly.317416/ + * Used for 1.19.3 + */ +public class ISmoothTeleport extends SmoothTeleport { + private final Set teleportFlags; + + private final Method positionMethod; + private final Method sendMethod; + + private final Constructor vec3Constructor; + private final Constructor packetConstructor; + + private final Field connectionField; + private final Field teleportPosField; + private final Field teleportAwaitField; + private final Field awaitingTeleportTimeField; + private final Field tickCountField; + private final Field yawField; + private final Field pitchField; + + private static @NotNull Class getNmClass(String name) throws ClassNotFoundException { + return Class.forName("net.minecraft." + name); + } + + private void sendPacket(Object packet, Player p) { + try { + Object handle = ReflectUtils.getHandle(p); + Object pConnection = connectionField.get(handle); + sendMethod.invoke(pConnection, packet); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public ISmoothTeleport() throws NoSuchFieldException, NoSuchMethodException, ClassNotFoundException { + Class packetClass = getNmClass("network.protocol.Packet"); + Class positionPacketClass = getNmClass("network.protocol.game.PacketPlayOutPosition"); // ClientboundPlayerPositionPacket + Class entityClass = getNmClass("world.entity.Entity"); + Class playerClass = getNmClass("server.level.EntityPlayer"); // ServerPlayer + Class connectionClass = getNmClass("server.network.PlayerConnection"); // ServerGamePacketListenerImpl + Class vectorClass = getNmClass("world.phys.Vec3D"); // Vec3 + + Object[] flags = getNmClass("network.protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); // $RelativeArgument + teleportFlags = Set.of(flags[4], flags[3]); // X_ROT, Y_ROT + + positionMethod = entityClass.getDeclaredMethod("a", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); // absMoveTo + sendMethod = connectionClass.getMethod("a", packetClass); // send + + vec3Constructor = vectorClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + packetConstructor = positionPacketClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE); + + connectionField = ReflectUtils.getField(playerClass, "b"); // connection + teleportPosField = ReflectUtils.getField(connectionClass, "D"); // awaitingPositionFromClient + teleportAwaitField = ReflectUtils.getField(connectionClass, "E"); // awaitingTeleport + awaitingTeleportTimeField = ReflectUtils.getField(connectionClass, "F"); // awaitingTeleportTime + tickCountField = ReflectUtils.getField(connectionClass, "j"); // tickCount + yawField = ReflectUtils.getField(entityClass, "aB"); // xRot + pitchField = ReflectUtils.getField(entityClass, "aA"); // yRot + } + + public void teleport(Player player, @NotNull Location location, float yawChange, float pitchChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Object handle = ReflectUtils.getHandle(player); + try { + positionMethod.invoke(handle, x, y, z, yawField.get(handle), pitchField.get(handle)); + Object connection = connectionField.get(handle); + teleportPosField.set(connection, vec3Constructor.newInstance(x, y, z)); + int teleportAwait = teleportAwaitField.getInt(connection) + 1; + if (teleportAwait == Integer.MAX_VALUE) + teleportAwait = 0; + teleportAwaitField.setInt(connection, teleportAwait); + awaitingTeleportTimeField.set(connection, tickCountField.get(connection)); + + Object packet = packetConstructor.newInstance(x, y, z, yawChange, pitchChange, teleportFlags, teleportAwait, false); + sendPacket(packet, player); + } + catch (IllegalAccessException | InvocationTargetException | InstantiationException e) { + e.printStackTrace(); + } + } +} diff --git a/pom.xml b/pom.xml index 64b7236ed..a0fdb4a8c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ http://github.com/apdevteam/Movecraft UTF-8 - 8.0.0-a.9 + 8.0.0-a.10-dev @@ -19,6 +19,7 @@ modules/v1_17_R1 modules/v1_18_R2 modules/v1_19_R1 + modules/v1_19_R2 modules/datapack modules/Movecraft diff --git a/setup.sh b/setup.sh index 327b4c1e5..63f69f1a3 100755 --- a/setup.sh +++ b/setup.sh @@ -40,13 +40,6 @@ else /usr/lib/jvm/temurin-11-jdk-amd64/bin/java -jar BuildTools.jar --rev 1.16.5 --compile craftbukkit fi -# Build 1.17.1 -if [ -f ~/.m2/repository/org/spigotmc/spigot/1.17.1-R0.1-SNAPSHOT/spigot-1.17.1-R0.1-SNAPSHOT.jar ]; then - echo "1.17.1 already exists, skipping build" -else - java -jar BuildTools.jar --rev 1.17.1 --remapped -fi - # Build 1.18.2 if [ -f ~/.m2/repository/org/spigotmc/spigot/1.18.2-R0.1-SNAPSHOT/spigot-1.18.2-R0.1-SNAPSHOT.jar ]; then echo "1.18.2 already exists, skipping build" @@ -54,13 +47,20 @@ else java -jar BuildTools.jar --rev 1.18.2 --remapped fi -# Build 1.19.1 -if [ -f ~/.m2/repository/org/spigotmc/spigot/1.19-R0.1-SNAPSHOT/spigot-1.19.2-R0.1-SNAPSHOT.jar ]; then +# Build 1.19.2 +if [ -f ~/.m2/repository/org/spigotmc/spigot/1.19.2-R0.1-SNAPSHOT/spigot-1.19.2-R0.1-SNAPSHOT.jar ]; then echo "1.19.2 already exists, skipping build" else java -jar BuildTools.jar --rev 1.19.2 --remapped fi +# Build 1.19.3 +if [ -f ~/.m2/repository/org/spigotmc/spigot/1.19.3-R0.1-SNAPSHOT/spigot-1.19.3-R0.1-SNAPSHOT.jar ]; then + echo "1.19.3 already exists, skipping build" +else + java -jar BuildTools.jar --rev 1.19.3 --remapped +fi + # Restore git information git config --global user.name "$git_name" git config --global user.email "$git_email"