Saving game states from importer

I’ve got a method to save the game state in the ADC2 importer. Right now for example, I cannot set the starting rotation for a unit in the module editor (everything in the importer works with the buildComponents tree directly so far).

The method to save states that doesn’t work is below. I cannot see why this is different from a regular save game call as it is almost verbatim from the GameState class. All of the game components are present when this is called–this is the last method called before the importer exits. I don’t want anyone to debug this for me, but if anyone can think off the tops of their heads why this is just not going to work this way, I’d be very glad of a hint (however, see the comment above the method).

As it stands, I’m going to abandon this approach for now as modifying the buildComponents tree directly works for about 95% of what I want to do, but so far, changing states is completely undoable for building modules from the exporter.

// TODO: This doesn't work the way I want.
// GameState returns NULL if the save game menu is disabled.
// however, if you comment that out, it still doesn't work. The saved game
// file results in nothing useable.
// It also ends up being wildly redundant with the rest of the module.
protected void writeSetupStacksToGameState(GameModule gameModule) throws IOException {
	ByteArrayOutputStream out = new ByteArrayOutputStream();
	ZipOutputStream zip = new ZipOutputStream(out);
	zip.setLevel(9);
	zip.putNextEntry(new ZipEntry(GameState.SAVEFILE_ZIP_ENTRY));
	Command restore = gameModule.getGameState().getRestoreCommand();		
	String save = gameModule.encode(restore);
	new Obfuscator(save.getBytes("UTF-8")).write(zip);
	zip.closeEntry();
	zip.close();		
	gameModule.getArchiveWriter().addFile(SETUP_NAME, out.toByteArray());
	
	PredefinedSetup setup = new PredefinedSetup();
	setup.build(null);
	setup.addTo(gameModule);
	gameModule.add(setup);
	setup.setConfigureName("Start game");
	setup.setAttribute(PredefinedSetup.USE_FILE, Boolean.TRUE);
	setup.setAttribute(PredefinedSetup.FILE, SETUP_NAME);
}

In response to my own e-mail, I think I’ve mostly solved the problem, but I’ve created a number of bugs in the importer that I still have to fix. The trick is to call setup(true) on all the game components and setup stacks. If it’s done in the right order, everything thinks that the game is started and the states are initialized. I had to create a method in SetupStack called forceSetup() as there are several protected methods that I cannot reach from ADC2Module.java and indicator.isNewGame() will return false no matter what I do (I don’t even see how it can ever return true). Everything else let me get away with it.

At one point I had subclassed SetupStack, but that appears to be a bad idea because of the way the class names are saved in the XML file (using a nested or anonymous classes is a big no-no as it throws a DOMException) and it didn’t seem very elegant to create a new top level class just for that purpose.

I’m asymptotically approaching 100%… Joel, doing the cyberboard importer should go a whole lot faster as this was a very steep learning curve.

  • M.

On 12/03/2008, mkiefte <messages@forums.vassalengine.org (messages@forums.vassalengine.org)> wrote:

Post generated using Mail2Forum (mail2forum.com)

I’m not sure why you’re trying to save an entire game. Don’t you want to only save the state of the SetupStacks? It sounds dangerous to me to be trying to trick the system into thinking that a game has started. Instead, you should try to build up and save a Command object that’s different from GameState.getRestoreCommand(). For example, you can build up a series of AddPiece commands, which ought to be enough to handle the SetupStacks if that’s all you’re interested in. For an example, look at the code in the Deck class for writing a deck to a file.

rk

Post generated using Mail2Forum (mail2forum.com)

Hi Rodney,

The savegame is now mostly AddPiece commands surrounded by SetupCommand(false) and SetupCommand(true) as that appears to be what’s done in setup files. The easiest solution was to call setup(true) on all of the game components themselves (which includes SetupStacks) to initialize their state (but it doesn’t start the game). It’s then possible to iterate through the game components and save the restore commands. That seemed to be a reasonable solution and it seems to work perfectly. The game is never actually started, however.

