Skip to content

Commit

Permalink
Fix height limit stuff (#225)
Browse files Browse the repository at this point in the history
  • Loading branch information
CrackedMatter authored Jan 6, 2024
1 parent 94784af commit 8de0240
Show file tree
Hide file tree
Showing 10 changed files with 98 additions and 105 deletions.
38 changes: 19 additions & 19 deletions src/server/commands/navigation/ascend.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { PlayerUtil } from "@modules/player_util.js";
import { RawText, Vector } from "@notbeer-api";
import { RawText } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { Player } from "@minecraft/server";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "ascend",
Expand All @@ -11,40 +12,39 @@ const registerInformation = {
{
name: "levels",
type: "int",
range: [1, null] as [number, null],
default: 1
}
]
};

function ascend(builder: Player) {
const location = PlayerUtil.getBlockLocation(builder);
const dimension = builder.dimension;
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder);

for (let i = location.y + 3; i <= 319; i++) {
const floor = new Vector(location.x, i - 1, location.z);
const legs = new Vector(location.x, i, location.z);
const head = new Vector(location.x, i + 1, location.z);
for (blockLoc.y = Math.max(limits[0], blockLoc.y);; blockLoc.y++) {
if (blockLoc.y > limits[1]) return false;
if (dimension.getBlock(blockLoc).isAir) continue;
if (blockLoc.y + 1 <= limits[1] && !dimension.getBlock(blockLoc.offset(0, 1, 0)).isAir) continue;
if (blockLoc.y + 2 <= limits[1] && !dimension.getBlock(blockLoc.offset(0, 2, 0)).isAir) continue;

let invalid = false;

if (dimension.getBlock(floor).isAir) invalid = true;
if (!dimension.getBlock(legs).isAir) invalid = true;
if (!dimension.getBlock(head).isAir) invalid = true;

if (!invalid) {
builder.teleport(new Vector(location.x + 0.5, legs.y, location.z + 0.5), { dimension });
return RawText.translate("commands.wedit:thru.explain");
}
builder.teleport(blockLoc.offset(0.5, 1, 0.5), { dimension });
return true;
}
return RawText.translate("commands.wedit:ascend.obstructed");
}

registerCommand(registerInformation, function (session, builder, args) {
const levels = args.get("levels") as number;

for (let level = 0; level < levels; level++) {
ascend(builder);
let count = 0;
while (ascend(builder)) {
count++;
if (count == levels) break;
}

if (count == 0) {
throw RawText.translate("commands.wedit:ascend.obstructed");
}
return RawText.translate("commands.wedit:thru.explain");
});
27 changes: 18 additions & 9 deletions src/server/commands/navigation/ceil.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PlayerUtil } from "@modules/player_util.js";
import { RawText } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "ceil",
Expand All @@ -17,19 +18,27 @@ const registerInformation = {
};

registerCommand(registerInformation, function (session, builder, args) {
const clearance = args.get("clearance") as number;

let blockLoc = PlayerUtil.getBlockLocation(builder);
let clearance = args.get("clearance") as number;
const dimension = builder.dimension;
for (let i = 0;; i++, blockLoc = blockLoc.offset(0, 1, 0)) {
if (!dimension.getBlock(blockLoc.offset(0, 2, 0)).isAir) {
blockLoc = blockLoc.offset(0, clearance < i ? -clearance : -i, 0);
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder).offset(0, 2, 0);

for (let i = 0;; i++, blockLoc.y++) {
if (blockLoc.y > limits[1]) {
throw RawText.translate("commands.wedit:ascend.obstructed");
}
if (blockLoc.y >= limits[0] && !dimension.getBlock(blockLoc).isAir) {
if (clearance > i) clearance = i;
break;
}
}

const block = dimension.getBlock(blockLoc.offset(0, -1, 0));
builder.teleport(blockLoc.offset(0.5, 0, 0.5), { dimension });
if (block.isAir) block.setType("minecraft:glass");
blockLoc.y -= clearance + 3;
if (blockLoc.y >= limits[0] && blockLoc.y <= limits[1]) {
const block = dimension.getBlock(blockLoc);
if (block.isAir) block.setType("minecraft:glass");
}

builder.teleport(blockLoc.offset(0.5, 1, 0.5), { dimension });
return RawText.translate("commands.wedit:up.explain");
});
40 changes: 20 additions & 20 deletions src/server/commands/navigation/descend.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { PlayerUtil } from "@modules/player_util.js";
import { RawText, Vector } from "@notbeer-api";
import { RawText } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { Player } from "@minecraft/server";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "descend",
Expand All @@ -11,40 +12,39 @@ const registerInformation = {
{
name: "levels",
type: "int",
range: [1, null] as [number, null],
default: 1
}
]
};

