respawn naturals while chunk loaded
This commit is contained in:
parent
63ca3220d1
commit
c5d89c898a
2 changed files with 114 additions and 33 deletions
|
|
@ -21,7 +21,7 @@
|
|||
"id": "pickup:forest_herb_01",
|
||||
"item": "item:forest_herb",
|
||||
"pos": [120, 140],
|
||||
"respawn_seconds": 5
|
||||
"respawn_seconds": 10
|
||||
},
|
||||
{
|
||||
"id": "pickup:rusty_coin_01",
|
||||
|
|
|
|||
|
|
@ -158,11 +158,6 @@ 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;
|
||||
|
|
@ -173,42 +168,29 @@ public partial class ChunkManager : Node2D
|
|||
|
||||
foreach (var p in data.pickups)
|
||||
{
|
||||
if (_save == null || PickupMarkerScene == null)
|
||||
return;
|
||||
if (_save == null || PickupMarkerScene == null) return;
|
||||
|
||||
// Unnatural / one-time pickups
|
||||
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)
|
||||
|
||||
SpawnPickupMarker(chunkNode, p);
|
||||
continue;
|
||||
}
|
||||
|
||||
var marker = (PickupMarker)PickupMarkerScene.Instantiate();
|
||||
marker.Position = new Vector2(p.pos[0], p.pos[1]);
|
||||
marker.PickupId = p.id;
|
||||
marker.ItemId = p.item;
|
||||
|
||||
marker.PickedUp += (pickupId, itemId) =>
|
||||
// Natural pickups: check cooldown
|
||||
//var now = NowUnixSeconds();
|
||||
if (_save.State.PickupRespawnAt.TryGetValue(p.id, out var respawnAt) && now < respawnAt)
|
||||
{
|
||||
GD.Print($"Picked up {itemId} ({pickupId})");
|
||||
|
||||
if (p.respawn_seconds <= 0)
|
||||
{
|
||||
_save.State.CollectedPickups.Add(pickupId);
|
||||
}
|
||||
else
|
||||
{
|
||||
_save.State.PickupRespawnAt[pickupId] = NowUnixSeconds() + p.respawn_seconds;
|
||||
// Chunk is loaded but pickup is still cooling down -> schedule its appearance.
|
||||
SchedulePickupRespawn(chunkNode, p.id, p.item, p.respawn_seconds, respawnAt, new int[] { p.pos[0], p.pos[1] });
|
||||
continue;
|
||||
}
|
||||
|
||||
_save.Save();
|
||||
marker.QueueFree();
|
||||
};
|
||||
chunkNode.AddChild(marker);
|
||||
// Ready now -> spawn immediately
|
||||
SpawnPickupMarker(chunkNode, p);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -247,4 +229,103 @@ public partial class ChunkManager : Node2D
|
|||
|
||||
// Collision rects: gray outlines (optional later)
|
||||
}
|
||||
|
||||
private static long NowUnixSeconds()
|
||||
{
|
||||
return DateTimeOffset.UtcNow.ToUnixTimeSeconds();
|
||||
}
|
||||
// Timer nodes are attached to the chunk node so they automatically die when the chunk unloads.
|
||||
private const string RespawnTimerPrefix = "RespawnTimer_";
|
||||
private static string RespawnTimerName(string pickupId) => $"{RespawnTimerPrefix}{pickupId.Replace(":", "_")}";
|
||||
// Spawn a pickup marker in world-space (y-sort friendly later).
|
||||
private void SpawnPickupMarker(Node2D chunkNode, ChunkPickup p)
|
||||
{
|
||||
if (_save == null || PickupMarkerScene == null) return;
|
||||
|
||||
var marker = (PickupMarker)PickupMarkerScene.Instantiate();
|
||||
marker.Position = new Vector2(p.pos[0], p.pos[1]);
|
||||
marker.PickupId = p.id;
|
||||
marker.ItemId = p.item;
|
||||
|
||||
// Capture only the values we need (avoid relying on foreach capture semantics).
|
||||
var respawnSeconds = p.respawn_seconds;
|
||||
var pickupId = p.id;
|
||||
var itemId = p.item;
|
||||
var posCopy = new int[] { p.pos[0], p.pos[1] };
|
||||
|
||||
marker.PickedUp += (_, __) =>
|
||||
{
|
||||
if (_save == null) return;
|
||||
|
||||
// Permanent pickups (unnatural): one-time removal.
|
||||
if (respawnSeconds <= 0)
|
||||
{
|
||||
_save.State.CollectedPickups.Add(pickupId);
|
||||
_save.Save();
|
||||
marker.QueueFree();
|
||||
return;
|
||||
}
|
||||
|
||||
// Natural pickups: schedule respawn by absolute timestamp.
|
||||
var respawnAt = NowUnixSeconds() + respawnSeconds;
|
||||
_save.State.PickupRespawnAt[pickupId] = respawnAt;
|
||||
_save.Save();
|
||||
|
||||
marker.QueueFree();
|
||||
|
||||
// If chunk stays loaded, respawn should still appear.
|
||||
SchedulePickupRespawn(chunkNode, pickupId, itemId, respawnSeconds, respawnAt, posCopy);
|
||||
};
|
||||
|
||||
chunkNode.AddChild(marker);
|
||||
}
|
||||
|
||||
// Schedule a respawn for a pickup that is currently on cooldown.
|
||||
private void SchedulePickupRespawn(
|
||||
Node2D chunkNode,
|
||||
string pickupId,
|
||||
string itemId,
|
||||
int respawnSeconds,
|
||||
long respawnAtUnix,
|
||||
int[] pos)
|
||||
{
|
||||
// Deduplicate: one timer per pickup per loaded chunk.
|
||||
var timerName = RespawnTimerName(pickupId);
|
||||
if (chunkNode.HasNode(timerName))
|
||||
return;
|
||||
|
||||
var now = NowUnixSeconds();
|
||||
var wait = Math.Max(0.1, respawnAtUnix - now); // remaining time (accounts for time while chunk was unloaded)
|
||||
|
||||
var timer = new Timer
|
||||
{
|
||||
Name = timerName,
|
||||
OneShot = true,
|
||||
WaitTime = wait
|
||||
};
|
||||
|
||||
timer.Timeout += () =>
|
||||
{
|
||||
if (_save == null) return;
|
||||
|
||||
// Re-check at fire time (handles clock changes / save edits).
|
||||
var now2 = NowUnixSeconds();
|
||||
if (_save.State.PickupRespawnAt.TryGetValue(pickupId, out var ra) && now2 < ra)
|
||||
{
|
||||
// Still not ready: reschedule with the updated remaining time.
|
||||
timer.QueueFree();
|
||||
SchedulePickupRespawn(chunkNode, pickupId, itemId, respawnSeconds, ra, pos);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ready: remove the timer node name and spawn the pickup.
|
||||
timer.QueueFree();
|
||||
|
||||
var p = new ChunkPickup(pickupId, itemId, pos, respawnSeconds);
|
||||
SpawnPickupMarker(chunkNode, p);
|
||||
};
|
||||
|
||||
chunkNode.AddChild(timer);
|
||||
timer.Start();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue