Dear forum users! In compliance with the new European GDPR regulations, we'd just like to inform you that if you have an account, your email address is stored in our database. We do not share your information with third parties, and your email address and password are encrypted for security reasons.

New to the forum? Say hello in this topic! Also make sure to read the rules.

Be able to insert the script text into a '*.sfdm' file from command line

Share questions, scripts and tutorials related to the ScriptAPI in SFD.
Forum rules
By using the forum you agree to the following rules.
Post Reply
Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Be able to insert the script text into a '*.sfdm' file from command line

Post by Juansero29 » Sun Mar 14, 2021 4:56 pm

I'm starting to get some contributions for the script used in my server on GitHub. I would like to setup a pipeline in which when a change is done in the master branch of my repository, it could inject the text (a String) in the script into an existing .sfdm file stored in a server.

This would be a replacement of having to go through the Map Editor, then the Script Editor, and pasting the code there manually. It could really speed up the development process as a scripting-guy.

Is this foreseeable?
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

User avatar
Gurt
Lead Programmer
Lead Programmer
Posts: 1884
Joined: Sun Feb 28, 2016 3:22 pm
Title: Lead programmer
Started SFD: Made it!
Location: Sweden
Gender:
Age: 34

Post by Gurt » Thu Mar 18, 2021 6:30 pm

The .sfdm file is a binary file. But at some section there is the script part of each map.
If you're working with a versus map it should be fine to find that section and overwrite that (as long as you also keep the null-terminator intact).

If you make your own program to insert the text then it should work but you might want to experiment to get it "just right". Try it out manually first in notepad++ for example.
0 x
Gurt

Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Post by Juansero29 » Sat Mar 20, 2021 9:40 pm

Huh, interesting. I'll definetly try. It does seem, when opening .sfdm files with a text editor, that the script is somehow there, but it seems unreadable.

Look at an example here: https://i.imgur.com/ITh867O.png

c_scrpt section is there, but is followed by a long string of binary. Do you think this could be any different if accessing the file from, for example, a c# FileStream?
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

User avatar
Gurt
Lead Programmer
Lead Programmer
Posts: 1884
Joined: Sun Feb 28, 2016 3:22 pm
Title: Lead programmer
Started SFD: Made it!
Location: Sweden
Gender:
Age: 34

Post by Gurt » Sat Mar 20, 2021 11:15 pm

The script is encoded in base64 utf8. You can easily decode and encode back and forth to utf8 base64.
1 x
Gurt

Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Post by Juansero29 » Sat Mar 20, 2021 11:26 pm

Damn you're completely right. This is awesome. It means I can actually inject the code directly into the map file and completely automize map deployment from github. This is some real useful thing to know! Wow. So many possibilities. Thanks a lot for that info Gurt, I'll surely make use of it to setup automatic deployment of code from GitHub directly into my server :)
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Post by Juansero29 » Mon Mar 22, 2021 10:18 pm

I've been trying a lot to make this modifications but it seems that whenever I modify the Base64 encoded string containing the script, even if it is for a minor modification for a espace in the script or something, it corrupts the file.

https://i.imgur.com/J7fCVBJ.png

This character seems to change whenever the script is modified via the internal script editor.

The script seems to live between a SYN and an EOF characters respectively, after the c_scrpt. But somehow the bytes between "c_scrpt" and SYN get modified when changing the script of a map from SFD Map Editor.

I could recover the script from code using the next tag "c_lr", however no matter what I do the file seems to be corrupt. @Gurt Have you got any ideas on maybe why this modification is made? The file does not corrupt if I change the name of the map or the description from NotePad++, so the problem is not tied to saving the file but actually the sections I modify within it.

This is the error I am getting: https://i.imgur.com/AazvTNR.png
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Post by Juansero29 » Mon Mar 22, 2021 10:48 pm

After making more tests it seems like this variable depends on the size of the text inside the c_scrpt section. Maybe it is the number of characters, or the amount or the amounts of bytes this text weights? I'm still making tests to find out.

EDIT #1: After even more testing, this changing number seems to be the number of bytes used by the Base64 string written into as much bytes as necessary between the c_script section and the begining of the Base64 encoded script text.

