@Tomura, Ja, ist toll, dass Unreal sowas bereitstellt, nur ist das ExceptionHandling nicht so gut gelöst . Vor einem Monat habe ich fast kaum Unreal C++ Snippets/Funktionen verwendet und nun eigentlich nur noch so, einfach auf Grund der Einfachheit und der Kompatibilität der verschiedenen Plattformen.
@Franz99, Danke für die positive Rückmeldung. Ich nehme dir das garantiert nicht übel.
Nun zur Problembehandlung. Ich habe mir mal den Quellcode von FMath::Eval() angesehen. Dies ist wirklich ein Bug von Unreal. Dieser Fehler tritt auf, solltest du das die abgerundete geschlossene Klammer verwenden ")". Alles danach wird nicht mehr ausgeführt.
(3+6*(2*7+3)-5)*5*(4-5/6)+(2*(4-2)) = (3+6*(2*7+3) = 105.0
Betroffene Zeile:
\Engine\Source\Runtime\Core\Private\Math\UnrealMath.cpp SubEval()
// ...
else if (c == TEXT(")"))
{
*pStr = FString(TEXT(")")) + *pStr;
*pResult = V;
return 1;
}
// ...
Das return 1; und *pStr = FString(TEXT(")")) + *pStr; haben zur Folge, dass die Funktion zu früh beendet wird. Etwaig braucht man den Source Code von Github (https://www.unrealengine.com/ue4-on-github), die Datei ist bei mir zumindest schreibgeschützt und wenn ich diese aufhebe und sie beschreibe/überschreibe lässt sich dadurch keine Veränderung feststellen. Wenn du dir nicht unbedingt den Source-Code holen willst, würde ich dir empfehlen den Ausschnitt von FMath::Eval() und SubEval ins Blueprint zu packen, dann kannst du auch direkt dein eigenes ExceptionHandling schreiben. Musst dann halt das Blueprint um UNumericalEquation::Eval() und UNumericalEquation::SubEval() erweitern.
FMath::Eval()
bool FMath::Eval( FString Str, float& OutValue )
{
bool bResult = true;
// Check for a matching number of brackets right up front.
int32 Brackets = 0;
for( int32 x = 0 ; x < Str.Len() ; x++ )
{
if( Str.Mid(x,1) == TEXT("(") )
{
Brackets++;
}
if( Str.Mid(x,1) == TEXT(")") )
{
Brackets--;
}
}
if( Brackets != 0 )
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Mismatched brackets"));
bResult = false;
}
else
{
if( !SubEval( &Str, &OutValue, 0 ) )
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Error in expression"));
bResult = false;
}
}
return bResult;
}
Alles anzeigen
SubEval()
bool SubEval( FString* pStr, float* pResult, int32 Prec )
{
FString c;
float V, W, N;
V = W = N = 0.0f;
c = GrabChar(pStr);
if( (c >= TEXT("0") && c <= TEXT("9")) || c == TEXT(".") ) // Number
{
V = 0;
while(c >= TEXT("0") && c <= TEXT("9"))
{
V = V * 10 + Val(c);
c = GrabChar(pStr);
}
if( c == TEXT(".") )
{
N = 0.1f;
c = GrabChar(pStr);
while(c >= TEXT("0") && c <= TEXT("9"))
{
V = V + N * Val(c);
N = N / 10.0f;
c = GrabChar(pStr);
}
}
}
else if( c == TEXT("(")) // Opening parenthesis
{
if( !SubEval(pStr, &V, 0) )
{
return 0;
}
c = GrabChar(pStr);
}
else if( c == TEXT("-") ) // Negation
{
if( !SubEval(pStr, &V, 1000) )
{
return 0;
}
V = -V;
c = GrabChar(pStr);
}
else if( c == TEXT("+")) // Positive
{
if( !SubEval(pStr, &V, 1000) )
{
return 0;
}
c = GrabChar(pStr);
}
else if( c == TEXT("@") ) // Square root
{
if( !SubEval(pStr, &V, 1000) )
{
return 0;
}
if( V < 0 )
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Can't take square root of negative number"));
return 0;
}
else
{
V = FMath::Sqrt(V);
}
c = GrabChar(pStr);
}
else // Error
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : No value recognized"));
return 0;
}
PrecLoop:
if( c == TEXT("") )
{
*pResult = V;
return 1;
}
else if( c == TEXT(")") )
{
*pStr = FString(TEXT(")")) + *pStr;
*pResult = V;
return 1;
}
else if( c == TEXT("+") )
{
if( Prec > 1 )
{
*pResult = V;
*pStr = c + *pStr;
return 1;
}
else
{
if( SubEval(pStr, &W, 2) )
{
V = V + W;
c = GrabChar(pStr);
goto PrecLoop;
}
else
{
return 0;
}
}
}
else if( c == TEXT("-") )
{
if( Prec > 1 )
{
*pResult = V;
*pStr = c + *pStr;
return 1;
}
else
{
if( SubEval(pStr, &W, 2) )
{
V = V - W;
c = GrabChar(pStr);
goto PrecLoop;
}
else
{
return 0;
}
}
}
else if( c == TEXT("/") )
{
if( Prec > 2 )
{
*pResult = V;
*pStr = c + *pStr;
return 1;
}
else
{
if( SubEval(pStr, &W, 3) )
{
if( W == 0 )
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Division by zero isn't allowed"));
return 0;
}
else
{
V = V / W;
c = GrabChar(pStr);
goto PrecLoop;
}
}
else
{
return 0;
}
}
}
else if( c == TEXT("%") )
{
if( Prec > 2 )
{
*pResult = V;
*pStr = c + *pStr;
return 1;
}
else
{
if( SubEval(pStr, &W, 3) )
{
if( W == 0 )
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Modulo zero isn't allowed"));
return 0;
}
else
{
V = (int32)V % (int32)W;
c = GrabChar(pStr);
goto PrecLoop;
}
}
else
{
return 0;
}
}
}
else if( c == TEXT("*") )
{
if( Prec > 3 )
{
*pResult = V;
*pStr = c + *pStr;
return 1;
}
else
{
if( SubEval(pStr, &W, 4) )
{
V = V * W;
c = GrabChar(pStr);
goto PrecLoop;
}
else
{
return 0;
}
}
}
else
{
UE_LOG(LogUnrealMath, Log, TEXT("Expression Error : Unrecognized Operator"));
}
*pResult = V;
return 1;
}
Alles anzeigen
Hoffe ich konnte dir den Fehler/Bug etwas genauer erläutern. Wenn dich C++ interessiert ist es sicher schlau, sich gerade damit auseinanderzusetzen. Hier hast du so gesehen ein einfaches Problem, welches du mit deiner langjährigen Programmiererfahrung, auch ohne grossartige C++ Kenntnisse, lösen kannst. Aber sonst würde ich mir das nicht antun. Finde ich ehrlich gesagt gerade bisschen Schade, dass die Funktion einen Bug hat.
PS: Wir werden uns denke ich noch gut verstehen,... ich meine wir kommen ja aus dem selben Fach (PHP<3 etc.), wenn's um Programmieren geht