[Spoiler] FTL Profile/SavedGame Editor v27 (2018-01-12)

All your guides, strategy discussions, request for help on how to play go here. Please use [SPOILER] if relevant.
Vhati
Posts: 792
Joined: Thu Oct 25, 2012 12:01 pm

Re: FTL Editor v16 - Questions from an excited noob

Postby Vhati » Tue Jul 02, 2013 6:46 am

iceburg333 wrote:I basically want to make a program that edit's the ship (a hanger bay) where you can use items like blue prints to edit or craft a ship: have 30 scrap and a warp core, you can make a Kestrel.
I'm not sure what you mean by this.

The tool here modifies the state of a saved game, swapping out crew and such, and changing values, almost as if you'd legitimately played and lucked into a given situation. The game's resources aren't altered at all. So the Kestrel's hull has a fixed maxumim, for example, but this tool can add damage as if it had occurred in-game.


Have you seen kartoFlane's Superluminal ship editor?

The tool there ultimately edits the game's resources to create ship blueprints that didn't already exist. They will appear in the hangar for starting new games.
iceburg333
Posts: 67
Joined: Tue Jun 25, 2013 8:52 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby iceburg333 » Tue Jul 02, 2013 12:16 pm

Vhati wrote:Maven manages compiling but also serves as a package manager of sorts. It automatically downloads libraries from repositories to meet project dependencies, so you don't have to scour the net.

I hadn't played with maven either before this project, but IIRC, all I had to do was install maven, open a prompt, cd to the project's dir, and run "mvn clean" then "mvn package". XML tells maven all it needs to know.

I assume Eclipse's maven plugin does something comparable, but I'm unfamiliar with that IDE.

Tip: After I got the source off github, I made a copy of the project directory to do all my tinkering and compiling in. When I was satisfied, I used WinMerge to copy the important changes into the original github folder for committing.


Ah thank you! I figured Maven had something to do with packing, but had no idea it worked with compiling as well. As someone who has grown by just modding Skyrim with their dedicated tools, the 'real programming' world still seems rather magical and mysterious. :D
If you don't mind, what IDE is IIRC? I learned eclipse a while back while learning html/css/basics of cold fusion, and so it's the only IDE I'm familiar with. One of its release packages had maven installed and once I downloaded it it probably did what you did manually.

I'm also a github noob, but if/when I get that far along in the program, I'll delve into that as well and check out WinMerge. :D


Vhati wrote:Sure. Have fun. :)
I hadn't designed the classes to be usable as an independent library, but they were intended to be a useful demonstration/documentation for other coders.

A lot of neat Java snippets in there, too. I guess if you lift entire class files, you can add a comment at the top about where you found them, but feel free to copy/port/paraphrase/mangle anything you want.


Dude, that's awesome! I'm so happy lol. I had the thought this morning as I was getting out of bed that I could make your jar a library mine would depend upon. The classes looked public, but I still don't know enough about Java to know that they weren't designed to be usable as independent libraries: If I can I'll use it as a library. Otherwise any classes I use I'll comment in the credits at the top, as well as credit you in the readme etc.

This is perfect. I've almost gone through all the java tutorials, so to have access to a java program/source that I can learn from and experiment with, that is on the subject that has me inspired, that has someone really knowledgeable that I may be able to ask questions to*, with resources parallel to what I need to do... it's awesome. Thank you! :D

*I don't want to bug or exasperate you; I've had my fair share of newbs ask me for all sorts of my time answering their questions, only to watch them disappear after I do a bunch of work for them. I don't want to be that sort of noob...

Vhati wrote:This was the first time I'd used JAXB to map XML to custom java objects. Viewing XML processing as deserialization was a little weird after being used to JDOM's tree of Elements. ;)


I'll admit this bit went mostly over my head. I'm not familiar with JAXB, though I do understand that the save files are serialized (they are xml as well?) From your link I *think* I get what JDOM does. In the tutorial series on persistence we used Xstream, but that was just to write to/get from xml, which it sounds like JDOM doesn't do so much as allow you to view the xml in your IDE as java objects?

