Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vscript additions and fixes 3 #105

Merged
merged 1 commit into from
Mar 11, 2021

Conversation

samisalreadytaken
Copy link

@samisalreadytaken samisalreadytaken commented Mar 7, 2021

Fixes, improvements, and new utility for vscript.


Fixed a critical bug in CBaseEntity::ScriptContextThink where the entity would stop thinking and/or skip think functions or even crash the game when some contexts were stopped while processing multiple and/or nested contexts.

Moved ScriptContextThink to shared code; however on client it is only supported on C_World for now. Usage:

if ( IsClient() )
{
	local TICK_INTERVAL = IntervalPerTick()
	local World = Entities.First()

	World.SetContextThink( "delay1", function(self)
	{
		print( "10 sec delay\n" )
	}, 10.0 )

	World.SetContextThink( "sv_tick", function(self)
	{
		printf( "tick: %i\n", GetTickCount() )
		return TICK_INTERVAL
	}, 0.0 )

	World.SetContextThink( "cl_frame", function(self)
	{
		printf( "frame: %i\n", GetFrameCount() )
		return 0.0
	}, 0.0 )
}

Moved player script registration on server before the player_spawn event to be able to access it on event.

ListenToGameEvent( "player_spawn", function(ev)
{
	printf( "'%s' has spawned\n", player.GetPlayerName() )

	player.SetContextThink("StopListener",function(self)
	{
		StopListeningToGameEvent( ev.game_event_listener )
	}, 0.01)

}, "" )

Added engine game event descriptor accession on CScriptGameEventListener::WriteEventData. This allows much more efficient code. Also enabled even datas on client.


Improved performance of coloured console printing in CGMsg by changing string comparisons to direct array access.

Replicated convars prevent unique colouring for sv/cl messages of the same types. A useful distinct sv/cl colours would be vscript printing. For the moment this workaround can be used for it:

local printc = printc
local format = format

::print = function(s)
{
	return printc( 230, 218, 115, s )
}

::printf = function(...)
{
	return printc( 230, 218, 115, format.acall(vargv.insert(0,null)) )
}

Placing this in vscript_client.nut will ensure these always run on client.


Changed v.tostring() calls in internal scripts to "" + v. Empty string concatentation implicitly converts the variable without the cost of an explicit function call. This is a micro optimisation, but there's not really any reason not to do it.

Simple benchmark (10000000 iterations)

tostring() : 3.72397949 sec
""+        : 3.40100098 sec

Printing a vector now prints the address. This allows tracking of vectors, and it is useful for debugging scripts. The syntax is from Source 2.

Vector Add, Subtract, Multiply, Divide set the result to the vector itself instead of creating a new vector like the overloaded operators do.

The unary minus operator can be used to negate the vector.

local vec = Vector( 1, 2, 3 )
vec = -vec
printl( vec )
printl( -Vector( 4, 5, 6 ) )

Vector::IsEqualTo takes an optional tolerance parameter. Vector::Set can take a vector to copy, or 3 floats.

Vector::FromKVString usage:

local szInput = "0.666 -78 37.0"

local vec = Vector()
if ( !vec.FromKVString( szInput ) )
	return printf( "Invalid KV string input '%s'\n", szInput )

print( "Set vector from KV string: " )
printl( vec )

FromKVString can be used with convars and file and data saving as well:

local vec1 = Vector(1,2,3)
local vec2 = Vector(4,5,6)

printl( vec1 )
printl( vec2 )

local write =
{
	vec1 = vec1.ToKVString(),
	vec2 = vec1.ToKVString(),
}
SaveTable( "context", write )

print("------\n")

local read = {}
RestoreTable( "context", read )

local read_vec1 = Vector().FromKVString( read.vec1 )
local read_vec2 = Vector().FromKVString( read.vec2 )

printl( read_vec1 )
printl( read_vec2 )

Added convar and concommand registration from script. Works both client and serverside.

if ( IsServer() )
{
	Convars.RegisterConvar( "my_convar1", "1337", "help string for convar", FCVAR_NONE )

	Convars.RegisterCommand( "my_concommand1", function(...)
	{
		printf( "%s callback with %d args\n", vargv[0], vargv.len() )

		foreach( v in vargv )
			printf( "\t%s\n", v )

		printf( "Value of my_convar1: '%s'\n", Convars.GetStr("my_convar1") )

	}, "help string for cmd", FCVAR_NONE )

	function test()
	{
		SendToConsole( "my_convar1 NEW VALUE FOR CONVAR" )
		SendToConsole( "my_concommand1 arg1 2 3 45 6 7 89" )
	}
}

Completion callback functions can be added to and removed from script concommands at any time.

Convars.SetCompletionCallback( "my_concommand1", function( cmd, partial, commands )
{
	cmd += " "

	if ( partial == " " || partial == "*" )
	{
		commands.append( cmd + "a_suggestion1" )
		commands.append( cmd + "b_suggestion2" )
		commands.append( cmd + "c_suggestion3" )
		commands.append( cmd + "d_suggestion4" )
		commands.append( cmd + "e_suggestion5" )
		commands.append( cmd + "keyword" )
		return
	}
	if ( partial.find("word") != null )
	{
		commands.append( cmd + "keyword" )
		return
	}
} )

// Convars.SetCompletionCallback( "my_concommand1", null )
// Convars.RegisterCommand( "my_concommand1", null, "", 0 )
// Convars.UnregisterCommand( "my_concommand1" )

No existing convars or concommands can be replaced except for a few allowed ones - I added the ability override movement keys. This may seem very similiar to PlayerRunCommand hook at first, but this allows complete control over the keys.

