Today I learned - Share your newly found knowledge!

TIL that mistyping for instead of foreach causes various errors, from pawncc segfaults, to scope leaks.

pawn Code:
//That stuff will do some serious damage
for(new i:Player) {
Reply

How to use Floatcos & Floatsin to create perfect positioning for races. (Was not today but I just finished my Race System and it is working great).
Reply

When you compile pwn with -O2 flag, samp-server will complain about wrong amx version. If you use some of YSI libraries, then using -O1 can result in weird errors. Stick with -O0 (default)
Reply

Quote:
Originally Posted by DeStunter
Посмотреть сообщение
I found out random when called after it self tends to generate a number just 1 off from it self. I made a little reaction test script, and when I generate a random number to pull a char out of a string, it tends to pick the letter afterwards.

Код:
new ReactionChars[] = "aAbBcCdDeEfFgGhHIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
it will generate something like gGmnNoO
It tends to do this quite often so I added a check to see if the number generated is within a +-1 error margin to prevent it. I also considered doing a random(1/2 size of str) + random(1/2 size of str)
I'm not quite sure how you are getting that to happen.

I ran this:
pawn Код:
#include <a_samp>

main() {
    SetTimer("Test", 250, true);
}

forward Test();
public Test()
{
    new ReactionChars[] = "aAbBcCdDeEfFgGhHIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ0123456789";
   
    new string[10];
    for (new i = 0; i < sizeof(string)-1; i++)
    {
        string[i] = ReactionChars[random(sizeof(ReactionChars)-1)];
    }
    print(string);
}
Here:http://slice-vps.nl:7070/#

and got this list:
pawn Код:
I1Be637Ba
qRpw3xZS1
Tubt1mtVN
Xfl8hk1xh
1tcL0Pvxv
WEb15SMyM
SCCZ49PT8
HUOSHYcuw
LQMKPmLdz
8emNShHUw
Jtbtmt5WK
mYXjDDe2G
Ua2hkREhC
jdoOXFHGr
ZMfe3aR0t
bIC1yJEhw
VUbTHkzRh
jbZoQafeu
oz4K5MTda
Reply

Just a handy little trick I came up with today (or within the last 24 hours at least). y_hashmap has the following function:


pawn Код:
enum E_DATA
{
    E_NAME[32],
    E_HASH[HASH_MAP_DATA],
    E_CUSTOM_FIELDS
}

new HashMap:gMap<>;
new gArray[100][E_DATA];

HashMap_Init(gMap, gArray, E_HASH);
The hash map library allows for fast lookup of strings in an array, so you can use those instead of indexes. The "gMap" variable is used to quickly enter the main "gArray" array to find similar strings. "HashMap_Init" links the two. This, however, is a macro that expands to:

pawn Код:
_HashMap_Init(gMap, gArray[0][E_HASH], sizeof (gArray), sizeof (gArray[]) * 4, gArray[0][0])
There are 5 parameters:

1) The map.
2) The address of the first hash data.
3) The size of the array.
4) The size of the enum in bytes.
5) The address of the first name.

I'm not going to lie, the API isn't brilliantly designed. A better way would be:

pawn Код:
_HashMap_Init(gMap, gArray[0][0], sizeof (gArray), sizeof (gArray[]) * 4, _:E_HASH)
So the last parameter is an offset with a tag override. The API also requires the name (i.e. the string used to look up the entry) to be the first item in the enum.

However, the exact parameters and their order don't matter for this, the problem is here:

pawn Код:
gArray[0][0]
That is a tag mismatch - the second "0" does not have a tag of "E_DATA" so will give a warning. The easy way to fix this would be to do "gArray[0][E_NAME]" and have that as an extra macro parameter:

pawn Код:
HashMap_Init(gMap, gArray, E_NAME, E_HASH);
That seems pointless because it is ALWAYS "0" with a tag. We could instead do an explicit tag override:

