News:

The forum has been updated to SMF (2.1.3)!
Please be patient as we work to polish up the place and update features as we can.

Main Menu

A new Golden Sun Editor

Started by Ryudo, 10, April, 2020, 04:57:08 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Ryudo

Hi everyone,

I'm currently working on my own Golden Sun Editor (since i'm on a Mac, i can't use the Atrius' editor and GSMagic).

I don't pretend that my editor will be better but it will ll be compatible with most OS as it is develop with React (javascript), so compatible with any web browser.

It is Open Source and i'll post later the link to my repository on GitHub when the project will be more advanced.

I keep you informed  :happy:

GitHub repository: https://github.com/RyudoSynbios/golden-sun-editor
[2020-04-22] Golden Sun Editor v1.0.0-alpha.4

> Once downloaded, just extract and open the file index.html on any browser)

IMPORTANT: Make a backup of your rom :!:

Daddy Poi's Oily Gorillas

That's great.
I'm not sure how well those run if you use WINE, but it might be an option.
I am happy to see someone besides me working on anything Editor related! So keep up the good work. And prepare for the huge challenge that it probably brings.
A Javascript version?  Can't wait to see it.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo

Thanks Daddy Poi, i tried WINE but didn't work, maybe because i'm on Catalina.
The first challenge was the text decryption (not brute force, true decoding),  guess the next will be the graphism decryption :happy:

Daddy Poi's Oily Gorillas

#3
Aw. That's unfortunate.
Hm. Well. At least you figured out.
I have three versions of decompression routines for text myself. (All of which decompress all strings at once.)
Oh yeah, and all this is C#.
The main thing is that I don't account for char IDs of 0x100+. (GS2 (U) version does not have any chars from 0x100+ anyway.)

