void UObjectPropertyBase::ExportTextItem( FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope ) const
{
	UObject* Temp = GetObjectPropertyValue(PropertyValue);
	if( Temp != NULL )
	{
		if (PortFlags & PPF_DebugDump)
		{
			ValueStr += Temp->GetFullName();
		}
		else if (Parent && !Parent->HasAnyFlags(RF_ClassDefaultObject) && Temp->IsDefaultSubobject())
		{
			if ((PortFlags & PPF_Delimited) && (!Temp->GetFName().IsValidXName(INVALID_OBJECTNAME_CHARACTERS)))
			{
				ValueStr += FString::Printf(TEXT("\"%s\""), *Temp->GetName().ReplaceQuotesWithEscapedQuotes());
			}
			else
			{
				ValueStr += Temp->GetName();
			}
		}
		else
		{
			ValueStr += GetExportPath(Temp, Parent, ExportRootScope, PortFlags);
		}
	}
	else
	{
		ValueStr += TEXT("None");
	}
}
Example #2
0
FText SGraphPinObject::GetObjectName() const
{
	FText Value = FText::GetEmpty();
	
	if (GraphPinObj != NULL)
	{
		UObject* DefaultObject = GraphPinObj->DefaultObject;
		if (DefaultObject != NULL)
		{
			Value = FText::FromString(DefaultObject->GetName());
			int32 StringLen = Value.ToString().Len();

			//If string is too long, then truncate (eg. "abcdefgijklmnopq" is converted as "abcd...nopq")
			const int32 MaxAllowedLength = 16;
			if (StringLen > MaxAllowedLength)
			{
				//Take first 4 characters
				FString TruncatedStr(Value.ToString().Left(4));
				TruncatedStr += FString( TEXT("..."));
				
				//Take last 4 characters
				TruncatedStr += Value.ToString().Right(4);
				Value = FText::FromString(TruncatedStr);
			}
		}
	}
	return Value;
}
Example #3
0
UObject* UObject::FindObject ( wchar_t* ObjectName )
{
	for ( int i = 0; i < UObject::GObjObjects()->Count; ++i )
	{
		UObject *pObject = GObjObjects()->Data[ i ];

		if ( pObject == NULL )
			continue;

		if( pObject->GetName().compare( ObjectName ) == 0 )
			return pObject;

		wstring FullName = pObject->GetFullName();

		if( FullName.length() )
		{
			if ( FullName.compare( ObjectName ) == 0 )
			{
				return pObject;
			}
		}
	}

	return NULL;
}
void UObjectPropertyBase::ExportTextItem( FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope ) const
{
	UObject* Temp = GetObjectPropertyValue(PropertyValue);

	if (0 != (PortFlags & PPF_ExportCpp))
	{
		FString::Printf(TEXT("%s%s*"), PropertyClass->GetPrefixCPP(), *PropertyClass->GetName());

		ValueStr += Temp
			? FString::Printf(TEXT("LoadObject<%s%s>(nullptr, TEXT(\"%s\"))")
				, PropertyClass->GetPrefixCPP()
				, *PropertyClass->GetName()
				, *(Temp->GetPathName().ReplaceCharWithEscapedChar()))
			: TEXT("nullptr");
		return;
	}

	if( Temp != NULL )
	{
		if (PortFlags & PPF_DebugDump)
		{
			ValueStr += Temp->GetFullName();
		}
		else if (Parent && !Parent->HasAnyFlags(RF_ClassDefaultObject) && Temp->IsDefaultSubobject())
		{
			if ((PortFlags & PPF_Delimited) && (!Temp->GetFName().IsValidXName(INVALID_OBJECTNAME_CHARACTERS)))
			{
				ValueStr += FString::Printf(TEXT("\"%s\""), *Temp->GetName().ReplaceQuotesWithEscapedQuotes());
			}
			else
			{
				ValueStr += Temp->GetName();
			}
		}
		else
		{
			ValueStr += GetExportPath(Temp, Parent, ExportRootScope, PortFlags);
		}
	}
	else
	{
		ValueStr += TEXT("None");
	}
}
FText SGraphPinObject::OnGetComboTextValue() const
{
	FText Value = GetDefaultComboText();
	
	if (GraphPinObj != NULL)
	{
		UObject* DefaultObject = GraphPinObj->DefaultObject;
		if (DefaultObject != NULL)
		{
			Value = FText::FromString(DefaultObject->GetName());
		}
	}
	return Value;
}
		/**
		* Saves the duplicated asset
		*/
		void SaveDuplicatedAsset()
		{
			if (DuplicatedPackage && DuplicatedAsset)
			{
				DuplicatedPackage->SetDirtyFlag(true);
				const FString PackagePath = FString::Printf(TEXT("%s/%s_Copy"), *GetGamePath(), *AssetName);
				if (UPackage::SavePackage(DuplicatedPackage, NULL, RF_Standalone, *FPackageName::LongPackageNameToFilename(PackagePath, FPackageName::GetAssetPackageExtension()), GError, nullptr, false, true, SAVE_NoError))
				{
					TestStats->NumDuplicatesSaved++;
					UE_LOG(LogEditorAssetAutomationTests, Display, TEXT("Saved asset %s (%s)"), *DuplicatedAsset->GetName(), *Class->GetName());
				}
				else
				{
					UE_LOG(LogEditorAssetAutomationTests, Display, TEXT("Unable to save asset %s (%s)"), *DuplicatedAsset->GetName(), *Class->GetName());
				}
			}
		}
FString SObjectNameEditableTextBox::GetObjectDisplayName(TWeakObjectPtr<UObject> Object)
{
	FString Result;
	if(Object.IsValid())
	{
		UObject* ObjectPtr = Object.Get();
		if (ObjectPtr->IsA(AActor::StaticClass()))
		{
			Result =  ((AActor*)ObjectPtr)->GetActorLabel();
		}
		else
		{
			Result = ObjectPtr->GetName();
		}
	}
	return Result;
}
Example #8
0
UActorComponent* AActor::CreateComponentFromTemplate(UActorComponent* Template, const FString& InName)
{
	UActorComponent* NewActorComp = NULL;
	if(Template != NULL)
	{
		// If there is a Component with this name already (almost certainly because it is an Instance component), we need to rename it out of the way
		if (!InName.IsEmpty())
		{
			UObject* ConflictingObject = FindObjectFast<UObject>(this, *InName);
			if (ConflictingObject && ConflictingObject->IsA<UActorComponent>() && CastChecked<UActorComponent>(ConflictingObject)->CreationMethod == EComponentCreationMethod::Instance)
			{		
				// Try and pick a good name
				FString ConflictingObjectName = ConflictingObject->GetName();
				int32 CharIndex = ConflictingObjectName.Len()-1;
				while (FChar::IsDigit(ConflictingObjectName[CharIndex]))
				{
					--CharIndex;
				}
				int32 Counter = 0;
				if (CharIndex < ConflictingObjectName.Len()-1)
				{
					Counter = FCString::Atoi(*ConflictingObjectName.RightChop(CharIndex+1));
					ConflictingObjectName = ConflictingObjectName.Left(CharIndex+1);
				}
				FString NewObjectName;
				do
				{
					NewObjectName = ConflictingObjectName + FString::FromInt(++Counter);
					
				} while (FindObjectFast<UObject>(this, *NewObjectName) != nullptr);

				ConflictingObject->Rename(*NewObjectName, this);
			}
		}

		// Note we aren't copying the the RF_ArchetypeObject flag. Also note the result is non-transactional by default.
		NewActorComp = (UActorComponent*)StaticDuplicateObject(Template, this, *InName, RF_AllFlags & ~(RF_ArchetypeObject|RF_Transactional|RF_WasLoaded|RF_Public|RF_InheritableComponentTemplate) );

		NewActorComp->CreationMethod = EComponentCreationMethod::UserConstructionScript;

		// Need to do this so component gets saved - Components array is not serialized
		BlueprintCreatedComponents.Add(NewActorComp);
	}
	return NewActorComp;
}
Example #9
0
FText SGraphPinObject::OnGetComboTextValue() const
{
	FText Value = GetDefaultComboText();
	
	if (GraphPinObj != NULL)
	{
		UObject* DefaultObject = GraphPinObj->DefaultObject;
		if (UField* Field = Cast<UField>(DefaultObject))
		{
			Value = Field->GetDisplayNameText();
		}
		else if (DefaultObject != NULL)
		{
			Value = FText::FromString(DefaultObject->GetName());
		}
	}
	return Value;
}
Example #10
0
	void GetInterpPropertyNames(UObject* InObject, const FString& Prefix)
	{
		UClass* ObjectClass = InObject->GetClass();

		// First search for any properties in this object
		for (TFieldIterator<UProperty> ClassFieldIt(ObjectClass); ClassFieldIt; ++ClassFieldIt)
		{
			UProperty* ClassMemberProperty = *ClassFieldIt;
			if (ClassMemberProperty->HasAnyPropertyFlags(CPF_Interp))
			{
				// Is this property the desired type?
				if (IsDesiredProperty(ClassMemberProperty))
				{
					const FString QualifiedFullPath = FString::Printf(TEXT("%s%s"), *Prefix, *ClassMemberProperty->GetName());
					GatheredPropertyPaths.Add(*QualifiedFullPath);
				}

				// If this is a struct, look for any desired properties inside of it
				if (UStructProperty* OuterStructProperty = Cast<UStructProperty>(ClassMemberProperty))
				{
					for (TFieldIterator<UProperty> StructFieldIt(OuterStructProperty->Struct); StructFieldIt; ++StructFieldIt)
					{
						UProperty* StructMemberProperty = *StructFieldIt;
						if (StructMemberProperty->HasAnyPropertyFlags(CPF_Interp) && IsDesiredProperty(StructMemberProperty))
						{
							const FString QualifiedFullPath = FString::Printf(TEXT("%s%s.%s"), *Prefix, *OuterStructProperty->GetName(), *StructMemberProperty->GetName());
							GatheredPropertyPaths.Add(*QualifiedFullPath);
						}
					}
				}
			}
		}

		// Then iterate over each subobject of this object looking for interp properties.
		TArray<UObject*> DefaultSubObjects;
		ObjectClass->GetDefaultObjectSubobjects(DefaultSubObjects);
		for (int32 SubObjectIndex = 0; SubObjectIndex < DefaultSubObjects.Num(); ++SubObjectIndex)
		{
			UObject* Component = DefaultSubObjects[SubObjectIndex];
			const FString ComponentPrefix = Component->GetName() + TEXT(".");

			GetInterpPropertyNames(Component, ComponentPrefix); 
		}
	}
