Skip to content

Commit 18f3ec7

Browse files
committed
UE4: added possibility to specify game-specific unversioned properties
1 parent 8bebb68 commit 18f3ec7

File tree

1 file changed

+62
-34
lines changed

1 file changed

+62
-34
lines changed

Unreal/UnObject4.cpp

Lines changed: 62 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ struct PropInfo
4040
{
4141
// Name of the property, should exist in class's property table (BEGIN_PROP_TABLE...)
4242
// If starts with '#', the property is ignored, and the following string is a property's type name.
43+
// If starts with '!', the property is ignored, and PropIndex defines the engine version constant.
4344
const char* Name;
4445
// Index of the property.
4546
int PropIndex;
@@ -52,6 +53,8 @@ struct PropInfo
5253
#define MAP(name,index) { #name, index, 0 }, // field specification
5354
#define END { NULL, 0, 0 }, // end of class - mark with NULL name
5455

56+
#define VERSION_BLOCK(version) { "!", version, 0 }, // begin engine-specific block
57+
5558
// Multi-property "drop" instructions
5659
#if _MSC_VER
5760
#define DROP_INT8(index, ...) { "#int8", index, MakeBitmaskWithOffset<index, __VA_ARGS__>() },
@@ -68,14 +71,18 @@ struct PropInfo
6871

6972
#define DROP_OBJ_ARRAY(index) { "#arr_int32", index, 0 }, // TArray<UObject*>
7073

71-
/*
72-
* Class table. If class is missing here, it's assumed that its property list
73-
* matches property table (declared with BEGIN_PROP_TABLE).
74-
* Notes:
75-
* - Classes should go in order: child, parent, parent's parent ... If not, the parent
76-
* class will be captured before the child, and the property index won't match.
77-
* - If property is not listed, SerializeUnversionedProperties4 will skip the property as int32.
78-
*/
74+
// Class table. If class is missing here, it's assumed that its property list matches property table
75+
// (declared with BEGIN_PROP_TABLE).
76+
// Declaration rules:
77+
// - Classes should go in order: child, parent, parent's parent ... If not, the parent
78+
// class will be captured before the child, and the property index won't match.
79+
// - If property is not listed, SerializeUnversionedProperties4 will assume the property is int32.
80+
// - VERSION_BLOCK has strict syntax
81+
// - no multiple fields in DROP_.. macros
82+
// - VERSION_BLOCK with higher version (newer one) should go before lower (older) version
83+
// - VERSION_BLOCK should be ended with constant 0
84+
// - all properties inside of the VERSION_BLOCK should go in ascending order
85+
7986
static const PropInfo PropData[] =
8087
{
8188
BEGIN("UStaticMesh4")
@@ -260,7 +267,10 @@ struct ParentInfo
260267
int MinEngineVersion = 0; // allow changing type information with newer engine versions
261268
};
262269

263-
// Note: parent classes should be defined after children, so the whole table could be iterated with a single pass
270+
// Declaration rules:
271+
// - Parent classes should be defined after children, so the whole table could be iterated with a single pass.
272+
// - If there's engine-specific class declaration, newer engine declarations should go before the older ones.
273+
264274
static const ParentInfo ParentData[] =
265275
{
266276
// Texture classes
@@ -350,28 +360,60 @@ const char* CTypeInfo::FindUnversionedProp(int InPropIndex, int& OutArrayIndex,
350360
p = PropData;
351361
end = PropData + ARRAY_COUNT(PropData);
352362

353-
bool bClassFound = false;
354363
while (p < end)
355364
{
356-
// Note: StrucType could correspond to a few classes from the list about
357-
// because of inheritance, so don't "break" a loop when we've scanned some class, check
358-
// other classes too
359-
bool IsOurClass;
360365
// Use exact name comparison to allow intermediate parents which aren't declared in PropData[].
361366
// Doing the same in FindTypeForProperty().
362-
IsOurClass = stricmp(p->Name, FoundProp.TypeName) == 0;
367+
if (stricmp(p->Name, FoundProp.TypeName) != 0)
368+
{
369+
// A different class, skip its declaration.
370+
while (++p < end && p->Name != NULL)
371+
{}
372+
// skip the END marker and continue with next type map
373+
p++;
374+
continue;
375+
}
376+
377+
bool bPatchingPropIndex = false;
378+
int NumInsertedProps = 0;
363379

364380
// Loop over PropInfo entries, either find a property or an end of the current class information.
365-
while (++p < end && p->Name)
381+
while (++p < end && p->Name != NULL)
366382
{
367-
if (!IsOurClass)
383+
if (p->Name[0] == '!')
368384
{
369-
// We're just waiting for the end of class, to try matching type name again
385+
// Adjust the property index so it will match previous engine version
386+
FoundProp.PropIndex -= NumInsertedProps;
387+
NumInsertedProps = 0;
388+
// This is the engine version block
389+
int RequiredVersion = p->PropIndex;
390+
bPatchingPropIndex = false;
391+
if (InGame < RequiredVersion)
392+
{
393+
// Skip the whole block for the engine which is newer than loaded asset use
394+
while (++p < end && p->Name != NULL && p->Name[0] != '!')
395+
{}
396+
// A step back, so next '++p' in outer loop will check this entry again
397+
p--;
398+
}
399+
else if (RequiredVersion != 0)
400+
{
401+
// The engine version matches, so the following block will probably insert new properties
402+
bPatchingPropIndex = true;
403+
}
370404
continue;
371405
}
372406

407+
if (p->PropIndex <= FoundProp.PropIndex && bPatchingPropIndex)
408+
{
409+
// This property was inserted in this engine version, so we'll need to adjust
410+
// property index at the end of version block to match previous engine version.
411+
NumInsertedProps++;
412+
}
413+
373414
if (p->PropMask)
374415
{
416+
assert(bPatchingPropIndex == false); // no support for masks inside VERSION_BLOCK
375417
// It is used only for DROP_... macros.
376418
uint32 IndexWithOffset = FoundProp.PropIndex - p->PropIndex;
377419
if (IndexWithOffset > 32)
@@ -388,26 +430,12 @@ const char* CTypeInfo::FindUnversionedProp(int InPropIndex, int& OutArrayIndex,
388430
else if (p->PropIndex == FoundProp.PropIndex)
389431
{
390432
// Found a matching property.
391-
//todo: not supporting arrays here, arrays relies on property table to match layout of CTypeInfo declaration
433+
//todo: we're not supporting arrays here, arrays relies on property table to match layout of CTypeInfo declaration
392434
return p->Name;
393435
}
394436
}
395437

396-
if (IsOurClass)
397-
{
398-
// the class has been verified, and we didn't find a property
399-
bClassFound = true;
400-
break;
401-
}
402-
403-
// skip the END marker and continue with next type map
404-
p++;
405-
}
406-
407-
if (bClassFound)
408-
{
409-
// We have a declaration of the class, but didn't find a property. Don't fall to CTypeInfo PROP declarations.
410-
//todo: review later, actually can "return NULL" from inside the loop body
438+
// The class has been verified, and we didn't find a property. Don't fall to CTypeInfo PROP declarations.
411439
return NULL;
412440
}
413441

0 commit comments

Comments
 (0)