Guten Abend,
ich habe ein unvorstellbaren Fehler im Script.
else if(dialogid == DIALOG_MP53)
{
new Waffen[13][2],string[144],gid = Spieler[playerid][GruppenID];
if(response)
{
if(!IsNumeric(inputtext))return ShowPlayerDialog(playerid,DIALOG_MP53,DIALOG_STYLE_INPUT,"{FF9000}Waffenschrank (Verstauen){FFFFF} - MP5","{FFFFFF}Wie viele Patronen möchtest du von deiner MP5 in den Waffenschrank verstauen?","Verstauen","Alle");
for(new i=0;i<13;i++)
{
GetPlayerWeaponData(playerid,i,Waffen[i][0],Waffen[i][1]);
if(Waffen[i][0] != 29)continue;
if(!strlen(inputtext))return ShowPlayerDialog(playerid,DIALOG_MP53,DIALOG_STYLE_INPUT,"{FF9000}Waffenschrank (Verstauen){FFFFF} - MP5","{FFFFFF}Wie viele Patronen möchtest du von deiner MP5 in den Waffenschrank verstauen?","Verstauen","Alle");
if(strval(inputtext) > Waffen[i][1])return SendClientMessage(playerid,rot,"[SERVER]:{FFFFFF} Soviele Patronen besitzt deine MP5 nicht!"),ShowPlayerDialog(playerid,DIALOG_MP53,DIALOG_STYLE_INPUT,"{FF9000}Waffenschrank (Verstauen){FFFFF} - MP5","{FFFFFF}Wie viele Patronen möchtest du von deiner MP5 in den Waffenschrank verstauen?","Verstauen","Alle");
RemovePlayerWeapon(playerid,29,strval(inputtext));
Gruppe[gid][G_MP5] += strval(inputtext);
format(string,144,"[ Waffenschrank - MP5 ]:{FFFFFF} %s hat %d Patronen seiner MP5 in den Waffenschrank verstaut!",Name(playerid),strval(inputtext));
SendGruppenChat(playerid,hblau,string);
return 1;
}
return 1;
}
for(new i=0;i<13;i++)
{
GetPlayerWeaponData(playerid,i,Waffen[i][0],Waffen[i][1]);
if(Waffen[i][0] != 29)continue;
RemovePlayerWeapon(playerid,29);
Gruppe[gid][G_MP5] += Waffen[i][1];
format(string,144,"[ Waffenschrank - MP5 ]:{FFFFFF} %s hat alle Patronen (%d) seiner MP5 in den Waffenschrank verstaut!",Name(playerid),Waffen[i][1]);
SendGruppenChat(playerid,hblau,string);
return 1;
}
}
In diesen Code wird mir angezeigt, dass Waffen bereits definiert ist.
Hier habe ich Waffen bereits definiert, ist aber in einem anderen else if.
else if(dialogid == DIALOG_DEAGLE3)
{
new Waffen[13][2],string[144],gid = Spieler[playerid][GruppenID];
if(response)
{
if(!IsNumeric(inputtext))return ShowPlayerDialog(playerid,DIALOG_DEAGLE3,DIALOG_STYLE_INPUT,"{FF9000}Waffenschrank{FFFFFF} - Desert Eagle","{FFFFFF}Wie viele Patronen möchtest du in den Waffenschrank verstauen?","Verstauen","Alle");
for(new i=0;i<13;i++)
{
GetPlayerWeaponData(playerid,i,Waffen[i][0],Waffen[i][1]);
if(Waffen[i][0] != 24)continue;
if(strval(inputtext) > Waffen[i][1])return SendClientMessage(playerid,rot,"[SERVER]:{FFFFFF} Soviele Patronen besitzt deine Desert Eagle nicht!"),ShowPlayerDialog(playerid,DIALOG_DEAGLE3,DIALOG_STYLE_INPUT,"{FF9000}Waffenschrank{FFFFFF} - Desert Eagle","{FFFFFF}Wie viele Patronen möchtest du in den Waffenschrank verstauen?","Verstauen","Alle");
RemovePlayerWeapon(playerid,24,strval(inputtext));
Gruppe[gid][G_Deagle] += strval(inputtext);
format(string,144,"[ Waffenschrank - Desert Eagle ]:{FFFFFF} %s hat %d Patronen seiner Desert Eagle in den Waffenschrank verstaut!",Name(playerid),strval(inputtext));
SendGruppenChat(playerid,hblau,string);
return 1;
}
return 1;
}
if(!response)
{
for(new i=0;i<13;i++)
{
GetPlayerWeaponData(playerid,i,Waffen[i][0],Waffen[i][1]);
if(Waffen[i][0] != 24)continue;
RemovePlayerWeapon(playerid,24);
Gruppe[gid][G_Deagle] += Waffen[i][1];
format(string,144,"[ Waffenschrank - Desert Eagle ]:{FFFFFF} %s hat alle Patronen (%d) seiner Deagle in den Waffenschrank verstaut!",Name(playerid),Waffen[i][1]);
SendGruppenChat(playerid,hblau,string);
return 1;
}
return 1;
}
return 1;
}
-
-
Hast du es nirgends anders definiert? Zum Beispiel global oder in einem Enum?
Wenn du nichts findest kannst du es ja immer noch umbenennen, machst eine 2 hin oder so. -
Nein, habe schon das ganze Script untersucht.
Eigentlich muss das doch funktioniert, da die beiden nicht global sind. -
Ich habe es grade bei mir getestet, es ist tatsächlich so.
Und zwar geht es, wenn es ein ein-dimensionales Array ist (Waffen[10]) oder eine normale Variable. Bei zwei-dimensionalen Arrays (Waffen[10][5]) geht es nicht mehr.
Muss wohl am Kompiler liegen.Also: Das zweite Array umbenennen.
Geht nicht:
if(dialogid == 1)
{
new Waffen[10][2];
Waffen[0][1] = 1;
}
if(dialogid == 2)
{
new Waffen[10][2];
Waffen[0][0] = 1;
}Geht:
if(dialogid == 1)
{
new Waffen[10];
Waffen[0] = 1;
}
if(dialogid == 2)
{
new Waffen[10];
Waffen[0] = 1;
} -
Muss wohl am Kompiler liegen.
einen genauen grund kann ich zwar nicht nennen, aber möglicherweise ist das Problem die Strukturebene und der Compiler schiebt sich das irgendwie zurecht.
bspw. sonew Waffen[10][2];
if(dialogid == 1)
{
Waffen[0][1] = 1;
}
new Waffen[10][2];
if(dialogid == 2)
{
Waffen[0][0] = 1;
}
Es könnte aber auch daran liegen, dass PAWN nur indirekt Mehrdimenionale Arrays unterstützt, denn diese werden sozusagen zusammen gerechnet.
sprich aus Waffen[10][2] wird Waffen[20]. -
der Compiler schiebt sich das irgendwie zurecht.
Das macht der Compiler nicht, sonst würde das hier keine Errors ergeben, tatsächlich sagt er aber, dass Waffen2 nicht definiert ist. Würde er es vor die if-Klammer ziehen, wäre es definiert, ebenso wenn er es als globales Array ansehen würde.
if(dialogid == 1)
{
new Waffen[10][5];
Waffen[0][1] = 1;
}
if(dialogid == 2)
{
Waffen2[0][1] = 1;
new Waffen2[10][5];
Waffen2[0][2] = 1;
}
=> error 017: undefined symbol "Waffen2" (in ZeileHatte ich mir zuerst auch gedacht, ist aber nicht so.
Es könnte aber auch daran liegen, dass PAWN nur indirekt Mehrdimenionale Arrays unterstützt, denn diese werden sozusagen zusammen gerechnet.
sprich aus Waffen[10][2] wird Waffen[20].
Glaube ich nicht, und selbst wenn, dann müsste es ja funktionieren, da es mit ein-dimensionalen Arrays ohne Probleme geht (siehe Beispiele oben).
So sieht es eher im RAM aus, zehn Pointer mit der jeweiligen Länge zwei (bei [10][2]) die hintereinander liegen.Die Definition fällt schlichtweg durch die kommenden Klammern durch (wie z.B. bei Java switch-case), da auch das hier funktioniert:
if(dialogid == 1)
{
new Waffen[10][5];
Waffen[0][1] = 1;
}
if(dialogid == 2)
{
Waffen[0][2] = 1;
}
Waffen[0][3] = 1;=> Wenn das also nicht so gewollt ist (Warum sollte es?), dann ist das ein Fehler im Compiler. Der Compiler ist im Grunde genommen auch nur ein Programm, und jedes Programm kann ja bekanntermaßen Fehler beinhalten.
-
Kann es sein, dass das Script schon ziemlich groß ist ?
PAWN war ja normalerweise nie dafür gedacht ein zu großes Programm zu sein. War eher für die kleinen Computer (z.B. wie Adruino).
-
Wie meinst du das?
Meinst du damit nun mein Script? -
Jap, im gesamten (inklusive Includes).
// EDIT: Also die beste Lösung statt zwei zu definieren, dass du vor dem großen if die Variable deklarierst. Herumschieben tut PAWN in dem Falle nicht. Aber es wäre wirklich interessant zu wissen Hier sollte mal ein Profi uns aufklären.
-
Nein, 3280 Zeilen, ich finde das geht noch
9 Includes, wovon ich eine gerade nicht benutze
EDIT:
Ich habe new Waffen[13][2]; nun mal unter OnDialogResponse ganz oben hingemacht.
Anscheinend klappt das wohl, so brauche ich auch nur einmal das definieren
Dankeschön. -
-
Hier meine Testläufe (Man bemerke jedoch, dass der Fehler zur Laufzeit nur mit "crashdetect" erkannt werden kann. Ohne dem Plugin sieht man den Fehler überhaupt nicht und er überspringt den Code):
public OnGameModeInit()
{
// Don't use these lines if it's a filterscript
SetGameModeText("Blank Script");
AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
new test = 5;
if(test == 5) {
if(test == 5) {
if(test == 5) {
if(test == 5) {
// Wenn Diese Zeile auskommentiert wird, komm kein Compilterfehler,
// kann er w‰hrend der Laufzeit nicht darauf zugreifen.
// new Waffen[10][2];
}
}
}
new Waffen[10][2];
Waffen[0][1] = 999;
printf("DEBUG %d", Waffen[0][1]);
// Wenn die folgende Initialisierung oberhalb vom 2-dimensionalem Array
// geschieht, dann erkennt der Compiler dies auch als Fehler.
new Waffe;
Waffe = 5;
printf("DEBUG %d", Waffe);
}if(test == 5) {
new Waffe;
Waffe = 6;printf("DEBUG %d", Waffe);
// Ergibt auch keinen Compilerfehler aber einen Fehler zur Laufzeit,
// wenn auskommentiert.
// new Waffen[10][2];
Waffen[0][1] = 888;
printf("DEBUG %d", Waffen[0][1]);
}
return 1;
}Finde die Tatsache mit der Variable "Waffe" lustig, weil wenn man die Deklaration "Waffen" und die Verwendung weglöscht, erkennt der PAWN Compiler es nicht als "already defined" für Waffe.
Nebenbei das "already defined" für die Variable "Waffe" erscheint nur, wenn sie oberhalb vom Array initialisiert wird.
Hier ein Test der fehlerfrei ist:
public OnGameModeInit()
{
// Don't use these lines if it's a filterscript
SetGameModeText("Blank Script");
AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);
new test = 5;
if(test == 5) {
new Waffe;
Waffe = 5;
printf("DEBUG %d", Waffe);
}if(test == 5) {
new Waffe;
Waffe = 6;printf("DEBUG %d", Waffe);
}
return 1;
}Hab aus der Dokumentation folgendes herausgelesen:
Zitat
Multi-dimensional arrays are arrays that contain references to the sub-arrays.
That is, a two-dimensional array is an “array of single-dimensional arrays”.∗
Below are a few examples of declarations of two-dimensional arraysBedeutet er erstellt in dem Fall zwei 1-dimensionale-Array´s womöglich, die wie folgt aussehen könnten:
ACHTUNG: Das folgende ist nur Bauernverstand, weil ich mich mit Compiler nie ausgesetzt habe.
LOGIK: Da PAWN 32-byte Felder erstellt (256 Bit) soll er die Adresse zu Waffen[0] um eben 256-bit verschieben, sodass die Adresse von Waffen[1] mit dem ODER-Parameter eingeordnet wird.
new Waffen{2], WaffenLink[10] = {&Waffen[1] << 256 | &Waffen[0], ...};Letzten Endes vermischt der Compiler den VariablenNamen mit dem Funktionsnamen und den inneren if´s (Ich geh davon aus, dass jedes if eine eigene ID in einer Funktion hat).
Also es muss ein Compilerfehler selbst sein, da er wahrscheinlich vergisst die 2. Variable (Anschaulich an "WaffenLink") nicht umwandelt und an die if-Strukturen (oder andere wie "switch") anpasst. (An der Funktion schon, sonst würde man nicht in einer anderen Funktion es erneut definieren können)
Wobei das mit den 32-byte (256 Bit Verschiebung) muss nicht stimmen, da es letztendlich nur auf einem Bauernverstand beruht.
Lg
-
Freut mich zu sehen, dass es immer wieder Leute gibt die ihr Gesagtes auch darlegen können, Templer gehört da auf jeden Fall dazu!
Also es muss ein Compilerfehler selbst sein, da er wahrscheinlich vergisst die 2. Variable (Anschaulich an "WaffenLink") nicht umwandelt und an die if-Strukturen (oder andere wie "switch") anpasst. (An der Funktion schon, sonst würde man nicht in einer anderen Funktion es erneut definieren können)
Genau. Deine Testläufe mit dem crashdetect-Plugin untermauern meine vorherige Aussage noch, dass es ein Fehler im Compiler ist. Ich habe diese Testläufe selbst auch nochmal gemacht und kann das bestätigen. Wie genau der Compiler das macht, da geht es mir wie dir, weiß ich nicht, aber das könnte eine Möglichkeit sein. Letztendlich ist es ja auch egal wie er es macht, er macht es falsch und zwar komplett falsch.
Der Fehler bleibt auch innerhalb einer Funktion bzw. eines Callbacks, da man das Multi-dimensionale Array in einer anderen Funktion wieder definieren kann.Mit 3-dimensionalen Arrays ist es übrigens genau gleich.
Finde die Tatsache mit der Variable "Waffe" lustig, weil wenn man die Deklaration "Waffen" und die Verwendung weglöscht, erkennt der PAWN Compiler es nicht als "already defined" für Waffe.
Nebenbei das "already defined" für die Variable "Waffe" erscheint nur, wenn sie oberhalb vom Array initialisiert wird.
Habe das eben auch nochmal ausprobiert. Es ist tatsächlich so, dass egal was man über einem Multi-dimensionalen Array auf gleicher Ebene (!) definiert hat, der Compiler erkennt es als Error (bereits definiert). Wirklich interessant, denn wenn man es drunter definiert macht es gar nichts aus.Noch interessanter wird es hier: (ich habe mir mal eben dein Beispiel geborgt)
public OnGameModeInit()
{
// Don't use these lines if it's a filterscript
SetGameModeText("Blank Script");
AddPlayerClass(0, 1958.3783, 1343.1572, 15.3746, 269.1425, 0, 0, 0, 0, 0, 0);new test = 5;
if(test == 5)
{
if(test == 5)
{
new Waffe;
new Waffen[10][2];
Waffen[0][1] = 999;
printf("DEBUG %d", Waffen[0][1]);Waffe = 5;
printf("DEBUG %d", Waffe);
}
}if(test == 5)
{
new Waffe;
Waffe = 6;printf("DEBUG %d", Waffe);
}return 1;
}=> warning 219: local variable "Waffe" shadows a variable at a preceding level
Es ist jetzt nicht mehr die gleiche Ebene, von der Syntax her passt es immer noch, da es nicht in der gleichen if-Klammer ist, dennoch meint der Compiler es sei schon vorhanden, in diesem Fall aber die Warnung, die normal kommt wenn es in einer tieferen Ebene erneut definiert wird, z.B. so:
new tmp;
if(tmp)
{
new tmp;
}
Hier bekommen wir die Warnung 219.Im Beispiel oben mit "Waffe" ist es aber anschaulich dargestellt so:
new xy;
if(xy)
{
new tmp;
}
new tmp;
Hier findet der Compiler keinen Fehler (ist ja auch korrekt!), abgesehen von den "is never used", die ich hier mal vernachlässige. Durch die nachfolgende Definition eines multi-dimensionalen Arrays wird es plötzlich als falsch erkannt.
new xy;
if(xy)
{
new tmp;
new array[10][10];
}
new tmp; //219
=> Warnung 219 für tmp.Irgendwas bringt den Compiler also mächtig durcheinander, wenn man Multi-dimensionale Arrays innerhalb von Funktionen/Callbacks definiert, auch wenn es von der Syntax her kein Problem sein darf.
Durch diese Tests und die Tests von Templer sehe ich es als bewiesen an, dass hier ein Fehler im Compiler ist.
...und zwar kein kleiner! -
Zur Vollständigkeit zitiere ich noch Y_Less, warum SAMP nicht auf die neue PAWN Version umgeschrieben wird: Die neue Version würde Sicherheitslücken schließen, welche von anderen Autoren ausgenutzt werden. (besonders weil Systeme von Y_Less nutzlos wären, weil er selbst diese Bug´s ausnutzt :P)
Ich finde es nur schade, weil in der neuen Version eine Mac Version bereitgestellt worden ist und ein User bei Google Code bereits einen patch schrieb, der das kompilieren einer Mac Version vervollständigte.
Leider steht aber auch der Source-Code von der PAWN Version 3.2.3664 nichtmehr zur Verfügung.
Die Änderungen zur Version Version 3.2, build 3664 hier:
http://pastebin.com/Qn4xmwCf
(Ein bisschen reinstöbern zeigt auch bereits die volle Änderung der Sprache und wahrscheinlich ist da drinnen auch irgendwo der Bugfix für unser Problem)Quelle: http://forum.sa-mp.com/showthread.php?t=274061&page=6
We have literally millions of lines of code written using the current version. We know well what the compiler can and can't do; there are some advanced techniques employed by libraries used in many many scripts that exploit some parts of the current compiler or VM's peculiarities. We know how to call arbitrary functions by address, escape the data segment, and obtain the AMX's real address. With those three tricks, based on security holes; people hook callbacks, query AMX file information, and can even modify the server itself from inside PAWN:
Quote:
* Opcode checking has become stricter: when initializing an abstract machine, the abstract machine tests the parameters of branch instructions and of instructions that access data in the data segment or the stack/heap.
"Holes" fixed.The compiler doesn't allow define replacements in:
pawn Code:
"%0"But a bug means this does work when it shouldn't:
pawn Code:
"\"%0\""Plus the new compiler doesn't use the same string concatenation and stringize operators as most SA-MP modes.
Quote:
* BUG fix in amx.c: when calling amx_Exec() with the flag to continue from the point that the abstract machine encountered a "sleep" instruction, it should also reload the overlay (a nested call to the AMX could have kicked the sleeping function out of the pool).
I use this bug in "y_malloc" to allocate data on the heap and hide it from being reclaimed by the VM.So any "fixes" might actually break widely used code.
Edit: A look at the latest source code shows that the "LREF" trick used to escape the VM hasn't been patched yet, but other things have.
p.S. Ich entschuldige wenn das Forum bereits ein solches Thema angeschnitten hat. Sollte jemand einen Link zu einem Post betreffend (Neue PAWN Version) finden, so schreibe er ihn bitte unterbei.
Hier wollte ich nur das endgültige Fazit zum derzeit unbeschreiblichen Fehler bringen, damit auch interessierte Leser in Zukunft damit klar kommen. (Daher auch Zitate beigefügt vom sa-mp.com Forum, wenn dieses vorher offline geschaltet werden sollte, als sa-mp.de :P)
Der Link zu Pastebin wird wahrscheinlich noch lange halten.
//EDIT: Tippfehler behoben
-
breadfish.de
Hat das Thema geschlossen.