I've posted a Windows game save here.
It's much further along than the others.
Is this a process that I can execute myself to convert from Linux to Windows and back again?
Cave Story+ Linux/Windows - incompatible saves?
Started by Theon144, Dec 25 2011 10:41 AM
- Please log in to reply
22 replies to this topic
#11
06 February 2012 - 09:03 PM
#12
12 February 2012 - 11:54 AM
Offline
Administrator
![]() | "Life begins and ends with Nu." |
Join Date: 15 Jul 2007
Location:
LocationAustralia
Posts: 4,793
Age: 27
#13
12 February 2012 - 10:42 PM
This appears to work perfectly. It loaded in both CaveStory+, and CaveStory+_64. I'm not sure of the version numbers.
I loaded it up and ran around a little. What's the process involved in making this conversion?
I loaded it up and ran around a little. What's the process involved in making this conversion?
#14
14 February 2012 - 12:39 PM
Offline
Administrator
![]() | "Life begins and ends with Nu." |
Join Date: 15 Jul 2007
Location:
LocationAustralia
Posts: 4,793
Age: 27
One's a 32-bit executable, and the other a 64-bit executable.This appears to work perfectly. It loaded in both CaveStory+, and CaveStory+_64. I'm not sure of the version numbers.

Spoiler
#15
15 February 2012 - 01:39 AM
Is making this conversion something I can do myself?
#16
16 February 2012 - 01:47 PM
Offline
Administrator
![]() | "Life begins and ends with Nu." |
Join Date: 15 Jul 2007
Location:
LocationAustralia
Posts: 4,793
Age: 27
I'm not sure how to explain it, so no unfortunately. Just let me know when you are ready and I'll convert it back.

