From 9362fb88845a09ab2a295255e8db0995d5fe11cd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:55:38 +0000 Subject: [PATCH 1/6] Initial plan From b5c41b5e4b3055155621231c35e5c656647ae48d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:58:40 +0000 Subject: [PATCH 2/6] Add TrajectoryCalculator utility and example usage Co-authored-by: DLandDS <28994412+DLandDS@users.noreply.github.com> --- .../core/util/TrajectoryCalculator.java | 188 ++++++++++++++++++ .../example/command/ExampleCommand.java | 33 +++ 2 files changed, 221 insertions(+) create mode 100644 Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java diff --git a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java new file mode 100644 index 0000000..6dc8c77 --- /dev/null +++ b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java @@ -0,0 +1,188 @@ +package org.rendang.plugin.core.util; + +import org.bukkit.Location; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; + +/** + * Utility class for calculating trajectory physics for launching players or entities. + * Provides methods to calculate the force/velocity needed to land at a specific target location. + */ +public class TrajectoryCalculator { + + /** + * Gravity constant in Minecraft (blocks per tick squared). + * Standard Minecraft gravity is approximately -0.08 blocks/tick² + */ + private static final double GRAVITY = 0.08; + + /** + * Calculates the velocity vector needed to launch a player to land at the center-top of a target block. + * + * @param player The player to be launched + * @param targetBlock The target block where the player should land + * @return The velocity vector to apply to the player, or null if trajectory is impossible + */ + public static Vector calculateForce(Player player, Block targetBlock) { + Location playerLoc = player.getLocation(); + + // Get target location: center of block horizontally, 1 block above the top + Location targetLoc = targetBlock.getLocation().add(0.5, 1.0, 0.5); + + return calculateForce(playerLoc, targetLoc); + } + + /** + * Calculates the velocity vector needed to launch from one location to another. + * + * @param from The starting location + * @param to The target location (should be centered and above the block) + * @return The velocity vector to apply, or null if trajectory is impossible + */ + public static Vector calculateForce(Location from, Location to) { + // Calculate horizontal and vertical distances + double deltaX = to.getX() - from.getX(); + double deltaY = to.getY() - from.getY(); + double deltaZ = to.getZ() - from.getZ(); + + // Calculate horizontal distance + double horizontalDistance = Math.sqrt(deltaX * deltaX + deltaZ * deltaZ); + + // If the target is at the same location, return zero velocity + if (horizontalDistance < 0.001) { + return new Vector(0, 0, 0); + } + + // We'll use a fixed launch angle approach + // Try different launch angles to find a valid trajectory + double bestAngle = findBestLaunchAngle(horizontalDistance, deltaY); + + if (Double.isNaN(bestAngle)) { + // If no valid angle found, use a high arc (45 degrees + offset) + bestAngle = Math.toRadians(50); + } + + // Calculate initial velocity magnitude needed for the trajectory + double velocity = calculateInitialVelocity(horizontalDistance, deltaY, bestAngle); + + // Calculate velocity components + double horizontalVelocity = velocity * Math.cos(bestAngle); + double verticalVelocity = velocity * Math.sin(bestAngle); + + // Calculate directional velocity components + double velocityX = (deltaX / horizontalDistance) * horizontalVelocity; + double velocityZ = (deltaZ / horizontalDistance) * horizontalVelocity; + + return new Vector(velocityX, verticalVelocity, velocityZ); + } + + /** + * Finds the best launch angle for a given horizontal distance and height difference. + * Uses the projectile motion equations to find a valid angle. + * + * @param horizontalDistance The horizontal distance to the target + * @param deltaY The vertical distance to the target (can be negative) + * @return The launch angle in radians, or NaN if no valid angle exists + */ + private static double findBestLaunchAngle(double horizontalDistance, double deltaY) { + // Try to find an angle that works well + // We prefer lower angles for shorter distances and higher angles for longer distances + + // The ideal angle for maximum range on flat ground is 45 degrees + // We'll adjust based on the height difference + + double baseAngle = Math.toRadians(45); + + // Adjust angle based on height difference + if (deltaY > 0) { + // Target is higher, use a steeper angle + baseAngle = Math.toRadians(60); + } else if (deltaY < -5) { + // Target is much lower, use a shallower angle + baseAngle = Math.toRadians(30); + } + + return baseAngle; + } + + /** + * Calculates the initial velocity magnitude needed for a projectile to reach a target. + * Uses the projectile motion equation: + * R = (v² * sin(2θ)) / g (horizontal range) + * H = (v² * sin²(θ)) / (2g) (max height) + * + * @param horizontalDistance The horizontal distance to the target + * @param deltaY The vertical distance to the target + * @param angle The launch angle in radians + * @return The initial velocity magnitude + */ + private static double calculateInitialVelocity(double horizontalDistance, double deltaY, double angle) { + // Using the trajectory equation: y = x*tan(θ) - (g*x²)/(2*v²*cos²(θ)) + // Solving for v: v² = (g*x²)/(2*cos²(θ)*(x*tan(θ) - y)) + + double cosAngle = Math.cos(angle); + double tanAngle = Math.tan(angle); + + double numerator = GRAVITY * horizontalDistance * horizontalDistance; + double denominator = 2 * cosAngle * cosAngle * (horizontalDistance * tanAngle - deltaY); + + // Prevent division by zero or negative values + if (denominator <= 0) { + // Fallback calculation using energy consideration + return Math.sqrt(2 * GRAVITY * (horizontalDistance + Math.abs(deltaY))); + } + + double velocitySquared = numerator / denominator; + + // Ensure velocity is positive + if (velocitySquared < 0) { + return Math.sqrt(GRAVITY * horizontalDistance); + } + + return Math.sqrt(velocitySquared); + } + + /** + * Alternative method using fixed time-of-flight approach. + * This method assumes a specific time to reach the target and calculates velocities accordingly. + * + * @param player The player to be launched + * @param targetBlock The target block where the player should land + * @param timeInTicks The desired time of flight in ticks (20 ticks = 1 second) + * @return The velocity vector to apply to the player + */ + public static Vector calculateForceWithTime(Player player, Block targetBlock, int timeInTicks) { + Location playerLoc = player.getLocation(); + Location targetLoc = targetBlock.getLocation().add(0.5, 1.0, 0.5); + + return calculateForceWithTime(playerLoc, targetLoc, timeInTicks); + } + + /** + * Calculates velocity using a time-based approach. + * + * @param from The starting location + * @param to The target location + * @param timeInTicks The desired time of flight in ticks + * @return The velocity vector to apply + */ + public static Vector calculateForceWithTime(Location from, Location to, int timeInTicks) { + double time = timeInTicks; // Time in ticks + + // Calculate displacement + double deltaX = to.getX() - from.getX(); + double deltaY = to.getY() - from.getY(); + double deltaZ = to.getZ() - from.getZ(); + + // Calculate horizontal velocities (constant velocity) + double velocityX = deltaX / time; + double velocityZ = deltaZ / time; + + // Calculate vertical velocity using: deltaY = v_y * t - 0.5 * g * t² + // Solving for v_y: v_y = (deltaY + 0.5 * g * t²) / t + double velocityY = (deltaY + 0.5 * GRAVITY * time * time) / time; + + return new Vector(velocityX, velocityY, velocityZ); + } +} diff --git a/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java b/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java index 89f25dd..1c54a5d 100644 --- a/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java +++ b/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java @@ -1,9 +1,13 @@ package org.rendang.plugin.example.command; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.util.Vector; import org.rendang.plugin.core.commands.RendangCommand; import org.rendang.plugin.core.commands.annotation.AutoComplete; import org.rendang.plugin.core.commands.annotation.CommandExecute; import org.rendang.plugin.core.commands.event.CommandEvent; +import org.rendang.plugin.core.util.TrajectoryCalculator; import org.rendang.plugin.example.ExampleConfigType; import org.rendang.plugin.example.ExampleMessageType; import org.rendang.plugin.example.ExamplePlugin; @@ -55,4 +59,33 @@ public boolean reload(CommandEvent event) { event.getSender().sendMessage(config.parse(ExampleMessageType.CONFIG_RELOADED)); return true; } + + @CommandExecute(command = "launch", usages = "", description = "Launch player to target block") + public boolean launch(CommandEvent event) { + if (!(event.getSender() instanceof Player player)) { + event.getSender().sendMessage("This command can only be used by a player!"); + return false; + } + + // Get the block the player is looking at + Block targetBlock = player.getTargetBlockExact(100); + if (targetBlock == null) { + player.sendMessage("You must be looking at a block!"); + return false; + } + + // Calculate the velocity needed to reach the target block + Vector velocity = TrajectoryCalculator.calculateForce(player, targetBlock); + + if (velocity == null) { + player.sendMessage("Cannot calculate trajectory to that location!"); + return false; + } + + // Apply the velocity to launch the player + player.setVelocity(velocity); + player.sendMessage("Launching you to the target block!"); + + return true; + } } From 937b1e6f879b7189c37f0dda4a69d8a609d85ff5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 15:59:35 +0000 Subject: [PATCH 3/6] Fix physics calculations in TrajectoryCalculator Co-authored-by: DLandDS <28994412+DLandDS@users.noreply.github.com> --- .../core/util/TrajectoryCalculator.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java index 6dc8c77..4b1f253 100644 --- a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java +++ b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java @@ -13,7 +13,7 @@ public class TrajectoryCalculator { /** * Gravity constant in Minecraft (blocks per tick squared). - * Standard Minecraft gravity is approximately -0.08 blocks/tick² + * Standard Minecraft gravity is 0.08 blocks/tick² downward (positive value used in calculations) */ private static final double GRAVITY = 0.08; @@ -109,8 +109,8 @@ private static double findBestLaunchAngle(double horizontalDistance, double delt /** * Calculates the initial velocity magnitude needed for a projectile to reach a target. * Uses the projectile motion equation: - * R = (v² * sin(2θ)) / g (horizontal range) - * H = (v² * sin²(θ)) / (2g) (max height) + * y = x*tan(θ) - (g*x²)/(2*v²*cos²(θ)) + * Solving for v: v² = (g*x²)/(2*cos²(θ)*(x*tan(θ) - y)) * * @param horizontalDistance The horizontal distance to the target * @param deltaY The vertical distance to the target @@ -127,17 +127,21 @@ private static double calculateInitialVelocity(double horizontalDistance, double double numerator = GRAVITY * horizontalDistance * horizontalDistance; double denominator = 2 * cosAngle * cosAngle * (horizontalDistance * tanAngle - deltaY); - // Prevent division by zero or negative values - if (denominator <= 0) { - // Fallback calculation using energy consideration - return Math.sqrt(2 * GRAVITY * (horizontalDistance + Math.abs(deltaY))); + // Check if the trajectory is possible with this angle + if (denominator <= 0 || Double.isInfinite(denominator)) { + // Use a simpler approach based on the distance + // Estimate velocity based on horizontal distance and a reasonable time of flight + double estimatedTime = Math.sqrt(horizontalDistance) * 2; + return Math.max(horizontalDistance / estimatedTime, 1.0); } double velocitySquared = numerator / denominator; - // Ensure velocity is positive - if (velocitySquared < 0) { - return Math.sqrt(GRAVITY * horizontalDistance); + // Ensure velocity is positive and reasonable + if (velocitySquared < 0 || Double.isNaN(velocitySquared)) { + // Fallback: estimate based on horizontal distance + double estimatedTime = Math.sqrt(horizontalDistance) * 2; + return Math.max(horizontalDistance / estimatedTime, 1.0); } return Math.sqrt(velocitySquared); @@ -168,20 +172,19 @@ public static Vector calculateForceWithTime(Player player, Block targetBlock, in * @return The velocity vector to apply */ public static Vector calculateForceWithTime(Location from, Location to, int timeInTicks) { - double time = timeInTicks; // Time in ticks - // Calculate displacement double deltaX = to.getX() - from.getX(); double deltaY = to.getY() - from.getY(); double deltaZ = to.getZ() - from.getZ(); // Calculate horizontal velocities (constant velocity) - double velocityX = deltaX / time; - double velocityZ = deltaZ / time; + double velocityX = deltaX / timeInTicks; + double velocityZ = deltaZ / timeInTicks; // Calculate vertical velocity using: deltaY = v_y * t - 0.5 * g * t² // Solving for v_y: v_y = (deltaY + 0.5 * g * t²) / t - double velocityY = (deltaY + 0.5 * GRAVITY * time * time) / time; + // Since gravity pulls down, we add it to compensate for the downward acceleration + double velocityY = (deltaY + 0.5 * GRAVITY * timeInTicks * timeInTicks) / timeInTicks; return new Vector(velocityX, velocityY, velocityZ); } From 06f543ae6a846389dd2e350107e2e881ad38b6b2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:00:27 +0000 Subject: [PATCH 4/6] Refactor TrajectoryCalculator: extract constants and remove code duplication Co-authored-by: DLandDS <28994412+DLandDS@users.noreply.github.com> --- .../core/util/TrajectoryCalculator.java | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java index 4b1f253..c5ffff5 100644 --- a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java +++ b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java @@ -17,6 +17,21 @@ public class TrajectoryCalculator { */ private static final double GRAVITY = 0.08; + /** + * Default launch angle in degrees when optimal angle calculation fails + */ + private static final double FALLBACK_LAUNCH_ANGLE_DEGREES = 50.0; + + /** + * Threshold for considering a target significantly lower (in blocks) + */ + private static final double STEEP_DESCENT_THRESHOLD = -5.0; + + /** + * Factor used in time estimation for fallback velocity calculation + */ + private static final double TIME_ESTIMATION_FACTOR = 2.0; + /** * Calculates the velocity vector needed to launch a player to land at the center-top of a target block. * @@ -59,8 +74,8 @@ public static Vector calculateForce(Location from, Location to) { double bestAngle = findBestLaunchAngle(horizontalDistance, deltaY); if (Double.isNaN(bestAngle)) { - // If no valid angle found, use a high arc (45 degrees + offset) - bestAngle = Math.toRadians(50); + // If no valid angle found, use a high arc + bestAngle = Math.toRadians(FALLBACK_LAUNCH_ANGLE_DEGREES); } // Calculate initial velocity magnitude needed for the trajectory @@ -98,7 +113,7 @@ private static double findBestLaunchAngle(double horizontalDistance, double delt if (deltaY > 0) { // Target is higher, use a steeper angle baseAngle = Math.toRadians(60); - } else if (deltaY < -5) { + } else if (deltaY < STEEP_DESCENT_THRESHOLD) { // Target is much lower, use a shallower angle baseAngle = Math.toRadians(30); } @@ -129,24 +144,32 @@ private static double calculateInitialVelocity(double horizontalDistance, double // Check if the trajectory is possible with this angle if (denominator <= 0 || Double.isInfinite(denominator)) { - // Use a simpler approach based on the distance - // Estimate velocity based on horizontal distance and a reasonable time of flight - double estimatedTime = Math.sqrt(horizontalDistance) * 2; - return Math.max(horizontalDistance / estimatedTime, 1.0); + return estimateVelocityFromDistance(horizontalDistance); } double velocitySquared = numerator / denominator; // Ensure velocity is positive and reasonable if (velocitySquared < 0 || Double.isNaN(velocitySquared)) { - // Fallback: estimate based on horizontal distance - double estimatedTime = Math.sqrt(horizontalDistance) * 2; - return Math.max(horizontalDistance / estimatedTime, 1.0); + return estimateVelocityFromDistance(horizontalDistance); } return Math.sqrt(velocitySquared); } + /** + * Estimates a reasonable velocity based on horizontal distance. + * Uses a simplified time-of-flight approach assuming the time scales with square root of distance. + * + * @param horizontalDistance The horizontal distance to the target + * @return Estimated velocity in blocks per tick + */ + private static double estimateVelocityFromDistance(double horizontalDistance) { + // Estimate time based on distance (assuming time scales with sqrt of distance) + double estimatedTime = Math.sqrt(horizontalDistance) * TIME_ESTIMATION_FACTOR; + return Math.max(horizontalDistance / estimatedTime, 1.0); + } + /** * Alternative method using fixed time-of-flight approach. * This method assumes a specific time to reach the target and calculates velocities accordingly. From 9e4f1ee490b383ed6853483ad5c2157bfbe1c1f0 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:01:44 +0000 Subject: [PATCH 5/6] Improve documentation and use message configuration system Co-authored-by: DLandDS <28994412+DLandDS@users.noreply.github.com> --- .../plugin/core/util/TrajectoryCalculator.java | 15 +++++++++++---- .../plugin/example/ExampleMessageType.java | 6 +++++- .../plugin/example/command/ExampleCommand.java | 10 ++++++---- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java index c5ffff5..8078bbd 100644 --- a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java +++ b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java @@ -159,14 +159,20 @@ private static double calculateInitialVelocity(double horizontalDistance, double /** * Estimates a reasonable velocity based on horizontal distance. - * Uses a simplified time-of-flight approach assuming the time scales with square root of distance. + * Uses a simplified time-of-flight approach. + * + * The time estimation uses sqrt(distance) scaling as a heuristic that provides reasonable + * results for typical Minecraft trajectories. The square root scaling means closer targets + * are reached quickly while distant targets take proportionally less additional time, + * preventing extremely high velocities for long distances. * * @param horizontalDistance The horizontal distance to the target - * @return Estimated velocity in blocks per tick + * @return Estimated velocity in blocks per tick (minimum 1.0 to ensure noticeable movement) */ private static double estimateVelocityFromDistance(double horizontalDistance) { // Estimate time based on distance (assuming time scales with sqrt of distance) double estimatedTime = Math.sqrt(horizontalDistance) * TIME_ESTIMATION_FACTOR; + // Ensure minimum velocity of 1.0 blocks/tick for noticeable player movement return Math.max(horizontalDistance / estimatedTime, 1.0); } @@ -204,9 +210,10 @@ public static Vector calculateForceWithTime(Location from, Location to, int time double velocityX = deltaX / timeInTicks; double velocityZ = deltaZ / timeInTicks; - // Calculate vertical velocity using: deltaY = v_y * t - 0.5 * g * t² + // Calculate vertical velocity using kinematic equation: deltaY = v_y * t - 0.5 * g * t² + // In Minecraft, gravity acts downward at GRAVITY blocks/tick², reducing Y velocity each tick // Solving for v_y: v_y = (deltaY + 0.5 * g * t²) / t - // Since gravity pulls down, we add it to compensate for the downward acceleration + // We ADD (0.5 * g * t²) because we need to counteract the downward acceleration double velocityY = (deltaY + 0.5 * GRAVITY * timeInTicks * timeInTicks) / timeInTicks; return new Vector(velocityX, velocityY, velocityZ); diff --git a/Example/src/main/java/org/rendang/plugin/example/ExampleMessageType.java b/Example/src/main/java/org/rendang/plugin/example/ExampleMessageType.java index 94d7d0d..7cb8f4b 100644 --- a/Example/src/main/java/org/rendang/plugin/example/ExampleMessageType.java +++ b/Example/src/main/java/org/rendang/plugin/example/ExampleMessageType.java @@ -4,7 +4,11 @@ public enum ExampleMessageType implements RendangMessageRecord { EXAMPLE_MESSAGE("message.hello", "Hello, <%>!", "player"), - CONFIG_RELOADED("message.config-reloaded", "Config reloaded!") + CONFIG_RELOADED("message.config-reloaded", "Config reloaded!"), + LAUNCH_PLAYER_ONLY("message.launch.player-only", "This command can only be used by a player!"), + LAUNCH_NO_TARGET("message.launch.no-target", "You must be looking at a block!"), + LAUNCH_NO_TRAJECTORY("message.launch.no-trajectory", "Cannot calculate trajectory to that location!"), + LAUNCH_SUCCESS("message.launch.success", "Launching you to the target block!") ; private final String path; diff --git a/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java b/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java index 1c54a5d..9af97d8 100644 --- a/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java +++ b/Example/src/main/java/org/rendang/plugin/example/command/ExampleCommand.java @@ -62,15 +62,17 @@ public boolean reload(CommandEvent event) { @CommandExecute(command = "launch", usages = "", description = "Launch player to target block") public boolean launch(CommandEvent event) { + var messages = plugin.getPluginMessages(); + if (!(event.getSender() instanceof Player player)) { - event.getSender().sendMessage("This command can only be used by a player!"); + event.getSender().sendMessage(messages.parse(ExampleMessageType.LAUNCH_PLAYER_ONLY)); return false; } // Get the block the player is looking at Block targetBlock = player.getTargetBlockExact(100); if (targetBlock == null) { - player.sendMessage("You must be looking at a block!"); + player.sendMessage(messages.parse(ExampleMessageType.LAUNCH_NO_TARGET)); return false; } @@ -78,13 +80,13 @@ public boolean launch(CommandEvent event) { Vector velocity = TrajectoryCalculator.calculateForce(player, targetBlock); if (velocity == null) { - player.sendMessage("Cannot calculate trajectory to that location!"); + player.sendMessage(messages.parse(ExampleMessageType.LAUNCH_NO_TRAJECTORY)); return false; } // Apply the velocity to launch the player player.setVelocity(velocity); - player.sendMessage("Launching you to the target block!"); + player.sendMessage(messages.parse(ExampleMessageType.LAUNCH_SUCCESS)); return true; } From ea78c71401825612a1154db0363aa56b16e5f916 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Feb 2026 16:02:24 +0000 Subject: [PATCH 6/6] Final documentation improvements Co-authored-by: DLandDS <28994412+DLandDS@users.noreply.github.com> --- .../org/rendang/plugin/core/util/TrajectoryCalculator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java index 8078bbd..b82332f 100644 --- a/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java +++ b/Core/src/main/java/org/rendang/plugin/core/util/TrajectoryCalculator.java @@ -170,7 +170,7 @@ private static double calculateInitialVelocity(double horizontalDistance, double * @return Estimated velocity in blocks per tick (minimum 1.0 to ensure noticeable movement) */ private static double estimateVelocityFromDistance(double horizontalDistance) { - // Estimate time based on distance (assuming time scales with sqrt of distance) + // Estimate time using sqrt scaling heuristic (see method javadoc for rationale) double estimatedTime = Math.sqrt(horizontalDistance) * TIME_ESTIMATION_FACTOR; // Ensure minimum velocity of 1.0 blocks/tick for noticeable player movement return Math.max(horizontalDistance / estimatedTime, 1.0); @@ -212,7 +212,8 @@ public static Vector calculateForceWithTime(Location from, Location to, int time // Calculate vertical velocity using kinematic equation: deltaY = v_y * t - 0.5 * g * t² // In Minecraft, gravity acts downward at GRAVITY blocks/tick², reducing Y velocity each tick - // Solving for v_y: v_y = (deltaY + 0.5 * g * t²) / t + // Solving for v_y: v_y = (deltaY + 0.5 * GRAVITY * t²) / t + // where GRAVITY is positive representing downward acceleration magnitude // We ADD (0.5 * g * t²) because we need to counteract the downward acceleration double velocityY = (deltaY + 0.5 * GRAVITY * timeInTicks * timeInTicks) / timeInTicks;