[Game]MicroCity colour edition [WIP]

Here is the general idea of my saving/loading process (with functions/variables renamed for clarity). It’s probably best not to follow some of my style preferences, but hopefully this can help. This isn’t enough to compile as-is, but it should have all the important pieces:

/* Required include files */
#include "SDFileSystem.h"
#include "FATFileHandle.h"

/* My custom save error codes, for debugging */
#define SAVE_ERR_NONE 0
#define SAVE_ERR_CDIR 1
#define SAVE_ERR_OPEN 2
uint8_t save_errno;

SDFileSystem *sd;
FATFileHandle *fp;
DirHandle *dh;

/* Where you actually save your save files */
const char save_dir[] = "/save_directory_name_goes_here";

void initialization_code(){
...
  sd = new SDFileSystem(P0_9, P0_8, P0_6, P0_7, "sd");
  sd->mount();
  sd->mkdir(save_dir, 0777);
...
}

/* Try to open file for saving.  If attempt fails, retry one more time and if
    it still fails give up.  This retry allows for a more elegant recovery from an
    accidentally removed SD card, as removing the SD card will result in an error
    even if it has been re-inserted before attempting to save. */
bool openSave(const char* name){
  fp = (FATFileHandle*) sd->open(name, O_WRONLY | O_CREAT);
  if( fp == NULL ){
    /* Try to re-initialize SD card connection */
    sd->unmount();
    sd->mount();
    /* Try once more */
    if( (fp = (FATFileHandle*) sd->open(name, O_WRONLY | O_CREAT)) != NULL ){
      save_errno = SAVE_ERR_NONE;
      return true;
    }
    save_errno = SAVE_ERR_OPEN;
    return false;
  }
  save_errno = SAVE_ERR_NONE;
  return true;
}

void writeSave(uint8_t* start, uint16_t len){
  fp->write(start, len);
}

void closeSave(){
  fp->close();
}

/* I have less error handling for loading, but you could probably use almost the
    same code as for saving to have better error handling.  I just wasn't as worried
    about a failed load and I haven't bothered to update and test it. */
bool openLoad(const char* name){
  fp = (FATFileHandle*) sd->open(name, O_RDONLY);
  if( fp == NULL ){
    return false;
  }
  return true;
}

void readLoad(uint8_t* start, uint16_t len){
  fp->read(start, len);
}

void closeLoad(){
  fp->close();
}

And here’s an example snippet using the save/load code, with some of my code that I use to create versions of my save data in case I make incompatible changes:

uint8_t save_version[] = "HEADER BYTES INDICATING VERSION GO HERE";

bool save_game(){
  if( !openSave("SAVE FILE FILENAME") ){
    return false;
  }
  writeSave(save_version,sizeof(save_version));
  writeSave(&GAME_DATA_TO_SAVE,sizeof(GAME_DATA_TO_SAVE));
  closeSave();
  return true;
}

bool load_game(){
  uint8_t load_version[] = {0,0,0,0,...};
  /* Check if file can be opened */
  if( !openLoad("SAVE FILE FILENAME") ){
    return false;
  }
  readLoad(load_version, sizeof(save_version));
  /* Verify version matches.  If not, do not load. */
  if( strncmp((char*)save_version,(char*)load_version,sizeof(save_version)) != 0 ){
    closeLoad();
    return false;
  }
  readLoad(&GAME_DATA_TO_LOAD,sizeof(GAME_DATA_TO_LOAD));
  closeLoad();
  return true;
}

Some of the wrapper functions (like writeSave and closeSave) exist because they are actually part of an abstraction layer I wrote to keep all platform-specific code in one file per platform, so you don’t necessarily need to have those wrappers in your version. I think this example would require more changes and polish to be a proper tutorial, and I don’t feel like I should recommend the way I personally prefer to code, which is why I hadn’t considered making a tutorial about this before. This should hopefully be enough to get things working, though.

4 Likes

Thanks for the detailed explanation and code example, this will be very helpful!

4 Likes

Saving the city would be a very much needed feature! :+1:

1 Like

There is now a new release on the Github page. It has SD card save / load support and has all the tiles fully coloured now.

There is some strange behaviour: my Pokitto squeaks briefly when I save the game. Odd!

I also did try a high resolution mode and I optimised the rendering so that it runs smoothly enough. However the compiler complains about RAM usage if I try to use high resolution mode and SD card loading in the same build. What is the easiest way to get a dump of where all the RAM usage is? The game itself should only be using ~1KB of RAM + any stack usage so I was quite surprised to be so close to the limit.

3 Likes

This is a known feature of Pokittos :grimacing: :joy: :blush:

5 Likes

I like to think of it as the Pokitto happily dooting a little tune as it works to get everything ready. The poor thing is a little tone deaf but it sure tries it’s best :grin:

5 Likes

I just played this for a bit, and it looks great, especially the water tiles. I managed to make a pretty big city by aggressively zoning as fast as possible without changing taxes, but I started getting rolling blackouts (I assume because everybody was using too much power). However, when I place a second power plant, the game completely freezes. Here is my save file. If I place a power plant in the space in the top right, it freezes every time.

MICROCITY.SAV (1.4 KB)

2 Likes

I think that this is an array out of bounds / memory stomp. I can fix this in the next release

3 Likes

Saving works fine! Now I can finally develop my city over time…:slight_smile:

5 Likes

@wuuff I managed to track down the bug you were experiencing thanks to your save game! I’ve made a fix and there is a new beta build release on the github releases page. This bug actually affects the Arduboy version too so I’ll have to go back and fix it!

I think the port is pretty much down now: I just need to package it up in a .pop file

5 Likes

https://felipemanga.github.io/mkpop/

3 Likes

Could someone please upload a .pop version of the last release? That would be awesome. I can`t find a .bin on the github page

Not sure if anyone ever made a .pop of this one

Hmm, you’re right, the latest release doesn’t have an included bin. However, it looks like @jhhoward pushed an updated bin with their latest commit here. I haven’t tested it, but that’s probably the bin for v0.4, the most recent tagged version.