UGX-Mods Login

or login with an authentication provider below
Sign In with Google
Sign In with Twitter
Sign In with Discord
Sign In with Steam
Sign In with Facebook
Sign In with Twitch

Unlimited Client Systems In WaW

broken avatar :(
Created 8 years ago
by alaurenc9
0 Members and 1 Guest are viewing this topic.
5,909 views
broken avatar :(
×
broken avatar :(
Location: us
Date Registered: 30 December 2012
Last active: 8 months ago
Posts
577
Respect
Forum Rank
Zombie Enslaver
Primary Group
Community Scripter
My Groups
More
My Contact & Social Links
More
Signature
My preferred name is "xSanchez78".
Check me out here: www.steamcommunity.com/id/xSanchez78
×
alaurenc9's Groups
Donator ♥ Benevolent Soul who has our eternal gratitude and exclusive access to betas and the donator section of the forum.
Community Scripter Has shown effort and knowledge in the area of scripting while being a part of the UGX-Mods community.
alaurenc9's Contact & Social LinksxSanchez78xSanchez78xSanchez78xSanchez78xSanchez78xSanchez78
Hey guys today I'm going to release something that I've been using for awhile in my der riese mod and thought it would probably help other people who use CSC. Today I'm releasing my fake client systems, which basically use one WaW engine client system to pass info in other "fake" systems.

This solves two problems that I have noticed with WaW client systems:

1. There is a limit of 8 in WaW, and 7 are used by default
2. When a player is spectating and you call a client system callback on them, it does not actually thread to them. Basically I use a separate way to specify which player you are threading to in CSC.

The setup is pretty simple.
First create a GSC script called _xS78_fake_clientsystems.gsc Put this into the script:
Code Snippet
Plaintext
#include maps\_utility;
#include common_scripts\utility;
#include maps\_zombiemode_utility;

init()
{
registerClientSys( "fake_client_systems" );
level thread onPlayerConnect();
}

onPlayerConnect()
{
while( true )
{
level waittill( "connecting", player );
setClientSysState( "levelNotify", "set_client_id_" + player GetEntityNumber(), player );
}
}
Next create a CSC script called _xS78_fake_clientsystems.csc Put this into the script:
Code Snippet
Plaintext
#include clientscripts\_utility;
#include clientscripts\_music;

init()
{
level.player_id_number = [];
level.fake_client_system_callbacks = [];
level thread set_client_id( 0 );
level thread set_client_id( 1 );
level thread set_client_id( 2 );
level thread set_client_id( 3 );
registerSystem( "fake_client_systems", ::fake_client_systems );
}

set_client_id( id )
{
level waittill( "set_client_id_" + id, localclientnum );
level.player_id_number[ localclientnum ] = id;
}

fake_client_systems( localclientnum, state )
{
tokens = StrTok( state, "|" );
system_info = StrTok( tokens[0], "," );
if( system_info[0] == "all" || system_info[0] == string( level.player_id_number[ localclientnum ] ) )
{
system_name_and_state = GetSubStr( state, tokens[0].size + 1, state.size );
system_name = GetSubStr( system_name_and_state, 0, Int( system_info[1] ) );
system_state = GetSubStr( system_name_and_state, system_name.size, system_name_and_state.size );
if( IsDefined( level.fake_client_system_callbacks ) && IsDefined( level.fake_client_system_callbacks[ system_name ] ) )
{
level thread [[ level.fake_client_system_callbacks[ system_name ] ]]( localclientnum, system_state );
}
}
}
Now open a utility file in GSC ( preferably _zombiemode_utility.gsc ) and place this function at the bottom:
Code Snippet
Plaintext
set_client_system_state( system_name, system_state, player )
{
if( IsDefined( player ) )
{
player_num = string( player GetEntityNumber() );
}
else
{
player_num = "all";
}
state = player_num + "," + string( system_name.size ) + "|" + system_name + system_state;
setClientSysState( "fake_client_systems", state );
}
For the next part, you will need to add stuff to _utility.csc Thanks to my friend I found out that this script is not in raw or included with the script placer or anything so here is one:
Code Snippet
Plaintext
#include clientscripts\_utility_code; 
#include clientscripts\_fx;

/*
=============
///ScriptDocBegin
"Name: getstructarray( <name> , <type )"
"Summary: gets an array of script_structs"
"Module: Array"
"CallOn: An entity"
"MandatoryArg: <name>: "
"MandatoryArg: <type>: "
"Example: fxemitters = getstructarray( "streetlights" , "targetname" )"
"SPMP: singleplayer"
///ScriptDocEnd
=============
*/

error( message )
{
println( "^c * ERROR * ", message );
wait 0.05;
 }

// fancy quicker struct array handling, assumes array elements are objects with which an index can be asigned to( IE: can't do 5.struct_array_index )
// also have to be sure that objects can't be a part of another structarray setup as the index position is asigned to the object



getstruct( name, type )
{
if(!IsDefined( level.struct_class_names ) )
return undefined;

array = level.struct_class_names[ type ][ name ];
if( !IsDefined( array ) )
{
println("**** Getstruct returns undefined on " + name + " : " + " type.");
return undefined;
}

if( array.size > 1 )
{
assertMsg( "getstruct used for more than one struct of type " + type + " called " + name + "." );
return undefined;
}
return array[ 0 ];
}

getstructarray( name, type )
{
assertEx( IsDefined( level.struct_class_names ), "Tried to getstruct before the structs were init" );

array = level.struct_class_names[type][name];
if(!IsDefined( array ) )
{
return [];
}
else
{
return array;
}
}

 /*
 =============
///ScriptDocBegin
"Name: play_sound_in_space( <clientNum>, <alias> , <origin>  )"
"Summary: Stop playing the the loop sound alias on an entity"
"Module: Sound"
"CallOn: Level"
"MandatoryArg: <clientNum> : local client to hear the sound."
"MandatoryArg: <alias> : Sound alias to play"
"MandatoryArg: <origin> : Origin of the sound"
"Example: play_sound_in_space( "siren", level.speaker.origin );"
"SPMP: singleplayer"
///ScriptDocEnd
 =============
 */
play_sound_in_space( localClientNum, alias, origin)
{
PlaySound( localClientNum, alias, origin);
}

vectorScale( vector, scale )
{
vector = (vector[0] * scale, vector[1] * scale, vector[2] * scale);
return vector;
}

vector_multiply( vec, dif )
{
vec = ( vec[ 0 ] * dif, vec[ 1 ] * dif, vec[ 2 ] * dif );
return vec;
}

/*
 =============
///ScriptDocBegin
"Name: array_thread( <entities> , <process> , <var1> , <var2> , <var3> )"
"Summary: Threads the < process > function on every entity in the < entities > array. The entity will become "self" in the specified function."
"Module: Array"
"CallOn: "
"MandatoryArg: <entities> : array of entities to thread the process"
"MandatoryArg: <process> : pointer to a script function"
"OptionalArg: <var1> : parameter 1 to pass to the process"
"OptionalArg: <var2> : parameter 2 to pass to the process"
"OptionalArg: <var3> : parameter 3 to pass to the process"
"Example: array_thread( getaiarray( "allies" ), ::set_ignoreme, false );"
"SPMP: both"
///ScriptDocEnd
 =============
*/
array_thread( entities, process, var1, var2, var3 )
{
keys = getArrayKeys( entities );

if ( IsDefined( var3 ) )
{
for( i = 0 ; i < keys.size ; i ++ )
entities[ keys[ i ] ] thread [[ process ]]( var1, var2, var3 );

return;
}

if ( IsDefined( var2 ) )
{
for( i = 0 ; i < keys.size ; i ++ )
entities[ keys[ i ] ] thread [[ process ]]( var1, var2 );

return;
}

if ( IsDefined( var1 ) )
{
for( i = 0 ; i < keys.size ; i ++ )
entities[ keys[ i ] ] thread [[ process ]]( var1 );

return;
}

for( i = 0 ; i < keys.size ; i ++ )
entities[ keys[ i ] ] thread [[ process ]]();
}

registerSystem(sSysName, cbFunc)
{
if(!IsDefined(level._systemStates))
{
level._systemStates = [];
}

if(level._systemStates.size >= 32)
{
error("Max num client systems exceeded.");
return;
}

if(IsDefined(level._systemStates[sSysName]))
{
error("Attempt to re-register client system : " + sSysName);
return;
}
else
{
level._systemStates[sSysName] = spawnstruct();
level._systemStates[sSysName].callback = cbFunc;
}
}

loop_sound_Delete( ender, entId )
{
// ent endon( "death" );
self waittill( ender );
deletefakeent(0, entId);
}

loop_fx_sound( clientNum, alias, origin, ender )
{
entId = spawnfakeent(clientNum);

if( IsDefined( ender ) )
{
thread loop_sound_Delete( ender, entId );
self endon( ender );
}

setfakeentorg(clientNum, entId, origin);
playloopsound( clientNum, entId, alias );
}

waitforclient(client)
{
while(!clienthassnapshot(client))
{
wait(0.01);
}
syncsystemstates(client);
}

/*
 =============
///CScriptDocBegin
"Name: within_fov( <start_origin> , <start_angles> , <end_origin> , <fov> )"
"Summary: Returns true if < end_origin > is within the players field of view, otherwise returns false."
"Module: Vector"
"CallOn: "
"MandatoryArg: <start_origin> : starting origin for FOV check( usually the players origin )"
"MandatoryArg: <start_angles> : angles to specify facing direction( usually the players angles )"
"MandatoryArg: <end_origin> : origin to check if it's in the FOV"
"MandatoryArg: <fov> : cosine of the FOV angle to use"
"Example: qBool = within_fov( level.player.origin, level.player.angles, target1.origin, cos( 45 ) );"
"SPMP: singleplayer"
///CScriptDocEnd
 =============
 */
within_fov( start_origin, start_angles, end_origin, fov )
{
normal = VectorNormalize( end_origin - start_origin );
forward = AnglesToForward( start_angles );
dot = VectorDot( forward, normal );

return dot >= fov;
}


/*
=============
///CScriptDocBegin
"Name: add_to_array( <array> , <ent> )"
"Summary: Adds < ent > to < array > and returns the new array."
"Module: Array"
"CallOn: "
"MandatoryArg: <array> : The array to add < ent > to."
"MandatoryArg: <ent> : The entity to be added."
"Example: nodes = add_to_array( nodes, new_node );"
"SPMP: singleplayer"
///CScriptDocEnd
=============
*/
add_to_array( array, ent )
{
if( !IsDefined( ent ) )
return array;

if( !IsDefined( array ) )
array[ 0 ] = ent;
else
array[ array.size ] = ent;

return array;
}

setFootstepEffect(name, fx)
{
assertEx(IsDefined(name), "Need to define the footstep surface type.");
assertEx(IsDefined(fx), "Need to define the mud footstep effect.");
if (!IsDefined(level._optionalStepEffects))
level._optionalStepEffects = [];
level._optionalStepEffects[level._optionalStepEffects.size] = name;
level._effect["step_" + name] = fx;
}

getExploderId( ent )
{
if(!IsDefined(level._exploder_ids))
{
level._exploder_ids = [];
level._exploder_id = 1;
}

if(!IsDefined(level._exploder_ids[ent.v["exploder"]]))
{
level._exploder_ids[ent.v["exploder"]] = level._exploder_id;
level._exploder_id ++;
}

return level._exploder_ids[ent.v["exploder"]];
}

reportExploderIds()
{
if(!IsDefined(level._exploder_ids))
return;

keys = GetArrayKeys( level._exploder_ids );

println("Client Exploder dictionary : ");

for( i = 0; i < keys.size; i++ )
{
println(keys[i] + " : " + level._exploder_ids[keys[i]]);
}

}

init_exploders()
{
println("*** Init exploders...");
script_exploders = [];

ents = GetStructArray( "script_brushmodel", "classname" );
println("Client : s_bm " + ents.size);

smodels = GetStructArray( "script_model", "classname" );
println("Client : sm " + smodels.size);

for( i = 0; i < smodels.size; i++ )
{
ents[ents.size] = smodels[i];
}

for( i = 0; i < ents.size; i++ )
{
if( IsDefined( ents[i].script_prefab_exploder ) )
{
ents[i].script_exploder = ents[i].script_prefab_exploder;
}
}

potentialExploders = GetStructArray( "script_brushmodel", "classname" );
println("Client : Potential exploders from script_brushmodel " + potentialExploders.size);

for( i = 0; i < potentialExploders.size; i++ )
{
if( IsDefined( potentialExploders[i].script_prefab_exploder ) )
{
potentialExploders[i].script_exploder = potentialExploders[i].script_prefab_exploder;
}

if( IsDefined( potentialExploders[i].script_exploder ) )
{
script_exploders[script_exploders.size] = potentialExploders[i];
}
}

potentialExploders = GetStructArray( "script_model", "classname" );
println("Client : Potential exploders from script_model " + potentialExploders.size);

for( i = 0; i < potentialExploders.size; i++ )
{
if( IsDefined( potentialExploders[i].script_prefab_exploder ) )
{
potentialExploders[i].script_exploder = potentialExploders[i].script_prefab_exploder;
}

if( IsDefined( potentialExploders[i].script_exploder ) )
{
script_exploders[script_exploders.size] = potentialExploders[i];
}
}

// Also support script_structs to work as exploders
for( i = 0; i < level.struct.size; i++ )
{
if( IsDefined( level.struct[i].script_prefab_exploder ) )
{
level.struct[i].script_exploder = level.struct[i].script_prefab_exploder;
}

if( IsDefined( level.struct[i].script_exploder ) )
{
script_exploders[script_exploders.size] = level.struct[i];
}
}

if( !IsDefined( level.createFXent ) )
{
level.createFXent = [];
}

acceptableTargetnames = [];
acceptableTargetnames["exploderchunk visible"] = true;
acceptableTargetnames["exploderchunk"] = true;
acceptableTargetnames["exploder"] = true;

exploder_id = 1;

for( i = 0; i < script_exploders.size; i++ )
{
exploder = script_exploders[i];
ent = createExploder( exploder.script_fxid );
ent.v = [];
if(!IsDefined(exploder.origin))
{
println("************** NO EXPLODER ORIGIN." + i);
}
ent.v["origin"] = exploder.origin;
ent.v["angles"] = exploder.angles;
ent.v["delay"] = exploder.script_delay;
ent.v["firefx"] = exploder.script_firefx;
ent.v["firefxdelay"] = exploder.script_firefxdelay;
ent.v["firefxsound"] = exploder.script_firefxsound;
ent.v["firefxtimeout"] = exploder.script_firefxtimeout;
ent.v["trailfx"] = exploder.script_trailfx;
ent.v["trailfxtag"] = exploder.script_trailfxtag;
ent.v["trailfxdelay"] = exploder.script_trailfxdelay;
ent.v["trailfxsound"] = exploder.script_trailfxsound;
ent.v["trailfxtimeout"] = exploder.script_firefxtimeout;
ent.v["earthquake"] = exploder.script_earthquake;
ent.v["rumble"] = exploder.script_rumble;
ent.v["damage"] = exploder.script_damage;
ent.v["damage_radius"] = exploder.script_radius;
ent.v["repeat"] = exploder.script_repeat;
ent.v["delay_min"] = exploder.script_delay_min;
ent.v["delay_max"] = exploder.script_delay_max;
ent.v["target"] = exploder.target;
ent.v["ender"] = exploder.script_ender;
ent.v["physics"] = exploder.script_physics;
ent.v["type"] = "exploder";
// ent.v["worldfx"] = true;

if( !IsDefined( exploder.script_fxid ) )
{
ent.v["fxid"] = "No FX";
}
else
{
ent.v["fxid"] = exploder.script_fxid;
}
ent.v["exploder"] = exploder.script_exploder;
// assertex( IsDefined( exploder.script_exploder ), "Exploder at origin " + exploder.origin + " has no script_exploder" );

if( !IsDefined( ent.v["delay"] ) )
{
ent.v["delay"] = 0;
}

// MikeD( 4/14/2008 ): Attempt to use the fxid as the sound reference, this way Sound can add sounds to anything
// without the scripter needing to modify the map
if( IsDefined( exploder.script_sound ) )
{
ent.v["soundalias"] = exploder.script_sound;
}
else if( ent.v["fxid"] != "No FX"  )
{
if( IsDefined( level.scr_sound ) && IsDefined( level.scr_sound[ent.v["fxid"]] ) )
{
ent.v["soundalias"] = level.scr_sound[ent.v["fxid"]];
}
}

fixup_set = false;

if(IsDefined(ent.v["target"]))
{
ent.needs_fixup = exploder_id;
exploder_id++;
fixup_set = true;

/* temp_ent = GetEnt(0, ent.v["target"], "targetname" );
if( IsDefined( temp_ent ) )
{
org = temp_ent.origin;
}
else */
{
temp_ent = GetStruct( ent.v["target"], "targetname" );
org = temp_ent.origin;
}

if(IsDefined(org))
{
ent.v["angles"] = VectorToAngles( org - ent.v["origin"] );
}
else
{
println("*** Client : Exploder " + exploder.script_fxid + " Failed to find target ");
}

if(IsDefined(ent.v["angles"]))
{
ent set_forward_and_up_vectors();
}
else
{
println("*** Client " + exploder.script_fxid + " has no angles.");
}

}


// this basically determines if its a brush/model exploder or not
if( exploder.classname == "script_brushmodel" || IsDefined( exploder.model ) )
{
if(IsDefined(exploder.model))
{
println("*** exploder " + exploder_id + " model " + exploder.model);
}
ent.model = exploder;
//ent.model.disconnect_paths = exploder.script_disconnectpaths;
if(fixup_set == false)
{
ent.needs_fixup = exploder_id;
exploder_id++;
}
}

if( IsDefined( exploder.targetname ) && IsDefined( acceptableTargetnames[exploder.targetname] ) )
{
ent.v["exploder_type"] = exploder.targetname;
}
else
{
ent.v["exploder_type"] = "normal";
}
}

for(i = 0; i < level.createFXent.size;i ++ )
{
ent = level.createFXent[i];

if(ent.v["type"] != "exploder")
continue;

ent.v["exploder_id"] = getExploderId( ent );

}

reportExploderIds();


println("*** Client : " + script_exploders.size + " exploders.");

}


playfx_for_all_local_clients( fx_id, pos, forward_vec, up_vec )
{

localPlayers = getlocalplayers();

if( IsDefined( up_vec ) )
{
for(i = 0; i < localPlayers.size; i ++)
{
playfx( i, fx_id, pos, forward_vec, up_vec );
}
}
else if( IsDefined( forward_vec ) )
{
for(i = 0; i < localPlayers.size; i ++)
{
playfx( i, fx_id, pos, forward_vec );
}
}
else
{
for(i = 0; i < localPlayers.size; i ++)
{
playfx( i, fx_id, pos );
}
}
}

play_sound_on_client( sound_alias )
{
players = GetLocalPlayers();

PlaySound( 0, sound_alias, players[0].origin );
}

loop_sound_on_client( sound_alias, min_delay, max_delay, end_on )
{
players = GetLocalPlayers();

if( IsDefined( end_on ) )
{
level endon( end_on );
}

for( ;; )
{
play_sound_on_client( sound_alias );
wait( min_delay + RandomFloat( max_delay ) );
}
}

add_listen_thread( wait_till, func, param1, param2, param3, param4, param5 )
{
level thread add_listen_thread_internal( wait_till, func, param1, param2, param3, param4, param5 );
}

add_listen_thread_internal( wait_till, func, param1, param2, param3, param4, param5 )
{
for( ;; )
{
level waittill( wait_till );

if( IsDefined( param5 ) )
{
level thread [[ func ]]( param1, param2, param3, param4, param5 );
}
else if( IsDefined( param4 ) )
{
level thread [[ func ]]( param1, param2, param3, param4 );
}
else if( IsDefined( param3 ) )
{
level thread [[ func ]]( param1, param2, param3 );
}
else if( IsDefined( param2 ) )
{
level thread [[ func ]]( param1, param2 );
}
else if( IsDefined( param1 ) )
{
level thread [[ func ]]( param1 );
}
else
{
level thread [[ func ]]();
}
}
}

addLightningExploder(num)
{
if (!isdefined(level.lightningExploder))
{
level.lightningExploder = [];
level.lightningExploderIndex = 0;
}

level.lightningExploder[level.lightningExploder.size] = num;
}


/*
 =============
///CScriptDocBegin
"Name: splitscreen_populate_dvars( <clientNum> )"
"Summary: Populates profile dvars with settings read from clientNum's profile data."
"Module: System"
"MandatoryArg: <clientNum> : the local client num of the profile to be read"
"Example: splitscreen_populate_dvars( 1 );"
"SPMP: singleplayer"
///CScriptDocEnd
 =============
 */
splitscreen_populate_dvars( clientNum )
{
if ( getlocalplayers().size <= 1 )
{
return;
}

UpdateDvarsFromProfile( clientNum );
}


/*
 =============
///CScriptDocBegin
"Name: splitscreen_restore_dvars()"
"Summary: Restores profile dvars with settings read from client 0's profile data."
"Module: System"
"Example: splitscreen_restore_dvars();"
"SPMP: singleplayer"
///CScriptDocEnd
 =============
 */
splitscreen_restore_dvars()
{
if ( getlocalplayers().size <= 1 )
{
return;
}

splitscreen_populate_dvars( 0 );
}



Place these functions at the bottom of that file:
Code Snippet
Plaintext
register_client_system( system_name, callback_func )
{
level.fake_client_system_callbacks[ system_name ] = callback_func;
}

StrTok( string, delimiter )
{
tokens = [];
next_token = "";
for( i = 0; i < string.size; i ++ )
{
if( string[i] == delimiter )
{
tokens[ tokens.size ] = next_token;
next_token = "";
}
else
{
next_token = next_token + string[i];
}
}
tokens[ tokens.size ] = next_token;
return tokens;
}

string( num )
{
return "" + num;
}
Now open maps\_zombiemode.gsc and look at the top function called main(). Under this:
Code Snippet
Plaintext
maps\_zombiemode_auto_turret::init();
Place this:
Code Snippet
Plaintext
maps\_xS78_fake_clientsystems::init();
Now open clientscripts\{MAPNAME}.csc and look at the function called main(). Under this:
Code Snippet
Plaintext
clientscripts\_load::main();
Place this:
Code Snippet
Plaintext
clientscripts\_xS78_fake_clientsystems::init();

That should be it. Remember to tick those new scripts in mod builder.

Now you can use set_client_system_state in GSC the same way you could use the original, if you don't know how I'm sure there are tutorials somewhere. And you no longer have to register new client systems in the GSC, you can just immediately call them from where ever you want. And in CSC you can use register_client_system the same way you could use the origins ( again, find you own tutorial ).
Last Edit: June 27, 2016, 10:17:21 pm by alaurenc9
broken avatar :(
×
broken avatar :(
Location: ruMoscow
Date Registered: 30 July 2013
Last active: 1 month ago
Posts
152
Respect
Forum Rank
Pack-a-Puncher
Primary Group
Donator ♥
My Groups
More
My Contact & Social Links
More
×
BuIlDaLiBlE's Groups
Donator ♥ Benevolent Soul who has our eternal gratitude and exclusive access to betas and the donator section of the forum.
ELI5 what is this even?
broken avatar :(
×
broken avatar :(
Location: gbSecret Rave Warehouse
Date Registered: 10 April 2015
Last active: 2 years ago
Posts
95
Respect
Forum Rank
Rotting Walker
Primary Group
Member
My Contact & Social Links
More
Personal Quote
am also a cat
Signature
×
Speedy's Groups
Do you place the first 2 files in Root/Raw/Maps ?
broken avatar :(
×
broken avatar :(
Location: us
Date Registered: 9 December 2015
Last active: 2 years ago
Posts
68
Respect
Forum Rank
Rotting Walker
Primary Group
Member
×
BrandynNew's Groups
BrandynNew's Contact & Social Links
Questions:

(1) When you say
Quote
Now open maps\_zombiemode.gsc and look at the top function called main(). Under this:
Code Snippet
Plaintext
maps\_zombiemode_auto_turret::init();
Should I edit the one in my mod's folder

(2) What is a CSC and how do I open it

(3) Once I do this, I shouldn't have to worry about this issue and can have HarryBo21's Perks and the MOTD HUD, or do I have to change those scripts

 
Loading ...