[spoiler=Offset Tree (My favorite one)]        static public byte[] decompText(byte[] src)
        { //, int srcInd) { // int srcPos) {
            //return decompTextOld2(src);
            int total = 0; int total2 = 0;
            DateTime c = DateTime.Now;
            //Scan char data to generate data for faster decompression than old method.
            int asmpchar = Bits.getInt32(src, 0x38578) - 0x8000000;
            int asmptext = Bits.getInt32(src, 0x385DC) - 0x8000000;
            int chardata = Bits.getInt32(src, asmpchar) - 0x08000000;
            int charpntrs = Bits.getInt32(src, asmpchar + 4) - 0x08000000;

            //Do a pre-scan of char tables to determine array sizes.
            int maxLetter = 0;
            int cTreeSize = 0;
            int maxDepth = 0;
            for (int char1 = 0; char1 <= maxLetter; char1++)
            {
                if ((char1 & 0xFF) == 0)
                {
                    chardata = Bits.getInt32(src, asmpchar + (char1 >> 8) * 8) - 0x08000000;
                    charpntrs = Bits.getInt32(src, asmpchar + (char1 >> 8) * 8 + 4) - 0x08000000;
                }
                //if (charpntrs == asmpchar) { break; }
                if (Bits.getInt16(src, charpntrs) == 0x8000) { charpntrs += 2; continue; }
                total2 += 1;
                int charTree = (chardata + Bits.getInt16(src, charpntrs)) << 3; charpntrs += 2;
                int charSlot = charTree - 12;
                int depth = 0;
                while (true)
                {
                    while (((src[charTree >> 3] >> (charTree++ & 7)) & 1) == 0) { depth++; cTreeSize++; }
                    int letter = ((Bits.getInt16(src, charSlot >> 3) >> (charSlot & 7)) & 0xFFF); charSlot -= 12; total += 1;
                    cTreeSize++;
                    if (letter > maxLetter) { maxLetter = letter; }
                    if (depth > maxDepth) { maxDepth = depth; }
                    //if ((char1 == 0) && (letter == 7))
                    //    Console.WriteLine("0-7 depth: " + depth);
                    if (depth <= 0) break;
                    --depth;
                } //while (depth > 0);
            }
            //Console.WriteLine("Total letter combos: " + total + "  \nTotal unique letters: " + total2 + "\nMax letter: " + maxLetter + "\nMax depth: " + maxDepth + "\ncTreeSize: " + cTreeSize);
 
            chardata = Bits.getInt32(src, asmpchar) - 0x08000000;
            charpntrs = Bits.getInt32(src, asmpchar + 4) - 0x08000000;
            int[] ctOffsets = new int[maxLetter + 1];// 0x1000];
            int[] cTree = new int[cTreeSize];// 0x10000];
            int[] nodeOffsets = new int[maxDepth]; //0x100]; //For temp use as we label leaves first, and iterate backwards.
            //int[] ctOffsets = new int[0x1000];
            //int[] cTree = new int[0x10000];
            //int[] nodeOffsets = new int[0x100]; //For temp use as we label leaves first, and iterate backwards.
            //int depth = 0;
            int pos = 0;
            for (int char1 = 0; char1 <= maxLetter; char1++)
            {
                if ((char1 & 0xFF) == 0)
                {
                    chardata = Bits.getInt32(src, asmpchar + (char1 >> 8) * 8) - 0x08000000;
                    charpntrs = Bits.getInt32(src, asmpchar + (char1 >> 8) * 8 + 4) - 0x08000000;
                }
                //if (charpntrs == asmpchar) { break; }
                if (Bits.getInt16(src, charpntrs) == 0x8000) { charpntrs += 2; continue; }
                //total2 += 1;
                int charTree = (chardata + Bits.getInt16(src, charpntrs)) << 3; charpntrs += 2;
                int charSlot = charTree - 12;
                int depth = 0;

                ctOffsets[char1] = pos;
                while (true)
                {
                    while (((src[charTree >> 3] >> (charTree++ & 7)) & 1) == 0) { nodeOffsets[depth++] = pos++; }
                    cTree[pos++] = -((Bits.getInt16(src, charSlot >> 3) >> (charSlot & 7)) & 0xFFF); charSlot -= 12; //total += 1;

                    if (depth <= 0) break;
                    cTree[nodeOffsets[--depth]] = pos;
                } //while (depth > 0);
            }

            //Console.WriteLine(DateTime.Now - c);
            //c = DateTime.Now;
            int textTree = 0, textLenAddr = 0;
            byte[] des = new byte[0x800000]; int desEntry = 0, desPos = 0xC300;
            for (int srcI = 0; srcI < 12461; srcI++)
            {
                Bits.setInt32(des, desEntry, desPos - 0xC300); desEntry += 4;
                int srcInd = srcI;
                if ((srcInd & 0xFF) == 0)
                {
                    textTree = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3)) - 0x08000000;
                    textLenAddr = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3) + 4) - 0x08000000;
                }
                else
                {
                    int cLen;
                    do
                    {
                        cLen = src[textLenAddr++];
                        textTree += cLen;
                    } while (cLen == 0xFF);
                }
                int initChar = 0, textTree2 = textTree << 3;//, bitnum = 1, val = 0;
                do
                {
                    pos = ctOffsets[initChar];
                    while (cTree[pos] > 0)
                    {
                        if ((src[textTree2 >> 3] >> (textTree2++ & 7) & 1) == 0) { pos++; }
                        else { pos = cTree[pos]; }
                        //--- if using textTree2 = textTree; ---
                        //if (bitnum >= 0x100) { bitnum = 1; textTree2++; }
                        //if ((src[textTree2] & bitnum) == 0) { pos++; }
                        //else { pos = cTree[pos]; }
                        //bitnum <<= 1;
                    }
                    initChar = -cTree[pos]; //bitChar[entry]; val >>= bitLen[entry]; bitnum -= bitLen[entry];
                    des[desPos++] = (byte)initChar;
                    //if (srcI == 5468)
                    //    Console.Write(initChar.ToString("X2")+" ");
                } while (initChar != 0);
            }
            Console.WriteLine(DateTime.Now - c + " (Text Decompression!)");
            return des;
        }[/spoiler]

