From b7c4ed9c6bb0edb8f94ca2afa94c26e49cc3646d Mon Sep 17 00:00:00 2001
From: Nev3r <apophycens@gmail.com>
Date: Sat, 18 Apr 2020 11:34:59 +0200
Subject: [PATCH] Implement dynamic global taggroups/lists functionality.

---
 src/p_saveg.c |  10 +++++
 src/taglist.c | 113 +++++++++++++++++++++++++++++++++++++-------------
 src/taglist.h |   3 ++
 3 files changed, 97 insertions(+), 29 deletions(-)

diff --git a/src/p_saveg.c b/src/p_saveg.c
index 4fdc3d4889..4a414e9e10 100644
--- a/src/p_saveg.c
+++ b/src/p_saveg.c
@@ -1149,6 +1149,12 @@ static void P_NetUnArchiveWorld(void)
 		if (diff2 & SD_TAG)
 		{
 			size_t ncount = READUINT32(get);
+
+			// Remove entries from global lists.
+			for (j = 0; j < sectors[i].tags.count; j++)
+				Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
+
+			// Reallocate if size differs.
 			if (ncount != sectors[i].tags.count)
 			{
 				sectors[i].tags.count = ncount;
@@ -1157,6 +1163,10 @@ static void P_NetUnArchiveWorld(void)
 
 			for (j = 0; j < ncount; j++)
 				sectors[i].tags.tags[j] = READINT16(get);
+
+			// Add new entries.
+			for (j = 0; j < sectors[i].tags.count; j++)
+				Taggroup_Remove(tags_sectors, sectors[i].tags.tags[j], i);
 		}
 
 		if (diff3 & SD_COLORMAP)
diff --git a/src/taglist.c b/src/taglist.c
index 1849c314c4..3b0135abd5 100644
--- a/src/taglist.c
+++ b/src/taglist.c
@@ -63,58 +63,97 @@ boolean Tag_Compare (const taglist_t* list1, const taglist_t* list2)
 	return true;
 }
 
-static void Taglist_AddToSectors (const mtag_t tag, const size_t itemid)
+
+size_t Taggroup_Find (const taggroup_t *group, const size_t id)
 {
-	taggroup_t* tagelems;
+	size_t i;
 
-	if (tag == MTAG_GLOBAL)
-		return;
+	if (!group)
+		return -1;
 
-	if (!tags_sectors[(UINT16)tag])
-		tags_sectors[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL);
+	for (i = 0; i < group->count; i++)
+		if (group->elements[i] == id)
+			return i;
 
-	tagelems = tags_sectors[(UINT16)tag];
-	tagelems->count++;
-	tagelems->elements = Z_Realloc(tagelems->elements, tagelems->count * sizeof(size_t), PU_LEVEL, NULL);
-	tagelems->elements[tagelems->count - 1] = itemid;
+	return -1;
 }
 
-static void Taglist_AddToLines (const mtag_t tag, const size_t itemid)
+void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id)
 {
-	taggroup_t* tagelems;
+	taggroup_t *group;
 
 	if (tag == MTAG_GLOBAL)
 		return;
 
-	if (!tags_lines[(UINT16)tag])
-		tags_lines[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL);
+	group = garray[(UINT16)tag];
+
+	// Don't add duplicate entries.
+	if (Taggroup_Find(group, id) != (size_t)-1)
+		return;
+
+	// Create group if empty.
+	if (!group)
+		group = garray[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL);
 
-	tagelems = tags_lines[(UINT16)tag];
-	tagelems->count++;
-	tagelems->elements = Z_Realloc(tagelems->elements, tagelems->count * sizeof(size_t), PU_LEVEL, NULL);
-	tagelems->elements[tagelems->count - 1] = itemid;
+	group->count++;
+	group->elements = Z_Realloc(group->elements, group->count * sizeof(size_t), PU_LEVEL, NULL);
+	group->elements[group->count - 1] = id;
 }
 
