Today I learned - Share your newly found knowledge!
#61

hmm k Vince.Let me explain,today i was doing something like that
pawn Код:
if(sscanf(params, "d", tmp) || sscanf(params, "d",tmp2) || !IsNumeric(tmp2)) return SendClientMessage(playerid, red, "USAGE: /settime [playerid] [hour]");
But it was wrong.then YSI told me to Read the whole topic again.I read it and then i got and changed to this

pawn Код:
if(sscanf(params, "dd",tmp,tmp2)) return SendClientMessage(playerid, red, "USAGE: /settime [playerid] [hour]");
S,fianlly today i learned how to use sscanf and calm down.I am not telling lie
Reply
#62

Today I learned a "new" bug in the compiler - not sure if or how it could be exploited yet...

https://sampforum.blast.hk/showthread.php?tid=425970
Reply
#63

Today I learned the only place you'll find a RET (not RETN) opcode in the AMX is in the entry function, which seems to be unsupported by SA-MP (correct me if I'm wrong).
Reply
#64

Today I learned that SetPlayerHealth actually rounds down the amount of health which is being set.

It is still treated as a float value although it only takes the number before the decimal point.

I believe this information could be useful if one is working on health hack / godmode anti-cheat.
Reply
#65

I don't know how useful this can be but I realized that you can scroll down or up faster by holding shift in the pawno IDE.
Reply
#66

Quote:
Originally Posted by admantis
Посмотреть сообщение
I don't know how useful this can be but I realized that you can scroll down or up faster by holding shift in the pawno IDE.
Ctrl*
Reply
#67

Today I learned the compiler explicitly recognises "::" as a valid token:

sc.h:

pawn Код:
#define tDBLCOLON   280 /* :: */
sc2.c:

pawn Код:
char *sc_tokens[] = {
         "*=", "/=", "%=", "+=", "-=", "<<=", ">>>=", ">>=", "&=", "^=", "|=",
         "||", "&&", "==", "!=", "<=", ">=", "<<", ">>>", ">>", "++", "--",
         "...", "..", "::",
         "assert", "break", "case", "const", "continue", "default", "defined",
         "do", "else", "exit", "for", "forward", "goto", "if", "native", "new",
         "operator", "public", "return", "sizeof", "sleep", "state", "static",
         "stock", "switch", "tagof", "while",
         "#assert", "#define", "#else", "#elseif", "#endif", "#endinput",
         "#error", "#file", "#if", "#include", "#line", "#pragma",
         "#tryinclude", "#undef",
         ";", ",", ";", "[integer value]", "[rational value]", "[identifier]",
         "[label]", "[field/parameter reference]", "[string]", "[string]"
       };
However, the "tDBLCOLON" identifier is never used anywhere so it is not valid code syntax anywhere.
Reply
#68

Today I (FINALLY) learned how to detect spaces in macro patterns! Because spaces are used to separate the pattern from the replacement, it was documented in pawn-lang.pdf that should you ever need to detect a space you could use "\32;" instead but I could never get it to work! Doing this:

pawn Код:
#define TEST1\32;(%1) TEST1(%1)
Will NOT detect spaces before the brackets and remove them. Similarly this will not work:

pawn Код:
#define TEST2(\32;%1) %1
That will NOT detect a call like "TEST2( 42)" - I'm still not sure why or what the exact rules governing how the macros work are, but this will work:

pawn Код:
#define TEST3(%0\32;%1) %1
In that case, even just a leading space like in "TEST3( 42)" can be detected and removed. This lack of space detection has been the bane of my code for literally YEARS (if you don't believe me, that's what the point of this topic was). It is why this works:

pawn Код:
foreach (new i : Player)
But this gives multiple cryptic errors:

pawn Код:
foreach ( new i : Player )
I knew the documentation claimed it could be done, but my repeated failed attempts led me to believe that maybe the SA:MP compiler version couldn't until I started really digging about in its code. Anyway, i am very happy about this and will be retrofitting certain bits of code to find any errors caused by bad spacing that I can now fix!
Reply
#69

Today I learned:
You can do stuff like
pawn Код:
#tryinclude test"
#tryinclude test>
Also if you try:
pawn Код:
#tryinclude a_samp"
#assert defined a_samp"
As expected you get compile-time assertion, but when you try something like:
pawn Код:
#tryinclude a_samp>
#assert defined a_samp>
You will find a code from few lines below as assertion text, you can in that strange way send message to the person that is compiling, example:
input:
pawn Код:
#assert defined _inc_a____________________samp>
//      Buffer ov..fuckover?AAAAAAAAAAAAAAAAA\\
//      n\/
dialog error output:
pawn Код:
.\pawno\Untitled.pwn(23) : fatal error 110: assertion failed: Buffer ov..fuckover?AAAAAAAAAAAAAAAAA\/

Compilation aborted.Pawn compiler 3.2.3664          Copyright (c) 1997-2006, ITB CompuPhase


1 Error.
Reply
#70

Today I learned that you can easily declare big array values while defining them easily, instead of using loops.
For example:
pawn Код:
new myArray[1024] = {12, ...};

//Instead
new myArray[1024];

main()
{
    for(new i = 0; i != sizeof(myArray); i++)
    {
        myArray[i] = 12;
    }
}
Reply
#71

Today i learned that even though you can do this:

pawn Код:
if( var1 < var2 < 0 )
//equivalent to: if( var1 < var2 && var2 < 0)
You can't do this:
pawn Код:
if( var1 != var2 != 0 ) //tag mismatch
//I thought it would be equivalent to:  if( var1 != var2 && var2 != 0)
Nothing special but yeah.
Reply
#72