pawn Код:
HashMap_Init(gMap, gArray, E_DATA, E_HASH); // gArray[0][E_DATA:0]
That still has the extra parameter for constant data. Note that the "E_HASH" parameter IS required because the size of the name isn't known and thus must be passed in. So I needed a way to make "0" without getting a tag mismatch warning, and without passing the tag. Fortunately, "E_HASH" has the correct tag but the wrong value, but that can change:

pawn Код:
gArray[0][E_HASH - E_HASH]
Any number subtracted from itself is 0, subtraction preserves tags, and because this is a constant minus a constant the compiler can do it for us and generate a constant in the resulting AMX (instead of generating code to do the maths).

Hence the macro contains the slightly odd looking "%1[0][(%2) - (%2)]" to generate a tagged 0 constant without passing in either 0 or the tag.
Reply

Native hash maps, nice!

Though why do you need to send the address of [0][0]? What about finding that inside the init function?

pawn Код:
// using varargs to avoid tag index mismatch
stock _HashMap_Init(other, things, size1, size2, ...) {
    new addr;
   
    #emit LOAD.S.pri 28 // 12+4*4
    #emit MOVE.alt
    #emit LOAD.I
    #emit ADD
    #emit STOR.S.pri addr
   
    printf("address of arr[0][0]: %08x", addr);
}

_HashMap_Init(123, 456, sizeof(gArray), sizeof(gArray[]), gArray);
BTW, it seems we think alike sometimes.

Edit: I just realized you can also make the array easy to deal with!

Abstract example:

pawn Код:
#include <a_samp>

enum E_DATA {
    E_NAME[32],
    E_OTHER1,
    E_OTHER2
};

enum E_HASH_MAP_START {
    E_NAME[32]
};

new g_EmptyArr[1][E_HASH_MAP_START];

stock func(arr[][E_HASH_MAP_START], size1, size2, ...) {
    new addr;
   
    #emit LOAD.S.pri 24
    #emit STOR.S.pri 12 // override the address of arr
    #emit MOVE.alt
    #emit LOAD.I
    #emit ADD
    #emit LOAD.I
    #emit STOR.S.pri addr
   
    for (new i = 0; i < size1; i++) {
        printf("%d: %s", i, arr[i][E_NAME]);
    }
}

new g_Data[3][E_DATA] = {{"one", 1, 11}, {"two", 2, 22}, {"three", 3, 33}};

main() {
    func(g_EmptyArr, sizeof(g_Data), sizeof(g_Data[]), g_Data);
}
Reply

Today i learned how to do stuff with loops :]
Ty Konstantinos
Reply

Quote:
Originally Posted by Slice
Посмотреть сообщение
Native hash maps, nice!

Though why do you need to send the address of [0][0]? What about finding that inside the init function?
In short, because that didn't occur to me! It should have really...

Quote:
Originally Posted by Slice
Посмотреть сообщение
BTW, it seems we think alike sometimes.
Ha! Hadn't seen you using that trick already, nice!

Quote:
Originally Posted by Slice
Посмотреть сообщение
Edit: I just realized you can also make the array easy to deal with!

Abstract example:

pawn Код:
// Clever code.
Interesting, that would simplify the code somewhat. It also took me about 10 reads of the code to figure out what you were doing there, and why I was wrong in thinking it didn't work...
Reply

Once again, Emmet has learned something:

You can predefine functions in the script:

pawn Код:
forward stock MyFunction();
AFAIK that just tells the compiler that the function is defined but doesn't exist. Now it's safe to do this:

pawn Код:
stock MyFunction() // yes, "stock" isn't a typo.
{
    print("hi!");
}
It's pretty pointless but I'm definitely going to use it in my scripts now, as a cool new method of listing the functions within :D.
Reply

Why would you think that "stock" was a typo? Does this do something other than just normal forwarding?
Reply

Quote:
Originally Posted by Y_Less
Посмотреть сообщение
Why would you think that "stock" was a typo? Does this do something other than just normal forwarding?
Wow. I guess not. I also found out that it has no effect since "MyFunction" isn't a callback, so the "forward" part is basically ignored.

