Browse Source

Matched with base, BSettings changes and fixing of STT Manger

master
Tillman Staffen 16 hours ago
parent
commit
b29679c01d
  1. BIN
      Unreal/Content/Project/BP/BP_Project_Manager.uasset
  2. 2
      Unreal/Plugins/AvatarCore_AI/Source/AvatarCore_AI/Public/AIBaseManager.h
  3. BIN
      Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_CreateAvatar.uasset
  4. BIN
      Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_MetahumanToAvatar.uasset
  5. BIN
      Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_UpdateAvatar.uasset
  6. 33
      Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/AzureRunnable.cpp
  7. 6
      Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp
  8. 372
      Unreal/Plugins/BSettings/Source/BSettings/Private/BSettingsSystem.cpp
  9. 1035
      Unreal/Plugins/BSettings/Source/BSettings/Public/BSettingsSystem.h

BIN
Unreal/Content/Project/BP/BP_Project_Manager.uasset (Stored with Git LFS)

Binary file not shown.

2
Unreal/Plugins/AvatarCore_AI/Source/AvatarCore_AI/Public/AIBaseManager.h

@ -86,7 +86,7 @@ public:
void OnAIReady(); void OnAIReady();
// Is the AI activated and ready? // Is the AI activated and ready?
UFUNCTION(BlueprintPure, Category = "AvatarCoreAI") UFUNCTION(BlueprintCallable, Category = "AvatarCoreAI")
bool IsAIActivated(); bool IsAIActivated();
/** /**

BIN
Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_CreateAvatar.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_MetahumanToAvatar.uasset (Stored with Git LFS)

Binary file not shown.

BIN
Unreal/Plugins/AvatarCore_MetaHuman/Content/BP/EditorUtility/EUS_UpdateAvatar.uasset (Stored with Git LFS)

Binary file not shown.

33
Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/AzureRunnable.cpp

@ -21,6 +21,7 @@ FAzureRunnable::~FAzureRunnable()
if (Thread) if (Thread)
{ {
Owner = nullptr; Owner = nullptr;
bIsRunning = false; // Unblock the Run() loop before killing the thread
Thread->Kill(true); Thread->Kill(true);
delete Thread; delete Thread;
} }
@ -113,12 +114,13 @@ uint32 FAzureRunnable::Run()
if (ConnectionTestOnly) { if (ConnectionTestOnly) {
//TODO Check if Api is correct //TODO Check if Api is correct
AsyncTask(ENamedThreads::GameThread, [this] { TWeakObjectPtr<USTTProcessorAzure> WeakOwnerLocal(Owner);
if (Owner != nullptr) AsyncTask(ENamedThreads::GameThread, [WeakOwnerLocal] {
if (WeakOwnerLocal.IsValid())
{ {
Owner->OnConnectionSuccess(); WeakOwnerLocal->OnConnectionSuccess();
} }
}); });
Stop(); Stop();
RecognitionEnd.set_value(); // Ensure promise is fulfilled RecognitionEnd.set_value(); // Ensure promise is fulfilled
return 0; return 0;
@ -142,15 +144,8 @@ uint32 FAzureRunnable::Run()
} }
Recognizer->StopContinuousRecognitionAsync().get(); Recognizer->StopContinuousRecognitionAsync().get();
// Use a weak pointer to Owner to avoid accessing this after destruction // Disconnect all events BEFORE posting the game-thread task to prevent
TWeakObjectPtr<USTTProcessorAzure> WeakOwner(Owner); // any in-flight SDK callbacks from firing during the async gap
AsyncTask(ENamedThreads::GameThread, [WeakOwner]() {
if (WeakOwner.IsValid() && WeakOwner.Get() != nullptr)
{
WeakOwner->OnRunnableEnded();
}
});
Recognizer->Canceled.DisconnectAll(); Recognizer->Canceled.DisconnectAll();
Recognizer->Recognized.DisconnectAll(); Recognizer->Recognized.DisconnectAll();
Recognizer->Recognizing.DisconnectAll(); Recognizer->Recognizing.DisconnectAll();
@ -159,6 +154,14 @@ uint32 FAzureRunnable::Run()
Recognizer->SessionStopped.DisconnectAll(); Recognizer->SessionStopped.DisconnectAll();
Recognizer->SessionStarted.DisconnectAll(); Recognizer->SessionStarted.DisconnectAll();
TWeakObjectPtr<USTTProcessorAzure> WeakOwner(Owner);
AsyncTask(ENamedThreads::GameThread, [WeakOwner]() {
if (WeakOwner.IsValid() && WeakOwner.Get() != nullptr)
{
WeakOwner->OnRunnableEnded();
}
});
RecognitionEnd.set_value(); // Ensure promise is fulfilled RecognitionEnd.set_value(); // Ensure promise is fulfilled
return 0; return 0;
} }
@ -170,7 +173,8 @@ void FAzureRunnable::Stop()
void FAzureRunnable::StopRecognition(bool Forced) void FAzureRunnable::StopRecognition(bool Forced)
{ {
if (Forced) { bIsRunning = false; // Always stop the Run() loop first
if (Forced && Recognizer) {
Recognizer->Canceled.DisconnectAll(); Recognizer->Canceled.DisconnectAll();
Recognizer->Recognized.DisconnectAll(); Recognizer->Recognized.DisconnectAll();
Recognizer->Recognizing.DisconnectAll(); Recognizer->Recognizing.DisconnectAll();
@ -180,7 +184,6 @@ void FAzureRunnable::StopRecognition(bool Forced)
Recognizer->SessionStarted.DisconnectAll(); Recognizer->SessionStarted.DisconnectAll();
Owner = nullptr; Owner = nullptr;
} }
bIsRunning = false;
} }
void FAzureRunnable::AddAudioChunk(const TArray<int16>& PCMData) void FAzureRunnable::AddAudioChunk(const TArray<int16>& PCMData)

6
Unreal/Plugins/AvatarCore_STT/Source/AvatarCore_STT/Private/Processor/Azure/STTProcessorAzure.cpp

@ -103,7 +103,7 @@ void USTTProcessorAzure::OnSpeechStateChanged(ESTTTalkingState TalkingState)
StopRecognition(false); StopRecognition(false);
else { else {
if (!intermediateResult.IsEmpty()) { if (!intermediateResult.IsEmpty()) {
USTTProcessorBase::OnTranscriptionIntermediateResult(TranscriptionCounter, *intermediateResult); USTTProcessorBase::OnTranscriptionResult(TranscriptionCounter, intermediateResult, DetectedLanguage);
intermediateResult = ""; intermediateResult = "";
} }
} }
@ -127,9 +127,7 @@ void USTTProcessorAzure::StopRecognition(bool Forced)
if (AzureRunnable) if (AzureRunnable)
{ {
AzureRunnable->StopRecognition(Forced); AzureRunnable->StopRecognition(Forced);
if (Forced) { AzureRunnable = nullptr;
AzureRunnable = nullptr;
}
if(bDebugMode && STTManager!=nullptr) if(bDebugMode && STTManager!=nullptr)
STTManager->OnSTTLog.Broadcast(TEXT("Recognition thread stopped.")); STTManager->OnSTTLog.Broadcast(TEXT("Recognition thread stopped."));
} }

372
Unreal/Plugins/BSettings/Source/BSettings/Private/BSettingsSystem.cpp

@ -339,7 +339,7 @@ void UBSettingsSystem::InitializeValues(TSharedPtr<FJsonObject> Destination, USt
} }
// Helper: resolve enum value from a string using internal name, display name, and UUserDefinedEnum's DisplayNameMap // Helper: resolve enum value from a string using internal name, display name, and UUserDefinedEnum's DisplayNameMap
static bool ResolveEnumValueFromString(const UEnum* Enum, const FString& InString, int64& OutValue) bool UBSettingsSystem::ResolveEnumValueFromString(const UEnum* Enum, const FString& InString, int64& OutValue)
{ {
if (!Enum) return false; if (!Enum) return false;
@ -1083,6 +1083,90 @@ void UBSettingsSystem::CollectEnumValues(const FProperty* Prop, TArray<FString>&
} }
} }
// Recursively builds a JSON schema description for a single property.
// Handles type, tooltip, enum values, struct sub-fields, and array items at any depth.
TSharedPtr<FJsonObject> UBSettingsSystem::BuildFieldSchema(const FProperty* Prop)
{
TSharedPtr<FJsonObject> FieldObj = MakeShared<FJsonObject>();
const FString TypeStr = GetSchemaType(Prop);
FieldObj->SetStringField(TEXT("type"), TypeStr);
// Tooltip
const FString Tooltip = Prop->GetMetaData(TEXT("ToolTip"));
if (!Tooltip.IsEmpty())
{
FieldObj->SetStringField(TEXT("tooltip"), Tooltip);
}
// Enum: collect available values
if (TypeStr == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(Prop, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& Val : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val));
}
FieldObj->SetArrayField(TEXT("enum"), JsonEnumVals);
}
// Struct: recurse into sub-fields
if (TypeStr == TEXT("struct"))
{
if (const FStructProperty* StructProp = CastField<FStructProperty>(Prop))
{
TSharedPtr<FJsonObject> FieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> It(StructProp->Struct); It; ++It)
{
const FProperty* SubProp = *It;
if (!SubProp || IsSchemaCategoryProperty(SubProp)) continue;
FieldsObj->SetObjectField(SubProp->GetAuthoredName(), BuildFieldSchema(SubProp));
}
FieldObj->SetObjectField(TEXT("fields"), FieldsObj);
}
}
// Array: item type + recurse for enum/struct items
if (TypeStr == TEXT("array"))
{
if (const FArrayProperty* ArrProp = CastField<FArrayProperty>(Prop))
{
const FProperty* Inner = ArrProp->Inner;
const FString InnerType = GetSchemaType(Inner);
FieldObj->SetStringField(TEXT("itemsType"), InnerType);
if (InnerType == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(Inner, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& Val : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val));
}
FieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals);
}
else if (InnerType == TEXT("struct"))
{
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner))
{
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> It(InnerStructProp->Struct); It; ++It)
{
const FProperty* SubProp = *It;
if (!SubProp || IsSchemaCategoryProperty(SubProp)) continue;
ItemsFieldsObj->SetObjectField(SubProp->GetAuthoredName(), BuildFieldSchema(SubProp));
}
FieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj);
}
}
}
}
return FieldObj;
}
// Exports a JSON schema file describing the structure of the provided UStruct. // Exports a JSON schema file describing the structure of the provided UStruct.
bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FString& ConfigName, const FString& SavedSubFolder, const uint8* DefaultDataOverride) bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FString& ConfigName, const FString& SavedSubFolder, const uint8* DefaultDataOverride)
{ {
@ -1165,299 +1249,27 @@ bool UBSettingsSystem::StructToJsonSchema(const UStruct* StructType, const FStri
// Use authored variable name (no generated suffixes) // Use authored variable name (no generated suffixes)
const FString VarName = Prop->GetAuthoredName(); const FString VarName = Prop->GetAuthoredName();
// Determine schema type for this property // Build field schema recursively (type, tooltip, enum, struct fields, array items)
const FString TypeStr = GetSchemaType(Prop); TSharedPtr<FJsonObject> FieldObj = BuildFieldSchema(Prop);
// Build JSON object for this variable (holds its attributes) // Top-level only: export default value
TSharedPtr<FJsonObject> FieldObj = MakeShared<FJsonObject>();
FieldObj->SetStringField(TEXT("type"), TypeStr);
// Export default value
if (TSharedPtr<FJsonValue> DefVal = Defaults->TryGetField(VarName)) if (TSharedPtr<FJsonValue> DefVal = Defaults->TryGetField(VarName))
{ {
FieldObj->SetField(TEXT("default"), DefVal); FieldObj->SetField(TEXT("default"), DefVal);
} }
// Tooltip: only include if explicitly set via UPROPERTY(meta = (ToolTip = "...")) // Top-level only: SaveGame flag
const FString Tooltip = Prop->GetMetaData(TEXT("ToolTip")); if (Prop->HasAnyPropertyFlags(CPF_SaveGame))
if (!Tooltip.IsEmpty())
{
FieldObj->SetStringField(TEXT("tooltip"), Tooltip);
}
// SaveGame: only include if explicitly set
const bool SaveGame = Prop->HasAnyPropertyFlags(CPF_SaveGame);
if (SaveGame)
{ {
FieldObj->SetBoolField(TEXT("hotreload"), SaveGame); FieldObj->SetBoolField(TEXT("hotreload"), true);
} }
// attach category name to each variable if a category context is active --- // Top-level only: attach category if active
if (!CurrentCategory.IsEmpty()) if (!CurrentCategory.IsEmpty())
{ {
FieldObj->SetStringField(TEXT("category"), CurrentCategory); FieldObj->SetStringField(TEXT("category"), CurrentCategory);
} }
// If this is a struct: list sub-variables and their types
if (TypeStr == TEXT("struct"))
{
if (const FStructProperty* StructProp = CastField<FStructProperty>(Prop))
{
TSharedPtr<FJsonObject> FieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> SubIt(StructProp->Struct); SubIt; ++SubIt)
{
const FProperty* SubProp = *SubIt;
if (!SubProp || IsSchemaCategoryProperty(SubProp))
{
continue; // Marker/Invalides Feld überspringen
}
const FString SubName = SubProp->GetAuthoredName();
const FString SubType = GetSchemaType(SubProp);
TSharedPtr<FJsonObject> SubFieldObj = MakeShared<FJsonObject>();
SubFieldObj->SetStringField(TEXT("type"), SubType);
// --- Enums als direkte Struct-Subfelder (optional aber konsistent)
if (SubType == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(SubProp, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& V : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(V));
}
SubFieldObj->SetArrayField(TEXT("enum"), JsonEnumVals);
}
// --- Verschachteltes Struct als Subfeld: nur Felder (Name+Typ) auflisten
else if (SubType == TEXT("struct"))
{
if (const FStructProperty* NestedStructProp = CastField<FStructProperty>(SubProp))
{
TSharedPtr<FJsonObject> NestedFieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> NIt(NestedStructProp->Struct); NIt; ++NIt)
{
const FProperty* NProp = *NIt;
if (!NProp || IsSchemaCategoryProperty(NProp)) continue;
const FString NName = NProp->GetAuthoredName();
const FString NType = GetSchemaType(NProp);
TSharedPtr<FJsonObject> NFieldObj = MakeShared<FJsonObject>();
NFieldObj->SetStringField(TEXT("type"), NType);
// Arrays innerhalb des verschachtelten Structs (1 Ebene)
if (NType == TEXT("array"))
{
if (const FArrayProperty* DeepArr = CastField<FArrayProperty>(NProp))
{
const FProperty* DeepInner = DeepArr->Inner;
const FString DeepInnerType = GetSchemaType(DeepInner);
NFieldObj->SetStringField(TEXT("itemsType"), DeepInnerType);
if (DeepInnerType == TEXT("enum"))
{
TArray<FString> EV;
CollectEnumValues(DeepInner, EV);
TArray<TSharedPtr<FJsonValue>> JV;
for (const FString& e : EV) JV.Add(MakeShared<FJsonValueString>(e));
NFieldObj->SetArrayField(TEXT("itemsEnum"), JV);
}
else if (DeepInnerType == TEXT("struct"))
{
if (const FStructProperty* DeepInnerStruct = CastField<FStructProperty>(DeepInner))
{
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> SIt(DeepInnerStruct->Struct); SIt; ++SIt)
{
const FProperty* SProp = *SIt;
if (!SProp || IsSchemaCategoryProperty(SProp)) continue;
const FString SName = SProp->GetAuthoredName();
const FString SType = GetSchemaType(SProp);
TSharedPtr<FJsonObject> SObj = MakeShared<FJsonObject>();
SObj->SetStringField(TEXT("type"), SType);
ItemsFieldsObj->SetObjectField(SName, SObj);
}
NFieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj);
}
}
}
}
NestedFieldsObj->SetObjectField(NName, NFieldObj);
}
SubFieldObj->SetObjectField(TEXT("fields"), NestedFieldsObj);
}
}
// --- Array als Struct-Subfeld: itemsType (+ itemsEnum / itemsFields)
else if (SubType == TEXT("array"))
{
if (const FArrayProperty* SubArr = CastField<FArrayProperty>(SubProp))
{
const FProperty* Inner = SubArr->Inner;
const FString InnerType = GetSchemaType(Inner);
SubFieldObj->SetStringField(TEXT("itemsType"), InnerType);
if (InnerType == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(Inner, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& V : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(V));
}
SubFieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals);
}
else if (InnerType == TEXT("struct"))
{
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner))
{
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> SIt(InnerStructProp->Struct); SIt; ++SIt)
{
const FProperty* SProp = *SIt;
if (!SProp || IsSchemaCategoryProperty(SProp)) continue;
const FString SName = SProp->GetAuthoredName();
const FString SType = GetSchemaType(SProp);
TSharedPtr<FJsonObject> SObj = MakeShared<FJsonObject>();
SObj->SetStringField(TEXT("type"), SType);
// Arrays innerhalb der Item-Structs (1 Ebene)
if (SType == TEXT("array"))
{
if (const FArrayProperty* DeepArr = CastField<FArrayProperty>(SProp))
{
const FProperty* DeepInner = DeepArr->Inner;
const FString DeepInnerType = GetSchemaType(DeepInner);
SObj->SetStringField(TEXT("itemsType"), DeepInnerType);
if (DeepInnerType == TEXT("enum"))
{
TArray<FString> EV;
CollectEnumValues(DeepInner, EV);
TArray<TSharedPtr<FJsonValue>> JV;
for (const FString& e : EV) JV.Add(MakeShared<FJsonValueString>(e));
SObj->SetArrayField(TEXT("itemsEnum"), JV);
}
else if (DeepInnerType == TEXT("struct"))
{
if (const FStructProperty* DeepInnerStruct = CastField<FStructProperty>(DeepInner))
{
TSharedPtr<FJsonObject> ItemsFields2 = MakeShared<FJsonObject>();
for (TFieldIterator<FProperty> S2It(DeepInnerStruct->Struct); S2It; ++S2It)
{
const FProperty* S2Prop = *S2It;
if (!S2Prop || IsSchemaCategoryProperty(S2Prop)) continue;
TSharedPtr<FJsonObject> S2Obj = MakeShared<FJsonObject>();
S2Obj->SetStringField(TEXT("type"), GetSchemaType(S2Prop));
ItemsFields2->SetObjectField(S2Prop->GetAuthoredName(), S2Obj);
}
SObj->SetObjectField(TEXT("itemsFields"), ItemsFields2);
}
}
}
}
ItemsFieldsObj->SetObjectField(SName, SObj);
}
SubFieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj);
}
}
}
}
// Feld registrieren
FieldsObj->SetObjectField(SubName, SubFieldObj);
}
// struct-Felddefinitionen anhängen
FieldObj->SetObjectField(TEXT("fields"), FieldsObj);
}
}
// Enums: collect available values and emit as array of strings
if (TypeStr == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(Prop, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& Val : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(Val));
}
FieldObj->SetArrayField(TEXT("enum"), JsonEnumVals);
}
// Arrays: determine item type and add additional metadata
if (TypeStr == TEXT("array"))
{
if (const FArrayProperty* ArrProp = CastField<FArrayProperty>(Prop))
{
const FProperty* Inner = ArrProp->Inner;
const FString InnerType = GetSchemaType(Inner);
// Always expose the item type
FieldObj->SetStringField(TEXT("itemsType"), InnerType);
// If item is enum: export enum values for the array items
if (InnerType == TEXT("enum"))
{
TArray<FString> EnumValues;
CollectEnumValues(Inner, EnumValues);
TArray<TSharedPtr<FJsonValue>> JsonEnumVals;
for (const FString& V : EnumValues)
{
JsonEnumVals.Add(MakeShared<FJsonValueString>(V));
}
// Keep flat style: itemsEnum mirrors "enum" of single fields
FieldObj->SetArrayField(TEXT("itemsEnum"), JsonEnumVals);
}
// If item is a struct: list sub-variables + their types (no tooltips)
if (InnerType == TEXT("struct"))
{
if (const FStructProperty* InnerStructProp = CastField<FStructProperty>(Inner))
{
TSharedPtr<FJsonObject> ItemsFieldsObj = MakeShared<FJsonObject>();
// Same as for single struct fields, but nested under itemsFields
for (TFieldIterator<FProperty> SubIt(InnerStructProp->Struct); SubIt; ++SubIt)
{
const FProperty* SubProp = *SubIt;
const FString SubName = SubProp->GetAuthoredName();
const FString SubType = GetSchemaType(SubProp);
TSharedPtr<FJsonObject> SubFieldObj = MakeShared<FJsonObject>();
SubFieldObj->SetStringField(TEXT("type"), SubType);
ItemsFieldsObj->SetObjectField(SubName, SubFieldObj);
}
// Flat style to match arrays: provide fields for items
FieldObj->SetObjectField(TEXT("itemsFields"), ItemsFieldsObj);
}
}
}
}
// push this variable object wrapped under its variable name key // push this variable object wrapped under its variable name key
{ {
TSharedPtr<FJsonObject> Wrapper = MakeShared<FJsonObject>(); TSharedPtr<FJsonObject> Wrapper = MakeShared<FJsonObject>();

1035
Unreal/Plugins/BSettings/Source/BSettings/Public/BSettingsSystem.h

File diff suppressed because it is too large
Loading…
Cancel
Save