Vhati wrote:I'm not sure what you mean by this.
The tool here modifies the state of a saved game, swapping out crew and such, and changing values, almost as if you'd legitimately played and lucked into a given situation. The game's resources aren't altered at all. So the Kestrel's hull has a fixed maxumim, for example, but this tool can add damage as if it had occurred in-game.

Have you seen kartoFlane's Superluminal ship editor?

The tool there ultimately edits the game's resources to create ship blueprints that didn't already exist. They will appear in the hangar for starting new games.


Yes! Superluminal's ship editor is awesome, and I've spent some time tinkering with it. However, that is used to make "New Ships" or "Custom Ships". My thought is that instead of the player starting each play through with a vanilla ship that they are just given, that they should have to "construct" that same premade ship. The hanger wouldn't let you add rooms or move systems. I wouldn't be adding anything new/modifying resources or layouts, but instead requiring the player to pay for that vanilla ship. Imagine your program, except you can't modify the crew or add that teleporter room (activate it/ turn the boolean from false to true) without paying resources gathered in your last playthrough (and stored at the hanger). The hanger would work like your program, changing values of a saved game. Basically: to make a save editor that wouldn't be 'cheating', but worked for. It sounds terribly unbalanced now, but I have an idea on how to balance it, but figure I need to do first things first.
Thanks again Vhati!
Ice
Image
boa13
Posts: 829
Joined: Mon Sep 17, 2012 11:42 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby boa13 » Tue Jul 02, 2013 8:52 pm

iceburg333 wrote:Ah thank you! I figured Maven had something to do with packing, but had no idea it worked with compiling as well.


It also runs your unit tests, does your code quality measurements, deploys your application to remote servers, builds your project web site (well, the automatically generated pages), etc. :)
Forum janitor — If you spot spam, PM me the URL and/or the username of the spammer.
I have powers, moderator powers. I am not keen on using them, but will do so if needed.
Vhati
Posts: 792
Joined: Thu Oct 25, 2012 12:01 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby Vhati » Tue Jul 02, 2013 10:44 pm

iceburg333 wrote:
Vhati wrote:IIRC, all I had to do was...
If you don't mind, what IDE is IIRC?

If I Recall Correctly :P

I just use a Windows command prompt (or *.bat scripts) and a plain text editor.


iceburg333 wrote:The classes looked public, but I still don't know enough about Java to know that they weren't designed to be usable as independent libraries
There's *technically* no difference: you *can* write your own class with a main(), then call anything you want from the net.blerf.ftl package: just include the editor's jar in your classpath.

In Java, "public" just means objects can call stuff on each other... I guess omitting the "public" keyword restricts access to 'only objects within the same package', but *shrug* I never bother being that protective.

I only meant I hadn't explicitly tried to minimize classes' interdependency, to allow someone to construct/call one object in isolation for some other purpose without modifying the editor's code.


iceburg333 wrote:it sounds like JDOM doesn't do so much as allow you to view the xml [...] as java objects?
Right. The JDOM library just read XML and returned a hierarchy of Element objects representing the document, each of which which contained Element children, and so on. And each Element had methods that returned attributes and such.

(De)serialization/persistence is focused on dumping objects from memory to xml (typically) and later (after exiting the app, or across a network) reversing that process to recreate the objects. Standardized save/load basically.

iceburg333 wrote:I do understand that the save files are serialized (they are xml as well?)
continue.sav is a proprietary binary format.
Most of my work involved reverse-engineering and documenting what each byte means: run FTL, change one thing in-game, save+quit, compare this save with one from minutes earlier using a hex editor.

ComaToes did the same to figure out profile.sav.
The only XML FTL uses is inside resource.dat and data.dat.


iceburg333 wrote:This is perfect. I've almost gone through all the java tutorials, so to have access to a java program/source that I can learn from and experiment with, that is on the subject that has me inspired, that has someone really knowledgeable that I may be able to ask questions to, with resources parallel to what I need to do... it's awesome. Thank you!
That's what opensource development is all about. 8-)


EDIT: BTW, WinMerge opens two text files or directories and highlights what's different between them. Extraordinarily useful on its own. No relation to github.
iceburg333
Posts: 67
Joined: Tue Jun 25, 2013 8:52 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby iceburg333 » Fri Jul 05, 2013 12:54 pm

