Check if an Actor is abstract

Discussions about Coding and Scripting
Buggie
Godlike
Posts: 1489
Joined: Sat Mar 21, 2020 5:32 am

Re: Check if an Actor is abstract

Post by Buggie » Mon Mar 29, 2021 5:46 pm

Mechanics - no. But some stuff (like ABI in OS) changed in terms of linker.
Native code strictly related on offset and fields/functions order.
So All depends how luck you are. If call stay on same places and placed in same hash basket then link will be fine.
If no - all goes to hell.

I try build native part for my EditorTools (not released yet). And if all fine in v436, on v469 not all good even in 469a. Some calls moved and linker pick another.
Engine and Core not native binary backward compatible.

Because changes not big as they can be, most functions called properly, but it is more happily coincidence rather predefined behavior.

User avatar
Shadow
Masterful
Posts: 730
Joined: Tue Jan 29, 2008 12:00 am
Personal rank: Mad Carpenter
Location: Germany

Re: Check if an Actor is abstract

Post by Shadow » Tue Mar 30, 2021 11:48 am

Look, its really not a big deal to check this stuff via a native function. I'm currently in deep development under 469a and everything is stable and works fine, which I cant say about 469b tho.
Image

User avatar
Feralidragon
Godlike
Posts: 5454
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Check if an Actor is abstract

Post by Feralidragon » Tue Mar 30, 2021 2:20 pm

It kinda is a big deal, because native packages imply that you should compile for all supported platforms, which starting at 469 means all major 3 of them: Windows, Linux and even Mac, to support all types of clients.
Plus, you then also need to think about online support, because these have to be downloaded by the client to actually work, which means to use NPLoader at the very least, and to also have the player to accept to download custom .dll/.so files.