I’ve tested it very extensively the last couple of days and to the best of my knowledge it works fine. I’ve tested it on roughly 20 different ADC2 modules of varying types and they’re all clear. Ultimately, the saved game is largely what you describe but the only problem was initializing the states so that there was actually something to save. I could have set the states manually, but it was a whole lot easier to let GameComponent.setup() to do it for me, as all of that information was already in the SetupStacks as attributes.

  • M.

On 13/03/2008, Rodney Kinney <rodneykinney@comcast.net (rodneykinney@comcast.net)> wrote:

Post generated using Mail2Forum (mail2forum.com)

Cool. If you find that you’re getting problems because of other game components’ startup commands sneaking into your saved game, then you can always go to iterating through the components you want explicitly.

rk

Post generated using Mail2Forum (mail2forum.com)

Thus spake “Michael Kiefte”:

The Cyberboard importer should go faster because we’ll have documentation
for the file format.

I’m really impressed by the work you’ve put into this.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Thanks!

The ADC2 format is almost fully documented as per the Java source code. I prototyped it in MATLAB and the M-files are available for browsing as well, but the Java code should surpass that soon anyway.

Do you know when we’ll see the Cyberboard code?

  • M.

Post generated using Mail2Forum (mail2forum.com)

It would appear that most components do nothing in response to setup(true). The critical ones appear to be the map-related components and the SetupStacks. I’ve looked at the code for many of the setup() methods, and they all appear to be pretty benign.

I didn’t have to create that extra method in SetupStacks – I managed to get around it.

I’m proceeding cautiously however, because the importer works very well now. Every new element that it incorporates requires a fair amount of testing. I’m going to have to figure out how JUnit works at some point.

  • M.

On 13/03/2008, Rodney Kinney <rodneykinney@comcast.net (rodneykinney@comcast.net)> wrote:


Michael Kiefte, Ph.D.
Associate Professor
School of Human Communication Disorders
Dalhousie University
Halifax, Nova Scotia, Canada
tel: +1 902 494 5150
fax: +1 902 494 5151

Post generated using Mail2Forum (mail2forum.com)

Thus spake “Michael Kiefte”:

I was wondering what you used for that. I didn’t think you were sitting
there with a hex editor…

No idea. They’ve never given a date estimate that I’ve seen.

(On the other hand, if you’re chomping at the bit to write another
converter, you could write a ZunTzu converter in a few hours, since
the format is open an straight XML.)


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Thus spake “Michael Kiefte”:

Does everything break if one of the setup methods changes to something less
benign?

Hey, now that would be something quite useful—if we had a battery of
regression tests!


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

I have a bunch of MATLAB scripts to do diffs on byte streams. As I find out more about the format, the scripts change to accomodate them.

The procedure went like this:
Open a module in ADC2.
Change something.
Find what bytes changed.
Change them in MATLAB and save.
Open in ADC2 and see what changed again.

ADC2 was also very nice about telling me what piece of information was invalid if it was out of range. There were also a number of buffer overflows present in ADC2 which helped a lot.

In MATLAB I save information in structs and then search the tree to find changes.

The only thing that threw me was the large number of bytes that do absolutely nothing. There’s also a couple of cases where a piece of info depends on two bytes that are very far apart in the file. Other than that, it’s pretty mechanistic.

Nice. I’m going to try to nail ADC2 before we’re finished with the betas. I still haven’t done hidden units, cards, or the turn counter.

  • M.

Post generated using Mail2Forum (mail2forum.com)

It’s hard to imagine what it would have to do to break it. They could throw a NullPointerException because the GameState wasn’t initialised with setup(true), but there’s nothing like that. If push came to shove, I’d write a new method in the component itself, but I haven’t had to do that.

I’m getting pretty bored looking at the same modules over and over again and you can download a bazillion ADC2 modules for free. I’ve got a multicore at work which would be perfect for this, but I’m not at work for the next couple of weeks. I’ll look into it when I get back.

  • M.

Post generated using Mail2Forum (mail2forum.com)

Thus spake “Michael Kiefte”:

I think is the first time I’ve ever seen a buffer overflow described
as beneficial by someone who was not trying to crack a system. :slight_smile:


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)