Spoiler
#17
16 February 2012 - 02:18 PM
Offline
.
![]() | "I'm sorry Mario, but your princess is in another castle." |
Join Date: 18 Oct 2011
Location:
Posts: 1,184
Age: 13
inb4 conversion tool
#18
18 February 2012 - 07:37 PM
Using the code from the conversion tool, written by Celtic Minstrel, and an application called VBinDiff I've been able to create a save game exactly identical to the one you posted.
My concern is that since I have to drop 652 bytes from the Windows game save (131104 != 130452), and I don't know what bytes are important.
Here's the code that I use:
The section where everything is listed out in the beginning could be summed up with a single copy command. It could be broken down into 3 sections, with dropping bytes at the end of each. I also need to figure out how to switch it back to a Windows game save, but I think that'll be for another day. It should be fairly easy if I can just fill the space with zeros where I dropped the bytes originally.
My concern is that since I have to drop 652 bytes from the Windows game save (131104 != 130452), and I don't know what bytes are important.
Here's the code that I use:
#!/usr/bin/python
import sys
import os
orig = file('Profile.Windows.2012-01-01.dat','rb')
new = file('Profile.new.dat','wb')
def copy(n):
new.write(orig.read(n))
def swap(n):
temp = orig.read(n)
temp2 = []
for c in temp: temp2 += c
temp2.reverse()
temp = ''.join(temp2)
new.write(temp)
#0000
copy(8) # 000-007 | header or something
copy(4) # 008-00B | current map
copy(4) # 00C-00F | current song?
#0010
copy(4) # 010-013 | horizontal pos
copy(4) # 014-017 | vertical pos
copy(4) # 018-01B | facing direction
copy(2) # 01C-01D | max HP
copy(2) # 01E-01F | whimsical star
#0020
copy(2) # 020-021 | Current HP
copy(2) # 022-023 | Unused? Possibly alignment filler
copy(4) # 024-027 | Current Weapon
copy(4) # 028-02B | Unused?
copy(4) # 02C-02F | Equipped Items
#0030
copy(4) # 030-033 | Unused?
copy(4) # 034-037 | Time
copy(4) # 038-03B | Slot 1 Weapon Type
copy(4) # 03C-03F | Slot 1 Weapon Level
#0040
copy(4) # 040-043 | Slot 1 Weapon Energy
copy(4) # 044-047 | Slot 1 Weapon Max Ammo
copy(4) # 048-04B | Slot 1 Weapon Current Ammo
copy(4) # 04C-04F | Slot 2 Weapon Type
#0050
copy(4) # 050-053 | Slot 2 Weapon Level
copy(4) # 054-057 | Slot 2 Weapon Energy
copy(4) # 058-05B | Slot 2 Weapon Max Ammo
copy(4) # 05C-05F | Slot 2 Weapon Current Ammo
#0060
copy(4) # 060-063 | Slot 3 Weapon Type
copy(4) # 064-067 | Slot 3 Weapon Level
copy(4) # 068-06B | Slot 3 Weapon Energy
copy(4) # 06C-06F | Slot 3 Weapon Max Ammo
#0070
copy(4) # 070-073 | Slot 3 Weapon Current Ammo
copy(4) # 074-077 | Slot 4 Weapon Type
copy(4) # 078-07B | Slot 4 Weapon Level
copy(4) # 07C-07F | Slot 4 Weapon Energy
#0080
copy(4) # 080-083 | Slot 4 Weapon Max Ammo
copy(4) # 084-087 | Slot 4 Weapon Current Ammo
copy(4) # 088-08B | Slot 5 Weapon Type
copy(4) # 08C-08F | Slot 5 Weapon Level
#0090
copy(4) # 090-093 | Slot 5 Weapon Energy
copy(4) # 094-097 | Slot 5 Weapon Max Ammo
copy(4) # 098-09B | Slot 5 Weapon Current Ammo
copy(4) # 09C-09F | Slot 6 Weapon Type
#00A0
copy(4) # 0A0-0A3 | Slot 6 Weapon Level
copy(4) # 0A4-0A7 | Slot 6 Weapon Energy
copy(4) # 0A8-0AB | Slot 6 Weapon Max Ammo
copy(4) # 0AC-0AF | Slot 6 Weapon Current Ammo
#00B0
copy(4) # 0B0-0B3 | Slot 7 Weapon Type
copy(4) # 0B4-0B7 | Slot 7 Weapon Level
copy(4) # 0B8-0BB | Slot 7 Weapon Energy
copy(4) # 0BC-0BF | Slot 7 Weapon Max Ammo
#00C0
copy(4) # 0C0-0C3 | Slot 7 Weapon Current Ammo
copy(4) # 0C4-0C7 | Slot 8 Weapon Type
copy(4) # 0C8-0CB | Slot 8 Weapon Level
copy(4) # 0CC-0CF | Slot 8 Weapon Energy
#00D0
copy(4) # 0D0-0D3 | Slot 8 Weapon Max Ammo
copy(4) # 0D4-0D7 | Slot 8 Weapon Current Ammo
copy(4) # 0D8-0DB | Inventory R1C1
copy(4) # 0DC-0DF | Inventory R1C2
#00E0
copy(4) # 0E0-0E3 | Inventory R1C3
copy(4) # 0E4-0E7 | Inventory R1C4
copy(4) # 0E8-0EB | Inventory R1C5
copy(4) # 0EC-0EF | Inventory R1C6
#00F0
copy(4) # 0F0-0F3 | Inventory R2C1
copy(4) # 0F4-0F7 | Inventory R2C2
copy(4) # 0F8-0FB | Inventory R2C3
copy(4) # 0FC-0FF | Inventory R2C4
#0100
copy(4) # 100-103 | Inventory R2C5
copy(4) # 104-107 | Inventory R2C6
copy(4) # 108-10B | Inventory R3C1
copy(4) # 10C-10F | Inventory R3C2
#0110
copy(4) # 110-113 | Inventory R3C3
copy(4) # 114-117 | Inventory R3C4
copy(4) # 118-11B | Inventory R3C5
copy(4) # 11C-11F | Inventory R3C6
#0120
copy(4) # 120-123 | Inventory R4C1
copy(4) # 124-127 | Inventory R4C2
copy(4) # 128-12B | Inventory R4C3
copy(4) # 12C-12F | Inventory R4C4
#0130
copy(4) # 130-133 | Inventory R4C5
copy(4) # 134-137 | Inventory R4C6
copy(4) # 138-13B | Inventory R5C1
copy(4) # 13C-13F | Inventory R5C2
#0140
copy(4) # 140-143 | Inventory R5C3
copy(4) # 144-147 | Inventory R5C4
copy(4) # 148-14B | Inventory R5C5
copy(4) # 14C-14F | Inventory R5C6
#0150
copy(4) # 150-153 | Inventory R6C1
copy(4) # 154-157 | Inventory R6C2
copy(4) # 158-15B | Slot 1 Teleporter Menu
copy(4) # 15C-15F | Slot 1 Teleporter Location
#0160
copy(4) # 160-163 | Slot 2 Teleporter Menu
copy(4) # 164-167 | Slot 2 Teleporter Location
copy(4) # 168-16B | Slot 3 Teleporter Menu
copy(4) # 16C-16F | Slot 3 Teleporter Location
#0170
copy(4) # 170-173 | Slot 4 Teleporter Menu
copy(4) # 174-177 | Slot 4 Teleporter Location
copy(4) # 178-17B | Slot 5 Teleporter Menu
copy(4) # 17C-17F | Slot 5 Teleporter Location
#0180
copy(4) # 180-183 | Slot 6 Teleporter Menu
copy(4) # 184-187 | Slot 6 Teleporter Location
copy(4) # 188-18B | Slot 7 Teleporter Menu
copy(4) # 18C-18F | Slot 7 Teleporter Location
#0190
copy(4) # 190-193 | Slot 8 Teleporter Menu
#0194
copy(4) # 194-197 | Slot 8 Teleporter Location
#0195
copy(1132) # 0196-0600 / Copy these...
orig.read(4) # Dropping 4 bytes from the end here.
#0604
copy(59288) #0604-ED9B / Copy these here
orig.read(644) # Drop 644 bytes ????
#1ED98-1FD93
copy(4091) #ED9C-FD96
copy(65533) #FD97-1FD90
orig.read(4) #Drop last four bytes
# And the remainder of the file:
#new.write(orig.read())
orig.close()
new.close()
print "--> Profile converted."I found that none of the bytes need swapped, however, there are sections which are longer. For those I simply just dropped the bytes from the end of whatever section in the Windows file. I don't know, however, if anything is stored in those bytes.The section where everything is listed out in the beginning could be summed up with a single copy command. It could be broken down into 3 sections, with dropping bytes at the end of each. I also need to figure out how to switch it back to a Windows game save, but I think that'll be for another day. It should be fairly easy if I can just fill the space with zeros where I dropped the bytes originally.
#19
19 February 2012 - 05:48 AM
Offline
Administrator
![]() | "Life begins and ends with Nu." |
Join Date: 15 Jul 2007
Location:
LocationAustralia
Posts: 4,793
Age: 27
My concern is that since I have to drop 652 bytes from the Windows game save (131104 != 130452), and I don't know what bytes are important.
This is the heart of the matter and why I didn't post any instructions or conversion tools in the first place.I don't know, however, if anything is stored in those bytes.
I'll see if I can ask tyrone for a rom map of the CS+ Profile.dat formats. Or at least a list of bytes to remove.
Edited by andwhyisit, 19 February 2012 - 05:52 AM.