void UCrowdFollowingComponent::DescribeSelfToVisLog(FVisualLogEntry* Snapshot) const
{
	if (!bEnableCrowdSimulation)
	{
		Super::DescribeSelfToVisLog(Snapshot);
		return;
	}

	FVisualLogStatusCategory Category;
	Category.Category = TEXT("Path following");

	if (DestinationActor.IsValid())
	{
		Category.Add(TEXT("Goal"), GetNameSafe(DestinationActor.Get()));
	}

	FString StatusDesc = GetStatusDesc();

	FNavMeshPath* NavMeshPath = Path.IsValid() ? Path->CastPath<FNavMeshPath>() : NULL;
	FAbstractNavigationPath* DirectPath = Path.IsValid() ? Path->CastPath<FAbstractNavigationPath>() : NULL;

	if (Status == EPathFollowingStatus::Moving)
	{
		StatusDesc += FString::Printf(TEXT(" [path:%d, visited:%d]"), PathStartIndex, LastPathPolyIndex);
	}

	Category.Add(TEXT("Status"), StatusDesc);
	Category.Add(TEXT("Path"), !Path.IsValid() ? TEXT("none") : NavMeshPath ? TEXT("navmesh") : DirectPath ? TEXT("direct") : TEXT("unknown"));

	UObject* CustomLinkOb = GetCurrentCustomLinkOb();
	if (CustomLinkOb)
	{
		Category.Add(TEXT("SmartLink"), CustomLinkOb->GetName());
	}

	UCrowdManager* Manager = UCrowdManager::GetCurrent(GetWorld());
	if (Manager && !Manager->IsAgentValid(this))
	{
		Category.Add(TEXT("Simulation"), TEXT("unable to register!"));
	}

	Snapshot->Status.Add(Category);
}
/**
 * Builds a human readable name from the commandlets name
 *
 * @param Commandlet the commandlet to mangle the name of
 */
static FString GetCommandletName(UCommandlet* Commandlet)
{
	// Don't print out the default portion of the name
	static INT SkipLen = appStrlen(TEXT("Default__"));
	FString Name(*Commandlet->GetName() + SkipLen);
	// Strip off everything past the friendly name
	INT Index = Name.InStr(TEXT("Commandlet"));
	if (Index != -1)
	{
		Name = Name.Left(Index);
	}
	// Get the code package this commandlet is contained in
	UObject* Outer = Commandlet->GetOutermost();
	// Build Package.Commandlet as the name
	FString FullName = Outer->GetName();
	FullName += TEXT(".");
	FullName += Name;
	return FullName;
}
FString SPropertyEditorCombo::GetDisplayValueAsString() const
{
	const UProperty* Property = PropertyEditor->GetProperty();
	const UByteProperty* ByteProperty = Cast<const UByteProperty>( Property );
	const bool bStringEnumProperty = Property && Property->IsA(UStrProperty::StaticClass()) && Property->HasMetaData(TEXT("Enum"));	

	if ( !(ByteProperty || bStringEnumProperty) )
	{
		UObject* ObjectValue = NULL;
		FPropertyAccess::Result Result = PropertyEditor->GetPropertyHandle()->GetValue( ObjectValue );

		if( Result == FPropertyAccess::Success && ObjectValue != NULL )
		{
			return ObjectValue->GetName();
		}
	}

	return (bUsesAlternateDisplayValues) ? PropertyEditor->GetValueAsDisplayString() : PropertyEditor->GetValueAsString();
}
FString UAnimNotify::GetNotifyName_Implementation() const
{
	UObject* ClassGeneratedBy = GetClass()->ClassGeneratedBy;
	FString NotifyName;

	if(ClassGeneratedBy)
	{
		// GeneratedBy will be valid for blueprint types and gives a clean name without a suffix
		NotifyName = ClassGeneratedBy->GetName();
	}
	else
	{
		// Native notify classes are clean without a suffix otherwise
		NotifyName = GetClass()->GetName();
	}

	NotifyName = NotifyName.Replace(TEXT("AnimNotify_"), TEXT(""), ESearchCase::CaseSensitive);
	
	return NotifyName;
}
	// Keep sync with FTypeSingletonCache::GenerateSingletonName
	static FString GenerateZConstructor(UField* Item)
	{
		FString Result;
		if (!ensure(Item))
		{
			return Result;
		}
		
		for (UObject* Outer = Item; Outer; Outer = Outer->GetOuter())
		{
			if (!Result.IsEmpty())
			{
				Result = TEXT("_") + Result;
			}

			if (Cast<UClass>(Outer) || Cast<UScriptStruct>(Outer))
			{
				FString OuterName = FEmitHelper::GetCppName(CastChecked<UField>(Outer), true);
				Result = OuterName + Result;

				// Structs can also have UPackage outer.
				if (Cast<UClass>(Outer) || Cast<UPackage>(Outer->GetOuter()))
				{
					break;
				}
			}
			else
			{
				Result = Outer->GetName() + Result;
			}
		}

		// Can't use long package names in function names.
		if (Result.StartsWith(TEXT("/Script/"), ESearchCase::CaseSensitive))
		{
			Result = FPackageName::GetShortName(Result);
		}

		const FString ClassString = Item->IsA<UClass>() ? TEXT("UClass") : TEXT("UScriptStruct");
		return FString(TEXT("Z_Construct_")) + ClassString + TEXT("_") + Result + TEXT("()");
	}
/**
 * prefilter shader for suspension raycasts
 */
