Skip to content

Commit

Permalink
Saving: Added new save system: Flatfile_Struct
Browse files Browse the repository at this point in the history
Uses struct.pack to store blockdata and sectors.
Currently only stores blockid and position, when blocks have more attributes
they'll need to be added to the save format.
savingsystem.py: Changed tabs to spaces, as per the rest of the project
main.py: Changed launch option -nocompression to -save-mode
  • Loading branch information
Nebual committed Apr 8, 2013
1 parent 2ddfa2d commit 364d2a7
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 32 deletions.
7 changes: 2 additions & 5 deletions controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,12 +258,9 @@ def set_highlighted_block(self, block):
self.crack.delete()
self.crack = None

def save_to_file(self, compression=False):
def save_to_file(self):
if DISABLE_SAVE:
if compression:
save_world(self, game_dir, SAVE_FILENAME)
else:
save_world(self, game_dir, SAVE_FILENAME, CLASSIC_SAVE_TYPE)
save_world(self, game_dir, SAVE_FILENAME)

def on_mouse_press(self, x, y, button, modifiers):
if self.window.exclusive:
Expand Down
4 changes: 2 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def main(options):
pyglet.clock.set_fps_limit(MAX_FPS)
pyglet.app.run()
if options.disable_auto_save and options.disable_save:
window.controller.save_to_file(compression=not options.nocompression)
window.controller.save_to_file()
if options.save_config:
try:
with open(config_file, 'wb') as handle:
Expand Down Expand Up @@ -217,7 +217,7 @@ def main(options):
save_group.add_argument("-save", type=unicode, default=SAVE_FILENAME, help = "Type a name for the world to be saved as.")
save_group.add_argument("--disable-save", action="store_false", default=True, help = "Disables saving.")
save_group.add_argument("--save-config", action="store_true", default=False, help = "Saves the choices as the default config.")
save_group.add_argument("-nocompression", action="store_true", default=False, help = "Disables compression for a smaller save file.")
save_group.add_argument("-save-mode", type=int, default=2, help = "0 = Uncompressed Pickle, 1 = Compressed Pickle, 2 = Flatfile Struct (smallest, fastest)")

parser.add_argument("-seed", default=None)
options = parser.parse_args()
Expand Down
107 changes: 82 additions & 25 deletions savingsystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,100 @@
import cPickle as pickle
import zlib
import cStringIO as StringIO
import struct
import math

# Modules from this project
from model import *
from player import *
import globals

# Save types
CLASSIC_SAVE_TYPE = 0
COMPRESSED_SAVE_TYPE = 1
FLATFILE_STRUCT_SAVE_TYPE = 2
SAVE_TYPES = [CLASSIC_SAVE_TYPE, COMPRESSED_SAVE_TYPE, FLATFILE_STRUCT_SAVE_TYPE] # last is always the newest

SAVE_TYPES = [CLASSIC_SAVE_TYPE, COMPRESSED_SAVE_TYPE] # last is always the newest
structvec = struct.Struct("hhh")
structushort = struct.Struct("H")
structuchar2 = struct.Struct("BB")
structvecBB = struct.Struct("hhhBB")

def save_world(window, game_dir, world=None, save_type=COMPRESSED_SAVE_TYPE):
if world is None: world = "world"
if not os.path.exists(os.path.join(game_dir, world)):
os.makedirs(os.path.join(game_dir, world))
#window.model.items(), window.model.sectors
#Non block related data
save = (3,window.player, window.time_of_day)
pickle.dump(save, open(os.path.join(game_dir, world, "save.pkl"), "wb"))
def save_world(window, game_dir, world=None):
if world is None: world = "world"
if not os.path.exists(os.path.join(game_dir, world)):
os.makedirs(os.path.join(game_dir, world))

blocks_save = (3,window.model.items(), window.model.sectors)
pickle.dump(blocks_save, open(os.path.join(game_dir, world, "blocks.pkl"), "wb"))
#Non block related data
save = (3,window.player, window.time_of_day)
pickle.dump(save, open(os.path.join(game_dir, world, "save.pkl"), "wb"))

