semantics and world reloading
authorhgn <hgodden00@gmail.com>
Thu, 18 May 2023 01:57:52 +0000 (02:57 +0100)
committerhgn <hgodden00@gmail.com>
Thu, 18 May 2023 01:57:52 +0000 (02:57 +0100)
15 files changed:
audio.h
blender_export.py
ent_skateshop.c
entity.h
maps_src/mp_gridmap.mdl
maps_src/mp_mtzero.mdl
maps_src/mp_spawn.mdl
skaterift.c
skaterift.h [new file with mode: 0644]
workshop.c
workshop.h
world.h
world_gate.h
world_gen.h
world_render.h

diff --git a/audio.h b/audio.h
index e6e76bdd22d5940a1ffb3beff528485d06b4854a..c07f0d15912ace5cb90eca6bcb1a6f09c8e767b3 100644 (file)
--- a/audio.h
+++ b/audio.h
@@ -173,12 +173,12 @@ enum audio_sprite_type
 VG_STATIC void audio_ambient_sprite_play( v3f co, audio_clip *clip )
 {
    audio_lock();
-   u32 channel_id = 31342352;
-   audio_channel *ch = audio_get_group_idle_channel( channel_id, 4 );
+   u16 group_id = 0xfff0;
+   audio_channel *ch = audio_get_group_idle_channel( group_id, 4 );
 
    if( ch ){
       audio_channel_init( ch, clip, AUDIO_FLAG_SPACIAL_3D );
-      audio_channel_group( ch, channel_id );
+      audio_channel_group( ch, group_id );
       audio_channel_set_spacial( ch, co, 80.0f );
       audio_channel_edit_volume( ch, 1.0f, 1 );
       ch = audio_relinquish_channel( ch );
index 3e6bb108853a4af2d38d0323e2c1812dfcf58397..cc51987624c7c05e1408d6747f0b5a91333b8db0 100644 (file)
@@ -186,6 +186,7 @@ class ent_gate(Structure):
 #{
    _fields_ = [("type",c_uint32),
                ("target", c_uint32),
+               ("key",c_uint32),
                ("dimensions", c_float*3),
                ("co", (c_float*3)*2),
                ("q", (c_float*4)*2),
@@ -1567,7 +1568,8 @@ def sr_compile( collection ):
                #}
             #}
             elif obj_data.tipo == 'nonlocal':#{
-               gate.target = sr_compile_string(obj_data.key)
+               gate.target = 0
+               gate.key = sr_compile_string(obj_data.key)
                gate.type = 2
             #}
             else: gate.type = 0
index fb9db29876bb5e521060d2726e37e7f12e1cba03..9438c00c6c6aa3c72e736843918a9900d827791e 100644 (file)
@@ -104,7 +104,7 @@ VG_STATIC void skateshop_update_viewpage(void)
 /* generic reciever */
 VG_STATIC void workshop_async_any_complete( void *data, u32 size )
 {
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 /*
@@ -348,7 +348,7 @@ next_file: tinydir_next( &dir );
  */
 VG_STATIC void workshop_op_item_scan(void)
 {
-   workshop_begin_op( k_workshop_op_item_scan );
+   skaterift_begin_op( k_workshop_op_item_scan );
    vg_loader_start( workshop_scan_thread, NULL );
 }
 
@@ -747,6 +747,7 @@ VG_STATIC void ent_skateshop_call( world_instance *world, ent_call *call )
    vg_info( "skateshop_call\n" );
 
    if( menu.active ) return;
+   if( skaterift.async_op != k_async_op_none ) return;
 
    if( call->function == k_ent_function_trigger ){
       if( localplayer.subsystem != k_player_subsystem_walk ){
index a14314a0ead9dea344529ae0ce668856a1f25565..867c74c8db0cdd0f38287dd1d25152ac74f3b544 100644 (file)
--- a/entity.h
+++ b/entity.h
@@ -98,7 +98,8 @@ enum gate_type{
 
 struct ent_gate{
    u32 type,
-       target;
+       target, 
+       key;
 
    v3f dimensions,
        co[2];
index ea3174f3c9bcf70df493ae1cb873f60310c42b2f..c4763ccc90f9ab6f97c3ba75fd2ef682ecf66eb4 100644 (file)
Binary files a/maps_src/mp_gridmap.mdl and b/maps_src/mp_gridmap.mdl differ
index 9b119a29dec3d95461eba9ee64f4d115447046cc..7de53a9627a861514055027a5474668b21986479 100644 (file)
Binary files a/maps_src/mp_mtzero.mdl and b/maps_src/mp_mtzero.mdl differ
index 9a8e5261875ae6fcfba5f0b13802861f51f2ebb1..8e3042afe83b3ea216e9d3036890f143684753d8 100644 (file)
Binary files a/maps_src/mp_spawn.mdl and b/maps_src/mp_spawn.mdl differ
index 9c7da4f2eaec4e4a3f3b57a5ced60f57090483f5..2edd7dc5231a84d5fa148270f815b124dbeb2e2b 100644 (file)
@@ -15,6 +15,7 @@
 
 #define SR_NETWORKED
 #define VG_DEVWINDOW
+
 #include "common.h"
 #include "conf.h"
 #include "steam.h"
 #include "entity.c"
 #include "workshop.c"
 
-VG_STATIC struct player_avatar localplayer_avatar;
-VG_STATIC struct player_model  localplayer_models[3];
-VG_STATIC int skaterift_status = 0;
-
 #include "network.h"
 #include "menu.h"
 #include "vehicle.h"
 
+static struct player_avatar localplayer_avatar;
+static struct player_model  localplayer_models[3];
+
+
 int main( int argc, char *argv[] )
 {
    vg_mem.use_libc_malloc = 0;
@@ -80,12 +81,6 @@ VG_STATIC void load_playermodels(void)
    player_model_load( &localplayer_models[0], "models/ch_new.mdl" );
    player_model_load( &localplayer_models[1], "models/ch_outlaw.mdl" );
    player_model_load( &localplayer_models[2], "models/ch_jordan.mdl" );
-   
-   /* load default board */
-#if 0
-   player_board_load( &localplayer_boards[0], 
-                      "models/boards/skaterift_fish.mdl" );
-#endif
 
    /* FIXME: hack */
    shader_model_character_view_register();
@@ -99,14 +94,16 @@ void temp_update_playermodel(void){
 
 VG_STATIC void async_skaterift_complete( void *payload, u32 size )
 {
-   skaterift_status = 1;
-
    localplayer.viewable_world = get_active_world();
    localplayer_cmd_respawn( 1, (const char *[]){ "start" } );
+
+   skaterift_end_op();
 }
 
 VG_STATIC void vg_load(void)
 {
+   vg_console_reg_cmd( "changeworld", skaterift_change_world_command, NULL );
+
    vg_loader_step( render_init, NULL );
    vg_loader_step( menu_init, NULL );
    vg_loader_step( world_init, NULL );
@@ -128,7 +125,6 @@ VG_STATIC void vg_load(void)
    player_avatar_load( &localplayer_avatar, "models/ch_new.mdl" );
    player__use_avatar( &localplayer, &localplayer_avatar );
    player__use_model( &localplayer, &localplayer_models[cl_playermdl_id] );
-   //localplayer.board = &localplayer_boards[0];
    player__bind( &localplayer );
 
    /* --------------------- */
@@ -137,10 +133,8 @@ VG_STATIC void vg_load(void)
    vg_loader_step( audio_init, audio_free );
 
    /* 'systems' are completely loaded now */
-   /* load home world */
-
+   /* load home/permanent world */
    world_load( 0, "maps/mp_spawn.mdl" );
-   world_load( 1, "maps/mp_mtzero.mdl" );
 
    vg_console_load_autos();
    menu_link();
@@ -155,64 +149,65 @@ VG_STATIC void draw_origin_axis(void)
    vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff );
 }
 
+static void skaterift_change_world_preupdate(void);
 VG_STATIC void vg_update(void)
 {
    steam_update();
-
    skaterift_preupdate_inputs();
+   if( skaterift.async_op == k_async_op_clientloading ) return;
+   if( skaterift.async_op == k_async_op_world_preloading ){
+      skaterift_change_world_preupdate();
+   }
 
-   if( skaterift_status == 1 ){
-      draw_origin_axis();
-      network_update();
-      
-      player__pre_update( &localplayer );
-      global_skateshop_preupdate();
+   draw_origin_axis();
+   network_update();
+   
+   player__pre_update( &localplayer );
+   global_skateshop_preupdate();
 
-      world_update( get_active_world(), localplayer.rb.co );
-      audio_ambient_sprites_update( get_active_world(), localplayer.rb.co );
-      //gui_helper_action( localplayer.input_use, "\x7f Hello \x1f""A \x1e\x84" );
-   }
+   world_update( get_active_world(), localplayer.rb.co );
+   audio_ambient_sprites_update( get_active_world(), localplayer.rb.co );
+   //gui_helper_action( localplayer.input_use, "\x7f Hello \x1f""A \x1e\x84" );
 }
 
 VG_STATIC void vg_update_fixed(void)
 {
-   if( skaterift_status == 1 ){
-      world_routes_fixedupdate( get_active_world() );
+   if( skaterift.async_op == k_async_op_clientloading ) return;
 
-      player__update( &localplayer );
-      vehicle_update_fixed();
-   }
+   world_routes_fixedupdate( get_active_world() );
+   player__update( &localplayer );
+   vehicle_update_fixed();
 }
 
 VG_STATIC void vg_update_post(void)
 {
-   if( skaterift_status == 1 ){
-      player__post_update( &localplayer );
+   if( skaterift.async_op == k_async_op_clientloading ) return;
 
-      float dist;
-      int sample_index;
-      world_audio_sample_distances( localplayer.rb.co, &sample_index, &dist );
+   player__post_update( &localplayer );
 
-      audio_lock();
-      vg_dsp.echo_distances[sample_index] = dist;
+   float dist;
+   int sample_index;
+   world_audio_sample_distances( localplayer.rb.co, &sample_index, &dist );
 
-      v3f ears = { 1.0f,0.0f,0.0f };
-      m3x3_mulv( main_camera.transform, ears, ears );
-      v3_copy( ears, vg_audio.external_listener_ears );
-      v3_copy( main_camera.transform[3], vg_audio.external_listener_pos );
+   audio_lock();
+   vg_dsp.echo_distances[sample_index] = dist;
 
-      if( localplayer.gate_waiting ){
-         m4x3_mulv( localplayer.gate_waiting->transport,
-                    vg_audio.external_listener_pos, 
-                    vg_audio.external_listener_pos );
-      }
+   v3f ears = { 1.0f,0.0f,0.0f };
+   m3x3_mulv( main_camera.transform, ears, ears );
+   v3_copy( ears, vg_audio.external_listener_ears );
+   v3_copy( main_camera.transform[3], vg_audio.external_listener_pos );
 
-      v3_copy( localplayer.rb.v, vg_audio.external_lister_velocity );
-      audio_unlock();
-
-      vg.time_rate = 1.0f-menu.factive;
-      vehicle_update_post();
+   if( localplayer.gate_waiting ){
+      m4x3_mulv( localplayer.gate_waiting->transport,
+                 vg_audio.external_listener_pos, 
+                 vg_audio.external_listener_pos );
    }
+
+   v3_copy( localplayer.rb.v, vg_audio.external_lister_velocity );
+   audio_unlock();
+
+   vg.time_rate = 1.0f-menu.factive;
+   vehicle_update_post();
 }
 
 VG_STATIC void vg_framebuffer_resize( int w, int h )
@@ -359,7 +354,7 @@ VG_STATIC void render_main_game(void)
 
 VG_STATIC void vg_render(void)
 {
-   if( skaterift_status == 0 ){
+   if( skaterift.async_op == k_async_op_clientloading ){
       _vg_loader_render();
       return;
    }
@@ -387,9 +382,7 @@ VG_STATIC void vg_render(void)
 
 VG_STATIC void vg_gui(void)
 {
-   if( skaterift_status == 0 ){
-      return;
-   }
+   if( skaterift.async_op == k_async_op_clientloading ) return;
 
    menu_update();
    if( menu.active ){
@@ -406,6 +399,78 @@ VG_STATIC void vg_gui(void)
    render_view_framebuffer_ui();
 }
 
+static void async_skaterift_world_loaded( void *payload, u32 size )
+{
+   skaterift_end_op();
+}
+
+static void skaterift_world_changer_thread( void *data )
+{
+   const char *path = data;
+   world_load( 1, world_global.load_target );
+   vg_async_call( async_skaterift_world_loaded, NULL, 0 );
+}
+
+/* holding pattern before we can start loading the new world, since we might be
+ * waiting for audio to stop */
+static void skaterift_change_world_preupdate(void)
+{
+   for( u32 i=1; i<vg_list_size(world_global.worlds); i++ ){
+      world_instance *inst = &world_global.worlds[i];
+      
+      if( inst->status == k_world_status_unloading ){
+         if( world_freeable( inst ) ){
+            world_free( inst );
+         }
+         return;
+      }
+   }
+
+   vg_info( "worlds cleared, begining load\n" );
+   skaterift_shift_op( k_async_op_world_loading );
+
+   /* finally can start the loader */
+   vg_loader_start( skaterift_world_changer_thread, NULL );
+}
+
+/* places all loaded worlds into unloading state */
+static void skaterift_change_world( const char *world_path )
+{
+   vg_info( "switching to %s\n", world_path );
+
+   if( world_global.active_world != 0 ){
+      vg_error( "Cannot change worlds while in non-root world\n" );
+   }
+   else{
+      skaterift_begin_op( k_async_op_world_preloading );
+
+      vg_linear_clear( vg_mem.scratch );
+      world_global.load_target = vg_linear_alloc( vg_mem.scratch, 1024 );
+      vg_strncpy( world_path, world_global.load_target, 
+                  1024, k_strncpy_overflow_fatal );
+      
+      vg_info( "unloading old worlds\n" );
+      world_unlink_nonlocal( &world_global.worlds[0] );
+      
+      for( u32 i=1; i<vg_list_size(world_global.worlds); i++ ){
+         world_instance *inst = &world_global.worlds[i];
+
+         if( inst->status == k_world_status_loaded ){
+            inst->status = k_world_status_unloading;
+            world_fadeout_audio( inst );
+         }
+      }
+   }
+}
+
+static int skaterift_change_world_command( int argc, const char *argv[] )
+{
+   if( argc == 1 )
+      skaterift_change_world( argv[0] );
+
+   return 0;
+}
+
 #else
 
 #include "skaterift_imgui_dev.c"
diff --git a/skaterift.h b/skaterift.h
new file mode 100644 (file)
index 0000000..b2d208c
--- /dev/null
@@ -0,0 +1,69 @@
+#ifndef SKATERIFT_H
+#define SKATERIFT_H
+
+#include "common.h"
+
+struct{
+   enum async_operation{
+      k_async_op_none,
+      k_async_op_clientloading,
+      k_async_op_world_preloading,
+      k_async_op_world_loading,
+      k_workshop_form_op_loading_model,
+      k_workshop_form_op_downloading_submission,
+      k_workshop_form_op_publishing_update,
+      k_workshop_op_item_scan,
+      k_workshop_op_item_load
+   }
+   async_op;
+}
+static skaterift = { .async_op = k_async_op_clientloading };
+
+
+/* Skaterift api */
+
+static void skaterift_change_world( const char *world_path );
+static int  skaterift_change_world_command( int argc, const char *argv[] );
+
+
+
+
+
+/*
+ * Start a new operation or crash if we are already running one. you can avoid
+ * crashing the game by checking the async status yourself before calling.
+ */
+VG_STATIC void skaterift_begin_op( enum async_operation op )
+{
+   if( skaterift.async_op != k_async_op_none ){
+      vg_fatal_error( "Async executing op(%d), tried to start op(%d)\n", 
+                       skaterift.async_op, op );
+   }
+   
+   skaterift.async_op = op;
+   vg_info( "Starting op( %d )\n", op );
+}
+
+/*
+ * Switch operation for those who have multiple parts
+ */
+VG_STATIC void skaterift_shift_op( enum async_operation op )
+{
+   if( skaterift.async_op == k_async_op_none ){
+      vg_fatal_error( "No current op, cannot shift operation (%d)\n", op );
+   }
+   
+   skaterift.async_op = op;
+   vg_info( "Shifting to op( %d )\n", op );
+}
+
+/*
+ * Finished operation, otheres can now run
+ */
+VG_STATIC void skaterift_end_op(void)
+{
+   vg_info( "Finishing op( %d )\n", skaterift.async_op );
+   skaterift.async_op = k_async_op_none;
+}
+
+#endif /* SKATERIFT_H */
index 30aaf7a376b5be2fe1933fb46cb36ed50bcf4bdb..d5eb820d34b6ebe790d7c0907713d554ad959fa1 100644 (file)
@@ -111,7 +111,7 @@ static struct ui_dropdown_opt workshop_form_visibility_opts[] = {
  */
 VG_STATIC void workshop_quit_form(void)
 {
-   workshop_begin_op( k_workshop_form_op_none );  /* safeguard */
+   skaterift_begin_op( k_async_op_none );  /* safeguard */
    player_board_unload( &workshop_form.board_model );
    workshop_form.file_intent = k_workshop_form_file_intent_none;
 
@@ -124,7 +124,7 @@ VG_STATIC void workshop_quit_form(void)
    }
 
    workshop_form.page = k_workshop_form_hidden;
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 /*
@@ -224,7 +224,7 @@ VG_STATIC void on_workshop_update_result( void *data, void *user )
       vg_error( "Error with the submitted file (%d)\n", result->m_eResult );
    }
 
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 struct workshop_package_info {
@@ -248,7 +248,7 @@ VG_STATIC void workshop_form_async_package_complete( void *data, u32 size )
    if( !info->success ){
       workshop_form.page = k_workshop_form_closing_bad;
       workshop_form.failure_or_success_string = info->failure_reason;
-      workshop_end_op();
+      skaterift_end_op();
       return;
    }
 
@@ -432,7 +432,7 @@ VG_STATIC void on_workshop_createitem( void *data, void *user )
 
       workshop_form.page = k_workshop_form_closing_bad;
       workshop_form.failure_or_success_string = errstr;
-      workshop_end_op();
+      skaterift_end_op();
    }
 }
 
@@ -535,7 +535,7 @@ VG_STATIC void workshop_op_submit(void)
       }
    }
 
-   workshop_begin_op( k_workshop_form_op_publishing_update );
+   skaterift_begin_op( k_workshop_form_op_publishing_update );
 
    player_board_unload( &workshop_form.board_model );
    workshop_form.file_intent = k_workshop_form_file_intent_none;
@@ -560,7 +560,7 @@ VG_STATIC void workshop_form_loadmodel_async_complete( void *payload, u32 size )
    workshop_form.file_intent = k_workshop_form_file_intent_new;
    
    vg_success( "workshop async load complete\n" );
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 /*
@@ -568,7 +568,7 @@ VG_STATIC void workshop_form_loadmodel_async_complete( void *payload, u32 size )
  */
 VG_STATIC void workshop_form_loadmodel_async_error( void *payload, u32 size )
 {
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 /*
@@ -593,7 +593,7 @@ VG_STATIC void _workshop_form_load_thread( void *data )
  */
 VG_STATIC void workshop_op_load_model(void)
 {
-   workshop_begin_op( k_workshop_form_op_loading_model );
+   skaterift_begin_op( k_workshop_form_op_loading_model );
    vg_loader_start( _workshop_form_load_thread, NULL );
 }
 
@@ -619,7 +619,7 @@ VG_STATIC void workshop_form_async_imageload( void *data, u32 len )
       vg_success( "Loaded workshop preview image\n" );
    }
    
-   workshop_end_op();
+   skaterift_end_op();
 }
 
 struct workshop_loadpreview_info {
@@ -670,7 +670,7 @@ VG_STATIC void on_workshop_download_ugcpreview( void *data, void *user )
    else{
       vg_error( "Error while donwloading UGC preview( %d )\n", 
                 result->m_eResult );
-      workshop_end_op();
+      skaterift_end_op();
    }
 }
 
@@ -687,7 +687,7 @@ VG_STATIC void workshop_op_download_and_view_submission( int result_index )
                                              result_index,
                                              &details ) )
    {
-      workshop_begin_op( k_workshop_form_op_downloading_submission );
+      skaterift_begin_op( k_workshop_form_op_downloading_submission );
       workshop_reset_submission_data();
       workshop_form.submission.submit_description = 0;
       workshop_form.submission.submit_file_and_image = 0;
@@ -721,7 +721,7 @@ VG_STATIC void workshop_op_download_and_view_submission( int result_index )
 
       if( details.m_hPreviewFile == 0 ){
          vg_error( "m_hPreviewFile is 0\n" );
-         workshop_end_op();
+         skaterift_end_op();
       }
       else{
          /* Now need to begin downloading the image so we can display it */
@@ -747,7 +747,7 @@ VG_STATIC void workshop_op_download_and_view_submission( int result_index )
    }
    else{
       vg_error( "GetQueryUGCResult: Index out of range\n" );
-      workshop_end_op();
+      skaterift_end_op();
    }
 }
 
@@ -1297,7 +1297,7 @@ VG_STATIC void workshop_form_gui(void)
    ui_rect quit_button;
    ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, quit_button );
 
-   if( workshop.operation == k_workshop_form_op_none ){
+   if( skaterift.async_op == k_async_op_none ){
       if( ui_button_text( quit_button, "X", 1 ) ){
          workshop_quit_form();
          return;
@@ -1310,11 +1310,11 @@ VG_STATIC void workshop_form_gui(void)
     * escapes here and we show them a basic string
     */
 
-   if( workshop.operation != k_workshop_form_op_none ){
+   if( skaterift.async_op != k_async_op_none ){
       const char *op_string = "The programmer has not bothered to describe "
                               "the current operation that is running.";
 
-      switch(workshop.operation){
+      switch( skaterift.async_op ){
          case k_workshop_form_op_loading_model:
             op_string = "Operation in progress: Loading model file.";
          break;
index 4a0f8b27008347d74cdc574d53fb790ea23b8162..6418339d4851dd7811b5a89977f62a1a4f558c83 100644 (file)
@@ -4,19 +4,7 @@
 #define VG_GAME
 #include "vg/vg.h"
 #include "vg/vg_steam_remote_storage.h"
-
-struct workshop{
-   enum workshop_operation{
-      k_workshop_form_op_none,
-      k_workshop_form_op_loading_model,
-      k_workshop_form_op_downloading_submission,
-      k_workshop_form_op_publishing_update,
-      k_workshop_op_item_scan,
-      k_workshop_op_item_load
-   }
-   operation;
-}
-static workshop;
+#include "skaterift.h"
 
 struct workshop_file_info{
    u64 author;
@@ -52,29 +40,4 @@ VG_STATIC void async_workshop_get_installed_files( void *data, u32 len );
 VG_STATIC void workshop_load_metadata( const char *path,
                                        struct workshop_file_info *info );
 
-/*
- * Start a new operation and crash if we are already running one.
- */
-VG_STATIC int workshop_begin_op( enum workshop_operation op )
-{
-   if( workshop.operation != k_workshop_form_op_none ){
-      vg_error( "Workshop form currently executing op(%d), tried to "
-                "start op(%d)\n", workshop.operation, op );
-      return 0;
-   }
-   
-   workshop.operation = op;
-   vg_info( "Starting op( %d )\n", op );
-   return 1;
-}
-
-/*
- * Finished operation, otheres can now run
- */
-VG_STATIC void workshop_end_op(void)
-{
-   vg_info( "Finishing op( %d )\n", workshop.operation );
-   workshop.operation = k_workshop_form_op_none;
-}
-
 #endif /* WORKSHOP_H */
diff --git a/world.h b/world.h
index 68c3f2b2ed4e9217fda06834e979f50f4cda5ca6..66b3b28f2c0b14a961cf7ea04ef4b27321332cc7 100644 (file)
--- a/world.h
+++ b/world.h
@@ -62,11 +62,11 @@ struct world_instance {
     */
 
    void *heap;
-   char  world_name[ 64 ];
    enum world_status{
       k_world_status_unloaded = 0,
       k_world_status_loading = 1,
-      k_world_status_loaded = 2
+      k_world_status_loaded = 2,
+      k_world_status_unloading = 3  /* dont spawn sounds and stuff */
    }
    status;
 
@@ -127,7 +127,6 @@ struct world_instance {
    float probabilities[3];
 
    v3i light_cubes;
-
    struct framebuffer heightmap;
 
    /*
@@ -206,6 +205,7 @@ struct world_global{
     * --------------------------------------------------------------------------
     */
    void *heap;
+   char *load_target;
 
    /* rendering */
    glmesh skydome;
@@ -239,8 +239,6 @@ struct world_global{
    v3f render_gate_pos;
    int in_volume;
 
-   int switching_to_new_world;
-
    world_instance worlds[4];
    u32            active_world;
 
@@ -441,6 +439,12 @@ VG_STATIC void ent_volume_call( world_instance *world, ent_call *call )
 
 VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
 {
+   if( world->status == k_world_status_unloading ){
+      vg_warn( "cannot modify audio while unloading world\n" );
+      return;
+   }
+
+   u8 world_id = (world - world_global.worlds) + 1;
    u32 index = mdl_entity_id_id( call->id );
    ent_audio *audio = mdl_arritm( &world->ent_audio, index );
 
@@ -468,7 +472,6 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
       bar += p;
 
       if( chance < bar ){
-
          audio_lock();
 
          if( audio->behaviour == k_channel_behaviour_unlimited ){
@@ -484,6 +487,7 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
             if( ch ){
                audio_channel_init( ch, &clip->clip, audio->flags );
                audio_channel_group( ch, audio->group );
+               audio_channel_world( ch, world_id );
                audio_channel_set_spacial( ch, sound_co, audio->transform.s[0] );
                audio_channel_edit_volume( ch, audio->volume, 1 );
                ch = audio_relinquish_channel( ch );
@@ -515,6 +519,7 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
             if( ch ){
                audio_channel_init( ch, &clip->clip, audio->flags );
                audio_channel_group( ch, audio->group );
+               audio_channel_world( ch, world_id );
                audio_channel_fadein( ch, audio->crossfade );
                ch = audio_relinquish_channel( ch );
             }
@@ -526,6 +531,28 @@ VG_STATIC void ent_audio_call( world_instance *world, ent_call *call )
    }
 }
 
+/* finds any active playing in world and fades them out, we can only do this 
+ * while unloading */
+VG_STATIC void world_fadeout_audio( world_instance *world )
+{
+   if( world->status != k_world_status_unloading ){
+      vg_fatal_error( "World status must be set to 'unloading', to fadeout"
+                      " audio.\n" );
+   }
+
+   u8 world_id = (world - world_global.worlds) + 1;
+
+   audio_lock();
+   for( u32 i=0; i<AUDIO_CHANNELS; i++ ){
+      audio_channel *ch = &vg_audio.channels[i];
+
+      if( ch->allocated && (ch->world_id == world_id) ){
+         ch = audio_channel_fadeout( ch, 1.0f );
+      }
+   }
+   audio_unlock();
+}
+
 VG_STATIC void world_update( world_instance *world, v3f pos )
 {
    world_global.sky_time += world_global.sky_rate * vg.time_delta;
index 469f73695e7da46489e08a2f3b6dc8a93e67b306..b409c51d0d482f65ced1193aa8108a88ea8ecaf3 100644 (file)
@@ -5,6 +5,7 @@
 #ifndef WORLD_GATE_H
 #define WORLD_GATE_H
 
+#include "skaterift.h"
 #include "common.h"
 #include "model.h"
 #include "entity.h"
@@ -229,6 +230,13 @@ VG_STATIC ent_gate *world_intersect_gates( world_instance *world,
           gate->type == k_gate_type_nonlocal_unlinked )
          continue;
 
+      if( gate->type == k_gate_type_nonlocel ){
+         if( skaterift.async_op == k_async_op_world_loading ||
+             skaterift.async_op == k_async_op_world_preloading ){
+            continue;
+         }
+      }
+
       if( gate_intersect( gate, pos, last ) ){
          return gate;
       }
index 2bada3aa5fcd79acb692054b0c9a239c38accddf..6cae853576ec97cee25c020bc35c29ef848bb3bc 100644 (file)
@@ -596,15 +596,15 @@ VG_STATIC void world_process_resources( world_instance *world )
    }
 }
 
-#if 0
 VG_STATIC void world_free( world_instance *world )
 {
-   vg_acquire_thread_sync();
+   vg_info( "Free world @%p\n", world );
 
    /* free meshes */
    mesh_free( &world->mesh_route_lines );
    mesh_free( &world->mesh_geo );
    mesh_free( &world->mesh_no_collide );
+   mesh_free( &world->mesh_water );
    
    /* glDeleteBuffers silently ignores 0's and names that do not correspond to 
     * existing buffer objects. 
@@ -616,11 +616,46 @@ VG_STATIC void world_free( world_instance *world )
    /* delete textures and meshes */
    glDeleteTextures( world->texture_count, world->textures );
 
-   vg_release_thread_sync();
+   u32 world_index = world - world_global.worlds;
+   if( world_index ){
+      vg_linear_del( world_global.worlds[world_index-1].heap, 
+                     vg_linear_header(world->heap) );
+   }
 
    world->status = k_world_status_unloaded;
 }
-#endif
+
+/* 
+ * checks:
+ *  1. to see if all audios owned by the world have been stopped
+ *  2. that this is the least significant world
+ */
+VG_STATIC int world_freeable( world_instance *world )
+{
+   if( world->status != k_world_status_unloading ) return 0;
+   u8 world_id = (world - world_global.worlds) + 1;
+
+   for( u32 i=world_id; i<vg_list_size(world_global.worlds); i++ ){
+      if( world_global.worlds[i].status != k_world_status_unloaded ){
+         return 0;
+      }
+   }
+
+   int freeable = 1;
+   audio_lock();
+   for( u32 i=0; i<AUDIO_CHANNELS; i++ ){
+      audio_channel *ch = &vg_audio.channels[i];
+      
+      if( ch->allocated && (ch->world_id == world_id)){
+         if( !audio_channel_finished( ch ) ){
+            freeable = 0;
+            break;
+         }
+      }
+   }
+   audio_unlock();
+   return freeable;
+}
 
 VG_STATIC void world_init_blank( world_instance *world )
 {
@@ -661,32 +696,29 @@ VG_STATIC void world_init_blank( world_instance *world )
    v3_copy( (v3f){1.10f, 0.89f, 0.35f}, state->g_sun_colour );
 }
 
-VG_STATIC void world_entities_init( u32 world_id )
+/* detatches any nonlocal gates */
+VG_STATIC void world_unlink_nonlocal( world_instance *world )
 {
-   world_instance *world = &world_global.worlds[world_id];
-
-   /* lights */
-   for( u32 j=0; j<mdl_arrcount(&world->ent_light); j ++ ){
-      ent_light *light = mdl_arritm( &world->ent_light, j );
-
-      m4x3f to_world;
-      q_m3x3( light->transform.q, to_world );
-      v3_copy( light->transform.co, to_world[3] );
-      m4x3_invert_affine( to_world, light->inverse_world );
+   for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
+      ent_gate *gate = mdl_arritm( &world->ent_gate, j );
 
-      light->angle_sin_cos[0] = sinf( light->angle * 0.5f );
-      light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
+      if( gate->type == k_gate_type_nonlocel ){
+         gate->type = k_gate_type_nonlocal_unlinked;
+      }
    }
+}
+
+/* attatches nonlocal gates, to be called from main thread ONLY! */
+VG_STATIC void world_link_nonlocal_async( void *payload, u32 size )
+{
+   world_instance *world = payload;
+   u32 world_id = world - world_global.worlds;
 
-   /* gates */
    for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
       ent_gate *gate = mdl_arritm( &world->ent_gate, j );
 
-      if( gate->type == k_gate_type_teleport ){
-         gate_transform_update( gate );
-      }
-      else if( gate->type == k_gate_type_nonlocal_unlinked ){
-         const char *key = mdl_pstr( &world->meta, gate->target );
+      if( gate->type == k_gate_type_nonlocal_unlinked ){
+         const char *key = mdl_pstr( &world->meta, gate->key );
          vg_info( "key: %s\n", key );
 
          for( u32 i=0; i<vg_list_size(world_global.worlds); i++ ){
@@ -699,7 +731,7 @@ VG_STATIC void world_entities_init( u32 world_id )
                ent_gate *gate2 = mdl_arritm( &other->ent_gate, j );
                if( gate2->type != k_gate_type_nonlocal_unlinked ) continue;
 
-               const char *key2 = mdl_pstr( &other->meta, gate2->target );
+               const char *key2 = mdl_pstr( &other->meta, gate2->key );
                vg_info( " key2: %s\n", key2 );
 
                if( strcmp( key, key2 ) ) continue;
@@ -731,6 +763,34 @@ VG_STATIC void world_entities_init( u32 world_id )
 matched:;
       }
    }
+}
+
+VG_STATIC void world_entities_init( u32 world_id )
+{
+   world_instance *world = &world_global.worlds[world_id];
+
+   /* lights */
+   for( u32 j=0; j<mdl_arrcount(&world->ent_light); j ++ ){
+      ent_light *light = mdl_arritm( &world->ent_light, j );
+
+      m4x3f to_world;
+      q_m3x3( light->transform.q, to_world );
+      v3_copy( light->transform.co, to_world[3] );
+      m4x3_invert_affine( to_world, light->inverse_world );
+
+      light->angle_sin_cos[0] = sinf( light->angle * 0.5f );
+      light->angle_sin_cos[1] = cosf( light->angle * 0.5f );
+   }
+
+   /* gates */
+   for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
+      ent_gate *gate = mdl_arritm( &world->ent_gate, j );
+
+      if( gate->type == k_gate_type_teleport ){
+         gate_transform_update( gate );
+      }
+   }
+   vg_async_call( world_link_nonlocal_async, world, 0 );
 
    /* water */
    for( u32 j=0; j<mdl_arrcount(&world->ent_water); j++ ){
@@ -811,8 +871,7 @@ VG_STATIC void world_load( u32 index, const char *path )
    }
 
    u32 size = heap_availible - min_overhead;
-   void *heap = vg_create_linear_allocator( allocator, size, 
-                                            VG_MEMORY_SYSTEM );
+   void *heap = vg_create_linear_allocator( allocator, size, VG_MEMORY_SYSTEM );
 
    world->heap = heap;
    mdl_context *meta = &world->meta;
@@ -872,7 +931,6 @@ VG_STATIC void world_load( u32 index, const char *path )
    world_post_process( world );
 
    mdl_close( meta );
-
    world->status = k_world_status_loaded;
 }
 
index ef5946e9941298076b71c9cb6bb1228d0252d83d..10e416325b306529daa4ec9d0f6f2faa369098b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved
+ * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved
  */
 
 #ifndef WORLD_RENDER_H
@@ -405,8 +405,11 @@ VG_STATIC void render_world_gates( world_instance *world, camera *cam,
          render_gate( world, gate, cam, layer_depth );
       }
       else if( gate->type == k_gate_type_nonlocel ){
-         world_instance *dest_world = &world_global.worlds[ gate->target ];
-         render_gate( dest_world, gate, cam, layer_depth );
+         if( skaterift.async_op != k_async_op_world_loading &&
+             skaterift.async_op != k_async_op_world_preloading ){
+            world_instance *dest_world = &world_global.worlds[ gate->target ];
+            render_gate( dest_world, gate, cam, layer_depth );
+         }
       }
       else
          world->rendering_gate = NULL;