static PxQueryHitType::Enum WheelRaycastPreFilter(	
	PxFilterData SuspensionData, 
	PxFilterData HitData,
	const void* constantBlock, PxU32 constantBlockSize,
	PxHitFlags& filterFlags)
{
	// SuspensionData is the vehicle suspension raycast.
	// HitData is the shape potentially hit by the raycast.

	// don't collide with owner chassis
	if ( SuspensionData.word0 == HitData.word0 )
	{
		return PxSceneQueryHitType::eNONE;
	}

	// collision channels filter
	ECollisionChannel SuspensionChannel = (ECollisionChannel)(SuspensionData.word3 >> 24);

	if ( ECC_TO_BITFIELD(SuspensionChannel) & HitData.word1)
	{
		// debug what object we hit
		if ( false )
		{
			for ( FObjectIterator It; It; ++It )
			{
				if ( It->GetUniqueID() == HitData.word0 )
				{
					UObject* HitObj = *It;
					FString HitObjName = HitObj->GetName();
					break;
				}
			}
		}

		return PxSceneQueryHitType::eBLOCK;
	}

	return PxSceneQueryHitType::eNONE;
}
uint32 FUnrealEnginePythonHouseKeeper::PyUObjectsGC()
{
    uint32 Garbaged = 0;
    TArray<UObject *> BrokenList;
    for (auto &UObjectPyItem : UObjectPyMapping)
    {
        UObject *Object = UObjectPyItem.Key;
        FPythonUOjectTracker &Tracker = UObjectPyItem.Value;
#if defined(UEPY_MEMORY_DEBUG)
        UE_LOG(LogPython, Warning, TEXT("Checking for UObject at %p"), Object);
#endif
        if (!Tracker.Owner.IsValid(true))
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Warning, TEXT("Removing UObject at %p (refcnt: %d)"), Object, Tracker.PyUObject->ob_base.ob_refcnt);
#endif
            BrokenList.Add(Object);
            Garbaged++;
    }
        else
        {
#if defined(UEPY_MEMORY_DEBUG)
            UE_LOG(LogPython, Error, TEXT("UObject at %p %s is in use"), Object, *Object->GetName());
#endif
}
    }

    for (UObject *Object : BrokenList)
    {
        FPythonUOjectTracker &Tracker = UObjectPyMapping[Object];
        if (!Tracker.bPythonOwned)
            Py_DECREF((PyObject *)Tracker.PyUObject);
        UnregisterPyUObject(Object);
    }

    return Garbaged;

}
/** Replicates properties to the Bunch. Returns true if it wrote anything */
bool FObjectReplicator::ReplicateProperties( FOutBunch & Bunch, FReplicationFlags RepFlags )
{
	UObject * Object = GetObject();

	check( Object );
	check( OwningChannel );
	check( RepLayout.IsValid() );
	check( RepState )
	check( RepState->StaticBuffer.Num() );

	UNetConnection * OwningChannelConnection = OwningChannel->Connection;

	const int32 StartingBitNum = Bunch.GetNumBits();

	bool	bContentBlockWritten	= false;
	int32	LastIndex				= 0;

	// Replicate all the custom delta properties (fast arrays, etc)
	ReplicateCustomDeltaProperties( Bunch, LastIndex, bContentBlockWritten );

	// Replicate properties in the layout
	RepLayout->ReplicateProperties( RepState, (uint8*)Object, ObjectClass, OwningChannel, Bunch, RepFlags, LastIndex, bContentBlockWritten );

	// LastUpdateEmpty - this is done before dequeing the multicasted unreliable functions on purpose as they should not prevent
	// an actor channel from going dormant.
	bLastUpdateEmpty = ( Bunch.GetNumBits() == StartingBitNum );

	// Replicate Queued (unreliable functions)
	if ( RemoteFunctions != NULL && RemoteFunctions->GetNumBits() > 0 )
	{
		static const auto * CVar = IConsoleManager::Get().FindTConsoleVariableDataInt( TEXT( "net.RPC.Debug" ) );

		if ( CVar && CVar->GetValueOnGameThread() == 1 )
		{
			UE_LOG( LogNetTraffic, Warning,	TEXT("      Sending queued RPCs: %s. Channel[%d] [%.1f bytes]"), *Object->GetName(), OwningChannel->ChIndex, RemoteFunctions->GetNumBits() / 8.f );
		}

		if ( !bContentBlockWritten )
		{
			OwningChannel->BeginContentBlock( Object, Bunch );
			bContentBlockWritten = true;
		}

		Bunch.SerializeBits( RemoteFunctions->GetData(), RemoteFunctions->GetNumBits() );
		RemoteFunctions->Reset();
		RemoteFuncInfo.Empty();
	}

	// See if we wrote something important (anything but the 'end' int below).
	// Note that queued unreliable functions are considered important (WroteImportantData) but not for bLastUpdateEmpty. LastUpdateEmpty
	// is used for dormancy purposes. WroteImportantData is for determining if we should not include a component in replication.
	const bool WroteImportantData = ( Bunch.GetNumBits() != StartingBitNum );

	if ( WroteImportantData )
	{
		OwningChannel->EndContentBlock( Object, Bunch, OwningChannelConnection->PackageMap->GetClassNetCache( ObjectClass ) );
	}

	return WroteImportantData;
}
bool FObjectReplicator::ReceivedBunch( FInBunch &Bunch, const FReplicationFlags & RepFlags )
{
	UObject *		Object		= GetObject();
	UPackageMap *	PackageMap	= OwningChannel->Connection->PackageMap;

	if ( Object == NULL )
	{
		UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Object == NULL" ) );
		return false;
	}

	const bool bIsServer = ( OwningChannel->Connection->Driver->ServerConnection == NULL );

	FClassNetCache * ClassCache = PackageMap->GetClassNetCache( ObjectClass );

	if ( ClassCache == NULL )
	{
		UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: ClassCache == NULL: %s" ), *Object->GetFullName() );
		return false;
	}

	bool bThisBunchReplicatedProperties = false;

	// First RepIndex.
	int32 RepIndex = Bunch.ReadInt( ClassCache->GetMaxIndex() + 1 );

	if ( Bunch.IsError() )
	{
		UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Error reading bunch 1: %s" ), *Object->GetFullName() );
		return false;
	}

	if ( RepIndex == ClassCache->GetMaxIndex() )
	{
		// There are no actual replicated properties or functions in this bunch. That is ok - we may have gotten this
		// actor/subobject because we want the client to spawn one (but we arent actually replicating properties on it)
		return true;
	}

	if ( RepIndex > ClassCache->GetMaxIndex() )
	{
		// We shouldn't be receiving this bunch of this object has no properties or RPC functions to process
		UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: RepIndex too large: %s" ), *Object->GetFullName() );
		return false;
	}

	FFieldNetCache * FieldCache = ClassCache->GetFromIndex( RepIndex );

	if ( FieldCache == NULL )
	{
		UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: FieldCache == NULL: %s" ), *Object->GetFullName() );
		return false;
	}

	while ( FieldCache )
	{
		// Receive properties from the net.
		UProperty * ReplicatedProp	= NULL;
		int32		LastIndex		= 0;

		while ( FieldCache && ( ReplicatedProp = Cast< UProperty >( FieldCache->Field ) ) != NULL )
		{
			NET_CHECKSUM( Bunch );

			// Server shouldn't receive properties.
			if ( bIsServer )
			{
				UE_LOG( LogNet, Error, TEXT( "Server received unwanted property value %s in %s" ), *ReplicatedProp->GetName(), *Object->GetFullName() );
				return false;
			}
		
			bThisBunchReplicatedProperties = true;

			if ( !bHasReplicatedProperties )
			{
				bHasReplicatedProperties = true;		// Persistent, not reset until PostNetReceive is called
				PreNetReceive();
			}

			bool DebugProperty = false;
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
			{
				static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("net.Replication.DebugProperty"));
				if (CVar && !CVar->GetString().IsEmpty() && ReplicatedProp->GetName().Contains(CVar->GetString()) )
				{
					UE_LOG(LogNet, Log, TEXT("Replicating Property[%d] %s on %s"), RepIndex, *ReplicatedProp->GetName(), *Object->GetName());
					DebugProperty = true;
				}
			}
#endif

			if ( !Retirement[ ReplicatedProp->RepIndex ].CustomDelta )
			{
				// We hijack a non custom delta property to signify we are using FRepLayout to read the entire property block
				FPropertyRetirement & Retire = Retirement[ ReplicatedProp->RepIndex ];

				bool bDiscardLayout = false;

				if ( Bunch.PacketId >= Retire.InPacketId ) //!! problem with reliable pkts containing dynamic references, being retransmitted, and overriding newer versions. Want "OriginalPacketId" for retransmissions?
				{
					// Receive this new property.
					Retire.InPacketId = Bunch.PacketId;
				}
				else
				{
					bDiscardLayout = true;
				}
				
				if ( !RepLayout->ReceiveProperties( ObjectClass, RepState, (void*)Object, Bunch, bDiscardLayout ) )
				{
					UE_LOG( LogNet, Error, TEXT( "ReceiveProperties FAILED %s in %s" ), *ReplicatedProp->GetName(), *Object->GetFullName() );
					return false;
				}
			}
			else
			{
				// Receive array index.
				int32 Element = 0;
				if ( ReplicatedProp->ArrayDim != 1 )
				{
					// Serialize index as delta from previous index to increase chance we'll only use 1 byte
					uint32 idx;
					Bunch.SerializeIntPacked( idx );
					Element = static_cast< int32 >( idx ) + LastIndex;
					LastIndex = Element;

					if ( Element >= ReplicatedProp->ArrayDim )
					{
						UE_LOG( LogNet, Error, TEXT( "Element index too large %s in %s" ), *ReplicatedProp->GetName(), *Object->GetFullName() );
						return false;
					}
				}

				// Pointer to destination.
				uint8 * DestObj		= (uint8*)Object;
				uint8 * DestRecent	= RepState->StaticBuffer.Num() ? RepState->StaticBuffer.GetTypedData() : NULL;

				// Check property ordering.
				FPropertyRetirement & Retire = Retirement[ ReplicatedProp->RepIndex + Element ];

				if ( Bunch.PacketId >= Retire.InPacketId ) //!! problem with reliable pkts containing dynamic references, being retransmitted, and overriding newer versions. Want "OriginalPacketId" for retransmissions?
				{
					// Receive this new property.
					Retire.InPacketId = Bunch.PacketId;
				}
				else
				{
					// Skip this property, because it's out-of-date.
					UE_LOG( LogNetTraffic, Log, TEXT( "Received out-of-date %s" ), *ReplicatedProp->GetName() );

					DestObj		= NULL;
					DestRecent	= NULL;
				}

				FMemMark Mark(FMemStack::Get());
				uint8 * Data = DestObj ? ReplicatedProp->ContainerPtrToValuePtr<uint8>(DestObj, Element) : NewZeroed<uint8>(FMemStack::Get(),ReplicatedProp->ElementSize);
				TArray<uint8>	MetaData;
				PTRINT Offset = 0;

				// Copy current value over to Recent for comparison
				if ( DestRecent )
				{
					Offset = ReplicatedProp->ContainerPtrToValuePtr<uint8>(DestRecent, Element) - DestRecent;
					check( Offset >= 0 && Offset < RepState->StaticBuffer.Num() ); //@todo if we move properties outside of the memory block, then this will not work anyway
					ReplicatedProp->CopySingleValue( DestRecent + Offset, Data );
				}

				// Receive custom delta property.
				UStructProperty * StructProperty = Cast< UStructProperty >( ReplicatedProp );

				if ( StructProperty == NULL )
				{
					// This property isn't custom delta
					UE_LOG( LogNetTraffic, Error, TEXT( "Property isn't custom delta %s" ), *ReplicatedProp->GetName() );
					return false;
				}

				UScriptStruct * InnerStruct = StructProperty->Struct;

				if ( !( InnerStruct->StructFlags & STRUCT_NetDeltaSerializeNative ) )
				{
					// This property isn't custom delta
					UE_LOG( LogNetTraffic, Error, TEXT( "Property isn't custom delta %s" ), *ReplicatedProp->GetName() );
					return false;
				}

				UScriptStruct::ICppStructOps * CppStructOps = InnerStruct->GetCppStructOps();

				check( CppStructOps );
				check( !InnerStruct->InheritedCppStructOps() );

				FNetDeltaSerializeInfo Parms;

				FNetSerializeCB NetSerializeCB( OwningChannel->Connection->Driver );

				Parms.DebugName			= StructProperty->GetName();
				Parms.Struct			= InnerStruct;
				Parms.Map				= PackageMap;
				Parms.InArchive			= &Bunch;
				Parms.NetSerializeCB	= &NetSerializeCB;

				// Call the custom delta serialize function to handle it
				CppStructOps->NetDeltaSerialize( Parms, Data );

				if ( Bunch.IsError() )
				{
					UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: NetDeltaSerialize - Bunch.IsError() == true: %s" ), *Object->GetFullName() );
					return false;
				}

				// See if it changed from our local value
				bool PropertyChanged = true;

				if ( DestRecent )
				{
					// POD types can do a memcmp with a call to Identical
					if ( ReplicatedProp->Identical( DestRecent + Offset, Data ) )
					{
						PropertyChanged = false;
					}
				}

				Mark.Pop();

				// Successfully received it.
				UE_LOG( LogNetTraffic, Log, TEXT( " %s - %s - Change: %d" ), *Object->GetName(), *ReplicatedProp->GetName(), PropertyChanged );

				// Notify the Object if this var is RepNotify
				if ( PropertyChanged )
				{
					QueuePropertyRepNotify( Object, ReplicatedProp, Element, MetaData );
				}
			}	
			
			// Next.
			RepIndex = Bunch.ReadInt( ClassCache->GetMaxIndex() + 1 );

			if ( Bunch.IsError() )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Error reading bunch 2: %s" ), *Object->GetFullName() );
				return false;
			}

			if ( RepIndex > ClassCache->GetMaxIndex() )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: RepIndex too large: %s" ), *Object->GetFullName() );
				return false;
			}
			
			if ( RepIndex == ClassCache->GetMaxIndex() )
			{
				// We're done
				FieldCache = NULL;
			}
			else
			{
				FieldCache = ClassCache->GetFromIndex( RepIndex );

				if ( FieldCache == NULL )
				{
					UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: FieldCache == NULL: %s" ), *Object->GetFullName() );
					return false;
				}
			}
		}

		// Handle function calls.
		if ( FieldCache && Cast< UFunction >( FieldCache->Field ) )
		{
			FName Message = FieldCache->Field->GetFName();
			UFunction * Function = Object->FindFunction( Message );

			if ( Function == NULL )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Function == NULL: %s" ), *Object->GetFullName() );
				return false;
			}

			if ( ( Function->FunctionFlags & FUNC_Net ) == 0 )
			{
				UE_LOG( LogNet, Error, TEXT( "Rejected non RPC function %s in %s" ), *Message.ToString(), *Object->GetFullName() );
				return false;
			}

			if ( ( Function->FunctionFlags & ( bIsServer ? FUNC_NetServer : ( FUNC_NetClient | FUNC_NetMulticast ) ) ) == 0 )
			{
				UE_LOG( LogNet, Error, TEXT( "Rejected RPC function due to access rights %s in %s" ), *Message.ToString(), *Object->GetFullName() );
				return false;
			}

			UE_LOG( LogNetTraffic, Log, TEXT( "      Received RPC: %s" ), *Message.ToString() );

			// Get the parameters.
			FMemMark Mark(FMemStack::Get());
			uint8* Parms = new(FMemStack::Get(),MEM_Zeroed,Function->ParmsSize)uint8;

			// Use the replication layout to receive the rpc parameter values
			TSharedPtr<FRepLayout> FuncRepLayout = OwningChannel->Connection->Driver->GetFunctionRepLayout( Function );

			FuncRepLayout->ReceivePropertiesForRPC( Object, Function, OwningChannel, Bunch, Parms );

			if ( Bunch.IsError() )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: ReceivePropertiesForRPC - Bunch.IsError() == true: %s" ), *Object->GetFullName() );
				return false;
			}

			// validate that the function is callable here
			const bool bCanExecute = ( ( !bIsServer || RepFlags.bNetOwner ) );		// we are client or net owner

			if ( bCanExecute )
			{
				// Call the function.
				RPC_ResetLastFailedReason();

				Object->ProcessEvent( Function, Parms );

				if ( RPC_GetLastFailedReason() != NULL )
				{
					UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: RPC_GetLastFailedReason: %s" ), RPC_GetLastFailedReason() );
					return false;
				}
			}
			else
			{
				UE_LOG( LogNet, Warning, TEXT( "Rejected unwanted function %s in %s" ), *Message.ToString(), *Object->GetFullName() );

				if ( !OwningChannel->Connection->TrackLogsPerSecond() )	// This will disconnect the client if we get her too often
				{
					return false;
				}
			}

			// Destroy the parameters.
			//warning: highly dependent on UObject::ProcessEvent freeing of parms!
			for ( UProperty * Destruct=Function->DestructorLink; Destruct; Destruct=Destruct->DestructorLinkNext )
			{
				if( Destruct->IsInContainer(Function->ParmsSize) )
				{
					Destruct->DestroyValue_InContainer(Parms);
				}
			}

			Mark.Pop();

			if ( Object == NULL || Object->IsPendingKill() )
			{
				// replicated function destroyed Object
				return true;		// FIXME: Should this return false to kick connection?  Seems we'll cause a read misalignment here if we don't
			}

			// Next.
			RepIndex = Bunch.ReadInt( ClassCache->GetMaxIndex() + 1 );

			if ( Bunch.IsError() )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Error reading bunch 2: %s" ), *Object->GetFullName() );
				return false;
			}

			if ( RepIndex > ClassCache->GetMaxIndex() )
			{
				UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: RepIndex too large: %s" ), *Object->GetFullName() );
				return false;
			}

			if ( RepIndex == ClassCache->GetMaxIndex() )
			{
				// We're done
				FieldCache = NULL;
			}
			else
			{
				FieldCache = ClassCache->GetFromIndex( RepIndex );

				if ( FieldCache == NULL )
				{
					UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: FieldCache == NULL: %s" ), *Object->GetFullName() );
					return false;
				}
			}
		}
		else if ( FieldCache )
		{
			UE_LOG( LogNet, Error, TEXT( "ReceivedBunch: Invalid replicated field %i in %s" ), RepIndex, *Object->GetFullName() );
			return false;
		}
	}

	return true;
}
void UExporter::ExportComponentDefinitions(const FExportObjectInnerContext* Context, const TArray<UObject*>& Components, FOutputDevice& Ar, uint32 PortFlags)
{
	PortFlags |= PPF_ExportsNotFullyQualified;

	if (!(PortFlags & PPF_SeparateDefine))
	{
		// export forward declarations
		// technically we only need to do this if there are circular references but it doesn't seem worth it
		// to complicate this code for a minor speed improvement in the text import path
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				if (Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject))
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s%s"), FCString::Spc(TextIndent), *Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), LINE_TERMINATOR);
				}
				else
				{
					Ar.Logf(TEXT("%sBegin Object Class=%s Name=%s ObjName=%s Archetype=%s'%s'%s"),FCString::Spc(TextIndent),*Component->GetClass()->GetName(), *ComponentName.ToString(), *Component->GetName(), *Component->GetArchetype()->GetClass()->GetName(), *Component->GetArchetype()->GetPathName(), LINE_TERMINATOR);
				}
				if (PortFlags & PPF_SeparateDeclare)
				{
					ExportObjectInner(Context, Component, Ar, PortFlags, false);
				}
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);
			}
		}
	}

	if (!(PortFlags & PPF_SeparateDeclare))
	{
		// export property definitions
		for (int32 ComponentIndex = 0; ComponentIndex < Components.Num(); ComponentIndex++)
		{
			UObject* Component = Components[ComponentIndex];
			FName ComponentName = Component->GetFName();
			if (!Component->HasAnyMarks(OBJECTMARK_TagImp) && !Component->HasAnyFlags(RF_TextExportTransient))
			{
				Ar.Logf(TEXT("%sBegin Object Name=%s%s"), FCString::Spc(TextIndent), *ComponentName.ToString(), LINE_TERMINATOR);

				uint32 OldPortFlags = PortFlags;

				if (!(Component->HasAnyFlags(RF_ClassDefaultObject) || Component->GetArchetype()->HasAllFlags(RF_ClassDefaultObject)))
				{
					// we created this thing with an archetype (see archetype=, above), so we don't want to list the archetype because it is unqualified and will clash, resetting the archetype pointer to something silly
					PortFlags |= PPF_NoInternalArcheType;
				}
				ExportObjectInner(Context, Component, Ar, PortFlags, false);

				PortFlags = OldPortFlags;
				Ar.Logf(TEXT("%sEnd Object%s"), FCString::Spc(TextIndent), LINE_TERMINATOR);

				Component->Mark(OBJECTMARK_TagImp);
			}
		}
	}
}
void FObjectMemoryAnalyzer::PrintSubObjects(FOutputDevice& Ar, const FString& Indent, UObject* Parent, uint32 PrintFlags)
{
	TArray<UObject*> ReferencedObjects;
	GetReferencedObjects(Parent, ReferencedObjects);

	for( int32 ObjIndex = 0; ObjIndex < ReferencedObjects.Num(); ObjIndex++ )
	{
		UObject* SubObj = ReferencedObjects[ObjIndex];
		const FObjectMemoryUsage& Annotation = GetObjectMemoryUsage(SubObj);

		if (!Annotation.IsRoot())
		{
			Ar.Logf( TEXT("%-100s %-10d %-10d %-10d %-10d"), *FString::Printf(TEXT("%s%s %s"), *Indent, *SubObj->GetClass()->GetName(), *SubObj->GetName()),
					 (int32)Annotation.InclusiveMemoryUsage, (int32)Annotation.ExclusiveMemoryUsage, 
					 (int32)(Annotation.InclusiveResourceSize/1024), (int32)(Annotation.ExclusiveResourceSize/1024) );

			if (!!(PrintFlags&EPrintFlags::PrintReferencer))
			{
				for (int32 i=0; i < Annotation.NonRootReferencer.Num(); ++i)
				{
					Ar.Logf(TEXT("%s  >> NonRootRef: %s"), *Indent, *Annotation.NonRootReferencer[i]->GetName());
				}

				for (int32 i=0; i < Annotation.RootReferencer.Num(); ++i)
				{
					Ar.Logf(TEXT("%s  >> RootRef: %s"), *Indent, *Annotation.RootReferencer[i]->GetName());
				}
			}
			
			if (!!(PrintFlags&EPrintFlags::PrintReferences))
			{
				PrintSubObjects(Ar, Indent + TEXT(" -> "), SubObj, PrintFlags);
			}
		}
	}
}
void SDetailsView::SetObjectArrayPrivate(const TArray< TWeakObjectPtr< UObject > >& InObjects)
{
	double StartTime = FPlatformTime::Seconds();

	PreSetObject(InObjects.Num());

	// Selected actors for building SelectedActorInfo
	TArray<AActor*> SelectedRawActors;

	bViewingClassDefaultObject = InObjects.Num() > 0 ? true : false;
	bool bOwnedByLockedLevel = false;
	for( int32 ObjectIndex = 0 ; ObjectIndex < InObjects.Num(); ++ObjectIndex )
	{
		TWeakObjectPtr< UObject > Object = InObjects[ObjectIndex];

		if( Object.IsValid() )
		{
			bViewingClassDefaultObject &= Object->HasAnyFlags( RF_ClassDefaultObject );

			if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
			{
				check(RootPropertyNodes.Num() == InObjects.Num());
				RootPropertyNodes[ObjectIndex]->AsObjectNode()->AddObject( Object.Get() );
			}
			else
			{
				RootPropertyNodes[0]->AsObjectNode()->AddObject( Object.Get() );
			}

			SelectedObjects.Add( Object );
			AActor* Actor = Cast<AActor>( Object.Get() );
			if( Actor )
			{
				SelectedActors.Add( Actor );
				SelectedRawActors.Add( Actor );
			}
		}
	}

	if( InObjects.Num() == 0 )
	{
		// Unlock the view automatically if we are viewing nothing
		bIsLocked = false;
	}

	// Selection changed, refresh the detail area
	if ( DetailsViewArgs.NameAreaSettings != FDetailsViewArgs::ActorsUseNameArea && DetailsViewArgs.NameAreaSettings != FDetailsViewArgs::ComponentsAndActorsUseNameArea )
	{
		NameArea->Refresh( SelectedObjects );
	}
	else
	{
		NameArea->Refresh( SelectedActors, SelectedObjects, DetailsViewArgs.NameAreaSettings );
	}
	
	// When selection changes rebuild information about the selection
	SelectedActorInfo = AssetSelectionUtils::BuildSelectedActorInfo( SelectedRawActors );

	// @todo Slate Property Window
	//SetFlags(EPropertyWindowFlags::ReadOnly, bOwnedByLockedLevel);


	PostSetObject();

	// Set the title of the window based on the objects we are viewing
	// Or call the delegate for handling when the title changed
	FString Title;

	if( GetNumObjects() == 0 )
	{
		Title = NSLOCTEXT("PropertyView", "NothingSelectedTitle", "Nothing selected").ToString();
	}
	else if( GetNumObjects() == 1 && RootPropertyNodes[0]->AsObjectNode()->GetNumObjects() > 0)
	{
		// if the object is the default metaobject for a UClass, use the UClass's name instead
		UObject* Object = RootPropertyNodes[0]->AsObjectNode()->GetUObject(0);
		FString ObjectName = Object->GetName();
		if ( Object->GetClass()->GetDefaultObject() == Object )
		{
			ObjectName = Object->GetClass()->GetName();
		}
		else
		{
			// Is this an actor?  If so, it might have a friendly name to display
			const AActor* Actor = Cast<const  AActor >( Object );
			if( Actor != nullptr)
			{
				// Use the friendly label for this actor
				ObjectName = Actor->GetActorLabel();
			}
		}

		Title = ObjectName;
	}
	else if(DetailsViewArgs.bAllowMultipleTopLevelObjects)
	{
		Title = FString::Printf(*NSLOCTEXT("PropertyView", "MultipleToLevelObjectsSelected", "%i selected").ToString(), GetNumObjects());
	}
	else
	{
		FObjectPropertyNode* RootPropertyNode = RootPropertyNodes[0]->AsObjectNode();
		Title = FString::Printf( *NSLOCTEXT("PropertyView", "MultipleSelected", "%s (%i selected)").ToString(), *RootPropertyNode->GetObjectBaseClass()->GetName(), RootPropertyNode->GetNumObjects() );
	}

	OnObjectArrayChanged.ExecuteIfBound(Title, InObjects);

	double ElapsedTime = FPlatformTime::Seconds() - StartTime;
}
Example #23
0
void FTimeline::SetPlaybackPosition(float NewPosition, bool bFireEvents)
{
	float OldPosition = Position;
	Position = NewPosition;

	// If playing sequence forwards.
	float MinTime, MaxTime;
	if(!bReversePlayback)
	{
		MinTime = OldPosition;
		MaxTime = Position;

		// Slight hack here.. if playing forwards and reaching the end of the sequence, force it over a little to ensure we fire events actually on the end of the sequence.
		if(MaxTime == GetTimelineLength())
		{
			MaxTime += (float)KINDA_SMALL_NUMBER;
		}
	}
	// If playing sequence backwards.
	else
	{
		MinTime = Position;
		MaxTime = OldPosition;

		// Same small hack as above for backwards case.
		if(MinTime == 0.f)
		{
			MinTime -= (float)KINDA_SMALL_NUMBER;
		}
	}

	// If we should be firing events for this track...
	if(bFireEvents)
	{
		// See which events fall into traversed region.
		for(int32 i=0; i<Events.Num(); i++)
		{
			float EventTime = Events[i].Time;

			// Need to be slightly careful here and make behavior for firing events symmetric when playing forwards of backwards.
			bool bFireThisEvent = false;
			if(!bReversePlayback)
			{
				if( EventTime >= MinTime && EventTime < MaxTime )
				{
					bFireThisEvent = true;
				}
			}
			else
			{
				if( EventTime > MinTime && EventTime <= MaxTime )
				{
					bFireThisEvent = true;
				}
			}

			if( bFireThisEvent )
			{
				Events[i].EventFunc.ExecuteIfBound();
			}
		}
	}

	UObject* PropSetObject = PropertySetObject.Get();

	// Iterate over each vector interpolation
	for(int32 InterpIdx=0; InterpIdx<InterpVectors.Num(); InterpIdx++)
	{
		FTimelineVectorTrack& VecEntry = InterpVectors[InterpIdx];
		if ( VecEntry.VectorCurve && (VecEntry.InterpFunc.IsBound() || VecEntry.VectorPropertyName != NAME_None || VecEntry.InterpFuncStatic.IsBound()) )
		{
			// Get vector from curve
			FVector const Vec = VecEntry.VectorCurve->GetVectorValue(Position);

			// Pass vec to specified function
			VecEntry.InterpFunc.ExecuteIfBound(Vec);

			// Set vector property
			if (PropSetObject)
			{
				if (VecEntry.VectorProperty == NULL)
				{
					VecEntry.VectorProperty = FindField<UStructProperty>(PropSetObject->GetClass(), VecEntry.VectorPropertyName);
					if(VecEntry.VectorProperty == NULL)
					{
						UE_LOG(LogTimeline, Log, TEXT("SetPlaybackPosition: No vector property '%s' in '%s'"), *VecEntry.VectorPropertyName.ToString(), *PropSetObject->GetName());
					}
				}
				if (VecEntry.VectorProperty)
				{
					*VecEntry.VectorProperty->ContainerPtrToValuePtr<FVector>(PropSetObject) = Vec;
				}
			}

			// Pass vec to non-dynamic version of the specified function
			VecEntry.InterpFuncStatic.ExecuteIfBound(Vec);
		}
	}

	// Iterate over each float interpolation
	for(int32 InterpIdx=0; InterpIdx<InterpFloats.Num(); InterpIdx++)
	{
		FTimelineFloatTrack& FloatEntry = InterpFloats[InterpIdx];
		if( FloatEntry.FloatCurve && (FloatEntry.InterpFunc.IsBound() || FloatEntry.FloatPropertyName != NAME_None || FloatEntry.InterpFuncStatic.IsBound()) )
		{
			// Get float from func
			const float Val = FloatEntry.FloatCurve->GetFloatValue(Position);

			// Pass float to specified function
			FloatEntry.InterpFunc.ExecuteIfBound(Val);

			// Set float property
			if (PropSetObject)
			{
				if (FloatEntry.FloatProperty == NULL)
				{
					FloatEntry.FloatProperty = FindField<UFloatProperty>(PropSetObject->GetClass(), FloatEntry.FloatPropertyName);
					if(FloatEntry.FloatProperty == NULL)
					{
						UE_LOG(LogTimeline, Log, TEXT("SetPlaybackPosition: No float property '%s' in '%s'"), *FloatEntry.FloatPropertyName.ToString(), *PropSetObject->GetName());
					}
				}
				if (FloatEntry.FloatProperty)
				{
					FloatEntry.FloatProperty->SetPropertyValue_InContainer(PropSetObject, Val);
				}
			}
			
			// Pass float to non-dynamic version of the specified function
			FloatEntry.InterpFuncStatic.ExecuteIfBound(Val);
		}
	}

	// Iterate over each color interpolation
	for(int32 InterpIdx=0; InterpIdx<InterpLinearColors.Num(); InterpIdx++)
	{
		FTimelineLinearColorTrack& ColorEntry = InterpLinearColors[InterpIdx];
		if ( ColorEntry.LinearColorCurve && (ColorEntry.InterpFunc.IsBound() || ColorEntry.LinearColorPropertyName != NAME_None || ColorEntry.InterpFuncStatic.IsBound()) )
		{
			// Get vector from curve
			const FLinearColor Color = ColorEntry.LinearColorCurve->GetLinearColorValue(Position);

			// Pass vec to specified function
			ColorEntry.InterpFunc.ExecuteIfBound(Color);

			// Set vector property
			if (PropSetObject)
			{
				if (ColorEntry.LinearColorProperty == NULL)
				{
					ColorEntry.LinearColorProperty = FindField<UStructProperty>(PropSetObject->GetClass(), ColorEntry.LinearColorPropertyName);
					if(ColorEntry.LinearColorProperty == NULL)
					{
						UE_LOG(LogTimeline, Log, TEXT("SetPlaybackPosition: No linear color property '%s' in '%s'"), *ColorEntry.LinearColorPropertyName.ToString(), *PropSetObject->GetName());
					}
				}
				if (ColorEntry.LinearColorProperty)
				{
					*ColorEntry.LinearColorProperty->ContainerPtrToValuePtr<FLinearColor>(PropSetObject) = Color;
				}
			}

			// Pass vec to non-dynamic version of the specified function
			ColorEntry.InterpFuncStatic.ExecuteIfBound(Color);
		}
	}

	if(DirectionPropertyName != NAME_None)
	{
		if (PropSetObject)
		{
			if (DirectionProperty == NULL)
			{
				DirectionProperty = FindField<UByteProperty>(PropSetObject->GetClass(), DirectionPropertyName);
				if (DirectionProperty == NULL)
				{
					UE_LOG(LogTimeline, Log, TEXT("SetPlaybackPosition: No direction property '%s' in '%s'"), *DirectionPropertyName.ToString(), *PropSetObject->GetName());
				}
			}
			if (DirectionProperty)
			{
				const ETimelineDirection::Type CurrentDirection = bReversePlayback ? ETimelineDirection::Backward : ETimelineDirection::Forward;
				TEnumAsByte<ETimelineDirection::Type> ValueAsByte(CurrentDirection);
				DirectionProperty->SetPropertyValue_InContainer(PropSetObject, ValueAsByte);
			}
		}
	}

	// Execute the delegate to say that all properties are updated
	TimelinePostUpdateFunc.ExecuteIfBound();
}
static void	FindInvalidScalableFloats(const TArray<FString>& Args, bool ShowCoeffecients)
{
	GCurrentBadScalableFloatList.Empty();

	TArray<UClass*>	ClassesWithScalableFloats;
	for (TObjectIterator<UClass> ClassIt; ClassIt; ++ClassIt)
	{
		UClass* ThisClass = *ClassIt;
		if (FindClassesWithScalableFloat_r(Args, ThisClass, ThisClass))
		{
			ClassesWithScalableFloats.Add(ThisClass);
			ABILITY_LOG(Warning, TEXT("Class has scalable float: %s"), *ThisClass->GetName());
		}
	}

	for (UClass* ThisClass : ClassesWithScalableFloats)
	{
		UObjectLibrary* ObjLibrary = nullptr;
		TArray<FAssetData> AssetDataList;
		TArray<FString> Paths;
		Paths.Add(TEXT("/Game/"));

		{
			FString PerfMessage = FString::Printf(TEXT("Loading %s via ObjectLibrary"), *ThisClass->GetName() );
			SCOPE_LOG_TIME_IN_SECONDS(*PerfMessage, nullptr)
			ObjLibrary = UObjectLibrary::CreateLibrary(ThisClass, true, true);

			ObjLibrary->LoadBlueprintAssetDataFromPaths(Paths, true);
			ObjLibrary->LoadAssetsFromAssetData();
			ObjLibrary->GetAssetDataList(AssetDataList);

			ABILITY_LOG( Warning, TEXT("Found: %d %s assets."), AssetDataList.Num(), *ThisClass->GetName());
		}


		for (FAssetData Data: AssetDataList)
		{
			UPackage* ThisPackage = Data.GetPackage();
			UBlueprint* ThisBlueprint =  CastChecked<UBlueprint>(Data.GetAsset());
			UClass* AssetClass = ThisBlueprint->GeneratedClass;
			UObject* ThisCDO = AssetClass->GetDefaultObject();		
		
			FString PathName = ThisCDO->GetName();
			PathName.RemoveFromStart(TEXT("Default__"));

			GCurrentBadScalableFloat.Asset = ThisCDO;
			
						
			//ABILITY_LOG( Warning, TEXT("Asset: %s "), *PathName	);
			CheckForBadScalableFloats_r(ThisCDO, AssetClass, AssetClass);
		}
	}


	ABILITY_LOG( Error, TEXT(""));
	ABILITY_LOG( Error, TEXT(""));

	if (ShowCoeffecients == false)
	{

		for ( FBadScalableFloat& BadFoo : GCurrentBadScalableFloatList)
		{
			ABILITY_LOG( Error, TEXT(", %s, %s, %s,"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String );

		}

		ABILITY_LOG( Error, TEXT(""));
		ABILITY_LOG( Error, TEXT("%d Errors total"), GCurrentBadScalableFloatList.Num() );
	}
	else
	{
		ABILITY_LOG( Error, TEXT("Non 1 coefficients: "));

		for ( FBadScalableFloat& BadFoo : GCurrentNaughtyScalableFloatList)
		{
			ABILITY_LOG( Error, TEXT(", %s, %s, %s"), *BadFoo.Asset->GetFullName(), *BadFoo.Property->GetFullName(), *BadFoo.String );

		}
	}
}
Example #25
0
/**
 *	Assigns the given UObject the give NetNetworkGUID.
 */
FNetworkGUID UPackageMap::AssignNetGUID(const UObject* Object, FNetworkGUID NewNetworkGUID)
{
	if (NewNetworkGUID.IsDefault())
	{
		// This is the default NetGUID, look up or generate a real one
		NewNetworkGUID = Cache->NetGUIDLookup.FindRef(Object);
		if (!NewNetworkGUID.IsValid())
		{
			NewNetworkGUID = AssignNewNetGUID(Object);
		}
		HandleUnAssignedObject(Object);
		return NewNetworkGUID;
	}

	UE_LOG(LogNetPackageMap, Log, TEXT("Assigning %s NetGUID <%s>"), Object ? *Object->GetName() : TEXT("NULL"), *NewNetworkGUID.ToString() );
	
	// Check for reassignment: this can happen during seamless travel, so leaving this off for now, but is useful for debugging purposes, so leaving it in.
#if 0
	{
		FNetworkGUID OldNetGUID = Cache->NetGUIDLookup.FindRef(Object);
		if (OldNetGUID.IsValid() && !OldNetGUID.IsDefault())
		{
			UE_LOG(LogNetPackageMap, Log, TEXT("Attempting to reassign NetGUID to %s (was previously <%s>. Now is <%s>"), Object ? *Object->GetName() : TEXT("NULL"), *OldNetGUID.ToString(),  *NewNetworkGUID.ToString() );
		}

		UObject *OldObject = Cache->ObjectLookup.FindRef(NewNetworkGUID).Get();
		if (OldObject)
		{
			UE_LOG(LogNetPackageMap, Warning, TEXT("Attempting to reassign NetGUID <%s> to %s (It is already assigned to object %s"), *NewNetworkGUID.ToString(), Object ? *Object->GetName() : TEXT("NULL"), *OldNetGUID.ToString(), *OldObject->GetName() );
		}
	}
#endif

	// Actually assign
	FNetGuidCacheObject CacheObject;

	CacheObject.Object = Object;
	CacheObject.FullPath = Object->GetPathName();

	// Remove any existing entries
	{
		FNetGuidCacheObject* ExistingCacheObjectPtr = Cache->ObjectLookup.Find( NewNetworkGUID );
		if ( ExistingCacheObjectPtr )
		{
			const FNetGuidCacheObject& ExistingCacheObject = *ExistingCacheObjectPtr;
			Cache->NetGUIDLookup.Remove( ExistingCacheObject.Object );
		}

		FNetworkGUID* ExistingNetworkGUIDPtr = Cache->NetGUIDLookup.Find( Object );
		if ( ExistingNetworkGUIDPtr )
		{
			const FNetworkGUID& ExistingNetworkGUID = *ExistingNetworkGUIDPtr;
			Cache->ObjectLookup.Remove( ExistingNetworkGUID );
		}
	}

	Cache->ObjectLookup.Add( NewNetworkGUID, CacheObject );
	Cache->NetGUIDLookup.Add(Object, NewNetworkGUID);

#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
	Cache->History.Add(NewNetworkGUID, Object ? Object->GetPathName() : TEXT("NULL"));
#endif

	return NewNetworkGUID;
}
Example #26
0
UObject * UPackageMap::GetObjectFromNetGUID( FNetworkGUID NetGUID )
{
	if ( !ensure( NetGUID.IsValid() ) )
	{
		return NULL;
	}

	if ( !ensure( !NetGUID.IsDefault() ) )
	{
		return NULL;
	}

	FNetGuidCacheObject * CacheObjectPtr = Cache->ObjectLookup.Find( NetGUID );

	if ( CacheObjectPtr == NULL )
	{
		// We don't have the object mapped yet
		return NULL;
	}

	UObject * Object = CacheObjectPtr->Object.Get();

	if ( Object != NULL )
	{
		check( Object->GetPathName() == CacheObjectPtr->FullPath );
		return Object;
	}

	if ( CacheObjectPtr->FullPath.IsEmpty() )
	{
		// This probably isn't possible, but making it a warning
		UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: No full path for %s" ), *NetGUID.ToString() );
		return NULL;
	}

	if ( NetGUID.IsDynamic() )
	{
		// Dynamic objects don't have stable names, so we can't possibly reload the same object
		UE_LOG( LogNetPackageMap, VeryVerbose, TEXT( "GetObjectFromNetGUID: Cannot re-create dynamic object after GC <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath );
		return NULL;
	}

	//
	// The object was previously mapped, but we GC'd it
	// We need to reload it now
	//

	Object = StaticFindObject( UObject::StaticClass(), NULL, *CacheObjectPtr->FullPath, false );

	if ( Object == NULL )
	{
		if ( IsNetGUIDAuthority() )
		{
			// The authority shouldn't be loading resources on demand, at least for now.
			// This could be garbage or a security risk
			// Another possibility is in dynamic property replication if the server reads the previously serialized state
			// that has a now destroyed actor in it.
			UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: Could not find Object for: NetGUID <%s, %s> (and IsNetGUIDAuthority())" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath );
			return NULL;
		}
		else
		{
			UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: Could not find Object for: NetGUID <%s, %s>"), *NetGUID.ToString(), *CacheObjectPtr->FullPath );
		}

		Object = StaticLoadObject( UObject::StaticClass(), NULL, *CacheObjectPtr->FullPath, NULL, LOAD_NoWarn );

		if ( Object )
		{
			UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: StaticLoadObject. Found: %s" ), Object ? *Object->GetName() : TEXT( "NULL" ) );
		}
		else
		{
			Object = LoadPackage( NULL, *CacheObjectPtr->FullPath, LOAD_None );
			UE_LOG( LogNetPackageMap, Log, TEXT( "GetObjectFromNetGUID: LoadPackage. Found: %s" ), Object ? *Object->GetName() : TEXT( "NULL" ) );
		}
	}
	else
	{
		// If we actually found the object, we probably shouldn't have GC'd it, so that's odd
		UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: Object should not be found after GC: <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath );
	}

	if ( Object == NULL )
	{
		// If we get here, that means we have an invalid path, which shouldn't be possible, but making it a warning
		UE_LOG( LogNetPackageMap, Warning, TEXT( "GetObjectFromNetGUID: FAILED to re-create object after GC: <%s, %s>" ), *NetGUID.ToString(), *CacheObjectPtr->FullPath );
	}
	else
	{
		// Reassign the object pointer for quick access next time
		CacheObjectPtr->Object = Object;		
		// Make sure the object is in the GUIDToObjectLookup.
		Cache->NetGUIDLookup.Add( Object, NetGUID );
	}

	return Object;
}
FText SComponentClassCombo::GetFriendlyComponentName(FComponentClassComboEntryPtr Entry) const
{
	// Get a user friendly string from the component name
	FString FriendlyComponentName;

	if( Entry->GetComponentCreateAction() == EComponentCreateAction::CreateNewCPPClass )
	{
		FriendlyComponentName = LOCTEXT("NewCPPComponentFriendlyName", "New C++ Component...").ToString();
	}
	else if (Entry->GetComponentCreateAction() == EComponentCreateAction::CreateNewBlueprintClass )
	{
		FriendlyComponentName = LOCTEXT("NewBlueprintComponentFriendlyName", "New Blueprint Script Component...").ToString();
	}
	else
	{
		FriendlyComponentName = GetSanitizedComponentName(Entry);

		// Don't try to match up assets for USceneComponent it will match lots of things and doesn't have any nice behavior for asset adds 
		if (Entry->GetComponentClass() != USceneComponent::StaticClass() && Entry->GetComponentNameOverride().IsEmpty())
		{
			// Search the selected assets and look for any that can be used as a source asset for this type of component
			// If there is one we append the asset name to the component name, if there are many we append "Multiple Assets"
			FString AssetName;
			UObject* PreviousMatchingAsset = NULL;

			FEditorDelegates::LoadSelectedAssetsIfNeeded.Broadcast();
			USelection* Selection = GEditor->GetSelectedObjects();
			for(FSelectionIterator ObjectIter(*Selection); ObjectIter; ++ObjectIter)
			{
				UObject* Object = *ObjectIter;
				UClass* Class = Object->GetClass();

				TArray<TSubclassOf<UActorComponent> > ComponentClasses = FComponentAssetBrokerage::GetComponentsForAsset(Object);
				for(int32 ComponentIndex = 0; ComponentIndex < ComponentClasses.Num(); ComponentIndex++)
				{
					if(ComponentClasses[ComponentIndex]->IsChildOf(Entry->GetComponentClass()))
					{
						if(AssetName.IsEmpty())
						{
							// If there is no previous asset then we just accept the name
							AssetName = Object->GetName();
							PreviousMatchingAsset = Object;
						}
						else
						{
							// if there is a previous asset then check that we didn't just find multiple appropriate components
							// in a single asset - if the asset differs then we don't display the name, just "Multiple Assets"
							if(PreviousMatchingAsset != Object)
							{
								AssetName = LOCTEXT("MultipleAssetsForComponentAnnotation", "Multiple Assets").ToString();
								PreviousMatchingAsset = Object;
							}
						}
					}
				}
			}

			if(!AssetName.IsEmpty())
			{
				FriendlyComponentName += FString(" (") + AssetName + FString(")");
			}
		}
	}
	return FText::FromString(FriendlyComponentName);
}
Example #28
0
		FORCEINLINE bool operator()( UObject& A, UObject& B ) const
		{
			return A.GetName() < B.GetName();
		}
void FBlueprintCompileReinstancer::VerifyReplacement()
{
	TArray<UObject*> SourceObjects;

	// Find all instances of the old class
	for( TObjectIterator<UObject> it; it; ++it )
	{
		UObject* CurrentObj = *it;

		if( (CurrentObj->GetClass() == DuplicatedClass) )
		{
			SourceObjects.Add(CurrentObj);
		}
	}

	// For each instance, track down references
	if( SourceObjects.Num() > 0 )
	{
		TFindObjectReferencers<UObject> Referencers(SourceObjects, NULL, false);
		for (TFindObjectReferencers<UObject>::TIterator It(Referencers); It; ++It)
		{
			UObject* CurrentObject = It.Key();
			UObject* ReferencedObj = It.Value();
			FPlatformMisc::LowLevelOutputDebugStringf(TEXT("- Object %s is referencing %s ---"), *CurrentObject->GetName(), *ReferencedObj->GetName());
		}
	}
}
Example #30
0
bool FObjectReplicator::ReceivedBunch( FInBunch& Bunch, const FReplicationFlags& RepFlags, bool& bOutHasUnmapped )
{
	UObject* Object = GetObject();

	if ( Object == NULL )
	{
		UE_LOG(LogNet, Verbose, TEXT("ReceivedBunch: Object == NULL"));
		return false;
	}

	UPackageMap * PackageMap = OwningChannel->Connection->PackageMap;

	const bool bIsServer = ( OwningChannel->Connection->Driver->ServerConnection == NULL );

	const FClassNetCache * ClassCache = OwningChannel->Connection->Driver->NetCache->GetClassNetCache( ObjectClass );

	if ( ClassCache == NULL )
	{
		UE_LOG(LogNet, Error, TEXT("ReceivedBunch: ClassCache == NULL: %s"), *Object->GetFullName());
		return false;
	}

	bool bThisBunchReplicatedProperties = false;

	// Read first field
	const FFieldNetCache * FieldCache = ReadField( ClassCache, Bunch );

	if ( Bunch.IsError() )
	{
		UE_LOG(LogNet, Error, TEXT("ReceivedBunch: Error reading field 1: %s"), *Object->GetFullName());
		return false;
	}

	if ( FieldCache == NULL )
	{
		// There are no actual replicated properties or functions in this bunch. That is ok - we may have gotten this
		// actor/sub-object because we want the client to spawn one (but we aren't actually replicating properties on it)
		return true;
	}

	while ( FieldCache )
	{
		// Receive properties from the net.
		UProperty* ReplicatedProp = NULL;

		while ( FieldCache && ( ReplicatedProp = Cast< UProperty >( FieldCache->Field ) ) != NULL )
		{
			NET_CHECKSUM( Bunch );

			// Server shouldn't receive properties.
			if ( bIsServer )
			{
				UE_LOG(LogNet, Error, TEXT("Server received unwanted property value %s in %s"), *ReplicatedProp->GetName(), *Object->GetFullName());
				return false;
			}
		
			bThisBunchReplicatedProperties = true;

			if ( !bHasReplicatedProperties )
			{
				bHasReplicatedProperties = true;		// Persistent, not reset until PostNetReceive is called
				PreNetReceive();
			}

			bool DebugProperty = false;
#if !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
			{
				static IConsoleVariable* CVar = IConsoleManager::Get().FindConsoleVariable(TEXT("net.Replication.DebugProperty"));
				if (CVar && !CVar->GetString().IsEmpty() && ReplicatedProp->GetName().Contains(CVar->GetString()) )
				{
					UE_LOG(LogRep, Log, TEXT("Replicating Property[%d] %s on %s"), ReplicatedProp->RepIndex, *ReplicatedProp->GetName(), *Object->GetName());
					DebugProperty = true;
				}
			}
#endif
			if ( !Retirement[ ReplicatedProp->RepIndex ].CustomDelta )
			{
				bool bLocalHasUnmapped = false;
				// We hijack a non custom delta property to signify we are using FRepLayout to read the entire property block
				if ( !RepLayout->ReceiveProperties( ObjectClass, RepState, (void*)Object, Bunch, bLocalHasUnmapped ) )
				{
					UE_LOG(LogRep, Error, TEXT("ReceiveProperties FAILED %s in %s"), *ReplicatedProp->GetName(), *Object->GetFullName());
					return false;
				}

				if ( bLocalHasUnmapped )
				{
					bOutHasUnmapped = true;
				}
			}
			else
			{
				// Receive array index.
				uint32 Element = 0;
				if ( ReplicatedProp->ArrayDim != 1 )
				{
					check( ReplicatedProp->ArrayDim >= 2 );

					Bunch.SerializeIntPacked( Element );

					if ( Element >= (uint32)ReplicatedProp->ArrayDim )
					{
						UE_LOG(LogRep, Error, TEXT("Element index too large %s in %s"), *ReplicatedProp->GetName(), *Object->GetFullName());
						return false;
					}
				}

				// Pointer to destination.
				uint8* Data = ReplicatedProp->ContainerPtrToValuePtr<uint8>((uint8*)Object, Element);
				TArray<uint8>	MetaData;
				const PTRINT DataOffset = Data - (uint8*)Object;

				// Receive custom delta property.
				UStructProperty * StructProperty = Cast< UStructProperty >( ReplicatedProp );

				if ( StructProperty == NULL )
				{
					// This property isn't custom delta
					UE_LOG(LogRepTraffic, Error, TEXT("Property isn't custom delta %s"), *ReplicatedProp->GetName());
					return false;
				}

				UScriptStruct * InnerStruct = StructProperty->Struct;

				if ( !( InnerStruct->StructFlags & STRUCT_NetDeltaSerializeNative ) )
				{
					// This property isn't custom delta
					UE_LOG(LogRepTraffic, Error, TEXT("Property isn't custom delta %s"), *ReplicatedProp->GetName());
					return false;
				}

				UScriptStruct::ICppStructOps * CppStructOps = InnerStruct->GetCppStructOps();

				check( CppStructOps );
				check( !InnerStruct->InheritedCppStructOps() );

				FNetDeltaSerializeInfo Parms;

				FNetSerializeCB NetSerializeCB( OwningChannel->Connection->Driver );

				Parms.DebugName			= StructProperty->GetName();
				Parms.Struct			= InnerStruct;
				Parms.Map				= PackageMap;
				Parms.Reader			= &Bunch;
				Parms.NetSerializeCB	= &NetSerializeCB;

				// Call the custom delta serialize function to handle it
				CppStructOps->NetDeltaSerialize( Parms, Data );

				if ( Bunch.IsError() )
				{
					UE_LOG(LogNet, Error, TEXT("ReceivedBunch: NetDeltaSerialize - Bunch.IsError() == true: %s"), *Object->GetFullName());
					return false;
				}

				if ( Parms.bOutHasMoreUnmapped )
				{
					UnmappedCustomProperties.Add( DataOffset, StructProperty );
					bOutHasUnmapped = true;
				}

				// Successfully received it.
				UE_LOG(LogRepTraffic, Log, TEXT(" %s - %s"), *Object->GetName(), *ReplicatedProp->GetName());

				// Notify the Object if this var is RepNotify
				QueuePropertyRepNotify( Object, ReplicatedProp, Element, MetaData );
			}	
			
			// Read next field
			FieldCache = ReadField( ClassCache, Bunch );

			if ( Bunch.IsError() )
			{
				UE_LOG(LogNet, Error, TEXT("ReceivedBunch: Error reading field 2: %s"), *Object->GetFullName());
				return false;
			}
		}

		// Handle function calls.
		if ( FieldCache && Cast< UFunction >( FieldCache->Field ) )
		{
			FName Message = FieldCache->Field->GetFName();
			UFunction * Function = Object->FindFunction( Message );

			if ( Function == NULL )
			{
				UE_LOG(LogNet, Error, TEXT("ReceivedBunch: Function == NULL: %s"), *Object->GetFullName());
				return false;
			}

			if ( ( Function->FunctionFlags & FUNC_Net ) == 0 )
			{
				UE_LOG(LogRep, Error, TEXT("Rejected non RPC function %s in %s"), *Message.ToString(), *Object->GetFullName());
				return false;
			}

			if ( ( Function->FunctionFlags & ( bIsServer ? FUNC_NetServer : ( FUNC_NetClient | FUNC_NetMulticast ) ) ) == 0 )
			{
				UE_LOG(LogRep, Error, TEXT("Rejected RPC function due to access rights %s in %s"), *Message.ToString(), *Object->GetFullName());
				return false;
			}

			UE_LOG(LogRepTraffic, Log, TEXT("      Received RPC: %s"), *Message.ToString());

			// Get the parameters.
			FMemMark Mark(FMemStack::Get());
			uint8* Parms = new(FMemStack::Get(),MEM_Zeroed,Function->ParmsSize)uint8;

			// Use the replication layout to receive the rpc parameter values
			TSharedPtr<FRepLayout> FuncRepLayout = OwningChannel->Connection->Driver->GetFunctionRepLayout( Function );

			FuncRepLayout->ReceivePropertiesForRPC( Object, Function, OwningChannel, Bunch, Parms );

			if ( Bunch.IsError() )
			{
				UE_LOG(LogRep, Error, TEXT("ReceivedBunch: ReceivePropertiesForRPC - Bunch.IsError() == true: Function: %s, Object: %s"), *Message.ToString(), *Object->GetFullName());
				return false;
			}

			// validate that the function is callable here
			const bool bCanExecute = ( !bIsServer || RepFlags.bNetOwner );		// we are client or net owner

			if ( bCanExecute )
			{
				// Call the function.
				RPC_ResetLastFailedReason();

				Object->ProcessEvent( Function, Parms );

				if ( RPC_GetLastFailedReason() != NULL )
				{
					UE_LOG(LogRep, Error, TEXT("ReceivedBunch: RPC_GetLastFailedReason: %s"), RPC_GetLastFailedReason());
					return false;
				}
			}
			else
			{
				UE_LOG(LogRep, Verbose, TEXT("Rejected unwanted function %s in %s"), *Message.ToString(), *Object->GetFullName());

				if ( !OwningChannel->Connection->TrackLogsPerSecond() )	// This will disconnect the client if we get here too often
				{
					UE_LOG(LogRep, Error, TEXT("Rejected too many unwanted functions %s in %s"), *Message.ToString(), *Object->GetFullName());
					return false;
				}
			}

			// Destroy the parameters.
			//warning: highly dependent on UObject::ProcessEvent freeing of parms!
			for ( UProperty * Destruct=Function->DestructorLink; Destruct; Destruct=Destruct->DestructorLinkNext )
			{
				if( Destruct->IsInContainer(Function->ParmsSize) )
				{
					Destruct->DestroyValue_InContainer(Parms);
				}
			}

			Mark.Pop();

			if ( Object == NULL || Object->IsPendingKill() )
			{
				// replicated function destroyed Object
				return true;		// FIXME: Should this return false to kick connection?  Seems we'll cause a read misalignment here if we don't
			}

			// Next.
			FieldCache = ReadField( ClassCache, Bunch );

			if ( Bunch.IsError() )
			{
				UE_LOG(LogNet, Error, TEXT("ReceivedBunch: Error reading field 3: %s"), *Object->GetFullName());
				return false;
			}
		}
		else if ( FieldCache )
		{
			UE_LOG(LogRep, Error, TEXT("ReceivedBunch: Invalid replicated field %i in %s"), FieldCache->FieldNetIndex, *Object->GetFullName());
			return false;
		}
	}

	return true;
}