309 lines
5.7 KiB
C#
309 lines
5.7 KiB
C#
using System;
|
|
using BlockSpace.Voxels;
|
|
using UnityEngine;
|
|
|
|
[Serializable]
|
|
public struct BSValue
|
|
{
|
|
private const double WholeNumberEpsilon = 0.0001;
|
|
|
|
public BSValueKind Kind;
|
|
|
|
public double Number;
|
|
|
|
public string Text;
|
|
|
|
public bool Bool;
|
|
|
|
public int PlayerId;
|
|
|
|
public int GroupId;
|
|
|
|
public bool IsInitialized
|
|
{
|
|
get
|
|
{
|
|
if (Kind == BSValueKind.None && !(Math.Abs(Number) > 0.0001) && string.IsNullOrEmpty(Text) && PlayerId == 0)
|
|
{
|
|
return GroupId != 0;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
public static BSValue None => new BSValue
|
|
{
|
|
Kind = BSValueKind.None
|
|
};
|
|
|
|
public static BSValue FromBool(bool value)
|
|
{
|
|
return new BSValue
|
|
{
|
|
Kind = BSValueKind.Bool,
|
|
Bool = value
|
|
};
|
|
}
|
|
|
|
public static BSValue FromNumber(double value)
|
|
{
|
|
return new BSValue
|
|
{
|
|
Kind = BSValueKind.Number,
|
|
Number = NormalizeNumber(value)
|
|
};
|
|
}
|
|
|
|
public static BSValue FromText(string value)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(value) || string.Equals(value, "None", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "Null", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return None;
|
|
}
|
|
if (string.Equals(value, "True", StringComparison.OrdinalIgnoreCase) || string.Equals(value, "False", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return FromBool(string.Equals(value, "True", StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
if (double.TryParse(value, out var result))
|
|
{
|
|
return FromNumber(result);
|
|
}
|
|
return new BSValue
|
|
{
|
|
Kind = BSValueKind.Text,
|
|
Text = value
|
|
};
|
|
}
|
|
|
|
public static BSValue FromPlayer(int playerId)
|
|
{
|
|
return new BSValue
|
|
{
|
|
Kind = BSValueKind.Player,
|
|
PlayerId = playerId
|
|
};
|
|
}
|
|
|
|
public static BSValue FromGroup(int groupId)
|
|
{
|
|
return new BSValue
|
|
{
|
|
Kind = BSValueKind.Group,
|
|
GroupId = groupId
|
|
};
|
|
}
|
|
|
|
public BSValue Normalize()
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case BSValueKind.Number:
|
|
Number = NormalizeNumber(Number);
|
|
break;
|
|
case BSValueKind.Text:
|
|
if (Text == null)
|
|
{
|
|
Text = string.Empty;
|
|
}
|
|
break;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
public bool IsWholeNumber()
|
|
{
|
|
return Math.Abs(Number - Math.Round(Number)) <= 0.0001;
|
|
}
|
|
|
|
public double AsNumber()
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case BSValueKind.Number:
|
|
return NormalizeNumber(Number);
|
|
case BSValueKind.Bool:
|
|
if (!Bool)
|
|
{
|
|
return 0.0;
|
|
}
|
|
return 1.0;
|
|
case BSValueKind.Text:
|
|
{
|
|
if (double.TryParse(Text, out var result))
|
|
{
|
|
return NormalizeNumber(result);
|
|
}
|
|
return EncodeTextAsNumber(Text);
|
|
}
|
|
case BSValueKind.Player:
|
|
return PlayerId;
|
|
case BSValueKind.Group:
|
|
return GroupId;
|
|
default:
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
public bool AsBool()
|
|
{
|
|
return Kind switch
|
|
{
|
|
BSValueKind.Bool => Bool,
|
|
BSValueKind.None => false,
|
|
BSValueKind.Number => Math.Abs(AsNumber()) > 0.0001,
|
|
BSValueKind.Text => !string.IsNullOrEmpty(AsText()),
|
|
BSValueKind.Player => AsPlayerId() > 0,
|
|
BSValueKind.Group => AsGroupId() > 0,
|
|
_ => false,
|
|
};
|
|
}
|
|
|
|
public string AsText()
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case BSValueKind.Number:
|
|
if (!IsWholeNumber())
|
|
{
|
|
return NormalizeNumber(Number).ToString("0.#######");
|
|
}
|
|
return Math.Round(Number).ToString();
|
|
case BSValueKind.Bool:
|
|
if (!Bool)
|
|
{
|
|
return "False";
|
|
}
|
|
return "True";
|
|
case BSValueKind.Text:
|
|
return Text ?? string.Empty;
|
|
case BSValueKind.Player:
|
|
return PlayerId.ToString();
|
|
case BSValueKind.Group:
|
|
return GroupId.ToString();
|
|
default:
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
public int AsPlayerId()
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case BSValueKind.Player:
|
|
return PlayerId;
|
|
case BSValueKind.Number:
|
|
return Mathf.RoundToInt((float)NormalizeNumber(Number));
|
|
case BSValueKind.Group:
|
|
return GroupId;
|
|
case BSValueKind.Text:
|
|
{
|
|
if (int.TryParse(Text, out var result))
|
|
{
|
|
return result;
|
|
}
|
|
return Mathf.RoundToInt((float)EncodeTextAsNumber(Text));
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public int AsGroupId()
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case BSValueKind.Group:
|
|
return GroupId;
|
|
case BSValueKind.Number:
|
|
return Mathf.RoundToInt((float)NormalizeNumber(Number));
|
|
case BSValueKind.Player:
|
|
return PlayerId;
|
|
case BSValueKind.Text:
|
|
{
|
|
if (int.TryParse(Text, out var result))
|
|
{
|
|
return result;
|
|
}
|
|
return Mathf.RoundToInt((float)EncodeTextAsNumber(Text));
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
public bool TryResolveGroup(out VoxelGroup group)
|
|
{
|
|
return TryResolveGroup(VoxelGroupManager.Instance, out group);
|
|
}
|
|
|
|
public bool TryResolveGroup(VoxelGroupManager manager, out VoxelGroup group)
|
|
{
|
|
group = null;
|
|
if (manager == null)
|
|
{
|
|
return false;
|
|
}
|
|
int num = AsGroupId();
|
|
if (num > 0 && num <= 65535 && manager.TryGetGroup((ushort)num, out group))
|
|
{
|
|
return group != null;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public BSValue ConvertTo(BSValueKind targetKind)
|
|
{
|
|
return targetKind switch
|
|
{
|
|
BSValueKind.Bool => FromBool(AsBool()),
|
|
BSValueKind.Number => FromNumber(AsNumber()),
|
|
BSValueKind.Text => new BSValue
|
|
{
|
|
Kind = BSValueKind.Text,
|
|
Text = AsText()
|
|
},
|
|
BSValueKind.Player => FromPlayer(AsPlayerId()),
|
|
BSValueKind.Group => FromGroup(AsGroupId()),
|
|
_ => None,
|
|
};
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
return Kind switch
|
|
{
|
|
BSValueKind.Number => AsText(),
|
|
BSValueKind.Text => AsText(),
|
|
BSValueKind.Bool => AsText(),
|
|
BSValueKind.Player => $"Player({AsPlayerId()})",
|
|
BSValueKind.Group => $"Group({AsGroupId()})",
|
|
_ => "None",
|
|
};
|
|
}
|
|
|
|
private static double NormalizeNumber(double value)
|
|
{
|
|
double num = Math.Round(value);
|
|
if (!(Math.Abs(value - num) <= 0.0001))
|
|
{
|
|
return value;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
private static double EncodeTextAsNumber(string value)
|
|
{
|
|
if (string.IsNullOrEmpty(value))
|
|
{
|
|
return 0.0;
|
|
}
|
|
uint num = 2166136261u;
|
|
for (int i = 0; i < value.Length; i++)
|
|
{
|
|
num ^= value[i];
|
|
num *= 16777619;
|
|
}
|
|
return num;
|
|
}
|
|
}
|