function descend(builder: Player) {
const location = PlayerUtil.getBlockLocation(builder);
const dimension = builder.dimension;
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder);

for (let i = location.y - 3; i >= -64; i--) {
const floor = new Vector(location.x, i - 1, location.z);
const legs = new Vector(location.x, i, location.z);
const head = new Vector(location.x, i + 1, location.z);
for (blockLoc.y = Math.min(limits[1], blockLoc.y - 2);; blockLoc.y--) {
if (blockLoc.y < limits[0]) return false;
if (dimension.getBlock(blockLoc).isAir) continue;
if (blockLoc.y + 1 <= limits[1] && !dimension.getBlock(blockLoc.offset(0, 1, 0)).isAir) continue;
if (blockLoc.y + 2 <= limits[1] && !dimension.getBlock(blockLoc.offset(0, 2, 0)).isAir) continue;

let invalid = false;

if (dimension.getBlock(floor).isAir) invalid = true;
if (!dimension.getBlock(legs).isAir) invalid = true;
if (!dimension.getBlock(head).isAir) invalid = true;

if (!invalid) {
builder.teleport(new Vector(location.x + 0.5, legs.y, location.z + 0.5), { dimension });
return RawText.translate("commands.wedit:thru.explain");
}
builder.teleport(blockLoc.offset(0.5, 1, 0.5), { dimension });
return true;
}
return RawText.translate("commands.wedit:descend.obstructed");
}

registerCommand(registerInformation, function (session, builder, args) {
const levels = args.get("levels") as number;

for (let level = 0; level < levels; level++) {
descend(builder);
let count = 0;
while (descend(builder)) {
count++;
if (count == levels) break;
}

if (count == 0) {
throw RawText.translate("commands.wedit:descend.obstructed");
}
return RawText.translate("commands.wedit:thru.explain");
});
});
5 changes: 4 additions & 1 deletion src/server/commands/navigation/thru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Vector } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { Cardinal } from "@modules/directions.js";
import { PlayerUtil } from "@modules/player_util.js";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "thru",
Expand All @@ -11,12 +12,14 @@ const registerInformation = {

registerCommand(registerInformation, function (session, builder) {
const dimension = builder.dimension;
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder);

const dir = new Cardinal().getDirection(builder);

function isSpaceEmpty(loc: Vector) {
return dimension.getBlock(loc).isAir && dimension.getBlock(loc.offset(0, 1, 0)).isAir;
return (loc.y < limits[0] || loc.y > limits[1] || dimension.getBlock(loc).isAir) &&
(loc.y + 1 < limits[0] || loc.y + 1 > limits[1] || dimension.getBlock(loc.offset(0, 1, 0)).isAir);
}

let testLoc = blockLoc.offset(dir.x, dir.y, dir.z);
Expand Down
21 changes: 10 additions & 11 deletions src/server/commands/navigation/unstuck.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PlayerUtil } from "@modules/player_util.js";
import { RawText } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "unstuck",
Expand All @@ -10,17 +11,15 @@ const registerInformation = {
};

registerCommand(registerInformation, function (session, builder) {
const blockLoc = PlayerUtil.getBlockLocation(builder);
const dimension = builder.dimension;
do {
if (dimension.getBlock(blockLoc).isAir &&
dimension.getBlock(blockLoc.offset(0, 1, 0)).isAir) {
break;
}
}
// eslint-disable-next-line no-cond-assign
while (blockLoc.y += 1);
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder);

builder.teleport(blockLoc.offset(0.5, 0, 0.5), { dimension });
return RawText.translate("commands.wedit:unstuck.explain");
for (blockLoc.y = Math.max(limits[0], blockLoc.y);; blockLoc.y++) {
if (blockLoc.y <= limits[1] && !dimension.getBlock(blockLoc).isAir) continue;
if (blockLoc.y + 1 <= limits[1] && !dimension.getBlock(blockLoc.offset(0, 1, 0)).isAir) continue;

builder.teleport(blockLoc.offset(0.5, 0, 0.5), { dimension });
return RawText.translate("commands.wedit:unstuck.explain");
}
});
20 changes: 13 additions & 7 deletions src/server/commands/navigation/up.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PlayerUtil } from "@modules/player_util.js";
import { RawText } from "@notbeer-api";
import { registerCommand } from "../register_commands.js";
import { getWorldHeightLimits } from "server/util.js";

