Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dev.architectury.event.CompoundEventResult;
import dev.architectury.event.EventResult;
import dev.architectury.event.events.common.*;
import dev.ftb.mods.ftbessentials.api.TeleportDestination;
import dev.ftb.mods.ftbessentials.api.event.TeleportImmediateEvent;
import dev.ftb.mods.ftbessentials.api.records.TPARequest;
import dev.ftb.mods.ftbessentials.commands.FTBCommands;
import dev.ftb.mods.ftbessentials.commands.impl.teleporting.TPACommand;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dev.ftb.mods.ftbessentials.api;

import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;
import java.util.UUID;

/**
* Represents a teleport destination used by the various teleportation commands in the mod.
*
* @param dimension the dimension
* @param pos the block position
* @param yRot the player's Y rotation (yaw) on arrival (if empty, use player's current yaw)
* @param xRot the player's X rotation (pitch) on arrival (if empty, use player's current pitch)
* @param playerId the player's UUID, only if this destination was created from a player, null otherwise
*/
public record TeleportDestination(
ResourceKey<Level> dimension,
BlockPos pos,
Optional<Float> yRot,
Optional<Float> xRot,
@Nullable UUID playerId
) {
public TeleportDestination withPos(BlockPos newPos) {
return new TeleportDestination(dimension, newPos, yRot, xRot, playerId);
}

/**
* Return a successful outcome for this destination. See also {@link dev.ftb.mods.ftbessentials.api.event.SavedTeleportEvent.PreTeleport#onTeleport(String, ServerPlayer, TeleportDestination, UUID)}.
*
* @return a successful outcome
*/
public Outcome success() {
return new Outcome(this, Component.empty());
}

/**
* Return a successful outcome with a new destination.
*
* @return a successful outcome
*/
public Outcome success(TeleportDestination newDest) {
return new Outcome(newDest, Component.empty());
}

/**
* Return a successful outcome for this destination. See also {@link dev.ftb.mods.ftbessentials.api.event.SavedTeleportEvent.PreTeleport#onTeleport(String, ServerPlayer, TeleportDestination, UUID)}.
*
* @param reason the failure reason to report to the player
* @return a failed outcome
*/
public Outcome failed(Component reason) {
return new Outcome(this, reason);
}

public record Outcome(TeleportDestination dest, Component reason) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package dev.ftb.mods.ftbessentials.api;

import dev.ftb.mods.ftblibrary.util.TimeUtils;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;

import java.util.function.LongSupplier;

@FunctionalInterface
public interface TeleportResult {
int runCommand(ServerPlayer player);

default boolean isSuccess() {
return false;
}

static TeleportResult failed(Component msg) {
return player -> {
player.displayClientMessage(msg, false);
return 0;
};
}

TeleportResult DIMENSION_NOT_FOUND = failed(Component.translatable("ftbessentials.dimension_not_found"));
TeleportResult UNKNOWN_DESTINATION = failed(Component.translatable("ftbessentials.unknown_dest"));
TeleportResult PREVENTED = failed(Component.translatable("ftbessentials.teleport_prevented"));
TeleportResult DIMENSION_NOT_ALLOWED_FROM = failed(Component.translatable("ftbessentials.teleport.not_from_here"));
TeleportResult DIMENSION_NOT_ALLOWED_TO = failed(Component.translatable("ftbessentials.teleport.not_to_here"));
TeleportResult SUCCESS = new TeleportResult() {
@Override
public int runCommand(ServerPlayer player) {
return 1;
}

@Override
public boolean isSuccess() {
return true;
}
};

@FunctionalInterface
interface OnCooldown extends TeleportResult {
long getCooldown();

@Override
default int runCommand(ServerPlayer player) {
String secStr = TimeUtils.prettyTimeString(getCooldown() / 1000L);
player.displayClientMessage(Component.translatable("ftbessentials.teleport.on_cooldown", secStr), false);
return 0;
}

static OnCooldown create(LongSupplier longSupplier) {
return longSupplier::getAsLong;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package dev.ftb.mods.ftbessentials.api.event;

import dev.architectury.event.CompoundEventResult;
import dev.architectury.event.Event;
import dev.architectury.event.EventFactory;
import dev.ftb.mods.ftbessentials.api.TeleportDestination;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Nullable;

import java.util.UUID;

public interface SavedTeleportEvent {
/**
* See {@link #onAdded(String, TeleportDestination, ServerPlayer, UUID)}
*/
Event<SavedTeleportEvent> ADDED = EventFactory.createLoop();
/**
* See {@link #onDeleted(String, TeleportDestination, UUID)}
*/
Event<SavedTeleportEvent> DELETED = EventFactory.createLoop();
/**
* See {@link PreTeleport#onTeleport(String, ServerPlayer, TeleportDestination, UUID)}
*/
Event<PreTeleport> PRE_TELEPORT = EventFactory.createCompoundEventResult();

/**
* Fired after a saved destination (home or warp) has been added.
*
* @param name the name of the destination
* @param dest the destination that was added
* @param player the player who added the destination
* @param owningPlayer the player's UUID for a home destination, or null for a global warp destination
*/
void onAdded(String name, TeleportDestination dest, ServerPlayer player, @Nullable UUID owningPlayer);

/**
* Fired after a saved destination (home or warp) has been deleted.
*
* @param name the name of the destination
* @param destination the destination that was removed
* @param owningPlayer the player's UUID for a home destination, or null for a global warp destination
*/
void onDeleted(String name, TeleportDestination destination, @Nullable UUID owningPlayer);

@FunctionalInterface
interface PreTeleport {
/**
* Fired when a player is about to teleport to a saved destination (home or warp). This event allows
* the destination to be modified, or the teleportation to be prevented entirely.
* <ul>
* <li>To modify the destination, return {@link CompoundEventResult#interruptTrue(Object)} with a new
* {@link TeleportDestination.Outcome} - see {@link TeleportDestination#success()}</li>
* <li>To prevent teleportation, return {@link CompoundEventResult#interruptFalse(Object)} - see {@link TeleportDestination#failed(Component)}</li>
* <li>To proceed with the default behavior, return {@link CompoundEventResult#pass()}</li>
* </ul>
* See also {@link TeleportEvent}, which is fired <em>after</em> this event, and provides a second opportunity to
* prevent teleportation.
*
* @param name the name of the saved destination
* @param player the player about to teleport
* @param dest the planned teleport destination
* @param owningPlayer UUID of the player who owns the destination; non-null for a player home, null for a global warp
* @return the event result (see above)
*/
CompoundEventResult<TeleportDestination.Outcome> onTeleport(String name, ServerPlayer player, TeleportDestination dest, @Nullable UUID owningPlayer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@
public class TeleportEvent {
public static Event<Teleport> TELEPORT = EventFactory.createCompoundEventResult();

@FunctionalInterface
public interface Teleport {
/**
* Fired when the player is ready to teleport, but before any warmup is started. This can be canceled to prevent
* teleportation by returning {@link CompoundEventResult#interruptFalse(Object)} with a message to supply to the
* player about why teleportation was prevented.
*
* @param player the player about to teleport
* @return the event result
*/
CompoundEventResult<Component> teleport(ServerPlayer player);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package dev.ftb.mods.ftbessentials.api.event;

import dev.architectury.event.CompoundEventResult;
import dev.architectury.event.Event;
import dev.architectury.event.EventFactory;
import dev.ftb.mods.ftbessentials.api.TeleportDestination;
import net.minecraft.server.level.ServerPlayer;

public class TeleportImmediateEvent {
public static Event<TeleportImmediate> TELEPORT = EventFactory.createCompoundEventResult(TeleportImmediate.class);

@FunctionalInterface
public interface TeleportImmediate {
/**
* Fired when the player is just about to teleport, when any possible teleportation warmup is complete.
* <p>
* Teleportation can be prevented by returning a failed outcome e.g. {@code destination.failed(reason)},
* or a modified destination e.g. {@code detination.success(newdest)}.
*
* @param player the player about to teleport
* @param destination the teleport destination
* @return the event outcome
*/
CompoundEventResult<TeleportDestination.Outcome> teleport(ServerPlayer player, TeleportDestination destination);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import dev.ftb.mods.ftbessentials.api.TeleportResult;
import dev.ftb.mods.ftbessentials.api.records.TPARequest;
import dev.ftb.mods.ftbessentials.commands.FTBCommand;
import dev.ftb.mods.ftbessentials.config.FTBEConfig;
Expand Down Expand Up @@ -62,7 +63,7 @@ public int tpa(ServerPlayer player, ServerPlayer target, boolean here) {
return 0;
}

TeleportPos.TeleportResult result = here ?
TeleportResult result = here ?
dataTarget.tpaTeleporter.checkCooldown(target) :
dataSource.tpaTeleporter.checkCooldown(player);

Expand Down Expand Up @@ -127,7 +128,7 @@ public int tpaccept(ServerPlayer player, String id) {
return 0;
}

TeleportPos.TeleportResult result = request.here() ?
TeleportResult result = request.here() ?
request.target().tpaTeleporter.teleport(player, p -> new TeleportPos(sourcePlayer)) :
request.source().tpaTeleporter.teleport(sourcePlayer, p -> new TeleportPos(player));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -247,14 +247,14 @@ public void read(CompoundTag tag) {
god = tag.getBoolean("god");
nick = tag.getString("nick");
recording = RecordingStatus.NAME_MAP.map.getOrDefault(tag.getString("recording"), RecordingStatus.NONE);
lastSeenPos = tag.contains("last_seen") ? new TeleportPos(tag.getCompound("last_seen")) : null;
lastSeenPos = tag.contains("last_seen") ? new TeleportPos(tag.getCompound("last_seen"), uuid) : null;

teleportHistory.clear();

ListTag th = tag.getList("teleport_history", Tag.TAG_COMPOUND);

for (int i = 0; i < th.size(); i++) {
teleportHistory.add(new TeleportPos(th.getCompound(i)));
teleportHistory.add(new TeleportPos(th.getCompound(i), uuid));
}

kitUseTimes.clear();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package dev.ftb.mods.ftbessentials.util;

import dev.ftb.mods.ftbessentials.api.TeleportResult;
import dev.ftb.mods.ftbessentials.api.event.SavedTeleportEvent;
import dev.ftb.mods.ftbessentials.config.FTBEConfig;
import dev.ftb.mods.ftblibrary.snbt.SNBTCompoundTag;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Stream;

public abstract class SavedTeleportManager {
Expand All @@ -19,20 +23,34 @@ public void addDestination(String name, TeleportPos dest, ServerPlayer player) {
throw new TooManyDestinationsException();
}
destinations.put(nameLower, dest);
SavedTeleportEvent.ADDED.invoker().onAdded(name, dest.asDestination(), player, owningPlayer());
onChanged();
}

public boolean deleteDestination(String name) {
if (destinations.remove(name.toLowerCase()) != null) {
TeleportPos removed = destinations.remove(name.toLowerCase());
if (removed != null) {
SavedTeleportEvent.DELETED.invoker().onDeleted(name, removed.asDestination(), owningPlayer());
onChanged();
return true;
}
return false;
}

public TeleportPos.TeleportResult teleportTo(String name, ServerPlayer player, WarmupCooldownTeleporter teleporter) {
public TeleportResult teleportTo(String name, ServerPlayer player, WarmupCooldownTeleporter teleporter) {
TeleportPos pos = destinations.get(name.toLowerCase());
return pos != null ? teleporter.teleport(player, p -> pos) : TeleportPos.TeleportResult.UNKNOWN_DESTINATION;
if (pos == null) {
return TeleportResult.UNKNOWN_DESTINATION;
}

var result = SavedTeleportEvent.PRE_TELEPORT.invoker().onTeleport(name, player, pos.asDestination(), owningPlayer());
if (result.isFalse()) {
return TeleportResult.failed(result.object().reason());
}

TeleportPos newPos = result.isEmpty() ? pos : TeleportPos.fromDestination(result.object().dest());

return newPos != null ? teleporter.teleport(player, p -> newPos) : TeleportResult.UNKNOWN_DESTINATION;
}

public Stream<DestinationEntry> destinations() {
Expand All @@ -48,7 +66,7 @@ public CompoundTag writeNBT() {
public void readNBT(CompoundTag tag) {
destinations.clear();
for (String key : tag.getAllKeys()) {
destinations.put(key, new TeleportPos(tag.getCompound(key)));
destinations.put(key, new TeleportPos(tag.getCompound(key), owningPlayer()));
}
}

Expand All @@ -62,6 +80,9 @@ protected int getMaxSize(ServerPlayer player) {

protected abstract void onChanged();

@Nullable
protected abstract UUID owningPlayer();

public static class HomeManager extends SavedTeleportManager {
private final FTBEPlayerData playerData;

Expand All @@ -78,6 +99,11 @@ protected int getMaxSize(ServerPlayer player) {
protected void onChanged() {
playerData.markDirty();
}

@Override
protected UUID owningPlayer() {
return playerData.getUuid();
}
}

public static class WarpManager extends SavedTeleportManager {
Expand All @@ -91,6 +117,11 @@ public WarpManager(FTBEWorldData worldData) {
protected void onChanged() {
worldData.markDirty();
}

@Override
protected UUID owningPlayer() {
return null;
}
}

public record DestinationEntry(String name, TeleportPos destination) {
Expand Down
Loading
Loading