[*S*] Left click for spawn, works all the time

Started by Sebastian, Mar 28, 2015, 09:34 PM

Previous topic - Next topic

EK.IceFlake

I still don't understand why you guys have to make global variables for keybinds
function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 );
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == 0 ) player.Spawn();
}
or if you really want variables you can use enumerators instead

enum Keys
{
        LeftMouseBtn
}

function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 ); //Add into enum keys in the same order as this!!!
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == Keys.LeftMouseBtn ) player.Spawn();
}

.

#16
Quote from: NE.CrystalBlue on Mar 29, 2015, 04:46 PMI still don't understand why you guys have to make global variables for keybinds
function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 );
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == 0 ) player.Spawn();
}

What makes you so sure that the keybind you previously created will have an ID of 0? What makes you so sure that someone else didn't use BindKey() previously, in which case you might end up spawning the player using some other random key. Hard coded values in this context.... might be the worst idea ever!

Quote from: NE.CrystalBlue on Mar 29, 2015, 04:46 PMor if you really want variables you can use enumerators instead

enum Keys
{
        LeftMouseBtn
}

function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 ); //Add into enum keys in the same order as this!!!
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == Keys.LeftMouseBtn ) player.Spawn();
}

Constants and Enumerations are processed at compile-time. That means when the script is read from your storage unit and transformed into byte-code. And you can only call BindKey() after the compilation, when the actual byte-code is executed. How are you going to trick this?

Yes I could trick this using dofile() to have a second file with delayed compilation, and getconsttable() to manipulate the constants table from the parent file before dofile() is executed. Which would cause the constants created in the parent file to already be available before the second file is even compiled. But I'd still have to rely on some unreliable methods to achieve that. And what's the purpose then.
.

EK.IceFlake

Quote from: S.L.C on Mar 29, 2015, 04:57 PM
Quote from: NE.CrystalBlue on Mar 29, 2015, 04:46 PMor if you really want variables you can use enumerators instead

enum Keys
{
        LeftMouseBtn
}

function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 ); //Add into enum keys in the same order as this!!!
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == Keys.LeftMouseBtn ) player.Spawn();
}

Constants and Enumerations are processed at compile-time. That means when the script is read from your storage unit and transformed into byte-code. And you can only call BindKey() after the compilation, when the actual byte-code is executed. How are you going to trick this?

Yes I could trick this using dofile() to have a second file with delayed compilation, and getconsttable() to manipulate the constants table from the parent file before dofile() is executed. Which would cause the constants created in the parent file to already be available before the second file is even compiled. But I'd still have to rely on some unreliable methods to achieve that. And what's the purpose then.
No, I mean that make the enums in the very same order which you binded the keys.
For example, if you first bind key x then bind key y then z use
enum Keys
{
        X,
        Y,
        Z
}
I know that they are processed precompilation but thats exactly the very reason I preferred them over variables.

.

Quote from: NE.CrystalBlue on Mar 29, 2015, 06:21 PMNo, I mean that make the enums in the very same order which you binded the keys.

Exactly one of two things happen right now and I don't know which. Either, I don't get what you're saying or you don't get what you're saying. So, I'd like some input from a third (knowledgeable) person to see which.
.

Stormeus

#19
Quote from: NE.CrystalBlue on Mar 29, 2015, 04:46 PMenum Keys
{
        LeftMouseBtn
}

function onScriptLoad()
{
        BindKey( true, 0x01, 0, 0 ); //Add into enum keys in the same order as this!!!
}

function onKeyDown( player, key )
{
        if( !player.IsSpawned && key == Keys.LeftMouseBtn ) player.Spawn();
}

I'm not one to debate semantics but isn't this the exact same thing as creating a global table called "Keys" with a "LeftMouseBtn" member?



Global variables have virtually zero impact on the performance of Squirrel. The important thing is code readability. If you have one file that creates a keybind on the left mouse button and another file holding the onKeyDown event, which is more readable?

if (key == 0)

or