const registerInformation = {
name: "up",
Expand All @@ -17,17 +18,22 @@ const registerInformation = {

registerCommand(registerInformation, function (session, builder, args) {
const height = args.get("height") as number;

let blockLoc = PlayerUtil.getBlockLocation(builder);
const dimension = builder.dimension;
for (let i = 0; i < height; i++, blockLoc = blockLoc.offset(0, 1, 0)) {
if (!dimension.getBlock(blockLoc.offset(0, 2, 0)).isAir) {
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(builder).offset(0, 2, 0);

for (let i = 0; i < height; i++, blockLoc.y++) {
if (blockLoc.y >= limits[0] && blockLoc.y <= limits[1] && !dimension.getBlock(blockLoc).isAir) {
break;
}
}

const block = dimension.getBlock(blockLoc.offset(0, -1, 0));
builder.teleport(blockLoc.offset(0.5, 0, 0.5), { dimension });
if (block.isAir) block.setType("minecraft:glass");
blockLoc.y -= 3;
if (blockLoc.y >= limits[0] && blockLoc.y <= limits[1]) {
const block = dimension.getBlock(blockLoc);
if (block.isAir) block.setType("minecraft:glass");
}

builder.teleport(blockLoc.offset(0.5, 1, 0.5), { dimension });
return RawText.translate("commands.wedit:up.explain");
});
2 changes: 2 additions & 0 deletions src/server/commands/utilities/drain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BlockPermutation } from "@minecraft/server";
import { SphereShape } from "../../shapes/sphere.js";
import { registerCommand } from "../register_commands.js";
import { floodFill } from "./floodfill_func.js";
import { canPlaceBlock } from "server/util.js";

const registerInformation = {
name: "drain",
Expand Down Expand Up @@ -45,6 +46,7 @@ registerCommand(registerInformation, function* (session, builder, args) {
let drainStart: Vector;
for (const offset of fluidLookPositions) {
const loc = playerBlock.offset(offset.x, offset.y, offset.z);
if (!canPlaceBlock(loc, dimension)) continue;
const block = dimension.getBlock(loc);
if (block.typeId.match(waterMatch) || (args.has("w") && block.isWaterlogged)) {
fluidMatch = waterMatch;
Expand Down
8 changes: 5 additions & 3 deletions src/server/commands/utilities/floodfill_func.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,11 @@ export function* floodFill<T extends FloodFillContext>(start: Vector3, size: num
result.set(locToString(block), true);
for (const offset of offsets) {
const newCtx = {...ctx};
if (spread(newCtx, offset)) {
addNeighbor(block, offset, newCtx);
}
try {
if (spread(newCtx, offset)) {
addNeighbor(block, offset, newCtx);
}
} catch { /* pass */ }
}
}

Expand Down
6 changes: 5 additions & 1 deletion src/server/tools/navigation_tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import { Tool } from "./base_tool.js";
import { Tools } from "./tool_manager.js";
import { PlayerUtil } from "@modules/player_util.js";
import { Server } from "@notbeer-api";
import { getWorldHeightLimits } from "server/util.js";

class NavigationTool extends Tool {
permission = "worldedit.navigation";

use = function (self: Tool, player: Player) {
if (!player.dimension.getBlock(PlayerUtil.getBlockLocation(player).offset(0, 1, 0)).isAir) {
const dimension = player.dimension;
const limits = getWorldHeightLimits(dimension);
const blockLoc = PlayerUtil.getBlockLocation(player).offset(0, 1, 0);
if (blockLoc.y >= limits[0] && blockLoc.y <= limits[1] && !dimension.getBlock(blockLoc).isAir) {
Server.command.callCommand(player, "unstuck", []);
} else if (player.isSneaking) {
Server.command.callCommand(player, "thru", []);
Expand Down
36 changes: 2 additions & 34 deletions src/server/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,45 +36,13 @@ export function getViewVector(entity: Entity | Player): Vector3 {
return entity.getViewDirection();
}

const worldY = new Map<Dimension, [number, number]>();
function findHeightLimits(dim: Dimension) {
const limits: [number, number] = [null, null];

for (const p of world.getPlayers()) {
if (p.dimension != dim) {
continue;
}

for (let i = -512; i <= 512; i += 16) {
const canPlace = canPlaceBlock(new Vector(p.location.x, i, p.location.z), dim);
if (limits[0] == null) {
if (canPlace) {
limits[0] = i;
}
} else if (limits[1] == null) {
if (!canPlace) {
limits[1] = i - 17;
}
}
}
break;
}

if (limits[0] != null && limits[1] != null) {
worldY.set(dim, limits);
}
}

/**
* Gets the minimum and maximum Y levels of a dimension.
* @param dim The dimension we're querying.
* @return The minimum and maximum Y levels.
*/
export function getWorldHeightLimits(dim: Dimension) {
if (!worldY.has(dim)) {
findHeightLimits(dim);
}
return worldY.get(dim) ?? [ -512, 511 ];
export function getWorldHeightLimits(dim: Dimension): [number, number] {
return [dim.heightRange.min, dim.heightRange.max - 1];
}

/**
Expand Down

0 comments on commit 8de0240

Please sign in to comment.