Native Coding FAQ
-
- Adept
- Posts: 258
- Joined: Sat Aug 24, 2013 6:04 pm
Re: Native Coding FAQ
As far as I know, there are several components for each latent function. One obviously is the latent function itself, another is the latent polling function. The latent function is a standard native function, but it sets up a "latent action" - the poll function. That poll function is implemented similarly to a standard native function, except that it is not accessible directly from UnrealScript. Instead, it is called every tick instead of the state code until it ends the latent action.
The Sleep function, for example, is implemented to set the Actor.LatentFloat value to the seconds to sleep and specifies the corresponding latent action, causing state code to suspend. The "PollSleep" function is called instead of state code the next time the actor is ticked and reduces LatentFloat by the delta time. If the sleep time has passed, the poll sleep function resets the latent action. Until that happens, state code continues to suspend after the poll function returns and next tick the poll function is called again. When the poll function resets the latent action, state code continues after the original latent function call.
The Sleep function, for example, is implemented to set the Actor.LatentFloat value to the seconds to sleep and specifies the corresponding latent action, causing state code to suspend. The "PollSleep" function is called instead of state code the next time the actor is ticked and reduces LatentFloat by the delta time. If the sleep time has passed, the poll sleep function resets the latent action. Until that happens, state code continues to suspend after the poll function returns and next tick the poll function is called again. When the poll function resets the latent action, state code continues after the original latent function call.
-
- Godlike
- Posts: 5498
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Native Coding FAQ
So probably my theory may end up working out...
I was thinking to create a poll boolean function with no arguments whatsoever, and thus only return true once it allowed the state code to continue, but maybe from your description at least the Tick delta argument may be needed...
I wonder though if to register the function as latent if it's as simple as declaring the function (in those macro statements) with execPoll instead of exec alone.
Anyway, thanks for the info, I will try to build a custom one later on and give news about it. My idea was (and still is): in case I am able to implement a multi-threading API of sorts accessible from UScript (to load/pre-cache files in parallel in a non-blocking way, or for expensive operations, or simply improve the speed of some stuff by taking advantage of multiple core CPUs) and being able to wait for it at some point if called from state code, rather than just use UScript-level semaphores to detect the same thing.
It would have configured limitations of course, whereas once the limit of threads was hit, it would keep on running it in the main thread while outputting an error to the log (I probably would limit it to 4 threads (excluding the native ones for very specific stuff), or make it smart enough and allow as many threads as reported CPUs).
Regardless, I still have to test all these things, so I am not even sure if half of them is even possible lol (although in theory it is)
I was thinking to create a poll boolean function with no arguments whatsoever, and thus only return true once it allowed the state code to continue, but maybe from your description at least the Tick delta argument may be needed...
I wonder though if to register the function as latent if it's as simple as declaring the function (in those macro statements) with execPoll instead of exec alone.
Anyway, thanks for the info, I will try to build a custom one later on and give news about it. My idea was (and still is): in case I am able to implement a multi-threading API of sorts accessible from UScript (to load/pre-cache files in parallel in a non-blocking way, or for expensive operations, or simply improve the speed of some stuff by taking advantage of multiple core CPUs) and being able to wait for it at some point if called from state code, rather than just use UScript-level semaphores to detect the same thing.
It would have configured limitations of course, whereas once the limit of threads was hit, it would keep on running it in the main thread while outputting an error to the log (I probably would limit it to 4 threads (excluding the native ones for very specific stuff), or make it smart enough and allow as many threads as reported CPUs).
Regardless, I still have to test all these things, so I am not even sure if half of them is even possible lol (although in theory it is)
-
- Skilled
- Posts: 165
- Joined: Mon Jan 24, 2011 3:22 am
- Personal rank: Codezilla
Re: Native Coding FAQ
I am sorry I wasn't clear enough. When I said that the art of native coding is'nt discussed much, I meant native coding on Linux. Writing an anticheat for Linux is pretty useless (or so I gather) because you can run anything (yeah Linux native cheats) from root without giving the anitcheat a clue. If the knowledge of compiling native cheats on Linux is spread then it would be terrible. (Please note that I am not familiar with native stuff. All my views regarding this are based on speculations and four years experience with Ubuntu)Feralidragon wrote:Generally cheaters are the reason to go native as they go native first, because realistically, if cheaters kept themselves to UScript based cheats, UScript based anti-cheats would be more than enough, even though a native one would always be more powerful, and that's the leap that ACE single handendly achieved, but from the first version onwards, cheaters kept trying to bypass it.
Patreon: https://www.patreon.com/FreeandOpenFeralidragon wrote:Trial and error is sometimes better than any tutorial, because we learn how it works for ourselfs, which kills any doubts about anything
-
- Godlike
- Posts: 5498
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Native Coding FAQ
Windows, Linux... both of them are vulnerable in the same way in that particular aspect.
What you can do with "sudo" in Linux you can do with "admin mode" in Windows as easily (they're equivalents in what they're supposed to do). Regardless, the processes and services are always listed anyway in some form, so you can always catch any cheat process going on.
Now, there's one thing that makes Linux better for cheat making indeed, I wouldn't say sudo, but the ability to modify and make your own kernel, sudo, ps, top, etc, given that it's all open source, and that way you can indeed have total control of your machine at the lowest levels, something you generally can't with Windows nor Mac.
So from that point of view, yes, from the "sudo", I don't agree, the difficulty is pretty much the same imho.
What you can do with "sudo" in Linux you can do with "admin mode" in Windows as easily (they're equivalents in what they're supposed to do). Regardless, the processes and services are always listed anyway in some form, so you can always catch any cheat process going on.
Now, there's one thing that makes Linux better for cheat making indeed, I wouldn't say sudo, but the ability to modify and make your own kernel, sudo, ps, top, etc, given that it's all open source, and that way you can indeed have total control of your machine at the lowest levels, something you generally can't with Windows nor Mac.
So from that point of view, yes, from the "sudo", I don't agree, the difficulty is pretty much the same imho.
-
- Godlike
- Posts: 5498
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Native Coding FAQ
I made a bit of research on this (given that I finally got VS2010 working with the headers, given that I will start a more serious project on UT stuff) and it affects both unsigned short and unsigned char (BYTE), and I found out that it's because of wchar_t, specifically on this setting:anth wrote:
- If you want to use a more recent VS version than 6.0, then stay away from TArray<BYTE>. The compiler will completely flip out if you attempt to use BYTE arrays. I never really bothered to figure out why.
"Treat wchar_t as built-in type"
Which once disabled causes problems of this sort from VS2008 and beyond given that they use updated libraries which evaluate this kind of thing, and needless to say that this setting has to be disabled in order for the code to compile at all.
I still tried to search for ways to modify the headers to conciliate both the setting and the overall wchar_t stuff, but to no avail (but I am quite a noob a this, so if someone knows or finds something more about this, it would come in handy), so yeah, it's best to stay out of TCHAR and BYTE. SBYTE works however.
If a TArray<BYTE> is absolutely necessary, perhaps the best workaround would be like the boolean array workaround in UScript, by building a single member struct:
Code: Select all
struct UBYTE { BYTE B; };
TArray<UBYTE> foo;
-
- Godlike
- Posts: 1866
- Joined: Sun Mar 04, 2012 6:47 pm
Re: Native Coding FAQ
One way to get around TArray<BYTE> problems:
Get these two header files, they disable some warnings and make some of the TArray methods 'FORCEINLINE' so that it calls directly FArray stuff instead of TArray<BYTE> ones that cause linking problems. If you're using these headers and are having problems with the TArray destructor in a function, then make it so that you manually init and destroy your TArray<BYTE>'s like the following code does:
Get these two header files, they disable some warnings and make some of the TArray methods 'FORCEINLINE' so that it calls directly FArray stuff instead of TArray<BYTE> ones that cause linking problems. If you're using these headers and are having problems with the TArray destructor in a function, then make it so that you manually init and destroy your TArray<BYTE>'s like the following code does:
Code: Select all
//Initialize
INT RawArray[3] = {0,0,0}; //[0]datapointer, [1]arraynum, [2]arraymax_allocated
TArray<BYTE>* A = (TArray<BYTE>*) &RawArray[0]; //By pointer, we treat those 3 INT as an array
//Functions using ->
A->Add( add_count_here );
//Element accessor works like this:
(*A)(0) = something;
(*A)(i) = something_i;
//Optional accessor (if you don't use modified headers, you must add elements first)
// ((BYTE*)RawArray[0])[i] = something_i;
//Once you're done, you MUST do this:
A->Empty();
// Manual mem-free, may work or not (if you don't use modified headers)
// if ( RawArray[2] )
// appFree( RawArray[0]);
//Notes:
//A->Num() is equivalent to RawArray[1]
You do not have the required permissions to view the files attached to this post.
-
- Godlike
- Posts: 1866
- Joined: Sun Mar 04, 2012 6:47 pm
Re: Native Coding FAQ
Some info:
In one of your main headers, most likely the one that autogenerates the unreal classes that have a script counterpart you'll find macros like these:
This AUTOGENERATE_NAME is a macro that creates 'extern FName' variables, which are used to globally access these names across your package (and likely other packages) from c++.
Something like this will be found in one of your CPP files.
Then a second inclusion of this header in a 'RegisterNames' function (as seen in SampleNativePackage) where said variables are initialized during runtime using the same macros.
Engine is just a little exception but the functionality is the same...
========================================
I noticed that while this works on Windows flawlessly (as long as you initialize the names before calling an event), in Linux the second include does nothing and instead keeps all names as "None".
So you may want to redefine the RegisterNames in case of a Linux build, or redefine the second 'AUTOGENERATE_NAME' macro into something else.
Checking the name before calling each individual unrealscript event is a way of doing things.
But you can do this anywhere in your code, but in cases of actors it can be best done in a AActor::Spawned derivate (don't forget to call Super::Spawned())
In one of your main headers, most likely the one that autogenerates the unreal classes that have a script counterpart you'll find macros like these:
Code: Select all
AUTOGENERATE_NAME(Spawned)
AUTOGENERATE_NAME(Destroyed)
AUTOGENERATE_NAME(GainedChild)
AUTOGENERATE_NAME(LostChild)
... etc
This AUTOGENERATE_NAME is a macro that creates 'extern FName' variables, which are used to globally access these names across your package (and likely other packages) from c++.
Something like this will be found in one of your CPP files.
Code: Select all
// Register things.
#define NAMES_ONLY
#define AUTOGENERATE_NAME(name) ENGINE_API FName ENGINE_##name;
#define AUTOGENERATE_FUNCTION(cls,idx,name) IMPLEMENT_FUNCTION(cls,idx,name)
#include "EngineClasses.h"
#undef AUTOGENERATE_FUNCTION
#undef AUTOGENERATE_NAME
#undef NAMES_ONLY
Then a second inclusion of this header in a 'RegisterNames' function (as seen in SampleNativePackage) where said variables are initialized during runtime using the same macros.
Engine is just a little exception but the functionality is the same...
Code: Select all
void UEngine::Init()
{
guard(UEngine::Init);
// Add the intrinsic names.
#define NAMES_ONLY
#define AUTOGENERATE_NAME(name) ENGINE_##name = FName(TEXT(#name),FNAME_Intrinsic);
#define AUTOGENERATE_FUNCTION(cls,idx,name)
#include "EngineClasses.h"
#undef AUTOGENERATE_FUNCTION
#undef AUTOGENERATE_NAME
#undef NAMES_ONLY
... etc
========================================
I noticed that while this works on Windows flawlessly (as long as you initialize the names before calling an event), in Linux the second include does nothing and instead keeps all names as "None".
So you may want to redefine the RegisterNames in case of a Linux build, or redefine the second 'AUTOGENERATE_NAME' macro into something else.
Checking the name before calling each individual unrealscript event is a way of doing things.
Code: Select all
void eventFinishedPathing()
{
if ( FERBOTZ_FinishedPathing.GetIndex() == NAME_None )
FERBOTZ_FinishedPathing = FName("FinishedPathing", FNAME_Intrinsic);
ProcessEvent(FindFunctionChecked(FERBOTZ_FinishedPathing),NULL);
}
-
- Masterful
- Posts: 577
- Joined: Tue Jun 20, 2017 1:00 pm
- Personal rank: ⚋⚊⚌☰⚞⌖⚟☰⚌⚊⚋
Re: Native Coding FAQ
Is there a pack of UT header files tweaked for VS2017 already (or close enough to it, like VS2015 or so)?
Yesterday I installed VS again (for the first time in 3 years), to check on the latest OpenGL renderer by Chris and do some experiments with it in UT (first understand its flow, change here and there and check the effects, then try to optimize and perhaps add a couple of features of my own, in other words, toy with it a little and check what I could do).
And I used my own header files which I tweaked back at the time with another VS version (not sure which... 2012 perhaps, I don't remember), and they compiled well without issues (other than a few harmless warnings for what they were).
First I tried a testing package that I made back then and it worked flawlessly in UT at the first try, but once I tried the OpenGL source, it compiled successfully but it crashes by the time it tries to get the viewport from UT (or so it seems).
The source I tried is this one by the way: http://www.cwdohnal.com/utglr/utglr37src.zip
from here: http://www.cwdohnal.com/utglr/#Installa ... structions
I remember toying with it a little back then, but I think it was the utglr34 source rather than the latest one, but it worked.
I will still try to investigate better why it's crashing at all in the meanwhile, but if there are updated headers out there from someone with everything sorted out, I could use them to at least rule the headers out.
Yesterday I installed VS again (for the first time in 3 years), to check on the latest OpenGL renderer by Chris and do some experiments with it in UT (first understand its flow, change here and there and check the effects, then try to optimize and perhaps add a couple of features of my own, in other words, toy with it a little and check what I could do).
And I used my own header files which I tweaked back at the time with another VS version (not sure which... 2012 perhaps, I don't remember), and they compiled well without issues (other than a few harmless warnings for what they were).
First I tried a testing package that I made back then and it worked flawlessly in UT at the first try, but once I tried the OpenGL source, it compiled successfully but it crashes by the time it tries to get the viewport from UT (or so it seems).
The source I tried is this one by the way: http://www.cwdohnal.com/utglr/utglr37src.zip
from here: http://www.cwdohnal.com/utglr/#Installa ... structions
I remember toying with it a little back then, but I think it was the utglr34 source rather than the latest one, but it worked.
I will still try to investigate better why it's crashing at all in the meanwhile, but if there are updated headers out there from someone with everything sorted out, I could use them to at least rule the headers out.
-
- Novice
- Posts: 14
- Joined: Thu May 02, 2013 4:28 pm
Re: Native Coding FAQ
What about compiling native mods using public 432 headers on linux? I successfully compiled 400 game engine with GCC 2.95.4-14 version, but have problems when compiling under 432 version (official headers and some cpp code). Example log (compiling XDrv):
Or XMesaGLDrv:
Whats wrong with it? Maybe different version of GCC I need? Thanks for help. OS - Debian Woody. I also tried to compile ServerCrashFix_v11 and result is similar like XDrv results.
Code: Select all
gcc -c -D__LINUX_X86__ -D__STATIC_LINK=0 -fno-for-scope -O2 -Werror -fomit-frame-pointer -m386 -D_REENTRANT -Werror -fPIC -I../../XDrv/Inc -I../../Engine/Inc -I../../Core/Inc -DGPackage=GPackageXDrv -o ../../XDrv/release-linux-i386-shared/XClient.o XClient.cpp > ../../XDrv/release-linux-i386-shared/XClient.lst
In file included from ../../Core/Inc/Core.h:61,
from ../../Engine/Inc/Engine.h:21,
from ../../XDrv/Inc/XDrv.h:20,
from XClient.cpp:9:
../../Core/Inc/UnGnuG.h:129: no data type for mode `TI'
../../Core/Inc/UnGnuG.h: In function `INT appRound(float)':
../../Core/Inc/UnGnuG.h:216: `F' undeclared (first use this function)
../../Core/Inc/UnGnuG.h:216: (Each undeclared identifier is reported only once
../../Core/Inc/UnGnuG.h:216: for each function it appears in.)
In file included from ../../Core/Inc/Core.h:389,
from ../../Engine/Inc/Engine.h:21,
from ../../XDrv/Inc/XDrv.h:20,
from XClient.cpp:9:
../../Core/Inc/UnFile.h: At top level:
../../Core/Inc/UnFile.h:379: syntax error before `('
../../Core/Inc/UnFile.h:380: syntax error before `('
../../Core/Inc/UnFile.h:381: syntax error before `('
../../Core/Inc/UnFile.h:382: syntax error before `('
../../Core/Inc/UnFile.h:383: syntax error before `('
../../Core/Inc/UnFile.h:384: syntax error before `('
../../Core/Inc/UnFile.h:385: syntax error before `('
../../Core/Inc/UnFile.h:386: syntax error before `('
../../Core/Inc/UnFile.h:387: syntax error before `('
../../Core/Inc/UnFile.h:388: syntax error before `('
../../Core/Inc/UnFile.h:389: syntax error before `('
../../Core/Inc/UnFile.h:390: `DOUBLE' was not declared in this scope
../../Core/Inc/UnFile.h:390: parse error before `)'
In file included from ../../Core/Inc/Core.h:407,
from ../../Engine/Inc/Engine.h:21,
from ../../XDrv/Inc/XDrv.h:20,
from XClient.cpp:9:
../../Core/Inc/UnMath.h: In method `FLOAT FVector::Size() const':
../../Core/Inc/UnMath.h:637: implicit declaration of function `int appSqrt(...)'
../../Core/Inc/UnMath.h: In function `class FVector RandomSpreadVector(float)':
../../Core/Inc/UnMath.h:2190: implicit declaration of function `int appCos(...)'
../../Core/Inc/UnMath.h:2191: implicit declaration of function `int appAcos(...)'
../../Core/Inc/UnMath.h:2193: implicit declaration of function `int appSin(...)'
XClient.cpp: In method `void UXClient::Tick()':
XClient.cpp:170: no match for `FTime & < FTime &'
make[1]: *** [../../XDrv/release-linux-i386-shared/XClient.o] Error 1
make: *** [usedeps] Error 2
Code: Select all
Generating dependencies for XMesaGLDrv.cpp
Generating dependencies for XMesaGL.cpp
XMesaGL.cpp:37: macro `DECLARE_CLASS' used with only 3 args
gcc -c -D__LINUX_X86__ -D__STATIC_LINK=0 -fno-for-scope -O2 -Werror -fomit-frame-pointer -m386 -D_REENTRANT -Werror -fPIC -I../../Render/Inc -I../../Engine/Inc -I../../Core/Inc -DGPackage=GPackageXMesaGLDrv -o ../../XMesaGLDrv/release-linux-i386-shared/XMesaGL.o XMesaGL.cpp > ../../XMesaGLDrv/release-linux-i386-shared/XMesaGL.lst
XMesaGL.cpp:37: macro `DECLARE_CLASS' used with only 3 args
make[1]: *** [../../XMesaGLDrv/release-linux-i386-shared/XMesaGL.o] Error 1
make: *** [usedeps] Error 2
-
- Posts: 2
- Joined: Sun Feb 18, 2018 7:56 pm
Re: Native Coding FAQ
Hello everyone UT99.org.
After successful compilation of dll (Thanks to Feralidragon),
I get a Critical Error when I start the game. (I changed the names to be very easy to understand)
Prologue: The native function is located in one package MyPackage.u,
but I use it from another MyOtherPackage.u as a static function.
There are no errors at compilation (C++ and UC)
I tried to do native (number) final function instead of native static function - but the result is the same.
I've seen ULinker class in UT headers, but it's hard to understand what's going on.
Any idea why everything is so bad?
After successful compilation of dll (Thanks to Feralidragon),
I get a Critical Error when I start the game. (I changed the names to be very easy to understand)
Code: Select all
Can't bind to native class MyPackage.MyNativeClass
History: UClass::Bind <- (Class MyPackage.MyNativeClass) <- ULinkerLoad::CreateExport <- (MyNativeClass 989) <- ULinkerLoad::CreateImport <- IndexToObject <- ULinkerLoad<<UObject <- (LinkerLoad Transient.LinkerLoad100 1780205)) <- UClass::Serialize <- (Class MyOtherPackage.MyOtherClass) <- LoadObject <- (Class MyOtherPackage.MyOtherClass1780205==1780205/97123156 1779538 670) Etc
but I use it from another MyOtherPackage.u as a static function.
There are no errors at compilation (C++ and UC)
I tried to do native (number) final function instead of native static function - but the result is the same.
I've seen ULinker class in UT headers, but it's hard to understand what's going on.
Any idea why everything is so bad?
-
- Godlike
- Posts: 1866
- Joined: Sun Mar 04, 2012 6:47 pm
Re: Native Coding FAQ
somewhere in a CPP file:
Also, character case must match at ALL TIMES in both native and unreal packages.
Code: Select all
IMPLEMENT_CLASS(MyNativeClass_otherwiseIllGetAFailedToBindError);
-
- Posts: 2
- Joined: Sun Feb 18, 2018 7:56 pm
Re: Native Coding FAQ
UC:Higor wrote:somewhere in a CPP file:Also, character case must match at ALL TIMES in both native and unreal packages.Code: Select all
IMPLEMENT_CLASS(MyNativeClass_otherwiseIllGetAFailedToBindError);
Code: Select all
class Custom extends Object
native;
native static function int Test(int i);
//Or native function int Test(int i) / native(number) final function int Test(int i) - It does not matter
Code: Select all
IMPLEMENT_PACKAGE(MyPackage);
IMPLEMENT_CLASS(UCustom);
void UCustom::execTest( FFrame& Stack, RESULT_DECL )
{
guard(UCustom::execTest);
P_GET_INT(i);
P_FINISH;
*(INT*)Result = i + 1;
unguard;
}
IMPLEMENT_FUNCTION(UCustom, -1, execTest);
//Or IMPLEMENT_FUNCTION(UCustom, number, execTest); - It does not matter
Code: Select all
Can't bind to native class MyPackage.Custom
History: UClass::Bind <- (Class MyPackage.Custom) <- ULinkerLoad::CreateExport <- (Custom989) <- ULinkerLoad::CreateImport <- IndexToObject <- ULinkerLoad<<UObject <- (LinkerLoad Transient.LinkerLoad100 1780205)) <- UClass::Serialize <- (Class MyOtherPackage.MyOtherClass) <- LoadObject <- (Class MyOtherPackage.MyOtherClass1780205==1780205/97123156 1779538 670) Etc
If I delete DLL, there will be the same error.
Game does not even see this DLL..
-
- Godlike
- Posts: 5498
- Joined: Wed Feb 27, 2008 6:24 pm
- Personal rank: Work In Progress
- Location: Liandri
Re: Native Coding FAQ
I just want to point out that the VS solution I gave Neophron is this one: http://www.mediafire.com/file/a5q69xohw ... roject.rar
(it's the same as the one listed in the topic where I released all my sources from years ago)
That's a base empty solution I created back then, I tweaked most of the headers myself (thing such as the TEXT or UTEXT macro), and I got some of them from another github project, specifically for VS2010, and it worked very well.
However, I am unsure how well they work in newer VS versions, but last time I tried they seemed to work as well, but still there's a small possibility that my headers may not be set up properly even if they compile without problems.
So if there's a better working base solution for newer VS versions from you guys that you can release, that would be preferable to ensure everything works as intended.
(it's the same as the one listed in the topic where I released all my sources from years ago)
That's a base empty solution I created back then, I tweaked most of the headers myself (thing such as the TEXT or UTEXT macro), and I got some of them from another github project, specifically for VS2010, and it worked very well.
However, I am unsure how well they work in newer VS versions, but last time I tried they seemed to work as well, but still there's a small possibility that my headers may not be set up properly even if they compile without problems.
So if there's a better working base solution for newer VS versions from you guys that you can release, that would be preferable to ensure everything works as intended.