#blocks and sectors (window.model and window.model.sectors)
if globals.LAUNCH_OPTIONS.save_mode == FLATFILE_STRUCT_SAVE_TYPE:
blocks = window.model
with open(os.path.join(game_dir, world, "blocks.dat"), "wb", 1024*1024) as f:
f.write(struct.pack("Q",len(blocks)))
for blockpos in blocks:
f.write(structvec.pack(*blockpos) + structuchar2.pack(blocks[blockpos].id_main, blocks[blockpos].id_sub))
sectors = window.model.sectors
with open(os.path.join(game_dir, world, "sectors.dat"), "wb", 1024*1024) as f:
f.write(struct.pack("Q",len(sectors)))
for secpos in sectors:
f.write(structvec.pack(*secpos) + structushort.pack(len(sectors[secpos])))
for blockpos in sectors[secpos]:
f.write(structvec.pack(*blockpos))
elif globals.LAUNCH_OPTIONS.save_mode == COMPRESSED_SAVE_TYPE:
worldsave = (window.model.items(), window.model.sectors)
save_string = zlib.compress(pickle.dumps(worldsave), 9)
file = open(os.path.join(game_dir, world, "blocks.pkl"), "wb")
file.write(struct.pack("B", 1)) #Save Version
file.write(save_string)
file.close()
elif globals.LAUNCH_OPTIONS.save_mode == CLASSIC_SAVE_TYPE:
worldsave = (window.model.items(), window.model.sectors)
save_string = pickle.dumps(worldsave)
file = open(os.path.join(game_dir, world, "blocks.pkl"), "wb")
file.write(struct.pack("B", 0)) #Save Version
file.write(save_string)
file.close()

def world_exists(game_dir, world=None):
if world is None: world = "world"
return os.path.lexists(os.path.join(game_dir, world))
if world is None: world = "world"
return os.path.lexists(os.path.join(game_dir, world))

def open_world(gamecontroller, game_dir, world=None):
if world is None: world = "world"
loaded_world = pickle.load(open(os.path.join(game_dir, world, "blocks.pkl"), "rb"))

gamecontroller.model = Model(initialize=False)
for item in loaded_world[0]:
gamecontroller.model[item[0]] = item[1]
gamecontroller.model.sectors = loaded_world[1]

loaded_save = pickle.load(open(os.path.join(game_dir, world, "save.pkl"), "rb"))
if loaded_save[0] == 3: #Version 3
if isinstance(loaded_save[1], Player): gamecontroller.player = loaded_save[1]
if isinstance(loaded_save[2], float): gamecontroller.time_of_day = loaded_save[2]
if world is None: world = "world"
gamecontroller.model = Model(initialize=False)

#Non block related data
loaded_save = pickle.load(open(os.path.join(game_dir, world, "save.pkl"), "rb"))
if loaded_save[0] == 3: #Version 3
if isinstance(loaded_save[1], Player): gamecontroller.player = loaded_save[1]
if isinstance(loaded_save[2], float): gamecontroller.time_of_day = loaded_save[2]
#blocks and sectors (window.model and window.model.sectors)
if globals.LAUNCH_OPTIONS.save_mode == FLATFILE_STRUCT_SAVE_TYPE:
sectors = gamecontroller.model.sectors
with open(os.path.join(game_dir, world, "sectors.dat"), "rb") as f:
for i in xrange(struct.unpack("Q",f.read(8))[0]):
sector = sectors[structvec.unpack(f.read(6))]
for i2 in xrange(structushort.unpack(f.read(2))[0]):
sector.append(structvec.unpack(f.read(6)))
blocks = gamecontroller.model
with open(os.path.join(game_dir, world, "blocks.dat"), "rb") as f:
for i in xrange(struct.unpack("Q",f.read(8))[0]):
bx, by, bz, blockid, dataid = structvecBB.unpack(f.read(8))
if dataid is not 0: blockid += (blockid / 10**math.ceil(math.log10(dataid)))
blocks[(bx,by,bz)] = BLOCKS_DIR[blockid]
else:
file = open(os.path.join(game_dir, world, "blocks.pkl"), "rb")
fileversion = struct.unpack("B",file.read(1))[0]
if fileversion == COMPRESSED_SAVE_TYPE:
loaded_world = pickle.load(StringIO.StringIO(zlib.decompress(file.read())))
for item in loaded_world[0]:
gamecontroller.model[item[0]] = item[1]
gamecontroller.model.sectors = loaded_world[1]
elif fileversion == CLASSIC_SAVE_TYPE:
loaded_world = pickle.load(file)
for item in loaded_world[0]:
gamecontroller.model[item[0]] = item[1]
gamecontroller.model.sectors = loaded_world[1]

0 comments on commit 364d2a7

Please sign in to comment.