Altering a sav file?

Anybody ever figure out how to open up a .sav file and change it?

In the Star Trek vs. Homeworld mod, the Federation AI justs stops building stuff sometimesbut I don’t know why. Anyway, I was thinking that I could save the game, switch myself to being that player in the sav file, and then see what they were doing when it locks up.

if I open it up in the editor it’s just jibberish.


I think your best bet is to put debug statements in your AI - out of interest are you using the default one or have either STC or Goliath have a custom AI?

Put in something like the following into your doai in default.lua

aitrace("-----\nStarting player: "..s_playerIndex.. " | RU: "..GetRU())

and then fill the cpu_build.lua and the races ai_build.lua with aitrace/prints to see where its getting stuck on.

(sorry that its not the answer your looking for but I think even if you cracked the save file it would be a fairly complex task in switching yourself to the AI player)


I’ve never gotten those aitrace things to actually work, have you?

Yeah the AI is new, but it’s pretty similar to the Goliath ones.

aitrace is a dummy function, its essentially a print that can be disabled so you don’t have to delete all your prints once your done debugging in case you need them again in future. All you gotta do is make it prints its argument. (its not a special homeworld function or anything)

So at the top of default.lua change aitrace = function() end to aitrace = function(str) print(str) end

Also scatter it around the SpendMoney() function in default.lua (like this roughly, extract from default homeworld AI). To get further you would also potentially want to add aitrace’s to the DoMilitaryBuild() and DoResourceBuild() functions (on the basis your AI is fairly similar to the layout of the default)

function SpendMoney()
  aitrace("Spending money")
  if (s_numOpenBuildChannels > 0) then
    aitrace("There are open build channels")
    local buildHasBeenDone = 0

    if (sg_dobuild == 1 and s_shipBuildQueuesFull == 0 and sg_reseachDemand < 0) then
      aitrace("If build queues aren't full and research demand is less than 0")
      if (CpuBuild_Process() == 1) then
        g_reseachDemand = sg_reseachDemand + 1
        buildHasBeenDone = 1

    if (sg_doresearch == 1) then
      if (CpuResearch_Process() == 1) then
        sg_reseachDemand = -sg_kDemandResetValue
      elseif (sg_reseachDemand >= 0 and sg_dobuild == 1 and s_shipBuildQueuesFull == 0 and buildHasBeenDone == 0) then
      sg_reseachDemand = -sg_kDemandResetValue

function CpuBuild_Process()
	if (Override_ShipDemand) then
	if (sg_resourceDemand > 0 or sg_militaryDemand <= 0) then
		if (DoResourceBuild()==1) then
			sg_resourceDemand = 1 - sg_militaryToBuildPerCollector
			aitrace("Built resource related ship")
			return 1
	aitrace("Military demand: "..sg_militaryDemand)
	if (sg_militaryDemand > 0) then
		if (DoMilitaryBuild()==1) then
			if(sg_resourceDemand <= 0) then
				sg_resourceDemand = sg_resourceDemand + 1
			aitrace("Built military related ship")
			return 1
	return 0

If you wanna chat about it a bit quicker on the Homeworld Universe discord hwrm-modding chat we can do :slight_smile: there are also a bunch of other brainer people than me who could potentially help!

NEATO! I’m gonna try it out over the weekend and I’ll let you know how it goes.

Thanks a lot!

I have a feeling @b8factor did this - I think remember him saying that he would play his mission as the human player and then switch to the CPU player to see how they were behaving…

Save games are a lot more legible if you unzip them, but are still kind of a big mess. There’s stuff in there that is not plaintext. Also lots of weird ASCII like the NULL character. Unless there’s some type of hash they might be editable however.

ah yeah, I just checked it out unzipped. There’s some pretty wild stuff in there that I totally wouldn’t have thought that they need. But yeah, that looks like it might be kind of a pain in the butt to change around. Unless somebody already knows how to do it. Maybe the file can be opened for real by a different program.

I’ll try out the AI trace thing instead.

I’m kind of surprised now thinking about it that no one created a save game editor for HWRM or HW2C. Normally, in video games, that’s one of the first tools that gets written!

I’ve got it working! Thanks! Oh man, this is gonna be FUN =D

Is there a way to get the player designation into the messages?

I tried this, which I got out of Main.lua and tryied to put into the Hiigaran aibuild just to see if I can get it to work:

	local playerNameWH = Player_GetName(playerIndex)
	stcgtrace("STCG-trace:This is from the hig aibuild function DetermineSpecialDemand_Hiigaran - the player is: "..playerNameWH.." ")

the function is stcgtrace just so I can keep my new stuff separate from the existing aitrace.

But I get this error in the HwRM file:

parameter: attempt to call global `Player_GetName’ (a nil value)

I kinda need to know who it is because the problem I’m having doesn’t affect all of the players; it’s usually just one guy in a game of 3 CPUs against 3 CPUs

Thanks again! I was trying to get that thing to work forever.

Glad you got it working :smiley:

For your error use s_playerIndex instead of playerIndex, there is also a chance Player_GetName is only available in the leveldata scope for whatever reason. From memory s_playerIndex should be ordered correctly with the lobby. An image for example:

1 Like

I thought the slot # was important? Or does that only have to do with maps?

This is TOTALLY working btw. I’ll write a longer response with some examples when I get a little time, but this is seriously a GOLD MINE!!

Thanks a lot!