// (c) 1995-2014 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// snapshot.c
// ============================================================================
#include "snapshot.h"
+#ifdef DEBUG
+#define DEBUG_SNAPSHOTS 0
+#endif
+
static ListNode *snapshot_single = NULL;
static ListNode *snapshot_list = NULL;
static ListNode *snapshot_current = NULL;
-static int num_snapshots_in_list = 0;
-
-
-#ifdef DEBUG
-#define DEBUG_SNAPSHOTS 0
-#endif
+static int num_snapshots = 0;
+static int num_snapshot_buffers = 0;
+static int num_snapshot_bytes = 0;
+static int next_snapshot_key = 0;
// -----------------------------------------------------------------------------
memcpy(bi->buffer_copy, buffer, size);
addNodeToList(snapshot_buffers, NULL, bi);
+
+ num_snapshot_buffers++;
+ num_snapshot_bytes += size;
}
static void LoadSnapshotBuffer(struct SnapshotNodeInfo *bi)
}
}
+static void FreeSnapshotBuffer(void *bi_raw)
+{
+ struct SnapshotNodeInfo *bi = (struct SnapshotNodeInfo *)bi_raw;
+
+ num_snapshot_buffers--;
+ num_snapshot_bytes -= bi->size;
+
+ checked_free(bi->buffer_copy);
+ checked_free(bi);
+}
+
void FreeSnapshotBuffers(ListNode *snapshot_buffers)
{
while (snapshot_buffers != NULL)
- deleteNodeFromList(&snapshot_buffers, snapshot_buffers->key, checked_free);
+ deleteNodeFromList(&snapshot_buffers, NULL, FreeSnapshotBuffer);
}
// -----------------------------------------------------------------------------
-// functions for handling one of several snapshots
+// functions for handling single shapshot or list of snapshots
// -----------------------------------------------------------------------------
-static void FreeSnapshotExt(void *snapshot_buffers_ptr)
+static void FreeSnapshot(void *snapshot_buffers_ptr)
{
FreeSnapshotBuffers(snapshot_buffers_ptr);
}
-void FreeSnapshotSingle()
+void FreeSnapshotSingle(void)
{
FreeSnapshotBuffers(snapshot_single);
snapshot_single = NULL;
}
-void FreeSnapshotList_UpToNode(ListNode *node)
+static void FreeSnapshotList_UpToNode(ListNode *node)
{
while (snapshot_list != node)
{
- deleteNodeFromList(&snapshot_list, snapshot_list->key, FreeSnapshotExt);
+#if DEBUG_SNAPSHOTS
+ Debug("snapshot:FreeSnapshotList_UpToNode", "[%s, %d, %d]",
+ snapshot_list->key, num_snapshot_buffers, num_snapshot_bytes);
+#endif
+
+ deleteNodeFromList(&snapshot_list, snapshot_list->key, FreeSnapshot);
- num_snapshots_in_list--;
+ num_snapshots--;
+ next_snapshot_key = (snapshot_list ? atoi(snapshot_list->key) + 1 : 0);
}
}
-void FreeSnapshotList()
+void FreeSnapshotList(void)
{
+#if DEBUG_SNAPSHOTS
+ Debug("snapshot:FreeSnapshotList", "");
+#endif
+
FreeSnapshotList_UpToNode(NULL);
+ num_snapshots = 0;
+ num_snapshot_buffers = 0;
+ num_snapshot_bytes = 0;
+ next_snapshot_key = 0;
+
snapshot_current = NULL;
}
+static void ReduceSnapshotList(void)
+{
+#if DEBUG_SNAPSHOTS
+ int num_snapshots_last = num_snapshots;
+#endif
+
+ // maximum number of snapshots exceeded -- thin out list of snapshots
+ ListNode *node = snapshot_list;
+ int num_snapshots_to_skip = num_snapshots / 10;
+
+ // do not remove the newest snapshots from the list
+ while (node && num_snapshots_to_skip--)
+ node = node->next;
+
+ // remove every second snapshot from the remaining list
+ while (node)
+ {
+ // never delete the first list node (snapshot at game start)
+ if (node->next == NULL)
+ break;
+
+ // in alternation, delete one node from the list ...
+ deleteNodeFromList(&node, node->key, FreeSnapshot);
+ num_snapshots--;
+
+ // ... and keep one node (which always exists here)
+ node = node->next;
+ }
+
+#if DEBUG_SNAPSHOTS
+ Debug("snapshot:ReduceSnapshotList",
+ "(Reducing number of snapshots from %d to %d.)",
+ num_snapshots_last, num_snapshots);
+
+#if 0
+ node = snapshot_list;
+ while (node)
+ {
+ Debug("snapshot:ReduceSnapshotList", "key: %s", node->key);
+
+ node = node->next;
+ }
+#endif
+#endif
+}
+
void SaveSnapshotSingle(ListNode *snapshot_buffers)
{
if (snapshot_single)
if (snapshot_current != snapshot_list)
FreeSnapshotList_UpToNode(snapshot_current);
- addNodeToList(&snapshot_list, i_to_a(num_snapshots_in_list),
+#if DEBUG_SNAPSHOTS
+ Debug("snapshot:SaveSnapshotToList",
+ "[%d] [%d snapshots, %d buffers, %d bytes]",
+ next_snapshot_key, num_snapshots,
+ num_snapshot_buffers, num_snapshot_bytes);
+#endif
+
+ addNodeToList(&snapshot_list, i_to_a(next_snapshot_key),
snapshot_buffers);
snapshot_current = snapshot_list;
- num_snapshots_in_list++;
+ num_snapshots++;
+ next_snapshot_key++;
-#if DEBUG_SNAPSHOTS
- printf("::: SaveSnapshotToList() [%s]\n", snapshot_current->key);
-#endif
+ if (num_snapshot_bytes > setup.engine_snapshot_memory)
+ ReduceSnapshotList();
}
-boolean LoadSnapshotSingle()
+boolean LoadSnapshotSingle(void)
{
if (snapshot_single)
{
return FALSE;
}
-boolean LoadSnapshotFromList_Older()
+boolean LoadSnapshotFromList_Older(int steps)
{
- if (snapshot_current->next)
+ if (snapshot_current && snapshot_current->next)
{
- snapshot_current = snapshot_current->next;
+ while (snapshot_current->next && steps--)
+ snapshot_current = snapshot_current->next;
LoadSnapshotBuffers(snapshot_current->content);
#if DEBUG_SNAPSHOTS
- printf("::: LoadSnapshotFromList_Older() [%s]\n", snapshot_current->key);
+ Debug("snapshot:LoadSnapshotFromList_Older", "[%s]", snapshot_current->key);
#endif
return TRUE;
return FALSE;
}
-boolean LoadSnapshotFromList_Newer()
+boolean LoadSnapshotFromList_Newer(int steps)
{
- if (snapshot_current->prev)
+ if (snapshot_current && snapshot_current->prev)
{
- snapshot_current = snapshot_current->prev;
+ while (snapshot_current->prev && steps--)
+ snapshot_current = snapshot_current->prev;
LoadSnapshotBuffers(snapshot_current->content);
#if DEBUG_SNAPSHOTS
- printf("::: LoadSnapshotFromList_Newer() [%s]\n", snapshot_current->key);
+ Debug("snapshot:LoadSnapshotFromList_Newer", "[%s]", snapshot_current->key);
#endif
return TRUE;
return FALSE;
}
+
+boolean CheckSnapshotList(void)
+{
+ return (snapshot_list ? TRUE : FALSE);
+}