login
April 19, 2024, 07:17:48 am

Author Topic: Hooking events in script releases  (Read 1857 times)

0 Members and 1 Guest are viewing this topic.

stormeus

  • Vice Underdog
  • Crazy Man
  • *
  • *
  • Posts: 1755
  • Country: us
  • VC:MP Developer
    • View Profile
    • GTA VICE CITY Respective owner
Hooking events in script releases
« 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:
Code: [Select]
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:
Code: [Select]
onServerStart <- function()
{
    print( "Server started" );
}

Because of that, you can overwrite a function like so:
Code: [Select]
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.
Code: [Select]
function onServerStart() { print( "aaaa" ); }

oldServerStart <- onServerStart;
onServerStart = function() { print( "bbbb" ); }

You can then call the old function since it still has a valid reference.
Code: [Select]
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:
Code: [Select]
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;
}
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor

<krystianoo> stormeus do good job
<krystianoo> with recent update
<krystianoo> if not agree; jeb yourself in head
<Avenger> yesterday you said death to stormeus
<karan> double standard krystianoo
<karan> he called him fake prophet too
<krystianoo> sure fake prophet
<krystianoo> but with recent updates real

morphine

  • Crazy Man
  • *****
  • Posts: 1909
  • Country: lt
    • View Profile
Re: Hooking events in script releases
« Reply #1 on: July 17, 2012, 07:59:10 am »
For the last part (hooking command functions specifically), I've always found it easier to do it this way:

Code: [Select]
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. :)
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor


Skirmant

  • Vice Underdog
  • Crazy Man
  • *
  • *
  • Posts: 681
  • Country: il
  • Ignorance is bliss.
    • View Profile
Re: Hooking events in script releases
« Reply #2 on: July 17, 2012, 10:16:57 am »
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
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor

"C++ is a horrible language" - Linus Torvalds, creator of Linux

Quote
<SLC> nope. changed my mind. squirrel still sux dix
<SLC> it's just a piece of sh!t
* SLC has quit (Connection closed)

Thijn

  • Forum Administrator
  • Crazy Man
  • *
  • *
  • *
  • Posts: 2946
  • Country: nl
    • View Profile
Re: Hooking events in script releases
« Reply #3 on: July 17, 2012, 02:02:14 pm »
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.
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor

I'm not totally useless,
I can be used as an bad example ;)

"Never do Today, What you can do Tomorrow"


Charley

  • Vice Underdog
  • Crazy Man
  • *
  • *
  • Posts: 4751
  • Country: 00
    • View Profile
Re: Hooking events in script releases
« Reply #4 on: July 28, 2012, 09:32:31 am »
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.
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor

Writer of excessively long posts


stormeus

  • Vice Underdog
  • Crazy Man
  • *
  • *
  • Posts: 1755
  • Country: us
  • VC:MP Developer
    • View Profile
    • GTA VICE CITY Respective owner
Re: Hooking events in script releases
« Reply #5 on: July 28, 2012, 10:33:27 am »
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.
Agree Disagree Funny Winner Pwnt Informative Friendly Useful Optimistic Artistic Late Brain Donor

<krystianoo> stormeus do good job
<krystianoo> with recent update
<krystianoo> if not agree; jeb yourself in head
<Avenger> yesterday you said death to stormeus
<karan> double standard krystianoo
<karan> he called him fake prophet too
<krystianoo> sure fake prophet
<krystianoo> but with recent updates real