I seriously need to re-read pawn_lang.pdf again (well, it's myself to blame really, not enough sleep causes me to make dumb moves).
Reply

I asked as the only interesting part is the fact that "forward stock" is valid syntax as well as just "forward", but that isn't overly surprising given that "forward", "forward public", "public", and "" are all equivalent too:

pawn Код:
// All valid forwards:

Func();
public Func();
forward Func();
forward public Func();

public Func()
{
}
Anyway, the reason I asked if that did anything more interesting is that Slice has previously shown that doing:

pawn Код:
// When using one of these:

public Func();
forward public Func();

// "public" isn't needed here as its already known.
Func()
{
}
Will put "Func" in to the public functions table, but will NOT generate the associated code for it.

Edit:

Today I learned how to transparently hook native functions without ALS.
Reply

Around one week ago I learnt how to return more than one value.

Instead of this:

Код:
if(HouseID[0] == -1) { SendClientMessage(playerid, COLOR_RED, "There has been a bug in regards to calculating the Second House, Contact KyleSmith"); return 0; }
I can do this:

Код:
if(HouseID[0] == -1) return SendClientMessage(playerid, COLOR_RED, "There has been a bug in regards to calculating the Second House, Contact KyleSmith"), 0;
Basically, it returns the SCM but also the returning 0 at the end! It is very useful!
Reply

TIL that it is possible to #undef specialized macros, but only by using the alphanumeric prefix:

pawn Code:
#define MyFunction(%0) \
    (Kick(%0))
This doesn't work:

pawn Code:
#undef MyFunction(%0)
This does:

pawn Code:
#undef MyFunction
From y_timers:

pawn Code:
#define @Yx:%0||||||;%8>%1,%2|||%4||| %0),%8);@Yj:%1@_yT(__r,%2);public @Yj:%1@_yT(__r,%2){%4(%2);}%4
And then to undefine it:

pawn Code:
#undef @Yx
However, I wouldn't recommend undefining working macros unless you really know what you're doing.
Reply

And that is due to precompiler rules
You have to undef part 1 (part until first not allowed character)
Reply

Today I learned that the anti-DoS timeout issues can be fixed by constantly unbanning the IP of a player experiencing problems.

Obviously a pretty bad solution, but it's better than nothing.
Reply

Today I learned that
Code:
if()
else
is faster than
Code:
if()
  return or continue or whatever
some code to handle else
Code:
#include <a_samp>
#include <ppg>

#define EQUALTO(%0,%1) (!(%0 ^ %1))
#define ITER 10000000
main() {
    new a = 15;
    new test1s,test2s,test1e,test2e;
    test1s = GetTickCount();
    for(new i = ITER;i > 0;i--)
    {
        if(a == 45)
        {
            continue;
        }
        else 
        {
            continue;
        }
    }
    test1e = test2s = GetTickCount();
    for(new i = ITER;i > 0;i--)
    {
        if(a == 45)
        {
           continue;
        }
        continue;
    }
    test2e = GetTickCount();
    printf("Test1 took %dms and Test2 took %dms",test1e-test1s,test2e-test2s);
}
Test1 took 691ms and Test2 took 741ms
Test1 took 708ms and Test2 took 719ms
Test1 took 678ms and Test2 took 703ms

Tested @ http://slice-vps.nl:7070/
Try multiple times because sometimes the Test 2 comes faster but the experimental probability that I calculated is Test Two comes faster every 6 times Test 1 comes faster.

To be sure which ones faster ,I need to see the Assembly code.
Reply

these things are so trivial i don't know why you even attempted..
Reply

because such if blocks are used frequently and I needed to know which was faster!
Reply

You really don't! With that small a difference (which even you admit isn't always a clean cut result), the code in the blocks with vastly outweigh any savings made unless you can code everything with the best algorithm possible perfectly every time.
Reply


Forum Jump:


Users browsing this thread: 10 Guest(s)