diff --git a/src/main/java/net/kewwbec/minigames/volume/effect/SpawnItemEffect.java b/src/main/java/net/kewwbec/minigames/volume/effect/SpawnItemEffect.java index d797393..f67e649 100644 --- a/src/main/java/net/kewwbec/minigames/volume/effect/SpawnItemEffect.java +++ b/src/main/java/net/kewwbec/minigames/volume/effect/SpawnItemEffect.java @@ -31,8 +31,8 @@ public final class SpawnItemEffect extends MinigameRuntimeEffect { .add() .append(new KeyedCodec<>("Amount", Codec.INTEGER, false), (effect, value) -> effect.amount = value, effect -> effect.amount) .add() - .append( - new KeyedCodec<>("RespawnDelaySeconds", Codec.INTEGER, false), + .append( + new KeyedCodec<>("RespawnDelaySeconds", Codec.DOUBLE, false), (effect, value) -> effect.respawnDelaySeconds = value, effect -> effect.respawnDelaySeconds ) @@ -51,7 +51,7 @@ public final class SpawnItemEffect extends MinigameRuntimeEffect { private String itemId = ""; private int amount = 1; - private int respawnDelaySeconds = 0; + private double respawnDelaySeconds = 0.0D; private String spawnKey = ""; private double offsetX = 0.0D; private double offsetY = 0.0D; @@ -87,9 +87,9 @@ public final class SpawnItemEffect extends MinigameRuntimeEffect { if (active != null) { activeItems.remove(key); - int delay = Math.max(0, respawnDelaySeconds); - if (delay > 0 && !nextSpawnTimes.containsKey(key)) { - nextSpawnTimes.put(key, Instant.now().plus(Duration.ofSeconds(delay))); + Duration delay = respawnDelay(); + if (!delay.isZero() && !nextSpawnTimes.containsKey(key)) { + nextSpawnTimes.put(key, Instant.now().plus(delay)); return; } } @@ -128,9 +128,9 @@ public final class SpawnItemEffect extends MinigameRuntimeEffect { activeItems.put(key, ref); nextSpawnTimes.remove(key); if (ignoreRespawnTimer) { - int delay = Math.max(0, respawnDelaySeconds); - if (delay > 0) { - nextSpawnTimes.put(key, Instant.now().plus(Duration.ofSeconds(delay))); + Duration delay = respawnDelay(); + if (!delay.isZero()) { + nextSpawnTimes.put(key, Instant.now().plus(delay)); } } runtime(context).ifPresent(runtime -> { @@ -142,6 +142,15 @@ public final class SpawnItemEffect extends MinigameRuntimeEffect { debugMessage(context, TYPE_ID, "FIRED spawned item='" + itemId + "' amount=" + Math.max(1, amount)); } + @Nonnull + private Duration respawnDelay() { + double seconds = Math.max(0.0D, respawnDelaySeconds); + if (seconds <= 0.0D) { + return Duration.ZERO; + } + return Duration.ofNanos(Math.max(1L, Math.round(seconds * 1_000_000_000.0D))); + } + @Nonnull private String key(@Nonnull TriggerContext context) { String configured = spawnKey != null ? spawnKey.trim() : ""; diff --git a/src/main/java/net/kewwbec/minigames/volume/effect/SpawnNpcEffect.java b/src/main/java/net/kewwbec/minigames/volume/effect/SpawnNpcEffect.java index 7322456..0abbca1 100644 --- a/src/main/java/net/kewwbec/minigames/volume/effect/SpawnNpcEffect.java +++ b/src/main/java/net/kewwbec/minigames/volume/effect/SpawnNpcEffect.java @@ -29,8 +29,8 @@ public final class SpawnNpcEffect extends MinigameRuntimeEffect { .add() .append(new KeyedCodec<>("Count", Codec.INTEGER, false), (effect, value) -> effect.count = value, effect -> effect.count) .add() - .append( - new KeyedCodec<>("RespawnDelaySeconds", Codec.INTEGER, false), + .append( + new KeyedCodec<>("RespawnDelaySeconds", Codec.DOUBLE, false), (effect, value) -> effect.respawnDelaySeconds = value, effect -> effect.respawnDelaySeconds ) @@ -61,7 +61,7 @@ public final class SpawnNpcEffect extends MinigameRuntimeEffect { private String roleId = ""; private int count = 1; - private int respawnDelaySeconds = 0; + private double respawnDelaySeconds = 0.0D; private String spawnKey = ""; private double offsetX = 0.0D; private double offsetY = 0.0D; @@ -100,9 +100,9 @@ public final class SpawnNpcEffect extends MinigameRuntimeEffect { } if (nextSpawn == null && activeNpcs.containsKey(key)) { - int delay = Math.max(0, respawnDelaySeconds); - if (delay > 0) { - nextSpawnTimes.put(key, Instant.now().plus(Duration.ofSeconds(delay))); + Duration delay = respawnDelay(); + if (!delay.isZero()) { + nextSpawnTimes.put(key, Instant.now().plus(delay)); return; } } @@ -199,6 +199,15 @@ public final class SpawnNpcEffect extends MinigameRuntimeEffect { return runtimeSegment + "|" + volumeId + "|" + (!configured.isBlank() ? configured : roleId); } + @Nonnull + private Duration respawnDelay() { + double seconds = Math.max(0.0D, respawnDelaySeconds); + if (seconds <= 0.0D) { + return Duration.ZERO; + } + return Duration.ofNanos(Math.max(1L, Math.round(seconds * 1_000_000_000.0D))); + } + /** Drops state belonging to runtimes that no longer exist. */ static void pruneStaleRuntimeKeys(Map... maps) { var services = services(); diff --git a/src/main/resources/Server/Languages/en-US/server.lang b/src/main/resources/Server/Languages/en-US/server.lang index 986acd0..10209e8 100644 --- a/src/main/resources/Server/Languages/en-US/server.lang +++ b/src/main/resources/Server/Languages/en-US/server.lang @@ -27,7 +27,7 @@ customUI.triggerVolumeEffectEditor.field.common.MapId.tooltip = The map id to vo customUI.triggerVolumeEffectEditor.field.common.ItemId = Item customUI.triggerVolumeEffectEditor.field.common.ItemId.tooltip = The item asset id to spawn on the ground. customUI.triggerVolumeEffectEditor.field.common.RespawnDelaySeconds = Respawn Delay -customUI.triggerVolumeEffectEditor.field.common.RespawnDelaySeconds.tooltip = Seconds to wait after the spawned item is picked up or despawns before spawning again. +customUI.triggerVolumeEffectEditor.field.common.RespawnDelaySeconds.tooltip = Seconds to wait before spawning again. Decimals are supported, e.g. 0.5. customUI.triggerVolumeEffectEditor.field.common.SpawnKey = Spawn Key customUI.triggerVolumeEffectEditor.field.common.SpawnKey.tooltip = Optional unique id for this spawn point when one volume has multiple item spawners. customUI.triggerVolumeEffectEditor.field.common.OffsetX = Offset X @@ -64,7 +64,7 @@ customUI.triggerVolumeEffectEditor.field.StartQueuedMinigame.MinigameId.tooltip customUI.triggerVolumeEffectEditor.field.SpawnItem.MinigameId.tooltip = Optional minigame runtime to associate this spawned pickup with. customUI.triggerVolumeEffectEditor.field.SpawnItem.ItemId.tooltip = The item asset id to spawn at this trigger volume. customUI.triggerVolumeEffectEditor.field.SpawnItem.Amount.tooltip = Number of items in the spawned stack. -customUI.triggerVolumeEffectEditor.field.SpawnItem.RespawnDelaySeconds.tooltip = Seconds to wait before respawning after the previous item is picked up or despawns. +customUI.triggerVolumeEffectEditor.field.SpawnItem.RespawnDelaySeconds.tooltip = Seconds to wait before respawning after the previous item is picked up or despawns. Decimals are supported. customUI.triggerVolumeEffectEditor.field.SpawnItem.SpawnKey.tooltip = Optional unique id for this item spawner. customUI.triggerVolumeEffectEditor.field.SpawnItem.OffsetX.tooltip = Spawn position offset on the X axis. customUI.triggerVolumeEffectEditor.field.SpawnItem.OffsetY.tooltip = Spawn position offset on the Y axis. @@ -72,7 +72,7 @@ customUI.triggerVolumeEffectEditor.field.SpawnItem.OffsetZ.tooltip = Spawn posit customUI.triggerVolumeEffectEditor.field.SpawnNpc.MinigameId.tooltip = Optional minigame runtime to associate this spawned NPC with. customUI.triggerVolumeEffectEditor.field.SpawnNpc.RoleId.tooltip = The spawnable NPC role id to spawn. customUI.triggerVolumeEffectEditor.field.SpawnNpc.Count.tooltip = Number of NPCs to keep active for this spawn key. -customUI.triggerVolumeEffectEditor.field.SpawnNpc.RespawnDelaySeconds.tooltip = Seconds to wait before respawning after all active NPCs for this spawn key are gone. +customUI.triggerVolumeEffectEditor.field.SpawnNpc.RespawnDelaySeconds.tooltip = Seconds to wait before respawning after all active NPCs for this spawn key are gone. Decimals are supported. customUI.triggerVolumeEffectEditor.field.SpawnNpc.SpawnKey.tooltip = Optional unique id for this NPC spawner. customUI.triggerVolumeEffectEditor.field.SpawnNpc.OffsetX.tooltip = Spawn position offset on the X axis. customUI.triggerVolumeEffectEditor.field.SpawnNpc.OffsetY.tooltip = Spawn position offset on the Y axis.