Vice Underdogs
Scripting => Script Showroom => Topic started by: stormeus on July 17, 2012, 06:31:37 am
-
Just sharing a method I thought would be helpful to those who hadn't known about it before:
Squirrel compiles all scripts into optimized bytecode that can either be stored in-memory or flushed to disk and then read in memory later. When the compiler parses a script, it processes and (in dofile's case) runs everything inside a makeshift function called main().
While most people don't think about it, you can basically do this in any file you want:
function onServerStart()
{
print( "Server started" );
}
// This would actually work
print( "myfile.nut parsed" );
In addition to that, functions are declared as variables, unlike Pawn. In fact, the Squirrel manual even makes mention of the ability to create "local functions," which I won't go into detail on since that's beside the point here. Essentially, creating a function such as function onServerStart() is syntactically the same as doing this:
onServerStart <- function()
{
print( "Server started" );
}
Because of that, you can overwrite a function like so:
function onServerStart() { print( "You shouldn't be able to see this." ); }
onServerStart = function()
{
print( "im in ur base, stealin ur funcshunz" );
}
// Or
function onOverwrittenServerStart()
{
print( "1 2 3 4" );
}
// Comment this line out to test the first example
onServerStart = onOverwrittenServerStart;
Writing over a function doesn't necessarily remove it from memory, however. As long as a reference is kept to the original function, the original function can still be called. You can keep a reference by simply storing it in a global variable.
function onServerStart() { print( "aaaa" ); }
oldServerStart <- onServerStart;
onServerStart = function() { print( "bbbb" ); }
You can then call the old function since it still has a valid reference.
function onServerStart() { print( "aaaa" ); }
oldServerStart <- onServerStart;
onServerStart = function() { oldServerStart(); print( "bbbb" ); }
You can now use the above method to hook a script's events without having to manually edit scripts, functions, and commands. You can instead do something like this to add to someone's onPlayerCommand function without really having to worry about manual editing:
function onPlayerCommand( player, command, arguments )
{
print( "hook-free" );
}
// In another file, probably
oldOnPlayerCommand <- null;
// Hook function
function myFunction( player, command, arguments )
{
// Call old onPlayerCommand if needed
if( oldOnPlayerCommand )
oldOnPlayerCommand( player, command, arguments );
// I dunno
print( "nah" );
}
// Check if onPlayerCommand is defined
if( "onPlayerCommand" in getroottable() )
{
// Store the old function
oldOnPlayerCommand = onPlayerCommand;
// Hook it
onPlayerCommand = myFunction;
}
else
{
// Define it
onPlayerCommand <- myFunction;
}
-
For the last part (hooking command functions specifically), I've always found it easier to do it this way:
function onPlayerOtherCommand( player, command, arguments )
{
command = command.tolower();
if( command == "noob" )
{
Message( "You are a noob." );
return 1;
}
}
function onPlayerCommand( player, command, arguments )
{
command = command.tolower();
if( command == "something" )
{
// idk
}
else if( onPlayerOtherCommand( player, command, arguments ) == 1 ) return 1;
}
Don't know if this is on-topic much but whatever. :)
-
Interesting, but not insanely useful.
For most scripts a single function call is insufficient to trigger specific events. And editing unlike hooking is a constant solution :P
-
Its interesting for sure. But like Skirmant said, i'm not really sure how to use this.
Like Morphine I mainly use different function names and call them all in the main event.
-
I dunno I think this can be extremely useful. It would be good to have a lag free version of a script where each part/system is separated into its own file, instead of just being able to separate certain functions into their own file.
-
The basic idea is to be able to dynamically alter a server by simply loading a release script/snippet instead of manually editing files in order to do so. Rather than edit your onPlayerCommand function in order to add a command someone released, if the script author released their script this way, all you would have to do is run dofile( "myscript.nut" ) after you load all of your files and callbacks. Plus, it makes for good insight on how the Squirrel interpreter works.