reader.cc

This commit is contained in:
fusion32 2025-07-01 09:26:06 -03:00
parent 6243967f1f
commit 5cfe00df82
19 changed files with 383 additions and 5488 deletions

View File

@ -13,9 +13,9 @@ else
CFLAGS += -O2
endif
HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/communication.hh $(SRCDIR)/config.hh $(SRCDIR)/connections.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/crypto.hh $(SRCDIR)/enums.hh $(SRCDIR)/houses.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/threads.hh $(SRCDIR)/writer.hh
HEADERS = $(SRCDIR)/common.hh $(SRCDIR)/communication.hh $(SRCDIR)/config.hh $(SRCDIR)/connections.hh $(SRCDIR)/containers.hh $(SRCDIR)/cr.hh $(SRCDIR)/crypto.hh $(SRCDIR)/enums.hh $(SRCDIR)/houses.hh $(SRCDIR)/info.hh $(SRCDIR)/magic.hh $(SRCDIR)/map.hh $(SRCDIR)/moveuse.hh $(SRCDIR)/objects.hh $(SRCDIR)/operate.hh $(SRCDIR)/query.hh $(SRCDIR)/reader.hh $(SRCDIR)/script.hh $(SRCDIR)/stubs.hh $(SRCDIR)/threads.hh $(SRCDIR)/writer.hh
$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/connections.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crnonpl.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/houses.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/receiving.obj $(BUILDDIR)/script.obj $(BUILDDIR)/sending.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj $(BUILDDIR)/writer.obj
$(BUILDDIR)/$(OUTPUTEXE): $(BUILDDIR)/communication.obj $(BUILDDIR)/config.obj $(BUILDDIR)/connections.obj $(BUILDDIR)/cract.obj $(BUILDDIR)/crcombat.obj $(BUILDDIR)/crmain.obj $(BUILDDIR)/crnonpl.obj $(BUILDDIR)/crplayer.obj $(BUILDDIR)/crskill.obj $(BUILDDIR)/crypto.obj $(BUILDDIR)/houses.obj $(BUILDDIR)/info.obj $(BUILDDIR)/magic.obj $(BUILDDIR)/main.obj $(BUILDDIR)/map.obj $(BUILDDIR)/moveuse.obj $(BUILDDIR)/objects.obj $(BUILDDIR)/operate.obj $(BUILDDIR)/query.obj $(BUILDDIR)/reader.obj $(BUILDDIR)/receiving.obj $(BUILDDIR)/script.obj $(BUILDDIR)/sending.obj $(BUILDDIR)/shm.obj $(BUILDDIR)/strings.obj $(BUILDDIR)/threads.obj $(BUILDDIR)/time.obj $(BUILDDIR)/utils.obj $(BUILDDIR)/writer.obj
@echo $(CC) $(CFLAGS) $(LFLAGS) -o $@ $^
$(BUILDDIR)/communication.obj: $(SRCDIR)/communication.cc $(HEADERS)
@ -94,6 +94,10 @@ $(BUILDDIR)/query.obj: $(SRCDIR)/query.cc $(HEADERS)
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
$(BUILDDIR)/reader.obj: $(SRCDIR)/reader.cc $(HEADERS)
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<
$(BUILDDIR)/receiving.obj: $(SRCDIR)/receiving.cc $(HEADERS)
@mkdir -p $(@D)
$(CC) -c $(CFLAGS) -o $@ $<

View File

@ -1,5 +1,4 @@
## TODO NEXT
- READER.CC
- DBFUNCS.CC
- QUERY.CC

File diff suppressed because it is too large Load Diff

View File

@ -38,20 +38,3 @@ struct TNotationOrderData {
char CharacterName[30];
char Comment[200];
};
struct TReaderThreadOrder {
enum TReaderThreadOrderType OrderType;
int SectorX;
int SectorY;
int SectorZ;
ulong CharacterID;
};
struct TReaderThreadReply {
enum TReaderThreadReplyType ReplyType;
int SectorX;
int SectorY;
int SectorZ;
uchar *Data;
int Size;
};

View File

@ -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);

View File

@ -1,8 +1,6 @@
#include "config.hh"
#include "script.hh"
#include "stubs.hh"
char BINPATH[4096];
char DATAPATH[4096];
char LOGPATH[4096];

View File

@ -4,8 +4,6 @@
#include "info.hh"
#include "operate.hh"
#include "stubs.hh"
// TShortway
// =============================================================================
struct TShortwayPoint {

View File

@ -4,8 +4,6 @@
#include "magic.hh"
#include "operate.hh"
#include "stubs.hh"
TCombat::TCombat(void){
this->Master = NULL;
this->EarliestAttackTime = 0;

View File

@ -1,8 +1,6 @@
#include "cr.hh"
#include "operate.hh"
#include "stubs.hh"
#include <math.h>
// TSkill REGULAR FUNCTIONS

View File

@ -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>

View File

@ -5,8 +5,6 @@
#include "houses.hh"
#include "script.hh"
#include "stubs.hh"
#include <dirent.h>
int SectorXMin;

View File

@ -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;

View File

@ -3,8 +3,6 @@
#include "containers.hh"
#include "script.hh"
#include "stubs.hh"
#include <fstream>
static vector<TObjectType> ObjectTypes(0, 5000, 1000);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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

View File

@ -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_

View File

@ -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];

View File

@ -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;