boiii-scripts/shared/visionset_mgr_shared.gsc
2023-04-13 17:30:38 +02:00

772 lines
25 KiB
Plaintext

#using scripts\shared\callbacks_shared;
#using scripts\shared\clientfield_shared;
#using scripts\shared\math_shared;
#using scripts\shared\system_shared;
#using scripts\shared\util_shared;
#namespace visionset_mgr;
function autoexec __init__sytem__() { system::register("visionset_mgr",&__init__,undefined,undefined); }
function __init__()
{
level.vsmgr_initializing = true;
level.vsmgr_default_info_name = "__none"; // underscores force this into the zeroth slot
level.vsmgr = [];
level thread register_type( "visionset" );
level thread register_type( "overlay" );
callback::on_finalize_initialization(&finalize_clientfields );
level thread monitor();
callback::on_connect( &on_player_connect );
}
function register_info( type, name, version, priority, lerp_step_count, should_activate_per_player, lerp_thread, ref_count_lerp_thread )
{
assert( level.vsmgr_initializing, "All info registration in the visionset_mgr system must occur during the first frame while the system is initializing" );
lower_name = ToLower( name );
validate_info( type, lower_name, priority );
add_sorted_name_key( type, lower_name );
add_sorted_priority_key( type, lower_name, priority );
level.vsmgr[type].info[lower_name] = spawnstruct();
level.vsmgr[type].info[lower_name] add_info( type, lower_name, version, priority, lerp_step_count, should_activate_per_player, lerp_thread, ref_count_lerp_thread );
if ( level.vsmgr[type].highest_version < version )
{
level.vsmgr[type].highest_version = version;
}
}
function activate( type, name, player, opt_param_1, opt_param_2, opt_param_3 )
{
if ( level.vsmgr[type].info[name].state.should_activate_per_player )
{
activate_per_player( type, name, player, opt_param_1, opt_param_2, opt_param_3 );
return;
}
state = level.vsmgr[type].info[name].state;
if ( state.ref_count_lerp_thread )
{
state.ref_count++;
if ( 1 < state.ref_count )
{
return;
}
}
if ( isdefined( state.lerp_thread ) )
{
state thread lerp_thread_wrapper( state.lerp_thread, opt_param_1, opt_param_2, opt_param_3 );
}
else
{
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
state set_state_active( players[player_index], 1 );
}
}
}
function deactivate( type, name, player )
{
if ( level.vsmgr[type].info[name].state.should_activate_per_player )
{
deactivate_per_player( type, name, player );
return;
}
state = level.vsmgr[type].info[name].state;
if ( state.ref_count_lerp_thread )
{
state.ref_count--;
if ( 0 < state.ref_count )
{
return;
}
}
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
state set_state_inactive( players[player_index] );
}
state notify( "visionset_mgr_deactivate_all" );
}
function set_state_active( player, lerp )
{
player_entnum = player GetEntityNumber();
if ( !IsDefined( self.players[player_entnum] ) )
{
return;
}
self.players[player_entnum].active = true;
self.players[player_entnum].lerp = lerp;
}
function set_state_inactive( player )
{
player_entnum = player GetEntityNumber();
if ( !IsDefined( self.players[player_entnum] ) )
{
return;
}
self.players[player_entnum].active = false;
self.players[player_entnum].lerp = 0;
}
function timeout_lerp_thread( timeout, opt_param_2, opt_param_3 )
{
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
self set_state_active( players[player_index], 1 );
}
wait( timeout );
deactivate( self.type, self.name );
}
function timeout_lerp_thread_per_player( player, timeout, opt_param_2, opt_param_3 )
{
self set_state_active( player, 1 );
wait( timeout );
deactivate_per_player( self.type, self.name, player );
}
function duration_lerp_thread( duration, max_duration )
{
start_time = GetTime();
end_time = start_time + int( duration * 1000 );
if ( isdefined( max_duration ) )
{
// if a max_duration is supplied, we adjust the start time so that our lerp begins at less than 1,
// since we won't be running for the full duration that the clientside expects
start_time = end_time - int( max_duration * 1000 );
}
while ( true )
{
lerp = calc_remaining_duration_lerp( start_time, end_time );
if ( 0 >= lerp )
{
break;
}
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
self set_state_active( players[player_index], lerp );
}
{wait(.05);};
}
deactivate( self.type, self.name );
}
function duration_lerp_thread_per_player( player, duration, max_duration )
{
start_time = GetTime();
end_time = start_time + int( duration * 1000 );
if ( isdefined( max_duration ) )
{
// if a max_duration is supplied, we adjust the start time so that our lerp begins at less than 1,
// since we won't be running for the full duration that the clientside expects
start_time = end_time - int( max_duration * 1000 );
}
while ( true )
{
lerp = calc_remaining_duration_lerp( start_time, end_time );
if ( 0 >= lerp )
{
break;
}
self set_state_active( player, lerp );
{wait(.05);};
}
deactivate_per_player( self.type, self.name, player );
}
function ramp_in_thread_per_player( player, duration )
{
start_time = GetTime();
end_time = start_time + int( duration * 1000 );
while ( true )
{
lerp = calc_ramp_in_lerp( start_time, end_time );
if ( 1 <= lerp )
{
break;
}
self set_state_active( player, lerp );
{wait(.05);};
}
}
function ramp_in_out_thread_hold_func()
{
level endon( "kill_ramp_in_out_thread_hold_func" );
while ( true )
{
for ( player_index = 0; player_index < level.players.size; player_index++ )
{
self visionset_mgr::set_state_active( level.players[player_index], 1 );
}
{wait(.05);};
}
}
function ramp_in_out_thread( ramp_in, full_period, ramp_out )
{
start_time = GetTime();
end_time = start_time + int( ramp_in * 1000 );
while ( true )
{
lerp = calc_ramp_in_lerp( start_time, end_time );
if ( 1 <= lerp )
{
break;
}
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
self set_state_active( players[player_index], lerp );
}
{wait(.05);};
}
self thread ramp_in_out_thread_hold_func();
if ( IsFunctionPtr( full_period ) )
{
self [[full_period]]();
}
else
{
wait( full_period );
}
level notify( "kill_ramp_in_out_thread_hold_func" );
start_time = GetTime();
end_time = start_time + int( ramp_out * 1000 );
while ( true )
{
lerp = calc_remaining_duration_lerp( start_time, end_time );
if ( 0 >= lerp )
{
break;
}
players = GetPlayers();
for ( player_index = 0; player_index < players.size; player_index++ )
{
self set_state_active( players[player_index], lerp );
}
{wait(.05);};
}
deactivate( self.type, self.name );
}
function ramp_in_out_thread_per_player_internal( player, ramp_in, full_period, ramp_out )
{
start_time = GetTime();
end_time = start_time + int( ramp_in * 1000 );
while ( true )
{
lerp = calc_ramp_in_lerp( start_time, end_time );
if ( 1 <= lerp )
{
break;
}
self set_state_active( player, lerp );
{wait(.05);};
}
self set_state_active( player, lerp );
if ( IsFunctionPtr( full_period ) )
{
player [[full_period]]();
}
else
{
wait( full_period );
}
start_time = GetTime();
end_time = start_time + int( ramp_out * 1000 );
while ( true )
{
lerp = calc_remaining_duration_lerp( start_time, end_time );
if ( 0 >= lerp )
{
break;
}
self set_state_active( player, lerp );
{wait(.05);};
}
deactivate_per_player( self.type, self.name, player );
}
function ramp_in_out_thread_watch_player_shutdown( player )
{
player notify( "ramp_in_out_thread_watch_player_shutdown" );
player endon( "ramp_in_out_thread_watch_player_shutdown" );
player endon( "disconnect" );
player waittill( "death" );
if ( player IsRemoteControlling() == false )
deactivate_per_player( self.type, self.name, player );
}
function ramp_in_out_thread_per_player_death_shutdown( player, ramp_in, full_period, ramp_out )
{
player endon ( "death" );
thread ramp_in_out_thread_watch_player_shutdown( player );
ramp_in_out_thread_per_player_internal( player, ramp_in, full_period, ramp_out );
}
function ramp_in_out_thread_per_player( player, ramp_in, full_period, ramp_out )
{
ramp_in_out_thread_per_player_internal( player, ramp_in, full_period, ramp_out );
}
function register_type( type )
{
level.vsmgr[type] = spawnstruct();
level.vsmgr[type].type = type;
level.vsmgr[type].in_use = false; // true if items other than the default value has been registered
level.vsmgr[type].highest_version = 0;
level.vsmgr[type].cf_slot_name = type + "_slot";
level.vsmgr[type].cf_lerp_name = type + "_lerp";
level.vsmgr[type].info = [];
level.vsmgr[type].sorted_name_keys = [];
level.vsmgr[type].sorted_prio_keys = [];
register_info( type, level.vsmgr_default_info_name, 1, 0, 1, false, undefined );
}
function finalize_clientfields()
{
typeKeys = GetArrayKeys( level.vsmgr );
for ( type_index = 0; type_index < typeKeys.size; type_index++ )
{
level.vsmgr[typeKeys[type_index]] thread finalize_type_clientfields();
}
level.vsmgr_initializing = false; // registering new infos is not allowed after this point
}
function finalize_type_clientfields()
{
/#println( "visionset_mgr [" + self.type + "] server registrations:" );#/
if ( 1 >= self.info.size ) // if only the default info has been registered, don't spend bits on this type
{
return;
}
self.in_use = true;
self.cf_slot_bit_count = GetMinBitCountForNum( self.info.size - 1 );
self.cf_lerp_bit_count = self.info[self.sorted_name_keys[0]].lerp_bit_count;
for ( i = 0; i < self.sorted_name_keys.size; i++ )
{
self.info[self.sorted_name_keys[i]].slot_index = i;
if ( self.info[self.sorted_name_keys[i]].lerp_bit_count > self.cf_lerp_bit_count )
{
self.cf_lerp_bit_count = self.info[self.sorted_name_keys[i]].lerp_bit_count;
}
/#println( " name: " + self.info[self.sorted_name_keys[i]].name + ", version: " + self.info[self.sorted_name_keys[i]].version + ", lerp_step_count: " + self.info[self.sorted_name_keys[i]].lerp_step_count + "" );#/
}
clientfield::register( "toplayer", self.cf_slot_name, self.highest_version, self.cf_slot_bit_count, "int" );
// don't spend a clientfield if all slots are just on/off
if ( 1 < self.cf_lerp_bit_count )
{
clientfield::register( "toplayer", self.cf_lerp_name, self.highest_version, self.cf_lerp_bit_count, "float" );
}
}
function validate_info( type, name, priority )
{
keys = GetArrayKeys( level.vsmgr );
for ( i = 0; i < keys.size; i++ )
{
if ( type == keys[i] )
{
break;
}
}
assert( i < keys.size, "In visionset_mgr, type '" + type + "'is unknown" );
keys = GetArrayKeys( level.vsmgr[type].info );
for ( i = 0; i < keys.size; i++ )
{
assert( level.vsmgr[type].info[keys[i]].name != name, "In visionset_mgr of type '" + type + "': name '" + name + "' has previously been registered" );
assert( level.vsmgr[type].info[keys[i]].priority != priority, "In visionset_mgr of type '" + type + "': priority '" + priority + "' requested for name '" + name + "' has previously been registered under name '" + level.vsmgr[type].info[keys[i]].name + "'");
}
}
function add_sorted_name_key( type, name )
{
for ( i = 0; i < level.vsmgr[type].sorted_name_keys.size; i++ )
{
if ( name < level.vsmgr[type].sorted_name_keys[i] )
{
break;
}
}
ArrayInsert( level.vsmgr[type].sorted_name_keys, name, i );
}
function add_sorted_priority_key( type, name, priority )
{
for ( i = 0; i < level.vsmgr[type].sorted_prio_keys.size; i++ )
{
if ( priority > level.vsmgr[type].info[level.vsmgr[type].sorted_prio_keys[i]].priority )
{
break;
}
}
ArrayInsert( level.vsmgr[type].sorted_prio_keys, name, i );
}
function add_info( type, name, version, priority, lerp_step_count, should_activate_per_player, lerp_thread, ref_count_lerp_thread )
{
self.type = type;
self.name = name;
self.version = version;
self.priority = priority;
self.lerp_step_count = lerp_step_count;
self.lerp_bit_count = GetMinBitCountForNum( lerp_step_count );
if ( !isdefined( ref_count_lerp_thread ) )
{
ref_count_lerp_thread = false;
}
self.state = spawnstruct();
self.state.type = type;
self.state.name = name;
self.state.should_activate_per_player = should_activate_per_player;
self.state.lerp_thread = lerp_thread;
self.state.ref_count_lerp_thread = ref_count_lerp_thread;
self.state.players = [];
if ( ref_count_lerp_thread && !should_activate_per_player )
{
self.state.ref_count = 0;
}
}
function on_player_connect()
{
self player_setup();
}
function player_setup()
{
self.vsmgr_player_entnum = self GetEntityNumber();
typeKeys = GetArrayKeys( level.vsmgr );
for ( type_index = 0; type_index < typeKeys.size; type_index++ )
{
type = typeKeys[type_index];
if ( !level.vsmgr[type].in_use )
{
continue;
}
for ( name_index = 0; name_index < level.vsmgr[type].sorted_name_keys.size; name_index++ )
{
name_key = level.vsmgr[type].sorted_name_keys[name_index];
level.vsmgr[type].info[name_key].state.players[self.vsmgr_player_entnum] = SpawnStruct();
level.vsmgr[type].info[name_key].state.players[self.vsmgr_player_entnum].active = false;
level.vsmgr[type].info[name_key].state.players[self.vsmgr_player_entnum].lerp = 0;
if ( level.vsmgr[type].info[name_key].state.ref_count_lerp_thread && level.vsmgr[type].info[name_key].state.should_activate_per_player )
{
level.vsmgr[type].info[name_key].state.players[self.vsmgr_player_entnum].ref_count = 0;
}
}
level.vsmgr[type].info[level.vsmgr_default_info_name].state set_state_active( self, 1 );
}
}
function player_shutdown()
{
self.vsmgr_player_entnum = self GetEntityNumber();
typeKeys = GetArrayKeys( level.vsmgr );
for ( type_index = 0; type_index < typeKeys.size; type_index++ )
{
type = typeKeys[type_index];
if ( !level.vsmgr[type].in_use )
{
continue;
}
for ( name_index = 0; name_index < level.vsmgr[type].sorted_name_keys.size; name_index++ )
{
name_key = level.vsmgr[type].sorted_name_keys[name_index];
deactivate_per_player( type, name_key, self );
}
}
}
function monitor()
{
while ( level.vsmgr_initializing )
{
{wait(.05);};
}
typeKeys = GetArrayKeys( level.vsmgr );
while ( true )
{
{wait(.05);};
waittillframeend;
players = GetPlayers();
for ( type_index = 0; type_index < typeKeys.size; type_index++ )
{
type = typeKeys[type_index];
if ( !level.vsmgr[type].in_use )
{
continue;
}
for ( player_index = 0; player_index < players.size; player_index++ )
{
if ( !IsDefined( players[player_index].vsmgr_player_entnum ) )
{
continue;
}
update_clientfields( players[player_index], level.vsmgr[type] );
}
}
}
}
function get_first_active_name( type_struct )
{
//player_entnum = player GetEntityNumber();
size = type_struct.sorted_prio_keys.size;
for ( prio_index = 0; prio_index < size; prio_index++ )
{
prio_key = type_struct.sorted_prio_keys[prio_index];
if ( type_struct.info[prio_key].state.players[self.vsmgr_player_entnum].active )
{
return prio_key;
}
}
return level.vsmgr_default_info_name;
}
function update_clientfields( player, type_struct )
{
//player_entnum = player GetEntityNumber();
name = player get_first_active_name( type_struct );
player clientfield::set_to_player( type_struct.cf_slot_name, type_struct.info[name].slot_index );
if ( 1 < type_struct.cf_lerp_bit_count )
{
player clientfield::set_to_player( type_struct.cf_lerp_name, type_struct.info[name].state.players[player.vsmgr_player_entnum].lerp );
}
}
function lerp_thread_wrapper( func, opt_param_1, opt_param_2, opt_param_3 )
{
self notify( "visionset_mgr_deactivate_all" );
self endon( "visionset_mgr_deactivate_all" );
self [[func]]( opt_param_1, opt_param_2, opt_param_3 );
}
function lerp_thread_per_player_wrapper( func, player, opt_param_1, opt_param_2, opt_param_3 )
{
player_entnum = player GetEntityNumber();
self.players[player_entnum] notify( "visionset_mgr_deactivate" );
self.players[player_entnum] endon( "visionset_mgr_deactivate" );
player endon( "disconnect" );
self [[func]]( player, opt_param_1, opt_param_2, opt_param_3 );
}
function activate_per_player( type, name, player, opt_param_1, opt_param_2, opt_param_3 )
{
player_entnum = player GetEntityNumber();
state = level.vsmgr[type].info[name].state;
if ( state.ref_count_lerp_thread )
{
state.players[player_entnum].ref_count++;
if ( 1 < state.players[player_entnum].ref_count )
{
return;
}
}
if ( isdefined( state.lerp_thread ) )
{
state thread lerp_thread_per_player_wrapper( state.lerp_thread, player, opt_param_1, opt_param_2, opt_param_3 );
}
else
{
state set_state_active( player, 1 );
}
}
function deactivate_per_player( type, name, player )
{
player_entnum = player GetEntityNumber();
state = level.vsmgr[type].info[name].state;
if ( state.ref_count_lerp_thread )
{
state.players[player_entnum].ref_count--;
if ( 0 < state.players[player_entnum].ref_count )
{
return;
}
}
state set_state_inactive( player );
state.players[player_entnum] notify( "visionset_mgr_deactivate" );
}
function calc_ramp_in_lerp( start_time, end_time )
{
if( 0 >= ( end_time - start_time ) )
{
return 1;
}
now = GetTime();
frac = float(now - start_time) / float(end_time - start_time);
return math::clamp( frac, 0, 1 );
}
function calc_remaining_duration_lerp( start_time, end_time )
{
if( 0 >= ( end_time - start_time ) )
{
return 0;
}
now = GetTime();
frac = float(end_time - now) / float(end_time - start_time);
return math::clamp( frac, 0, 1 );
}