boa13 wrote:It also runs your unit tests, does your code quality measurements, deploys your application to remote servers, builds your project web site (well, the automatically generated pages), etc.

Dang, sounds like it does everything! :D

Vhati wrote:
iceburg333 wrote:
Vhati wrote:IIRC, all I had to do was...
If you don't mind, what IDE is IIRC?

If I Recall Correctly :P

I just use a Windows command prompt (or *.bat scripts) and a plain text editor.

Haha, I totally thought that was some crazy IDE or something, lol. That's CRAZY that you did what you did with just a plain text editor. I read that a lot of people advocate that, but to do so you must really have to know your stuff. :D


Vhati wrote:There's *technically* no difference: you *can* write your own class with a main(), then call anything you want from the net.blerf.ftl package: just include the editor's jar in your classpath.

In Java, "public" just means objects can call stuff on each other... I guess omitting the "public" keyword restricts access to 'only objects within the same package', but *shrug* I never bother being that protective.

I only meant I hadn't explicitly tried to minimize classes' interdependency, to allow someone to construct/call one object in isolation for some other purpose without modifying the editor's code.

That makes sense. And I can understand your rational, the save editor would be pretty much a standalone program that normally wouldn't be used for anything else. I just thought that since the only things we can edit are adding new events, items, and adding saves, I'd need to learn to edit saves to do anything really unique.


Vhati wrote:Right. The JDOM library just read XML and returned a hierarchy of Element objects representing the document, each of which which contained Element children, and so on. And each Element had methods that returned attributes and such.

(De)serialization/persistence is focused on dumping objects from memory to xml (typically) and later (after exiting the app, or across a network) reversing that process to recreate the objects. Standardized save/load basically.

Makes sense. :)

Vhati wrote:continue.sav is a proprietary binary format.
Most of my work involved reverse-engineering and documenting what each byte means: run FTL, change one thing in-game, save+quit, compare this save with one from minutes earlier using a hex editor.

ComaToes did the same to figure out profile.sav.
The only XML FTL uses is inside resource.dat and data.dat.

I used a cheat gene on a SNES emulator to give myself unlimited lives once, so I understand the premise, but doing that for an entire save file, figuring out all the classes and fields, and then putting it into Java must have been crazy!

Vhati wrote:That's what opensource development is all about. 8-)

EDIT: BTW, WinMerge opens two text files or directories and highlights what's different between them. Extraordinarily useful on its own. No relation to github.

Yay! Then I'm digging open source development. :D
Alright, I'll check out WinMerge when my project is farther along (as well as try to better understand github.) I've finished the tutorial on persistence, so I'm going to work my way through the debugger tutorial, read through an article on creating a gui that I found, and then start going through your code. :D
Image
iceburg333
Posts: 67
Joined: Tue Jun 25, 2013 8:52 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby iceburg333 » Sat Jul 06, 2013 4:39 pm

So far things are going really well, I'm understanding a lot of your code and learning tons. However, I've hit one snag that I'm banging my head against. I can't figure it out. Would you be able to help me?
I've created a readShipSavetest method that returns a ShipSave object. In my test class I have the code written:

Code: Select all

ShipSave ss2 =
         ShipSaveParser.readShipSavetest();

It's telling me that I "Cannot make a static reference to the non-static method readShipSavetest() from the type
ShipSaveParser". But why is ss2 static? Nothing in my test method is defined as static.
Thanks!
Iceburg

EDIT: I think I got it! My new code reads like this and I'm not getting compiler errors:

Code: Select all

   @Test
   public void ShipSaveParser() throws IOException {
      //save a ship to file
      ShipSave ss1 = createShipSave();
      String fileName = "testShipSave.sav";
      File testFile = new File(fileName);
      testFile.delete();
      assertFalse("File should not exist",
            testFile.exists());
      assertTrue("File should have been saved",
            ShipSaveParser.updateShipSave(ss1));
      //get the ship from file
      ShipSaveParser parser = new ShipSaveParser();
      ShipSaveParser.ShipSave ss2 = parser.readShipSave(testFile);;
      assertEquals("Enterprise", ss2.getPlayerShipName());
      assertEquals("NCC-1701-D", ss2.getPlayerShipBlueprintId());
   }