[spoiler=Bit codes version]
        static public byte[] decompTextOld2(byte[] src) { //, int srcInd) { // int srcPos) {
            //return decompTextOld(src);
            int total = 0;
            DateTime c = DateTime.Now;
            int[] bitcode = new int[0x10000];
            byte[] bitLen = new byte[0x10000];
            short[] bitChar = new short[0x10000];
            //Scan char data to generate data for faster decompression than old method.
            int asmpchar = Bits.getInt32(src, 0x38578) - 0x8000000;
            int asmptext = Bits.getInt32(src, 0x385DC) - 0x8000000;
            int chardata = Bits.getInt32(src, asmpchar) - 0x08000000;
            int charpntrs = Bits.getInt32(src, asmpchar + 4) - 0x08000000;
            for (int char1 = 0; char1 < 0x100; char1++) {
                if (charpntrs == asmpchar) { break; }
                if (Bits.getInt16(src, charpntrs) == 0x8000) { charpntrs += 2; continue; }
                int charTree = (chardata + Bits.getInt16(src, charpntrs)) << 3; charpntrs += 2;
                int charSlot = charTree - 12;
                byte bits = 0; int bitC = 0; int entry = (char1 << 8);
                do {
                    while (((src[charTree >> 3] >> (charTree++ & 7)) & 1) == 0) { bits++; }
                    bitChar[entry] = (short)((Bits.getInt16(src, charSlot >> 3) >> (charSlot & 7)) & 0xFFF); charSlot -= 12; total += 1;
                    bitLen[entry] = bits; if (bits >= 24) { return decompTextOld(src); }
                    bitcode[entry] = bitC;
                    while (((bitC >> (bits - 1)) & 1) == 1) { bits -= 1; bitC ^= 1 << bits; }
                    bitC |= 1 << (bits - 1);
                    entry += 1;
                } while (bits > 0);
            }
            Console.WriteLine("Total: " + total);
            //Console.WriteLine(DateTime.Now - c);
            //c = DateTime.Now;
            int textTree = 0, textLenAddr = 0;
            byte[] des = new byte[0x800000]; int desEntry = 0, desPos = 0xC300;
            for (int srcI = 0; srcI < 12461; srcI++) {
                Bits.setInt32(des, desEntry, desPos - 0xC300); desEntry += 4;
                int srcInd = srcI;
                if ((srcInd & 0xFF) == 0) {
                    textTree = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3)) - 0x08000000;
                    textLenAddr = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3) + 4) - 0x08000000;
                } else {
                    int cLen;
                    do {
                        cLen = src[textLenAddr++];
                        textTree += cLen;
                    } while (cLen == 0xFF);
                }
                int initChar = 0, bitnum = 0, val = 0, textTree2 = textTree;
                do {
                    while (bitnum < 24) { val |= (int)src[textTree2++] << bitnum; bitnum += 8; }
                    int entry = initChar << 8;
                    while ((val & ((1 << bitLen[entry]) - 1)) != bitcode[entry]) { entry++; }
                    initChar = bitChar[entry]; val >>= bitLen[entry]; bitnum -= bitLen[entry];
                    des[desPos++] = (byte)initChar;
                    //if (desPos >= 0x10000) { break; }
                } while (initChar != 0);
            }
            Console.WriteLine(DateTime.Now - c + " (Text Decompression)");
            return des;
        }[/spoiler]

[spoiler=Direct]
        static public byte[] decompTextOld(byte[] src) {
            DateTime c = DateTime.Now;
            int asmpchar = Bits.getInt32(src, 0x38578) - 0x8000000;
            int asmptext = Bits.getInt32(src, 0x385DC) - 0x8000000;
            int chardata = Bits.getInt32(src, asmpchar) - 0x08000000;
            int charpntrs = Bits.getInt32(src, asmpchar + 4) - 0x08000000;
            byte[] des = new byte[0x800000]; int desEntry = 0, desPos = 0xC300;
            for (int srcI = 0; srcI < 12461; srcI++) {
                Bits.setInt32(des, desEntry, desPos - 0xC300); desEntry += 4;
                int srcInd = srcI;

                int textTree = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3)) - 0x08000000;
                int textLenAddr = Bits.getInt32(src, asmptext + ((srcInd >> 8) << 3) + 4) - 0x08000000;
                srcInd &= 0xFF;
                while (srcInd-- != 0) {
                    int cLen;
                    do {
                        cLen = src[textLenAddr++];
                        textTree += cLen;
                    } while (cLen == 0xFF);
                }
                int initChar = 0;

                textTree <<= 3;
                do {
                    int charTree = (chardata + Bits.getInt16(src, charpntrs + (initChar << 1))) << 3;
                    int charSlot = charTree - 12;
                    while (((src[charTree >> 3] >> (charTree++ & 7)) & 1) == 0) {
                        if (((src[textTree >> 3] >> (textTree++ & 7)) & 1) == 1) {
                            int depth = 0;
                            while (depth >= 0) {
                                while (((src[charTree >> 3] >> (charTree++ & 7)) & 1) == 0) {
                                    depth++;
                                }
                                charSlot -= 12;
                                depth--;
                            }
                        }
                    }
                    initChar = (Bits.getInt16(src, charSlot >> 3) >> (charSlot & 7)) & 0xFFF;
                    des[desPos++] = (byte)initChar;
                    //do {
                    // n=getNextCharacter(argument0)
                    // if n!=0 {
                    //  if (n<32 || n>ord('~')) {
                    //   if argument2
                    //   { str+='['+string(n)+']'; }
                    //   if argument3 && (n==1 || n==3) && (p<17 || p>20) && p!=26 && p!=29
                    //   { n=0 }
                    //  } else { str+=chr(n); }
                    // }
                    // p=n
                    //} until n=0
                } while (initChar != 0);
            }
            Console.WriteLine(DateTime.Now - c + " (Old Text Decompression)");
            return des;
        }