if (key == KEYBIND_LMOUSE)

Also, it's generally a very bad idea™ to not name your keybinds; if another script or another plugin creates a keybind, there is no guarantee your keybind ID is correct.

.

#20
Quote from: stormeus on Mar 29, 2015, 07:56 PMI'm not one to debate semantics but isn't this the exact same thing as creating a global table called "Keys" with a "LeftMouseBtn" member?

According to Squirrel documentation (and I might be wrong about this). Enums, being evaluated at compile time, would have their value in-place when used. As an example, the following code:
enum MyE
{
    elemX = 2
}

print(MyE.elemX);

Would result as:
print(2);
Similar to the macros in C/C++  etc. But I might be wrong. The documentation was very vague about this.

When using tables, that same code would result in more byte code near the print function. Something like:
MyE <-
{
    elemX = 2
}

// Push table name on stack: MyE
// Perform a get operation on the root table.
//    Which pushes the MyE table on stack now.
// Push element name on stack: elemX
// Perform a get operation on the table from the stack.
//    Which pushes the value 2 on stack now.
// Now call the print function with the arguments on stack. I.e. 2

print(MyE.elemX);

Quote from: stormeus on Mar 29, 2015, 07:56 PMAlso, it's generally a very bad idea™ to not name your keybinds; if another script or another plugin creates a keybind, there is no guarantee your keybind ID is correct.

That's the exact same thing I was trying to say.
.

.

Anyway, this is the trick I was talking about earlier with constants and delayed scripts.

main.nut
function onServerStart()
{
    // Create a constant named 'KEYBIND_LMOUSE_PRESS' with the id of the key-bind
    getconsttable().rawset( "KEYBIND_LMOUSE_PRESS", BindKey( true, 0x01, 0, 0 ) );

    // That constant is available before even compiling this file
    dofile("delayed.nut");
}

delayed.nut
function onKeyDown( player, key )
{
    // 'KEYBIND_LMOUSE_PRESS' will be replaced by
    //    the literal value inside that constant
    if( !player.IsSpawned && key == KEYBIND_LMOUSE_PRESS ) player.Spawn();
}
.

EK.IceFlake

Quote from: S.L.C on Mar 29, 2015, 08:29 PMAnyway, this is the trick I was talking about earlier with constants and delayed scripts.

main.nut
function onServerStart()
{
    // Create a constant named 'KEYBIND_LMOUSE_PRESS' with the id of the key-bind
    getconsttable().rawset( "KEYBIND_LMOUSE_PRESS", BindKey( true, 0x01, 0, 0 ) );

    // That constant is available before even compiling this file
    dofile("delayed.nut");
}