I'm trying to do test driven design... so next I need to finish the WIP functions that actually do what I'm testing.
I realize that this could end up spamming your thread with semi off topic stuff. Perhaps I should start a WIP thread...
iceburg333
Posts: 67
Joined: Tue Jun 25, 2013 8:52 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby iceburg333 » Sat Jul 06, 2013 9:40 pm

Hi runawaybros!
I had another question for Vhati, concerning:

Code: Select all

int headerAlpha = readInt(in)


From what I can tell, in is incremented as each stat/variable is read in SavedGameParser. So that means that the variables must be read in order and cannot be skipped. Is that correct? If so, and if I only want to read 2 variables from the file (ship blueprint and ship name), is it possible for me to skip further into the stream without reading the whole file?
Thanks again Vhati!
Vhati
Posts: 792
Joined: Thu Oct 25, 2012 12:01 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby Vhati » Sun Jul 07, 2013 1:37 am

therunawaybros615 wrote:Hello, everyone! Hey Vhati, remember the problems I had starting the editor? I fixed it
Glad to hear it. :)
I only stumbled across JarFix a couple pages ago. Linking it in the OP is a good idea.

As a matter of fact, I was also revising the launcher generator I wrote for you.
There was a place it overlooked when searching for Java on 64bit machines.

I'll PM you when that's ready, if you don't mind testing it out.
Last edited by Vhati on Sun Jul 07, 2013 4:05 am, edited 1 time in total.
Vhati
Posts: 792
Joined: Thu Oct 25, 2012 12:01 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby Vhati » Sun Jul 07, 2013 3:13 am

iceburg333 wrote:In my test class I have the code written:

Code: Select all

ShipSave ss2 = ShipSaveParser.readShipSavetest();

It's telling me that I "Cannot make a static reference to the non-static method readShipSavetest() from the type
ShipSaveParser". But why is ss2 static? Nothing in my test method is defined as static.
Since Java is primarily an object-oriented language, unless a method is explicitly "public static void foo() {...}", that method only exists as part of instantiated objects of the relevant class. In other words you either have to do the following...
iceburg333 wrote:

Code: Select all

ShipSaveParser parser = new ShipSaveParser();
ShipSaveParser.ShipSave ss2 = parser.readShipSave(testFile);;
Or declare the method "static" so that it becomes part of the class itself, rather than of objects.

You've got an extra semicolon up there, btw.

...

iceburg333 wrote:

Code: Select all

int headerAlpha = readInt(in)

From what I can tell, in is incremented as each stat/variable is read in SavedGameParser. So that means that the variables must be read in order and cannot be skipped. Is that correct?
Correct. InputStreams let you consume bytes from a source in the order they appear (some will allow limited buffering to repeat bytes that just passed to mimic backtracking). Streams will let you skip forward (read and ignore bytes) but...

iceburg333 wrote:if I only want to read 2 variables from the file (ship blueprint and ship name), is it possible for me to skip further into the stream without reading the whole file?
The continue.sav file format doesn't store data at absolute offsets.
Values take up varying amounts of bytes (for example, lists of more/fewer crew names, even the name strings have different lengths), and the next value just appears wherever the previous one ended, not at the Nth byte from the beginning.

So you have to read the whole file to know where anything is.
Just read the entire game state, then pick out what you're interested in...

Code: Select all

DataManager.init(new File("path/to/FTL/resources/"));

SavedGameParser parser = new SavedGameParser();
SavedGameState gameState = readSavedGame(new File("continue.sav"));
ShipState shipState = gameState.getPlayerShipState();
String shipName = shipState.getShipName();
String shipBlueprintID = shipState.getShipBlueprintId();
The DataManager's necessary because the only way to know how many doors to expect in the saved game (how many bytes to read before the next thing), is to have read the ship layout txt beforehand. And the only way to know the layout for a ship's blueprintId, is to have read the <shipBlueprint> xml for that blueprintId.

