target: bpy.props.PointerProperty( \
type=bpy.types.Object, name="destination", \
poll=lambda self,obj: sr_filter_ent_type(obj,['ent_gate']))
-
+
+ nonlocal_world: bpy.props.StringProperty()
key: bpy.props.StringProperty()
tipo: bpy.props.EnumProperty(items=(('default', 'Default', ""),
('nonlocal', 'Non-Local', "")))
flip: bpy.props.BoolProperty( name="Flip exit", default=False )
custom: bpy.props.BoolProperty( name="Mesh is surface", default=False )
locked: bpy.props.BoolProperty( name="Start Locked", default=False )
+ no_linkback: bpy.props.BoolProperty( name="No Linkback", default=False )
@staticmethod
def sr_inspector( layout, data ):
box = layout.box()
box.prop( data[0], 'tipo', text="subtype" )
- if data[0].tipo == 'default': box.prop( data[0], 'target' )
- elif data[0].tipo == 'nonlocal': box.prop( data[0], 'key' )
+ if data[0].tipo == 'default':
+ #{
+ box.prop( data[0], 'target' )
+ #}
+ elif data[0].tipo == 'nonlocal':
+ #{
+ box.prop( data[0], 'nonlocal_world' )
+ box.prop( data[0], 'key' )
+ #}
flags = box.box()
flags.prop( data[0], 'flip' )
flags.prop( data[0], 'custom' )
flags.prop( data[0], 'locked' )
+
+ if data[0].tipo == 'nonlocal':
+ flags.prop( data[0], 'no_linkback' )
#}
#}
flags |= 0x0001
#}
#}
- elif obj_data.tipo == 'nonlocal':#{
- gate.target = 0
+ elif obj_data.tipo == 'nonlocal':
+ #{
+ gate.target = _af_pack_string(obj_data.nonlocal_world)
gate.key = _af_pack_string(obj_data.key)
flags |= 0x0002
#}
mdl_compile_mesh_internal( obj )
#}
if obj_data.locked: flags |= 0x0010
+ if obj_data.no_linkback: flags |= 0x0040
gate.flags = flags
gate.dimensions[0] = mesh_data.dimensions[0]
#endif
/* v102+ */
-enum ent_gate_flag{
+enum ent_gate_flag
+{
k_ent_gate_linked = 0x1, /* this is a working 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_locked = 0x10,/* has to be unlocked to be useful */
k_ent_gate_clean_pass = 0x20,/* player didn't rewind while getting here */
+ k_ent_gate_no_linkback = 0x40,/* NONLOCAL Recievers are not allowed to linkback through this gate */
};
struct ent_gate{
/* runtime */
m4x3f to_world, transport;
-
- union{
+ union
+ {
u32 timing_version;
+ u32 addon_reg;
struct{
u8 ref_count;
SDL_AtomicUnlock( &air_audio_data.sl );
}
+void player__transport( m4x3f transport )
+{
+ struct player_cam_controller *cc = &localplayer.cam_control;
+ m4x3_mulv( transport, cc->tpv_lpf, cc->tpv_lpf );
+ m3x3_mulv( transport, cc->cam_velocity_smooth, cc->cam_velocity_smooth );
+ m4x3_mulv( transport, localplayer.cam.pos, localplayer.cam.pos );
+
+ v3f v0;
+ v3_angles_vector( localplayer.angles, v0 );
+ m3x3_mulv( transport, v0, v0 );
+ v3_angles( v0, localplayer.angles );
+
+ if( player_subsystems[ localplayer.subsystem ]->transport )
+ player_subsystems[ localplayer.subsystem ]->transport( transport );
+ else
+ vg_warn( "Player passed gate, but subsystem(%d) doesn't have a transport function.\n", localplayer.subsystem );
+}
+
/*
* Applies gate transport to a player_interface
*/
void player__pass_gate( u32 id )
{
- world_instance *world = &_world.main;
- skaterift_record_frame( &player_replay.local, 1 );
+ audio_lock();
+ audio_oneshot( &audio_gate_pass, 1.0f, 0.0f );
+ audio_unlock();
- /* update boundary hash (network animation) */
- u16 index = mdl_entity_id_id(id) & ~NETMSG_BOUNDARY_MASK;
- localplayer.boundary_hash ^= NETMSG_GATE_BOUNDARY_BIT;
- localplayer.boundary_hash &= ~NETMSG_BOUNDARY_MASK;
- localplayer.boundary_hash |= index;
-
+ world_instance *world = &_world.main;
ent_gate *gate = af_arritm( &world->ent_gate, mdl_entity_id_id(id) );
- world_routes_fracture( world, gate, localplayer.rb.co, localplayer.rb.v );
- localplayer.gate_waiting = gate;
- localplayer.deferred_frame_record = 1;
+ if( gate->flags & k_ent_gate_nonlocal )
+ {
+ _world.travelled_through_nonlocal_gate = 1;
+ _world.copy_of_nonlocal_sender = *gate;
+ _world.copy_of_nonlocal_sender.target = 0;
+ _world.copy_of_nonlocal_sender.key = 0;
+ _world.copy_of_nonlocal_sender.submesh_start = 0;
+ _world.copy_of_nonlocal_sender.submesh_count = 0;
+
+ vg_strncpy( af_str( &world->meta.af, gate->key ),
+ _world.nonlocal_destination_key, 32,
+ k_strncpy_overflow_fatal );
+
+ addon_reg *reg = get_addon_from_index( k_addon_type_world, gate->addon_reg, 0 );
+ skaterift_switch_world_start( reg );
+ return;
+ }
+ else
+ {
+ player__transport( gate->transport );
- struct player_cam_controller *cc = &localplayer.cam_control;
- m4x3_mulv( gate->transport, cc->tpv_lpf, cc->tpv_lpf );
- m3x3_mulv( gate->transport, cc->cam_velocity_smooth,
- cc->cam_velocity_smooth );
+ skaterift_record_frame( &player_replay.local, 1 );
- m4x3_mulv( gate->transport, localplayer.cam.pos, localplayer.cam.pos );
+ /* update boundary hash (network animation) */
+ u16 index = mdl_entity_id_id(id) & ~NETMSG_BOUNDARY_MASK;
+ localplayer.boundary_hash ^= NETMSG_GATE_BOUNDARY_BIT;
+ localplayer.boundary_hash &= ~NETMSG_BOUNDARY_MASK;
+ localplayer.boundary_hash |= index;
- if( gate->flags & k_ent_gate_nonlocal )
- vg_error( "Nonlocal gates are deprecated!\n" );
- else
- world_routes_activate_entry_gate( world, gate );
-
- v3f v0;
- v3_angles_vector( localplayer.angles, v0 );
- m3x3_mulv( gate->transport, v0, v0 );
- v3_angles( v0, localplayer.angles );
+ localplayer.gate_waiting = gate;
+ localplayer.deferred_frame_record = 1;
- audio_lock();
- audio_oneshot( &audio_gate_pass, 1.0f, 0.0f );
- audio_unlock();
+ world_routes_fracture( world, gate, localplayer.rb.co, localplayer.rb.v );
+ world_routes_activate_entry_gate( world, gate );
+ }
}
void player_apply_transport_to_cam( m4x3f transport )
void(*sfx_comp)(void *animator);
void(*sfx_kill)(void);
+ void(*transport)( m4x3f transport );
void *animator_data;
u32 animator_size;
void player__post_update(void);
void player__pass_gate( u32 id );
+void player__transport( m4x3f transport );
void player__im_gui( ui_context *ctx );
void player__setpos( v3f pos );
void player__spawn( ent_spawn *rp );
.bind = player__skate_bind,
.pre_update = player__skate_pre_update,
.update = player__skate_update,
+ .transport = player__skate_transport,
.post_update = player__skate_post_update,
.im_gui = player__skate_im_gui,
.animate = player__skate_animate,
return new_activity;
}
-void player__skate_update(void){
+void player__skate_update(void)
+{
struct player_skate_state *state = &player_skate.state;
world_instance *world = &_world.main;
u32 id = world_intersect_gates( world, localplayer.rb.co, state->prev_pos );
- if( id ){
+ if( id )
+ {
ent_gate *gate = af_arritm( &world->ent_gate, mdl_entity_id_id(id) );
-
- m4x3_mulv( gate->transport, localplayer.rb.co, localplayer.rb.co );
- m3x3_mulv( gate->transport, localplayer.rb.v, localplayer.rb.v );
- m4x3_mulv( gate->transport, state->cog, state->cog );
- m3x3_mulv( gate->transport, state->cog_v, state->cog_v );
- m3x3_mulv( gate->transport, state->throw_v, state->throw_v );
- m3x3_mulv( gate->transport, state->head_position,
- state->head_position );
- m3x3_mulv( gate->transport, state->up_dir, state->up_dir );
-
- v4f transport_rotation;
- m3x3_q( gate->transport, transport_rotation );
- q_mul( transport_rotation, localplayer.rb.q, localplayer.rb.q );
- q_mul( transport_rotation, state->smoothed_rotation,
- state->smoothed_rotation );
- q_normalize( localplayer.rb.q );
- q_normalize( state->smoothed_rotation );
- rb_update_matrices( &localplayer.rb );
player__pass_gate( id );
}
}
}
+void player__skate_transport( m4x3f transport )
+{
+ struct player_skate_state *state = &player_skate.state;
+ m4x3_mulv( transport, localplayer.rb.co, localplayer.rb.co );
+ m3x3_mulv( transport, localplayer.rb.v, localplayer.rb.v );
+ m4x3_mulv( transport, state->cog, state->cog );
+ m3x3_mulv( transport, state->cog_v, state->cog_v );
+ m3x3_mulv( transport, state->throw_v, state->throw_v );
+ m3x3_mulv( transport, state->head_position, state->head_position );
+ m3x3_mulv( transport, state->up_dir, state->up_dir );
+
+ v4f transport_rotation;
+ m3x3_q( transport, transport_rotation );
+ q_mul( transport_rotation, localplayer.rb.q, localplayer.rb.q );
+ q_mul( transport_rotation, state->smoothed_rotation, state->smoothed_rotation );
+ q_normalize( localplayer.rb.q );
+ q_normalize( state->smoothed_rotation );
+ rb_update_matrices( &localplayer.rb );
+}
+
void player__skate_im_gui( ui_context *ctx )
{
struct player_skate_state *state = &player_skate.state;
void player__skate_bind (void);
void player__skate_pre_update (void);
void player__skate_update (void);
+void player__skate_transport( m4x3f transport );
void player__skate_post_update (void);
void player__skate_im_gui ( ui_context *ctx );
void player__skate_animate (void);
.bind = player__walk_bind,
.pre_update = player__walk_pre_update,
.update = player__walk_update,
+ .transport = player__walk_transport,
.post_update = player__walk_post_update,
.im_gui = player__walk_im_gui,
.animate = player__walk_animate,
}
u32 id = world_intersect_gates(world, localplayer.rb.co, w->state.prev_pos);
- if( id ){
+ if( id )
+ {
ent_gate *gate = af_arritm( &world->ent_gate, mdl_entity_id_id(id) );
- m4x3_mulv( gate->transport, localplayer.rb.co, localplayer.rb.co );
- m3x3_mulv( gate->transport, localplayer.rb.v, localplayer.rb.v );
-
- v4f transport_rotation;
- m3x3_q( gate->transport, transport_rotation );
- q_mul( transport_rotation, localplayer.rb.q, localplayer.rb.q );
- q_normalize( localplayer.rb.q );
- rb_update_matrices( &localplayer.rb );
player__pass_gate( id );
}
rb_update_matrices( &localplayer.rb );
k_runspeed );
}
+void player__walk_transport( m4x3f transport )
+{
+ m4x3_mulv( transport, localplayer.rb.co, localplayer.rb.co );
+ m3x3_mulv( transport, localplayer.rb.v, localplayer.rb.v );
+
+ v4f transport_rotation;
+ m3x3_q( transport, transport_rotation );
+ q_mul( transport_rotation, localplayer.rb.q, localplayer.rb.q );
+ q_normalize( localplayer.rb.q );
+ rb_update_matrices( &localplayer.rb );
+}
+
+
void player__walk_post_update(void){
struct player_walk *w = &player_walk;
void player__walk_pre_update (void);
void player__walk_update (void);
+void player__walk_transport ( m4x3f transport );
void player__walk_post_update (void);
void player__walk_animate (void);
void player__walk_pose (void *animator, player_pose *pose);
world_instance main;
addon_reg *default_hub_addon, *switch_to_addon;
+ addon_reg *previous_world_addon;
+ char nonlocal_destination_key[32];
+ bool travelled_through_nonlocal_gate;
+ ent_gate copy_of_nonlocal_sender;
+
enum world_loader_state
{
k_world_loader_none,
VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main );
world_instance *world = payload;
+ bool found_nonlocal_reciever = 0;
+
for( u32 j=0; j<af_arrcount(&world->ent_gate); j ++ )
{
ent_gate *gate = af_arritm( &world->ent_gate, j );
gate_transform_update( gate );
+
+ if( gate->flags & k_ent_gate_nonlocal )
+ {
+ if( gate->target )
+ {
+ const char *dest_world = af_str( &world->meta.af, gate->target );
+
+ addon_alias q;
+ addon_uid_to_alias( dest_world, &q );
+
+ gate->addon_reg = addon_match( &q );
+ if( gate->addon_reg != 0xffffffff )
+ {
+ gate->flags |= k_ent_gate_linked;
+ vg_info( "Linked non-local gate to addon #%u\n", gate->addon_reg );
+ }
+ else
+ {
+ vg_error( "Reference in non-local gate to other world '%s' was not found.\n", dest_world );
+ }
+ }
+ else
+ {
+ if( _world.travelled_through_nonlocal_gate )
+ {
+ const char *key = af_str( &world->meta.af, gate->key );
+ if( vg_str_eq( key, _world.nonlocal_destination_key ) )
+ {
+ if( found_nonlocal_reciever )
+ vg_warn( "There are multiple nonlocal gates that share the same key in this world (%s)\n", key );
+ else
+ {
+ found_nonlocal_reciever = 1;
+
+ ent_gate *gate2 = &_world.copy_of_nonlocal_sender;
+
+ 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.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] );
+ }
+
+ gate_transform_update( gate );
+ gate_transform_update( gate2 );
+
+ if( !(_world.copy_of_nonlocal_sender.flags & k_ent_gate_no_linkback) )
+ {
+ gate->addon_reg = get_index_from_addon( k_addon_type_world, _world.previous_world_addon );
+
+ if( gate->addon_reg != 0xffffffff )
+ {
+ gate->flags |= k_ent_gate_linked;
+ vg_info( "Linked non-local gate to addon #%u\n", gate->addon_reg );
+ }
+ else
+ {
+ vg_error( "Error while linking to previous world.\n" );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( _world.travelled_through_nonlocal_gate && !found_nonlocal_reciever )
+ {
+ vg_error( "Player travelled through non-local gate, but no reciever gate was found. Player will default to start spawn or world save file.\n" );
+ _world.travelled_through_nonlocal_gate = 0;
}
}
/* start entities in the world */
world_entity_start( data->instance, &sav );
- world_default_spawn_pos( data->instance, localplayer.rb.co );
/* start player in the world */
- vg_msg_init( &sav, data->save.buf, data->save.len );
- vg_msg player_frame = sav;
- if( vg_msg_seekframe( &player_frame, "player" ) )
+ if( _world.travelled_through_nonlocal_gate )
{
- vg_msg_getkvvecf( &player_frame, "position", k_vg_msg_v3f,
- localplayer.rb.co, NULL );
+ player__transport( _world.copy_of_nonlocal_sender.transport );
+ _world.travelled_through_nonlocal_gate = 0;
+ vg_success( "Successfuly consumed linked non-local gates composite transport matrix.\n" );
+ }
+ else
+ {
+ bool restored_player_position = 0;
+
+ vg_msg_init( &sav, data->save.buf, data->save.len );
+ vg_msg player_frame = sav;
+ if( vg_msg_seekframe( &player_frame, "player" ) )
+ {
+ if( vg_msg_getkvvecf( &player_frame, "position", k_vg_msg_v3f,
+ localplayer.rb.co, NULL ) )
+ restored_player_position = 1;
+ }
+
+ if( !restored_player_position )
+ world_default_spawn_pos( data->instance, localplayer.rb.co );
+
+ player__reset();
}
- player__reset();
}
void load_player_from_world_savedata_thread( void *_args )
return;
}
}
+
+ if( reg != _world.main.addon )
+ _world.previous_world_addon = _world.main.addon;
g_client.unreadyness ++;
_world.loader_state = k_world_loader_saving_current;
if( gate->flags & k_ent_gate_nonlocal )
{
+ world->rendering_gate = NULL; /* this is for jump prediction only. */
+
+ if( gate->flags & k_ent_gate_linked )
+ {
+
+ }
+ else
+ {
+ render_gate_unlinked( world, gate, cam );
+ }
}
else
render_gate( world, world, gate, cam );
route->active_checkpoint = 0xffff;
}
- for( u32 i=0; i<af_arrcount( &world->ent_gate ); i++ ){
+ for( u32 i=0; i<af_arrcount( &world->ent_gate ); i++ )
+ {
ent_gate *rg = af_arritm( &world->ent_gate, i );
- rg->timing_version = 0;
- rg->timing_time = 0.0;
+
+ if( !(rg->flags & k_ent_gate_nonlocal) )
+ {
+ rg->timing_version = 0;
+ rg->timing_time = 0.0;
+ }
}
_world.current_run_version += 4;
&world->mesh_route_lines,
200000, 300000 );
- for( u32 i=0; i<af_arrcount(&world->ent_gate); i++ ){
+ for( u32 i=0; i<af_arrcount(&world->ent_gate); i++ )
+ {
ent_gate *gate = af_arritm( &world->ent_gate, i );
- gate->ref_count = 0;
- gate->route_count = 0;
+
+ if( !(gate->flags & k_ent_gate_nonlocal) )
+ {
+ gate->ref_count = 0;
+ gate->route_count = 0;
+ }
}
- for( u32 i=0; i<af_arrcount(&world->ent_route_node); i++ ){
+ for( u32 i=0; i<af_arrcount(&world->ent_route_node); i++ )
+ {
ent_route_node *rn = af_arritm( &world->ent_route_node, i );
rn->ref_count = 0;
rn->ref_total = 0;