Clean repo for open source release
Remove build artifacts, dev tool configs, unused dependencies, and third-party source dumps. Add proper README, update .gitignore, clean up Makefile.
This commit is contained in:
367
src/main/java/com/tiedup/remake/util/teleport/Position.java
Normal file
367
src/main/java/com/tiedup/remake/util/teleport/Position.java
Normal file
@@ -0,0 +1,367 @@
|
||||
package com.tiedup.remake.util.teleport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
/**
|
||||
* Represents a teleport position with coordinates, rotation, and dimension.
|
||||
*
|
||||
* <p>Used by collar teleport commands and warp points in the original mod.</p>
|
||||
*
|
||||
* <h2>Use Cases</h2>
|
||||
* <ul>
|
||||
* <li>Collar warp points (home, prison, custom locations)</li>
|
||||
* <li>EntityKidnapper prison teleportation</li>
|
||||
* <li>Admin teleport commands</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>NBT Structure</h2>
|
||||
* <pre>
|
||||
* position (CompoundTag)
|
||||
* ├── x (double)
|
||||
* ├── y (double)
|
||||
* ├── z (double)
|
||||
* ├── yaw (float)
|
||||
* ├── pitch (float)
|
||||
* └── dimension (string) - e.g., "minecraft:overworld"
|
||||
* </pre>
|
||||
*
|
||||
* <h2>Original Reference</h2>
|
||||
* Based on Original/com/yuti/kidnapmod/util/teleport/Position.java
|
||||
*/
|
||||
public class Position {
|
||||
|
||||
private final double x;
|
||||
private final double y;
|
||||
private final double z;
|
||||
private final float yaw;
|
||||
private final float pitch;
|
||||
private final ResourceKey<Level> dimension;
|
||||
|
||||
/**
|
||||
* Create a new position with full rotation.
|
||||
*
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param z Z coordinate
|
||||
* @param yaw Horizontal rotation (0-360)
|
||||
* @param pitch Vertical rotation (-90 to 90)
|
||||
* @param dimension Dimension key (e.g., Level.OVERWORLD, Level.NETHER)
|
||||
*/
|
||||
public Position(
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
float yaw,
|
||||
float pitch,
|
||||
ResourceKey<Level> dimension
|
||||
) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
this.dimension = dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new position without rotation (defaults to 0).
|
||||
*
|
||||
* @param x X coordinate
|
||||
* @param y Y coordinate
|
||||
* @param z Z coordinate
|
||||
* @param dimension Dimension key
|
||||
*/
|
||||
public Position(
|
||||
double x,
|
||||
double y,
|
||||
double z,
|
||||
ResourceKey<Level> dimension
|
||||
) {
|
||||
this(x, y, z, 0.0f, 0.0f, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a position from BlockPos and dimension.
|
||||
*
|
||||
* @param pos Block position
|
||||
* @param dimension Dimension key
|
||||
*/
|
||||
public Position(BlockPos pos, ResourceKey<Level> dimension) {
|
||||
this(
|
||||
pos.getX() + 0.5,
|
||||
pos.getY(),
|
||||
pos.getZ() + 0.5,
|
||||
0.0f,
|
||||
0.0f,
|
||||
dimension
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a position from Vec3 and dimension.
|
||||
*
|
||||
* @param vec Vector position
|
||||
* @param dimension Dimension key
|
||||
*/
|
||||
public Position(Vec3 vec, ResourceKey<Level> dimension) {
|
||||
this(vec.x, vec.y, vec.z, 0.0f, 0.0f, dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a position from an entity's current location.
|
||||
*
|
||||
* @param entity The entity
|
||||
* @return Position at entity's location with rotation
|
||||
*/
|
||||
public static Position fromEntity(Entity entity) {
|
||||
return new Position(
|
||||
entity.getX(),
|
||||
entity.getY(),
|
||||
entity.getZ(),
|
||||
entity.getYRot(),
|
||||
entity.getXRot(),
|
||||
entity.level().dimension()
|
||||
);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// NBT SERIALIZATION
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Save this position to NBT.
|
||||
*
|
||||
* @return CompoundTag containing position data
|
||||
*/
|
||||
public CompoundTag save() {
|
||||
CompoundTag tag = new CompoundTag();
|
||||
tag.putDouble("x", this.x);
|
||||
tag.putDouble("y", this.y);
|
||||
tag.putDouble("z", this.z);
|
||||
tag.putFloat("yaw", this.yaw);
|
||||
tag.putFloat("pitch", this.pitch);
|
||||
tag.putString("dimension", this.dimension.location().toString());
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save this position to an existing CompoundTag.
|
||||
*
|
||||
* @param tag The tag to save to
|
||||
* @return The modified tag
|
||||
*/
|
||||
public CompoundTag save(CompoundTag tag) {
|
||||
tag.putDouble("x", this.x);
|
||||
tag.putDouble("y", this.y);
|
||||
tag.putDouble("z", this.z);
|
||||
tag.putFloat("yaw", this.yaw);
|
||||
tag.putFloat("pitch", this.pitch);
|
||||
tag.putString("dimension", this.dimension.location().toString());
|
||||
return tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a position from NBT.
|
||||
*
|
||||
* @param tag The CompoundTag to load from
|
||||
* @return Position or null if invalid
|
||||
*/
|
||||
@Nullable
|
||||
public static Position load(CompoundTag tag) {
|
||||
if (
|
||||
tag == null ||
|
||||
!tag.contains("x") ||
|
||||
!tag.contains("y") ||
|
||||
!tag.contains("z")
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
double x = tag.getDouble("x");
|
||||
double y = tag.getDouble("y");
|
||||
double z = tag.getDouble("z");
|
||||
float yaw = tag.contains("yaw") ? tag.getFloat("yaw") : 0.0f;
|
||||
float pitch = tag.contains("pitch") ? tag.getFloat("pitch") : 0.0f;
|
||||
|
||||
// Parse dimension
|
||||
ResourceKey<Level> dimension = Level.OVERWORLD; // Default
|
||||
if (tag.contains("dimension")) {
|
||||
String dimStr = tag.getString("dimension");
|
||||
ResourceLocation dimLoc = ResourceLocation.tryParse(dimStr);
|
||||
if (dimLoc != null) {
|
||||
dimension = ResourceKey.create(Registries.DIMENSION, dimLoc);
|
||||
}
|
||||
}
|
||||
|
||||
return new Position(x, y, z, yaw, pitch, dimension);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// GETTERS
|
||||
// ========================================
|
||||
|
||||
public double getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public double getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public double getZ() {
|
||||
return z;
|
||||
}
|
||||
|
||||
public float getYaw() {
|
||||
return yaw;
|
||||
}
|
||||
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
public ResourceKey<Level> getDimension() {
|
||||
return dimension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to Vec3.
|
||||
* @return Vector representation
|
||||
*/
|
||||
public Vec3 toVec3() {
|
||||
return new Vec3(x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to BlockPos.
|
||||
* @return Block position (floored)
|
||||
*/
|
||||
public BlockPos toBlockPos() {
|
||||
return new BlockPos(
|
||||
(int) Math.floor(x),
|
||||
(int) Math.floor(y),
|
||||
(int) Math.floor(z)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dimension name for display.
|
||||
* @return Dimension name (e.g., "overworld", "the_nether")
|
||||
*/
|
||||
public String getDimensionName() {
|
||||
return dimension.location().getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this position is in the same dimension as another.
|
||||
* @param other The other position
|
||||
* @return true if same dimension
|
||||
*/
|
||||
public boolean isSameDimension(Position other) {
|
||||
return other != null && this.dimension.equals(other.dimension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if this position is in the given dimension.
|
||||
* @param dim The dimension to check
|
||||
* @return true if in that dimension
|
||||
*/
|
||||
public boolean isInDimension(ResourceKey<Level> dim) {
|
||||
return this.dimension.equals(dim);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate distance to another position (ignores dimension).
|
||||
* @param other The other position
|
||||
* @return Distance in blocks
|
||||
*/
|
||||
public double distanceTo(Position other) {
|
||||
double dx = this.x - other.x;
|
||||
double dy = this.y - other.y;
|
||||
double dz = this.z - other.z;
|
||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate horizontal distance to another position (ignores Y and dimension).
|
||||
* @param other The other position
|
||||
* @return Horizontal distance in blocks
|
||||
*/
|
||||
public double horizontalDistanceTo(Position other) {
|
||||
double dx = this.x - other.x;
|
||||
double dz = this.z - other.z;
|
||||
return Math.sqrt(dx * dx + dz * dz);
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// OBJECT OVERRIDES
|
||||
// ========================================
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
"Position{x=%.2f, y=%.2f, z=%.2f, yaw=%.1f, pitch=%.1f, dim=%s}",
|
||||
x,
|
||||
y,
|
||||
z,
|
||||
yaw,
|
||||
pitch,
|
||||
dimension.location()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short string for display (e.g., in tooltips).
|
||||
* @return Short position string like "X: 100, Y: 64, Z: -200"
|
||||
*/
|
||||
public String toShortString() {
|
||||
return String.format("X: %.0f, Y: %.0f, Z: %.0f", x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a display string with dimension for tooltips.
|
||||
* @return Display string like "overworld - X: 100, Y: 64, Z: -200"
|
||||
*/
|
||||
public String toDisplayString() {
|
||||
return String.format(
|
||||
"%s - X: %.0f, Y: %.0f, Z: %.0f",
|
||||
getDimensionName(),
|
||||
x,
|
||||
y,
|
||||
z
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof Position other)) return false;
|
||||
return (
|
||||
Double.compare(other.x, x) == 0 &&
|
||||
Double.compare(other.y, y) == 0 &&
|
||||
Double.compare(other.z, z) == 0 &&
|
||||
Float.compare(other.yaw, yaw) == 0 &&
|
||||
Float.compare(other.pitch, pitch) == 0 &&
|
||||
dimension.equals(other.dimension)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Double.hashCode(x);
|
||||
result = 31 * result + Double.hashCode(y);
|
||||
result = 31 * result + Double.hashCode(z);
|
||||
result = 31 * result + Float.hashCode(yaw);
|
||||
result = 31 * result + Float.hashCode(pitch);
|
||||
result = 31 * result + dimension.hashCode();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
package com.tiedup.remake.util.teleport;
|
||||
|
||||
import com.tiedup.remake.core.TiedUpMod;
|
||||
import java.util.function.Function;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.portal.PortalInfo;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraftforge.common.util.ITeleporter;
|
||||
|
||||
/**
|
||||
* Utility class for teleporting entities across dimensions.
|
||||
*
|
||||
* <p>Handles the complexity of cross-dimension teleportation in 1.20.1,
|
||||
* including proper chunk loading, entity transfer, and rotation preservation.</p>
|
||||
*
|
||||
* <h2>Features</h2>
|
||||
* <ul>
|
||||
* <li>Same-dimension teleportation</li>
|
||||
* <li>Cross-dimension teleportation</li>
|
||||
* <li>Player-specific handling (smooth client sync)</li>
|
||||
* <li>Rotation preservation</li>
|
||||
* <li>Safe position validation</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Original Reference</h2>
|
||||
* Based on Original/com/yuti/kidnapmod/util/teleport/TeleportHelper.java
|
||||
*/
|
||||
public class TeleportHelper {
|
||||
|
||||
/**
|
||||
* Teleport an entity to a position.
|
||||
* Handles both same-dimension and cross-dimension teleportation.
|
||||
*
|
||||
* @param entity The entity to teleport
|
||||
* @param position The target position
|
||||
* @return The entity after teleportation (may be different instance after dimension change)
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity teleportEntity(Entity entity, Position position) {
|
||||
if (entity == null || position == null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Server-side only
|
||||
if (entity.level().isClientSide) {
|
||||
TiedUpMod.LOGGER.warn(
|
||||
"[TeleportHelper] Attempted client-side teleport"
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Get server and target level
|
||||
MinecraftServer server = entity.getServer();
|
||||
if (server == null) {
|
||||
TiedUpMod.LOGGER.error(
|
||||
"[TeleportHelper] No server found for entity"
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
ResourceKey<Level> targetDimension = position.getDimension();
|
||||
ServerLevel targetLevel = server.getLevel(targetDimension);
|
||||
|
||||
if (targetLevel == null) {
|
||||
TiedUpMod.LOGGER.error(
|
||||
"[TeleportHelper] Target dimension not found: {}",
|
||||
targetDimension
|
||||
);
|
||||
return entity;
|
||||
}
|
||||
|
||||
// Check if same dimension or cross-dimension
|
||||
if (entity.level().dimension().equals(targetDimension)) {
|
||||
return teleportSameDimension(entity, position);
|
||||
} else {
|
||||
return teleportCrossDimension(entity, targetLevel, position);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport an entity within the same dimension.
|
||||
*
|
||||
* @param entity The entity to teleport
|
||||
* @param position The target position
|
||||
* @return The entity after teleportation
|
||||
*/
|
||||
private static Entity teleportSameDimension(
|
||||
Entity entity,
|
||||
Position position
|
||||
) {
|
||||
if (entity == null || position == null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
// For players, use the connection method for smooth sync
|
||||
if (entity instanceof ServerPlayer player) {
|
||||
player.connection.teleport(
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ(),
|
||||
position.getYaw(),
|
||||
position.getPitch()
|
||||
);
|
||||
|
||||
// Reset fall distance to prevent fall damage after teleport
|
||||
player.fallDistance = 0;
|
||||
player.resetFallDistance();
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[TeleportHelper] Teleported player {} to {}",
|
||||
player.getName().getString(),
|
||||
position.toShortString()
|
||||
);
|
||||
} else {
|
||||
// For other entities, set position and rotation directly
|
||||
entity.teleportTo(
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ()
|
||||
);
|
||||
entity.setYRot(position.getYaw());
|
||||
entity.setXRot(position.getPitch());
|
||||
entity.setYHeadRot(position.getYaw());
|
||||
|
||||
// Reset fall distance to prevent fall damage after teleport
|
||||
entity.fallDistance = 0;
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[TeleportHelper] Teleported entity {} to {}",
|
||||
entity.getName().getString(),
|
||||
position.toShortString()
|
||||
);
|
||||
}
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport an entity across dimensions.
|
||||
*
|
||||
* @param entity The entity to teleport
|
||||
* @param targetLevel The target dimension
|
||||
* @param position The target position
|
||||
* @return The entity after teleportation (may be different instance)
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity teleportCrossDimension(
|
||||
Entity entity,
|
||||
ServerLevel targetLevel,
|
||||
Position position
|
||||
) {
|
||||
if (entity == null || targetLevel == null || position == null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
// For players, use changeDimension with custom teleporter
|
||||
if (entity instanceof ServerPlayer player) {
|
||||
return teleportPlayerCrossDimension(player, targetLevel, position);
|
||||
}
|
||||
|
||||
// For other entities, use changeDimension
|
||||
Entity newEntity = entity.changeDimension(
|
||||
targetLevel,
|
||||
new PositionTeleporter(position)
|
||||
);
|
||||
|
||||
if (newEntity != null) {
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[TeleportHelper] Cross-dimension teleport: {} to {} in {}",
|
||||
entity.getName().getString(),
|
||||
position.toShortString(),
|
||||
targetLevel.dimension().location()
|
||||
);
|
||||
} else {
|
||||
TiedUpMod.LOGGER.warn(
|
||||
"[TeleportHelper] Cross-dimension teleport failed for {}",
|
||||
entity.getName().getString()
|
||||
);
|
||||
}
|
||||
|
||||
return newEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport a player across dimensions.
|
||||
*
|
||||
* @param player The player to teleport
|
||||
* @param targetLevel The target dimension
|
||||
* @param position The target position
|
||||
* @return The player after teleportation
|
||||
*/
|
||||
public static ServerPlayer teleportPlayerCrossDimension(
|
||||
ServerPlayer player,
|
||||
ServerLevel targetLevel,
|
||||
Position position
|
||||
) {
|
||||
if (player == null || targetLevel == null || position == null) {
|
||||
return player;
|
||||
}
|
||||
|
||||
// Use Forge's teleportTo method for cross-dimension
|
||||
player.changeDimension(targetLevel, new PositionTeleporter(position));
|
||||
|
||||
TiedUpMod.LOGGER.info(
|
||||
"[TeleportHelper] Cross-dimension player teleport: {} to {} in {}",
|
||||
player.getName().getString(),
|
||||
position.toShortString(),
|
||||
targetLevel.dimension().location()
|
||||
);
|
||||
|
||||
return player;
|
||||
}
|
||||
|
||||
/**
|
||||
* Teleport a living entity to another entity's position.
|
||||
*
|
||||
* @param entity The entity to teleport
|
||||
* @param target The target entity to teleport to
|
||||
* @return The entity after teleportation
|
||||
*/
|
||||
@Nullable
|
||||
public static Entity teleportToEntity(Entity entity, Entity target) {
|
||||
if (entity == null || target == null) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
Position targetPos = Position.fromEntity(target);
|
||||
return teleportEntity(entity, targetPos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if teleportation to a position is safe.
|
||||
* Checks for solid ground and non-suffocating blocks.
|
||||
*
|
||||
* @param level The level to check in
|
||||
* @param position The position to check
|
||||
* @return true if position is safe for teleportation
|
||||
*/
|
||||
public static boolean isSafePosition(Level level, Position position) {
|
||||
if (level == null || position == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if there's solid ground below
|
||||
var groundPos = position.toBlockPos().below();
|
||||
var groundState = level.getBlockState(groundPos);
|
||||
|
||||
if (!groundState.isSolid()) {
|
||||
return false; // No solid ground
|
||||
}
|
||||
|
||||
// Check if the position itself is not solid (entity can fit)
|
||||
var feetPos = position.toBlockPos();
|
||||
var headPos = feetPos.above();
|
||||
|
||||
var feetState = level.getBlockState(feetPos);
|
||||
var headState = level.getBlockState(headPos);
|
||||
|
||||
return !feetState.isSolid() && !headState.isSolid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a safe position near the target position.
|
||||
* Searches in a small radius for a valid teleport location.
|
||||
*
|
||||
* @param level The level to search in
|
||||
* @param position The target position
|
||||
* @param radius Search radius
|
||||
* @return Safe position or original if none found
|
||||
*/
|
||||
public static Position findSafePosition(
|
||||
Level level,
|
||||
Position position,
|
||||
int radius
|
||||
) {
|
||||
if (level == null || position == null) {
|
||||
return position;
|
||||
}
|
||||
|
||||
// First check if original position is safe
|
||||
if (isSafePosition(level, position)) {
|
||||
return position;
|
||||
}
|
||||
|
||||
// Search in expanding circles
|
||||
for (int r = 1; r <= radius; r++) {
|
||||
for (int x = -r; x <= r; x++) {
|
||||
for (int z = -r; z <= r; z++) {
|
||||
// Only check edge of current radius
|
||||
if (Math.abs(x) != r && Math.abs(z) != r) continue;
|
||||
|
||||
Position testPos = new Position(
|
||||
position.getX() + x,
|
||||
position.getY(),
|
||||
position.getZ() + z,
|
||||
position.getYaw(),
|
||||
position.getPitch(),
|
||||
position.getDimension()
|
||||
);
|
||||
|
||||
if (isSafePosition(level, testPos)) {
|
||||
return testPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No safe position found, return original
|
||||
TiedUpMod.LOGGER.warn(
|
||||
"[TeleportHelper] No safe position found near {}",
|
||||
position.toShortString()
|
||||
);
|
||||
return position;
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// CUSTOM TELEPORTER FOR FORGE
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Custom teleporter that preserves exact position and rotation.
|
||||
*/
|
||||
private static class PositionTeleporter implements ITeleporter {
|
||||
|
||||
private final Position position;
|
||||
|
||||
public PositionTeleporter(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity placeEntity(
|
||||
Entity entity,
|
||||
ServerLevel currentWorld,
|
||||
ServerLevel destWorld,
|
||||
float yaw,
|
||||
Function<Boolean, Entity> repositionEntity
|
||||
) {
|
||||
// Reposition the entity first (handles mounting, leashing, etc.)
|
||||
Entity repositioned = repositionEntity.apply(false);
|
||||
|
||||
if (repositioned != null) {
|
||||
// Set exact position and rotation
|
||||
repositioned.teleportTo(
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ()
|
||||
);
|
||||
repositioned.setYRot(position.getYaw());
|
||||
repositioned.setXRot(position.getPitch());
|
||||
repositioned.setYHeadRot(position.getYaw());
|
||||
}
|
||||
|
||||
return repositioned;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PortalInfo getPortalInfo(
|
||||
Entity entity,
|
||||
ServerLevel destWorld,
|
||||
Function<ServerLevel, PortalInfo> defaultPortalInfo
|
||||
) {
|
||||
return new PortalInfo(
|
||||
new Vec3(position.getX(), position.getY(), position.getZ()),
|
||||
Vec3.ZERO, // No velocity
|
||||
position.getYaw(),
|
||||
position.getPitch()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVanilla() {
|
||||
return false; // Custom teleporter
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playTeleportSound(
|
||||
ServerPlayer player,
|
||||
ServerLevel sourceWorld,
|
||||
ServerLevel destWorld
|
||||
) {
|
||||
return false; // No teleport sound
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user