172 lines
4.3 KiB
C#
172 lines
4.3 KiB
C#
// Copyright © Gamesmiths Guild.
|
|
|
|
using System;
|
|
using System.Globalization;
|
|
using Gamesmiths.Forge.Statescript;
|
|
using Gamesmiths.Forge.Statescript.Properties;
|
|
|
|
namespace Gamesmiths.Forge.Godot.Resources.Statescript;
|
|
|
|
internal static class StatescriptNumericCompatibility
|
|
{
|
|
public static bool CanCoerce(Type sourceType, Type targetType)
|
|
{
|
|
if (sourceType == targetType)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (!IsNumericType(sourceType) || !IsNumericType(targetType))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (IsIntegralType(targetType))
|
|
{
|
|
return IsIntegralType(sourceType);
|
|
}
|
|
|
|
return IsFloatingPointType(targetType);
|
|
}
|
|
|
|
public static Variant128 Coerce(Variant128 value, Type sourceType, Type targetType)
|
|
{
|
|
if (!CanCoerce(sourceType, targetType))
|
|
{
|
|
throw new InvalidOperationException(
|
|
$"Cannot coerce Statescript numeric value from '{sourceType}' to '{targetType}'.");
|
|
}
|
|
|
|
object numericValue = GetNumericValue(sourceType, value);
|
|
return targetType switch
|
|
{
|
|
_ when targetType == typeof(byte) => new Variant128(
|
|
Convert.ToByte(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(sbyte) => new Variant128(
|
|
Convert.ToSByte(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(char) => new Variant128(
|
|
Convert.ToChar(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(short) => new Variant128(
|
|
Convert.ToInt16(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(ushort) => new Variant128(
|
|
Convert.ToUInt16(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(int) => new Variant128(
|
|
Convert.ToInt32(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(uint) => new Variant128(
|
|
Convert.ToUInt32(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(long) => new Variant128(
|
|
Convert.ToInt64(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(ulong) => new Variant128(
|
|
Convert.ToUInt64(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(float) => new Variant128(
|
|
Convert.ToSingle(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(double) => new Variant128(
|
|
Convert.ToDouble(numericValue, CultureInfo.InvariantCulture)),
|
|
_ when targetType == typeof(decimal) => new Variant128(
|
|
Convert.ToDecimal(numericValue, CultureInfo.InvariantCulture)),
|
|
_ => throw new InvalidOperationException(
|
|
$"Cannot coerce Statescript numeric value to unsupported target type '{targetType}'."),
|
|
};
|
|
}
|
|
|
|
public static bool IsNumericType(Type type)
|
|
{
|
|
return type == typeof(byte)
|
|
|| type == typeof(sbyte)
|
|
|| type == typeof(char)
|
|
|| type == typeof(short)
|
|
|| type == typeof(ushort)
|
|
|| type == typeof(int)
|
|
|| type == typeof(uint)
|
|
|| type == typeof(long)
|
|
|| type == typeof(ulong)
|
|
|| type == typeof(float)
|
|
|| type == typeof(double)
|
|
|| type == typeof(decimal);
|
|
}
|
|
|
|
private static bool IsFloatingPointType(Type type)
|
|
{
|
|
return type == typeof(float) || type == typeof(double) || type == typeof(decimal);
|
|
}
|
|
|
|
private static bool IsIntegralType(Type type)
|
|
{
|
|
return type == typeof(byte)
|
|
|| type == typeof(sbyte)
|
|
|| type == typeof(char)
|
|
|| type == typeof(short)
|
|
|| type == typeof(ushort)
|
|
|| type == typeof(int)
|
|
|| type == typeof(uint)
|
|
|| type == typeof(long)
|
|
|| type == typeof(ulong);
|
|
}
|
|
|
|
private static object GetNumericValue(Type type, Variant128 value)
|
|
{
|
|
if (type == typeof(byte))
|
|
{
|
|
return value.AsByte();
|
|
}
|
|
|
|
if (type == typeof(sbyte))
|
|
{
|
|
return value.AsSByte();
|
|
}
|
|
|
|
if (type == typeof(char))
|
|
{
|
|
return value.AsChar();
|
|
}
|
|
|
|
if (type == typeof(short))
|
|
{
|
|
return value.AsShort();
|
|
}
|
|
|
|
if (type == typeof(ushort))
|
|
{
|
|
return value.AsUShort();
|
|
}
|
|
|
|
if (type == typeof(int))
|
|
{
|
|
return value.AsInt();
|
|
}
|
|
|
|
if (type == typeof(uint))
|
|
{
|
|
return value.AsUInt();
|
|
}
|
|
|
|
if (type == typeof(long))
|
|
{
|
|
return value.AsLong();
|
|
}
|
|
|
|
if (type == typeof(ulong))
|
|
{
|
|
return value.AsULong();
|
|
}
|
|
|
|
if (type == typeof(float))
|
|
{
|
|
return value.AsFloat();
|
|
}
|
|
|
|
if (type == typeof(double))
|
|
{
|
|
return value.AsDouble();
|
|
}
|
|
|
|
if (type == typeof(decimal))
|
|
{
|
|
return value.AsDecimal();
|
|
}
|
|
|
|
throw new InvalidOperationException(
|
|
$"Cannot read Statescript numeric value from unsupported source type '{type}'.");
|
|
}
|
|
}
|