[/spoiler] (I'm not sure if this last one is what you mean by brute force or not.)



And my text compression function was huge... But I like it because it's fast.
[spoiler]
        static public void comptext(byte[] src, byte[] dest) {
            DateTime c = DateTime.Now;//.Ticks;
            //Welcome to my Huffman Hamburger! (Scan text, do complex char tables, compress text.)
            //Scan text to generate frequency table.
            ushort char1 = 0, char2 = 0;
            ushort[] freq = new ushort[0x10000]; //We need to know how often each character combination occurs to determine best bit amounts.
            ushort[] clen = new ushort[0x100]; //How many chars each char has associated with it.
            ushort[] clst = new ushort[0x10000]; //Char list in the order they appear in the text.
            int srcEntry = 0;
            while ((Bits.getInt32(src, srcEntry) != 0) || (srcEntry == 0)) { //Set up frequency table and char list (in order displayed in text.)
                int srcPos = 0xC300 + Bits.getInt32(src, srcEntry);
                do {
                    char2 = src[srcPos++];
                    if (freq[char1 * 0x100 + char2]++ == 0) {
                        clst[char1 * 0x100 + clen[char1]++] = char2; //clen[char1]++;// += 1;
                    }
                    //freq[char1 * 0x100 + char2] += 1;
                    char1 = char2;
                } while (char1 != 0); //Change to while < textArray?-- No, go through offset list instead.
                srcEntry += 4;
            }
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/clst.dmp", Array.ConvertAll<short, byte>(clst, delegate(short item) { return (byte)item; }));
            byte[] bitLen = new byte[0x10000]; //int[] bitLen = new int[0x10000];
            int[] bitCode = new int[0x10000];
            int addr2 = 0, chrptlen = 0;
            byte[] chrTbl = new byte[0x8000];
            byte[] chrPtrs = new byte[0x200];
            for (int c1 = 0; c1 < 0x100; c1++) {
                if (clen[c1] == 0) { chrPtrs[(c1 << 1) + 1] = 0x80;  continue; }
                chrptlen = (c1 + 1) << 1;
                //if (c1 > 5) { continue; } //For testing.
                //Sort chars by symbol frequency (simple)
                //See https://en.wikipedia.org/wiki/Sorting_algorithm - Use a Stable one so same-freq chars stay in order.
                //I pick simple Insertion Sort for now, since we are dealing with small sets. (https://en.wikipedia.org/wiki/Insertion_sort)
                for (int i = 1; i < clen[c1]; i++) {
                    ushort x = clst[(c1 << 8) + i];
                    int j = i;
                    while ((j > 0) && (freq[(c1 << 8) + clst[(c1 << 8) + j - 1]] > freq[(c1 << 8) + x])) {
                        clst[(c1 << 8) + j] = clst[(c1 << 8) + j - 1];
                        j = j - 1;
                    }
                    clst[(c1 << 8) + j] = x;
                }
                //Sort chars by node frequency (More advanced)
                int[] symbSort = new int[0x100]; //Basically points to chars in order to be displayed in data.
                int[] symbBits = new int[0x100];
                int[] nodeHead = new int[0x100];
                int[] nodeTail = new int[0x100];
                int[] nodeFreq = new int[0x100]; nodeFreq[0] = 0x7FFFFFFF; nodeFreq[1] = 0x7FFFFFFF; //Ensure unused/node2 when there is none.
                int nodeA = 0, nodeI = 0, symbI = 0;
                if (clen[c1] > 1) {
                    while ((symbI < clen[c1]) || (nodeA < nodeI - 1)) {
                        int symfreq1 = freq[(c1 << 8) + clst[(c1 << 8) + symbI]];
                        int symfreq2 = freq[(c1 << 8) + clst[(c1 << 8) + symbI + 1]];
                        if ((symbI + 1 < clen[c1]) && (symfreq2 <= nodeFreq[nodeA])) { //Symbol - Symbol
                            symbSort[symbI] = symbI + 1;
                            nodeHead[nodeI] = symbI; nodeTail[nodeI] = symbI + 1;
                            nodeFreq[nodeI] = symfreq1 + symfreq2;
                            symbI += 2;
                        } else if ((symbI < clen[c1]) && (symfreq1 <= nodeFreq[nodeA])) { // Symbol - Node
                            symbSort[symbI] = nodeHead[nodeA];
                            nodeHead[nodeI] = symbI; nodeTail[nodeI] = nodeTail[nodeA];
                            nodeFreq[nodeI] = symfreq1 + nodeFreq[nodeA];
                            symbI++; nodeA++;
                        } else if ((nodeA < nodeI - 1) && ((nodeFreq[nodeA + 1] < symfreq1) || ((symbI >= clen[c1])))) { // Node - Node
                            symbSort[nodeTail[nodeA]] = nodeHead[nodeA + 1];
                            nodeHead[nodeI] = nodeHead[nodeA]; nodeTail[nodeI] = nodeTail[nodeA + 1];
                            nodeFreq[nodeI] = nodeFreq[nodeA] + nodeFreq[nodeA + 1];
                            nodeA += 2;
                        } else if (nodeFreq[nodeA] < symfreq1) { // Node - Symbol
                            symbSort[nodeTail[nodeA]] = symbI;
                            nodeHead[nodeI] = nodeHead[nodeA]; nodeTail[nodeI] = symbI;
                            nodeFreq[nodeI] = nodeFreq[nodeA] + symfreq1;
                            symbI++; nodeA++;
                        }
                        symbBits[clst[(c1 << 8) + nodeHead[nodeI++]]] += 1;
                    }
                }
                addr2 += (((clen[c1] * 12) + 4) & -8);
                chrPtrs[(c1 << 1)] = (byte)(addr2 >> 3);
                chrPtrs[(c1 << 1) + 1] = (byte)(addr2 >> 11);
                int addr1 = addr2 - 12;
                byte bitsL = 0;
                //int val = 0;
                //int bitnum = (clen[c1] & 1) * 4;
                int bitC = 0;
                for (int n = clen[c1]; n > 0; n--) {
                    //List chars
                    chrTbl[(addr1 >> 3)] |= (byte)(clst[(c1 << 8) + nodeHead[nodeA]] << (addr1 & 7));
                    chrTbl[(addr1 >> 3) + 1] |= (byte)(clst[(c1 << 8) + nodeHead[nodeA]] >> (8 - (addr1 & 7)));
                    addr1 -= 12;
                    //val |= clst[(c1 << 8) + nodeHead[nodeA]] << bitnum; bitnum += 12;
                    //while (bitnum >= 8) {
                    //    chrTbl[addr1++] = (byte)val; bitnum -= 8;
                    //}
                    //List the char's tree/flags
                    addr2 += symbBits[clst[(c1 << 8) + nodeHead[nodeA]]];
                    chrTbl[addr2 >> 3] |= (byte)(1 << (addr2++ & 7));
                    //Calculate bit lengths for bit code.
                    bitsL += (byte)symbBits[clst[(c1 << 8) + nodeHead[nodeA]]];
                    //bitLen[clst[(c1 << 8) + nodeHead[nodeA]]] = bitsL;
                    bitLen[(c1 << 8) + clst[(c1 << 8) + nodeHead[nodeA]]] = bitsL;
                    //if (symbBits[clst[(c1 << 8) + nodeHead[nodeA]]] == 0) { bitsL -= 1; }
                    //if (c1 == 0) { Console.WriteLine(bitC.ToString("X8") + "   " + bitsL.ToString("X8") + "   " + (char)clst[(c1 << 8) + nodeHead[nodeA]]); }
                    //Generate bitCode table.
                    bitCode[(c1 << 8) + clst[(c1 << 8) + nodeHead[nodeA]]] = bitC;
                    while (((bitC >> (bitsL - 1)) & 1) == 1) { bitsL -= 1; bitC ^= 1 << bitsL; }
                    bitC |= 1 << (bitsL - 1);
                   
                    nodeHead[nodeA] = symbSort[nodeHead[nodeA]];
                }
                addr2 = (addr2 + 8) & -8;
                //Console.WriteLine("\nLetter by node order");
                //for (int zz = 0; zz < clen[c1]; zz++) {
                //    Console.Write(clst[(c1 << 8) + nodeHead[nodeA]].ToString("X4") + " ");
                //    //Console.Write(symbBits[clst[(c1 << 8) + nodeHead[nodeA]]].ToString("X4") + " ");
                //    nodeHead[nodeA] = symbSort[nodeHead[nodeA]];
                //}
                //Console.WriteLine("\nsymbSort");
                //for (int zz = 0; zz < clen[c1]; zz++) {
                //    Console.Write(symbSort[zz].ToString("X4") + " ");
                //}
            }
            /*//-------------------------------------------
            // Making spreadsheet of char tables! (Temp?)
            int[] bmp = new int[0x10000];
            System.Text.StringBuilder strbuild = new System.Text.StringBuilder(0x1000);
            for (int i = 0; i < 0x10000; i++)
            {
                if (freq == 0)
                    continue;
                strbuild.Append((i >> 8).ToString("X2") + (char)9 + (i & 0xFF).ToString("X2") + (char)9);
                strbuild.Append(freq);
                strbuild.Append((char)9);
                //strbuild.Append(bitCode);
                int j = i;
                //int j = 0;j = i & 0xFF00;
                //while (true)
                //{
                //    if (clst[j] == (i & 0xFF))
                //        break;
                //    j++;
                //}
                if (bitLen[j] > 0)
                    strbuild.Append(Convert.ToString(bitCode[j], 2).PadLeft(bitLen[j], '0'));
                strbuild.Append((char)9);
                strbuild.Append(bitLen[j]);
                strbuild.AppendLine();
                /*
                int color = 0xF8F8F8;
                if (((i >> 8) >= 0x41) && ((i >> 8) <= 0x5A))
                    color = 0x00F8F800;
                if (((i >> 8) >= 0x61) && ((i >> 8) <= 0x7A))
                    color = 0x00F8F800;
                if (((i >> 8) >= 0x30) && ((i >> 8) <= 0x39))
                    color = 0x00F8F800;

                if (((i & 0xFF) >= 0x41) && ((i & 0xFF) <= 0x5A))
                    color = 0x00F8F800;
                if (((i & 0xFF) >= 0x61) && ((i & 0xFF) <= 0x7A))
                    color = 0x00F8F800;
                if (((i & 0xFF) >= 0x30) && ((i & 0xFF) <= 0x39))
                    color = 0x00F8F800;

                if (color == 0x00F8F800)
                    color = 0x20A0F8;

                bmp = color;
               
            }
           
            System.Windows.Forms.PictureBox pb = new System.Windows.Forms.PictureBox();

            pb.Image = Bits.PixelsToImage(bmp, 256, 256);
            pb.Image.Save(@"C:\Users\tmttb\Desktop\usedchars.png");
           
            System.IO.File.WriteAllText(@"C:\Users\tmttb\Desktop\usedchars.txt", strbuild.ToString());
            *///-------------------------------------------

            //Finally compress the text.
            int val = 0, bitnum = 0, ctAddr = 0, cstrstart = 0;
            byte[] cText = new byte[src.Length];
            byte[] txtref1 = new byte[0x200]; int tr1Addr = 0;
            byte[] txtref2 = new byte[0x8000]; int tr2Addr = 0;
            srcEntry = 0; char1 = 0;
            while ((Bits.getInt32(src, srcEntry) != 0) || (srcEntry == 0)) {
                if ((srcEntry & 0x3FC) == 0) {
                    Bits.setInt32(txtref1, tr1Addr, ctAddr); tr1Addr += 4;
                    Bits.setInt32(txtref1, tr1Addr, tr2Addr); tr1Addr += 4;
                }
                cstrstart = ctAddr;
                int srcPos = 0xC300 + Bits.getInt32(src, srcEntry); val = 0;
                do {
                    char2 = src[srcPos++];
                    val |= bitCode[(char1 << 8) + char2] << bitnum;
                    bitnum += bitLen[(char1 << 8) + char2];
                    while (bitnum >= 8) {
                        cText[ctAddr++] = (byte)val; val >>= 8; bitnum -= 8;
                    }
                    //if (freq[char1 * 0x100 + char2]++ == 0) {
                    //    clst[char1 * 0x100 + clen[char1]++] = char2; //clen[char1]++;// += 1;
                    //}
                    //freq[char1 * 0x100 + char2] += 1;
                    //if (srcEntry == 0) { Console.WriteLine(bitCode[(char1 << 8) + char2].ToString("X8") + "   " + bitLen[(char1 << 8) + char2].ToString("X8")); }
                    char1 = char2;
                } while (char1 != 0); //Change to while < textArray?-- No, go through offset list instead.
                srcEntry += 4; if (bitnum != 0) { cText[ctAddr++] = (byte)val; bitnum = 0; }
                while ((ctAddr - cstrstart) > 0xFE) { txtref2[tr2Addr++] = 0xFF; cstrstart += 0xFF; }
                txtref2[tr2Addr++] = (byte)(ctAddr - cstrstart); //cstrstart = ctAddr;
            }
            //Now insert everything into the ROM.
            int insAddr = 0xFA0000;
            int loc1 = insAddr;
            Array.Copy(chrTbl, 0, dest, insAddr, addr2 >> 3); insAddr += addr2 >> 3;
            insAddr = (insAddr + 1) & -2;
            int loc2 = insAddr;
            Array.Copy(chrPtrs, 0, dest, insAddr, chrptlen); insAddr += chrptlen;
            insAddr = (insAddr + 3) & -4;
            Bits.setInt32(dest, 0x38578, 0x08000000 + insAddr);
            Bits.setInt32(dest, insAddr, 0x08000000 + loc1); insAddr += 4;
            Bits.setInt32(dest, insAddr, 0x08000000 + loc2); insAddr += 4;
            loc1 = insAddr;
            Array.Copy(cText, 0, dest, insAddr, ctAddr); insAddr += ctAddr;
            loc2 = insAddr;
            Array.Copy(txtref2, 0, dest, insAddr, tr2Addr); insAddr += tr2Addr;
            insAddr = (insAddr + 3) & -4;
            Bits.setInt32(dest, 0x385DC, 0x08000000 + insAddr);
            for (int a = 0; a < tr1Addr; a += 8) {
                Bits.setInt32(dest, insAddr + a, 0x08000000 + Bits.getInt32(txtref1, a) + loc1);
                Bits.setInt32(dest, insAddr + a + 4, 0x08000000 + Bits.getInt32(txtref1, a + 4) + loc2);
            }
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtromtest.gba", dest);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtref1.dmp", txtref1);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/txtref2.dmp", txtref2);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/cText.dmp", cText);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/chrPtrs.dmp", chrPtrs);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/chrTbl.dmp", chrTbl);
            //System.IO.File.WriteAllBytes("C:/Users/Tea/Desktop/bitLen.dmp", bitLen);
            //DateTime c = DateTime.Now;//.Ticks;
            Console.WriteLine((DateTime.Now - c).ToString());
        }
