Hallo Besucher, der Thread wurde 5k mal aufgerufen und enthält 37 Antworten

letzter Beitrag von ThomBraxton am

Editor für Relative Dateien

  • Im Rahmen eines Adventures will ich Texte auslagern in einer Relative Datei, da man die schön schnell anspringen kann. Nun habe ich keine Lust die Relative Datei im Emulator anzulegen. Da muss es doch im Rahmen von Cross Development eine bessere Lösung/Editor geben.
    Vielleicht hat ja jemand noch eine andere Idee zum Auslagern der Texte. Da die Recordgröße bei Relativen Dateien auf 256 Bytes begrenzt ist. Und manchmal ist das auch Platzverschwendung.

  • Nun habe ich keine Lust die Relative Datei im Emulator anzulegen.

    Ich geh davon aus, dass du damit einschließlich der Texte verfassen meinst, richtig?


    Ich würde das einfach in eine .txt-Datei schreiben, kleines BASIC-Programm basteln, .txt-Datei irgendwo in den Emu-Speicher laden und dann halt daraus die REL-Datei schreiben. Ggf. dabei halt noch die Groß-/Kleinschreibung wandeln. Evtl. müsste man sich ein Trennzeichen suchen, falls ein einzelnes CR/LF nicht reicht bzw. CHR$(13) im Text benötigt wird.


    Hoffe ich hatte dich richtig verstanden.

  • Während der Entwicklung könnte man sich mit Einzeldateien behelfen, also "data0123.txt" als Datei mit dem Text für Raum Nummer 123. Wenn das Spiel dann fertig ist, konvertiert man die Einzeldateien in eine große REL-Datei (oder Direktzugriffsblöcke oder whatever) und tauscht die Zugriffsfunktion aus.

  • Wenn Du wirklich ein schnelles Laden der Texte haben möchtest, ist ein direkter Sektorzugriff die beste Wahl, entweder mittels blockread bzw. unitread oder mit Hilfe eines Schnelladers. Das Laden der Daten aus einer REL-Datei (oder generell über das Dateisystem der 1541) ist sehr langsam. Es gibt aber noch einen Grund, warum man einen Direktzugriff verwenden sollte: Man kann dann in dem verbleibenden freien Speicher des C64 einen Sektorcache anlegen, der beim Spielen dafür sorgt, daß weniger nachgeladen werden muß. Die beste Beschleunigung von Diskettenzugriffen ist immer noch, nicht auf Diskette zuzugreifen.


    Die Vorgehensweise könnte folgendermaßen aussehen:
    1.) Schreibe die Texte mit einem einfachen Texteditor. Kopiere anschließend die Texte mit einem kleinen Hilfsprogramm in ein (leeres) Diskettenimage angefangen bei Track 1 Sektor 0. Merke Dir dabei jeweils den Anfangsindex des Textes bezogen auf das DIskimage.
    2.) Diese Indizes sind nichts anderes als 24-Bit-Adressen Deiner Texte. (Sofern Deine Textmenge > 64kb ist. Ansonsten würden dafür natürlich auch 16 Bit reichen.) Lege dafür im Speicher des C64 eine Tabelle an. Die Tabelle kannst Du entweder von dem Hilfsprogramm gleich automatisch miterzeugen lassen zum Einbau in Dein Adventure oder Du definierst Dir einen gesonderten Sektor, in dem Du die Anfangsadressen speicherst. Diesen Sektor lädst Du zu Beginn des Adventures und packst die darin enthaltenen Adressen in die Tabelle.
    3.) Soll das Adventure jetzt einen Text ausgeben, holst Du Dir die Anfangsadresse aus der Tabelle und rufst damit die Routine "sektor_setzen" auf. Diese Routine lädt den Sektor, der zu dieser Adresse paßt, in den Speicher und setzt intern einen Zeiger auf den Anfang des Textes.
    4.) Nun kann man den Text Byte für Byte mit einer Routine "byte_holen" auslesen. In dieser Routine wird ein Byte aus dem Sektorspeicher im C64 geholt und anschließend der interne Zeiger erhöht. Tritt dabei ein Überlauf des unteren Bytes des Zeigers auf, wird die gesamte Adresse (24 oder 16) um 256 erhöht und erneut die Routine "sektor_setzen" aufgerufen, die den Folgesektor in den Speicher lädt.
    5.) Die Routine "sektor_setzen" läßt sich dann gut dazu gebrauchen, den erwähnten DIskcache im Speicher einzurichten nach dem LRU-Prinzip, so daß bei einem erneuten Zugriff auf den gleichen Text oder dem Zugriff auf einen Text in der Nähe des vorgehenden nicht wieder von Diskette geladen werden muß.


    Das Verfahren mag sich ein wenig umständlich anhören, ist aber tatsächlich gar nicht so kompliziert und wirkt sich später deutlich spürbar beim Spielen aus. (Gegenbeispiel: "Mit Jeans und Hellebarde". Bei diesem Spiel wird andauernd von Diskette nachgeladen, was ohne Emulator schnell zu längeren Kaffeepausen führt.)

  • Noch einen kleinen Nachtrag:
    1.) Achte bei der Definition Deines Textformats darauf, auch Kommentare einfügen zu können, die dann von dem Hilfsprogramm übersprungen werden, z. B. indem ein ";" oder "//" am Anfang einer Zeile eine Kommentarzeile einleitet. Das könnte beim Erstellen und Verwalten der Texte hilfreich sein:
    // Antwort auf "Lies Buch"
    Darin findest Du nur einen Haufen uninteressanten Mülls.
    // Ortsbeschreibung des Kellers im dunklen Turm
    ...
    2.) Falls Dir die Vorstellung eines direkten Zugriffs auf Sektoren nicht zusagt, weil Du z. B. planst, Dein Spiel später auch von einer d81 zu starten oder es auf ein anderes System wie den CPC zu portieren, kannst Du auch so vorgehen, daß Du mit Hilfe des Dateisystems eigene "Sektoren" in Form von durchnumerierten Dateien erschaffst, idealerweise dann größer als 256 Bytes. So wäre es möglich, den gesamten Text in Teile von jeweils 4 KB zu unterteilen, die einzeln als Dateien "0", "1", "2" usw. auf der Diskette abgelegt werden. Das Verfahren wäre identisch, nur daß halt der "Sektor"puffer nicht 256 Bytes groß wäre, sondern eben 4 KB. Bei einem Überlauf würde dann die Folgedatei mit der nächsthöheren Nummer geladen werden.
    3.) Wenn Du die Textdatei mit Hilfe eines kleinen Programms konvertierst, kannst Du diesen Schritt auch dafür benutzen, um den Text zu packen. Das spart nicht nur Platz, sondern auch Ladezeit. Eine sehr simple, aber trotzdem schon recht effiziente Möglichkeit, einen Text zu komprimieren, sieht wie folgt aus:
    a) Suche Dir aus der Gesamtmenge Deines Textes die am meisten verwendeten 15 Zeichen (inklusive CR und NULL '\0') heraus und speichere sie in einer Tabelle. Diese 15 Zeichen kannst Du jetzt mit nur 4 Bits kodieren.
    b) Für die übrigen Zeichen definierst Du Dir einen Escapecode (idealerweise 4 Nullbits) gefolgt von 8 Bit Deines eigentlichen Zeichens.
    c) Wenn Du den Text entpacken willst, rufst Du eine Routine auf "4_bits_holen". In dieser Routine muß lediglich festgehalten werden, ob die oberen oder unteren 4 Bits an der Reihe sind. In Pseudocode (ungetestet):

    Falls Du Dein Adventure in Assembler schreibst bzw. Assemblerroutinen in BASIC einbauen kannst, wäre die Routine recht kurz und schnell, sollte aber auch in BASIC funktionieren. In BASIC wäre das Entpacken zwar etwas langsam, aber immer noch schneller als ein längerer Diskettenzugriff.

  • @M. J. Hört sich interessant an. Ich habe aber noch ein paar Fragen:
    1) Jeder Block den ich über Spur und Sektor anspreche umfasst ja 256 Bytes. Ein Satz der z.B. weniger Zeichen umfasst würde trotzdem einenen ganzen Block beanspruchen. Das wäre dann ziemliche Platzverschwendung. Oder übersehe ich was?
    2) Wenn ich Blockread nutze, muss ich ja wissen in welcher Spur/Sektor der Text den ich ausgeben will steht. Dass heisst die Position der Datei auf der Diskette darf sich nicht ändern, da ja sonst die Angaben zu Spur und Sektor nicht mehr passen. Richtig? Da ich das Image der Diskette aber automatisch nach dem Compilieren im "Post Build" Prozess mit dem C64 Studio erstelle, kann ich nicht sicher sein, dass die Datei genau bei Track 1 Sektor 0 anfängt. Für den Entwicklungsprozess eigenet sich das irgendwie nicht gut. Oder übersehe ich was?


    Viele Dank an alle für eure Mithilfe.

  • Jeder Block den ich über Spur und Sektor anspreche umfasst ja 256 Bytes. Ein Satz der z.B. weniger Zeichen umfasst würde trotzdem einenen ganzen Block beanspruchen. Das wäre dann ziemliche Platzverschwendung.

    Die Texte liegen direkt nacheinander auf der Diskette. Die Anfgangsposition des jeweiligenTextes hälst Du in der Tabelle fest. Damit geht kein Speicherplatz verloren.
    Stell Dir Deinen Text vor als eine Art eigenes großes Textspeicherimage. Für dieses Textspeicherimage kreierst Du Dir eine Art Fenster, den Sektorpuffer im C64-Speicher, mit dessen Hilfe Du Dir im laufenden Spiel jeweils einen kleinen Ausschnitt daraus angucken kannst. Im Grunde genommen ist es wie bei einer MMU: Stößt das Programm auf eine Adresse Deines Textspeicherimages, dessen Inhalt nicht im C64-Speicher vorhanden ist, wird der alte Puffer für ungültig erklärt und dann mit neuen Daten aus dem Textspeicherimage geladen.
    Dafür ist es auch irrelevant, wo dieses Textspeicherimage auf Diskette beginnt. Es könnte auch erst bei Track 15 Sektor 7 sein. Es ist allein für die Umrechnung von Speicheradresse auf Diskettenposition günstiger, wenn das Speicherimage bei Track 0 Sektor 1 anfängt. Einzig wichtig beim Direktzugriff ist, daß sehr einfach ermittelt werden kann, wo sich der Folgeblock befindet, und das bedeutet beim Direktzugriff eben, daß man lediglich den Sektorzähler (und eventuell den Trackzähler) um eins erhöhen muß.

    Für den Entwicklungsprozess eigenet sich das irgendwie nicht gut.

    Für diesen Fall würde ich vorschlagen, den zweiten Weg zu gehen und das Textspeicherimage in kleine Dateien mit fester Größe einzuteilen, die dann als Fenster dienen können.

  • 1) Jeder Block den ich über Spur und Sektor anspreche umfasst ja 256 Bytes. Ein Satz der z.B. weniger Zeichen umfasst würde trotzdem einenen ganzen Block beanspruchen. Das wäre dann ziemliche Platzverschwendung. Oder übersehe ich was?

    Du sollst ja nicht nur einen Satz pro Datei speichern. Du beendest ein Satz mit einem von Dir gewählten Trennzeichen (beispielsweise ein Return chr$(13)).
    Das heißt mehrere Sätze stehen hintereinander. Jetzt kannst Du z.B. entweder aus Datei 003 den Satz ab Position 27 auslesen (bis zum Trennzeichen) oder aus Datei 003 den zweiten Datensatz (also nach dem ersten Trennzeichen).


    Zu 2.)
    Kannst Du für den Entwicklungsprozess als Datenquelle nicht Laufwerk 9 benutzen und da bleiben die Daten ja unverändert. Wenn es fertig ist, kopierst Du die entsprechenden Programmdateien auf die Datendiskette.


    EDIT:
    Komisch, solange habe ich gar nicht geschrieben, aber der Eintrag von M. J. war eben noch nicht da... (wenn das mein Arzt wüsste...)


    EDIT2:
    M. J. ,Zur Komprimierungsgeschichte: D.h. ich benötige 12 Bits für die anderen Zeichen? Wie stark wird das dabei etwa komprimiert?

  • Zu 2.)
    Kannst Du für den Entwicklungsprozess als Datenquelle nicht Laufwerk 9 benutzen und da bleiben die Daten ja unverändert. Wenn es fertig ist, kopierst Du die entsprechenden Programmdateien auf die Datendiskette.

    Habe ich auch schon im C64 Studio Thread vorgeschlagen. Ich weiss nicht, wieso man sich das nicht einfach macht. Das ist eh nur während der Entwicklung im VICE nötig. In der Endfassung landet alles auf einem D64/Diskette.

  • Wie stark wird das dabei etwa komprimiert?

    Gute Frage... Ist leider schon eine Weile her, daß ich mit Textkomprimierung experimentiert habe. Das letzte Mal bei Claus' Compo, glaube ich. Wenn ich mich recht erinnere, spart man je nach Text so um ein Drittel ein, also aus 100% werden dann ca. 66%. Es kann aber auch ein wenig darunter oder darüber liegen. Das liegt daran, daß die Zeichen in der Sprache sehr ungleich verteilt sind. Vokale kommen viel häufiger vor als Konsonanten, und unter letzteren wiederum einige weitaus häufiger als andere ("x", "y", "q" usw.). Wichtig ist, daß man die Tabelle für jeden Text neu anpaßt, indem man die Zeichen durchzählt und beim Zählen auch wirklich alle Zeichen (inklusive CR und Textende) berücksichtigt. Will man mehr einsparen, muß man auf kompliziertere Methoden zurückgreifen, z. B. indem man das Parservokabular als Wörterbuch mit einbezieht oder ein Format entwickelt, bei dem angehängte Leerzeichen gesondert gekennzeichnet werden etc. Das (oder auch Huffman) ist für BASIC aber zu aufwendig. Daher mein Vorschlag dieser einfachen Methode.

  • Habe ich auch schon im C64 Studio Thread vorgeschlagen. Ich weiss nicht, wieso man sich das nicht einfach macht. Das ist eh nur während der Entwicklung im VICE nötig. In der Endfassung landet alles auf einem D64/Diskette.

    Ja, habe ich gelesen und die Idee ist gut. Nur leider funkioniert die Parameterübergabe im C64 Studio nicht so einfach. Das hat selbst Endurion gesagt. Bestimmte Parameter wie truedrive können eingestellt werden. Aber das einlegen eines Image in ein bestimmtes Laufwerk gehört nicht dazu.

  • 1) Angenomme ich nutze Blockread. Dann muss ich ja wissen in welchem Track/Sektor der Textteil der Datei auf der Diskette liegt. Um den zu kalkulieren, muss ich wissen, bei welchem Track/Sektor die Datei anfängt. Wie kriege ich das zur Laufzeit raus. BAM auslesen?
    2) Wie zwinge ich eine Datei, dass sie bei Track 1 Sektor 0 anfängt? Kann ich dafür DirMaster nutzen?

  • Gute Frage... Ist leider schon eine Weile her, daß ich mit Textkomprimierung experimentiert habe. Das letzte Mal bei Claus' Compo, glaube ich. Wenn ich mich recht erinnere, spart man je nach Text so um ein Drittel ein, also aus 100% werden dann ca. 66%. Es kann aber auch ein wenig darunter oder darüber liegen. Das liegt daran, daß die Zeichen in der Sprache sehr ungleich verteilt sind. Vokale kommen viel häufiger vor als Konsonanten, und unter letzteren wiederum einige weitaus häufiger als andere ("x", "y", "q" usw.). Wichtig ist, daß man die Tabelle für jeden Text neu anpaßt, indem man die Zeichen durchzählt und beim Zählen auch wirklich alle Zeichen (inklusive CR und Textende) berücksichtigt. Will man mehr einsparen, muß man auf kompliziertere Methoden zurückgreifen, z. B. indem man das Parservokabular als Wörterbuch mit einbezieht oder ein Format entwickelt, bei dem angehängte Leerzeichen gesondert gekennzeichnet werden etc. Das (oder auch Huffman) ist für BASIC aber zu aufwendig. Daher mein Vorschlag dieser einfachen Methode.

    Achja, da gab es mal eine Compo. Wollte ich mir irgendwann mal durchgucken.


    Interessant ist hier, dass es wirklich relativ einfach ist. Und vermutlich erziehlt man schon eine relativ gute Komprimierung, wenn man die üblichen Verdächtigen verwendet (Vokale, Leerzeichen...).
    Ich hatte mal die Überlegung häufig vorkommende Buchstabenkombinationen gesondert zu listen, aber vermutlich kommen die seltener vor und bringen dann nicht so viel.
    Macht es hier nicht dann eher Sinn z.B. als erstes Bit nur 0 für Standardzeichen, 1 für Listenzeichen zu verwenden und dann gefolgt von 4 oder 8 Bits... klar, so wird die "Zeichenkette" sehr wirr, aber man spart pro Standardzeichen nochmal 3 Bit. Ok, ich werde zu sehr OT.


    Aber zu dem Verschlüsselungsvorschlag allgemein: Werden denn überhaupt für diese Texte alle 256 Bytes benötigt? Oder kann man evtl. schon mit den ersten 128 auskommen (z.B. den Bildschirmcodes entsprechend).


    Ja, habe ich gelesen und die Idee ist gut. Nur leider funkioniert die Parameterübergabe im C64 Studio nicht so einfach. Das hat selbst Endurion gesagt. Bestimmte Parameter wie truedrive können eingestellt werden. Aber das einlegen eines Image in ein bestimmtes Laufwerk gehört nicht dazu.

    Wenn Du Vice startest, Laufwerk 9 festlegst und die Einstellungen beim beenden speicherst, sollte das doch klappen, oder? Nehme doch an, dass c64 Studio nur Laufwerk 8 einstellt.
    (Wie öffnet man direkt aus C64 Studio in Vice? Klappt bei mir gar nicht)

  • Ja, habe ich gelesen und die Idee ist gut. Nur leider funkioniert die Parameterübergabe im C64 Studio nicht so einfach. Das hat selbst Endurion gesagt. Bestimmte Parameter wie truedrive können eingestellt werden. Aber das einlegen eines Image in ein bestimmtes Laufwerk gehört nicht dazu.

    Das müsste doch indirekt gehen: Statt x64.exe direkt als Parameter im C64Studio aufrufen, rufst Du eine Batchdatei, welches die D64 Disks einlegt mit dem x64.exe gestartet wird.
    Hab's nicht ausprobiert, aber ich sehe gerade nicht, wieso das nicht funktionieren sollte. Ob Du ein EXE oder Batchfile aufrufst müsste C64Studio ja wurscht sein.

  • 1) Angenomme ich nutze Blockread. Dann muss ich ja wissen in welchem Track/Sektor der Textteil der Datei auf der Diskette liegt. Um den zu kalkulieren, muss ich wissen, bei welchem Track/Sektor die Datei anfängt.

    Nein, entweder Du verwendest Sektoren als Fenster in Dein Textimage und umgehst mit Blockread das Dateisystem vollständig (keine Dateien mehr) oder Du spaltest Dein Textimage auf in einzelne Dateien, die Du dann komplett lädst.

    Wie zwinge ich eine Datei, dass sie bei Track 1 Sektor 0 anfängt?

    Sobald Du Disketten mit Blockread ansprichst, gibt es kein Dateisystem mehr. Im Grunde genommen kreierst Du Dir ein eigenes Dateisystem, und die Tabelle mit den Positionen der Texte auf Diskette ist Dein Inhaltsverzeichnis.


    Macht es hier nicht dann eher Sinn z.B. als erstes Bit nur 0 für Standardzeichen, 1 für Listenzeichen zu verwenden und dann gefolgt von 4 oder 8 Bits... klar, so wird die "Zeichenkette" sehr wirr, aber man spart pro Standardzeichen nochmal 3 Bit.

    Sowas hatte ich damals bei Claus' Vorgabetext probiert, aber das Ergebnis war dann doch eher ernüchternd. Oft schnitten diese Verfahren schlechter ab, da die wirklich häufigen Fälle nun mit 5 anstelle von 4 Bits codiert werden mußten. Die Menge der nicht-häufigen Zeichen ist zu klein und zu unregelmäßig, als daß eine Codierung zu Lasten der häufigen Zeichen eine Ersparnis bringen könnte.

    Ich hatte mal die Überlegung häufig vorkommende Buchstabenkombinationen gesondert zu listen, aber vermutlich kommen die seltener vor und bringen dann nicht so viel.

    Sofern Du nur einfache Buchstabenkombinationen kodierst, bringt es noch nicht so viel. Interessant wird es, wenn man den Algorithmus rekursiv verwendet (vgl. BPE (Byte Pair Encoding)). Hierbei kann man tatsächlich besonders bei großen Texten sehr gute Kompressionsraten erhalten, da hier nicht nur Buchstabenkombinationen, sondern im Ergebnis auch ganze Silben oder Wörter gepackt werden. Jedoch ist die Komprimierung etwas aufwendig, und für das Entpacken benötigt man die Möglichkeit einer Rekursion, was in BASIC nicht ohne weiteres möglich ist.


    Edit: Grrr... Tipfehler... Grrr...

  • Sobald Du Disketten mit Blockread ansprichst, gibt es ein Dateisystem mehr. Im Grunde genommen kreierst Du Dir ein eigenes Dateisystem, und die Tabelle mit den Positionen der Texte auf Diskette ist Dein Inhaltsverzeichnis.

    Gar nicht? Kann ich nicht die entsprechenden Blocks in der BAM als belegt kennzeichnen und den Rest der Disk wie gewohnt nutzen?

    Sowas hatte ich damals bei Claus' Vorgabetext probiert, aber das Ergebnis war dann doch eher ernüchternd. Oft schnitten diese Verfahren schlechter ab, da die wirklich häufigen Fälle nun mit 5 anstelle von 4 Bits codiert werden mußten. Die Menge der nicht-häufigen Zeichen ist zu klein und zu unregelmäßig, als daß eine Codierung zu Lasten der häufigen Zeichen eine Ersparnis bringen könnte.

    Das leuchtet mir ein... reden wir hier von dieser ASM-Compo #3: Text Compression Compo? Ich dachte da gab es auch was in Basic...



    Sofern Du nur einfache Buchstabenkombinationen kodierst, bringt es noch nicht so viel. Interessant wird es, wenn man den Algorithus rekursiv verwendet (vgl. BPE (Byte Pair Encoding)). Hierbei kann man tatsächlich besonders bei großen Texten sehr gute Kompressionsraten erhalten, da hier nicht nur Buchstabenkombinationen, sondern im Ergebnis auch ganze Silben oder Wörter gepackt werden. Jedoch ist die Komprimierung etwas aufwendig, und für das Entpacken benötigt man die Möglichkeit einer Rekursion, was in BASIC nicht ohne weiteres möglich ist.

    Wäre trotzdem ein Versuch Wert... muss ich hier nochmal in Ruhe angucken.

  • Wenn Du Vice startest, Laufwerk 9 festlegst und die Einstellungen beim beenden speicherst, sollte das doch klappen, oder? Nehme doch an, dass c64 Studio nur Laufwerk 8 einstellt.
    (Wie öffnet man direkt aus C64 Studio in Vice? Klappt bei mir gar nicht

    Nein. Die Einstellungen werden nicht genutzt. Aber ich habe eine Lösung gefunden, um in Laufwerk 9 eine Diskette beim Start einzulegen. Ist blau markiert.


    Sobald Du Disketten mit Blockread ansprichst, gibt es ein Dateisystem mehr. Im Grunde genommen kreierst Du Dir ein eigenes Dateisystem, und die Tabelle mit den Positionen der Texte auf Diskette ist Dein Inhaltsverzeichnis.

    :honk: Klar. Ich habe total auf dem Schlauch gestanden.


    Bleibt trotzdem die Frage, wie ich das Textimage -jenseits vom Emulator -auf eine bestimmte Blockposition zwinge. Klar kann ich mir ein C64-Programm kloppen, dass das mit Blockwrite im Emulator macht. Aber schöner wäre es, wenn das z.B. mit DirMaster gehen könnte.