-static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid)
+void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id)
 {
-	taggroup_t* tagelems;
+	taggroup_t *group;
+	size_t rempos;
+	size_t newcount;
 
 	if (tag == MTAG_GLOBAL)
 		return;
 
-	if (!tags_mapthings[(UINT16)tag])
-		tags_mapthings[(UINT16)tag] = Z_Calloc(sizeof(taggroup_t), PU_LEVEL, NULL);
+	group = garray[(UINT16)tag];
+
+	if ((rempos = Taggroup_Find(group, id)) == (size_t)-1)
+		return;
 
-	tagelems = tags_mapthings[(UINT16)tag];
-	tagelems->count++;
-	tagelems->elements = Z_Realloc(tagelems->elements, tagelems->count * sizeof(size_t), PU_LEVEL, NULL);
-	tagelems->elements[tagelems->count - 1] = itemid;
+	// Strip away taggroup if no elements left.
+	if (!(newcount = --group->count))
+	{
+		Z_Free(group->elements);
+		Z_Free(group);
+		garray[(UINT16)tag] = NULL;
+	}
+	else
+	{
+		size_t *newelements = Z_Malloc(newcount * sizeof(size_t), PU_LEVEL, NULL);
+		size_t i;
+
+		// Copy the previous entries save for the one to remove.
+		for (i = 0; i < rempos; i++)
+			newelements[i] = group->elements[i];
+
+		for (i = rempos + 1; i < group->count; i++)
+			newelements[i - 1] = group->elements[i];
+
+		Z_Free(group->elements);
+		group->elements = newelements;
+		group->count = newcount;
+	}
 }
 
-void Tag_SectorFSet (const size_t id, const mtag_t tag)
+// Initialization.
+
+static void Taglist_AddToSectors (const mtag_t tag, const size_t itemid)
 {
-	sector_t* sec = &sectors[id];
-	Tag_FSet(&sec->tags, tag);
+	Taggroup_Add(tags_sectors, tag, itemid);
+}
+
+static void Taglist_AddToLines (const mtag_t tag, const size_t itemid)
+{
+	Taggroup_Add(tags_lines, tag, itemid);
+}
+
+static void Taglist_AddToMapthings (const mtag_t tag, const size_t itemid)
+{
+	Taggroup_Add(tags_mapthings, tag, itemid);
 }
 
 void Taglist_InitGlobalTables(void)
@@ -144,6 +183,8 @@ void Taglist_InitGlobalTables(void)
 	}
 }
 
+// Iteration, inagme search.
+
 INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p)
 {
 	if (tag == MTAG_GLOBAL)
@@ -217,3 +258,17 @@ INT32 Tag_FindLineSpecial(const INT16 special, const mtag_t tag)
 	}
 	return -1;
 }
+
+// Ingame list manipulation.
+
+void Tag_SectorFSet (const size_t id, const mtag_t tag)
+{
+	sector_t* sec = &sectors[id];
+	mtag_t curtag = Tag_FGet(&sec->tags);
+	if (curtag == tag)
+		return;
+
+	Taggroup_Remove(tags_sectors, curtag, id);
+	Taggroup_Add(tags_sectors, tag, id);
+	Tag_FSet(&sec->tags, tag);
+}
diff --git a/src/taglist.h b/src/taglist.h
index 050bebed7e..d1acff6cbb 100644
--- a/src/taglist.h
+++ b/src/taglist.h
@@ -35,6 +35,9 @@ taggroup_t* tags_sectors[MAXTAGS + 1];
 taggroup_t* tags_lines[MAXTAGS + 1];
 taggroup_t* tags_mapthings[MAXTAGS + 1];
 
+void Taggroup_Add (taggroup_t *garray[], const mtag_t tag, size_t id);
+void Taggroup_Remove (taggroup_t *garray[], const mtag_t tag, size_t id);
+
 void Taglist_InitGlobalTables(void);
 
 INT32 Tag_Iterate_Sectors (const mtag_t tag, const size_t p);
-- 
GitLab