[/spoiler]
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo

No it's ok, i learned a lot with this Huffman Algorithm :happy:

You did a great job! I have to improve my decryption script, it's a bit slow.

I didn't work on the compression part, i want to have something working on the editor first :happy:

Ryudo

As promise, here's some screenshots.

The design is not definitive, i'm not webdesigner so it's a bit complicated for me.

The order of fields is subject to change, i just put them randomly.


Ryudo

The second part of screenshots.

Also, it's now possible to load an USA/English rom (of the first Golden Sun).

Daddy Poi's Oily Gorillas

#7
Would be interesting to see if your project could completely replace gsmagic some day. I guess we'll see. I think I felt more comfortable working with C# than with Javascript, but if I get use to Javascript, then I guess it could work out.


Djinnis = Typo? "Djinn" would be the plural form. ("Djinni" is the singular.)
And I believe it to be pronounced as Jen/Jenny.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo

We'll see, i have time for this project since the confinement in France, buy i'll have less time after, that's why the project is Open Source :happy:

Do you have some screenshots of GSMagic? I can't open it, even with VirtualBox and i can't find images / videos.

Thank's for the correction :VenusDjinni:

Daddy Poi's Oily Gorillas

#9
Might take a lot of screenshots to show everything... so won't go over everything right now, but I guess I can give you a few...

