+static void load_playermodels(void){
+ /* FIXME: hack */
+ shader_model_character_view_register();
+ shader_model_board_view_register();
+ shader_model_entity_register();
+}
+
+static void async_skaterift_player_start( void *payload, u32 size ){
+ localplayer.viewable_world = world_current_instance();
+ localplayer_cmd_respawn( 1, (const char *[]){ "start" } );
+}
+
+static void async_call_ready( void *payload, u32 size ){
+ skaterift.op = k_async_op_none;
+}
+
+static void skaterift_restore_state(void){
+ savedata_file sav;
+ strcpy( sav.path, str_skaterift_main_save );
+ savedata_file_read( &sav );
+
+ vg_msg kvsav;
+ vg_msg_init( &kvsav, sav.buf, sizeof(sav.buf) );
+
+ u32 board_reg_id = 0,
+ player_reg_id = 0;
+
+ vg_msg_cursor orig = kvsav.cur;
+
+ if( vg_msg_seekframe( &kvsav, "player" ) ){
+ addon_alias q;
+
+ /* board */
+ skaterift_read_addon_alias( &kvsav, "board", k_addon_type_board, &q );
+ u32 reg_id = addon_match( &q );
+ if( reg_id != 0xffffffff )
+ board_reg_id = reg_id;
+
+ /* playermodel */
+ skaterift_read_addon_alias( &kvsav, "playermodel",
+ k_addon_type_player, &q );
+ reg_id = addon_match( &q );
+ if( reg_id != 0xffffffff )
+ player_reg_id = reg_id;
+ }
+
+ localplayer.board_view_slot =
+ addon_cache_create_viewer( k_addon_type_board, board_reg_id );
+ localplayer.playermodel_view_slot =
+ addon_cache_create_viewer( k_addon_type_player, player_reg_id );
+
+ kvsav.cur = orig;
+ if( vg_msg_seekframe( &kvsav, "world" ) ){
+ addon_alias q;
+
+ /* world */
+ skaterift_read_addon_alias( &kvsav, "alias", k_addon_type_world, &q );
+ u32 reg_id = addon_match( &q );
+ if( reg_id != 0xffffffff ){
+ addon_reg *reg = get_addon_from_index( k_addon_type_world, reg_id );
+
+ world_static.load_state = k_world_loader_load;
+ struct world_load_args args = {
+ .purpose = k_world_purpose_client,
+ .reg = reg
+ };
+ skaterift_world_load_thread( &args );
+
+ world_set_active_instance( vg_msg_getkvu32( &kvsav, "index", 0 ) );
+ world_static.active_trigger_volume_count = 0;
+ localplayer.viewable_world = world_current_instance();
+ }
+
+ v3f pos;
+ vg_msg_getkvv3f( &kvsav, "position", pos, (v3f){0.0f,0.0f,0.0f} );
+
+ if( v3_length2(pos) > 1.0f )
+ player__setpos( pos );
+ }
+}
+
+static void vg_load(void){
+ vg_console_reg_cmd( "changeworld", skaterift_change_world_command, NULL );
+