fix(generator): fix 6 generation bugs
- Fix JumpDirector diagonal drift - axis-aligned vectors per border side - Fix schematic end-block - only last block triggers completion, skip scoring - Fix JumpOffsetGenerator - clamp random offset to validator limits - Fix JumpCalculator retry height clamp to -2 - Fix JumpValidator duplication - Vector.canJump delegates to common impl - Remove rotateAroundY (offset already aligned with heading)
This commit is contained in:
parent
0b6409397b
commit
5b946c4222
4 changed files with 55 additions and 67 deletions
|
|
@ -1,6 +1,5 @@
|
|||
package dev.loki.loparkour.generator.jump.calculation;
|
||||
|
||||
import dev.loki.loparkour.config.options.Option;
|
||||
import dev.loki.loparkour.generator.core.model.GeneratorOption;
|
||||
import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator;
|
||||
import dev.loki.loparkour.generator.jump.placement.BlockSelector;
|
||||
|
|
@ -100,7 +99,10 @@ public class JumpCalculator {
|
|||
@NotNull
|
||||
private Vector calculateJumpOffset(int distance, int height) {
|
||||
double sd = java.util.Arrays.asList(generator.generatorOptions).contains(GeneratorOption.REDUCE_RANDOM_BLOCK_SELECTION_ANGLE) ? 0.5 : 1;
|
||||
int randomOffset = new JumpOffsetGenerator(height, distance).getRandomOffset(0, sd);
|
||||
int randomOffset = Math.min(
|
||||
new JumpOffsetGenerator(height, distance).getRandomOffset(0, sd),
|
||||
(int) Math.floor(Math.sqrt(JumpValidator.MAX_HORIZONTAL_DISTANCE * JumpValidator.MAX_HORIZONTAL_DISTANCE - distance * distance))
|
||||
);
|
||||
|
||||
Vector offset = generator.state.heading.clone().multiply(distance).setY(height);
|
||||
if (offset.getX() == 0) {
|
||||
|
|
@ -109,7 +111,6 @@ public class JumpCalculator {
|
|||
offset.setZ(randomOffset);
|
||||
}
|
||||
|
||||
offset.rotateAroundY(angleInY(generator.state.heading, Option.HEADING.getDirection()));
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
|
@ -121,7 +122,7 @@ public class JumpCalculator {
|
|||
while (!validator.canJump(current.getLocation(), candidate.getLocation()) && attempts < 10) {
|
||||
// Reduce distance and height to make jump easier
|
||||
distance = Math.max(1, distance - 1);
|
||||
height = Math.max(-1, height - 1);
|
||||
height = Math.max(-2, height - 1);
|
||||
|
||||
Vector offset = calculateJumpOffset(distance, height);
|
||||
candidate = current.getLocation().add(offset).getBlock();
|
||||
|
|
@ -150,11 +151,7 @@ public class JumpCalculator {
|
|||
default -> 3; // Default restriction
|
||||
};
|
||||
}
|
||||
|
||||
private double angleInY(@NotNull Vector a, @NotNull Vector b) {
|
||||
return Math.atan2(b.getZ(), b.getX()) - Math.atan2(a.getZ(), a.getX());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents jump constraints for a specific block type.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -80,30 +80,43 @@ public class JumpDirector {
|
|||
double tz = progress[2][0];
|
||||
double borderMarginZ = progress[2][1];
|
||||
|
||||
Vector recommendedHeading = new Vector(0, 0, 0);
|
||||
// check border
|
||||
// Determine per-axis corrections needed
|
||||
boolean needX = false;
|
||||
boolean needZ = false;
|
||||
double dirX = 0;
|
||||
double dirZ = 0;
|
||||
|
||||
if (tx < borderMarginX) {
|
||||
// x should increase
|
||||
recommendedHeading = new Vector(1, 0, 1);
|
||||
needX = true;
|
||||
dirX = 1;
|
||||
} else if (tx > 1 - borderMarginX) {
|
||||
// x should decrease
|
||||
recommendedHeading = new Vector(-1, 0, -1);
|
||||
needX = true;
|
||||
dirX = -1;
|
||||
}
|
||||
|
||||
if (tz < borderMarginZ) {
|
||||
// z should increase
|
||||
recommendedHeading = new Vector(1, 0, 1);
|
||||
needZ = true;
|
||||
dirZ = 1;
|
||||
} else if (tz > 1 - borderMarginZ) {
|
||||
// z should decrease
|
||||
recommendedHeading = new Vector(-1, 0, -1);
|
||||
needZ = true;
|
||||
dirZ = -1;
|
||||
}
|
||||
|
||||
if (recommendedHeading.lengthSquared() == 0) {
|
||||
if (!needX && !needZ) {
|
||||
return current;
|
||||
} else {
|
||||
// Normalize so diagonal vectors don't multiply distance by √2
|
||||
return recommendedHeading.normalize();
|
||||
}
|
||||
|
||||
if (needX && needZ) {
|
||||
// Both axes need correction — return a diagonal
|
||||
return new Vector(dirX, 0, dirZ).normalize();
|
||||
}
|
||||
|
||||
if (needX) {
|
||||
return new Vector(dirX, 0, 0);
|
||||
}
|
||||
|
||||
// needZ is true
|
||||
return new Vector(0, 0, dirZ);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ import org.jetbrains.annotations.NotNull;
|
|||
|
||||
public class JumpValidator {
|
||||
|
||||
private static final double MAX_JUMP_DISTANCE = 4.5;
|
||||
private static final double MAX_HORIZONTAL_DISTANCE = 4.1;
|
||||
private static final double MAX_VERTICAL_UP = 1.25;
|
||||
private static final double MAX_VERTICAL_DOWN = 3.0;
|
||||
public static final double MAX_JUMP_DISTANCE = 4.5;
|
||||
public static final double MAX_HORIZONTAL_DISTANCE = 4.1;
|
||||
public static final double MAX_VERTICAL_UP = 1.25;
|
||||
public static final double MAX_VERTICAL_DOWN = 3.0;
|
||||
|
||||
private final double maxDistance;
|
||||
private final double maxHorizontal;
|
||||
|
|
@ -122,43 +122,7 @@ public class JumpValidator {
|
|||
|
||||
// Check if jump is possible: sqrt(dx² + dy² + dz²) <= maxDistance
|
||||
public boolean canJump(@NotNull Vector from, @NotNull Vector to) {
|
||||
// Null safety check
|
||||
if (from == null || to == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
double dx = to.getX() - from.getX();
|
||||
double dy = to.getY() - from.getY();
|
||||
double dz = to.getZ() - from.getZ();
|
||||
|
||||
// Check if same location (no jump)
|
||||
double horizontalDistance = Math.sqrt(dx * dx + dz * dz);
|
||||
if (horizontalDistance < 0.01 && Math.abs(dy) < 0.01) {
|
||||
return false; // Same location
|
||||
}
|
||||
|
||||
// Check horizontal distance limit
|
||||
if (horizontalDistance > maxHorizontal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check vertical limits
|
||||
if (dy > maxVerticalUp || dy < -maxVerticalDown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For upward jumps, reduce max horizontal distance
|
||||
// Player can't jump as far when jumping up
|
||||
if (dy > 0) {
|
||||
double adjustedMaxHorizontal = maxHorizontal - (dy * 0.5); // Reduce by 0.5 blocks per block up
|
||||
if (horizontalDistance > adjustedMaxHorizontal) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check total distance
|
||||
double totalDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
return totalDistance <= maxDistance;
|
||||
return canJumpWithAdjustment(from, to, 0.0);
|
||||
}
|
||||
|
||||
public double calculateDistance(@NotNull Location from, @NotNull Location to) {
|
||||
|
|
|
|||
|
|
@ -110,14 +110,23 @@ public class PlayerInteractionHandler {
|
|||
// Check if it's a schematic end block
|
||||
if (isSchematicEndBlock(block)) {
|
||||
handleSchematicEndBlock(block);
|
||||
} else if (isOnSchematicBlock(block)) {
|
||||
// Schematic block that is NOT the last — skip scoring
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Check for scoring (compare by coordinates, not reference — Bukkit Block uses identity)
|
||||
if (historyContains(generator.state.history, block) && !player.hasScored(block)) {
|
||||
player.markScored(block);
|
||||
handleScore();
|
||||
}
|
||||
}
|
||||
|
||||
/** Check if block is any schematic block (not just the last one). */
|
||||
private boolean isOnSchematicBlock(@NotNull Block block) {
|
||||
return generator.state.schematicBlocks != null
|
||||
&& historyContains(generator.state.schematicBlocks, block);
|
||||
}
|
||||
|
||||
private void handleSchematicEndBlock(@NotNull Block block) {
|
||||
// Remove schematic blocks and continue with normal generation
|
||||
|
|
@ -131,8 +140,13 @@ public class PlayerInteractionHandler {
|
|||
}
|
||||
|
||||
private boolean isSchematicEndBlock(@NotNull Block block) {
|
||||
return generator.state.schematicBlocks != null
|
||||
&& historyContains(generator.state.schematicBlocks, block);
|
||||
List<Block> schematicBlocks = generator.state.schematicBlocks;
|
||||
if (schematicBlocks == null || schematicBlocks.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
// Only the LAST block of the schematic triggers completion
|
||||
Block last = schematicBlocks.get(schematicBlocks.size() - 1);
|
||||
return isSameBlock(block, last);
|
||||
}
|
||||
|
||||
/** Block directly under feet; {@code null} in air — scoring runs when landed. */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue