FString UK2Node_BaseMCDelegate::GetDocumentationLink() const { UClass* ParentClass = NULL; if (DelegateReference.IsSelfContext()) { if (HasValidBlueprint()) { UField* Delegate = FindField<UField>(GetBlueprint()->GeneratedClass, DelegateReference.GetMemberName()); if (Delegate != NULL) { ParentClass = Delegate->GetOwnerClass(); } } } else { ParentClass = DelegateReference.GetMemberParentClass(this); } if ( ParentClass != NULL ) { return FString( TEXT("Shared/") ) + ParentClass->GetName(); } return TEXT(""); }
void FGatherConvertedClassDependencies::DependenciesForHeader() { TArray<UObject*> ObjectsToCheck; GetObjectsWithOuter(OriginalStruct, ObjectsToCheck, true); TArray<UObject*> NeededObjects; FReferenceFinder HeaderReferenceFinder(NeededObjects, nullptr, false, false, true, false); auto ShouldIncludeHeaderFor = [&](UObject* InObj)->bool { if (InObj && (InObj->IsA<UClass>() || InObj->IsA<UEnum>() || InObj->IsA<UScriptStruct>()) && !InObj->HasAnyFlags(RF_ClassDefaultObject)) { auto ObjAsBPGC = Cast<UBlueprintGeneratedClass>(InObj); const bool bWillBeConvetedAsBPGC = ObjAsBPGC && WillClassBeConverted(ObjAsBPGC); const bool bRemainAsUnconvertedBPGC = ObjAsBPGC && !bWillBeConvetedAsBPGC; if (!bRemainAsUnconvertedBPGC && (InObj->GetOutermost() != OriginalStruct->GetOutermost())) { return true; } } return false; }; for (auto Obj : ObjectsToCheck) { const UProperty* Property = Cast<const UProperty>(Obj); if (const UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property)) { Property = ArrayProperty->Inner; } const UProperty* OwnerProperty = IsValid(Property) ? Property->GetOwnerProperty() : nullptr; const bool bIsParam = OwnerProperty && (0 != (OwnerProperty->PropertyFlags & CPF_Parm)) && OwnerProperty->IsIn(OriginalStruct); const bool bIsMemberVariable = OwnerProperty && (OwnerProperty->GetOuter() == OriginalStruct); if (bIsParam || bIsMemberVariable) { if (auto ObjectProperty = Cast<const UObjectPropertyBase>(Property)) { DeclareInHeader.Add(GetFirstNativeOrConvertedClass(ObjectProperty->PropertyClass)); } else if (auto InterfaceProperty = Cast<const UInterfaceProperty>(Property)) { IncludeInHeader.Add(InterfaceProperty->InterfaceClass); } else if (auto DelegateProperty = Cast<const UDelegateProperty>(Property)) { IncludeInHeader.Add(DelegateProperty->SignatureFunction ? DelegateProperty->SignatureFunction->GetOwnerStruct() : nullptr); } /* MC Delegate signatures are recreated in local scope anyway. else if (auto MulticastDelegateProperty = Cast<const UMulticastDelegateProperty>(Property)) { IncludeInHeader.Add(MulticastDelegateProperty->SignatureFunction ? MulticastDelegateProperty->SignatureFunction->GetOwnerClass() : nullptr); } */ else if (const UByteProperty* ByteProperty = Cast<const UByteProperty>(Property)) { // HeaderReferenceFinder.FindReferences(Obj); cannot find this enum.. IncludeInHeader.Add(ByteProperty->Enum); } else { HeaderReferenceFinder.FindReferences(Obj); } } } if (auto SuperStruct = OriginalStruct->GetSuperStruct()) { IncludeInHeader.Add(SuperStruct); } if (auto SourceClass = Cast<UClass>(OriginalStruct)) { for (auto& ImplementedInterface : SourceClass->Interfaces) { IncludeInHeader.Add(ImplementedInterface.Class); } } for (auto Obj : NeededObjects) { if (ShouldIncludeHeaderFor(Obj)) { IncludeInHeader.Add(CastChecked<UField>(Obj)); } } // DEFAULT VALUES FROM UDS: UUserDefinedStruct* UDS = Cast<UUserDefinedStruct>(OriginalStruct); if (UDS) { FStructOnScope StructOnScope(UDS); UDS->InitializeDefaultValue(StructOnScope.GetStructMemory()); for (TFieldIterator<UObjectPropertyBase> PropertyIt(UDS); PropertyIt; ++PropertyIt) { UObject* DefaultValueObject = ((UObjectPropertyBase*)*PropertyIt)->GetObjectPropertyValue_InContainer(StructOnScope.GetStructMemory()); UField* ObjAsField = Cast<UField>(DefaultValueObject); UField* FieldForHeader = ObjAsField ? ObjAsField : (DefaultValueObject ? DefaultValueObject->GetClass() : nullptr); IncludeInHeader.Add(FieldForHeader); } } // REMOVE UNNECESSARY HEADERS UClass* AsBPGC = Cast<UBlueprintGeneratedClass>(OriginalStruct); UClass* OriginalClassFromOriginalPackage = AsBPGC ? FindOriginalClass(AsBPGC) : nullptr; const UPackage* OriginalStructPackage = OriginalStruct ? OriginalStruct->GetOutermost() : nullptr; for (auto Iter = IncludeInHeader.CreateIterator(); Iter; ++Iter) { UField* CurrentField = *Iter; if (CurrentField) { if (CurrentField->GetOutermost() == OriginalStructPackage) { Iter.RemoveCurrent(); } else if (CurrentField == OriginalStruct) { Iter.RemoveCurrent(); } else if (OriginalClassFromOriginalPackage && (CurrentField == OriginalClassFromOriginalPackage)) { Iter.RemoveCurrent(); } } } }
void UCollisionProfile::LoadProfileConfig(bool bForceInit) { /** * This function loads all config data to memory * * 1. First it fixes the meta data for each custom channel name since those meta data is used for #2 * 2. Load Default Profile so that it can be used later * 3. Second it sets up Correct ResponseToChannel for all profiles * 4. It loads profile redirect data **/ // read "EngineTraceChanne" and "GameTraceChanne" and set meta data FConfigSection* Configs = GConfig->GetSectionPrivate( TEXT("/Script/Engine.CollisionProfile"), false, true, GEngineIni ); // before any op, verify if profiles contains invalid name - such as Custom profile name - remove all of them for (auto Iter=Profiles.CreateConstIterator(); Iter; ++Iter) { // make sure it doens't have any if (Iter->Name == CustomCollisionProfileName) { UE_LOG(LogCollisionProfile, Error, TEXT("Profiles contain invalid name : %s is reserved for internal use"), *CustomCollisionProfileName.ToString()); Profiles.RemoveAt(Iter.GetIndex()); } } // 1. First loads all meta data for custom channels // this can be used in #2, so had to fix up first // this is to replace ECollisionChannel's DisplayName to be defined by users FString EngineTraceChannel = TEXT("EngineTraceChannel"); FString GameTraceChannel = TEXT("GameTraceChannel"); // find the enum UEnum* Enum = FindObject<UEnum>(ANY_PACKAGE, TEXT("ECollisionChannel"), true); // we need this Enum check (Enum); UStruct* Struct = FCollisionResponseContainer::StaticStruct(); check (Struct); const FString KeyName = TEXT("DisplayName"); const FString TraceType = TEXT("TraceQuery"); const FString TraceValue = TEXT("1"); const FString HiddenMeta = TEXT("Hidden"); // need to initialize displaynames separate int32 NumEnum = Enum->NumEnums(); ChannelDisplayNames.Empty(NumEnum); ChannelDisplayNames.AddZeroed(NumEnum); TraceTypeMapping.Empty(); ObjectTypeMapping.Empty(); // first go through enum entry, and add suffix to displaynames int32 PrefixLen = FString(TEXT("ECC_")).Len(); // need to have mapping table between ECollisionChannel and EObjectTypeQuery/ETraceTypeQuery UEnum* ObjectTypeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("EObjectTypeQuery"), true); UEnum* TraceTypeEnum = FindObject<UEnum>(ANY_PACKAGE, TEXT("ETraceTypeQuery"), true); check (ObjectTypeEnum && TraceTypeEnum); for ( int32 EnumIndex=0; EnumIndex<NumEnum; ++EnumIndex ) { FString EnumName = Enum->GetEnumName(EnumIndex); EnumName = EnumName.RightChop(PrefixLen); FName DisplayName = FName(*EnumName); if ( IS_VALID_COLLISIONCHANNEL(EnumIndex) ) { // verify if the Struct name matches // this is to avoid situations where they mismatch and causes random bugs UField* Field = FindField<UField>(Struct, DisplayName); if (!Field) { // error - this is bad. This means somebody changed variable name without changing channel enum UE_LOG(LogCollisionProfile, Error, TEXT("Variable (%s) isn't found for Channel (%s). \nPlease make sure you name matches between ECollisionChannel and FCollisionResponseContainer."), *DisplayName.ToString(), *EnumName); } #if WITH_EDITOR // clear displayname since we're setting it in below Enum->RemoveMetaData(*KeyName, EnumIndex); if (Enum->HasMetaData(*HiddenMeta, EnumIndex) == false) { Enum->SetMetaData(*HiddenMeta, NULL, EnumIndex); } #endif } else { // fix up FCollisionQueryFlag AllObjects flag, if trace type=1 ECollisionChannel CollisionChannel = (ECollisionChannel)EnumIndex; // for any engine level collision profile, we hard coded here // meta data doesn't work in cooked build, so we'll have to manually handle them if ((CollisionChannel == ECC_Visibility) || (CollisionChannel == ECC_Camera)) { // remove from object query flags FCollisionQueryFlag::Get().RemoveFromAllObjectsQueryFlag(CollisionChannel); TraceTypeMapping.Add(CollisionChannel); } else if ( CollisionChannel < ECC_OverlapAll_Deprecated ) { ObjectTypeMapping.Add(CollisionChannel); } } ChannelDisplayNames[EnumIndex] = DisplayName; } // Now Load Channel setups, and set display names if customized // also initialize DefaultResposneContainer with default response for each channel FCollisionResponseContainer::DefaultResponseContainer.SetAllChannels(ECR_Block); for (auto Iter=DefaultChannelResponses.CreateConstIterator(); Iter; ++Iter) { const FCustomChannelSetup& CustomChannel = *Iter; int32 EnumIndex = CustomChannel.Channel; // make sure it is the range of channels we allow to change if ( IS_VALID_COLLISIONCHANNEL(EnumIndex) ) { if ( CustomChannel.Name != NAME_None ) { // before you set meta data, you'll have to save this value to modify // ECollisionResponseContainer variables meta data FString VariableName = ChannelDisplayNames[EnumIndex].ToString(); FString DisplayValue = CustomChannel.Name.ToString(); // also has to set this for internal use ChannelDisplayNames[EnumIndex] = FName(*DisplayValue); #if WITH_EDITOR // set displayvalue for this enum entry Enum->SetMetaData(*KeyName, *DisplayValue, EnumIndex); // also need to remove "Hidden" Enum->RemoveMetaData(*HiddenMeta, EnumIndex); #endif // now add MetaData type for trace type if it does if (CustomChannel.bTraceType) { #if WITH_EDITOR // add to enum Enum->SetMetaData(*TraceType, *TraceValue, EnumIndex); #endif // remove from all object queries FCollisionQueryFlag::Get().RemoveFromAllObjectsQueryFlag(CustomChannel.Channel); TraceTypeMapping.Add(CustomChannel.Channel); } // if it has display value else { #if WITH_EDITOR // add to enum Enum->RemoveMetaData(*TraceType, EnumIndex); #endif ObjectTypeMapping.Add(CustomChannel.Channel); if (CustomChannel.bStaticObject) { // add to static object FCollisionQueryFlag::Get().AddToAllStaticObjectsQueryFlag(CustomChannel.Channel); } } #if WITH_EDITOR // now enum is fixed, so find member variable for the field UField* Field = FindField<UField>(Struct, FName(*VariableName)); // I verified up in the class, this can't happen check (Field); Field->SetMetaData(*KeyName, *DisplayValue); #endif } else { // missing name UE_LOG(LogCollisionProfile, Warning, TEXT("Name can't be empty for Channel (%d) "), EnumIndex ); } // allow it to set default response FCollisionResponseContainer::DefaultResponseContainer.SetResponse((ECollisionChannel) EnumIndex, CustomChannel.DefaultResponse); } else { // you can't customize those channels UE_LOG(LogCollisionProfile, Warning, TEXT("Default Setup doesn't allow for predefined engine channels (%d) "), EnumIndex); } } #if WITH_EDITOR // now propagate all changes to the channels to EObjectTypeQuery and ETraceTypeQuery for blueprint accessibility // this code is to show in editor more friendly, so it doesn't have to be set if it's not for editor int32 ObjectTypeEnumIndex = 0; int32 TraceTypeEnumIndex = 0; // first go through fill up ObjectType Enum for ( int32 EnumIndex=0; EnumIndex<NumEnum; ++EnumIndex ) { // if not hidden const FString& Hidden = Enum->GetMetaData(*HiddenMeta, EnumIndex); if ( Hidden.IsEmpty() ) { const FString& DisplayName = Enum->GetMetaData(*KeyName, EnumIndex); if ( !DisplayName.IsEmpty() ) { // find out trace type or object type if (Enum->GetMetaData(*TraceType, EnumIndex) == TraceValue) { TraceTypeEnum->RemoveMetaData(*HiddenMeta, TraceTypeEnumIndex); TraceTypeEnum->SetMetaData(*KeyName, *DisplayName, TraceTypeEnumIndex); ++TraceTypeEnumIndex; } else { ObjectTypeEnum->RemoveMetaData(*HiddenMeta, ObjectTypeEnumIndex); ObjectTypeEnum->SetMetaData(*KeyName, *DisplayName, ObjectTypeEnumIndex); ++ObjectTypeEnumIndex; } } } } // make sure TraceTypeEnumIndex matches TraceTypeMapping check (TraceTypeMapping.Num() == TraceTypeEnumIndex); check (ObjectTypeMapping.Num() == ObjectTypeEnumIndex); #endif // collision redirector has to be loaded before profile CollisionChannelRedirectsMap.Empty(); for(auto Iter = CollisionChannelRedirects.CreateConstIterator(); Iter; ++Iter) { FName OldName = Iter->OldName; FName NewName = Iter->NewName; // at least we need to have OldName if(OldName!= NAME_None && NewName != NAME_None) { // add to pair CollisionChannelRedirectsMap.Add(OldName, NewName); } else { // print error UE_LOG(LogCollisionProfile, Warning, TEXT("CollisionChannel Redirects : Name Can't be none (%s: %s)"), *OldName.ToString(), *NewName.ToString()); } } // 2. Second loads all set up back to ResponseToChannels // this does a lot of iteration, but this only happens once loaded, so it's better to be convenient than efficient // fill up Profiles data FillProfileData(Profiles, Enum, KeyName, EditProfiles); // 3. It loads redirect data - now time to load profile redirect ProfileRedirectsMap.Empty(); // handle profile redirect here for(auto Iter = ProfileRedirects.CreateConstIterator(); Iter; ++Iter) { FName OldName = Iter->OldName; FName NewName = Iter->NewName; // at least we need to have OldName if(OldName!= NAME_None && NewName != NAME_None) { FCollisionResponseTemplate Template; // make sure the template exists if(FindProfileData(Profiles, NewName, Template)) { // add to pair ProfileRedirectsMap.Add(OldName, NewName); } else { // print error UE_LOG(LogCollisionProfile, Warning, TEXT("ProfileRedirect (%s : %s) - New Name (\'%s\') isn't found "), *OldName.ToString(), *NewName.ToString(), *NewName.ToString()); } } } #if WITH_EDITOR if (bForceInit) { // go through objects, and see if we can reinitialize profile for(TObjectIterator<UPrimitiveComponent> PrimIt; PrimIt; ++PrimIt) { PrimIt->UpdateCollisionProfile(); } } #endif }
void FKismetBytecodeDisassembler::ProcessCommon(int32& ScriptIndex, EExprToken Opcode) { switch (Opcode) { case EX_PrimitiveCast: { // A type conversion. uint8 ConversionType = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: PrimitiveCast of type %d"), *Indents, (int32)Opcode, ConversionType); AddIndent(); Ar.Logf(TEXT("%s Argument:"), *Indents); ProcessCastByte(ConversionType, ScriptIndex); //@TODO: //Ar.Logf(TEXT("%s Expression:"), *Indents); //SerializeExpr( ScriptIndex ); break; } case EX_ObjToInterfaceCast: { // A conversion from an object variable to a native interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: ObjToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_CrossInterfaceCast: { // A conversion from one interface variable to a different interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: InterfaceToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_InterfaceToObjCast: { // A conversion from an interface variable to a object variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* ObjectClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: InterfaceToObjCast to %s"), *Indents, (int32)Opcode, *ObjectClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_Let: { Ar.Logf(TEXT("%s $%X: Let (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetObj: case EX_LetWeakObjPtr: { if( Opcode == EX_LetObj ) { Ar.Logf(TEXT("%s $%X: Let Obj (Variable = Expression)"), *Indents, (int32)Opcode); } else { Ar.Logf(TEXT("%s $%X: Let WeakObjPtr (Variable = Expression)"), *Indents, (int32)Opcode); } AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetBool: { Ar.Logf(TEXT("%s $%X: LetBool (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case Ex_LetValueOnPersistentFrame: { Ar.Logf(TEXT("%s $%X: LetValueOnPersistentFrame"), *Indents, (int32)Opcode); AddIndent(); auto Prop = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s Destination variable: %s, offset: %d"), *Indents, *GetNameSafe(Prop), Prop ? Prop->GetOffset_ForDebug() : 0); Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr(ScriptIndex); DropIndent(); break; } case EX_StructMemberContext: { Ar.Logf(TEXT("%s $%X: Struct member context "), *Indents, (int32)Opcode); AddIndent(); UProperty* Prop = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s Expression within struct %s, offset %d"), *Indents, *(Prop->GetName()), Prop->GetOffset_ForDebug()); // although that isn't a UFunction, we are not going to indirect the props of a struct, so this should be fine Ar.Logf(TEXT("%s Expression to struct:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetDelegate: { Ar.Logf(TEXT("%s $%X: LetDelegate (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetMulticastDelegate: { Ar.Logf(TEXT("%s $%X: LetMulticastDelegate (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_ComputedJump: { Ar.Logf(TEXT("%s $%X: Computed Jump, offset specified by expression:"), *Indents, (int32)Opcode); AddIndent(); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_Jump: { CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X"), *Indents, (int32)Opcode, SkipCount); break; } case EX_LocalVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Local variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_InstanceVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Instance variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_LocalOutVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Local out variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_InterfaceContext: { Ar.Logf(TEXT("%s $%X: EX_InterfaceContext:"), *Indents, (int32)Opcode); SerializeExpr(ScriptIndex); break; } case EX_DeprecatedOp4A: { Ar.Logf(TEXT("%s $%X: This opcode has been removed and does nothing."), *Indents, (int32)Opcode); break; } case EX_Nothing: { Ar.Logf(TEXT("%s $%X: EX_Nothing"), *Indents, (int32)Opcode); break; } case EX_EndOfScript: { Ar.Logf(TEXT("%s $%X: EX_EndOfScript"), *Indents, (int32)Opcode); break; } case EX_EndFunctionParms: { Ar.Logf(TEXT("%s $%X: EX_EndFunctionParms"), *Indents, (int32)Opcode); break; } case EX_EndStructConst: { Ar.Logf(TEXT("%s $%X: EX_EndStructConst"), *Indents, (int32)Opcode); break; } case EX_EndArray: { Ar.Logf(TEXT("%s $%X: EX_EndArray"), *Indents, (int32)Opcode); break; } case EX_IntZero: { Ar.Logf(TEXT("%s $%X: EX_IntZero"), *Indents, (int32)Opcode); break; } case EX_IntOne: { Ar.Logf(TEXT("%s $%X: EX_IntOne"), *Indents, (int32)Opcode); break; } case EX_True: { Ar.Logf(TEXT("%s $%X: EX_True"), *Indents, (int32)Opcode); break; } case EX_False: { Ar.Logf(TEXT("%s $%X: EX_False"), *Indents, (int32)Opcode); break; } case EX_NoObject: { Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode); break; } case EX_NoInterface: { Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode); break; } case EX_Self: { Ar.Logf(TEXT("%s $%X: EX_Self"), *Indents, (int32)Opcode); break; } case EX_EndParmValue: { Ar.Logf(TEXT("%s $%X: EX_EndParmValue"), *Indents, (int32)Opcode); break; } case EX_Return: { Ar.Logf(TEXT("%s $%X: Return expression"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); // Return expression. break; } case EX_FinalFunction: { UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Final Function (stack node %s::%s)"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)")); while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms) { // Params } break; } case EX_CallMulticastDelegate: { UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex); Ar.Logf(TEXT("%s $%X: CallMulticastDelegate (signature %s::%s) delegate:"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)")); SerializeExpr( ScriptIndex ); Ar.Logf(TEXT("Params:")); while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms) { // Params } break; } case EX_VirtualFunction: { FString FunctionName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: Virtual Function named %s"), *Indents, (int32)Opcode, *FunctionName); while (SerializeExpr(ScriptIndex) != EX_EndFunctionParms) { } break; } case EX_Context: case EX_Context_FailSilent: { Ar.Logf(TEXT("%s $%X: %s"), *Indents, (int32)Opcode, TEXT("Context")); AddIndent(); // Object expression. Ar.Logf(TEXT("%s ObjectExpression:"), *Indents); SerializeExpr( ScriptIndex ); if (Opcode == EX_Context_FailSilent) { Ar.Logf(TEXT(" Can fail silently on access none ")); } // Code offset for NULL expressions. CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s Skip Bytes: 0x%X"), *Indents, SkipCount); // Property corresponding to the r-value data, in case the l-value needs to be mem-zero'd UField* Field = ReadPointer<UField>(ScriptIndex); Ar.Logf(TEXT("%s R-Value Property: %s"), *Indents, Field ? *Field->GetName() : TEXT("(null)")); // Property type, in case the r-value is a non-property such as dynamic array length uint8 PropType = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s PropertyTypeIfNeeded: %d"), *Indents, PropType); // Context expression. Ar.Logf(TEXT("%s ContextExpression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_IntConst: { int32 ConstValue = ReadINT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal int32 %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_SkipOffsetConst: { CodeSkipSizeType ConstValue = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal CodeSkipSizeType 0x%X"), *Indents, (int32)Opcode, ConstValue); break; } case EX_FloatConst: { float ConstValue = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal float %f"), *Indents, (int32)Opcode, ConstValue); break; } case EX_StringConst: { FString ConstValue = ReadString8(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal ansi string \"%s\""), *Indents, (int32)Opcode, *ConstValue); break; } case EX_UnicodeStringConst: { FString ConstValue = ReadString16(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal unicode string \"%s\""), *Indents, (int32)Opcode, *ConstValue); break; } case EX_TextConst: { Ar.Logf(TEXT("%s $%X: literal text"), *Indents, (int32)Opcode); break; } case EX_ObjectConst: { UObject* Pointer = ReadPointer<UObject>(ScriptIndex); Ar.Logf(TEXT("%s $%X: EX_ObjectConst (%p:%s)"), *Indents, (int32)Opcode, Pointer, *Pointer->GetFullName()); break; } case EX_NameConst: { FString ConstValue = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal name %s"), *Indents, (int32)Opcode, *ConstValue); break; } case EX_RotationConst: { float Pitch = ReadFLOAT(ScriptIndex); float Yaw = ReadFLOAT(ScriptIndex); float Roll = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal rotation (%f,%f,%f)"), *Indents, (int32)Opcode, Pitch, Yaw, Roll); break; } case EX_VectorConst: { float X = ReadFLOAT(ScriptIndex); float Y = ReadFLOAT(ScriptIndex); float Z = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal vector (%f,%f,%f)"), *Indents, (int32)Opcode, X, Y, Z); break; } case EX_TransformConst: { float RotX = ReadFLOAT(ScriptIndex); float RotY = ReadFLOAT(ScriptIndex); float RotZ = ReadFLOAT(ScriptIndex); float RotW = ReadFLOAT(ScriptIndex); float TransX = ReadFLOAT(ScriptIndex); float TransY = ReadFLOAT(ScriptIndex); float TransZ = ReadFLOAT(ScriptIndex); float ScaleX = ReadFLOAT(ScriptIndex); float ScaleY = ReadFLOAT(ScriptIndex); float ScaleZ = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal transform R(%f,%f,%f,%f) T(%f,%f,%f) S(%f,%f,%f)"), *Indents, (int32)Opcode, TransX, TransY, TransZ, RotX, RotY, RotZ, RotW, ScaleX, ScaleY, ScaleZ); break; } case EX_StructConst: { UScriptStruct* Struct = ReadPointer<UScriptStruct>(ScriptIndex); int32 SerializedSize = ReadINT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal struct %s (serialized size: %d)"), *Indents, (int32)Opcode, *Struct->GetName(), SerializedSize); while( SerializeExpr(ScriptIndex) != EX_EndStructConst ) { // struct contents } break; } case EX_SetArray: { Ar.Logf(TEXT("%s $%X: set array"), *Indents, (int32)Opcode); SerializeExpr(ScriptIndex); while( SerializeExpr(ScriptIndex) != EX_EndArray) { // Array contents } break; } case EX_ByteConst: { uint8 ConstValue = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal byte %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_IntConstByte: { int32 ConstValue = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal int %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_MetaCast: { UClass* Class = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: MetaCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_DynamicCast: { UClass* Class = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: DynamicCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_JumpIfNot: { // Code offset. CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X if not expr:"), *Indents, (int32)Opcode, SkipCount); // Boolean expr. SerializeExpr( ScriptIndex ); break; } case EX_Assert: { uint16 LineNumber = ReadWORD(ScriptIndex); uint8 InDebugMode = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: assert at line %d, in debug mode = %d with expr:"), *Indents, (int32)Opcode, LineNumber, InDebugMode); SerializeExpr( ScriptIndex ); // Assert expr. break; } case EX_Skip: { CodeSkipSizeType W = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: possibly skip 0x%X bytes of expr:"), *Indents, (int32)Opcode, W); // Expression to possibly skip. SerializeExpr( ScriptIndex ); break; } case EX_InstanceDelegate: { // the name of the function assigned to the delegate. FString FuncName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: instance delegate function named %s"), *Indents, (int32)Opcode, *FuncName); break; } case EX_AddMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Add MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); SerializeExpr( ScriptIndex ); break; } case EX_RemoveMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Remove MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); SerializeExpr( ScriptIndex ); break; } case EX_ClearMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Clear MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); break; } case EX_BindDelegate: { // the name of the function assigned to the delegate. FString FuncName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: BindDelegate '%s' "), *Indents, (int32)Opcode, *FuncName); Ar.Logf(TEXT("%s Delegate:"), *Indents); SerializeExpr( ScriptIndex ); Ar.Logf(TEXT("%s Object:"), *Indents); SerializeExpr( ScriptIndex ); break; } case EX_PushExecutionFlow: { CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: FlowStack.Push(0x%X);"), *Indents, (int32)Opcode, SkipCount); break; } case EX_PopExecutionFlow: { Ar.Logf(TEXT("%s $%X: if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! }"), *Indents, (int32)Opcode); break; } case EX_PopExecutionFlowIfNot: { Ar.Logf(TEXT("%s $%X: if (!condition) { if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! } }"), *Indents, (int32)Opcode); // Boolean expr. SerializeExpr( ScriptIndex ); break; } case EX_Breakpoint: { Ar.Logf(TEXT("%s $%X: <<< BREAKPOINT >>>"), *Indents, (int32)Opcode); break; } case EX_WireTracepoint: { Ar.Logf(TEXT("%s $%X: .. wire debug site .."), *Indents, (int32)Opcode); break; } case EX_Tracepoint: { Ar.Logf(TEXT("%s $%X: .. debug site .."), *Indents, (int32)Opcode); break; } default: { // This should never occur. UE_LOG(LogScriptDisassembler, Warning, TEXT("Unknown bytecode 0x%02X; ignoring it"), (uint8)Opcode ); break; } } }
void FKismetBytecodeDisassembler::ProcessCommon(int32& ScriptIndex, EExprToken Opcode) { switch (Opcode) { case EX_PrimitiveCast: { // A type conversion. uint8 ConversionType = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: PrimitiveCast of type %d"), *Indents, (int32)Opcode, ConversionType); AddIndent(); Ar.Logf(TEXT("%s Argument:"), *Indents); ProcessCastByte(ConversionType, ScriptIndex); //@TODO: //Ar.Logf(TEXT("%s Expression:"), *Indents); //SerializeExpr( ScriptIndex ); break; } case EX_ObjToInterfaceCast: { // A conversion from an object variable to a native interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: ObjToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_CrossInterfaceCast: { // A conversion from one interface variable to a different interface variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* InterfaceClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: InterfaceToInterfaceCast to %s"), *Indents, (int32)Opcode, *InterfaceClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_InterfaceToObjCast: { // A conversion from an interface variable to a object variable. // We use a different bytecode to avoid the branching each time we process a cast token // the interface class to convert to UClass* ObjectClass = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: InterfaceToObjCast to %s"), *Indents, (int32)Opcode, *ObjectClass->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_Let: { Ar.Logf(TEXT("%s $%X: Let (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); ReadPointer<UProperty>(ScriptIndex); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetObj: case EX_LetWeakObjPtr: { if( Opcode == EX_LetObj ) { Ar.Logf(TEXT("%s $%X: Let Obj (Variable = Expression)"), *Indents, (int32)Opcode); } else { Ar.Logf(TEXT("%s $%X: Let WeakObjPtr (Variable = Expression)"), *Indents, (int32)Opcode); } AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetBool: { Ar.Logf(TEXT("%s $%X: LetBool (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetValueOnPersistentFrame: { Ar.Logf(TEXT("%s $%X: LetValueOnPersistentFrame"), *Indents, (int32)Opcode); AddIndent(); auto Prop = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s Destination variable: %s, offset: %d"), *Indents, *GetNameSafe(Prop), Prop ? Prop->GetOffset_ForDebug() : 0); Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr(ScriptIndex); DropIndent(); break; } case EX_StructMemberContext: { Ar.Logf(TEXT("%s $%X: Struct member context "), *Indents, (int32)Opcode); AddIndent(); UProperty* Prop = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s Expression within struct %s, offset %d"), *Indents, *(Prop->GetName()), Prop->GetOffset_ForDebug()); // although that isn't a UFunction, we are not going to indirect the props of a struct, so this should be fine Ar.Logf(TEXT("%s Expression to struct:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetDelegate: { Ar.Logf(TEXT("%s $%X: LetDelegate (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_LetMulticastDelegate: { Ar.Logf(TEXT("%s $%X: LetMulticastDelegate (Variable = Expression)"), *Indents, (int32)Opcode); AddIndent(); // Variable expr. Ar.Logf(TEXT("%s Variable:"), *Indents); SerializeExpr( ScriptIndex ); // Assignment expr. Ar.Logf(TEXT("%s Expression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_ComputedJump: { Ar.Logf(TEXT("%s $%X: Computed Jump, offset specified by expression:"), *Indents, (int32)Opcode); AddIndent(); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_Jump: { CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X"), *Indents, (int32)Opcode, SkipCount); break; } case EX_LocalVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Local variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_DefaultVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Default variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_InstanceVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Instance variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_LocalOutVariable: { UProperty* PropertyPtr = ReadPointer<UProperty>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Local out variable named %s"), *Indents, (int32)Opcode, PropertyPtr ? *PropertyPtr->GetName() : TEXT("(null)")); break; } case EX_InterfaceContext: { Ar.Logf(TEXT("%s $%X: EX_InterfaceContext:"), *Indents, (int32)Opcode); SerializeExpr(ScriptIndex); break; } case EX_DeprecatedOp4A: { Ar.Logf(TEXT("%s $%X: This opcode has been removed and does nothing."), *Indents, (int32)Opcode); break; } case EX_Nothing: { Ar.Logf(TEXT("%s $%X: EX_Nothing"), *Indents, (int32)Opcode); break; } case EX_EndOfScript: { Ar.Logf(TEXT("%s $%X: EX_EndOfScript"), *Indents, (int32)Opcode); break; } case EX_EndFunctionParms: { Ar.Logf(TEXT("%s $%X: EX_EndFunctionParms"), *Indents, (int32)Opcode); break; } case EX_EndStructConst: { Ar.Logf(TEXT("%s $%X: EX_EndStructConst"), *Indents, (int32)Opcode); break; } case EX_EndArray: { Ar.Logf(TEXT("%s $%X: EX_EndArray"), *Indents, (int32)Opcode); break; } case EX_EndArrayConst: { Ar.Logf(TEXT("%s $%X: EX_EndArrayConst"), *Indents, (int32)Opcode); break; } case EX_IntZero: { Ar.Logf(TEXT("%s $%X: EX_IntZero"), *Indents, (int32)Opcode); break; } case EX_IntOne: { Ar.Logf(TEXT("%s $%X: EX_IntOne"), *Indents, (int32)Opcode); break; } case EX_True: { Ar.Logf(TEXT("%s $%X: EX_True"), *Indents, (int32)Opcode); break; } case EX_False: { Ar.Logf(TEXT("%s $%X: EX_False"), *Indents, (int32)Opcode); break; } case EX_NoObject: { Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode); break; } case EX_NoInterface: { Ar.Logf(TEXT("%s $%X: EX_NoObject"), *Indents, (int32)Opcode); break; } case EX_Self: { Ar.Logf(TEXT("%s $%X: EX_Self"), *Indents, (int32)Opcode); break; } case EX_EndParmValue: { Ar.Logf(TEXT("%s $%X: EX_EndParmValue"), *Indents, (int32)Opcode); break; } case EX_Return: { Ar.Logf(TEXT("%s $%X: Return expression"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); // Return expression. break; } case EX_CallMath: { UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Call Math (stack node %s::%s)"), *Indents, (int32)Opcode, *GetNameSafe(StackNode ? StackNode->GetOuter() : nullptr), *GetNameSafe(StackNode)); while (SerializeExpr(ScriptIndex) != EX_EndFunctionParms) { // Params } break; } case EX_FinalFunction: { UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex); Ar.Logf(TEXT("%s $%X: Final Function (stack node %s::%s)"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)")); while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms) { // Params } break; } case EX_CallMulticastDelegate: { UStruct* StackNode = ReadPointer<UStruct>(ScriptIndex); Ar.Logf(TEXT("%s $%X: CallMulticastDelegate (signature %s::%s) delegate:"), *Indents, (int32)Opcode, StackNode ? *StackNode->GetOuter()->GetName() : TEXT("(null)"), StackNode ? *StackNode->GetName() : TEXT("(null)")); SerializeExpr( ScriptIndex ); Ar.Logf(TEXT("Params:")); while (SerializeExpr( ScriptIndex ) != EX_EndFunctionParms) { // Params } break; } case EX_VirtualFunction: { FString FunctionName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: Virtual Function named %s"), *Indents, (int32)Opcode, *FunctionName); while (SerializeExpr(ScriptIndex) != EX_EndFunctionParms) { } break; } case EX_ClassContext: case EX_Context: case EX_Context_FailSilent: { Ar.Logf(TEXT("%s $%X: %s"), *Indents, (int32)Opcode, Opcode == EX_ClassContext ? TEXT("Class Context") : TEXT("Context")); AddIndent(); // Object expression. Ar.Logf(TEXT("%s ObjectExpression:"), *Indents); SerializeExpr( ScriptIndex ); if (Opcode == EX_Context_FailSilent) { Ar.Logf(TEXT(" Can fail silently on access none ")); } // Code offset for NULL expressions. CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s Skip Bytes: 0x%X"), *Indents, SkipCount); // Property corresponding to the r-value data, in case the l-value needs to be mem-zero'd UField* Field = ReadPointer<UField>(ScriptIndex); Ar.Logf(TEXT("%s R-Value Property: %s"), *Indents, Field ? *Field->GetName() : TEXT("(null)")); // Context expression. Ar.Logf(TEXT("%s ContextExpression:"), *Indents); SerializeExpr( ScriptIndex ); DropIndent(); break; } case EX_IntConst: { int32 ConstValue = ReadINT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal int32 %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_SkipOffsetConst: { CodeSkipSizeType ConstValue = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal CodeSkipSizeType 0x%X"), *Indents, (int32)Opcode, ConstValue); break; } case EX_FloatConst: { float ConstValue = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal float %f"), *Indents, (int32)Opcode, ConstValue); break; } case EX_StringConst: { FString ConstValue = ReadString8(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal ansi string \"%s\""), *Indents, (int32)Opcode, *ConstValue); break; } case EX_UnicodeStringConst: { FString ConstValue = ReadString16(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal unicode string \"%s\""), *Indents, (int32)Opcode, *ConstValue); break; } case EX_TextConst: { // What kind of text are we dealing with? const EBlueprintTextLiteralType TextLiteralType = (EBlueprintTextLiteralType)Script[ScriptIndex++]; switch (TextLiteralType) { case EBlueprintTextLiteralType::Empty: { Ar.Logf(TEXT("%s $%X: literal text - empty"), *Indents, (int32)Opcode); } break; case EBlueprintTextLiteralType::LocalizedText: { const FString SourceString = ReadString(ScriptIndex); const FString KeyString = ReadString(ScriptIndex); const FString Namespace = ReadString(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal text - localized text { namespace: \"%s\", key: \"%s\", source: \"%s\" }"), *Indents, (int32)Opcode, *Namespace, *KeyString, *SourceString); } break; case EBlueprintTextLiteralType::InvariantText: { const FString SourceString = ReadString(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal text - invariant text: \"%s\""), *Indents, (int32)Opcode, *SourceString); } break; case EBlueprintTextLiteralType::LiteralString: { const FString SourceString = ReadString(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal text - literal string: \"%s\""), *Indents, (int32)Opcode, *SourceString); } break; default: checkf(false, TEXT("Unknown EBlueprintTextLiteralType! Please update FKismetBytecodeDisassembler::ProcessCommon to handle this type of text.")); break; } break; } case EX_ObjectConst: { UObject* Pointer = ReadPointer<UObject>(ScriptIndex); Ar.Logf(TEXT("%s $%X: EX_ObjectConst (%p:%s)"), *Indents, (int32)Opcode, Pointer, *Pointer->GetFullName()); break; } case EX_AssetConst: { Ar.Logf(TEXT("%s $%X: EX_AssetConst"), *Indents, (int32)Opcode); SerializeExpr(ScriptIndex); break; } case EX_NameConst: { FString ConstValue = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal name %s"), *Indents, (int32)Opcode, *ConstValue); break; } case EX_RotationConst: { float Pitch = ReadFLOAT(ScriptIndex); float Yaw = ReadFLOAT(ScriptIndex); float Roll = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal rotation (%f,%f,%f)"), *Indents, (int32)Opcode, Pitch, Yaw, Roll); break; } case EX_VectorConst: { float X = ReadFLOAT(ScriptIndex); float Y = ReadFLOAT(ScriptIndex); float Z = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal vector (%f,%f,%f)"), *Indents, (int32)Opcode, X, Y, Z); break; } case EX_TransformConst: { float RotX = ReadFLOAT(ScriptIndex); float RotY = ReadFLOAT(ScriptIndex); float RotZ = ReadFLOAT(ScriptIndex); float RotW = ReadFLOAT(ScriptIndex); float TransX = ReadFLOAT(ScriptIndex); float TransY = ReadFLOAT(ScriptIndex); float TransZ = ReadFLOAT(ScriptIndex); float ScaleX = ReadFLOAT(ScriptIndex); float ScaleY = ReadFLOAT(ScriptIndex); float ScaleZ = ReadFLOAT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal transform R(%f,%f,%f,%f) T(%f,%f,%f) S(%f,%f,%f)"), *Indents, (int32)Opcode, TransX, TransY, TransZ, RotX, RotY, RotZ, RotW, ScaleX, ScaleY, ScaleZ); break; } case EX_StructConst: { UScriptStruct* Struct = ReadPointer<UScriptStruct>(ScriptIndex); int32 SerializedSize = ReadINT(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal struct %s (serialized size: %d)"), *Indents, (int32)Opcode, *Struct->GetName(), SerializedSize); while( SerializeExpr(ScriptIndex) != EX_EndStructConst ) { // struct contents } break; } case EX_SetArray: { Ar.Logf(TEXT("%s $%X: set array"), *Indents, (int32)Opcode); SerializeExpr(ScriptIndex); while( SerializeExpr(ScriptIndex) != EX_EndArray) { // Array contents } break; } case EX_ArrayConst: { UProperty* InnerProp = ReadPointer<UProperty>(ScriptIndex); int32 Num = ReadINT(ScriptIndex); Ar.Logf(TEXT("%s $%X: set array const - elements number: %d, inner property: %s"), *Indents, (int32)Opcode, Num, *GetNameSafe(InnerProp)); while (SerializeExpr(ScriptIndex) != EX_EndArrayConst) { // Array contents } break; } case EX_ByteConst: { uint8 ConstValue = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal byte %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_IntConstByte: { int32 ConstValue = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: literal int %d"), *Indents, (int32)Opcode, ConstValue); break; } case EX_MetaCast: { UClass* Class = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: MetaCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_DynamicCast: { UClass* Class = ReadPointer<UClass>(ScriptIndex); Ar.Logf(TEXT("%s $%X: DynamicCast to %s of expr:"), *Indents, (int32)Opcode, *Class->GetName()); SerializeExpr( ScriptIndex ); break; } case EX_JumpIfNot: { // Code offset. CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: Jump to offset 0x%X if not expr:"), *Indents, (int32)Opcode, SkipCount); // Boolean expr. SerializeExpr( ScriptIndex ); break; } case EX_Assert: { uint16 LineNumber = ReadWORD(ScriptIndex); uint8 InDebugMode = ReadBYTE(ScriptIndex); Ar.Logf(TEXT("%s $%X: assert at line %d, in debug mode = %d with expr:"), *Indents, (int32)Opcode, LineNumber, InDebugMode); SerializeExpr( ScriptIndex ); // Assert expr. break; } case EX_Skip: { CodeSkipSizeType W = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: possibly skip 0x%X bytes of expr:"), *Indents, (int32)Opcode, W); // Expression to possibly skip. SerializeExpr( ScriptIndex ); break; } case EX_InstanceDelegate: { // the name of the function assigned to the delegate. FString FuncName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: instance delegate function named %s"), *Indents, (int32)Opcode, *FuncName); break; } case EX_AddMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Add MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); SerializeExpr( ScriptIndex ); break; } case EX_RemoveMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Remove MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); SerializeExpr( ScriptIndex ); break; } case EX_ClearMulticastDelegate: { Ar.Logf(TEXT("%s $%X: Clear MC delegate"), *Indents, (int32)Opcode); SerializeExpr( ScriptIndex ); break; } case EX_BindDelegate: { // the name of the function assigned to the delegate. FString FuncName = ReadName(ScriptIndex); Ar.Logf(TEXT("%s $%X: BindDelegate '%s' "), *Indents, (int32)Opcode, *FuncName); Ar.Logf(TEXT("%s Delegate:"), *Indents); SerializeExpr( ScriptIndex ); Ar.Logf(TEXT("%s Object:"), *Indents); SerializeExpr( ScriptIndex ); break; } case EX_PushExecutionFlow: { CodeSkipSizeType SkipCount = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: FlowStack.Push(0x%X);"), *Indents, (int32)Opcode, SkipCount); break; } case EX_PopExecutionFlow: { Ar.Logf(TEXT("%s $%X: if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! }"), *Indents, (int32)Opcode); break; } case EX_PopExecutionFlowIfNot: { Ar.Logf(TEXT("%s $%X: if (!condition) { if (FlowStack.Num()) { jump to statement at FlowStack.Pop(); } else { ERROR!!! } }"), *Indents, (int32)Opcode); // Boolean expr. SerializeExpr( ScriptIndex ); break; } case EX_Breakpoint: { Ar.Logf(TEXT("%s $%X: <<< BREAKPOINT >>>"), *Indents, (int32)Opcode); break; } case EX_WireTracepoint: { Ar.Logf(TEXT("%s $%X: .. wire debug site .."), *Indents, (int32)Opcode); break; } case EX_InstrumentationEvent: { const uint8 EventType = ReadBYTE(ScriptIndex); switch (EventType) { case EScriptInstrumentation::InlineEvent: Ar.Logf(TEXT("%s $%X: .. instrumented inline event .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::Stop: Ar.Logf(TEXT("%s $%X: .. instrumented event stop .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::PureNodeEntry: Ar.Logf(TEXT("%s $%X: .. instrumented pure node entry site .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::NodeDebugSite: Ar.Logf(TEXT("%s $%X: .. instrumented debug site .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::NodeEntry: Ar.Logf(TEXT("%s $%X: .. instrumented wire entry site .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::NodeExit: Ar.Logf(TEXT("%s $%X: .. instrumented wire exit site .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::PushState: Ar.Logf(TEXT("%s $%X: .. push execution state .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::RestoreState: Ar.Logf(TEXT("%s $%X: .. restore execution state .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::ResetState: Ar.Logf(TEXT("%s $%X: .. reset execution state .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::SuspendState: Ar.Logf(TEXT("%s $%X: .. suspend execution state .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::PopState: Ar.Logf(TEXT("%s $%X: .. pop execution state .."), *Indents, (int32)Opcode); break; case EScriptInstrumentation::TunnelEndOfThread: Ar.Logf(TEXT("%s $%X: .. tunnel end of thread .."), *Indents, (int32)Opcode); break; } break; } case EX_Tracepoint: { Ar.Logf(TEXT("%s $%X: .. debug site .."), *Indents, (int32)Opcode); break; } case EX_SwitchValue: { const auto NumCases = ReadWORD(ScriptIndex); const auto AfterSkip = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s $%X: Switch Value %d cases, end in 0x%X"), *Indents, (int32)Opcode, NumCases, AfterSkip); AddIndent(); Ar.Logf(TEXT("%s Index:"), *Indents); SerializeExpr(ScriptIndex); for (uint16 CaseIndex = 0; CaseIndex < NumCases; ++CaseIndex) { Ar.Logf(TEXT("%s [%d] Case Index (label: 0x%X):"), *Indents, CaseIndex, ScriptIndex); SerializeExpr(ScriptIndex); // case index value term const auto OffsetToNextCase = ReadSkipCount(ScriptIndex); Ar.Logf(TEXT("%s [%d] Offset to the next case: 0x%X"), *Indents, CaseIndex, OffsetToNextCase); Ar.Logf(TEXT("%s [%d] Case Result:"), *Indents, CaseIndex); SerializeExpr(ScriptIndex); // case term } Ar.Logf(TEXT("%s Default result (label: 0x%X):"), *Indents, ScriptIndex); SerializeExpr(ScriptIndex); Ar.Logf(TEXT("%s (label: 0x%X)"), *Indents, ScriptIndex); DropIndent(); break; } case EX_ArrayGetByRef: { Ar.Logf(TEXT("%s $%X: Array Get-by-Ref Index"), *Indents, (int32)Opcode); AddIndent(); SerializeExpr(ScriptIndex); SerializeExpr(ScriptIndex); DropIndent(); break; } default: { // This should never occur. UE_LOG(LogScriptDisassembler, Warning, TEXT("Unknown bytecode 0x%02X; ignoring it"), (uint8)Opcode ); break; } } }