Spoiler
#20
19 February 2012 - 11:15 AM
Unfortunately the save game handling in Cave Story is a bit messed up. Instead of proper serialization, it just uses something like
Everyone familiar with C structures knows that alignment is treated differently depending on the compiler used. In particular, GCC seems to use a maximum alignment of 4 bytes while MSVC uses 8 bytes.
Profile.dat starts with an array of 81 saved game states (27 mods, 3 slots each). In the Windows version, those are 1568 bytes each, while in the Linux version, the size is 1560. Finally, the total struct size is padded by an additional 4 bytes (the last 4 bytes in the file) in Windows.
Summing up, 8*81 + 4 = 652, which explains the difference.
I hope this explanation makes at least some sense. The following code should work, although I didn't have the chance to test it. I'm running Linux only at the moment. If someone could post Profile.dat from Windows, that would be very appreciated. I'm particularly interested in a Profile.dat where several of the 81 slots are filled with actual savegames, with different difficulty (easy/normal/hard) settings. A file where only the first slot has been used is not really suitable for testing.
HTH
len = sizeof(SaveData); fread(&gSaveData, 1, len, file);SaveData is a C struct consisting of lots of arrays and other structs.
Everyone familiar with C structures knows that alignment is treated differently depending on the compiler used. In particular, GCC seems to use a maximum alignment of 4 bytes while MSVC uses 8 bytes.
Profile.dat starts with an array of 81 saved game states (27 mods, 3 slots each). In the Windows version, those are 1568 bytes each, while in the Linux version, the size is 1560. Finally, the total struct size is padded by an additional 4 bytes (the last 4 bytes in the file) in Windows.
Summing up, 8*81 + 4 = 652, which explains the difference.
I hope this explanation makes at least some sense. The following code should work, although I didn't have the chance to test it. I'm running Linux only at the moment. If someone could post Profile.dat from Windows, that would be very appreciated. I'm particularly interested in a Profile.dat where several of the 81 slots are filled with actual savegames, with different difficulty (easy/normal/hard) settings. A file where only the first slot has been used is not really suitable for testing.
#!/usr/bin/python
import sys
import os
orig = file('Profile.Windows.2012-01-01.dat','rb')
new = file('Profile.new.dat','wb')
def copy(n):
new.write(orig.read(n))
for i in range(81):
copy(1540)
orig.read(4)
copy(20)
orig.read(4)
copy(160)
copy(3932)
orig.read(4)
orig.close()
new.close()HTH
Edited by simon, 03 April 2012 - 06:00 PM.
0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users