Only a tiny bit of information, so I'll stick it here. TIL there is a website called "compileonline" which (unsurprisingly) allows you to compile code online, and (IMHO quite surprisingly) includes a PAWN compiler. Unfortunately, it is for version 4.x of PAWN not 3.x:

http://www.compileonline.com/index.php
Reply
#73

I've worked out, for myself, before I read what's listed below that you can use hex numbers for anything.

pawn Код:
#include <Pawn/Default>

main()
{
    new a, b, c, abc, health;
    health = 0xFFFF; // Would be a unlimited health value.
    a = 0xA;
    b = 0xB;
    c = 0xC;
    abc = 0xABC;
   
    /*
        A = 10
        B = 11
        C = 12
        ABC = 2748
        Health = 65538
    */

   
    printf("a = %d b = %d c = %d abc = %d health = %d", a, b, c, abc, health);
}
Although there is no real reason for using HEX numbers, other than colors, it could be useful to a few people, however they cannot be used as floats, strings or anything other than integers that I've found.
Quote:
Originally Posted by Basssiiie
Maybe you might want to read this. It explains why 0xF works and why 0xG doesn't work.

But indeed, 0xA is the same as 10, which is also the same as 0b1010, which is also the same as 75 - 65, which is also the same as 'K' - 'A' (Ascii character codes). For more information about this similarity stuff, you might be interested at this, look under Minor Optimisations -> Small Snippets -> Equivalence.
Useful things from Basssiiie:

ASCII
Hexadecimal
Code optimisations
Reply
#74

UBER cull of posts. I've removed or moved a load of posts that were either "TIL" with no explanation or just discussion about points. I will say that if there are any posts that you think should stay, or that you want the information from, they all still exist but are hidden. Note that this post won't last very long either.

I also re-discovered some things I had forgotten about reading through the topic!
Reply
#75

I see you copied my post into Isolated's as a quote. Maybe an idea to copy the links with it? That would be great. Now nobody knows what webpages I'm talking about. You can remove this post after you've read it.
Reply
#76

Links should be there buddy.

EDIT: Sorry; links added now.
Reply
#77

Today I Learned how to use: * numargs, * getarg, * setarg . I must thanks to this post and also to greentarch
Reply
#78

Today I learned how to confuse the PAWN VM and "steal" parts of the heap for my own uses. For the new version of y_malloc I switched to using the heap instead of an array because it makes compiling and file sizes better. I wrote code something like this:

pawn Код:
#emit LCTRL  5
#emit STOR.S <malloc pointer>
#emit ADD.C  <malloc size>
#emit SCTRL  5
And everything was fine - it didn't take me long at all to convince y_malloc to allocate memory from this freshly reserved portion of the heap and seemed to be going well untill I called "malloc" from a different callback (i.e. not OnGameModeInit).

The problem was that the PAWN virtual machine (i.e. the thing that runs PAWN scripts) resets the heap after every callback (which is normally the right thing to do). The function amx_Exec contains something like:

pawn Код:
reset_heap = amx->heap;
reset_stack = amx->stack;
heap = amx->heap;
stack = amx->stack;

// Run the PAWN callback.

amx->heap = reset_heap;
amx->stack = reset_stack;
So any modifications or assignments we make in the heap are lost as soon as the callback ends, which is no good if we are using it as global memory. Fortunately, I found a solution by confusing the virtual machine! When you call "sleep" this code is run:

pawn Код:
amx->reset_heap = reset_heap;
amx->reset_stack = reset_stack;
And then "amx_Exec" ends without resetting the values, because it was never designed for callbacks in the way SA:MP does them. When the sleep time is up, the code resumes and this code is run:

pawn Код:
reset_heap = amx->reset_heap;
reset_stack = amx->reset_stack;
heap = amx->heap;
stack = amx->stack;
Then when the callback finally ends, the normal end code is run to again reset the stack and heap back to their original values:

pawn Код:
amx->heap = reset_heap;
amx->stack = reset_stack;
Now people have said that you can only call "sleep" from "main" - this is not STRICTLY true, you can call it from anywhere, it just won't do anything. "main" is the only function that you can sleep and resume later, so "main" is the only function that can call the code we DO NOT WANT - i.e. the code I just showed to reset "reset_stack" and "reset_heap". But there's a bug! Calling "sleep" from a callback first, THEN from "main" will do the following:


pawn Код:
// Start amx_Exec
reset_heap = amx->heap;
reset_stack = amx->stack;
heap = amx->heap;
stack = amx->stack;

// Run OnGameModeInit

// Call "sleep":
amx->reset_heap = reset_heap;
amx->reset_stack = reset_stack;

// Start amx_Exec
reset_heap = amx->heap;
reset_stack = amx->stack;
heap = amx->heap;
stack = amx->stack;

// Run "main":

// Call "sleep":
amx->reset_heap = reset_heap;
amx->reset_stack = reset_stack;
We have finally manged to overwrite the value of "amx->reset_heap" with our own value, i.e. the value AFTER our allocated data. If "main" doesn't exist (i.e. this is a filterscript) then the code still works because "sleep" can never be resumed from to fully reset the heap pointer. I'm sorry this is not well explained - it is hard to explain and took me ages to understand and figure out!
Reply
#79

Good to hear that you found a way to confuse the average user even more. :')
I bet the only people that understand what you just said are Slice and yourself.
Reply
#80

Quote:
Originally Posted by Y_Less
Посмотреть сообщение
...
Benchmarks? How are you dealing with fragmentation? Can you allocate huge amount of data in heap?

I thought sleep wasn't safe to use in SA:MP.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)