revision of savedata
authorhgn <hgodden00@gmail.com>
Mon, 24 Jul 2023 07:05:34 +0000 (08:05 +0100)
committerhgn <hgodden00@gmail.com>
Mon, 24 Jul 2023 07:05:34 +0000 (08:05 +0100)
12 files changed:
addon.h
build.c
ent_skateshop.c
save.c
save.h
skaterift.c
skaterift.h
world.c
world.h
world_entity.c
world_entity.h
world_load.c

diff --git a/addon.h b/addon.h
index 691046da23299929ae749c1cd5123006f14f5cb9..6dda8a8bdb3347454d3a3d88a468a65920e876f5 100644 (file)
--- a/addon.h
+++ b/addon.h
@@ -73,7 +73,7 @@ static addon_system;
 
 static void addon_system_init( void );
 static u32 addon_count( enum addon_type type );
-static addon_reg *get_addon_from_index(enum addon_type type, u32 index);
+static addon_reg *get_addon_from_index( enum addon_type type, u32 index );
 static u32 get_index_from_addon( enum addon_type type, addon_reg *a );
 static int addon_get_content_folder( addon_reg *reg, vg_str *folder );
 
diff --git a/build.c b/build.c
index 154c4744f306b402c3bf54d2f2f00e7bda5f6874..f504e10f528622bca1c5ee3dcb7e762af123c87b 100644 (file)
--- a/build.c
+++ b/build.c
@@ -81,6 +81,7 @@ void build_game( enum compiler compiler )
    vg_build_symbolic_link( "sound_src", "sound" );
    vg_build_symbolic_link( "playermodels_src", "playermodels" );
    vg_build_syscall( "mkdir -p %s/cfg", vg_compiler.build_dir );
+   vg_build_syscall( "mkdir -p %s/savedata", vg_compiler.build_dir );
 
    vg_build_syscall( "mkdir -p %s/tools", vg_compiler.build_dir );
    vg_build_syscall( "cp blender_export.py %s/tools/", vg_compiler.build_dir );
index 44a669abee8f43288e03d54073cacb12dbac4f7e..1b10153d6404efff08751f4f1c09007e8952067c 100644 (file)
@@ -252,7 +252,7 @@ VG_STATIC void global_skateshop_preupdate(void){
          localplayer.board_view_slot = cache_id;
 
          global_skateshop_exit();
-         skaterift_write_main_savedata();
+         skaterift_autosave(1);
          return;
       }
    }
diff --git a/save.c b/save.c
index 094095ca4dbbcba5931c94d2d19cd20532e2cc4e..ed869e67af7aa031f7b332fb063657a2cdd21171 100644 (file)
--- a/save.c
+++ b/save.c
@@ -2,29 +2,39 @@
 #define SAVE_C
 
 #include "save.h"
+#include "addon.h"
 #include "vg/vg_msg.h"
+#include "vg/vg_log.h"
+#include "world.h"
 
