Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
ac0a158
WIP permission for back on death.
vLuckyyy Sep 13, 2025
32bce4b
Improve back logic
Jakubk15 Oct 4, 2025
1b130ad
Merge branch 'master' into back-on-deatch-permission-wip
Jakubk15 Oct 4, 2025
c733197
Update eternalcore-core/src/main/java/com/eternalcode/core/configurat…
Jakubk15 Oct 4, 2025
a2b33a8
Adjust to others' suggestions
Jakubk15 Oct 11, 2025
043f190
Document tpaTimer to also work for /back command
Jakubk15 Oct 11, 2025
98fc5f6
Simplify if-else statement
Jakubk15 Oct 11, 2025
d973b9c
Merge branch 'master' into back-on-deatch-permission-wip
Jakubk15 Oct 11, 2025
ad729d7
Merge branch 'master' into back-on-deatch-permission-wip
Jakubk15 Oct 18, 2025
ed16382
Add missing comma
Jakubk15 Oct 18, 2025
265a842
wip
Jakubk15 Oct 18, 2025
cc42f2d
Update messages
Jakubk15 Oct 18, 2025
75ea7fd
Adjust to others' suggestions (WIP)
Jakubk15 Oct 24, 2025
738ee16
Remove unused imports
Jakubk15 Oct 24, 2025
29b76e2
Create a default executor for /back command
Jakubk15 Oct 24, 2025
16362d6
Add proper permission to BackCommand
Jakubk15 Oct 25, 2025
8f7ffa1
Reduce nesting level
Jakubk15 Oct 25, 2025
282c4bd
Properly send a message to player when teleporting back
Jakubk15 Oct 25, 2025
b41d2d4
Fix ClassCastException
Jakubk15 Oct 25, 2025
ecae120
Revert accidental world name change
Jakubk15 Oct 28, 2025
52a5d8a
Encapsulate classes
Jakubk15 Oct 28, 2025
ca54463
Merge branch 'master' into back-on-deatch-permission-wip
Jakubk15 Nov 22, 2025
8a61a51
Delete deprecated translations in favor for the new dedicated back se…
Jakubk15 Nov 22, 2025
16b10fe
Fix comment formatting in TeleportRequestConfig
Jakubk15 Nov 22, 2025
5fc66b8
Merge branch 'master' into back-on-deatch-permission-wip
Jakubk15 Nov 30, 2025
6518f6c
Rename `backTeleportTimer` to `backTeleportTime` in BackSettings, Bac…
vLuckyyy Dec 1, 2025
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
@@ -0,0 +1,17 @@
package com.eternalcode.core.configuration.migrations;

import eu.okaeri.configs.migrate.builtin.NamedMigration;

import static eu.okaeri.configs.migrate.ConfigMigrationDsl.move;

