Problem mit Speichersystem

  • Problem mit Speichersystem

    Ich habe ein Problem mit meinem Secret-Speichersystem.
    Das System ist so aufgebaut, das es die Geldmenge im Spiel in 2 Bytes umwandelt, da noch 100 Bytes dazupackt, in denen gespeichert ist, welche Secrets freigeschaltet wurden und welche nicht und das dann alles in eine Textdatei schreibt.

    Das Problem ist: in den meisten fällen klappts aber manchmal wird ein Byte einfach 'vergessen', was in einer Verschiebung der 'Secret-Bytes' (z.b. vorher war nur secret 2 freigeschaltet, hinterher nur secret 1...) und Änderung der Geldmenge resultiert.
    Das ist natürlich fatal wenn man sich vorher für viel Geld ein teures Secret erkauft hat nur, um es dann wieder gesperrt zu sehen.

    Ich habe keine Ahnung, warum das passiert und fange schon an, zu glauben, das der Fehler beim Gamemaker liegt.

    Hier ist der Code für das System:

    scr_encode_number:
    Verwandelt eine positive nummer in 2 Bytes.

    GML-Quellcode

    1. var num,str;
    2. num=argument0;
    3. str="";
    4. num=min(65025+254,floor(sqrt(sqr(num))));
    5. str+=chr((num-(num mod 255))/255)
    6. str+=chr(num mod 255);
    7. return str;
    Alles anzeigen


    scr_decode_number:
    Verwandelt 2 Bytes in eine Nummer.

    GML-Quellcode

    1. var num,str;
    2. num=0;
    3. str=argument0;
    4. num+=255*ord(string_char_at(str,1));
    5. num+=ord(string_char_at(str,2));
    6. return num;


    scr_setup_secretfile:
    Erstellt eine neue, leere Secret-Speicherdatei.

    GML-Quellcode

    1. f=file_text_open_write(working_directory+"\unrat.dat");
    2. file_text_write_string(f,scr_encode_number(0));
    3. repeat(100)
    4. file_text_write_string(f,chr(0));
    5. file_text_close(f);


    scr_save_secrets:
    Speichert die Geldmenge und die Secrets in der Textdatei ab.

    GML-Quellcode

    1. if(!file_exists(working_directory+"\unrat.dat"))
    2. scr_setup_secretfile();
    3. var f,str,i;
    4. str=scr_encode_number(global.credits);
    5. for(i=0;i<100;i+=1)
    6. {
    7. str+=chr(floor(random(120)+1)*2+global.secret[i]);
    8. }
    9. f=file_text_open_write(working_directory+"\unrat.dat")
    10. file_text_write_string(f,str);
    11. file_text_close(f);
    Alles anzeigen


    scr_load_secrets:
    Lädt die Geldmenge und die Secrets ins Spiel.

    GML-Quellcode

    1. var str,f;
    2. if(!file_exists(working_directory+"\unrat.dat"))
    3. scr_setup_secretfile();
    4. f=file_text_open_read(working_directory+"\unrat.dat")
    5. str=file_text_read_string(f);
    6. file_text_close(f);
    7. str=string_copy(str,1,2);
    8. global.credits=scr_decode_number(str);
    9. for(i=0;i<100;i+=1)
    10. {
    11. global.secret[i]=scr_get_secret_load(i)
    12. }
    Alles anzeigen


    Ich hoffe, jemand kann mir helfen denn hier bin ich mit meinem Latein am Ende.
  • Ich seh den Fehler schon:

    Du musst überall statt 255 die Zahl 256 nehmen.
    Es ist zwar schon richtig, dass das letzte Element die 255 ist, weil das erste die 0 ist.
    Was zählt ist aber die Anzahl der Elemente und das sind 256.
    Deine Möglichkeit ginge zwar auch, aber du würdest nicht den kompletten Byte ausnutzen.

    EDIT:
    Außerdem solltest du die file_bin_ Funktionen nehmen, die für solche sachen gedacht sind, statt die für Textdateien.
    gm-d.de/help/410_01_files.html
    Bin mir aber nicht sicher, ob die file_text_ Funktionen dafür auch gehen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Bl@ckSp@rk ()

  • 255 sollte doch eigentlich in Ordnung sein, da ord() mit 0 anfängt.
    Ausserdem funktioniert das Zahlen-Umwandlungssystem einwandfrei.
    Ich habe alle mit diesem System möglichen zahlen, von 0-65279 (im Spiel ist die Maximalmenge des Geldes eh auf 60000 beschränkt) in einer for-schleife durchlaufen lassen und es ergab immer schön artig 2 bytes, die auch wieder in die entsprechende Zahl umgewandelt werden können.

    Bei den anderen 100 Bytes kam es mir auch nur darauf an, ob die im Char gespeicherte Zahl gerade oder ungerade ist, da nur die Werte 1 und 0 (Secret gesperrt/ freigeschatet) abgespeichert werden müssen (quasi so eine Art Verschlüsselung).

    Wie genau die file_bin_ Funktionen funktionieren weiss ich nicht. Damit habe ich bis jetzt nur Dateien kopiert.
    Ich schätze mal, die fressen keine Strings sondern nur 1 und 0, daher müsste ich das System dafür ja komplett umschreiben, was nicht gerade in meinem Sinne wäre ^^'
    Erst recht wo es doch eigentlich funktionieren *sollte*.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Verwurster ()

  • Wie genau die file_bin_ Funktionen funktionieren weiss ich nicht. Damit habe ich bis jetzt nur Dateien kopiert.
    Ich schätze mal, die fressen keine Strings sondern nur 1 und 0...


    Lies dir doch erst mal die beschreibung dazu durch. Dann wirst du feststellen, dass man ein ganzes Byte (256) reinschreiben kann. Musst halt nur jedes Byte einzeln schreiben und nicht den kompletten string.

    gm-d.de/help/410_01_files.html

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Bl@ckSp@rk ()

  • Hmm... ich persönlich würde die Bit operatoren hernehmen um eine zahl in 2 bytes zu zerlegen.

    GML-Quellcode

    1. num=min(65535,abs(num));
    2. byte[0] = num&$FF;
    3. byte[1] = (num>>8)&FF


    >> ist ein bitshift, sprich wenn die zahl vorher so aussieht (in binärschreibweise) 1111111100000000 werde die zahlen um 8 positionen verschoben und es entsteht 11111111. Das &$FF ist ein binäres und, welches mit 255 gemacht wird. Das heißt, es bleibt immer eine zahl zwischen 0 und 255 übrig.

    wenn du dann deine restlichen 100 bytes gefüllt hast, solltest du diese wirklich mit file_bin_write_byte(fileid,byte) reinschreiben, das geht dann auch ganz einfach:

    GML-Quellcode

    1. var i,FILE;
    2. if(file_exists('Filename.dat')) file_delete('Filename.dat');
    3. FILE = file_bin_open('Filename.dat',2);
    4. for(i = 0; i < 100; i+=1)
    5. {
    6. file_bin_write_byte(FILE,byte[i])
    7. }
    8. file_bin_close(FILE);
    ...

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Shoba ()

  • Also das mit dem num&FF hat gar nicht geklappt und auch nachdem ich das FF mit 255 ersetzt habe, hat's nur relativ willkürliche Zahlen die u.a. mehr als doppelt so gross wie 255 waren ausgespuckt.
    Mit Bit operatoren habe ich mich allerdings niemals auseinandergesetzt.
    Deshalb auch der etwas umständliche code um die Zahl umzuwandeln, aber er funktioniert.

    Ich werde jetzt mal versuchen, auf binärdateien umzusteigen.
    Wenn sich das Problem denn dadurch löst verstehe ich das zwar nicht was mir dann aber relativ egal ist. Hauptsache es funzt.
    Bleibt das 'Byteleck' weiterhin bestehen melde ich mich dann hier nochmal.

    edit: so hab's jetzt umgestellt und es funktioniert aber das heisst nichts.
    vorher hat es auch tagelang funktioniert bis auf einmal einfach falsch gespeichert wurde...

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Verwurster ()

  • Sorry, da war ein Tippfehler im Source. Es hätte in beiden fällen $FF heißen müssen. Das ist die hexadezimalschreibweise für 255. Also die genaue größe von einem Byte.

    Ich habs jetzt mal im GM ausprobiert, die ergebnisse stimmen eigentlich immer.

    GML-Quellcode

    1. num=min(65535,abs(num));
    2. byte[0] = num & $FF;
    3. byte[1] = (num>>8) & $FF
    ...
  • Ich benutze jetzt deine Methode mit 3 Bytes und das funktioniert tadellos.
    Jetzt will ich aber die restlichen 100 bytes ein wenig effizienter nutzen.
    In ein Byte passen ja 8 true/false Indikatoren oder einfach 1 und 0.
    Wie man jetzt eine Zahl in 8 Einsen und Nullen zerlegt habe ich schon rausgefunden, aber wie man z.b. 10000000 in 1 oder 01010000 in 10 umwandelt weiss ich nicht.
    Wie wandelt man 8 Einsen und Nullen in ein Byte um?
  • Benutzer online 1

    1 Besucher