dieser Bugfix ist vermutlich nur für wenige interessant, die sich schon etwas mehr mit dem Source auseinandergesetzt haben, aber diejenigen, die irgendwann mal dieses vermeintlich unlogische Problem bekommen sollten, welches ich heute gehabt habe und 3 Stunden an einer Lösung gesessen habe, denen möchte ich hiermit helfen.
Worum geht es in diesem Release? Ich möchte einen Fehler im Game-Source nennen, der Standartmäßig vorhanden ist - nur bisher nicht aufgefallen ist, da man diesen Fehler nur auf komplizierten Wegen erreicht. Der Fehler liegt in der Verbarbeitung von Events - also zeitabhängigen Ereignissen die einem bestimmten Intervall folgen. Der Fehler liegt darin, dass die Warteschlangenelemente
vor dem Aufruf der Event-Funktion
gelöscht werden (operator delete) und aber erst
nach dem Aufruf der Pointer vom Event auf das Warteschlangenelement auf
NULL gesetzt wird - sofern das Event während der Ausführung sich selbst beendet hat (durch "event_cancel") oder durch eine 0-Rückgabe der Event-Funktion.
Praktisches Beispiel für den Fehler (ich nehme jetzt mal den Weg, wie ich den Fehler bekommen habe):
a) In der Warteschlange von den Events wird das Warteschlangenelement W1 geladen
b) Dieses Element enthält Event E1 (welches einen Pointer auf W1 enthält)
c) Das Warteschlangenelement W1 wird gelöscht (operator delete)
d) Die Event-Funktion F1 wird von E1 aufgerufen
e) Diese Event-Funktion ruft eine weitere Funktion (F2) auf
f) In F2 wird ein neues Event (E2) erstellt
g) Dabei wird ein neues Warteschlangenelement W2 erstellt
h) Am Ende von F2 wird der Befehl "event_cancel(&E1)" aufgerufen (das Event (vermeintlich E1) wird beendet)
So, wo ist der Fehler? Der Fehler liegt darin, dass E2 niemals aufgerufen wird. Egal welche Zeit eingestellt wurde oder welche Funktion (F3) angegeben wurde, es wird niemals aufgerufen werden - da es von dem Befehl bei h) beendet wurde. Warum? Schauen wir es uns noch einmal detailierter mit Pointern an:
a) In der Warteschlange von den Events wird das Warteschlangenelement W1 geladen [W1->Data = E1]
b) Dieses Element enthält Event E1 [E1->pElement = W1]
c) Das Warteschlangenelement W1 wird gelöscht (operator delete) [E1->pElement = (gelöschtes) W1]
d) Die Event-Funktion F1 wird von E1 aufgerufen [E1->pElement = (gelöschtes) W1]
e) Diese Event-Funktion ruft eine weitere Funktion (F2) auf [E1->pElement = (gelöschtes) W1]
f) In F2 wird ein neues Event (E2) erstellt [W2->Data = E2; E2->pElement = W2; E1->pElement = (gelöschtes) W1 = W2]
g) Am Ende von F2 wird der Befehl "event_cancel(&E1)" aufgerufen [E1->pElement = (gelöschtes) W1 = W2 -> event_cancel(&E1) = event_cancel(&E2)]
Ich hoffe, dies war detailiert genug - für alle die sich mit kleinen Änderungen am Source auseinandersetzen ist dies sowieso noch uninteressant bzw. unrelevant.
Lösung für das Problem: ihr öffnet eure event.cpp & geht dort zur Funktion
Code:
int event_process(int pulse)
Dort scrollt ihr runter bis
Code:
new_time = (the_event->func) (get_pointer(the_event), processing_time);
und ändert den Teil
Code:
new_time = (the_event->func) (get_pointer(the_event), processing_time);
if (new_time <= 0 || the_event->is_force_to_end)
{
the_event->q_el = NULL;
}
else
{
the_event->q_el = cxx_q.Enqueue(the_event, new_time, pulse);
the_event->is_processing = FALSE;
}
zu diesem Teil ab:
Code:
the_event->q_el = NULL;
//sys_log(0, "EVENT: event %p info %p", &(*the_event), the_event->info);
new_time = (the_event->func) (get_pointer(the_event), processing_time);
if (new_time > 0 && !the_event->is_force_to_end)
{
the_event->q_el = cxx_q.Enqueue(the_event, new_time, pulse);
the_event->is_processing = FALSE;
}