It may be kind of messy. - And plenty of work may need to be done.
But here's what Heightmap looks like. (You can also edit them too, if you are on the Height table page in subwindow.)
And here's what the Events may look like.

In both, it's done in three layers, so to see the other layers, hit 1/2/3 on keyboard. (Layers may be blank if it wasn't needed.)

And third image is what the subwindow looks like when you can put event tiles in the map. I have this here to also show that each tile lists the frequency of how often they were used in the map. (The tile uses a brighter color if the frequency is at least 1... with the exception of ID 0.)
The latest release version actually does 16 columns instead of 10.... but I decided to try 10, and I haven't finished fixing it. Heheh.



And the Editors windows is also kind of messy/needs work. Has a few tables, and I consider it slightly less interesting, so didn't include screenshots. (PLus, I'm limited to 4 per post, so...)
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo


Daddy Poi's Oily Gorillas

#11
You are welcome!
(FYI - Daddy Poi is a reference to that old guy in Kandarian temple (or whatever it is called.), and how a few of us joked about him on Discord way back. Heheh.)



Sounds like daddy boy to me, kinda.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo

Haha, with the French version, i don't have this reference :happy:

Daddy Boy: it's the sound that i had on saying your pseudo in my head xD

Ryudo

#13
Hi, you can find a link to download the current state of the project on my first post.

