//------------------------------------------------------------------------------
static int32 GetHiddenProperties(uint32 Indent, UClass* Class, FString& JsonOut)
{
	int32 HiddenPropCount = 0;

	FString IndentString = GetIndentString(Indent);
	JsonOut += IndentString + TEXT("\"HiddenProperties\" : [");

	for (TFieldIterator<UProperty> PropertyIt(Class, EFieldIteratorFlags::IncludeSuper); PropertyIt; ++PropertyIt)
	{
		UProperty* Property = *PropertyIt;
		if (FObjectEditorUtils::IsVariableCategoryHiddenFromClass(Property, Class))
		{
			++HiddenPropCount;
			JsonOut += TEXT("\n\t") + IndentString + TEXT("\"") + Property->GetPathName() + TEXT("\",");
		}
	}
	if (HiddenPropCount > 0)
	{
		JsonOut.RemoveAt(JsonOut.Len() - 1); // remove the last comma
	}
	JsonOut += TEXT("\n") + IndentString + TEXT("]");

	return HiddenPropCount;
}
Esempio n. 2
0
bool FJsonObjectConverter::UStructToJsonObject(const UStruct* StructDefinition, const void* Struct, TSharedRef<FJsonObject> OutJsonObject, int64 CheckFlags, int64 SkipFlags)
{
	for(TFieldIterator<UProperty> It(StructDefinition); It; ++It)
	{
		UProperty* Property = *It;

		// Check to see if we should ignore this property
		if (CheckFlags != 0 && !Property->HasAnyPropertyFlags(CheckFlags))
		{
			continue;
		}
		if (Property->HasAnyPropertyFlags(SkipFlags))
		{
			continue;
		}

		FString VariableName = StandardizeCase(Property->GetName());
		const void* Value = Property->ContainerPtrToValuePtr<uint8>(Struct);

		// convert the property to a FJsonValue
		TSharedPtr<FJsonValue> JsonValue = UPropertyToJsonValue(Property, Value, CheckFlags, SkipFlags);
		if (!JsonValue.IsValid())
		{
			UClass* PropClass = Property->GetClass();
			UE_LOG(LogJson, Error, TEXT("UStructToJsonObject - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
			return false;
		}

		// set the value on the output object
		OutJsonObject->SetField(VariableName, JsonValue);
	}

	return true;
}
/**
 * Deserialize the data contained within a message using the parameter fields of a given UStruct 
 * @param Message message containing the data to retrieve
 * @param Object structure containing reflection information that matches message
 * @param Parms memory layout to store the message's data
 * @param PropFlags any flags relevant to the field iteration
 *
 * @return TRUE if successful, FALSE otherwise
 */
bool DeserializeRPCParams(const google::protobuf::Message* Message, UStruct* Object, void* Parms, int64 PropFlags)
{
	bool bSuccess = true;
	const google::protobuf::Descriptor* Desc = Message->GetDescriptor();
	const google::protobuf::Reflection* Refl = Message->GetReflection();

	for(TFieldIterator<UProperty> It(Object); It && (It->PropertyFlags & PropFlags); ++It)
	{
		UProperty* Property = *It;
		UClass* PropClass = Property->GetClass();
		const google::protobuf::FieldDescriptor* FieldDesc = Desc->FindFieldByName(TCHAR_TO_UTF8(*Property->GetNameCPP()));
		if (FieldDesc)
		{
			if (FieldDesc->is_repeated())
			{
				int32 NumElements = Refl->FieldSize(*Message, FieldDesc);
				FScriptArrayHelper* ArrayHelper = NULL;
				if (PropClass == UArrayProperty::StaticClass())
				{
					void* Value = Property->ContainerPtrToValuePtr<uint8>(Parms);
					UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
					Property = ArrayProperty->Inner;
					PropClass = Property->GetClass();

					ArrayHelper = new FScriptArrayHelper(ArrayProperty, Value);
					ArrayHelper->EmptyAndAddValues(NumElements);
				}
				else
				{
					if (Property->ArrayDim < NumElements)
					{
						UE_LOG_ONLINE(Error, TEXT("DeserializeRPCParams - Static array mismatch (%d != %d) property type '%s': %s"), NumElements, Property->ArrayDim, *PropClass->GetName(), *Property->GetPathName());
						NumElements = Property->ArrayDim;
					}
				}

				for (int32 i = 0; i < NumElements; i++)
				{
					void* Value = ArrayHelper ? ArrayHelper->GetRawPtr(i) : Property->ContainerPtrToValuePtr<uint8>(Parms, i);
					if (PropClass == UIntProperty::StaticClass())
					{
						*(int32*)Value = Refl->GetRepeatedInt32(*Message, FieldDesc, i);
					}
					else if (PropClass == UFloatProperty::StaticClass())
					{
						*(float*)Value = Refl->GetRepeatedFloat(*Message, FieldDesc, i);
					}
					else if (PropClass == UBoolProperty::StaticClass() && CastChecked<UBoolProperty>(Property)->IsNativeBool())
					{
						*(bool*)Value = Refl->GetRepeatedBool(*Message, FieldDesc, i);
					}
					else if (PropClass == UByteProperty::StaticClass() && CastChecked<UByteProperty>(Property)->Enum == NULL)
					{
						const google::protobuf::string& String = Refl->GetRepeatedStringReference(*Message, FieldDesc, i, NULL);
						if (ArrayHelper)
						{
							// Message only contains one string, but we need an array of bytes
							ArrayHelper->AddValues(String.size() - 1);
							Value = ArrayHelper->GetRawPtr(i);
						}

						FMemory::Memcpy(Value, String.c_str(), String.size());
						break;
					}
					else if (PropClass == UStrProperty::StaticClass())
					{
						const google::protobuf::string& String = Refl->GetRepeatedStringReference(*Message, FieldDesc, i, NULL);
						*(FString*)Value = UTF8_TO_TCHAR(String.c_str());
					}
					else if (PropClass == UStructProperty::StaticClass())
					{
						UStructProperty* StructProperty = Cast<UStructProperty>(Property);
						const google::protobuf::Message& SubMessage = Refl->GetRepeatedMessage(*Message, FieldDesc, i);
						DeserializeRPCParams(&SubMessage, StructProperty->Struct, Value, CPF_AllFlags);
					}
					else
					{
						bSuccess = false;
						UE_LOG_ONLINE(Error, TEXT("DeserializeRPCParams - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
					}
				}

				if (ArrayHelper)
				{
					delete ArrayHelper;
				}
			}
			else
			{
				if (Property->ArrayDim == 1)
				{
					void* Value = Property->ContainerPtrToValuePtr<uint8>(Parms);
					if (PropClass == UIntProperty::StaticClass())
					{
						*(int32*)Value = Refl->GetInt32(*Message, FieldDesc);
					}
					else if (PropClass == UFloatProperty::StaticClass())
					{
						*(float*)Value = Refl->GetFloat(*Message, FieldDesc);
					}
					else if (PropClass == UBoolProperty::StaticClass() && CastChecked<UBoolProperty>(Property)->IsNativeBool())
					{
						*(bool*)Value = Refl->GetBool(*Message, FieldDesc);
					}
					else if (PropClass == UByteProperty::StaticClass() && CastChecked<UByteProperty>(Property)->Enum == NULL)
					{
						int32 NumBytes = Refl->FieldSize(*Message, FieldDesc);
						google::protobuf::string Bytes = Refl->GetString(*Message, FieldDesc);
						FMemory::Memcpy(Value, Bytes.c_str(), NumBytes);
					}
					else if (PropClass == UStrProperty::StaticClass())
					{
						google::protobuf::string String = Refl->GetString(*Message, FieldDesc);
						*(FString*)Value = UTF8_TO_TCHAR(String.c_str());
					}
					else if (PropClass == UStructProperty::StaticClass())
					{
						UStructProperty* StructProperty = Cast<UStructProperty>(Property);
						const google::protobuf::Message& SubMessage = Refl->GetMessage(*Message, FieldDesc);
						DeserializeRPCParams(&SubMessage, StructProperty->Struct, Value, CPF_AllFlags);
					}
					else
					{
						bSuccess = false;
						UE_LOG_ONLINE(Error, TEXT("DeserializeRPCParams - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
					}
				}
				else
				{
					bSuccess = false;
					UE_LOG_ONLINE(Error, TEXT("DeserializeRPCParams - Property reflection mismatch type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
				}
			}
		}
		else
		{
			bSuccess = false;
			UE_LOG_ONLINE(Error, TEXT("DeserializeRPCParams - Property reflection missing type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
		}
	}

	return bSuccess;
}
/**
 * Serialize the parameter fields of a given UStruct into a message object
 * @param NewMessage message to fill
 * @param Object structure containing reflection information that matches message
 * @param Parms data to serialize into the new message
 * @param PropFlags any flags relevant to the field iteration
 *
 * @return TRUE if successful, FALSE otherwise
 */
bool SerializeRPCParams(google::protobuf::Message* NewMessage, UStruct* Object, void* Parms, int64 PropFlags)
{
	bool bSuccess = true;
	const google::protobuf::Descriptor* Desc = NewMessage->GetDescriptor();
	const google::protobuf::Reflection* Refl = NewMessage->GetReflection();

	for(TFieldIterator<UProperty> It(Object); It && (It->PropertyFlags & PropFlags); ++It)
	{
		UProperty* Property = *It;
		UClass* PropClass = Property->GetClass();
		const google::protobuf::FieldDescriptor* FieldDesc = Desc->FindFieldByName(TCHAR_TO_UTF8(*Property->GetNameCPP()));
		if (FieldDesc)
		{
			if (FieldDesc->is_repeated())
			{
				int32 NumElements = Property->ArrayDim;
				FScriptArrayHelper* ArrayHelper = NULL;
				if (PropClass == UArrayProperty::StaticClass())
				{
					void* Value = Property->ContainerPtrToValuePtr<uint8>(Parms);
					UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
					Property = ArrayProperty->Inner;
					PropClass = Property->GetClass();

					ArrayHelper = new FScriptArrayHelper(ArrayProperty, Value);
					NumElements = ArrayHelper->Num();
				}

				for (int32 i = 0; i < NumElements; i++)
				{
					void* Value = ArrayHelper ? ArrayHelper->GetRawPtr(i) : Property->ContainerPtrToValuePtr<void>(Parms, i);
					if (PropClass == UIntProperty::StaticClass())
					{
						Refl->AddInt32(NewMessage, FieldDesc, *(int32*)Value);
					}
					else if (PropClass == UFloatProperty::StaticClass())
					{
						Refl->AddFloat(NewMessage, FieldDesc, *(float*)Value);
					}
					else if (PropClass == UBoolProperty::StaticClass() && CastChecked<UBoolProperty>(Property)->IsNativeBool())
					{
						Refl->AddBool(NewMessage, FieldDesc, *(bool*)Value);
					}
					else if (PropClass == UByteProperty::StaticClass() && CastChecked<UByteProperty>(Property)->Enum == NULL)
					{
						// All bytes are stored in a single string
						google::protobuf::string Bytes((ANSICHAR*)Value, NumElements);
						Refl->AddString(NewMessage, FieldDesc, Bytes);
						break;
					}
					else if (PropClass == UStrProperty::StaticClass())
					{
						Refl->AddString(NewMessage, FieldDesc, TCHAR_TO_UTF8(**(FString*)Value));
					}
					else if (PropClass == UStructProperty::StaticClass())
					{
						UStructProperty* StructProperty = Cast<UStructProperty>(Property);
						google::protobuf::Message* SubMessage = Refl->AddMessage(NewMessage, FieldDesc, NULL);
						SerializeRPCParams(SubMessage, StructProperty->Struct, Value, CPF_AllFlags);
					}
					else
					{
						bSuccess = false;
						UE_LOG_ONLINE(Error, TEXT("SerializeRPCParams - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
					}
				}

				if (ArrayHelper)
				{
					delete ArrayHelper;
				}
			}
			else
			{
				if (Property->ArrayDim == 1)
				{
					void* Value = Property->ContainerPtrToValuePtr<uint8>(Parms);
					if (PropClass == UIntProperty::StaticClass())
					{
						Refl->SetInt32(NewMessage, FieldDesc, *(int32*)Value);
					}
					else if (PropClass == UFloatProperty::StaticClass())
					{
						Refl->SetFloat(NewMessage, FieldDesc, *(float*)Value);
					}
					else if (PropClass == UBoolProperty::StaticClass() && CastChecked<UBoolProperty>(Property)->IsNativeBool())
					{
						Refl->SetBool(NewMessage, FieldDesc, *(bool*)Value);
					}
					else if (PropClass == UByteProperty::StaticClass() && CastChecked<UByteProperty>(Property)->Enum == NULL)
					{
						google::protobuf::string Bytes((ANSICHAR*)Value, 1);
						Refl->SetString(NewMessage, FieldDesc, Bytes);
					}
					else if (PropClass == UStrProperty::StaticClass())
					{
						Refl->SetString(NewMessage, FieldDesc, TCHAR_TO_UTF8(**(FString*)Value));
					}
					else if (PropClass == UStructProperty::StaticClass())
					{
						UStructProperty* StructProperty = Cast<UStructProperty>(Property);
						google::protobuf::Message* SubMessage = Refl->MutableMessage(NewMessage, FieldDesc, NULL);
						SerializeRPCParams(SubMessage, StructProperty->Struct, Value, CPF_AllFlags);
					}
					else
					{
						bSuccess = false;
						UE_LOG_ONLINE(Error, TEXT("SerializeRPCParams - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
					}
				}
				else
				{
					bSuccess = false;
					UE_LOG_ONLINE(Error, TEXT("SerializeRPCParams - Property reflection mismatch type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
				}
			}
		}
		else
		{
			bSuccess = false;
			UE_LOG_ONLINE(Error, TEXT("SerializeRPCParams - Property reflection missing type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
		}
	}

	return bSuccess;
}
	/**
	 * Creates a message definition for a group of properties
	 * @param MsgProtoDesc descriptor to fill with the definition
	 * @param FieldIt grouping of properties to define
	 * @param PropertyFlags flags properties must have to be considered for the message
	 *
	 * @return TRUE on successful creation, FALSE otherwise
	 */
	bool CreateProtoDeclaration(google::protobuf::DescriptorProto* MsgProtoDesc, UStruct* Object, uint64 PropertyFlags)
	{	
		bool bSuccess = true;
		int32 FieldIdx = 1;

		TFieldIterator<UProperty> FieldIt(Object);
		for(; FieldIt && (FieldIt->PropertyFlags & PropertyFlags); ++FieldIt)
		{
			UProperty* Property = *FieldIt;
			UClass* PropClass = Property->GetClass();

			if (PropClass != UInterfaceProperty::StaticClass() && PropClass != UObjectProperty::StaticClass())
			{
				bool bIsRepeated = false;
				UArrayProperty* ArrayProperty = Cast<UArrayProperty>(Property);
				if (ArrayProperty != NULL)
				{
					UClass* InnerPropClass = ArrayProperty->Inner->GetClass();
					if (InnerPropClass != UInterfaceProperty::StaticClass() && InnerPropClass != UObjectProperty::StaticClass())
					{
						Property = ArrayProperty->Inner;
						bIsRepeated = true;
					}
					else
					{
						UE_LOG_ONLINE(Error, TEXT("CreateProtoDeclaration - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
						bSuccess = false;
						break;
					}
				}
				else if(Property->ArrayDim != 1)
				{
					bIsRepeated = true;
				}

				FString SubMsgName;
				UStructProperty* StructProperty = Cast<UStructProperty>(Property);
				if (StructProperty != NULL)
				{
					FString TypeText, ExtendedTypeText;
					TypeText = Property->GetCPPType(&ExtendedTypeText, CPPF_None);

					google::protobuf::DescriptorProto* StructProtDesc = MsgProtoDesc->add_nested_type();
					SubMsgName = FString::Printf(TEXT("%s%sMessage"), *TypeText, *ExtendedTypeText);
					StructProtDesc->set_name(TCHAR_TO_UTF8(*SubMsgName));

					if (!CreateProtoDeclaration(StructProtDesc, StructProperty->Struct, CPF_AllFlags))
					{
						StructProtDesc->Clear();
						bSuccess = false;
						break;
					}
				}

				int32 Type = GetTypeFromProperty(Property);
				if (google::protobuf::FieldDescriptorProto_Type_IsValid(Type))
				{
					google::protobuf::FieldDescriptorProto* MsgFieldProto = MsgProtoDesc->add_field();
					MsgFieldProto->set_name(TCHAR_TO_UTF8(*Property->GetNameCPP()));
					MsgFieldProto->set_number(FieldIdx);
					MsgFieldProto->set_type((google::protobuf::FieldDescriptorProto_Type)Type);
					if (SubMsgName.Len() > 0)
					{
						MsgFieldProto->set_type_name(TCHAR_TO_UTF8(*SubMsgName));
					}
					if (bIsRepeated)
					{
						MsgFieldProto->set_label(google::protobuf::FieldDescriptorProto_Label_LABEL_REPEATED);
					}
					else
					{
						MsgFieldProto->set_label(google::protobuf::FieldDescriptorProto_Label_LABEL_OPTIONAL);
					}

					FieldIdx++;
				}
				else
				{
					UE_LOG_ONLINE(Error, TEXT("CreateProtoDeclaration - Unhandled property mapping '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
					bSuccess = false;
					break;
				}
			}
			else
			{
				UE_LOG_ONLINE(Error, TEXT("CreateProtoDeclaration - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
				bSuccess = false;
				break;
			}
		}

		return bSuccess;
	}
bool FJsonObjectConverter::UStructToJsonAttributes(const UStruct* StructDefinition, const void* Struct, TMap< FString, TSharedPtr<FJsonValue> >& OutJsonAttributes, int64 CheckFlags, int64 SkipFlags, const CustomExportCallback* ExportCb)
{
	if (SkipFlags == 0)
	{
		// If we have no specified skip flags, skip deprecated by default when writing
		SkipFlags |= CPF_Deprecated;
	}

	if (StructDefinition == FJsonObjectWrapper::StaticStruct())
	{
		// Just copy it into the object
		const FJsonObjectWrapper* ProxyObject = (const FJsonObjectWrapper *)Struct;

		if (ProxyObject->JsonObject.IsValid())
		{
			OutJsonAttributes = ProxyObject->JsonObject->Values;
		}
		return true;
	}

	for (TFieldIterator<UProperty> It(StructDefinition); It; ++It)
	{
		UProperty* Property = *It;

		// Check to see if we should ignore this property
		if (CheckFlags != 0 && !Property->HasAnyPropertyFlags(CheckFlags))
		{
			continue;
		}
		if (Property->HasAnyPropertyFlags(SkipFlags))
		{
			continue;
		}

		FString VariableName = StandardizeCase(Property->GetName());
		const void* Value = Property->ContainerPtrToValuePtr<uint8>(Struct);

		// convert the property to a FJsonValue
		TSharedPtr<FJsonValue> JsonValue = UPropertyToJsonValue(Property, Value, CheckFlags, SkipFlags, ExportCb);
		if (!JsonValue.IsValid())
		{
			UClass* PropClass = Property->GetClass();
			UE_LOG(LogJson, Error, TEXT("UStructToJsonObject - Unhandled property type '%s': %s"), *PropClass->GetName(), *Property->GetPathName());
			return false;
		}

		// set the value on the output object
		OutJsonAttributes.Add(VariableName, JsonValue);
	}

	return true;
}