That is, if the native package has a client component of course (for server-side-only packages a native package is 100% fine, and doesn't necessarily need to be compiled to every platform).

Having that said, the release of new public headers and a native SDK is definitely planned, but there's still some work to do that only Anthrax knows about, and there's also some extra stuff to be validated with Epic first (which may take a little while).

I suggest you to head towards the official 469 Discord server, to discuss with them directly about this:
https://discord.gg/bYkXPUZs

(nice to see you back btw :tu: )

Buggie
Godlike
Posts: 1489
Joined: Sat Mar 21, 2020 5:32 am

Re: Check if an Actor is abstract

Post by Buggie » Tue Mar 30, 2021 3:29 pm

Feralidragon wrote:
Tue Mar 30, 2021 2:20 pm
That is, if the native package has a client component of course (for server-side-only packages a native package is 100% fine, and doesn't necessarily need to be compiled to every platform).
It is most time true, until you not need update server.

For example you are happy with your custom server-only native stuff on v451 Linux server.
And now you want update your server to v469b.
It is meant fully rebuild all your native stuff with new headers (which not released yet :lol2: ).
So this native stuff prevent you upgrade.

User avatar
sektor2111
Godlike
Posts: 5873
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Check if an Actor is abstract

Post by sektor2111 » Tue Mar 30, 2021 5:22 pm

In Uscript as I can see there is no easier way to detect an abstract than trying to spawn actor. Either way in C++ you might have opened gates to gain these class flags. Perhaps in Editor a builder won't hurt any compatibility if it does only a check and not adding stuff in Level....

Code: Select all

AActor* ULevel::SpawnActor
(
	UClass*			Class,
	FName			InName,
	AActor*			Owner,
	class APawn*	Instigator,
	FVector			Location,
	FRotator		Rotation,
	AActor*			Template,
	UBOOL			bNoCollisionFail,
	UBOOL			bRemoteOwned
)
{
	guard(ULevel::SpawnActor);

	// Make sure this class is spawnable.
	if( !Class )
	{
		debugf( NAME_Warning, TEXT("SpawnActor failed because no class was specified") );
		return NULL;
	}
	if( Class->ClassFlags & CLASS_Abstract ) //How can I see these easily ?
	{
		debugf( NAME_Warning, TEXT("SpawnActor failed because class %s is abstract"), Class->GetName() );
		return NULL;
	}
	else if( !Class->IsChildOf(AActor::StaticClass()) )
	{
		debugf( NAME_Warning, TEXT("SpawnActor failed because %s is not an actor class"), Class->GetName() );
		return NULL;
	}
	else if( !GIsEditor && (Class->GetDefaultActor()->bStatic || Class->GetDefaultActor()->bNoDelete) )
	{
		debugf( NAME_Warning, TEXT("SpawnActor failed because class %s has bStatic or bNoDelete"), Class->GetName() );
		return NULL;		
	}
Which means that Editor can actually spawn all sort of actors as it doesn't have restrictions... It's Editor after all.

User avatar
sektor2111
Godlike
Posts: 5873
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Check if an Actor is abstract

Post by sektor2111 » Thu Apr 01, 2021 9:47 pm

I've got something for MapGarbage at this chapter. It is concerning STOCK abstracts as posted by Buggie.
We are iterating through factories / Actors

Code: Select all

...
	local int i;
...
		if ( ThingFactory(A) != None )
		{
			for ( i=0; i<66; i++ )
			{
				if ( Instr(string(ThingFactory(A).Prototype),Abstracts[i] ) != -1 )
				{
					log (A.Name@"uses an abstract prototype"@ThingFactory(A).Prototype$", this won't spawn in map's run-time...",'TRASHFactory');
					break;
				}
			}
		}
Abstracts[ i ] is an array hard-coded with 66 types (+ position 0) which are... strings, lol...

Code: Select all

defaultproperties
{
...
...
	Abstracts(0)=Arena
	Abstracts(1)=Bot
	Abstracts(2)=ChallengeVoicePack
	Abstracts(3)=FemaleBotPlus
	Abstracts(4)=HumanBotPlus
	Abstracts(5)=Ladder
	Abstracts(6)=MaleBotPlus
	Abstracts(7)=StationaryPawn
	Abstracts(8)=TFemaleBody
	Abstracts(9)=TMaleBody
	Abstracts(10)=TournamentAmmo
	Abstracts(11)=TournamentConsole
	Abstracts(12)=TournamentFemale
	Abstracts(13)=TournamentHealth
	Abstracts(14)=TournamentMale
	Abstracts(15)=TournamentPlayer
	Abstracts(16)=TournamentWeapon
	Abstracts(17)=UTHumanCarcass
	Abstracts(18)=UT_Decoration
	Abstracts(19)=VoiceFemale
	Abstracts(20)=VoiceMale
	Abstracts(21)=Commandlet
	Abstracts(22)=BrushBuilder
	Abstracts(23)=Actor
	Abstracts(24)=Ammo
	Abstracts(25)=DamageType
	Abstracts(26)=Decoration
	Abstracts(27)=HUD
	Abstracts(28)=Info
	Abstracts(29)=Inventory
	Abstracts(30)=Keypoint
	Abstracts(31)=MessagingSpectator
	Abstracts(32)=Pawn
	Abstracts(33)=Pickup
	Abstracts(34)=Projectile
	Abstracts(35)=ReplicationInfo
	Abstracts(36)=VoicePack
	Abstracts(37)=Weapon
	Abstracts(38)=FractalTexture
	Abstracts(39)=WaterTexture
	Abstracts(40)=CustomBot
	Abstracts(41)=customplayer
	Abstracts(42)=Relic
	Abstracts(43)=UBrowserServerListFactory
	Abstracts(44)=Burned
	Abstracts(45)=Corroded
	Abstracts(46)=Decapitated
	Abstracts(47)=Drowned
	Abstracts(48)=Fell
	Abstracts(49)=UnrealDamageType
	Abstracts(50)=Bots
	Abstracts(51)=DeadMales
	Abstracts(52)=Female
	Abstracts(53)=FemaleBot
	Abstracts(54)=Human
	Abstracts(55)=HumanBot
	Abstracts(56)=HumanCarcass
	Abstracts(57)=Male
	Abstracts(58)=MaleBot
	Abstracts(59)=ScriptedPawn
	Abstracts(60)=ShareSounds
	Abstracts(61)=Skaarj
	Abstracts(62)=UnrealIPlayer
	Abstracts(63)=MeshBrowser
	Abstracts(64)=UTLadder
	Abstracts(65)=UTLadderStub
For another abstracts we can only pray for more mapper intelligence... either way, logging Factories...
Code might be like a doggy slow and causing iterations but it won't create dependencies and then it prevents loading all sort of assets in memory...

If we talk about run-time checks, I think this check would need to be scheduled for second 1 or 2. Me one I have a lot of iterations in PostBeginPlay and the rest, I have already too much charge around first tick... it's why I moved all movers tweaking in a background state code...

Buggie
Godlike
Posts: 1489
Joined: Sat Mar 21, 2020 5:32 am

Re: Check if an Actor is abstract

Post by Buggie » Sat Jun 05, 2021 7:13 pm

OjitroC wrote:
Sun Mar 28, 2021 1:09 pm
Barbie wrote:
Sun Mar 28, 2021 12:44 pm
BTW: I suspect that the star in front of a class name in UnrealEd v469b indicate an abstract class?
Yes, it does - it took me a while to work that out. First noticed that in the 227 Editor.
Not at all.
scr_1622916627.png
You do not have the required permissions to view the files attached to this post.

User avatar
OjitroC
Godlike
Posts: 2984
Joined: Sat Sep 12, 2015 8:46 pm

Re: Check if an Actor is abstract

Post by OjitroC » Sat Jun 05, 2021 7:44 pm

Buggie wrote:
Sat Jun 05, 2021 7:13 pm
Not at all.
scr_1622916627.png
Indeed not, as you've shown - so the question is :- what does it mean?

User avatar
Feralidragon
Godlike
Posts: 5454
Joined: Wed Feb 27, 2008 6:24 pm
Personal rank: Work In Progress
Location: Liandri

Re: Check if an Actor is abstract

Post by Feralidragon » Sat Jun 05, 2021 8:56 pm

It means whether or not the class is placeable in a map from the editor.
In other words, if you try to place any class flagged like that in a map, it will fail, because it's not allowed.

Abstract classes are just one type of class that are flagged like that in that view because they cannot be spawned at all, so by extension they cannot be placed in a map from the editor either.
In the case of the classes Buggie pointed out, while they're not abstract, they are native, so they may have some flag set on the corresponding native class that doesn't allow it to be spawned from the editor, even though this isn't visible from the UScript side for that class.

The same happens (or should happen at least, I don't remember a practical example out of my head right now) with classes set as nousercreate as well (classes which aren't abstract, but are explicitly set to not be spawned from the editor).

Deaod
Novice
Posts: 13
Joined: Fri Jul 10, 2020 9:22 am

Re: Check if an Actor is abstract

Post by Deaod » Mon Dec 27, 2021 3:53 am

There is a hacky way to check if a class is abstract. Heres how:
  • First youll need the attached .uc files. Copy these into your package, next to all your other .uc files
    XClass.zip
  • Then, you need these functions (and class variable):

    Code: Select all

    var XClass TempClass;
    
    function XClass GetClass(class C) {
    	SetPropertyText("TempClass", "class'"$string(C)$"'");
    	return TempClass;
    }
    
    function bool IsClassAbstract(class C) {
    	local XClass XC;
    	XC = GetClass(C);
    	return (XC.ClassFlags & 1) != 0;
    }
  • Finally, you can now check if a class is abstract using IsClassAbstract(class'Pawn') or IsClassAbstract(SomeObject.Class)
Of course this is not all you can check; here are all the flags:

Code: Select all

	// Base flags.
	CLASS_Abstract          = 0x00001,  // Class is abstract and can't be instantiated directly.
	CLASS_Compiled			= 0x00002,  // Script has been compiled successfully.
	CLASS_Config			= 0x00004,  // Load object configuration at construction time.
	CLASS_Transient			= 0x00008,	// This object type can't be saved; null it out at save time.
	CLASS_Parsed            = 0x00010,	// Successfully parsed.
	CLASS_Localized         = 0x00020,  // Class contains localized text.
	CLASS_SafeReplace       = 0x00040,  // Objects of this class can be safely replaced with default or NULL.
	CLASS_RuntimeStatic     = 0x00080,	// Objects of this class are static during gameplay.
	CLASS_NoExport          = 0x00100,  // Don't export to C++ header.
	CLASS_NoUserCreate      = 0x00200,  // Don't allow users to create in the editor.
	CLASS_PerObjectConfig   = 0x00400,  // Handle object configuration on a per-object basis, rather than per-class.
	CLASS_NativeReplication = 0x00800,  // Replication handled in C++.
	CLASS_EditorExpanded    = 0x02000,	// Editor use only. Set when the Actor Browser has added this class' children to the actor tree.
Some of these arent useful, i think, like CLASS_Compiled or CLASS_Parsed.

Notes:
  • I make no guarantees about compatibility with game versions other than 469b (which is the version i tested on). This method will break if a future version adds a field to any of the native classes that im duplicating in unrealscript. Its also not compatible with some prior versions of the game, check with the released SDK to figure out what the data structures look like for your particular version.
  • Before implementing this in production code, please test thoroughly, because mistakes can easily lead to crashes.
  • I want to stress again, this is incredibly hacky. I dont know why youd ever want to know whether a class is abstract. Chances are you dont need that information (until you do, yada yada).
  • If you want to do this in a simulated function you need to temporarily change the Role of the actor to ROLE_Authority, because SetPropertyText doesn't work otherwise.
EDIT: Fixed return type of IsClassAbstract
You do not have the required permissions to view the files attached to this post.
Last edited by Deaod on Mon Dec 27, 2021 3:47 pm, edited 2 times in total.

User avatar
sektor2111
Godlike
Posts: 5873
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Check if an Actor is abstract

Post by sektor2111 » Mon Dec 27, 2021 12:43 pm

Deaod wrote:
Mon Dec 27, 2021 3:53 am
I dont know why youd ever want to know whether a class is abstract.
As Barbie said, some mappers with less tech knowledge or by accident are doing wrong settings to actors (projectiles, creatures, etc.) and then... an abstract cannot be created. A tool for doing a basic check BEFORE blindly adding map-files into a public gaming place will prevent ugly events which not always are making players happy.
Anyway I will look to your code and I think I'll do some testing - definitely I'm interested about these operators as long as I wasn't very familiar in how to gain some flags of an Object/Actor. And... there are maps with broken actors, un-compiled, I'm not curious about consequences of using broken things. I'm one of those targeting quality in front of quantity and then... broken things are moved out of my any UT installation.

Thanks a lot so far :tu: .

Edit: Code was printing compiling errors until I defined this function as a BOOL...

Code: Select all

function bool IsClassAbstract(class C)
{
	local XClass XC;

	XC = GetClass(C);
	return (XC.ClassFlags & 1) != 0;
}
Edit2: And a basic check seems to work....
An Abstract is reported as follows:
AnAbstract.PNG
A normally useable class is reported as follows:
ANonAbstract.PNG
And then... I might want to implement these in testing code for Factories...

Can I have your brain for 3 hours :mrgreen: ?
:gj:

Edit3: And I think I have in LevelValidate clone command a report of UnCompiled junks like here:

Code: Select all

LEVELVALIDATE: Level Validation:
PlayerStart: Checking PlayerStart12
...
PlayerStart: Checking PlayerStart23
Null: Found Uncompiled ParticleSprayer0.
..
Null: Found Uncompiled EAHeavySkaarjTrooper2.
...
Null: Found Uncompiled EASkaarjTrooper0.
...
Null: Found Uncompiled ShockerCore0.
...
Null: Found Uncompiled Shocker2.
...
Null: Found Uncompiled EAPupae0.
...
Null: Found Uncompiled EAHeavySkaarjTrooper0.
Null: Found Uncompiled EABrute0.
...
Null: Found Uncompiled EAWarlord0.
NullCodes: Found 25 junk actors that have not been compiled.
You do not have the required permissions to view the files attached to this post.