/** * 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; }
void UConsole::BuildRuntimeAutoCompleteList(bool bForce) { #if !UE_BUILD_SHIPPING if (!bForce) { // unless forced delay updating until needed bIsRuntimeAutoCompleteUpToDate = false; return; } // clear the existing tree //@todo - probably only need to rebuild the tree + partial command list on level load for (int32 Idx = 0; Idx < AutoCompleteTree.ChildNodes.Num(); Idx++) { FAutoCompleteNode *Node = AutoCompleteTree.ChildNodes[Idx]; delete Node; } AutoCompleteTree.ChildNodes.Empty(); const UConsoleSettings* ConsoleSettings = GetDefault<UConsoleSettings>(); // copy the manual list first AutoCompleteList.Empty(); AutoCompleteList.AddZeroed(ConsoleSettings->ManualAutoCompleteList.Num()); for (int32 Idx = 0; Idx < ConsoleSettings->ManualAutoCompleteList.Num(); Idx++) { AutoCompleteList[Idx] = ConsoleSettings->ManualAutoCompleteList[Idx]; } // console variables { IConsoleManager::Get().ForEachConsoleObject( FConsoleObjectVisitor::CreateStatic< TArray<struct FAutoCompleteCommand>& >( &FConsoleVariableAutoCompleteVisitor::OnConsoleVariable, AutoCompleteList ) ); } // iterate through script exec functions and append to the list int32 ScriptExecCnt = 0; for (TObjectIterator<UFunction> It; It; ++It) { UFunction *Func = *It; // Determine whether or not this is a level script event that we can call (must be defined in the level script actor and not in parent, and has no return value) const UClass* FuncOuter = Cast<UClass>(Func->GetOuter()); const bool bIsLevelScriptFunction = FuncOuter && (FuncOuter->IsChildOf(ALevelScriptActor::StaticClass())) && (FuncOuter != ALevelScriptActor::StaticClass()) && (Func->ReturnValueOffset == MAX_uint16) && (Func->GetSuperFunction() == NULL); // exec functions that either have no parent, level script events, or are in the global state (filtering some unnecessary dupes) if ( (Func->HasAnyFunctionFlags(FUNC_Exec) && (Func->GetSuperFunction() == NULL || FuncOuter)) || bIsLevelScriptFunction) { FString FuncName = Func->GetName(); if(FDefaultValueHelper::HasWhitespaces(FuncName)) { FuncName = FString::Printf(TEXT("\"%s\""), *FuncName); } if( bIsLevelScriptFunction ) { FuncName = FString(TEXT("ce ")) + FuncName; } int32 NewIdx = AutoCompleteList.AddZeroed(1); AutoCompleteList[NewIdx].Command = FuncName; // build a help string // append each property (and it's type) to the help string for (TFieldIterator<UProperty> PropIt(Func); PropIt && (PropIt->PropertyFlags & CPF_Parm); ++PropIt) { UProperty *Prop = *PropIt; FuncName = FString::Printf(TEXT("%s %s[%s]"),*FuncName,*Prop->GetName(),*Prop->GetCPPType()); } AutoCompleteList[NewIdx].Desc = FuncName; ScriptExecCnt++; } } // enumerate maps TArray<FString> Packages; for (int32 PathIdx = 0; PathIdx < ConsoleSettings->AutoCompleteMapPaths.Num(); ++PathIdx) { FPackageName::FindPackagesInDirectory(Packages, FString::Printf(TEXT("%s%s"), *FPaths::GameDir(), *ConsoleSettings->AutoCompleteMapPaths[PathIdx])); } // also include maps in this user's developer dir FPackageName::FindPackagesInDirectory(Packages, FPaths::GameUserDeveloperDir()); for (int32 PackageIndex = 0; PackageIndex < Packages.Num(); PackageIndex++) { FString Pkg = Packages[PackageIndex]; int32 ExtIdx = Pkg.Find(*FPackageName::GetMapPackageExtension(),ESearchCase::IgnoreCase, ESearchDir::FromEnd); FString MapName; if (ExtIdx != INDEX_NONE && Pkg.Split(TEXT("/"),NULL,&MapName,ESearchCase::CaseSensitive, ESearchDir::FromEnd)) { // try to peel off the extension FString TrimmedMapName; if (!MapName.Split(TEXT("."),&TrimmedMapName,NULL,ESearchCase::CaseSensitive, ESearchDir::FromEnd)) { TrimmedMapName = MapName; } int32 NewIdx; // put _P maps at the front so that they match early, since those are generally the maps we want to actually open if (TrimmedMapName.EndsWith(TEXT("_P"))) { NewIdx = 0; AutoCompleteList.InsertZeroed(0,3); } else { NewIdx = AutoCompleteList.AddZeroed(3); } AutoCompleteList[NewIdx].Command = FString::Printf(TEXT("open %s"),*TrimmedMapName); AutoCompleteList[NewIdx].Desc = FString::Printf(TEXT("open %s"),*TrimmedMapName); AutoCompleteList[NewIdx+1].Command = FString::Printf(TEXT("travel %s"),*TrimmedMapName); AutoCompleteList[NewIdx+1].Desc = FString::Printf(TEXT("travel %s"),*TrimmedMapName); AutoCompleteList[NewIdx+2].Command = FString::Printf(TEXT("servertravel %s"),*TrimmedMapName); AutoCompleteList[NewIdx+2].Desc = FString::Printf(TEXT("servertravel %s"),*TrimmedMapName); //MapNames.AddItem(Pkg); } } // misc commands { int32 NewIdx = AutoCompleteList.AddZeroed(1); AutoCompleteList[NewIdx].Command = FString(TEXT("open 127.0.0.1")); AutoCompleteList[NewIdx].Desc = FString(TEXT("open 127.0.0.1 (opens connection to localhost)")); } #if STATS // stat commands { const TSet<FName>& StatGroupNames = FStatGroupGameThreadNotifier::Get().StatGroupNames; int32 NewIdx = AutoCompleteList.AddZeroed(StatGroupNames.Num()); for (const FName& StatGroupName : StatGroupNames) { FString Command = FString(TEXT("Stat ")); Command += StatGroupName.ToString().RightChop(sizeof("STATGROUP_") - 1); AutoCompleteList[NewIdx].Command = Command; AutoCompleteList[NewIdx].Desc = FString(); NewIdx++; } } #endif // build the magic tree! for (int32 ListIdx = 0; ListIdx < AutoCompleteList.Num(); ListIdx++) { FString Command = AutoCompleteList[ListIdx].Command.ToLower(); FAutoCompleteNode *Node = &AutoCompleteTree; for (int32 Depth = 0; Depth < Command.Len(); Depth++) { int32 Char = Command[Depth]; int32 FoundNodeIdx = INDEX_NONE; TArray<FAutoCompleteNode*> &NodeList = Node->ChildNodes; for (int32 NodeIdx = 0; NodeIdx < NodeList.Num(); NodeIdx++) { if (NodeList[NodeIdx]->IndexChar == Char) { FoundNodeIdx = NodeIdx; Node = NodeList[FoundNodeIdx]; NodeList[FoundNodeIdx]->AutoCompleteListIndices.Add(ListIdx); break; } } if (FoundNodeIdx == INDEX_NONE) { FAutoCompleteNode *NewNode = new FAutoCompleteNode(Char); NewNode->AutoCompleteListIndices.Add(ListIdx); Node->ChildNodes.Add(NewNode); Node = NewNode; } } } bIsRuntimeAutoCompleteUpToDate = true; //PrintNode(&AutoCompleteTree); #endif }