public class Migration_0010_Move_back_to_dedicated_section extends NamedMigration {
Migration_0010_Move_back_to_dedicated_section() {
super(
"Improve homes config",
move("teleport.teleportedToLastLocation", "back.lastLocationNoExist"),
move("teleport.teleportedSpecifiedPlayerLastLocation", "back.teleportedSpecifiedPlayerLastLocation"),
move("teleport.lastLocationNoExist", "back.lastLocationNoExist")
);
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
package com.eternalcode.core.feature.back;

import com.eternalcode.annotations.scan.command.DescriptionDocs;
import com.eternalcode.core.feature.back.BackService.BackLocation;
import com.eternalcode.core.injector.annotations.Inject;
import com.eternalcode.core.notice.NoticeService;
import com.eternalcode.core.viewer.Viewer;
import dev.rollczi.litecommands.annotations.argument.Arg;
import dev.rollczi.litecommands.annotations.command.Command;
import dev.rollczi.litecommands.annotations.context.Sender;
import dev.rollczi.litecommands.annotations.execute.Execute;
import dev.rollczi.litecommands.annotations.permission.Permission;
import java.util.Optional;
import org.bukkit.entity.Player;
import panda.std.Pair;

@Command(name = "back")
public class BackCommand {

private final BackService backService;
private final NoticeService noticeService;

@Inject
public BackCommand(BackService backService, NoticeService noticeService) {
this.backService = backService;
this.noticeService = noticeService;
}

@Execute(name = "death")
@Permission("eternalcore.back.death")
@DescriptionDocs(description = "Teleport to your last death location")
public void executeBackDeath(@Sender Player player) {
Optional<Pair<BackLocation, BackLocation>> backPair = this.backService.getBackLocationPair(player.getUniqueId());

if (backPair.isEmpty() || backPair.get().getFirst() == null) {
this.noticeService.player(player.getUniqueId(), translation -> translation.back().lastLocationNoExist());
return;
}

BackLocation deathLocation = backPair.get().getFirst();
this.backService.teleportBack(player, deathLocation.location());
this.noticeService.player(player.getUniqueId(), translation -> translation.back().teleportedToLastLocation());
}

@Execute(name = "teleport")
@Permission("eternalcore.back.teleport")
@DescriptionDocs(description = "Teleport to your last teleport location")
public void executeBackTeleport(@Sender Player player) {
Optional<Pair<BackLocation, BackLocation>> backPair = this.backService.getBackLocationPair(player.getUniqueId());

if (backPair.isEmpty() || backPair.get().getSecond() == null) {
this.noticeService.player(player.getUniqueId(), translation -> translation.back().lastLocationNoExist());
return;
}

BackLocation teleportLocation = backPair.get().getSecond();
this.backService.teleportBack(player, teleportLocation.location());
this.noticeService.player(player.getUniqueId(), translation -> translation.back().teleportedToLastLocation());
}

@Execute(name = "death")
@Permission("eternalcore.back.death.other")
@DescriptionDocs(description = "Teleport specified player to their last death location", arguments = "<player>")
public void executeBackDeathOther(@Sender Viewer viewer, @Arg Player target) {
Optional<Pair<BackLocation, BackLocation>> backPair = this.backService.getBackLocationPair(target.getUniqueId());

if (backPair.isEmpty() || backPair.get().getFirst() == null) {
this.noticeService.viewer(viewer, translation -> translation.back().lastLocationNoExist());
return;
}

BackLocation deathLocation = backPair.get().getFirst();
this.backService.teleportBack(target, deathLocation.location());
this.noticeService.player(target.getUniqueId(), translation -> translation.back().teleportedToLastLocation());

this.noticeService.create()
.viewer(viewer)
.notice(translation -> translation.back().teleportedSpecifiedPlayerLastLocation())
.placeholder("{PLAYER}", target.getName())
.send();
}

@Execute(name = "teleport")
@Permission("eternalcore.back.teleport.other")
@DescriptionDocs(description = "Teleport specified player to their last teleport location", arguments = "<player>")
public void executeBackTeleportOther(@Sender Viewer viewer, @Arg Player target) {
Optional<Pair<BackLocation, BackLocation>> backPair = this.backService.getBackLocationPair(target.getUniqueId());

if (backPair.isEmpty() || backPair.get().getSecond() == null) {
this.noticeService.viewer(viewer, translation -> translation.back().lastLocationNoExist());
return;
}

BackLocation teleportLocation = backPair.get().getSecond();
this.backService.teleportBack(target, teleportLocation.location());
this.noticeService.player(target.getUniqueId(), translation -> translation.back().teleportedToLastLocation());

this.noticeService.create()
.viewer(viewer)
.notice(translation -> translation.back().teleportedSpecifiedPlayerLastLocation())
.placeholder("{PLAYER}", target.getName())
.send();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.eternalcode.core.feature.back;

import com.eternalcode.core.injector.annotations.Inject;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerTeleportEvent;

public class BackController implements Listener {

private final BackService backService;

@Inject
public BackController(BackService backService) {
this.backService = backService;
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
Player entity = event.getEntity();

this.backService.setBackLocation(entity.getUniqueId(), entity.getLocation(), true);
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerTeleport(PlayerTeleportEvent event) {
if (event.getCause() == PlayerTeleportEvent.TeleportCause.PLUGIN) {
return;
}

this.backService.setBackLocation(event.getPlayer().getUniqueId(), event.getFrom(), false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.eternalcode.core.feature.back;

import com.eternalcode.commons.bukkit.position.PositionAdapter;
import com.eternalcode.core.feature.teleport.TeleportService;
import com.eternalcode.core.feature.teleport.TeleportTaskService;
import com.eternalcode.core.feature.teleportrequest.TeleportRequestSettings;
import com.eternalcode.core.injector.annotations.Inject;
import com.eternalcode.core.injector.annotations.component.Service;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import panda.std.Pair;

@Service
public class BackService {

private final TeleportService teleportService;
private final TeleportTaskService teleportTaskService;
private final TeleportRequestSettings settings;

private final Cache<UUID, Pair<BackLocation, BackLocation>> backLocationsCache;

@Inject
public BackService(
TeleportService teleportService,
TeleportTaskService teleportTaskService,
TeleportRequestSettings settings
) {
this.teleportService = teleportService;
this.teleportTaskService = teleportTaskService;
this.settings = settings;

this.backLocationsCache = Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(2, TimeUnit.HOURS)
.build();
}

public Optional<Pair<BackLocation, BackLocation>> getBackLocationPair(UUID playerId) {
return Optional.ofNullable(backLocationsCache.getIfPresent(playerId));
}

public void setBackLocation(UUID playerId, Location location, boolean isFromDeath) {
Pair<BackLocation, BackLocation> existing = backLocationsCache.getIfPresent(playerId);
BackLocation newLocation = new BackLocation(location);
BackLocation deathLocation;
BackLocation normalLocation;
if (existing == null) {
deathLocation = isFromDeath ? newLocation : null;
normalLocation = isFromDeath ? null : newLocation;
}
else {
deathLocation = isFromDeath ? newLocation : existing.getFirst();
normalLocation = isFromDeath ? existing.getSecond() : newLocation;
}
backLocationsCache.put(playerId, Pair.of(deathLocation, normalLocation));
}

public void teleportBack(Player player, Location location) {
if (player.hasPermission("eternalcore.teleport.bypass")) {
teleportService.teleport(player, location);
}
else {
teleportTaskService.createTeleport(
player.getUniqueId(),
PositionAdapter.convert(player.getLocation()),
PositionAdapter.convert(location),
settings.tpaTimer()
);
}
}

public record BackLocation(Location location) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.eternalcode.core.feature.back.messages;

import com.eternalcode.multification.notice.Notice;

public interface BackMessages {

Notice lastLocationNoExist();

Notice teleportedToLastLocation();

Notice teleportedSpecifiedPlayerLastLocation();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.eternalcode.core.feature.back.messages;

import com.eternalcode.multification.notice.Notice;
import eu.okaeri.configs.OkaeriConfig;
import lombok.Getter;
import lombok.experimental.Accessors;

@Getter
@Accessors(fluent = true)
public class ENBackMessages extends OkaeriConfig implements BackMessages {

public Notice lastLocationNoExist = Notice.chat("<red>► <white>You don't have any last location to teleport to!");
public Notice teleportedToLastLocation = Notice.chat("<green>► <white>You have been teleported to your last location!");
public Notice teleportedSpecifiedPlayerLastLocation = Notice.chat("<green>► <white>Player <green>{PLAYER} <white>has been teleported to their last location!");

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.eternalcode.core.feature.back.messages;

import com.eternalcode.multification.notice.Notice;
import eu.okaeri.configs.OkaeriConfig;
import lombok.Getter;
import lombok.experimental.Accessors;

@Getter
@Accessors(fluent = true)
public class PLBackMessages extends OkaeriConfig implements BackMessages {

public Notice lastLocationNoExist = Notice.chat("<red>► <white>Nie masz żadnej ostatniej lokalizacji, do której można się teleportować!");
public Notice teleportedToLastLocation = Notice.chat("<green>► <white>Zostałeś przeteleportowany do ostatniej lokalizacji!");
public Notice teleportedSpecifiedPlayerLastLocation = Notice.chat("<green>► <white>Gracz <green>{PLAYER} <white>został przeteleportowany do swojej ostatniej lokalizacji!");

}

This file was deleted.

Loading