diff options
| author | fusion32 <marcopuzziello@gmail.com> | 2025-07-01 09:26:06 -0300 |
|---|---|---|
| committer | fusion32 <marcopuzziello@gmail.com> | 2025-07-01 09:26:39 -0300 |
| commit | 5cfe00df82a69f44187b1cd77fe3d6865cf3425f (patch) | |
| tree | 395527bb97a908035ef9d6b1eb354b591005264f /src/reader.cc | |
| parent | 6243967f1fac3af8ed3e72790cabed0f79978bdb (diff) | |
| download | game-5cfe00df82a69f44187b1cd77fe3d6865cf3425f.tar.gz game-5cfe00df82a69f44187b1cd77fe3d6865cf3425f.zip | |
`reader.cc`
Diffstat (limited to 'src/reader.cc')
| -rw-r--r-- | src/reader.cc | 273 |
1 files changed, 272 insertions, 1 deletions
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; + } +} |