-static void savedata_write_thread( void *file ){
-   struct savedata *sav = file;
+static void savedata_file_write( savedata_file *file ){
+   savedata_file *sav = file;
    FILE *fp = fopen( sav->path, "wb" );
    if( fp ){
       fwrite( sav->buf, sav->len, 1, fp );
       fclose( fp );
+      vg_success( "savedata written to '%s'\n", sav->path );
    }
    else {
       vg_error( "Error writing savedata (%s)\n", sav->path );
    }
 }
 
-static void savedata_read( struct savedata *sav ){
-   FILE *fp = fopen( sav->path, "rb" );
+static void savedata_group_write( savedata_group *group ){
+   for( u32 i=0; i<group->file_count; i++ ){
+      savedata_file_write( &group->files[i] );
+   }
+}
+
+static void savedata_file_read( savedata_file *file ){
+   FILE *fp = fopen( file->path, "rb" );
    if( fp ){
-      sav->len = fread( sav->buf, 1, sizeof(sav->buf), fp );
+      file->len = fread( file->buf, 1, sizeof(file->buf), fp );
       fclose( fp );
    }
    else{
-      sav->len = 0;
-      vg_warn( "Error reading savedata (%s)\n", sav->path );
+      file->len = 0;
+      vg_warn( "Error reading savedata (%s)\n", file->path );
    }
 }
 
@@ -51,7 +61,6 @@ static void skaterift_write_viewslot( vg_msg *msg, const char *key,
 static void skaterift_read_addon_alias( vg_msg *msg, const char *key,
                                         enum addon_type type, 
                                         addon_alias *alias ){
-   
    alias->foldername[0] = '\0';
    alias->workshop_id = 0;
    alias->type = type;
@@ -65,47 +74,109 @@ static void skaterift_read_addon_alias( vg_msg *msg, const char *key,
       alias->workshop_id = vg_msg_read_as_u64( &kv );
 }
 
-static void skaterift_write_main_savedata(void){
-   if( !vg_loader_availible() ) return;
+static void skaterift_populate_world_savedata( savedata_file *file,
+                                              enum world_purpose which ){
+   file->path[0] = '\0';
+   file->len = 0;
+   addon_reg *reg = NULL;
+   if( which == k_world_purpose_hub ) reg = world_static.addon_hub;
+   else reg = world_static.addon_client;
+
+   if( !reg ){
+      vg_error( "Tried to save unspecified world (reg was null)\n" );
+      return;
+   }
 
-   vg_linear_clear( vg_async.buffer );
-   struct savedata *sav = vg_linear_alloc( vg_async.buffer, 
-                                           vg_align8(sizeof(struct savedata)) );
+   skaterift_world_get_save_path( which, file->path );
+
+   vg_msg sav = {0};
+   sav.buf = file->buf;
+   sav.max = sizeof(file->buf);
+
+   if( which == k_world_purpose_hub ){
+      if( world_static.instances[0].status == k_world_status_loaded )
+         world_entity_serialize( &world_static.instances[0], &sav );
+   }
+   else {
+      for( u32 i=1; i<vg_list_size(world_static.instances); i++ ){
+         world_instance *instance = &world_static.instances[i];
+         if( instance->status == k_world_status_loaded ){
+            world_entity_serialize( instance, &sav );
+         }
+      }
+   }
+
+   file->len = sav.len;
+}
 
-   strcpy( sav->path, "save.bkv" );
+static void skaterift_populate_main_savedata( savedata_file *file ){
+   strcpy( file->path, str_skaterift_main_save );
 
-   vg_msg kvsav = {0};
-   kvsav.buf = sav->buf;
-   kvsav.max = sizeof(sav->buf);
+   vg_msg sav = {0};
+   sav.buf = file->buf;
+   sav.max = sizeof(file->buf);
 
-   vg_msg_frame( &kvsav, "player" );
+   vg_msg_frame( &sav, "player" );
    {
-      skaterift_write_viewslot( &kvsav, "board", k_addon_type_board, 
+      skaterift_write_viewslot( &sav, "board", k_addon_type_board, 
                                 localplayer.board_view_slot );
-      skaterift_write_viewslot( &kvsav, "playermodel", k_addon_type_player,
+      skaterift_write_viewslot( &sav, "playermodel", k_addon_type_player,
                                 localplayer.playermodel_view_slot );
    }
-   vg_msg_end_frame( &kvsav );
+   vg_msg_end_frame( &sav );
 
-   vg_msg_frame( &kvsav, "world" );
+   vg_msg_frame( &sav, "world" );
    {
       addon_reg *reg = world_static.addon_client;
       if( reg && (world_static.active_instance > 0) ){
-         skaterift_write_addon_alias( &kvsav, "alias", &reg->alias );
-         vg_msg_wkvu32( &kvsav, "index", world_static.active_instance );
-         vg_msg_wkvnum( &kvsav, "position", k_vg_msg_float|k_vg_msg_32b, 3, 
+         skaterift_write_addon_alias( &sav, "alias", &reg->alias );
+         vg_msg_wkvu32( &sav, "index", world_static.active_instance );
+         vg_msg_wkvnum( &sav, "position", k_vg_msg_float|k_vg_msg_32b, 3, 
                         localplayer.rb.co );
       }
    }
-   vg_msg_end_frame( &kvsav );
+   vg_msg_end_frame( &sav );
+
+   file->len = sav.len;
+}
+
+static int skaterift_autosave( int async ){
+   if( async )
+      if( !vg_loader_availible() ) return 0;
+
+   u32 save_files = 2;
+   if( world_static.addon_client )
+      save_files ++;
+
+   vg_linear_clear( vg_async.buffer );
+   u32 size = sizeof(savedata_group) + sizeof(savedata_file) * save_files;
+
+   savedata_group *group;
+   if( async ){
+      size = vg_align8( size );
+      group = vg_linear_alloc( vg_async.buffer, size );
+   }
+   else
+      group = alloca( size );
+
+   group->file_count = save_files;
+   skaterift_populate_main_savedata( &group->files[0] );
+   skaterift_populate_world_savedata( &group->files[1], k_world_purpose_hub );
+
+   if( world_static.addon_client )
+      skaterift_populate_world_savedata( &group->files[2], 
+                                          k_world_purpose_client );
+
+   if( async )
+      vg_loader_start( (void *)savedata_group_write, group );
+   else
+      savedata_group_write( group );
 
-   sav->len = kvsav.len;
-   vg_loader_start( savedata_write_thread, sav );
+   return 1;
 }
 
-static void skaterift_read_main_savedata( struct savedata *sav ){
-   strcpy( sav->path, "save.bkv" );
-   savedata_read( sav );
+static void skaterift_autosave_synchronous(void){
+   skaterift_autosave(0);
 }
 
 #endif /* SAVE_C */
diff --git a/save.h b/save.h
index 25b9548cd571d4bb8bcf010ffbf740ecb3560761..941dd12769f659f035748c3accf9e7ff98431bd8 100644 (file)
--- a/save.h
+++ b/save.h
@@ -3,17 +3,27 @@
 
 #include "vg/vg_stdint.h"
 
-struct savedata {
-   char path[128];
-   u8  buf[1024];
-   u32 len;
+static const char *str_skaterift_main_save = "save.bkv";
+static f64 skaterift_last_autosave = 0.0;
+
+typedef struct savedata_file savedata_file;
+typedef struct savedata_group savedata_group;
+
+struct savedata_group {
+   u32 file_count;
+   struct savedata_file {
+      char path[128];
+      u8  buf[1024];
+      u32 len;
+   }
+   files[];
 };
 
-#include "ent_skateshop.h"
+static void savedata_file_read( savedata_file *file );
+static void savedata_file_write( savedata_file *file );
+static void savedata_group_write( savedata_group *group );
 
-static void savedata_read( struct savedata *sav );
-static void savedata_write_thread( void *file );
+//static void skaterift_read_main_save( savedata_file *sav );
+static int skaterift_autosave(int async);
 
-static void skaterift_read_main_savedata( struct savedata *sav );
-static void skaterift_write_main_savedata(void);
 #endif /* SAVE_H */
index c9afd0b4ef6e2f5fe84a6b41670b79f650418cc9..5804a3d647c3604072989d5e6a6b236fe6cc92ae 100644 (file)
@@ -95,8 +95,10 @@ static void async_call_ready( void *payload, u32 size ){
 }
 
 static void skaterift_restore_state(void){
-   struct savedata sav;
-   skaterift_read_main_savedata( &sav );
+   savedata_file sav;
+   strcpy( sav.path, str_skaterift_main_save );
+   savedata_file_read( &sav );
+
    vg_msg kvsav = {0};
    kvsav.buf = sav.buf;
    kvsav.len = sav.len;
@@ -257,7 +259,7 @@ VG_STATIC void vg_load(void){
 
    /* and now */
    skaterift_restore_state();
-   vg_loader_step( NULL, skaterift_write_main_savedata );
+   vg_loader_step( NULL, skaterift_autosave_synchronous );
 
    board_processview_thread(NULL);
    vg_async_call( async_call_ready, NULL, 0 );
@@ -337,6 +339,12 @@ VG_STATIC void vg_post_update(void){
    audio_unlock();
 
    vehicle_update_post();
+
+   if( vg.time - skaterift.last_autosave > 20.0 ){
+      if( skaterift_autosave(1) ){
+         skaterift.last_autosave = vg.time;
+      }
+   }
 }
 
 /*
index 319efa503c5bf8b0f1c3f071cc9d0b612fd19c78..fd5953766091b6a60de4fc5608620028b0bc2477 100644 (file)
@@ -52,6 +52,8 @@ struct{
       k_skaterift_menu       = 0x04
    }
    activity;
+
+   f64 last_autosave;
 }
 static skaterift = { .op = k_async_op_clientloading, .time_rate = 1.0f };
 
diff --git a/world.c b/world.c
index 0612644bb305b2a49a9c0f7d93a59210b30fd7e2..c3b55163110fe686905d99ba31e0d878719a9ad8 100644 (file)
--- a/world.c
+++ b/world.c
@@ -26,6 +26,21 @@ static void world_init(void)
                                                    VG_MEMORY_SYSTEM );
 }
 
+static void skaterift_world_get_save_path( enum world_purpose which, 
+                                           char buf[128] ){
+   addon_reg *reg;
+
+   if( which == k_world_purpose_hub ) reg = world_static.addon_hub;
+   else reg = world_static.addon_client;
+
+   assert( reg );
+
+   char id[76];
+   addon_alias_uid( &reg->alias, id );
+   snprintf( buf, 128, "savedata/%s.bkv", id );
+}
+
+
 #include "world_entity.c"
 #include "world_gate.c"
 #include "world_gen.c"
diff --git a/world.h b/world.h
index c412a88097cc3bb98ba044f0a08df45c4dc49764..4da3791969609b9d12742a6e64d783aaa01c15c7 100644 (file)
--- a/world.h
+++ b/world.h
@@ -16,8 +16,17 @@ enum world_geo_type{
    k_world_geo_type_water = 2
 };
 
+enum world_purpose{
+   k_world_purpose_hub,
+   k_world_purpose_client
+}
+purpose;
+
 typedef struct world_instance world_instance;
 
+static void skaterift_world_get_save_path( enum world_purpose which, 
+                                           char buf[128] );
+
 /* submodule headers */
 #include "world_entity.h"
 #include "world_gate.h"
index 7ffa1d643012493f53637131e86446284f935ff5..b95961df49060157c39361bde609f4d9b7ff0195 100644 (file)
@@ -6,6 +6,7 @@
 #include "world.h"
 #include "world_load.h"
 #include "save.h"
+#include "vg/vg_msg.h"
 
 VG_STATIC void world_gen_entities_init( world_instance *world ){
    /* lights */
@@ -439,8 +440,7 @@ VG_STATIC void entity_bh_closest( void *user, u32 item_index, v3f point,
    }
 }
 
-VG_STATIC void world_entity_start( world_instance *world, 
-                                   struct savedata *sav ){
+VG_STATIC void world_entity_start( world_instance *world, vg_msg *sav ){
    vg_info( "Start instance %p\n", world );
 
    world->probabilities[ k_probability_curve_constant ] = 1.0f;
@@ -454,10 +454,31 @@ VG_STATIC void world_entity_start( world_instance *world,
          entity_call( world, &call );
       }
    }
+
+   /* read savedata 
+    * ----------------------------------------------------------------------- */
+
+   for( u32 i=0; i<mdl_arrcount(&world->ent_unlock); i++ ){
+      ent_unlock *unlock = mdl_arritm( &world->ent_unlock, i );
+      const char *alias = mdl_pstr( &world->meta, unlock->pstr_alias );
+
+      if( vg_msg_seekkvu32( sav, alias, k_vg_msg_first ) ){
+         ent_call call;
+         call.data = NULL;
+         call.function = 0;
+         call.id = mdl_entity_id( k_ent_unlock, i );
+         entity_call( world, &call );
+      }
+   }
 }
 
-VG_STATIC void async_world_entity_start( void *payload, u32 size ){
+VG_STATIC void world_entity_serialize( world_instance *world, vg_msg *sav ){
+   for( u32 i=0; i<mdl_arrcount(&world->ent_unlock); i++ ){
+      ent_unlock *unlock = mdl_arritm(&world->ent_unlock,i);
 
+      const char *alias = mdl_pstr(&world->meta,unlock->pstr_alias);
+      vg_msg_wkvu32( sav, alias, unlock->status );
+   }
 }
 
 #endif /* WORLD_ENTITY_C */
index 63cab47673e075f9c237c9032d36303abf414d91..c3af72a398d4e717bf986e81322aa9555645df73 100644 (file)
@@ -5,14 +5,15 @@
 #include "entity.h"
 #include "bvh.h"
 #include "save.h"
+#include "vg/vg_msg.h"
 
 VG_STATIC void world_gen_entities_init( world_instance *world );
 VG_STATIC ent_spawn *world_find_spawn_by_name( world_instance *world, 
                                                const char *name );
 VG_STATIC ent_spawn *world_find_closest_spawn( world_instance *world, 
                                                v3f position );
-VG_STATIC void world_entity_start( world_instance *world,
-                                   struct savedata *sav );
+VG_STATIC void world_entity_start( world_instance *world, vg_msg *sav );
+VG_STATIC void world_entity_serialize( world_instance *world, vg_msg *sav );
 
 VG_STATIC void ent_volume_call( world_instance *world, ent_call *call );
 VG_STATIC void ent_audio_call( world_instance *world, ent_call *call );
index 0b96ad8cd0a83b42c144f6d0e8921e0cb67fb31a..25d5b048af77274107d03d9b1e7e082a7cdf14fc 100644 (file)
@@ -7,6 +7,7 @@
 #include "ent_skateshop.h"
 #include "addon.h"
 #include "save.h"
+#include "vg/vg_msg.h"
 
 /* 
  * load the .mdl file located in path as a world instance
@@ -99,27 +100,28 @@ VG_STATIC void world_instance_load_mdl( u32 instance_id, const char *path ){
 
 
 struct world_load_complete_data{
-   struct savedata save;
+   savedata_file save;
    u32 instance_start, instance_count;
 };
 
 static void skaterift_world_load_done( void *payload, u32 size ){
    struct world_load_complete_data *data = payload;
 
+   vg_msg sav = {0};
+   sav.buf = data->save.buf;
+   sav.len = data->save.len;
+   sav.max = data->save.len;
+
    for( u32 i=0; i<data->instance_count; i++ ){
       world_instance *world = &world_static.instances[ data->instance_start+i ];
-      world_entity_start( world, &data->save );
+      world_entity_start( world, &sav );
    }
 
    world_static.load_state = k_world_loader_none;
 }
 
 struct world_load_args {
-   enum world_purpose{
-      k_world_purpose_hub,
-      k_world_purpose_client
-   }
-   purpose;
+   enum world_purpose purpose;
    addon_reg *reg;
 };
 
@@ -218,9 +220,9 @@ static void skaterift_world_load_thread( void *_args ){
    struct world_load_complete_data *data = final_call->payload;
    data->instance_start = instance_start;
    data->instance_count = instance_count;
-   strcpy( data->save.path, "temp_fuckyou.bkv" );
 
-   savedata_read( &data->save );
+   skaterift_world_get_save_path( purpose, data->save.path );
+   savedata_file_read( &data->save );
 
    vg_async_dispatch( final_call, skaterift_world_load_done );
    vg_async_stall();
@@ -266,6 +268,7 @@ static void skaterift_change_world_start( addon_reg *reg ){
       char buf[76];
       addon_alias_uid( &reg->alias, buf );
       vg_info( "switching to: %s\n", buf );
+      skaterift_autosave(1);
 
       world_static.load_state = k_world_loader_preload;
 
@@ -279,8 +282,6 @@ static void skaterift_change_world_start( addon_reg *reg ){
          if( inst->status == k_world_status_loaded ){
             inst->status = k_world_status_unloading;
             world_fadeout_audio( inst );
-
-            /* TODO: THIS IS WHERE A SAVE SHOULD BE DONE */
          }
       }
 
@@ -311,12 +312,6 @@ static int skaterift_change_world_command( int argc, const char *argv[] ){
    return 0;
 }
 
-#if 0
-static world_instance *world_loading_instance(void){
-   return &world_static.instances[ world_loader.world_index ];
-}
-#endif
-
 /* 
  * checks:
  *  1. to see if all audios owned by the world have been stopped