aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common.hh4
-rw-r--r--src/config.cc2
-rw-r--r--src/cract.cc2
-rw-r--r--src/crcombat.cc2
-rw-r--r--src/crskill.cc2
-rw-r--r--src/main.cc3
-rw-r--r--src/map.cc2
-rw-r--r--src/moveuse.cc3
-rw-r--r--src/objects.cc2
-rw-r--r--src/operate.cc5
-rw-r--r--src/reader.cc273
-rw-r--r--src/reader.hh47
-rw-r--r--src/stubs.hh7
-rw-r--r--src/utils.cc35
-rw-r--r--src/writer.cc23
15 files changed, 371 insertions, 41 deletions
diff --git a/src/common.hh b/src/common.hh
index 57c7745..b97de3c 100644
--- a/src/common.hh
+++ b/src/common.hh
@@ -153,6 +153,10 @@ typedef void TErrorFunction(const char *Text);
typedef void TPrintFunction(int Level, const char *Text);
void SetErrorFunction(TErrorFunction *Function);
void SetPrintFunction(TPrintFunction *Function);
+void SilentHandler(const char *Text);
+void SilentHandler(int Level, const char *Text);
+void LogFileHandler(const char *Text);
+void LogFileHandler(int Level, const char *Text);
void error(const char *Text, ...) ATTR_PRINTF(1, 2);
void print(int Level, const char *Text, ...) ATTR_PRINTF(2, 3);
int random(int Min, int Max);
diff --git a/src/config.cc b/src/config.cc
index d08b791..257985b 100644
--- a/src/config.cc
+++ b/src/config.cc
@@ -1,8 +1,6 @@
#include "config.hh"
#include "script.hh"
-#include "stubs.hh"
-
char BINPATH[4096];
char DATAPATH[4096];
char LOGPATH[4096];
diff --git a/src/cract.cc b/src/cract.cc
index a7bb2fe..8397d79 100644
--- a/src/cract.cc
+++ b/src/cract.cc
@@ -4,8 +4,6 @@
#include "info.hh"
#include "operate.hh"
-#include "stubs.hh"
-
// TShortway
// =============================================================================
struct TShortwayPoint {
diff --git a/src/crcombat.cc b/src/crcombat.cc
index 43c3f76..f942332 100644
--- a/src/crcombat.cc
+++ b/src/crcombat.cc
@@ -4,8 +4,6 @@
#include "magic.hh"
#include "operate.hh"
-#include "stubs.hh"
-
TCombat::TCombat(void){
this->Master = NULL;
this->EarliestAttackTime = 0;
diff --git a/src/crskill.cc b/src/crskill.cc
index 923c0ab..e12e9c6 100644
--- a/src/crskill.cc
+++ b/src/crskill.cc
@@ -1,8 +1,6 @@
#include "cr.hh"
#include "operate.hh"
-#include "stubs.hh"
-
#include <math.h>
// TSkill REGULAR FUNCTIONS
diff --git a/src/main.cc b/src/main.cc
index c64838a..2875e94 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -9,10 +9,9 @@
#include "objects.hh"
#include "operate.hh"
#include "query.hh"
+#include "reader.hh"
#include "writer.hh"
-#include "stubs.hh"
-
#include <signal.h>
#include <sys/stat.h>
#include <sys/time.h>
diff --git a/src/map.cc b/src/map.cc
index 90a2c1a..a4f3fac 100644
--- a/src/map.cc
+++ b/src/map.cc
@@ -5,8 +5,6 @@
#include "houses.hh"
#include "script.hh"
-#include "stubs.hh"
-
#include <dirent.h>
int SectorXMin;
diff --git a/src/moveuse.cc b/src/moveuse.cc
index 3db2016..6c83dcc 100644
--- a/src/moveuse.cc
+++ b/src/moveuse.cc
@@ -4,10 +4,9 @@
#include "info.hh"
#include "magic.hh"
#include "operate.hh"
+#include "reader.hh"
#include "writer.hh"
-#include "stubs.hh"
-
static vector<TMoveUseCondition> MoveUseConditions(1, 1000, 1000);
static int NumberOfMoveUseConditions;
diff --git a/src/objects.cc b/src/objects.cc
index 5231fc8..94edca4 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -3,8 +3,6 @@
#include "containers.hh"
#include "script.hh"
-#include "stubs.hh"
-
#include <fstream>
static vector<TObjectType> ObjectTypes(0, 5000, 1000);
diff --git a/src/operate.cc b/src/operate.cc
index 7099cc1..7827d0d 100644
--- a/src/operate.cc
+++ b/src/operate.cc
@@ -4,8 +4,7 @@
#include "info.hh"
#include "magic.hh"
#include "moveuse.hh"
-
-#include "stubs.hh"
+#include "reader.hh"
#include <dirent.h>
@@ -2876,7 +2875,7 @@ void RefreshMap(void){
}
char FileName[4096];
- snprintf(FileName, sizeof(FileName), "%s/%04u-%04u-%02u.sec",
+ snprintf(FileName, sizeof(FileName), "%s/%04d-%04d-%02d.sec",
ORIGMAPPATH, SectorX, SectorY, SectorZ);
if(!FileExists(FileName)){
continue;
diff --git a/src/reader.cc b/src/reader.cc
index f2da968..09d739b 100644
--- a/src/reader.cc
+++ b/src/reader.cc
@@ -1,6 +1,277 @@
#include "reader.hh"
+#include "config.hh"
+#include "cr.hh"
+#include "map.hh"
#include "threads.hh"
-static Semaphore OrderBufferEmpty(200);
+static ThreadHandle ReaderThread;
+
+static TReaderThreadOrder OrderBuffer[200];
+static int OrderPointerWrite;
+static int OrderPointerRead;
+static Semaphore OrderBufferEmpty(NARRAY(OrderBuffer));
static Semaphore OrderBufferFull(0);
+
+static TReaderThreadReply ReplyBuffer[200];
+static int ReplyPointerWrite;
+static int ReplyPointerRead;
+
static TDynamicWriteBuffer HelpBuffer(KB(64));
+
+// Reader Orders
+// =============================================================================
+void InitReaderBuffers(void){
+ OrderPointerWrite = 0;
+ OrderPointerRead = 0;
+ ReplyPointerWrite = 0;
+ ReplyPointerRead = 0;
+}
+
+void InsertOrder(TReaderThreadOrderType OrderType,
+ int SectorX, int SectorY, int SectorZ, uint32 CharacterID){
+ int Orders = (OrderPointerWrite - OrderPointerRead);
+ if(Orders >= NARRAY(OrderBuffer)){
+ error("InsertOrder (Reader): Order-Puffer ist voll => Vergrößern.\n");
+ }
+
+ OrderBufferEmpty.down();
+ int WritePos = OrderPointerWrite % NARRAY(OrderBuffer);
+ OrderBuffer[WritePos].OrderType = OrderType;
+ OrderBuffer[WritePos].SectorX = SectorX;
+ OrderBuffer[WritePos].SectorY = SectorY;
+ OrderBuffer[WritePos].SectorZ = SectorZ;
+ OrderBuffer[WritePos].CharacterID = CharacterID;
+ OrderPointerWrite += 1;
+ OrderBufferFull.up();
+}
+
+void GetOrder(TReaderThreadOrder *Order){
+ OrderBufferFull.down();
+ *Order = OrderBuffer[OrderPointerRead % NARRAY(OrderBuffer)];
+ OrderPointerRead += 1;
+ OrderBufferEmpty.up();
+}
+
+void TerminateReaderOrder(void){
+ InsertOrder(READER_ORDER_TERMINATE, 0, 0, 0, 0);
+}
+
+void LoadSectorOrder(int SectorX, int SectorY, int SectorZ){
+ InsertOrder(READER_ORDER_LOADSECTOR, SectorX, SectorY, SectorZ, 0);
+}
+
+void LoadCharacterOrder(uint32 CharacterID){
+ InsertOrder(READER_ORDER_LOADCHARACTER, 0, 0, 0, CharacterID);
+}
+
+void ProcessLoadSectorOrder(int SectorX, int SectorY, int SectorZ){
+ // TODO(fusion): We parsed sector files way too many times now. And there
+ // is also a drop in loader quality.
+ char FileName[4096];
+ snprintf(FileName, sizeof(FileName), "%s/%04d-%04d-%02d.sec",
+ ORIGMAPPATH, SectorX, SectorY, SectorZ);
+ if(!FileExists(FileName)){
+ return;
+ }
+
+ int OffsetX = -1;
+ int OffsetY = -1;
+ bool Refreshable = false;
+ HelpBuffer.Position = 0;
+
+ TReadScriptFile Script;
+ Script.open(FileName);
+ while(true){
+ Script.nextToken();
+ if(Script.Token == ENDOFFILE){
+ Script.close();
+ break;
+ }
+
+ if(Script.Token == SPECIAL && Script.getSpecial() == ','){
+ continue;
+ }
+
+ if(Script.Token == BYTES){
+ uint8 *Offset = Script.getBytesequence();
+ OffsetX = (int)Offset[0];
+ OffsetY = (int)Offset[1];
+ Refreshable = false;
+ Script.readSymbol(':');
+ }else if(Script.Token == IDENTIFIER){
+ if(OffsetX == -1 || OffsetY == -1){
+ Script.error("coordinate expected");
+ }
+
+ const char *Identifier = Script.getIdentifier();
+ if(strcmp(Identifier, "refresh") == 0){
+ Refreshable = true;
+ }else if(strcmp(Identifier, "content") == 0){
+ Script.readSymbol('=');
+
+ if(Refreshable){
+ HelpBuffer.writeByte((uint8)OffsetX);
+ HelpBuffer.writeByte((uint8)OffsetY);
+ }
+
+ LoadObjects(&Script, &HelpBuffer, !Refreshable);
+ }
+ }
+ }
+
+ int Size = HelpBuffer.Position;
+ if(Size > 0){
+ uint8 *Data = new uint8[Size];
+ memcpy(Data, HelpBuffer.Data, Size);
+ SectorReply(SectorX, SectorY, SectorZ, Data, Size);
+ }
+}
+
+void ProcessLoadCharacterOrder(uint32 CharacterID){
+ while(true){
+ TPlayerData *Slot = AssignPlayerPoolSlot(CharacterID, true);
+ if(Slot == NULL){
+ error("ProcessLoadCharacterOrder: Kann keinen Slot für Spielerdaten zuweisen.\n");
+ break;
+ }
+
+ if(Slot->Locked == GetGameThreadPID()){
+ break;
+ }
+
+ if(Slot->Locked == getpid()){
+ IncreasePlayerPoolSlotSticky(Slot);
+ ReleasePlayerPoolSlot(Slot);
+ CharacterReply(CharacterID);
+ break;
+ }
+
+ DelayThread(1, 0);
+ }
+}
+
+int ReaderThreadLoop(void *Unused){
+ TReaderThreadOrder Order = {};
+ while(true){
+ GetOrder(&Order);
+ if(Order.OrderType == READER_ORDER_TERMINATE){
+ break;
+ }
+
+ switch(Order.OrderType){
+ case READER_ORDER_LOADSECTOR:{
+ ProcessLoadSectorOrder(Order.SectorX, Order.SectorY, Order.SectorZ);
+ break;
+ }
+
+ case READER_ORDER_LOADCHARACTER:{
+ ProcessLoadCharacterOrder(Order.CharacterID);
+ break;
+ }
+
+ default:{
+ error("ReaderThreadLoop: Unbekanntes Kommando %d.\n", Order.OrderType);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+// Reader Replies
+// =============================================================================
+void InsertReply(TReaderThreadReplyType ReplyType,
+ int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size){
+ int Replies = (ReplyPointerWrite - ReplyPointerRead);
+ while(Replies > NARRAY(ReplyBuffer)){
+ error("InsertReply (Reader): Puffer ist voll; warte...\n");
+ DelayThread(5, 0);
+ }
+
+ int WritePos = ReplyPointerWrite % NARRAY(ReplyBuffer);
+ ReplyBuffer[WritePos].ReplyType = ReplyType;
+ ReplyBuffer[WritePos].SectorX = SectorX;
+ ReplyBuffer[WritePos].SectorY = SectorY;
+ ReplyBuffer[WritePos].SectorZ = SectorZ;
+ ReplyBuffer[WritePos].Data = Data;
+ ReplyBuffer[WritePos].Size = Size;
+ ReplyPointerWrite += 1;
+}
+
+bool GetReply(TReaderThreadReply *Reply){
+ bool Result = (ReplyPointerRead < ReplyPointerWrite);
+ if(Result){
+ *Reply = ReplyBuffer[ReplyPointerRead % NARRAY(ReplyBuffer)];
+ ReplyPointerRead += 1;
+ }
+ return Result;
+}
+
+void SectorReply(int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size){
+ InsertReply(READER_REPLY_SECTORDATA, SectorX, SectorY, SectorZ, Data, Size);
+}
+
+void CharacterReply(uint32 CharacterID){
+ InsertReply(READER_REPLY_CHARACTERDATA, 0, 0, 0, NULL, (int)CharacterID);
+}
+
+void ProcessSectorReply(TRefreshSectorFunction *RefreshSector,
+ int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size){
+ RefreshSector(SectorX, SectorY, SectorZ, Data, Size);
+ delete[] Data;
+}
+
+void ProcessCharacterReply(TSendMailsFunction *SendMails, uint32 CharacterID){
+ TPlayerData *Slot = AttachPlayerPoolSlot(CharacterID, true);
+ if(Slot == NULL){
+ DecreasePlayerPoolSlotSticky(Slot);
+ return;
+ }
+
+ SendMails(Slot);
+ DecreasePlayerPoolSlotSticky(Slot);
+ ReleasePlayerPoolSlot(Slot);
+}
+
+void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails){
+ TReaderThreadReply Reply = {};
+ while(GetReply(&Reply)){
+ switch(Reply.ReplyType){
+ case READER_REPLY_SECTORDATA:{
+ ProcessSectorReply(RefreshSector,
+ Reply.SectorX, Reply.SectorY, Reply.SectorZ,
+ Reply.Data, Reply.Size);
+ break;
+ }
+
+ case READER_REPLY_CHARACTERDATA:{
+ ProcessCharacterReply(SendMails, (uint32)Reply.Size);
+ break;
+ }
+
+ default:{
+ error("ProcessReaderThreadReplies: Unbekannte Rückmeldung %d.\n", Reply.ReplyType);
+ break;
+ }
+ }
+ }
+}
+
+// Initialization
+// =============================================================================
+void InitReader(void){
+ InitReaderBuffers();
+ ReaderThread = StartThread(ReaderThreadLoop, NULL, false);
+ if(ReaderThread == INVALID_THREAD_HANDLE){
+ throw "cannot start reader thread";
+ }
+}
+
+void ExitReader(void){
+ if(ReaderThread != INVALID_THREAD_HANDLE){
+ TerminateReaderOrder();
+ JoinThread(ReaderThread);
+ ReaderThread = INVALID_THREAD_HANDLE;
+ }
+}
diff --git a/src/reader.hh b/src/reader.hh
index 2dbf02f..7db1ca7 100644
--- a/src/reader.hh
+++ b/src/reader.hh
@@ -3,6 +3,12 @@
#include "common.hh"
+struct TPlayerData;
+
+typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ,
+ const uint8 *Data, int Size);
+typedef void TSendMailsFunction(TPlayerData *PlayerData);
+
enum TReaderThreadOrderType: int {
READER_ORDER_TERMINATE = 0,
READER_ORDER_LOADSECTOR = 1,
@@ -14,4 +20,45 @@ enum TReaderThreadReplyType: int {
READER_REPLY_CHARACTERDATA = 1,
};
+struct TReaderThreadOrder {
+ TReaderThreadOrderType OrderType;
+ int SectorX;
+ int SectorY;
+ int SectorZ;
+ uint32 CharacterID;
+};
+
+struct TReaderThreadReply {
+ TReaderThreadReplyType ReplyType;
+ int SectorX;
+ int SectorY;
+ int SectorZ;
+ uint8 *Data;
+ int Size;
+};
+
+void InitReaderBuffers(void);
+void InsertOrder(TReaderThreadOrderType OrderType,
+ int SectorX, int SectorY, int SectorZ, uint32 CharacterID);
+void GetOrder(TReaderThreadOrder *Order);
+void TerminateReaderOrder(void);
+void LoadSectorOrder(int SectorX, int SectorY, int SectorZ);
+void LoadCharacterOrder(uint32 CharacterID);
+void ProcessLoadSectorOrder(int SectorX, int SectorY, int SectorZ);
+void ProcessLoadCharacterOrder(uint32 CharacterID);
+int ReaderThreadLoop(void *Unused);
+
+void InsertReply(TReaderThreadReplyType ReplyType,
+ int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size);
+bool GetReply(TReaderThreadReply *Reply);
+void SectorReply(int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size);
+void CharacterReply(uint32 CharacterID);
+void ProcessSectorReply(TRefreshSectorFunction *RefreshSector,
+ int SectorX, int SectorY, int SectorZ, uint8 *Data, int Size);
+void ProcessCharacterReply(TSendMailsFunction *SendMails, uint32 CharacterID);
+void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails);
+
+void InitReader(void);
+void ExitReader(void);
+
#endif //TIBIA_READER_HH
diff --git a/src/stubs.hh b/src/stubs.hh
index 4e974d7..0be5c77 100644
--- a/src/stubs.hh
+++ b/src/stubs.hh
@@ -9,15 +9,8 @@
// IMPORTANT(fusion): These function definitions exist to test compilation. They're
// not yet implemented and will cause the linker to fail with unresolved symbols.
-typedef void TRefreshSectorFunction(int SectorX, int SectorY, int SectorZ, const uint8 *Data, int Size);
-typedef void TSendMailsFunction(TPlayerData *PlayerData);
-
-extern void LoadCharacterOrder(uint32 CharacterID);
-extern void LoadSectorOrder(int SectorX, int SectorY, int SectorZ);
-extern void ProcessReaderThreadReplies(TRefreshSectorFunction *RefreshSector, TSendMailsFunction *SendMails);
extern void SavePlayerData(TPlayerData *Slot);
extern bool LoadPlayerData(TPlayerData *Slot);
extern bool PlayerDataExists(uint32 CharacterID);
-extern void SavePlayerDataOrder(void);
#endif //TIBIA_STUBS_HH_
diff --git a/src/utils.cc b/src/utils.cc
index 4a3523b..11aa048 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -2,8 +2,9 @@
#include <sys/stat.h>
-static void (*ErrorFunction)(const char *Text) = NULL;
-static void (*PrintFunction)(int Level, const char *Text) = NULL;
+static TErrorFunction *ErrorFunction;
+static TPrintFunction *PrintFunction;
+static char StandardLogFile[4096];
void SetErrorFunction(TErrorFunction *Function){
ErrorFunction = Function;
@@ -13,6 +14,36 @@ void SetPrintFunction(TPrintFunction *Function){
PrintFunction = Function;
}
+void SetStandardLogFile(const char *FileName){
+ strcpy(StandardLogFile, FileName);
+}
+
+void SilentHandler(const char *Text){
+ // no-op
+}
+
+void SilentHandler(int Level, const char *Text){
+ // no-op
+}
+
+void LogFileHandler(const char *Text){
+ if(StandardLogFile[0] == 0){
+ return;
+ }
+
+ FILE *File = fopen(StandardLogFile, "at");
+ if(File != NULL){
+ fprintf(File, "%s", Text);
+ if(fclose(File) != 0){
+ error("LogfileHandler: Fehler %d beim Schließen der Datei.\n", errno);
+ }
+ }
+}
+
+void LogFileHandler(int Level, const char *Text){
+ LogFileHandler(Text);
+}
+
void error(const char *Text, ...){
char s[1024];
diff --git a/src/writer.cc b/src/writer.cc
index f4d5589..dbe0cb0 100644
--- a/src/writer.cc
+++ b/src/writer.cc
@@ -197,8 +197,7 @@ void InsertOrder(TWriterThreadOrderType OrderType, const void *Data){
void GetOrder(TWriterThreadOrder *Order){
OrderBufferFull.down();
- int ReadPos = OrderPointerRead % NARRAY(OrderBuffer);
- *Order = OrderBuffer[ReadPos];
+ *Order = OrderBuffer[OrderPointerRead % NARRAY(OrderBuffer)];
OrderPointerRead += 1;
OrderBufferEmpty.up();
}
@@ -857,6 +856,15 @@ void InsertReply(TWriterThreadReplyType ReplyType, const void *Data){
ReplyPointerWrite += 1;
}
+bool GetReply(TWriterThreadReply *Reply){
+ bool Result = (ReplyPointerRead < ReplyPointerWrite);
+ if(Result){
+ *Reply = ReplyBuffer[ReplyPointerRead % NARRAY(ReplyBuffer)];
+ ReplyPointerRead += 1;
+ }
+ return Result;
+}
+
void BroadcastReply(const char *Text, ...){
if(Text == NULL){
error("BroadcastReply: Kein Text angegeben.\n");
@@ -905,15 +913,6 @@ void LogoutReply(const char *PlayerName){
InsertReply(WRITER_REPLY_LOGOUT, Data);
}
-bool GetReply(TWriterThreadReply *Reply){
- bool Result = (ReplyPointerRead < ReplyPointerWrite);
- if(Result){
- *Reply = ReplyBuffer[ReplyPointerRead % NARRAY(ReplyBuffer)];
- ReplyPointerRead += 1;
- }
- return Result;
-}
-
void ProcessBroadcastReply(TBroadcastReplyData *Data){
if(Data == NULL){
error("ProcessBroadcastReply: Keine Daten übergeben.\n");
@@ -981,7 +980,7 @@ void ProcessWriterThreadReplies(void){
}
}
-// Writer Initialization
+// Initialization
// =============================================================================
void ClearPlayers(void){
int NumberOfAffectedPlayers;