If you ever want to make your own custom DataManager (to add methods or something) you'd have to copy SavedGameParser.java and change "import net.blerf.ftl.parser.DataManager;" to your own class.
iceburg333
Posts: 67
Joined: Tue Jun 25, 2013 8:52 pm

Re: [Spoiler] FTL Editor v16 - Unlock ships, Edit SavedGames

Postby iceburg333 » Sun Jul 07, 2013 8:47 pm

Vhati wrote:Since Java is primarily an object-oriented language, unless a method is explicitly "public static void foo() {...}", that method only exists as part of instantiated objects of the relevant class. In other words you either have to do the following...

Code: Select all

ShipSaveParser parser = new ShipSaveParser();
ShipSaveParser.ShipSave ss2 = parser.readShipSave(testFile);;
Or declare the method "static" so that it becomes part of the class itself, rather than of objects.

You've got an extra semicolon up there, btw.

Thank you! It makes more sense now, static vs object.... I think I'm just now coming to grips with the theory behind it, though the idea of a 'new parser' still hurts my brain. :D
lol. Silly semicolons. Thanks. :)
...

Vhati wrote:Correct. InputStreams let you consume bytes from a source in the order they appear (some will allow limited buffering to repeat bytes that just passed to mimic backtracking). Streams will let you skip forward (read and ignore bytes) but...

The continue.sav file format doesn't store data at absolute offsets.
Values take up varying amounts of bytes (for example, lists of more/fewer crew names, even the name strings have different lengths), and the next value just appears wherever the previous one ended, not at the Nth byte from the beginning.

So you have to read the whole file to know where anything is.
Just read the entire game state, then pick out what you're interested in...

Thanks, that's what I was figuring, but I appreciate you getting back to me before I wracked my brain try to figure out if that was really the case. I'm getting better at combing through the code/looking at java source, but you still saved me at least an hour of pulling my hair out, if not three. :D
I only hesitated to read the whole file because I want to load multiple files (a save game selector, if you will) and I didn't want it to take a long time. Happily, all of the data I need is in that first section, so I shouldn't have to read too much code! :D

Vhati wrote:The DataManager's necessary because the only way to know how many doors to expect in the saved game (how many bytes to read before the next thing), is to have read the ship layout txt beforehand. And the only way to know the layout for a ship's blueprintId, is to have read the <shipBlueprint> xml for that blueprintId.


Wow, the more I look at this code, the more I think you and ComaToes did some beast work. Again, thank you for making it open source!
I'm certain that my program will require FTL Editor, so my ShipSaveParser class is modled after your SavedGameParser and calls classes from/extends your parser and datamanager, so I should be good just calling those functions. (and that bit is working, it's just pulling the wrong bytes since I cherry picked what data I wanted).

I'm going to start adapting my Parser to handle the input/output stream and test it, and I also spent a couple hours yesterday working to get github working, I'm going to keep doing that so I can share more code. However, in the meantime would you be willing to answer another question? (If I'm wearing you out, please let me know, it's just so nice to have a pro to answer questions.) :D

I'm working on making a savegame manager (calling it a space dock) where you see all of your ships (save files) and choose one to play with (board) while all the others are 'docked'. Your current ship is "continue.sav" while your others are named iteratively "continue_1.sav" etc. Everything is setting up nicely (I figured out a while loop to give the right name to docked ships), but I can't get a rename function to work! My code is this:

Code: Select all

public boolean boardShip(ShipSave ss1) {
      boolean success = false;
      File oldFile = ss1.getshipFilePath();
      File newFile = new File("continue.sav");
      if (!newFile.exists()) {
         //success = oldFile.renameTo(newFile);
         
         Path source = oldFile.toPath();
                try {
               Files.move(source, newFile.toPath());
            } catch (IOException e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
            }
         }
         
      ss1.setshipFilePath(newFile);
      return success;
   }

When I run it I get an IO error like this:

Code: Select all

"java.nio.file.FileSystemException: continue_3.sav -> continue.sav: The process cannot access the file because it is being used by another process."

The commented out renameTo method also fails. My google searches tell me that my file is locked by my program and that I may need to lock the directory, but that doesn't make any sense. Would you be able to point me in the right direction?
Thanks again Vhati!
Ice