/* v102+ */
enum ent_gate_flag{
k_ent_gate_linked = 0x1, /* this is a working portal */
- k_ent_gate_nonlocal_DELETED = 0x2, /* use the key string to link this portal.
+ k_ent_gate_nonlocal = 0x2, /* use the key string to link this portal.
NOTE: if set, it adds the flip flag. */
k_ent_gate_flip = 0x4, /* flip direction 180* for exiting portal */
k_ent_gate_custom_mesh = 0x8, /* use a custom submesh instead of default */
vg.window_should_close = 1;
}
- else if( MDL_CONST_PSTREQ( &menu.model, q, "reset" ) ){
-
- /* FIXME: Should only be availible in CLIENT WORLD */
+ else if( MDL_CONST_PSTREQ( &menu.model, q, "map" ) ){
menu_close();
respawn_begin_chooser();
-
- /* FIXME: Need a back to hub button */
-#if 0
+ }
+ else if( MDL_CONST_PSTREQ( &menu.model, q, "hub" ) ){
srinput.state = k_input_state_resume;
menu_close();
ent_miniworld_goback();
-#endif
}
-
else if( MDL_CONST_PSTREQ( &menu.model, q, "credits" ) ){
menu.credits_open = 1;
}
cc->cam_velocity_smooth );
m4x3_mulv( gate->transport, localplayer.cam.pos, localplayer.cam.pos );
+
+ if( gate->flags & k_ent_gate_nonlocal ){
+ /* FIXME: Code dupe with world_load.c */
+ ent_spawn *rp = world_find_spawn_by_name( world, "start" );
+ if( !rp ) rp = world_find_closest_spawn( world, (v3f){0.0f,0.0f,0.0f} );
+ /* TODO: fallback to searching for a safe location using raycasts */
+ assert(rp);
+ v3_copy( rp->transform.co, world->player_co );
+
+ world_static.active_instance = gate->target;
+ player__clean_refs();
+ }
v3f v0;
v3_angles_vector( localplayer.angles, v0 );
rb_update_transform( &localplayer.rb );
}
-static void player__reset(void){
+static void player__clean_refs(void){
replay_clear( &skaterift.replay );
gui_helper_clear();
- v3_zero( localplayer.rb.v );
- v3_zero( localplayer.rb.w );
-
- f32 l = v4_length( localplayer.rb.q );
- if( (l < 0.9f) || (l > 1.1f) )
- q_identity( localplayer.rb.q );
-
- rb_update_transform( &localplayer.rb );
-
- localplayer.subsystem = k_player_subsystem_walk;
- player__walk_reset();
-
- localplayer.immobile = 0;
- localplayer.gate_waiting = NULL;
-
world_static.challenge_target = NULL;
world_static.challenge_timer = 0.0f;
world_static.focused_entity = 0;
world_routes_clear( instance );
}
}
+}
+
+static void player__reset(void){
+ v3_zero( localplayer.rb.v );
+ v3_zero( localplayer.rb.w );
+
+ f32 l = v4_length( localplayer.rb.q );
+ if( (l < 0.9f) || (l > 1.1f) )
+ q_identity( localplayer.rb.q );
+
+ rb_update_transform( &localplayer.rb );
+
+ localplayer.subsystem = k_player_subsystem_walk;
+ player__walk_reset();
+
+ localplayer.immobile = 0;
+ localplayer.gate_waiting = NULL;
v3_copy( localplayer.rb.co, localplayer.cam_control.tpv_lpf );
+ player__clean_refs();
}
static void player__spawn( ent_spawn *rp ){
static void player__im_gui(void);
static void player__setpos( v3f pos );
static void player__spawn( ent_spawn *rp );
+static void player__clean_refs(void);
static void player__reset(void);
static void player__kill(void);
static void player__begin_holdout( v3f offset );
m4x3_mulv( gate->transport, co1, co1 );
m3x3_mulv( gate->transport, launch_v, launch_v);
m4x3_mulv( gate->transport, launch_co, launch_co );
+
+ if( gate->flags & k_ent_gate_nonlocal )
+ trace_world = &world_static.instances[ gate->target ];
}
}
if( world->water.enabled ){
if( localplayer.rb.co[1]+0.25f < world->water.height ){
-#if 0
player__networked_sfx( k_player_subsystem_walk, 32,
k_player_walk_soundeffect_splash,
localplayer.rb.co, 1.0f );
-#endif
player__skate_kill_audio();
player__dead_transition();
return;
if( world->water.enabled ){
if( localplayer.rb.co[1]+0.4f < world->water.height ){
- audio_oneshot_3d( &audio_splash, localplayer.rb.co, 40.0f, 1.0f );
+ player__networked_sfx( k_player_subsystem_walk, 32,
+ k_player_walk_soundeffect_splash,
+ localplayer.rb.co, 1.0f );
player__dead_transition();
return;
}
&animator->pitch );
}
}
+
+static void player__walk_sfx_oneshot( u8 id, v3f pos, f32 volume ){
+ audio_lock();
+
+ if( id == k_player_walk_soundeffect_splash ){
+ audio_oneshot_3d( &audio_splash, pos, 40.0f, 1.0f );
+ }
+
+ audio_unlock();
+}
#endif /* PLAYER_DEVICE_WALK_H */
}
static player_walk;
+enum player_walk_soundeffect {
+ k_player_walk_soundeffect_splash
+};
+
static f32
k_walkspeed = 10.0f,
k_airspeed = 1.2f,
}
}
+ for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
+ ent_gate *gate = mdl_arritm( &world->ent_gate, i );
+ if( gate->flags & k_ent_gate_nonlocal ){
+ respawn_map_draw_icon( cam, k_gui_icon_rift, gate->co[0] );
+ }
+ }
+
for( u32 i=0; i<mdl_arrcount(&world->ent_route); i++ ){
ent_route *route = mdl_arritm( &world->ent_route, i );
if( uIsoAmt > 0.0 ){
float height = fract( aCo.y * 0.1 );
float lg = 2.0*length(vec2(dFdx(height), dFdy(height)));
- vfrag *= 1.0f+(lg*0.4*uIsoAmt);
+ vfrag *= 1.0f+(lg*0.2*uIsoAmt);
}
-
oColour = vec4( vfrag, 1.0 );
//oColour = vec4( vfrag, 1.0 );
}
" float d3 = distance(p0,aCo);\n"
" emit += vec3(fract(t*0.2-g_realtime+d3*0.2)*max(0.0,1.0-d3*0.2));\n"
"\n"
+" vfrag += emit;\n"
+"\n"
" if( uIsoAmt > 0.0 ){\n"
" float height = fract( aCo.y * 0.1 );\n"
" float lg = 2.0*length(vec2(dFdx(height), dFdy(height)));\n"
-" emit += vec3(lg*0.1*uIsoAmt);\n"
+" vfrag *= 1.0f+(lg*0.4*uIsoAmt);\n"
" }\n"
"\n"
-" oColour = vec4( vfrag+emit, 1.0 );\n"
+"\n"
+" oColour = vec4( vfrag, 1.0 );\n"
" //oColour = vec4( vfrag, 1.0 );\n"
"}\n"
""},
player__render( &small_cam );
}
+static world_instance *get_view_world(void){
+ world_instance *view_world = world_current_instance();
+ if( localplayer.gate_waiting &&
+ (localplayer.gate_waiting->flags & k_ent_gate_nonlocal) ){
+ view_world = &world_static.instances[world_static.active_instance ^ 0x1];
+ }
+
+ return view_world;
+}
+
static void render_scene(void){
/* Draw world */
glEnable( GL_DEPTH_TEST );
return;
}
- render_world( world_current_instance(), &skaterift.cam, 0, 0, 1, 1 );
+ world_instance *view_world = get_view_world();
+ render_world( view_world, &skaterift.cam, 0, 0, 1, 1 );
+
+ /*
+ * render transition
+ */
+ if( global_miniworld.transition == 0 )
+ return;
world_instance *holdout_world = NULL;
f32 t = 0.0f;
holdout_world = &world_static.instances[ k_world_purpose_hub ];
t = global_miniworld.t;
}
- else if( global_miniworld.transition == -1 ){
+ else{
holdout_world = &world_static.instances[ k_world_purpose_client ];
t = 1.0f-global_miniworld.t;
}
- else {
- }
- if( holdout_world ){
- if( holdout_world->status != k_world_status_loaded )
- return;
+ if( holdout_world->status != k_world_status_loaded )
+ return;
- t = vg_smoothstepf( t );
+ t = vg_smoothstepf( t );
- glEnable( GL_STENCIL_TEST );
- glDisable( GL_DEPTH_TEST );
- glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
- glStencilFunc( GL_ALWAYS, 1, 0xFF );
- glStencilMask( 0xFF );
+ glEnable( GL_STENCIL_TEST );
+ glDisable( GL_DEPTH_TEST );
+ glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE );
+ glStencilFunc( GL_ALWAYS, 1, 0xFF );
+ glStencilMask( 0xFF );
- shader_blit_transition_use();
- shader_blit_transition_uInverseRatio( (v2f){1.0f,1.0f} );
- shader_blit_transition_uT( -(sqrtf(2)+0.5f) * t );
+ shader_blit_transition_use();
+ shader_blit_transition_uInverseRatio( (v2f){1.0f,1.0f} );
+ shader_blit_transition_uT( -(sqrtf(2)+0.5f) * t );
- render_fsquad();
- render_world( holdout_world, &global_miniworld.cam, 1, 0, 1, 1 );
- }
+ render_fsquad();
+ render_world( holdout_world, &global_miniworld.cam, 1, 0, 1, 1 );
}
static void skaterift_composite_maincamera(void){
skaterift_composite_maincamera();
/* --------------------------------------------------------------------- */
- if( skaterift.activity != k_skaterift_respawning )
- render_world_cubemaps( world_current_instance() );
+ if( skaterift.activity != k_skaterift_respawning ){
+ world_instance *world = world_current_instance();
+ render_world_cubemaps( world );
+
+ ent_gate *nlg = world->rendering_gate;
+ if( nlg && nlg->flags & k_ent_gate_nonlocal )
+ render_world_cubemaps( &world_static.instances[nlg->target] );
+ }
/* variable res target */
render_fb_bind( gpipeline.fb_main, 1 );
if( !global_miniworld.transition &&
(skaterift.activity != k_skaterift_respawning) ){
render_fb_bind( gpipeline.fb_main, 1 );
- render_world_gates( world_current_instance(), &skaterift.cam );
+ render_world_gates( get_view_world(), &skaterift.cam );
}
/* composite */
for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
ent_gate *gate = mdl_arritm( &world->ent_gate, j );
- if( !(gate->flags & k_ent_gate_nonlocal_DELETED) ) {
+ if( !(gate->flags & k_ent_gate_nonlocal) ) {
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++ ){
if( !(gate->flags & k_ent_gate_linked) ) continue;
if( gate->flags & k_ent_gate_locked ) continue;
- if( gate->flags & k_ent_gate_nonlocal_DELETED )
- continue;
+ if( gate->flags & k_ent_gate_nonlocal ){
+ if( world_static.instances[gate->target].status
+ != k_world_status_loaded )
+ continue;
+ }
if( gate_intersect( gate, pos, last ) )
return mdl_entity_id( k_ent_gate, i );
}
}
+
+/*
+ * detatches any nonlocal gates
+ */
+static void world_unlink_nonlocal( world_instance *world ){
+ for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
+ ent_gate *gate = mdl_arritm( &world->ent_gate, j );
+
+ if( gate->flags & k_ent_gate_nonlocal ){
+ gate->flags &= ~k_ent_gate_linked;
+ }
+ }
+}
+
+/*
+ * attatches nonlocal gates, to be called from main thread ONLY!
+ */
+static void world_link_nonlocal_async( void *payload, u32 size ){
+ world_instance *world = payload;
+ u32 world_id = world - world_static.instances;
+
+ for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
+ ent_gate *gate = mdl_arritm( &world->ent_gate, j );
+
+ if( !(gate->flags & k_ent_gate_nonlocal) ) continue;
+ if( gate->flags & k_ent_gate_linked ) continue;
+
+ const char *key = mdl_pstr( &world->meta, gate->key );
+ vg_info( "key: %s\n", key );
+
+ for( u32 i=0; i<vg_list_size(world_static.instances); i++ ){
+ world_instance *other = &world_static.instances[i];
+ if( other == world ) continue;
+ if( other->status != k_world_status_loaded ) continue;
+ vg_info( "Checking world %u for key matches\n", i );
+
+ for( u32 k=0; k<mdl_arrcount( &other->ent_gate ); k++ ){
+ ent_gate *gate2 = mdl_arritm( &other->ent_gate, k );
+
+ if( !(gate2->flags & k_ent_gate_nonlocal) ) continue;
+ if( gate2->flags & k_ent_gate_linked ) continue;
+
+ const char *key2 = mdl_pstr( &other->meta, gate2->key );
+ vg_info( " key2: %s\n", key2 );
+
+ if( strcmp( key, key2 ) ) continue;
+
+ vg_success( "Non-local matching pair '%s' found. (%u:%u)\n",
+ key, world_id, i );
+
+ gate->flags |= k_ent_gate_linked;
+ gate2->flags |= k_ent_gate_linked;
+ gate->target = i;
+ gate2->target = world_id;
+
+ v3_copy( gate->co[0], gate2->co[1] );
+ v3_copy( gate2->co[0], gate->co[1] );
+ v4_copy( gate->q[0], gate2->q[1] );
+ v4_copy( gate2->q[0], gate->q[1] );
+
+ if( world->meta.info.version < 102 ){
+ /* LEGACY BEHAVIOUR: v101
+ * this would flip both the client worlds portal's entrance and
+ * exit. effectively the clients portal would be the opposite
+ * to the hub worlds one. new behaviour is to just flip the
+ * destinations so the rules are consistent in each world.
+ */
+ v4f qflip;
+ q_axis_angle( qflip, (v3f){0.0f,1.0f,0.0f}, VG_PIf );
+ q_mul( gate->q[0], qflip, gate->q[0] );
+ q_mul( gate->q[1], qflip, gate->q[1] );
+ q_mul( gate2->q[1], qflip, gate2->q[1] );
+ }
+
+ gate_transform_update( gate );
+ gate_transform_update( gate2 );
+
+ goto matched;
+ }
+ } matched:;
+ }
+}
+
#endif /* WORLD_GATE_C */
static void ent_gate_call( world_instance *world, ent_call *call );
static void ent_gate_get_mdl_mtx( ent_gate *gate, m4x3f mmdl );
+static void world_link_nonlocal_async( void *payload, u32 size );
+static void world_unlink_nonlocal( world_instance *world );
+
#endif /* WORLD_GATE_H */
vg_linear_clear( vg_mem.scratch ); /* ?? */
vg_info( "unloading old worlds\n" );
-
- for( u32 i=1; i<vg_list_size(world_static.instances); i++ ){
- world_instance *inst = &world_static.instances[i];
- if( inst->status == k_world_status_loaded ){
- inst->status = k_world_status_unloading;
- world_fadeout_audio( inst );
- }
+ world_instance *client_world =
+ &world_static.instances[ k_world_purpose_client ];
+
+ if( client_world->status == k_world_status_loaded ){
+ client_world->status = k_world_status_unloading;
+ world_fadeout_audio( client_world );
}
world_static.instance_addons[ k_world_purpose_client ] = reg;
network_send_item( k_netmsg_playeritem_world1 );
relink_all_remote_player_worlds();
+ world_unlink_nonlocal( &world_static.instances[k_world_purpose_hub] );
}
}
for( u32 i=0; i<mdl_arrcount(&world->ent_gate); i++ ){
ent_gate *gi = mdl_arritm( &world->ent_gate, i );
- if( !(gi->flags & (k_ent_gate_linked|k_ent_gate_nonlocal_DELETED|
- k_ent_gate_locked)) )
- continue;
-
float dist = v3_dist2( gi->co[0], cam->transform[3] );
vg_line_point( gi->co[0], 0.25f, VG__BLUE );
}
world->rendering_gate = gate;
- if( gate )
- render_gate( world, world, gate, cam );
+
+ if( gate ){
+ if( gate->flags & k_ent_gate_locked ){
+ world->rendering_gate = NULL;
+ return;
+ }
+
+ if( gate->flags & k_ent_gate_nonlocal ){
+ if( world_static.load_state != k_world_loader_none ){
+ world->rendering_gate = NULL;
+ return;
+ }
+
+ world_instance *dest_world = &world_static.instances[ gate->target ];
+ render_gate( world, dest_world, gate, cam );
+ }
+ else
+ render_gate( world, world, gate, cam );
+ }
}
static void world_prerender( world_instance *world ){
}
if( (gate->flags & k_ent_gate_linked) &
- !(gate->flags & k_ent_gate_nonlocal_DELETED) ){
+ !(gate->flags & k_ent_gate_nonlocal) ){
gate = mdl_arritm(&world->ent_gate, gate->target );
for( u32 k=0; k<4; k++ ){
for( u32 j=0; j<mdl_arrcount(&world->ent_gate); j ++ ){
ent_gate *gate = mdl_arritm( &world->ent_gate, j );
- if( !(gate->flags & k_ent_gate_nonlocal_DELETED) )
+ if( !(gate->flags & k_ent_gate_nonlocal) )
render_gate_markers( mmdl, i, gate );
}
}