EDIT #2: After many many tries I have only got a different error message now that I include the number of bytes used by the Base64 text after the c_script, but still not able to use the map with a different script.

https://i.imgur.com/YH0FX4C.png

There's still some binary differences between a map created with SFD Map Editor to when I inject the script into the map via a C# console application. Something is still wrong but I don't know what exactly. I'm guessing is still tied to the bytes between the c_script tag and the Base64 text. They are still different and they seem to be very important for the GameWorld.ReadFromStream function. I still don't know what exactly to do to get this right :/ some help would really be appreciated.

https://i.imgur.com/FWrja2B.png
Last edited by KliPeH on Tue Mar 23, 2021 1:50 pm, edited 1 time in total.
Reason: Merged a triple post.
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

User avatar
Gurt
Lead Programmer
Lead Programmer
Posts: 1884
Joined: Sun Feb 28, 2016 3:22 pm
Title: Lead programmer
Started SFD: Made it!
Location: Sweden
Gender:
Age: 34

Post by Gurt » Tue Mar 23, 2021 8:38 pm

Yes, it is a length prefixed string.
https://docs.microsoft.com/en-us/dotnet ... tem_String_

Here some demo code in C# (if you're using another language you will have to figure out the implementation details in a BinaryWriter in C# yourself)

Code: Select all

string script = "Arbitary script region here with data";

            // WRITING
            using (Stream stream = new FileStream(@"C:\temp\test.bin", FileMode.Create, FileAccess.ReadWrite, FileShare.None))
            {
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    // ... arbitary amount of data written before
                    //writer.Write(false);
                    //writer.Write(241536);
                    //writer.Write(2412.902f);

		    // if script {
                    writer.Write("c_scrpt");
                    byte[] bytes = Encoding.UTF8.GetBytes(script);
                    string base64 = Convert.ToBase64String(bytes);
                    writer.Write(base64);
                    // }

                    // ... continued data after
                    writer.Write("c_lr");

                    writer.Flush();
                }   
            }

            // READING
            using (Stream stream = new FileStream(@"C:\temp\test.bin", FileMode.Open, FileAccess.Read, FileShare.None))
            {
                using (BinaryReader reader = new BinaryReader(stream))
                {

                    switch(reader.ReadString())
                    {
                        case "c_scrpt":
                            string base64String = reader.ReadString();
                            byte[] base64Data = Convert.FromBase64String(base64String);
                            script = Encoding.UTF8.GetString(base64Data);
                            break;
                    }
                }
            }
1 x
Gurt

Juansero29
Fighter
Fighter
Posts: 52
Joined: Sun Jun 12, 2016 1:07 am
Title: Superfighter
SFD Account: Juansero29
SFD Alias: Juansero29
Started SFD: Pre-Alpha 1.0.5
Location: France
Gender:
Age: 25
Contact:

Post by Juansero29 » Wed Mar 24, 2021 9:37 am

Thanks a lot Gurt, may head was in pain trying to figure out those bytes. I'll give that a try this afternoon!

EDIT: Okay so if this may be interesting for anyone else out there: I could use simply a BinaryWriter with a memory stream and get the expected result in form of a byte array like this:

Code: Select all

        private static byte[] GetSizePrefixedScript(string newScriptTextInBase64)
        {
            using MemoryStream stream = new MemoryStream();
            using BinaryWriter writer = new BinaryWriter(stream);
            writer.Write(newScriptTextInBase64);
            return stream.ToArray();
        }
In this way the script is injected into the map with the correct bytes, and then opens just fine inside the map editor with the expected code. Thank you soo much @Gurt for your help! This discovery is gold. It will much more facilitate the way I create maps and gives much more possibilities. See you soon!

EDIT #2: To everyone who may be interested, I developed a tool that allows you to inject a script inside a .sfdm file from command line. You can find the source code in here. Thanks again @Gurt
Last edited by KliPeH on Thu Mar 25, 2021 1:50 pm, edited 1 time in total.
Reason: Merged a double post.
0 x

Code: Select all

boom() {
  echo "BOOM!";			
}
BOOM!
----------------------------------------
Setting the world free since 1998
----------------------------------------

Post Reply