Checking a system-defined enum with equality operators fails
tracked
naqtn
Checking the equality/inequality of a system-defined enum with equality/inequality operators (
==
/!=
) will fail.As a result, this example codes in the document don't work as expected: https://creators.vrchat.com/platforms/android/android-best-practices/#2-detect-mobile-players-in-your-world-automatically
public override void OnInputMethodChanged(VRCInputMethod inputMethod)
{
if (inputMethod == VRCInputMethod.Touch)
{
// Run code for touch input
}
else
{
// Run code for non-touch input
}
}
(The UdonGraph version (attached image) also has an identical issue.)
Workaround
Cast to underlying values and compare them.
if ((int)inputMethod == (int)VRCInputMethod.Touch)
Analysis
UdonSharp compiles the expression
inputMethod == VRCInputMethod.Touch
into EXTERN, "SystemObject.__Equals__SystemObject__SystemBoolean"
Although
Object.Equals(Object)
is overridden by Enum.Equals(Object)
, which the inputMethod
may have, with comparing underlying value, this EXTERN
seems to call the Object.Equals
directly (maybe via reflection API), and it returns the unexpected result (by only comparing the referencing instances).The
EXTERN, "SystemObject.__Equals__
comes from here https://github.com/vrchat-community/UdonSharp/blob/22307065bd408dfd163fe46b0b8b701a4efcbc00/Packages/com.vrchat.UdonSharp/Editor/Compiler/Binder/BoundNodes/BoundInvocationExpression.cs#L420 And replacing the System_Object
of this line with System_Enum
doesn't work because the Enum.Equals
is not exposed.Suggestions
- Temporary, rewrite the example codes using cast operator
- ExposeSystem.Enum.Equals
- And replace the EXTERNwithSystem.Enum.Equals
Log In
This post was marked as
tracked
Μerlin
public class EnumTest : UdonSharpBehaviour
{
public VRCInputMethod inputMethod;
void Start()
{
Debug.Log($"Input method: {inputMethod}");
Debug.Log($"Input method == Touch: {inputMethod == VRCInputMethod.Touch}");
Debug.Log($"Input method != Touch: {inputMethod != VRCInputMethod.Touch}");
Debug.Log($"Input method == Gaze: {inputMethod == VRCInputMethod.Gaze}");
Debug.Log($"Input method != Gaze: {inputMethod != VRCInputMethod.Gaze}");
}
}
This appears to work as expected in-editor and in-game on desktop with the
inputMethod
set to Touch. Note: calling .Equals() on an object
should call the virtual inherited member of that type so it would be calling the inherited enum.Equals() even though it isn't directly exposed. Maybe this is a mobile-specific issue, or the input method changed event isn't getting the expected argument always?naqtn
Μerlin Thank you for the info and testing. I realized that my analysis was wrong and found another possibility of the cause.
The type of the
OnInputMethodChanged
argument and the type of the constant in the heap differ, although both are VRCInputMethod
on the source code. If so, Enum.Equals
may return false. public override void OnInputMethodChanged(VRCInputMethod inputMethod)
{
Debug.Log($"OnInputMethodChanged inputMethod={inputMethod}");
// Comparing to VRCInputMethod.Keyboard to be easy to test on PC
Debug.Log($"inputMethod == VRCInputMethod.Keyboard: {inputMethod == VRCInputMethod.Keyboard}");
Debug.Log($"(int)inputMethod == (int)VRCInputMethod.Keyboard: {(int)inputMethod == (int)VRCInputMethod.Keyboard}");
// Examin the types
System.Type argType = inputMethod.GetType();
System.Type constType = VRCInputMethod.Keyboard.GetType();
Debug.Log($"argType == constType: {argType == constType}");
Debug.Log($"argType.FullName={argType.FullName}");
Debug.Log($"constType.FullName={constType.FullName}");
}
Log - OnInputMethodChanged inputMethod=Keyboard
Log - inputMethod == VRCInputMethod.Keyboard: False
Log - (int)inputMethod == (int)VRCInputMethod.Keyboard: True
Log - argType == constType: False
Log - argType.FullName=ÏÎÎÌÎÌÍÌÎÎÌÌÏÏÎÌÌÎÎÍÌÌÌ+ÎÍÍÏÌÌÍÏÏÎÍÎÍÍÍÎÌÌÎÎÎÍÌ
Log - constType.FullName=VRC.SDKBase.VRCInputMethod
I forgot to note the versions. SDK 3.7.1, Client 2024.3.2p2 build 1506