From 63ca3220d169b230f7eb691ae87c03fa0f00fbed Mon Sep 17 00:00:00 2001 From: anonoe <8bdd1ef7-1633-4e26-83a0-8dda8605bcd0@aleeas.com> Date: Tue, 10 Feb 2026 16:11:33 +0100 Subject: [PATCH] basic natural respawn --- packs/base/data/world/chunks/0_0.json | 2 +- scripts/core/SaveState.cs | 5 ++++ scripts/world/ChunkManager.cs | 34 +++++++++++++++++++++++---- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/packs/base/data/world/chunks/0_0.json b/packs/base/data/world/chunks/0_0.json index c752617..3ceb19a 100644 --- a/packs/base/data/world/chunks/0_0.json +++ b/packs/base/data/world/chunks/0_0.json @@ -21,7 +21,7 @@ "id": "pickup:forest_herb_01", "item": "item:forest_herb", "pos": [120, 140], - "respawn_seconds": 600 + "respawn_seconds": 5 }, { "id": "pickup:rusty_coin_01", diff --git a/scripts/core/SaveState.cs b/scripts/core/SaveState.cs index 569654e..8c754c6 100644 --- a/scripts/core/SaveState.cs +++ b/scripts/core/SaveState.cs @@ -3,7 +3,12 @@ using System.Collections.Generic; public class SaveState { + // Permanent one-time removals (e.g. chests, unique items) public HashSet CollectedPickups { get; set; } = new(); + + // Respawnables: pickupId -> unixTimeSeconds when it becomes available again + public Dictionary PickupRespawnAt { get; set; } = new(); + //public Vector2I? LastPlayerChunk { get; set; } // optional debug, requires "using Godot;" //public int[]? LastPlayerChunk { get; set; } // [x,y] same debug as above, does not require Godot } diff --git a/scripts/world/ChunkManager.cs b/scripts/world/ChunkManager.cs index 514b7fc..1e1761a 100644 --- a/scripts/world/ChunkManager.cs +++ b/scripts/world/ChunkManager.cs @@ -158,16 +158,34 @@ public partial class ChunkManager : Node2D return n; } + private static long NowUnixSeconds() + { + return DateTimeOffset.UtcNow.ToUnixTimeSeconds(); + } + private void AddChunkMarkers(Node2D chunkNode, ChunkData data) { if (_save == null || PickupMarkerScene == null) return; if (data.pickups != null && _save != null) { + var now = NowUnixSeconds(); + foreach (var p in data.pickups) { - if (_save.State.CollectedPickups.Contains(p.id)) - continue; // already collected + if (_save == null || PickupMarkerScene == null) + return; + + if (p.respawn_seconds <= 0) + { + if (_save.State.CollectedPickups.Contains(p.id)) + continue; + } + else + { + if (_save.State.PickupRespawnAt.TryGetValue(p.id, out var respawnAt) && now < respawnAt) + continue; + } var marker = (PickupMarker)PickupMarkerScene.Instantiate(); marker.Position = new Vector2(p.pos[0], p.pos[1]); @@ -178,12 +196,18 @@ public partial class ChunkManager : Node2D { GD.Print($"Picked up {itemId} ({pickupId})"); - _save.State.CollectedPickups.Add(pickupId); - _save.Save(); + if (p.respawn_seconds <= 0) + { + _save.State.CollectedPickups.Add(pickupId); + } + else + { + _save.State.PickupRespawnAt[pickupId] = NowUnixSeconds() + p.respawn_seconds; + } + _save.Save(); marker.QueueFree(); }; - chunkNode.AddChild(marker); } }