Native Coding FAQ

Discussions about Coding and Scripting
User avatar
Wormbo
Adept
Posts: 258
Joined: Sat Aug 24, 2013 6:04 pm
Contact:

Re: Native Coding FAQ

Post by Wormbo »

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.
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Native Coding FAQ

Post by Feralidragon »

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)
User avatar
The_Cowboy
Skilled
Posts: 165
Joined: Mon Jan 24, 2011 3:22 am
Personal rank: Codezilla

Re: Native Coding FAQ

Post by The_Cowboy »

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.
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:Trial and error is sometimes better than any tutorial, because we learn how it works for ourselfs, which kills any doubts about anything :tu:
Patreon: https://www.patreon.com/FreeandOpen
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Native Coding FAQ

Post by Feralidragon »

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.
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Native Coding FAQ

Post by Feralidragon »

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.
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:
"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;
It's ugly, but it's the best workaround I managed to think of and try out (and it actually works).
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: Native Coding FAQ

Post by Higor »

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.
VS2015_Core_1.7z
(10.92 KiB) Downloaded 133 times
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]
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: Native Coding FAQ

Post by Higor »

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:

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);
    }
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())
nogardilaref
Masterful
Posts: 577
Joined: Tue Jun 20, 2017 1:00 pm
Personal rank: ⚋⚊⚌☰⚞⌖⚟☰⚌⚊⚋

Re: Native Coding FAQ

Post by nogardilaref »

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.
lolo121
Novice
Posts: 14
Joined: Thu May 02, 2013 4:28 pm

Re: Native Coding FAQ

Post by lolo121 »

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):

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
Or XMesaGLDrv:

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
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.
User avatar
Neophron
Posts: 2
Joined: Sun Feb 18, 2018 7:56 pm

Re: Native Coding FAQ

Post by Neophron »

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)

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 
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? :noidea
Higor
Godlike
Posts: 1866
Joined: Sun Mar 04, 2012 6:47 pm

Re: Native Coding FAQ

Post by Higor »

somewhere in a CPP file:

Code: Select all

IMPLEMENT_CLASS(MyNativeClass_otherwiseIllGetAFailedToBindError);
Also, character case must match at ALL TIMES in both native and unreal packages.
User avatar
Neophron
Posts: 2
Joined: Sun Feb 18, 2018 7:56 pm

Re: Native Coding FAQ

Post by Neophron »

Higor wrote:somewhere in a CPP file:

Code: Select all

IMPLEMENT_CLASS(MyNativeClass_otherwiseIllGetAFailedToBindError);
Also, character case must match at ALL TIMES in both native and unreal packages.
UC:

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
CPP:

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
As a result, it is always:

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
Not much space to make a typo :noidea
If I delete DLL, there will be the same error.
Game does not even see this DLL..
User avatar
Feralidragon
Godlike
Posts: 5489
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Native Coding FAQ

Post by Feralidragon »

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. :)
Post Reply