delayed.nut
function onKeyDown( player, key )
{
    // 'KEYBIND_LMOUSE_PRESS' will be replaced by
    //    the literal value inside that constant
    if( !player.IsSpawned && key == KEYBIND_LMOUSE_PRESS ) player.Spawn();
}
I wonder if the same will work with compilescript();
function onServerStart()
{
    // Create a constant named 'KEYBIND_LMOUSE_PRESS' with the id of the key-bind
    getconsttable().rawset( "KEYBIND_LMOUSE_PRESS", BindKey( true, 0x01, 0, 0 ) );

    // That constant is available before even compiling this file
    local keydownfunc = compilescript(@"function onKeyDown(player, key)
    {
        if( !player.IsSpawned && key == KEYBIND_LMOUSE_PRESS ) player.Spawn();
    }");
    keydownfunc();
}

.

#23
Quote from: NE.CrystalBlue on Mar 30, 2015, 04:31 AMI wonder if the same will work with compilescript();

It's exactly the same thing. The only difference is that compilestring() won't look very pretty when you add more keybinds and more code.
.

EK.IceFlake

Quote from: S.L.C on Mar 29, 2015, 07:30 PM
Quote from: NE.CrystalBlue on Mar 29, 2015, 06:21 PMNo, I mean that make the enums in the very same order which you binded the keys.

Exactly one of two things happen right now and I don't know which. Either, I don't get what you're saying or you don't get what you're saying. So, I'd like some input from a third (knowledgeable) person to see which.
But I still want to explain it to you. Key bind ids are created in the very order the binds were created. Same thing with enumerators. So in this enumerator
enum Keys
{
    LeftMouseBtn,
    RightMouseBtn,
    F2
}
so LeftMouseBtn has a value of 0, RightMouseBtn has a value of 1 and F2 has a value of 2.
Now if you keybind
BindKey(...);//This will make a key and if you use key == Keys.LeftMouseBtn in onKeyDown then this is the key assigned to that since this is id 0
BindKey(...);//This will make a key and if you use key == Keys.RightMouseBtn in onKeyDown then this is the key assigned to that since this is id 1
BindKey(...);//This will make a key and if you use key == Keys.F2 in onKeyDown then this is the key assigned to that since this is id 2
Simple and readable but will require the user of the script to do this with his keys also.

.

#25
Quote from: NE.CrystalBlue on Mar 30, 2015, 04:41 AMBut I still want to explain it to you. Key bind ids are created in the very order the binds were created. Same thing with enumerators. So in this

The way you want to achieve that is still dangerous because the returned IDs may vary. You could use the same delay trick for enumerations as well:
function onServerStart()
{
    // Create an enum named 'KeyBinds' with the ids of the key-binds
    getconsttable().rawset( "KeyBinds", {
        LMOUSE_PRESS = BindKey( true, 0x01, 0, 0 ),
        LMOUSE_RELEASE = BindKey( false, 0x01, 0, 0 ),
        RMOUSE_PRESS = BindKey( true, 0x02, 0, 0 ),
        RMOUSE_RELEASE = BindKey( false, 0x02, 0, 0 )
    });

    // That enum is available before even compiling this file
    local keydownfunc = compilestring(@"
    function onKeyDown( player, key )
    {
        switch (key)
        {
            case KeyBinds.LMOUSE_PRESS: break; // Left mouse press
            case KeyBinds.LMOUSE_RELEASE: break; // Left mouse release
            case KeyBinds.RMOUSE_PRESS: break; // Right mouse press
            case KeyBinds.RMOUSE_RELEASE: break; // Right mouse release
        }
    }");

    keydownfunc();
}

And even better now you can use a switch case, which is much faster for many equality conditions.



Also, a suggestion to @sseebbyy. Verify the keybind ID first to avoid a function call when it's not even the key you need:
function onKeyDown( player, key )
{
if( key == BIND_LEFT_MOUSE && !player.IsSpawned ) player.Spawn( );
}
.

Sebastian

Quote from: S.L.C on Mar 30, 2015, 04:54 AMAlso, a suggestion to @sseebbyy. Verify the keybind ID first to avoid a function call when it's not even the key you need:
function onKeyDown( player, key )
{
if( key == BIND_LEFT_MOUSE && !player.IsSpawned ) player.Spawn( );
}

I disagree. If I will do your way,, the event will be called everytime a player shoots. (and here comes your e.g. about 100 players firing at the same time; that's more possible, when there is a war)
Using my way, the event will be called whenever an unspawned player presses a binded key.
(there is a small chance to be 100 players in the spawnscreen, and an even more small chance that they press other key than the binded LMB)

.

The event get's called no mater if the player is spawned or not. My concern was that you always check IsSpawned (which is actually a function, internaly) even if the key is not the one you expect. Which is why, comparing the key first, eliminates most of the useless calls. Comparing two integers is faster then calling a function.
.

Sebastian

Ye, now it seems better.
First post was updated. :)

aXXo

A much needed solution is to add several bool attributes to the current classes similar to object.TrackingBumps

Example:
player.TrackingKeys = true would enable monitoring OnPlayerKeyDown for that player. Any other player pressing a key would have no impact on the server performance. I mentioned the same in my post here, but I hope this is feasible in an update to the official Squirrel plugin.