#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);
}
Comments