Please, read carefully all the post :!:

Don't hesitate to push any problem or idea of amelioration :happy:

Daddy Poi's Oily Gorillas

Seems blank for Microsoft Edge and Internet Explorer. (Hopefully I'm not using outdated versions? *shrug*)

Seems to work with Google Chrome and Firefox, though. So that's good.
Golden Sun Docs: Broken Seal - The Lost Age - Dark Dawn | Mario Sports Docs: Mario Golf & Mario Tennis | Misc. Docs
Refer to Yoshi's Lighthouse for any M&L hacking needs...

Sometimes I like to compare apples to oranges. (Figuratively) ... They are both fruits, but which one would you eat more? (If taken literally, I'd probably choose apples.)
Maybe it is over-analyzing, but it doesn't mean the information is useless.


The only GS Discord servers with significance are:
Golden Sun Hacking Community
GS Speedrunning
/r/Golden Sun
GS United Nations
Temple of Kraden

Can you believe how small the Golden Sun Community is?

2+2=5 Don't believe me? Those are rounded decimal numbers. Take that, flat earth theorists! :)

Ryudo

Yep, didn't check on IE and Edge, i'll check later !

There's also a standalone version but i only can generate it like a MacOS application (for the moment).

Thanks for your test !

Ryudo

Golden Sun Editor v1.0.0-alpha.2
- Improve Dropzone
- Improve speed navigation
- Improve translations
- Add icon and favicon
- Add About
- Allow to change language (English/French)
- Allow to Eject rom
- Temporary fix incomplete CircularProgress

Ryudo

Golden Sun Editor v1.0.0-alpha.3
- Add compatibility with Golden Sun 1 [ Germany / Italy / Spain ]
- Add Shops
- Add Classes
- Add Sprites
- Add icons (from rom) on Abilities and Items
- Improve header design

Ryudo

Golden Sun Editor v1.0.0-alpha.4
- Add Maps (just names)
- Add Party Members
- Improve Shops
- Add type and uses on Abilities
- Translate attributes from rom on Abilities
- Tabs are now scrollable