It can even be used along with PlayerRunCommand, basically intercepting button masks in script. Example reverse move keys, and suppress +use 3 times:

forwardmove <- 0.0
sidemove <- 0.0

local IN_Forward = function(...)
{
	if ( vargv[0][0] == '+' )
	{
		forwardmove += -175.0
	}
	else
	{
		forwardmove -= -175.0
	}
}
Convars.RegisterCommand( "+forward", IN_Forward, "", FCVAR_NONE )
Convars.RegisterCommand( "-forward", IN_Forward, "", FCVAR_NONE )

local IN_Back = function(...)
{
	if ( vargv[0][0] == '+' )
	{
		forwardmove += 175.0
	}
	else
	{
		forwardmove -= 175.0
	}
}
Convars.RegisterCommand( "+back", IN_Back, "", FCVAR_NONE )
Convars.RegisterCommand( "-back", IN_Back, "", FCVAR_NONE )

local IN_Moveleft = function(...)
{
	if ( vargv[0][0] == '+' )
	{
		sidemove += 175.0
	}
	else
	{
		sidemove -= 175.0
	}
}
Convars.RegisterCommand( "+moveleft", IN_Moveleft, "", FCVAR_NONE )
Convars.RegisterCommand( "-moveleft", IN_Moveleft, "", FCVAR_NONE )

local IN_Moveright = function(...)
{
	if ( vargv[0][0] == '+' )
	{
		sidemove += -175.0
	}
	else
	{
		sidemove -= -175.0
	}
}
Convars.RegisterCommand( "+moveright", IN_Moveright, "", FCVAR_NONE )
Convars.RegisterCommand( "-moveright", IN_Moveright, "", FCVAR_NONE )


use_suppress_count <- 0
Convars.RegisterCommand( "+use", function(...)
{
	++use_suppress_count
	printf("suppressing +use (%d)\n", use_suppress_count)

	if ( use_suppress_count >= 3 )
		Convars.UnregisterCommand( "+use" )

}, "", 0 )

player.GetOrCreatePrivateScriptScope().PlayerRunCommand <- function()
{
	local cmd = ::command

	if ( forwardmove )
	{
		cmd.SetForwardMove( forwardmove )
	}
	if ( sidemove )
	{
		cmd.SetSideMove( sidemove )
	}
}

This example script features concommands, multiple context thinking at different frequencies, network communication, effects and dynamic lights. It can be ran on any map with script_execute

https://gist.github.com/samisalreadytaken/dbb6d96ac97c5ef24a123b14f96fb84e

baseentity_shared.cpp
baseentity.cpp
c_baseentity.h
c_baseentity.cpp
c_world.h
   - Fixed critical ScriptSetContextThink bugs
   - Added C_BaseEntity::SetContextThink (ScriptSetContextThink)
   - Added C_BaseEntity::SetSize
   - Added C_BaseEntity::SetModel
   - Added C_BaseEntity::Destroy

baseentity.h
baseentity.cpp
   - Removed duplicate functions ScriptSetSize and ScriptUtilRemove

player.cpp
   - Moved player script instance registration before player_spawn event

vscript_server.cpp
   - Added CEntities::FindByClassNearestFacing

vscript_funcs_shared.cpp
   - Added GetFrameCount
   - Added IntervalPerTick

vscript_singletons.cpp
   - Better game event descriptors for CScriptGameEventListener
   - Added ::effects (CEffectsScriptHelper)
   - Added ::Convars (CScriptConvarAccessor)

vscript_shared.cpp
   - Fixed clientside entity printing in script VM

mapbase_con_groups.h
mapbase_con_groups.cpp
   - Improved performance by changing string comparisons to direct array access

vscript_bindings_base.h
vscript_bindings_base.cpp
   - Added CScriptKeyValues::SubKeysToTable

vscript_bindings_math.cpp
   - Added ::SimpleSplineRemapVal
   - Added ::SimpleSplineRemapValClamped
   - Added ::Bias
   - Added ::Gain
   - Added ::SmoothCurve
   - Added ::SmoothCurve_Tweak
   - Added ::ExponentialDecay

vscript_squirrel.nut
   - Added ::Lerp
   - Added ::FLerp
   - Added ::SimpleSpline

vscript_squirrel.cpp
   - Added Vector::_unm
   - Added Vector::Set
   - Added Vector::Add
   - Added Vector::Subtract
   - Added Vector::Multiply
   - Added Vector::Divide
   - Added Vector::DistTo
   - Added Vector::DistToSqr
   - Added Vector::IsEqualTo
   - Added Vector::WithinAABox
   - Added Vector::FromKVString
   - Changed vector print syntax
@Blixibon
Copy link
Member

Thank you for continuing your improvements to VScript and continuing to maintain your previous contributions.


I had attempted to add custom cvars/commands to VScript myself some months ago, but I think I gave up after about a week. I didn't think it was possible to clean them up properly after the VM shuts down (I think I must've missed ICVar::UnregisterConCommand), although this is naturally much better than anything I would've done. I know you had some difficulties yourself, so very well done getting them working.


I've already tested most of these changes as of writing, so I'm probably going to merge this PR a few hours from now. Thanks again for your continued contributions.

@Blixibon Blixibon mentioned this pull request Mar 10, 2021
2 tasks
@Blixibon Blixibon merged commit c17d32d into mapbase-source:develop Mar 11, 2021
VDeltaGabriel pushed a commit to Project-P2009/p2009_sdk that referenced this pull request Apr 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants