top.hendrixshen.magiclib.util.minecraft.PositionUtil Maven / Gradle / Ivy
/*
* This file is part of the TweakerMore project, licensed under the
* GNU Lesser General Public License v3.0
*
* Copyright (C) 2023 Fallen_Breath and contributors
*
* TweakerMore is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* TweakerMore 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with TweakerMore. If not, see .
*/
package top.hendrixshen.magiclib.util.minecraft;
import com.google.common.collect.Lists;
import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
/**
* Reference to TweakerMore
*/
public class PositionUtil {
public static @NotNull Vec3 centerOf(@NotNull BlockPos blockPos) {
return new Vec3(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);
}
public static @NotNull Collection boxSurface(@NotNull BlockPos pos1, @NotNull BlockPos pos2) {
int minX = Math.min(pos1.getX(), pos2.getX());
int minY = Math.min(pos1.getY(), pos2.getY());
int minZ = Math.min(pos1.getZ(), pos2.getZ());
int maxX = Math.max(pos1.getX(), pos2.getX());
int maxY = Math.max(pos1.getY(), pos2.getY());
int maxZ = Math.max(pos1.getZ(), pos2.getZ());
LongOpenHashSet set = new LongOpenHashSet();
List result = Lists.newArrayList();
Consumer storage = pos -> {
if (set.add(pos.asLong())) {
result.add(pos);
}
};
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
storage.accept(new BlockPos(x, y, minZ));
storage.accept(new BlockPos(x, y, maxZ));
}
}
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
storage.accept(new BlockPos(x, minY, z));
storage.accept(new BlockPos(x, maxY, z));
}
}
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
storage.accept(new BlockPos(minX, y, z));
storage.accept(new BlockPos(maxX, y, z));
}
}
return result;
}
public static Collection beam(Vec3 startPos, @NotNull Vec3 endPos, double coneAngle, BeamMode mode) {
Vec3 dir1 = endPos.subtract(startPos).normalize();
if (dir1 == Vec3.ZERO) {
return Collections.emptyList();
}
double maxLen = startPos.distanceTo(endPos);
double step = 1 / (1 + Math.sin(coneAngle));
Long2DoubleOpenHashMap positions = new Long2DoubleOpenHashMap();
BlockPos lastMin = null;
BlockPos lastMax = null;
for (double len = 0, angle = coneAngle; len < maxLen + step; len += step) {
double r = len * Math.sin(angle);
Vec3 vec3 = startPos.add(dir1.scale(len));
Vec3 a = vec3.add(-r, -r, -r);
Vec3 b = vec3.add(+r, +r, +r);
BlockPos pos1 = new BlockPos((int) Math.floor(a.x), (int) Math.floor(a.y), (int) Math.floor(a.z));
BlockPos pos2 = new BlockPos((int) Math.ceil(b.x), (int) Math.ceil(b.y), (int) Math.ceil(b.z));
if (lastMin != null) {
// Optimize increasing PositionUtil.boxSurface
int minX = pos1.getX();
int minY = pos1.getY();
int minZ = pos1.getZ();
int maxX = pos2.getX();
int maxY = pos2.getY();
int maxZ = pos2.getZ();
// minX changed
if (minX != lastMin.getX()) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
positions.putIfAbsent(new BlockPos(minX, y, z).asLong(), angle);
}
}
}
// maxX changed
if (maxX != lastMax.getX()) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
positions.putIfAbsent(new BlockPos(maxX, y, z).asLong(), angle);
}
}
}
// minY changed
if (minY != lastMin.getY()) {
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
positions.putIfAbsent(new BlockPos(x, minY, z).asLong(), angle);
}
}
}
// minY changed
if (maxY != lastMax.getY()) {
for (int x = minX; x <= maxX; x++) {
for (int z = minZ; z <= maxZ; z++) {
positions.putIfAbsent(new BlockPos(x, maxY, z).asLong(), angle);
}
}
}
// minZ changed
if (minZ != lastMin.getZ()) {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
positions.putIfAbsent(new BlockPos(x, y, minZ).asLong(), angle);
}
}
}
// maxZ changed
if (maxZ != lastMin.getZ()) {
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
positions.putIfAbsent(new BlockPos(x, y, maxZ).asLong(), angle);
}
}
}
} else {
for (BlockPos pos : PositionUtil.boxSurface(pos1, pos2)) {
positions.putIfAbsent(pos.asLong(), angle);
}
}
lastMin = pos1;
lastMax = pos2;
switch (mode) {
case BEAM:
angle = coneAngle * Math.max(1 - len / maxLen, 0);
break;
case CONE:
angle = coneAngle;
break;
}
}
List result = Lists.newArrayList();
positions.forEach((l, a) -> {
BlockPos pos = BlockPos.of(l);
Vec3 vec3 = PositionUtil.centerOf(pos).subtract(startPos);
if (vec3.length() <= maxLen) {
Vec3 dir2 = vec3.normalize();
double cos = dir2.dot(dir1);
if (cos >= Math.cos(a)) {
result.add(pos);
}
}
});
return result;
}
public enum BeamMode {
/*
* / ---\
* / ---------\
* x -----------|
* \ ---------/
* \ ---/
*/
BEAM,
/*
* /-|
* /---|
* /-----|
* x ------|
* \-----|
* \---|
* \-|
*/
CONE
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy