Skip to content

Commit

Permalink
POIs will now only respawn 10 seconds after the last player leaves (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
Njol authored Aug 22, 2024
1 parent b0f80b0 commit fb5bce7
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 30 deletions.
6 changes: 6 additions & 0 deletions src/main/java/com/playmonumenta/structures/StructuresAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.entity.Tameable;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
Expand Down Expand Up @@ -679,6 +680,11 @@ private static boolean entityShouldBeRemoved(final Entity entity) {
return false;
}

/* Keep entities that a player is riding (mostly boats - horses are already not removed in any case) */
if (entity.getPassengers().stream().anyMatch(passenger -> passenger instanceof Player)) {
return false;
}

/* Remove otherwise */
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.regex.Pattern;
import javax.annotation.Nullable;
import net.kyori.adventure.text.Component;
Expand Down Expand Up @@ -57,6 +58,9 @@ private enum NearbyState {
NO_PLAYER_WITHIN
}

// Minimum respawn timer value while players are inside a POI to prevent immediate respawns when leaving
private static final int MIN_TICKS_LEFT_WITH_PLAYERS_INSIDE = 20 * 10;

private final StructuresPlugin mPlugin;
private final World mWorld;
private final Random mRandom;
Expand Down Expand Up @@ -323,8 +327,7 @@ public void respawn() {

StructuresAPI.loadAndPasteStructure(respawnPath, new Location(mWorld, mLoadPos.getBlockX(), mLoadPos.getBlockY(), mLoadPos.getBlockZ()), true, false).whenComplete((unused, exception) -> {
if (exception != null) {
mPlugin.getLogger().severe("Failed to respawn structure '" + mConfigLabel + "'");
exception.printStackTrace();
mPlugin.getLogger().log(Level.SEVERE, "Failed to respawn structure '" + mConfigLabel + "'", exception);
} else if (mPostRespawnCommand != null) {
Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), mPostRespawnCommand);
}
Expand Down Expand Up @@ -371,7 +374,9 @@ public void forcedRespawn(Player player, boolean ignoreDefaultSpawnerCount) {

public void tellRespawnTime(Player player) {
Component message = Component.text(
mTicksLeft <= 0 ? mName + " will respawn when empty." : mName + " is respawning in " + MessagingUtils.durationToString(mTicksLeft),
mTicksLeft <= MIN_TICKS_LEFT_WITH_PLAYERS_INSIDE && !mForcedRespawn && mNextRespawnPath == null
? mName + " will respawn once all players have left the area."
: mName + " is respawning in " + MessagingUtils.durationToString(mTicksLeft) + (mForcedRespawn || mNextRespawnPath != null ? "" : " once all players have left the area."),
mTicksLeft <= 600 ? NamedTextColor.RED : NamedTextColor.GREEN
).decorate(TextDecoration.BOLD);

Expand Down Expand Up @@ -483,37 +488,40 @@ public void tick(int ticks) {
}
}

mTicksLeft -= ticks;

if (mTicksLeft < 0) {
boolean isPlayerNearby = false;
boolean isPlayerWithin = false;
boolean isAmped = mNextRespawnPath != null;

for (Player player : mWorld.getPlayers()) {
if (player.getGameMode() != GameMode.SPECTATOR) {
if (isWithin(player)) {
isPlayerNearby = true;
isPlayerWithin = true;
break;
} else if (isNearby(player)) {
isPlayerNearby = true;
/* Don't break - another player might still be within */
}
boolean isPlayerNearby = false;
boolean isPlayerWithin = false;
for (Player player : mWorld.getPlayers()) {
if (player.getGameMode() != GameMode.SPECTATOR) {
if (isWithin(player)) {
isPlayerNearby = true;
isPlayerWithin = true;
break;
} else if (isNearby(player)) {
isPlayerNearby = true;
/* Don't break - another player might still be within */
}
}
}

boolean isAmped = mNextRespawnPath != null;
/*
* To respawn, a player must be nearby (within the outer detection zone)
* AND one of the following conditions
*/
boolean shouldRespawn = isPlayerNearby &&
(mForcedRespawn || // The POI was force to respawn by a player
isAmped || // The POI is amplified for the next spawn
mPlayerNearbyLastTick == NearbyState.NO_PLAYER_WITHIN || // There was no player nearby last check (they teleported in)
!isPlayerWithin); // There is no player within the POI itself, just nearby OR respawn is forced

if (isPlayerWithin && !shouldRespawn) {
// With players inside and no (forced) respawn happening, stop the timer before it gets to zero
mTicksLeft = Math.max(MIN_TICKS_LEFT_WITH_PLAYERS_INSIDE, mTicksLeft - ticks);
} else {
mTicksLeft -= ticks;
}

/*
* To respawn, a player must be nearby (within the outer detection zone)
* AND one of the following conditions
*/
boolean shouldRespawn = isPlayerNearby &&
(mForcedRespawn || // The POI was force to respawn by a player
isAmped || // The POI is amplified for the next spawn
mPlayerNearbyLastTick == NearbyState.NO_PLAYER_WITHIN || // There was no player nearby last check (they teleported in)
!isPlayerWithin); // There is no player within the POI itself, just nearby OR respawn is forced

if (mTicksLeft < 0) {
mPlayerNearbyLastTick = isPlayerNearby ? NearbyState.PLAYER_WITHIN : NearbyState.NO_PLAYER_WITHIN;

if (shouldRespawn) {
Expand Down Expand Up @@ -582,6 +590,20 @@ public World getWorld() {
return mWorld;
}

/**
* The display name of this structure
*/
public String getName() {
return mName;
}

/**
* The label of this structure, e.g. used in commands
*/
public String getConfigLabel() {
return mConfigLabel;
}

public void registerZone() {
RespawnManager respawnManager = StructuresPlugin.getRespawnManager();
ZoneNamespace zoneNamespaceInside = respawnManager.mZoneNamespaceInside;
Expand Down

0 comments on commit fb5bce7

Please sign in to comment.