Welcome, Guest |
You have to register before you can post on our site.
|
Online Users |
There are currently 257 online users. » 1 Member(s) | 253 Guest(s) Bing, Google, Twitter, Armeat2005
|
|
|
A few missing things from SAMP |
Posted by: LaszloR1 - 2019-04-17, 05:48 PM - Forum: Questions and Suggestions
- Replies (1)
|
 |
There are a few vehicles in gta that have 4 colors, samp only let's you use two.
Code: camper, 1,31,1,0, 1,31,1,0, 1,20,3,0, 1,5,0,0, 0,6,3,0, 3,6,3,0, 16,0,8,0, 17,0,120,0
cement, 60,24,23,0, 61,27,123,0, 65,31,31,0, 61,61,30,0, 81,35,23,0, 62,61,62,0, 83,66,64,0, 83,64,64,0
squalo, 0,0,0,1, 1,5,1,1, 3,3,0,1, 1,22,1,1, 1,35,1,1, 1,44,1,1, 1,53,1,1, 1,57,1,1
carcols.dat
On SA-MP you can not choose what variation of a car or bike you want. (There are extras on bikes and cars, would be cool to be able to choose when spawning)
http://static2.wikia.nocookie.net/__cb20...A-rear.jpg (Wingless ZR350)
https://gtwfilesie-thumb.grandtheftwiki....-front.jpg (ZR350 with wing)
Some tuning parts are appliable in SP, but not in SA-MP. These parts are in the data file, just commented out and do fit the cars. There are probably more possible variations to these.
https://forum.sa-mp.com/showthread.php?t=525760 (Scroll down to the bottom for the interesting ones)
Moved from: https://www.burgershot.gg/showthread.php...19#pid2519
|
|
|
[INFO] Czego dotyczy ta czesc forum? |
Posted by: Riddick - 2019-04-17, 05:25 PM - Forum: Skryptowanie
- No Replies
|
 |
Ta czesc forum dotyczy wsparcia dla ludzi, kt?rzy tego wymagaja przy skryptowaniu w jezyku PAWN (lub nowym API)?dla OpenMP lub SA-MP.
Jezeli masz problem z:
- Error'ami/Warning'ami w Twoim skrypcie
- Nie potrafisz napisac jakiegos skryptu
- Potrzebujesz og?lnej pomocy przy skryptowaniu
Powinienes najpierw przeszukac to forum.?
Jezeli nie znalazles odpowiedzi na sw?j problem w naszej polskiej czesci, mozesz utworzyc nowy temat opisujac sw?j problem szczeg?lowo.
|
|
|
[WAZNE] Regulamin dot. reklamowania serwer?w |
Posted by: Riddick - 2019-04-17, 05:20 PM - Forum: Serwery
- No Replies
|
 |
Jezeli jestes wlascicielem/wlascicielka serwera na platformie OpenMP lub SA-MP, masz mozliwosc opublikowania swojego serwera w tej sekcji.
Sekcja ta jest przeznaczona tylko do reklamowania serwer?w OpenMP lub SA-MP. Jakiekolwiek inne posty beda usuwane.
Kr?tko:
- Kazdy serwera mozna jednorazowo reklamowac co miesiac. W przeciwnym razie temat zostanie usuniety.
- Jezeli ktos opublikowal Tw?j serwer bez Twojej zgody, mozesz zglosic sie do mnie poprzez prywatna wiadomosc i powiadomic mnie o tym fakcie. Prawdopodobnie taki temat zostanie usuniety.
- Mozesz udostepnic link do swojego serwera Discord powiazanego z serwerem.
- Powinienes udostepnic adresacje do polaczenia sie do serwera.
- Mile widziane linki do forum powiazanych z Twoim serwerem.
|
|
|
Today I learned - Share your newly found knowledge! |
Posted by: kristo - 2019-04-17, 02:31 PM - Forum: Pawn Scripting
- Replies (1)
|
 |
