aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-05-29 00:04:19 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-05-29 00:14:32 -0300
commite5b60ae075e571a29868993a5f0d191d91f8d266 (patch)
tree066282b89375e893de810032f5781bccecfbe9d5
parent565d28e480a5a320682f87cb598404f1a34bbc5d (diff)
downloadgame-e5b60ae075e571a29868993a5f0d191d91f8d266.tar.gz
game-e5b60ae075e571a29868993a5f0d191d91f8d266.zip
impl `strings.cc`
-rw-r--r--reference/game.c355
-rw-r--r--reference/types.hh14
-rw-r--r--src/common.hh5
-rw-r--r--src/strings.cc207
-rw-r--r--src/stubs.hh5
5 files changed, 212 insertions, 374 deletions
diff --git a/reference/game.c b/reference/game.c
index dff762d..e8bb7cd 100644
--- a/reference/game.c
+++ b/reference/game.c
@@ -2667,339 +2667,6 @@ void __static_initialization_and_destruction_0(int __initialize_p,int __priority
return;
}
-
-
-// WARNING: Variable defined which should be unmapped: p
-
-char * AddStaticString(char *String)
-
-{
- size_t sVar1;
- char *__dest;
- listnode<> *plVar2;
- TStaticStringTableBlock *pTVar3;
- listIterator<> iter;
- TStaticStringTableBlock *local_18;
- char *p;
-
- sVar1 = strlen(String);
- if ((int)sVar1 < 0x10000) {
- __dest = "";
- if (sVar1 != 0) {
- for (plVar2 = StaticStringTable.firstNode; plVar2 != (listnode<> *)0x0;
- plVar2 = plVar2->next) {
- if ((int)(sVar1 + 1) < 0x10000 - (plVar2->data).TotalTextLength) {
- if (plVar2 != (listnode<> *)0x0) goto LAB_0805197a;
- break;
- }
- }
- plVar2 = list<>::append(&StaticStringTable);
- if (plVar2 == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- pTVar3 = (TStaticStringTableBlock *)0x0;
- }
- else {
- pTVar3 = &plVar2->data;
- }
- pTVar3->TotalTextLength = 0;
- if (plVar2 == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- local_18 = (TStaticStringTableBlock *)0x0;
- }
- else {
-LAB_0805197a:
- local_18 = &plVar2->data;
- }
- if (plVar2 == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- pTVar3 = (TStaticStringTableBlock *)0x0;
- }
- else {
- pTVar3 = &plVar2->data;
- }
- __dest = local_18->Text + pTVar3->TotalTextLength;
- memcpy(__dest,String,sVar1 + 1);
- if (plVar2 == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- pTVar3 = (TStaticStringTableBlock *)0x0;
- }
- else {
- pTVar3 = &plVar2->data;
- }
- pTVar3->TotalTextLength = sVar1 + pTVar3->TotalTextLength + 1;
- }
- }
- else {
- error("AddStaticString: String zu lang (%d).\n",sVar1);
- __dest = (char *)0x0;
- }
- return __dest;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: iter
-
-ulong AddDynamicString(char *String)
-
-{
- int iVar1;
- int i_1;
- size_t sVar2;
- int i;
- int iVar3;
- TDynamicStringTableBlock *pTVar4;
- int pos;
- int iVar5;
- int local_18;
- int count;
- listIterator<> iter;
-
- sVar2 = strlen(String);
- if ((int)sVar2 < 0x8000) {
- if (sVar2 == 0) {
- return 0;
- }
- local_18 = 0;
- count = (int)DynamicStringTable.firstNode;
- while ((listnode<> *)count != (listnode<> *)0x0) {
- if (0 < (((listnode<> *)count)->data).FreeEntries) {
- if ((listnode<> *)count == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- pTVar4 = (TDynamicStringTableBlock *)0x0;
- }
- else {
- pTVar4 = &((listnode<> *)count)->data;
- }
- if ((int)(sVar2 + 1) < 0x8000 - pTVar4->TotalTextLength) {
- if ((listnode<> *)count != (listnode<> *)0x0) goto LAB_08051ae9;
- break;
- }
- }
- if ((listnode<> *)count == (listnode<> *)0x0) {
- error("listIterator::operator++: Iterator ist NULL.\n");
- }
- else {
- count = (int)((listnode<> *)count)->next;
- }
- local_18 = local_18 + 1;
- }
- count = (int)list<>::append(&DynamicStringTable);
- if ((listnode<> *)count == (listnode<> *)0x0) {
- error("listIterator::operator*: Iterator ist NULL.\n");
- pTVar4 = (TDynamicStringTableBlock *)0x0;
- }
- else {
- pTVar4 = &((listnode<> *)count)->data;
- }
- pTVar4->FreeEntries = 0x100;
- iVar3 = 0;
- pTVar4->TotalTextLength = 0;
- pTVar4->Dirty = false;
- do {
- pTVar4->EntryType[iVar3] = '\0';
- iVar3 = iVar3 + 1;
- } while (iVar3 < 0x100);
- if ((listnode<> *)count == (listnode<> *)0x0) {
- pTVar4 = (TDynamicStringTableBlock *)0x0;
- error("listIterator::operator*: Iterator ist NULL.\n");
- }
- else {
-LAB_08051ae9:
- pTVar4 = &((listnode<> *)count)->data;
- }
- iVar3 = 0;
- do {
- iVar5 = iVar3;
- if (pTVar4->EntryType[iVar3] == '\0') break;
- iVar3 = iVar3 + 1;
- iVar5 = -1;
- } while (iVar3 < 0x100);
- if (iVar5 != -1) {
- iVar1 = pTVar4->TotalTextLength;
- pTVar4->EntryType[iVar5] = '\x01';
- iVar3 = pTVar4->TotalTextLength;
- pTVar4->FreeEntries = pTVar4->FreeEntries + -1;
- pTVar4->StringOffset[iVar5] = (ushort)iVar1;
- memcpy(pTVar4->Text + iVar3,String,sVar2 + 1);
- pTVar4->TotalTextLength = sVar2 + pTVar4->TotalTextLength + 1;
- return iVar5 + 1 + local_18 * 0x100;
- }
- error("AddDynamicString: Keinen freien Platz gefunden.\n");
- }
- else {
- error("AddDynamicString: String zu lang (%d)\n",sVar2);
- }
- return 0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: iter
-
-char * GetDynamicString(ulong Number)
-
-{
- int count;
- int iVar1;
- int Block;
- uint uVar2;
- uint uVar3;
- char *Text;
- listnode<> *local_10;
- listIterator<> iter;
-
- if (Number == 0) {
- return (char *)0x0;
- }
- uVar2 = Number - 1 >> 8;
- iVar1 = 0;
- uVar3 = Number - 1 & 0xff;
- local_10 = DynamicStringTable.firstNode;
- if (uVar2 == 0) {
-LAB_08051c50:
- if (local_10 != (listnode<> *)0x0) {
- if ((local_10->data).EntryType[uVar3] == '\x01') {
- return (local_10->data).Text + (local_10->data).StringOffset[uVar3];
- }
- Text = &DAT_080f0540;
- goto LAB_08051c3a;
- }
- }
- else if (DynamicStringTable.firstNode != (listnode<> *)0x0) {
- do {
- local_10 = local_10->next;
- iVar1 = iVar1 + 1;
- if ((int)uVar2 <= iVar1) goto LAB_08051c50;
- } while (local_10 != (listnode<> *)0x0);
- }
- Text = &DAT_080f0500;
-LAB_08051c3a:
- error(Text,Number);
- return (char *)0x0;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: iter
-
-void DeleteDynamicString(ulong Number)
-
-{
- int count;
- int iVar1;
- int Block;
- uint uVar2;
- uint uVar3;
- char *Text;
- listnode<> *local_10;
- listIterator<> iter;
-
- if (Number == 0) {
- return;
- }
- uVar2 = Number - 1 >> 8;
- iVar1 = 0;
- uVar3 = Number - 1 & 0xff;
- local_10 = DynamicStringTable.firstNode;
- if (uVar2 == 0) {
-LAB_08051ce0:
- if (local_10 != (listnode<> *)0x0) {
- if ((local_10->data).EntryType[uVar3] == '\x01') {
- (local_10->data).EntryType[uVar3] = '\x02';
- (local_10->data).Dirty = true;
- return;
- }
- Text = &DAT_080f05c0;
- goto LAB_08051cca;
- }
- }
- else if (DynamicStringTable.firstNode != (listnode<> *)0x0) {
- do {
- local_10 = local_10->next;
- iVar1 = iVar1 + 1;
- if ((int)uVar2 <= iVar1) goto LAB_08051ce0;
- } while (local_10 != (listnode<> *)0x0);
- }
- Text = &DAT_080f0580;
-LAB_08051cca:
- error(Text,Number);
- return;
-}
-
-
-
-// WARNING: Variable defined which should be unmapped: iter
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void CleanupDynamicStrings(void)
-
-{
- int *piVar1;
- int iVar2;
- char *__s;
- ushort uVar3;
- int Help;
- size_t sVar4;
- int j;
- int iVar5;
- int Offset;
- uint uVar6;
- int Length;
- int local_18;
- int i;
- listIterator<> iter;
-
- i = (int)DynamicStringTable.firstNode;
- if (DynamicStringTable.firstNode != (listnode<> *)0x0) {
- do {
- piVar1 = (int *)(i + 8);
- if (*(char *)(i + 0x10) != '\0') {
- local_18 = 0;
- do {
- if (*(char *)(local_18 + 9 + (int)piVar1) == '\x02') {
- uVar6 = (uint)*(ushort *)(i + 0x112 + local_18 * 2);
- __s = (char *)(uVar6 + 0x30a + (int)piVar1);
- sVar4 = strlen(__s);
- iVar2 = sVar4 + 1;
- *(int *)(i + 0xc) = *(int *)(i + 0xc) - iVar2;
- *(undefined1 *)(local_18 + 9 + (int)piVar1) = 0;
- if ((int)(iVar2 + uVar6) < 0x8001) {
- sVar4 = (-iVar2 - uVar6) + 0x8000;
- if (0 < (int)sVar4) {
- memmove(__s,(void *)(iVar2 + uVar6 + 0x30a + (int)piVar1),sVar4);
- }
- *piVar1 = *piVar1 + 1;
- iVar5 = 0;
- do {
- if ((*(char *)(iVar5 + 9 + (int)piVar1) != '\0') &&
- (uVar3 = *(ushort *)(i + 0x112 + iVar5 * 2), uVar6 < uVar3)) {
- *(ushort *)(i + 0x112 + iVar5 * 2) = uVar3 - (short)iVar2;
- }
- iVar5 = iVar5 + 1;
- } while (iVar5 < 0x100);
- }
- else {
- error("CleanupDynamicStrings: Stringende fehlt\n");
- }
- }
- local_18 = local_18 + 1;
- } while (local_18 < 0x100);
- *(undefined1 *)(i + 0x10) = 0;
- }
- if (i == 0) {
- error("listIterator::operator++: Iterator ist NULL.\n");
- }
- else {
- i = *(int *)i;
- }
- } while (i != 0);
- }
- return;
-}
-
-
-
bool IsCountable(char *s)
{
@@ -3809,28 +3476,6 @@ char * Capitals(char *Text)
return Text;
}
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void InitStrings(void)
-
-{
- return;
-}
-
-
-
-// WARNING: Unknown calling convention -- yet parameter storage is locked
-
-void ExitStrings(void)
-
-{
- return;
-}
-
-
-
void __tcf_0(void *param_1)
{
diff --git a/reference/types.hh b/reference/types.hh
index 2fc67a0..b87faf2 100644
--- a/reference/types.hh
+++ b/reference/types.hh
@@ -197,15 +197,6 @@ struct TAttackWave {
struct vector<TItemData> ExtraItem;
};
-struct TDynamicStringTableBlock {
- int FreeEntries;
- int TotalTextLength;
- bool Dirty;
- uchar EntryType[256];
- ushort StringOffset[256];
- char Text[32768];
-};
-
struct TNonplayer {
struct TCreature super_TCreature; // INHERITANCE?
enum STATE State;
@@ -254,11 +245,6 @@ struct TMonsterhome {
int Timer;
};
-struct TStaticStringTableBlock {
- int TotalTextLength;
- char Text[65536];
-};
-
struct TCondition {
int Type;
ulong Text;
diff --git a/src/common.hh b/src/common.hh
index b981b2b..33fd694 100644
--- a/src/common.hh
+++ b/src/common.hh
@@ -117,6 +117,11 @@ void ExitSHMExtern(void);
// strings.cc
// =============================================================================
+const char *AddStaticString(const char *String);
+uint32 AddDynamicString(const char *String);
+const char *GetDynamicString(uint32 Number);
+void DeleteDynamicString(uint32 Number);
+void CleanupDynamicStrings(void);
void InitStrings(void);
void ExitStrings(void);
diff --git a/src/strings.cc b/src/strings.cc
index 478ad69..41fdc44 100644
--- a/src/strings.cc
+++ b/src/strings.cc
@@ -1,4 +1,211 @@
#include "common.hh"
+#include "containers.hh"
+
+struct TStaticStringTableBlock {
+ int TotalTextLength;
+ char Text[65536];
+};
+
+struct TDynamicStringTableBlock {
+ int FreeEntries;
+ int TotalTextLength;
+ bool Dirty;
+ uint8 EntryType[256];
+ uint16 StringOffset[256];
+ char Text[32768];
+};
+
+constexpr int StaticBlockSize = NARRAY(TStaticStringTableBlock::Text);
+constexpr int DynamicBlockSize = NARRAY(TDynamicStringTableBlock::Text);
+constexpr int DynamicBlockEntries = NARRAY(TDynamicStringTableBlock::EntryType);
+
+enum : uint8 {
+ DYNAMIC_STRING_FREE = 0,
+ DYNAMIC_STRING_ALLOCATED = 1,
+ DYNAMIC_STRING_DELETED = 2,
+};
+
+static list<TStaticStringTableBlock> StaticStringTable;
+static list<TDynamicStringTableBlock> DynamicStringTable;
+
+const char *AddStaticString(const char *String){
+ int StringLen = (int)strlen(String);
+ if((StringLen + 1) > StaticBlockSize){
+ error("AddStaticString: String zu lang (%d).\n", StringLen);
+ return NULL;
+ }
+
+ if(StringLen == 0){
+ return "";
+ }
+
+ listnode<TStaticStringTableBlock> *Node = StaticStringTable.firstNode;
+ while(Node != NULL){
+ if((Node->data.TotalTextLength + StringLen + 1) <= StaticBlockSize){
+ break;
+ }
+ Node = Node->next;
+ }
+
+ if(Node == NULL){
+ Node = StaticStringTable.append();
+ memset(&Node->data, 0, sizeof(TStaticStringTableBlock));
+ }
+
+ TStaticStringTableBlock *Block = &Node->data;
+ char *Result = &Block->Text[Block->TotalTextLength];
+ memcpy(Result, String, StringLen + 1);
+ Block->TotalTextLength += StringLen + 1;
+ return Result;
+}
+
+uint32 AddDynamicString(const char *String){
+ int StringLen = (int)strlen(String);
+ if((StringLen + 1) > DynamicBlockSize){
+ error("AddDynamicString: String zu lang (%d)\n", StringLen);
+ return 0;
+ }
+
+ if(StringLen == 0){
+ return 0;
+ }
+
+ int BlockIndex = 0;
+ listnode<TDynamicStringTableBlock> *Node = DynamicStringTable.firstNode;
+ while(Node != NULL){
+ if(Node->data.FreeEntries > 0){
+ if((Node->data.TotalTextLength + StringLen + 1) <= DynamicBlockSize){
+ break;
+ }
+ }
+ Node = Node->next;
+ BlockIndex += 1;
+ }
+
+ if(Node == NULL){
+ Node = DynamicStringTable.append();
+ memset(&Node->data, 0, sizeof(TDynamicStringTableBlock));
+ Node->data.FreeEntries = DynamicBlockEntries;
+ }
+
+ TDynamicStringTableBlock *Block = &Node->data;
+ int EntryIndex = -1;
+ for(int i = 0; i < DynamicBlockEntries; i += 1){
+ if(Block->EntryType[i] == DYNAMIC_STRING_FREE){
+ EntryIndex = i;
+ break;
+ }
+ }
+
+ if(EntryIndex == -1){
+ error("AddDynamicString: Keinen freien Platz gefunden.\n");
+ return 0;
+ }
+
+ int StringOffset = Block->TotalTextLength;
+ Block->FreeEntries -= 1;
+ Block->TotalTextLength += StringLen + 1;
+ Block->EntryType[EntryIndex] = DYNAMIC_STRING_ALLOCATED;
+ Block->StringOffset[EntryIndex] = (uint16)StringOffset;
+ memcpy(&Block->Text[StringOffset], String, StringLen + 1);
+
+ return (uint32)(1 + BlockIndex * DynamicBlockEntries + EntryIndex);
+}
+
+const char *GetDynamicString(uint32 Number){
+ if(Number == 0){
+ return NULL;
+ }
+
+ int BlockIndex = (int)(Number - 1) / DynamicBlockEntries;
+ int EntryIndex = (int)(Number - 1) % DynamicBlockEntries;
+ listnode<TDynamicStringTableBlock> *Node = DynamicStringTable.firstNode;
+ while(BlockIndex > 0 && Node != NULL){
+ Node = Node->next;
+ BlockIndex -= 1;
+ }
+
+ if(Node == NULL){
+ error("GetDynamicString: Block für String %u existiert nicht\n", Number);
+ return NULL;
+ }
+
+ TDynamicStringTableBlock *Block = &Node->data;
+ if(Block->EntryType[EntryIndex] != DYNAMIC_STRING_ALLOCATED){
+ error("GetDynamicString: Eintrag für String %u existiert nicht\n", Number);
+ return NULL;
+ }
+
+ int StringOffset = (int)Block->StringOffset[EntryIndex];
+ return &Block->Text[StringOffset];
+}
+
+void DeleteDynamicString(uint32 Number){
+ if(Number == 0){
+ return;
+ }
+
+ int BlockIndex = (int)(Number - 1) / DynamicBlockEntries;
+ int EntryIndex = (int)(Number - 1) % DynamicBlockEntries;
+ listnode<TDynamicStringTableBlock> *Node = DynamicStringTable.firstNode;
+ while(BlockIndex > 0 && Node != NULL){
+ Node = Node->next;
+ BlockIndex -= 1;
+ }
+
+ if(Node == NULL){
+ error("DeleteDynamicString: Block für String %u existiert nicht\n", Number);
+ return;
+ }
+
+ TDynamicStringTableBlock *Block = &Node->data;
+ if(Block->EntryType[EntryIndex] != DYNAMIC_STRING_ALLOCATED){
+ error("DeleteDynamicString: Eintrag für String %u existiert nicht\n", Number);
+ return;
+ }
+
+ Block->EntryType[EntryIndex] = DYNAMIC_STRING_DELETED;
+ Block->Dirty = true;
+}
+
+void CleanupDynamicStrings(void){
+ // IMPORTANT(fusion): The way we manage dynamic strings also mean pointers
+ // returned from `GetDynamicString` aren't stable.
+ for(listnode<TDynamicStringTableBlock> *Node = DynamicStringTable.firstNode;
+ Node != NULL;
+ Node = Node->next){
+ TDynamicStringTableBlock *Block = &Node->data;
+ if(!Block->Dirty){
+ continue;
+ }
+
+ for(int i = 0; i < DynamicBlockEntries; i += 1){
+ if(Block->EntryType[i] == DYNAMIC_STRING_DELETED){
+ int StringOffset = Block->StringOffset[i];
+ char *String = &Block->Text[StringOffset];
+ int StringLen = (int)strlen(String);
+ int StringEnd = StringOffset + StringLen + 1;
+ Block->EntryType[i] = DYNAMIC_STRING_FREE;
+
+ if(StringEnd > DynamicBlockSize){
+ error("CleanupDynamicStrings: Stringende fehlt\n");
+ continue;
+ }
+
+ if(StringEnd < DynamicBlockSize){
+ memmove(String, String + StringEnd, DynamicBlockSize - StringEnd);
+ }
+
+ for(int j = 0; j < DynamicBlockEntries; j += 1){
+ if(Block->EntryType[j] != DYNAMIC_STRING_FREE
+ && Block->StringOffset[j] > StringOffset){
+ Block->StringOffset[j] -= StringLen + 1;
+ }
+ }
+ }
+ }
+ }
+}
void InitStrings(void){
// no-op
diff --git a/src/stubs.hh b/src/stubs.hh
index 316a2fe..372ca92 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -15,18 +15,13 @@ typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ, const
typedef void TSendMailsFunction(TPlayerData *PlayerData);
extern void AbortWriter(void);
-extern uint32 AddDynamicString(const char *String);
-extern const char *AddStaticString(const char *String);
extern void AnnounceChangedCreature(uint32 CreatureID, int Type);
extern void BroadcastMessage(int Mode, const char *Text, ...) ATTR_PRINTF(2, 3);
extern void Change(Object Obj, ObjectType NewType, uint32 Value);
extern bool CheckRight(uint32 CreatureID, RIGHT Right);
extern void CleanHouseField(int x, int y, int z);
-extern void CleanupDynamicStrings(void);
extern void CreatePlayerList(bool Online);
-extern void DeleteDynamicString(uint32 Number);
extern TCreature *GetCreature(uint32 CreatureID);
-extern const char *GetDynamicString(uint32 Number);
extern TConnection *GetFirstConnection(void);
extern TConnection *GetNextConnection(void);
extern void Log(const char *ProtocolName, const char *Text, ...) ATTR_PRINTF(2, 3);