#include "TriggerCore.h" TriggerCore::TriggerCore(EUDStarcraft* sc, char* data, unsigned int length) { this->data = data; this->length = length; this->sc = sc; this->sc->PlayersTriggerList[0].first = nullptr; this->sc->PlayersTriggerList[1].first = nullptr; this->sc->PlayersTriggerList[2].first = nullptr; this->sc->PlayersTriggerList[3].first = nullptr; this->sc->PlayersTriggerList[4].first = nullptr; this->sc->PlayersTriggerList[5].first = nullptr; this->sc->PlayersTriggerList[6].first = nullptr; this->sc->PlayersTriggerList[7].first = nullptr; } #define NODE_NEEDED EnabledFor(t, player) || EnabledFor(t, Players::AllPlayers) || EnabledFor(t, Players::Force1 + playerForces[player]) void createNodeIfNeeded(TriggerNode* nodes, unsigned int* freeNodeIndex, Trigger* t, unsigned int player, unsigned char* playerForces, TriggerList* PlayersTriggerList) { if (NODE_NEEDED) { TriggerList* lst = &(PlayersTriggerList[player]); TriggerNode* node = &(nodes[*freeNodeIndex]); *freeNodeIndex = (*freeNodeIndex) + 1; node->prev = nullptr; node->next = nullptr; memcpy(&(node->data), t->data, sizeof(TriggerData)); if (lst->first == nullptr) { // First lst->first = node; } else { // Has prev node->prev = lst->last; node->prev->next = node; } lst->last = node; } } bool TriggerCore::construct() { char* localData = this->data; // Construct trigger array for (unsigned int i = 0; i < length / sizeof(TriggerData); i++) { Trigger* t = new Trigger(localData, i); localData += sizeof(TriggerData); if (!triggers.append(t)) { delete t; return false; } } // Calculate how many nodes it takes totalNodes = 0; unsigned char* playerForces = sc->playerForces; for (unsigned int i = 0; i < triggers.getSize(); i++) { Trigger* t = triggers.get(i); for (unsigned int player = 0; player < 8; player++) { if (NODE_NEEDED) { totalNodes++; } } } sc->firstNode = nullptr; sc->lastNode = nullptr; if (totalNodes > 0) { // Create nodes memset(sc->PlayersTriggerList, 0, sizeof(TriggerList) * 8); MALLOC_N(newNodes, TriggerNode, totalNodes, { return false; }); nodes = newNodes; sc->firstNode = nodes; sc->lastNode = nodes + (sizeof(TriggerNode)*totalNodes); // Create trigger lists unsigned int currentNodeIndex = 0; for (unsigned int i = 0; i < triggers.getSize(); i++) { Trigger* t = triggers.get(i); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player1, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player2, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player3, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player4, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player5, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player6, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player7, sc->playerForces, sc->PlayersTriggerList); createNodeIfNeeded(nodes, ¤tNodeIndex, t, Players::Player8, sc->playerForces, sc->PlayersTriggerList); } } return true; } inline bool TriggerCore::isNativeTrigger(TriggerNode* node) { return node >= nodes && node < nodes + ((sizeof(TriggerNode)*totalNodes)); } TriggerCore::~TriggerCore() { for (unsigned int i = 0; i < triggers.getSize(); i++) { Trigger* trig = triggers.get(i); delete trig; } FREE_NOT_NULL(nodes); FREE_NOT_NULL(data); } TriggerCore * TriggerCore::get(char * file, EUDStarcraft* sc) { bool error = false; FILE* f; if (!fopen_s(&f, file, "rb")) { ReadBuffer rb(f, &error); fclose(f); if (error) { return nullptr; } unsigned int length = rb.getDataSize(); char* data = (char*) rb.readArray(length, &error); if (error) { return nullptr; } TriggerCore* tc = new TriggerCore(sc, data, length); if (!tc->construct()) { delete tc; return nullptr; } return tc; } return nullptr; } void TriggerCore::run() { sc->load(); bool _segFault = false; bool* segFault = &_segFault; FILE* f; if (fopen_s(&f, "..\\EUDEmulator\\exec.txt", "wb")) { return; } // Execute triggers in loops while(true) { TriggerNode* prev = nullptr; for (unsigned int playerTriggerIndex = 0; playerTriggerIndex < 8; playerTriggerIndex++) { sc->currentPlayerIndexForTriggers = playerTriggerIndex; if (sc->executePlayerLoop[playerTriggerIndex]) { TriggerList* triggers = &(sc->PlayersTriggerList[playerTriggerIndex]); TriggerNode* node = triggers->first; unsigned int triggersExecutedCounter = 0; while (node != nullptr) { bool outputCurrentTrigger = false; int triggerIndex = -1; int triggerFlags = -1; WriteBuffer conditionBuffer; WriteBuffer actionBuffer; if (!sc->isAllocated((unsigned int) node, sizeof(TriggerNode))) { *segFault = true; #ifdef TRIG_PRINT OutputDebugStringA("\r\n\r\n =================== End of execution because of segfault of node =================== \r\n\r\n"); #endif } if (!(*segFault)) { // Node is valid // Update current trigger sc->currentTriggerNode = node; triggersExecutedCounter++; TriggerData* trigger = (TriggerData*)(&node->data); triggerIndex = trigger->flags >> 16; triggerFlags = trigger->flags & 0xffff; if (Trigger::canBeExecutedNow(sc, trigger, &conditionBuffer, segFault)) { // Can be executed SET_EXECUTE(trigger); } if (!(*segFault)) { // Conditions didn't cause segfault if (HAS_EXECUTE(trigger)) { // Can be executed outputCurrentTrigger = true; CLEAR_EXECUTE(trigger); // Clear execution flag bool stopTriggersForCurrentPlayer = false; bool stopTriggersForAllPlayers = false; Trigger::executeNow(sc, trigger, &actionBuffer, &stopTriggersForCurrentPlayer, &stopTriggersForAllPlayers, segFault); if (!HAS_PRESERVE(trigger)) { SET_IGNORE_EXECUTION(trigger); } if (stopTriggersForCurrentPlayer) { sc->executePlayerLoop[playerTriggerIndex] = false; } if (stopTriggersForAllPlayers) { for (unsigned int playerIndex = 0; playerIndex < 8; playerIndex++) { sc->executePlayerLoop[playerIndex] = false; } break; } } } } #ifdef TRIG_PRINT if (outputCurrentTrigger || (*segFault)) { // Output incomplete trigger causing segfault or any executed trigged bool error = false; conditionBuffer.writeByte(0, &error); actionBuffer.writeByte(0, &error); unsigned char* actData; unsigned char* condData; unsigned int actDataLen; unsigned int condDataLen; conditionBuffer.getWrittenData(&condData, &condDataLen); actionBuffer.getWrittenData(&actData, &actDataLen); char trigID[128]; if (isNativeTrigger(node)) { sprintf_s(trigID, "%d (flags: %d), for player %d", triggerIndex, triggerFlags, playerTriggerIndex + 1); } else { // Trigger outside of TRIG section unsigned int offPtr = 0; char* fmt = sc->getTriggerOrigin(node, &offPtr, segFault); sprintf_s(trigID, "%s[%d] 0x%X (flags: %d), for player %d", fmt, offPtr, (unsigned int)node, triggerFlags, playerTriggerIndex + 1); } if (!outputCurrentTrigger) { OutputDebugStringA("Following trigger was NOT executed\r\n"); } if (*segFault) { OutputDebugStringA("Following trigger caused segfault\r\n"); } OutputDebugStringA("///////////////////// Conditions["); OutputDebugStringA(trigID); OutputDebugStringA("] ////////////////////\r\n"); OutputDebugStringA((char*)condData); OutputDebugStringA("////////////////////// Actions["); OutputDebugStringA(trigID); OutputDebugStringA("] //////////////////////\r\n"); OutputDebugStringA((char*)actData); OutputDebugStringA("///////////////////////////////////////////////////////////////////////////////////\r\n\r\n"); } #endif if (*segFault) { // Break trigger loop for current player break; } prev = node; node = node->next; } } if (*segFault) { // Break trigger loop for all players break; } } if (*segFault) { // Stop triggers break; } OutputDebugStringA("\r\n\r\n ================== End of trigger loop =================\r\n\r\n"); Sleep(500); } if (*segFault) { OutputDebugStringA("\r\n\r\n =================== End of execution because of segfault =================== \r\n\r\n"); } fclose(f); }