Credits for the concept of this thread go to Slice.
Slice Wrote:Simple.?If you learned something new?related to SA-MP scripting, share it here!
Please:- Explain what it is you learned, don't just say you learned something.?<----
- Try keeping it concise.
- Don't post stupid pictures or otherwise annoying, non-related stuff.
- Don't link to or quote posts then say you learned that.
Today I learned that natives can be forwarded and this can be used to deprecate natives and add replacements for them without getting a deprecation warning inside the replacement function:
PHP Code: forward DeprecatedNative();
stock NewFunction() { ? ?return DeprecatedNative(); // no warning here }
#pragma deprecated Use `NewFunction` instead. native DeprecatedNative();
main() { ? ?DeprecatedNative(); //?(warning) function is deprecated (symbol "DeprecatedNative") Use `NewFunction` instead. ? ?NewFunction(); }
|
|
|
Calculate accuracy of individual shotgun shots |
Posted by: Markski - 2019-04-17, 02:05 PM - Forum: Libraries
- Replies (5)
|
 |
Very simple library based on damage measurement, all it does is calculate how many pellets of a shotgun shot hit the player, and returns the amount of pellets that hit or the percentage, depending on parameters. Might be useful for accuracy measurements, and maybe you can implement some interesting tools if coupled with distance measurement and logging..
Consists of only two functions, one for Normal or Sawnoff shotgun and one for Combat shotgun. The functions should be called from within your OnPlayerGiveDamage, if the correct weaponid hits.
Configuration
None required.
Installation
Just #include the file into your script.
Download
|
|
|
The internals of switch and chained else ifs and which one should you use |
Posted by: kristo - 2019-04-17, 12:25 PM - Forum: Tutorials
- No Replies
|
 |
The internals of switch and chained else ifs and which one should you use
This tutorial takes a look into how if and switch statements work on the assembly level and helps determine, where to use a switch and where to prefer chained else ifs. I decided to write this tutorial, because one of the topics I am about to address is a semi-common issue and currently there is no good place to refer to when it comes to it. In addition to that, the research I did for this tutorial helped me understand the AMX structure quite a bit more than I used to before.
The internals
I used the -a flag to generate the assembly of two simple snippets of code that perform the same task, one using switch and the other using chained else ifs. I also took the time to rewrite them in a more human-readable form (using variable names instead of raw addresses, named labels instead of numbered ones prefixed with l., etc.) and to document them. It is worth noting that while the rewritten assembly is valid, it does not currently compile due to a compiler bug related to forward jumps.
Chained else ifs
PHP Code: new val;
if (val == 1) {
? ?// do something here
} else if (2 <= val <= 4) {
? ?// do something here
} else {
? ?// do something here
}
For the sake of simplicity I used the form 2 <= val <= 4 instead of val >= 2 && val <= 4 for the range check. If written the other way, the code would use 7 jump instructions instead of 4 and keeping track of the instructions would be more difficult. It would also be a tiny bit slower since it would have to load the value of val to the primary register one more time.
When using chained else ifs, the assembly contains the AMX instructions for each individual check. If the check fails, it jumps to the next check, otherwise it jumps to the end of the chain. Here is the assembly equivalent to this code:
PHP Code: new val;
// if (val == 1)
#emit LOAD.S.pri ? ?val ? ? ? ? // load the value of val to the primary register
#emit EQ.C.pri ? ? ?1 ? ? ? ? ? // compare the value in the primary register to constant 1: they must be equal; store the result in the primary register
#emit JZER ? ? ? ? ?range ? ? ? // if the result of the comparison is false, jump to "range" to perform the next check
// do something here
#emit JUMP ? ? ? ? ?done ? ? ? ?// everything is done, jump to "done"
// else if (2 <= val <= 4)
range:
#emit CONST.pri ? ? 2 ? ? ? ? ? // store the constant value 2 in the primary register
#emit LOAD.S.alt ? ?val ? ? ? ? // load the value of val to the alternate register
#emit SLEQ ? ? ? ? ? ? ? ? ? ? ?// compare the values in the registers to eachother: 2 (primary) must be less than or equal to val (alternate); store the result in the primary register
#emit PUSH.pri ? ? ? ? ? ? ? ? ?// load the value to the primary register (the result of the comparison) in the stack
#emit CONST.pri ? ? 4 ? ? ? ? ? // store the constant value 4 in the primary register
#emit SGEQ ? ? ? ? ? ? ? ? ? ? ?// compare the values in the registers to eachother: 4 (primary) must be greater than or equal to val (alternate); store the result in the primary register
#emit POP.alt ? ? ? ? ? ? ? ? ? // load the value of the first comparison from the stack to the alternate register
#emit AND ? ? ? ? ? ? ? ? ? ? ? // check if both of the comparisons were true by checking if both registers contain a non-zero value
#emit JZER ? ? ? ? ?otherwise ? // if the result of the comparison is false, jump to "otherwise"
// do something here
#emit JUMP ? ? ? ? ?done ? ? ? ?// everything is done, jump to "done"
// else
otherwise:
// do something here
// no jump needed since "done" is just after this code
done:
If the value of val is 1, the code uses four instructions:
PHP Code: LOAD.S.pri? val
EQ.C.pri? ? 1
JZER? ? ? ? range ; the jump does not happen, but the instruction is still used
JUMP? ? ? ? done
If the value of val is 2, 3 or 4, the code uses 13 instructions:
PHP Code: LOAD.S.pri? val
EQ.C.pri? ? 1
JZER? ? ? ? range
CONST.pri? ?2
LOAD.S.alt? val
SLEQ
PUSH.pri
CONST.pri? ?4
SGEQ
POP.alt
AND
JZER? ? ? ? otherwise ; the jump does not happen, but the instruction is still used
JUMP? ? ? ? done
If the value is not matched by any of the previous checks, the code uses 12 instructions:
PHP Code: LOAD.S.pri? val
EQ.C.pri? ? 1
JZER? ? ? ? range
CONST.pri? ?2
LOAD.S.alt? val
SLEQ
PUSH.pri
CONST.pri? ?4
SGEQ
POP.alt
AND
JZER? ? ? ? otherwise
The longer your chain is and the more failed checks there are, the more instructions the code uses. Each failed single value check adds 3 instructions and each failed range check adds 9 instructions.
switch
PHP Code: new val;
switch (val) {
? ?case 1: {
? ? ? ?// do something here
? ?}
? ?case 2 .. 4: {
? ? ? ?// do something here
? ?}
? ?default: {
? ? ? ?// do something here
? ?}
}
When using switch, the compiler generates a case table that contains the value and jump address for every single case, including the default case. Here is the assembly equivalent to this code:
PHP Code: new val;
#emit LOAD.S.pri ? ?val ? ? ? ? // load the value of val to the primary register
#emit SWITCH ? ? ? ?casetable ? // jump to the case table
// case 1:
single:
// do something here
#emit JUMP ? ? ? ? ?done ? ? ? ?// everything is done, jump to "done"
range:
// do something here
#emit JUMP ? ? ? ? ?done ? ? ? ?// everything is done, jump to "done"
otherwise:
// do something here
#emit JUMP ? ? ? ? ?done ? ? ? ?// everything is done, jump to "done"
casetable:
#emit CASETBL
// default:
#emit CASE ? ? ? ? ?4 otherwise // the amount of case table items; the jump address of "default"
// case 1:
#emit CASE ? ? ? ? ?1 single ? ?// the value and jump address of the case
// case 2 .. 4:
#emit CASE ? ? ? ? ?2 range
#emit CASE ? ? ? ? ?3 range
#emit CASE ? ? ? ? ?4 range
done:
Whatever the value of val is 1, the code always uses just three instructions:
PHP Code: LOAD.S.pri? val
SWITCH? ? ? casetable
JUMP? ? ? ? done
The SWITCH instruction jumps to the case table, performs a linear search on the cases and jumps to the correct one. If the search does not find a matching case, it jumps to the default case instead. It is similar to the behaviour of chained else ifs, but since it is done in native code instead of using AMX instructions, the performance is a lot better.
When NOT to use switch?
Large ranges
As seen before, case tables can only use single values as cases, which means that if you use a range of 10000 elements in your switch, the compiler will have to write 10000 entries to the case table and the runtime will have to search through 10000 entries. Using the following benchmarking script I determined that the runtime performance of a case table becomes worse than the one of a single a <= x <= b check at around 30 entries.
PHP Code: #define MAX 30
#define ITERATIONS 1000000
new tick = GetTickCount();
for (new i; i < ITERATIONS; i) {
? ?switch ((i % MAX) 1) {
? ? ? ?case 1 .. MAX: {}
? ?}
}
printf("switch: %i", GetTickCount() - tick);
tick = GetTickCount();
for (new i; i < ITERATIONS; i) {
? ?if (1 <= (i % MAX) 1 <= MAX) {}
}
printf("if: %i", GetTickCount() - tick);
However, runtime performance is not the biggest issue. As seen from this forum topic, the amount of time it takes for the compiler to generate large case tables can be so long that it seems for the user that the compiler has ran into an infinite loop. Even ranges small enough to only have a small impact on the compilation time (for example, 1000 elements) can eventually make the compilation process painful if the delays stack up.
Floating point values
When using switch with floating point values, the case table must also contain every single value within the range. The step between two cases grows as the values grow, but it starts at the smallest possible floating point value in the IEEE754 specification, which is 1.4E-45. This means that each entry differs from the previous and next one by just 0.0000000000000000000000000000000000000000000014.
Some examples of ranges with the respective amounts of case table elements:
Code: |? ? ? ? ? ? ? ? ? ? ? ?Range? ? ? ? ? ? ? ? ? ? ? ?| Amount of entries |
|---------------------------------------------------|-------------------|
| 0.0 .. 0.0000000000000000000000000000000000000001 |? ? ? ?71363? ? ? ?|
|? ? ? ? ? ? ? ? ? ? 1.0 .. 1.01? ? ? ? ? ? ? ? ? ? |? ? ? ?83887? ? ? ?|
|? ? ? ? ? ? ? ? ? ?10.0 .. 10.1? ? ? ? ? ? ? ? ? ? |? ? ? ?104859? ? ? |
|? ? ? ? ? ? ? ? ? 100.0 .. 101.0? ? ? ? ? ? ? ? ? ?|? ? ? ?131073? ? ? |
|? ? ? ? ? ? ? ? ?1000.0 .. 1010.0? ? ? ? ? ? ? ? ? |? ? ? ?163841? ? ? |
|? ? ? ? ? ? ? ? 10000.0 .. 10100.0? ? ? ? ? ? ? ? ?|? ? ? ?102401? ? ? |
|? ? ? ? ? ? ? ?100000.0 .. 101000.0? ? ? ? ? ? ? ? |? ? ? ?128001? ? ? |
This test should be enough to show that using switch with floating point values relevant in the context of SA-MP (coordinates, health, etc.) is completely unreasonable.
When to use switch?
I would say that everywhere where there are chains of comparisons against constant values. I have seen people saying that switch is faster no matter what and using a switch with two cases is much faster than an if-else. However, their runtime performance is about the same and where an if and an else make more sense, they should be used instead.
Tips and tricks
Using switch with floatcmp to compare floating point values
Comparison operators for variables with the Float tag are overloaded to use the floatcmp native instead of comparing them with AMX instructions. When comparing floating point values to eachother and having different outcomes depending of if one of the values is larger than the other or they are equal, you can save a floatcmp call by comparing them using switch instead. floatcmp returns 0 if the values are equal, 1 if the first value is larger and -1 if the second value is larger, so the following snippets of code are equivalent, but the second one performs better:
PHP Code: if (a > b) { // floatcmp called implicitly
? ?// a is larger than b
} else if (a < b) { // floatcmp called implicitly
? ?// a is smaller than b
} else {
? ?// a and b are equal
}
PHP Code: switch (floatcmp(a, b)) {
? ?case 1: {
? ? ? ?// a is larger than b
? ?}
? ?case -1: {
? ? ? ?// a is smaller than b
? ?}
? ?case 0: {
? ? ? ?// a and b are equal
? ?}
}
Using switch to compare strings
Comparing strings with strcmp has been notorious being both slow and tedious for a long time. Although most of that bad reputation came when ZCMD became the goto command processor and strcmp is still very useful elsewhere, there is a grain of truth in every joke. When comparing a string to a long chain of other strings, comparing their hashes would be more efficient and also convenient due to the ability to use switch, because the hashes are in the form of integers. The PAWN language does not support such thing natively, but y_stringhash from YSI does just the job. According to Y_Less? tests, comparing strings using hashes becomes more efficient than using strcmp at around 10 comparisons. More information about y_stringhash and its usage can be found from this topic.
PHP Code: if (!strcmp(number, "one")) {
} else if (!strcmp(number, "two") || !strcmp(number, "three")) {
} else {
}
PHP Code: switch (YHash(number)) {
? ?case _H<one>: {
? ?}
? ?case _H<two>, _H<three>: {
? ?}
? ?default: {
? ?}
}
Credits
- Yashas for the excellent AMX Assembly documentation.
- Y_Less for reviewing the tutorial prior to me publishing it.
- Users of the SA-MP Discord for productive conversations on this topic.
|
|
|
|