From 5787ec961879650ac4c4b2e757df10448d2a32fb Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 23 Nov 2021 18:05:24 +0100 Subject: [PATCH] - use EventObject as storage in EVENT. --- source/games/blood/src/callback.cpp | 4 +- source/games/blood/src/eventq.cpp | 174 +++++++++++++++++----------- source/games/blood/src/eventq.h | 43 ++++--- source/games/blood/src/nnexts.cpp | 8 +- 4 files changed, 141 insertions(+), 88 deletions(-) diff --git a/source/games/blood/src/callback.cpp b/source/games/blood/src/callback.cpp index 6afafb81c..4b2343d50 100644 --- a/source/games/blood/src/callback.cpp +++ b/source/games/blood/src/callback.cpp @@ -742,9 +742,7 @@ void callbackCondition(DBloodActor* actor, int) TRCONDITION const* pCond = &gCondition[pXSprite->sysData1]; for (unsigned i = 0; i < pCond->length; i++) { EVENT evn; - evn.type = pCond->obj[i].type; - evn.actor = pCond->obj[i].actor; - evn.index_ = pCond->obj[i].index_; + evn.target.fromElements(pCond->obj[i].type, pCond->obj[i].index_, pCond->obj[i].actor); evn.cmd = pCond->obj[i].cmd; evn.funcID = kCallbackCondition; useCondition(actor, evn); diff --git a/source/games/blood/src/eventq.cpp b/source/games/blood/src/eventq.cpp index b37d6e590..54ef0bd5b 100644 --- a/source/games/blood/src/eventq.cpp +++ b/source/games/blood/src/eventq.cpp @@ -40,6 +40,15 @@ unsigned short bucketHead[kMaxID + 1]; static int bucketCount; static std::multiset queue; + +FString EventObject::description() const +{ + if (isActor()) return FStringf("actor %d", ActorP->GetIndex()); // do not add a read barrier here! + if (isSector()) return FStringf("sector %d", int(index >> 8)); + if (isWall()) return FStringf("wall %d", int(index >> 8)); + return FString("invalid object"); +} + //--------------------------------------------------------------------------- // // @@ -318,18 +327,22 @@ void evInit() // //--------------------------------------------------------------------------- -static bool evGetSourceState(int type, int nIndex, DBloodActor* actor) +static bool evGetSourceState(const EventObject& eob) { - switch (type) + if (eob.isSector()) { - case SS_SECTOR: - return sector[nIndex].hasX() && sector[nIndex].xs().state != 0; - - case SS_WALL: - return wall[nIndex].hasX() && wall[nIndex].xw().state != 0; - - case SS_SPRITE: - if (actor->hasX()) + auto pSect = eob.sector(); + return pSect->hasX() && pSect->xs().state != 0; + } + else if (eob.isWall()) + { + auto pWall = eob.wall(); + return pWall->hasX() && pWall->xw().state != 0; + } + else if (eob.isActor()) + { + auto actor = eob.actor(); + if (actor && actor->hasX()) return actor->x().state != 0; } @@ -343,29 +356,27 @@ static bool evGetSourceState(int type, int nIndex, DBloodActor* actor) // //--------------------------------------------------------------------------- -void evSend(DBloodActor* actor, int nIndex, int nType, int rxId, COMMAND_ID command) +void evSend(const EventObject& eob, int rxId, COMMAND_ID command) { switch (command) { case kCmdState: - command = evGetSourceState(nType, nIndex, actor) ? kCmdOn : kCmdOff; + command = evGetSourceState(eob) ? kCmdOn : kCmdOff; break; case kCmdNotState: - command = evGetSourceState(nType, nIndex, actor) ? kCmdOff : kCmdOn; + command = evGetSourceState(eob) ? kCmdOff : kCmdOn; break; default: break; } EVENT event; - event.actor = actor; - event.index_ = nIndex; - event.type = nType; + event.target = eob; event.cmd = command; switch (rxId) { case kChannelTextOver: if (command >= kCmdNumberic) trTextOver(command - kCmdNumberic); - else viewSetSystemMessage("Invalid TextOver command by xobject #%d (object type %d)", nIndex, nType); + else viewSetSystemMessage("Invalid TextOver command by %s", eob.description().GetChars()); return; case kChannelLevelExitNormal: levelEndLevel(0); @@ -377,16 +388,20 @@ void evSend(DBloodActor* actor, int nIndex, int nType, int rxId, COMMAND_ID comm // finished level and load custom level ¹ via numbered command. case kChannelModernEndLevelCustom: if (command >= kCmdNumberic) levelEndLevelCustom(command - kCmdNumberic); - else viewSetSystemMessage("Invalid Level-Exit# command by xobject #%d (object type %d)", nIndex, nType); + else viewSetSystemMessage("Invalid Level-Exit# command by %s", eob.description().GetChars()); return; #endif case kChannelSetTotalSecrets: if (command >= kCmdNumberic) gSecretMgr.SetCount(command - kCmdNumberic); - else viewSetSystemMessage("Invalid Total-Secrets command by xobject #%d (object type %d)", nIndex, nType); + else viewSetSystemMessage("Invalid Total-Secrets command by %s", eob.description().GetChars()); break; case kChannelSecretFound: - if (actor != nullptr) nIndex = actor->GetIndex(); // the hint system needs the sprite index. - if (SECRET_Trigger(nIndex + 65536 * nType)) // if the hint system knows this secret it's a retrigger - skip that. + { + int nIndex = -1; + if (eob.isActor() && eob.actor()) nIndex = eob.actor()->GetIndex() + 3 * 65536; // the hint system needs the sprite index. + else if (eob.isSector()) nIndex = eob.rawindex() + 6 * 65536; + else if (eob.isWall()) nIndex = eob.rawindex(); + if (SECRET_Trigger(nIndex)) // if the hint system knows this secret it's a retrigger - skip that. { if (command >= kCmdNumberic) { @@ -396,9 +411,10 @@ void evSend(DBloodActor* actor, int nIndex, int nType, int rxId, COMMAND_ID comm viewSetMessage(GStrings(FStringf("TXTB_SECRET%d", Random(2))), 0, MESSAGE_PRIORITY_SECRET); } } - else viewSetSystemMessage("Invalid Trigger-Secret command by xobject #%d (object type %d)", nIndex, nType); + else viewSetSystemMessage("Invalid Trigger-Secret command by %s", eob.description().GetChars()); } break; + } case kChannelRemoteBomb0: case kChannelRemoteBomb1: case kChannelRemoteBomb2: @@ -469,7 +485,9 @@ void evSend(DBloodActor* actor, int nIndex, int nType, int rxId, COMMAND_ID comm #endif for (int i = bucketHead[rxId]; i < bucketHead[rxId + 1]; i++) { - if (!event.isObject(rxBucket[i].type, rxBucket[i].actor, rxBucket[i].rxindex)) + EventObject eo; + eo.fromElements(rxBucket[i].type, rxBucket[i].rxindex, rxBucket[i].actor); + if (!event.event_isObject(eo)) { switch (rxBucket[i].type) { @@ -501,45 +519,45 @@ void evSend(DBloodActor* actor, int nIndex, int nType, int rxId, COMMAND_ID comm // //--------------------------------------------------------------------------- -void evPost_(DBloodActor* actor, int nIndex, int nType, unsigned int nDelta, COMMAND_ID command) +void evPost_(const EventObject& eob, unsigned int nDelta, COMMAND_ID command) { assert(command != kCmdCallback); - if (command == kCmdState) command = evGetSourceState(nType, nIndex, actor) ? kCmdOn : kCmdOff; - else if (command == kCmdNotState) command = evGetSourceState(nType, nIndex, actor) ? kCmdOff : kCmdOn; - EVENT evn = {actor, nIndex, (int8_t)nType, (int8_t)command, 0, PlayClock + (int)nDelta }; + if (command == kCmdState) command = evGetSourceState(eob) ? kCmdOn : kCmdOff; + else if (command == kCmdNotState) command = evGetSourceState(eob) ? kCmdOff : kCmdOn; + EVENT evn = {eob, (int8_t)command, 0, PlayClock + (int)nDelta }; queue.insert(evn); } -void evPost_(DBloodActor* actor, int nIndex, int nType, unsigned int nDelta, CALLBACK_ID callback) +void evPost_(const EventObject& eob, unsigned int nDelta, CALLBACK_ID callback) { - EVENT evn = {actor, nIndex, (int8_t)nType, kCmdCallback, (int16_t)callback, PlayClock + (int)nDelta }; + EVENT evn = {eob, kCmdCallback, (int16_t)callback, PlayClock + (int)nDelta }; queue.insert(evn); } void evPostActor(DBloodActor* actor, unsigned int nDelta, COMMAND_ID command) { - evPost_(actor, 0, SS_SPRITE, nDelta, command); + evPost_(EventObject(actor), nDelta, command); } void evPostActor(DBloodActor* actor, unsigned int nDelta, CALLBACK_ID callback) { - evPost_(actor, 0, SS_SPRITE, nDelta, callback); + evPost_(EventObject(actor), nDelta, callback); } void evPostSector(sectortype* sect, unsigned int nDelta, COMMAND_ID command) { - evPost_(nullptr, sectnum(sect), SS_SECTOR, nDelta, command); + evPost_(EventObject(sect), nDelta, command); } void evPostSector(sectortype* sect, unsigned int nDelta, CALLBACK_ID callback) { - evPost_(nullptr, sectnum(sect), SS_SECTOR, nDelta, callback); + evPost_(EventObject(sect), nDelta, callback); } void evPostWall(walltype* wal, unsigned int nDelta, COMMAND_ID command) { - evPost_(nullptr, wallnum(wal), SS_WALL, nDelta, command); + evPost_(EventObject(wal), nDelta, command); } @@ -549,63 +567,63 @@ void evPostWall(walltype* wal, unsigned int nDelta, COMMAND_ID command) // //--------------------------------------------------------------------------- -void evKill_(DBloodActor* actor, int index, int type) +void evKill_(const EventObject& eob) { for (auto ev = queue.begin(); ev != queue.end();) { - if (ev->isObject(type, actor, index)) ev = queue.erase(ev); + if (ev->event_isObject(eob)) ev = queue.erase(ev); else ev++; } } -void evKill_(DBloodActor* actor, int index, int type, CALLBACK_ID cb) +void evKill_(const EventObject& eob, CALLBACK_ID cb) { for (auto ev = queue.begin(); ev != queue.end();) { - if (ev->isObject(type, actor, index) && ev->funcID == cb) ev = queue.erase(ev); + if (ev->event_isObject(eob) && ev->funcID == cb) ev = queue.erase(ev); else ev++; } } void evKillActor(DBloodActor* actor) { - evKill_(actor, 0, SS_SPRITE); + evKill_(EventObject(actor)); } void evKillActor(DBloodActor* actor, CALLBACK_ID cb) { - evKill_(actor, 0, SS_SPRITE, cb); + evKill_(EventObject(actor)); } void evKillWall(walltype* wal) { - evKill_(nullptr, wallnum(wal), SS_WALL); + evKill_(EventObject(wal)); } void evKillSector(sectortype* sec) { - evKill_(nullptr, sectnum(sec), SS_SECTOR); + evKill_(EventObject(sec)); } // these have no target. void evSendGame(int rxId, COMMAND_ID command) { - evSend(nullptr, 0, 0, rxId, command); + evSend(EventObject(nullptr), rxId, command); } void evSendActor(DBloodActor* actor, int rxId, COMMAND_ID command) { - evSend(actor, 0, SS_SPRITE, rxId, command); + evSend(EventObject(actor), rxId, command); } void evSendSector(sectortype* sect, int rxId, COMMAND_ID command) { - evSend(nullptr, sectnum(sect), SS_SECTOR, rxId, command); + evSend(EventObject(sect), rxId, command); } void evSendWall(walltype* wal, int rxId, COMMAND_ID command) { - evSend(nullptr, wallnum(wal), SS_WALL, rxId, command); + evSend(EventObject(wal), rxId, command); } //--------------------------------------------------------------------------- @@ -620,34 +638,27 @@ void evProcess(unsigned int time) { EVENT event = *queue.begin(); queue.erase(queue.begin()); - if (event.type == SS_SPRITE) + if (event.target.isActor()) { // Don't call events on destroyed actors. Seems to happen occasionally. - if (!event.actor || event.actor->s().statnum == kStatFree) continue; + if (!event.target.actor() || event.target.actor()->s().statnum == kStatFree) continue; } if (event.cmd == kCmdCallback) { assert(event.funcID < kCallbackMax); assert(gCallback[event.funcID] != nullptr); - gCallback[event.funcID](event.actor, event.index_); + if (event.target.isActor()) gCallback[event.funcID](event.target.actor(), -1); + else if (event.target.isSector()) gCallback[event.funcID](nullptr, sectnum(event.target.sector())); + // no case for walls defined here. } else { - switch (event.type) - { - case SS_SECTOR: - trMessageSector(event.index_, event); - break; - case SS_WALL: - trMessageWall(event.index_, event); - break; - case SS_SPRITE: - trMessageSprite(event.actor, event); - break; + if (event.target.isActor()) trMessageSprite(event.target.actor(), event); + else if (event.target.isSector()) trMessageSector(sectnum(event.target.sector()), event); + else if (event.target.isWall()) trMessageWall(wallnum(event.target.wall()), event); } } - } } //--------------------------------------------------------------------------- @@ -656,14 +667,47 @@ void evProcess(unsigned int time) // //--------------------------------------------------------------------------- +FSerializer& Serialize(FSerializer& arc, const char* keyname, EventObject& w, EventObject* def) +{ + if (arc.BeginObject(keyname)) + { + int type = w.isActor() ? 0 : w.isSector() ? 1 : 2; + arc("type", type); + switch (type) + { + case 0: + { + DBloodActor* a = arc.isWriting()? w.actor() : nullptr; + arc("actor", a); + if (arc.isReading()) w = a; + break; + } + case 1: + { + auto s = arc.isWriting()? w.sector() : nullptr; + arc("sector", s); + if (arc.isReading()) w = s; + break; + } + case 2: + { + auto s = arc.isWriting()? w.wall() : nullptr; + arc("wall", s); + if (arc.isReading()) w = s; + break; + } + } + arc.EndObject(); + } + return arc; +} + FSerializer& Serialize(FSerializer& arc, const char* keyname, EVENT& w, EVENT* def) { if (arc.BeginObject(keyname)) { - arc("type", w.type); - if (w.type != SS_SPRITE) arc("index", w.index_); - else arc("index", w.actor); - arc("command", w.cmd) + arc("target", w.target) + ("command", w.cmd) ("func", w.funcID) ("prio", w.priority) .EndObject(); diff --git a/source/games/blood/src/eventq.h b/source/games/blood/src/eventq.h index 10ea33440..e2bbff2dc 100644 --- a/source/games/blood/src/eventq.h +++ b/source/games/blood/src/eventq.h @@ -40,10 +40,12 @@ class EventObject uint64_t index; }; +public: EventObject() = default; - EventObject(DBloodActor* actor_) { ActorP = actor_; assert(isActor()); /* GC:WriteBarrier(actor);*/ } - EventObject(sectortype *sect) { index = (sectnum(sect) << 8) | Sector; } - EventObject(walltype* wall) { index = (wallnum(wall) << 8) | Wall; } + explicit EventObject(std::nullptr_t) { index = -1; } + explicit EventObject(DBloodActor* actor_) { ActorP = actor_; assert(isActor()); /* GC:WriteBarrier(actor);*/ } + explicit EventObject(sectortype *sect) { index = (sectnum(sect) << 8) | Sector; } + explicit EventObject(walltype* wall) { index = (wallnum(wall) << 8) | Wall; } EventObject& operator=(DBloodActor* actor_) { ActorP = actor_; assert(isActor()); /* GC:WriteBarrier(actor);*/ return *this; } EventObject& operator=(sectortype *sect) { index = (sectnum(sect) << 8) | Sector; return *this; } @@ -56,6 +58,21 @@ class EventObject DBloodActor* actor() const { assert(isActor()); return /*GC::ReadBarrier*/(ActorP); } sectortype* sector() const { assert(isSector()); return &::sector[index >> 8]; } walltype* wall() const { assert(isWall()); return &::wall[index >> 8]; } + int rawindex() const { return index >> 8; } + + bool operator==(const EventObject& other) const { return index == other.index; } + bool operator!=(const EventObject& other) const { return index != other.index; } + + FString description() const; + + // refactoring helper + [[deprecated]] void fromElements(int type, int index, DBloodActor* act) + { + if (type == 0) *this = &::wall[index]; + else if (type == 6) *this = &::sector[index]; + else if (type == 3) *this = act; + else assert(false); + } }; @@ -182,9 +199,7 @@ inline bool channelRangeIsFine(int channel) { struct EVENT { - DBloodActor* actor; - int index_; - int8_t type; + EventObject target; int8_t cmd; int16_t funcID; int priority; @@ -194,42 +209,42 @@ struct EVENT return priority < other.priority; } - bool isObject(int type, DBloodActor* actor, int index) const + bool event_isObject(const EventObject& obj) const { - return (this->type == type && (this->type != SS_SPRITE ? (this->index_ == index) : (this->actor == actor))); + return (this->target == obj); } bool isActor() const { - return type == SS_SPRITE; + return target.isActor(); } bool isSector() const { - return type == SS_SECTOR; + return target.isSector(); } bool isWall() const { - return type == SS_WALL; + return target.isWall(); } DBloodActor* getActor() const { assert(isActor()); - return actor; + return target.actor(); } sectortype* getSector() const { assert(isSector()); - return §or[index_]; + return target.sector(); } walltype* getWall() const { assert(isWall()); - return &wall[index_]; + return target.wall(); } }; diff --git a/source/games/blood/src/nnexts.cpp b/source/games/blood/src/nnexts.cpp index 7d0534ad0..bd2d362fd 100644 --- a/source/games/blood/src/nnexts.cpp +++ b/source/games/blood/src/nnexts.cpp @@ -1115,10 +1115,8 @@ void nnExtProcessSuperSprites() if (pXCond->data1 >= kCondGameBase && pXCond->data1 < kCondGameMax) { EVENT evn; - evn.index_ = 0; - evn.actor = pCond->actor; + evn.target = pCond->actor; evn.cmd = (int8_t)pXCond->command; - evn.type = OBJ_SPRITE; evn.funcID = kCallbackMax; useCondition(pCond->actor, evn); } @@ -1128,10 +1126,8 @@ void nnExtProcessSuperSprites() for (unsigned k = 0; k < pCond->length; k++) { EVENT evn; - evn.actor = pCond->obj[k].actor; - evn.index_ = pCond->obj[k].index_; + evn.target.fromElements(pCond->obj[k].type, pCond->obj[k].index_, pCond->obj[k].actor); evn.cmd = pCond->obj[k].cmd; - evn.type = pCond->obj[k].type; evn.funcID = kCallbackMax; useCondition(pCond->actor, evn); }