• Hallo zusammen

    Ich würde gerne beim GeoLadder ein pausiertes Spiel nach dem Neustart von PC/GEOS fortsetzen können. Die Messages "MSG_GEN_PROCESS_OPEN_APPLICATION" und "MSG_GEN_PROCESS_CLOSE_APPLICATION" habe ich schon in Gebrauch.

    Zwei Datenbereiche überleben den Neustart noch nicht.

    1. Ein globales Struct mit Zustandsinformationen, aber auch einem Pointer auf den Levelbuffer

    Dieses könnte ich beim Herunterfahren in eine Instanz-Variable eines Objekts kopieren, welches im State gespeichert wird und beim Starten davon wieder laden. Macht das Sinn? Den Pointer auf den Levelbuffer muss ich sicher noch neu setzen.

    2. Den Levelbuffer:

    @chunk char GameLevelBuffer[] = "";

    Der Levelbuffer muss beim ersten Start vergrössert werden. Beim Speichern und Wiederherstellen aber seinen Inhalt behalten.

    Habt Ihr hierzu Tipps, welchen Weg am vernünftigsten / praktikabelsten ist? Hints zu Beispielen nehme ich sehr gerne an.

    Besten Dank schon einmal im Voraus!

  • Hi,

    schön von Dir mit Entwicklungsfragen zu lesen :)

    Zu 1.)

    Sieh mal hier:

    pcgeos/Appl/EduApps/Fontmgck/FONTM/fontm.goc at master · bluewaysw/pcgeos
    #FreeGEOS source codes. The offical home of the PC/GEOS operating system technology. For personal computing fans. For all developers and assembly lovers. For…
    github.com

    extraState ist das Konzept anstelle einer Instanzvariablen. Im CLOSE_APPLICATION extra block befüllen im OPEN_APPLICATION wieder herstellen.

    Zu 2.)

    Normalerweise sollt er den State von Object-Blocks selbst sicher und wiederherstellen. Kannst Du da noch mehr Kontext geben? Z.b. was ist das für ein Block?

    Viele Grüße, Falk

  • Hallo Falk

    Herzlichen Dank für Deine Antworten!

    Zu 1:
    Das mit dem extraState werde ich so versuchen. Fontmagick scheint den auch zu verwenden, um festzustellen, ob die Anwendung frisch gestartet wurde oder ob man aus dem State wiederhergestellt wird. Wie man das unterscheidet war mir auch noch nicht ganz klar.

    Zu 2:
    Ich habe eine Ressource:

    resource GAME lmem

    In dieser habe ich einen Chunk:

    @chunk char GameLevelBuffer[] = "";

    Der Chunk ist am Anfang leer und wird in der Methode MSG_GEN_PROCESS_OPEN_APPLICATION auf die benötigte Grösse erweitert:

    C
    MemLock(OptrToHandle(@GameLevelBuffer));
    LMemReAlloc(@GameLevelBuffer, LVL_M_SIZE);
    MemUnlock(OptrToHandle(@GameLevelBuffer));

    Dieser Chunk wird jeweils zu Beginn einer Runder (sprich Levels) mit den Leveldaten gefüllt. Während dem Spiel gibt aber Änderungen an den Daten. Einzelne Zeichen fallen Weg, bzw. werden mit einem Leerzeichen überschrieben. Darum muss ich den Inhalt dieses Buffers über einen Neustart hinweg behalten.

    Schönen Gruss
    Andreas

  • Cool, das mit extraState war mir nicht bewusst. Ich hätte einfach ne Datei genommen.

    Zu 2. M.E ist das ja kein Objektblock. Kannst du den Inhalt nicht auch nach extraState kopieren?

    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Ich hab nochmal im Kernel geschaut. Nur LMEM-Blöcke die als DETACHABLE markiert sind, werde im State-File gespeichert. Da DETACHABLE Flag wird durch die Tools nur für Object-Blöcke gesetzt. Du könntest versuchen zu Laufzeit zu setzen oder einfach object anstellen lmem im gp-File verwenden.

    Falk \\ blueway.Softworks

  • Du könntest versuchen ..... einfach object anstellen lmem im gp-File verwenden.

    Damit dürftest du dir eine swat warnung beim Locken des Blocks (CANNOT_CALL_MEMLOCK_ON_OBJ_BLOCK) einhandeln. Ist zwar in dem Fall kein Problem, aber ich würde das vermeiden (so sie denn tatsächlich kommt).

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Das mit den attachFlags funktioniert tadellos. Ich kann ohne Probleme in der OPEN Message das verwenden:

    Code
    if (attachFlags & AAF_RESTORING_FROM_STATE)
    {
       @send process::MSG_LAD_ABC();
    }
    else
    {
       @send process::MSG_LAD_XYZ();
    }

    Ich habe dann das äquivalente für die CLOSE Message gesucht. Habe da aber nichts verwertbares gefunden. Auch im Fontmagic wird einfach nur der State gesichert. Bedeutet das, dass die CLOSE Message beim normalen Beenden der Anwendung gar nicht aufgerufen wird?

  • Wenn ich das richtig verstanden habe, könntest Du bei jedem „Close“ den State speichern?!

    So scheint es im Moment zu funktionieren, wenn die CLOSE Message immer aufgerufen wird und ich keine Möglichkeit zum Untershceiden finde, ob nun die Anwendung selbst beendet wird oder ob das System herunterfährt. Das würde ich gerne vermeiden...

  • Junge, junge! Lange nichts mehr mit dem SDK programmiert, da R-Basic so schön bequem ist. Aber das mit den State-Files beim Beenden klingt extrem kompliziert:

    … If a MSG_META_DETACH is used without MSG_META_QUIT, the application will create a state file. … There is no special shutdown message for shutting down to a state file; instead, MSG_GEN_PROCESS_CLOSE_APPLICATION is used.
    When the system shuts down or task-switches, a different type of shutdown occurs. Applications (or other objects interested in this event) must register for notification on the notification list GCNSLT_SHUTDOWN_CONTROL (notification lists are described in "General Change Notification," Chapter 9). When the system shuts down or task-switches, the object will then receive a MSG_META_CONFIRM_SHUTDOWN, at which time the object must call SysShutdown().

    There are two rules in life:
    1. Never give out all of the information.

  • Ich habe einmal an Tests bezüglich "extraState" gemacht und dazu einfach etwas Code geklaut. In der CLOSE Message sieht es nun so aus:

    Code
     Globals *globals;
     MemHandle mh;
     mh = MemAlloc(sizeof(Globals), HF_DYNAMIC | HF_SHARABLE, 0);
     globals = (Globals *) MemLock(mh);
     *globals = g;
     MemUnlock(mh);
     return mh;

    Dann wollte ich das umbauen, um mit "memcpy()" arbeiten zu können. Dies ist bis jetzt kläglich gescheitert. Der Hintergrund ist, dass ich auch noch den LevelBuffer im "extraState" bringen möchte. Dieser ist ein Chunk. Das wiederum könnte mit LMem gehen. Aber ein Struct und ein Chunk zusammen in den "extraState" macht mir noch Kopfzerbrechen...

  • Junge, junge! Lange nichts mehr mit dem SDK programmiert, da R-Basic so schön bequem ist. Aber das mit den State-Files beim Beenden klingt extrem kompliziert:

    … If a MSG_META_DETACH is used without MSG_META_QUIT, the application will create a state file. … There is no special shutdown message for shutting down to a state file; instead, MSG_GEN_PROCESS_CLOSE_APPLICATION is used.
    When the system shuts down or task-switches, a different type of shutdown occurs. Applications (or other objects interested in this event) must register for notification on the notification list GCNSLT_SHUTDOWN_CONTROL (notification lists are described in "General Change Notification," Chapter 9). When the system shuts down or task-switches, the object will then receive a MSG_META_CONFIRM_SHUTDOWN, at which time the object must call SysShutdown().

    Da verstehe ich, dass das wohl die wenigsten gemacht haben... Sich auf eine GCN setzten mit entsprechender Message und dann noch denn weiteren Shutdown sicherstellen... Hab das auch mal gesehen, mit Begründung Print-Spooler oder Downloads...

  • Der Hintergrund ist, dass ich auch noch den LevelBuffer im "extraState" bringen möchte.

    Ich würde so vorgehen:

    1. Definition einer Struktur, die alle Daten enthält, die du in extraState unterbringen willst. Dein LevelBuffer ist wohl ein char[] oder byte[] array. Also musst du ein entsprechendes Feld in der Struktur vorsehen, dass so groß ist, dass es den LevelBuffer in jedem Fall aufnehmen kann. Wenn der Levelbuffer unterschiedlich groß sein kann, dann brauchst du noch eine word, das sagt, wie groß der buffer ist.

    Code
    typdef struct {
    word levBuffSize;
    char  levelBuffer[max_level_buffer_size];
    Globals  savedGlobals;
    .....
    } ExtraStateStruct;

    2. Alloc ein Memblock von sizeof(ExtraStateStruct) und einen Pointer drauf besorgen

    3. Alle benötigten Daten in den Block kopieren. beim LevelBuffer z.b. mit

    Code
    memcpy(ptr->levelBuffer, LMemDeref(@GameLevelBuffer)) , num_bytes_to_copy)

    bei savedGlobals z.B. mit

    Code
    ptr->savedGlobals = g;  <-- wenn deine globale Strukturvariable g heißt.

    4. MemUnlock(mh), return mh;

    Beim Restart der App kopierts du die Daten aus dem ExtraState Block auf die gleiche Weise zurück.

    Dass man beim Herunterfahren nicht (oder nur mit Klimzügen) weiß, ab es ein App-Exit oder ein GEOS Shutdwon ist, ist nicht schön aber letztlich wurscht. Du speicherst deinen Status. Fertig. Wenn es ein App-Exit war, dann wird beim nächsten Öffnen der App das RESTORE_FORM_SATE Bit nicht gesetzt sein und du ignorierst den gespeicherten Status. Das ist genauso, als hättest du gar keinen gespeichert.

    Rainer

    Es gibt 10 Arten von Menschen - die einen wissen was binär ist, die anderen nicht.

  • Halloe Rainer

    Perfekt! Du hast mich wieder einmal entscheidend weitergebracht. Das Ganze nochmals in eine Struktur zu packen funktioniert wie gewünscht, sehr fein!

    So ein "detachedFlags" bei der CLOSE Methode wäre trotzdem schön. Im Moment ist es aber wie es ist. Trotzdem kann man das vielleicht in einer zukünftigen Version entsprechend implementieren. Apps die davon wissen, können es brauchen. Für alle Anderen sollte sich nichts ändern...

    Lieben Gruss
    Andreas

  • Mir ist noch aufgefallen, dass meiner Objekte, welche Zahlen auf dem Screen anzeigen, nach dem Wiederherstellen aus dem State den Standardwert anstatt den aktuellen Wert anzeigen. Sprich, der geänderte Inhalt der Instanzvariable scheint nicht im State erhalten zu bleiben. Muss ich das Objekt irgendwie Dirty setzen und geht das nicht automatisch?

    Die Definition sieht folgendermassen aus:

    Es geht im die Instanzvariable LVI_value welche über die Methode MSG_VAL_SET_VALUE oder MSG_VAL_UPDATE_VALUE geändert wird. (SET setzt den Wert während UPDATE auch ein Neuzeichnen auslöst)

    Weiter merkt sich die View ihren geänderten Mauszeiger nicht über einen Neustart.

    Scheint, dass ich da noch etwas komplett übersehen habe...