using Cryville.Common;
using Cryville.Common.Pdt;
using Cryville.Crtr.Event;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace Cryville.Crtr {
	public class PdtEvaluator : PdtEvaluatorBase {
		static readonly Dictionary<PdtOperatorSignature, PdtOperator> _shortops = new Dictionary<PdtOperatorSignature, PdtOperator>();
		readonly Dictionary<int, PdtOperator> _ctxops = new Dictionary<int, PdtOperator>();

		readonly byte[] _numbuf = new byte[4];
		static readonly int _var_w = IdentifierManager.SharedInstance.Request("w");
		static readonly int _var_h = IdentifierManager.SharedInstance.Request("h");
		static readonly int _var_true = IdentifierManager.SharedInstance.Request("true");
		static readonly int _var_false = IdentifierManager.SharedInstance.Request("false");
		protected override void GetVariable(int name, out int type, out byte[] value) {
			if (name == _var_w) { LoadNum(ChartPlayer.hitRect.width); type = PdtInternalType.Number; value = _numbuf; }
			else if (name == _var_h) { LoadNum(ChartPlayer.hitRect.height); type = PdtInternalType.Number; value = _numbuf; }
			else if (name == _var_true) { LoadNum(1); type = PdtInternalType.Number; value = _numbuf; }
			else if (name == _var_false) { LoadNum(0); type = PdtInternalType.Number; value = _numbuf; }
			else {
				var id = new Identifier(name);
				PropSrc prop;
				string str;
				float num;
				if (ContextEvent != null && ContextEvent.PropSrcs.TryGetValue(name, out prop)) {
					prop.Get(out type, out value);
				}
				else if (ContextState != null && ChartPlayer.motionRegistry.ContainsKey(id)) {
					var vec = ContextState.GetRawValue(id);
					new VectorSrc(() => vec).Get(out type, out value);
				}
				else if (ContextJudge != null && ContextJudge.scores.TryGetValue(name, out num)) {
					type = PdtInternalType.Number;
					LoadNum(num);
					value = _numbuf;
					RevokePotentialConstant();
				}
				else if (ContextJudge != null && ContextJudge.GetFormattedScoreStrings().TryGetValue(name, out str)) {
					type = PdtInternalType.String;
					value = GetBytes(str);
					RevokePotentialConstant();
				}
				else {
					PropSrc.Arbitrary result = ContextCascadeLookup(name);
					if (result != null) {
						result.Get(out type, out value);
					}
					else {
						type = PdtInternalType.Undefined;
						LoadNum(name);
						value = _numbuf;
					}
				}
			}
		}
		unsafe void LoadNum(int value) {
			fixed (byte* ptr = _numbuf) *(int*)ptr = value;
		}
		unsafe void LoadNum(float value) {
			fixed (byte* ptr = _numbuf) *(float*)ptr = value;
		}
		unsafe byte[] GetBytes(string value) {
			int strlen = value.Length;
			byte[] result = new byte[strlen * sizeof(char) + sizeof(int)];
			fixed (byte* _ptr = result) {
				char* ptr = (char*)(_ptr + sizeof(int));
				*(int*)_ptr = strlen;
				int i = 0;
				foreach (var c in value) ptr[i++] = c;
			}
			return result;
		}
		static readonly int _op_sep = IdentifierManager.SharedInstance.Request(",");
		static readonly int _func_int_map = IdentifierManager.SharedInstance.Request("int_map");
		protected override PdtOperator GetOperator(PdtOperatorSignature sig) {
			PdtOperator result;
			if (_shortops.TryGetValue(sig, out result)) {
				return result;
			}
			else if (sig.Name == _op_sep) {
				result = new op_arr(sig.ParamCount);
				_shortops.Add(new PdtOperatorSignature(_op_sep, sig.ParamCount), result);
				return result;
			}
			else if (sig.Name == _func_int_map) {
				result = new func_int_map(sig.ParamCount);
				_shortops.Add(new PdtOperatorSignature(_func_int_map, sig.ParamCount), result);
				return result;
			}
			else if (_ctxops.TryGetValue(sig.Name, out result)) {
				return result;
			}
			else throw new KeyNotFoundException(string.Format("Undefined operator {0}", sig));
		}

		static readonly int _colop_and = IdentifierManager.SharedInstance.Request("&");
		static readonly int _colop_or = IdentifierManager.SharedInstance.Request("|");
		protected override bool Collapse(int name, PdtVariableMemory param) {
			if (name == _colop_and) return param.Type == PdtInternalType.Number && param.AsNumber() <= 0;
			else if (name == _colop_or) return param.Type != PdtInternalType.Number || param.AsNumber() > 0;
			else throw new KeyNotFoundException(string.Format("Undefined collapse operator {0}", name));
		}

		public ChartEvent ContextEvent { private get; set; }
		public ContainerState ContextState { private get; set; }
		public Transform ContextTransform { private get; set; }
		public Judge ContextJudge { private get; set; }
		public PropSrc ContextSelfValue { private get; set; }

		readonly Dictionary<int, PropSrc.Arbitrary>[] ContextCascade = new Dictionary<int, PropSrc.Arbitrary>[256];
		int _cascadeHeight;
		public void ContextCascadeInsert() {
			ContextCascade[_cascadeHeight++].Clear();
		}
		public void ContextCascadeUpdate(int key, PropSrc.Arbitrary value) {
			ContextCascade[_cascadeHeight - 1][key] = value;
		}
		public PropSrc.Arbitrary ContextCascadeLookup(int name) {
			PropSrc.Arbitrary result;
			for (int i = _cascadeHeight - 1; i >= 0; i--) {
				Dictionary<int, PropSrc.Arbitrary> cas = ContextCascade[i];
				if (cas.TryGetValue(name, out result)) {
					return result;
				}
			}
			return null;
		}
		public void ContextCascadeDiscard() {
			--_cascadeHeight;
		}

		public PdtEvaluator() {
			for (int i = 0; i < ContextCascade.Length; i++) ContextCascade[i] = new Dictionary<int, PropSrc.Arbitrary>();

			_ctxops.Add(IdentifierManager.SharedInstance.Request("screen_edge"), new func_screen_edge(() => ContextTransform));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("int"), new func_int(() => ContextSelfValue));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("clamp"), new func_clamp(() => ContextSelfValue));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("min"), new func_min(() => ContextSelfValue));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("max"), new func_max(() => ContextSelfValue));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("abs"), new func_abs(() => ContextSelfValue));

			Func<int, PropSrc> cccb = k => ContextCascadeLookup(k);
			_ctxops.Add(IdentifierManager.SharedInstance.Request("attack_timing"), new func_attack_timing(cccb));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("enter_timing"), new func_enter_timing(cccb));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("release_timing"), new func_release_timing(cccb));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("leave_timing"), new func_leave_timing(cccb));
			_ctxops.Add(IdentifierManager.SharedInstance.Request("contact_timing"), new func_contact_timing(cccb));
		}
		static PdtEvaluator() {
			_shortops.Add(new PdtOperatorSignature("@", 2), new op_at_2());

			_shortops.Add(new PdtOperatorSignature("*", 2), new op_mul_2());
			_shortops.Add(new PdtOperatorSignature("/", 2), new op_div_2());
			_shortops.Add(new PdtOperatorSignature("%", 2), new op_mod_2());

			_shortops.Add(new PdtOperatorSignature("+", 1), new op_add_1());
			_shortops.Add(new PdtOperatorSignature("+", 2), new op_add_2());
			_shortops.Add(new PdtOperatorSignature("-", 1), new op_sub_1());
			_shortops.Add(new PdtOperatorSignature("-", 2), new op_sub_2());

			_shortops.Add(new PdtOperatorSignature("=", 2), new op_eq_2());
			_shortops.Add(new PdtOperatorSignature("<", 2), new op_lt_2());
			_shortops.Add(new PdtOperatorSignature(">", 2), new op_gt_2());

			_shortops.Add(new PdtOperatorSignature("!", 1), new op_not_1());

			_shortops.Add(new PdtOperatorSignature("frame_seq", 3), new func_frame_seq());
			_shortops.Add(new PdtOperatorSignature("in_area", 1), new func_in_area());
		}
		#region Operators
#pragma warning disable IDE1006
		#region Basic Operators
		class op_add_1 : PdtOperator {
			public op_add_1() : base(1) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_add_2 : PdtOperator {
			public op_add_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() + GetOperand(1).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_sub_1 : PdtOperator {
			public op_sub_1() : base(1) { }
			protected override void Execute() {
				float result = -GetOperand(0).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_sub_2 : PdtOperator {
			public op_sub_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() - GetOperand(1).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_mul_2 : PdtOperator {
			public op_mul_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() * GetOperand(1).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_div_2 : PdtOperator {
			public op_div_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() / GetOperand(1).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_mod_2 : PdtOperator {
			public op_mod_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() % GetOperand(1).AsNumber();
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_eq_2 : PdtOperator {
			public op_eq_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() == GetOperand(1).AsNumber() ? 1 : 0;
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_lt_2 : PdtOperator {
			public op_lt_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() < GetOperand(1).AsNumber() ? 1 : 0;
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_gt_2 : PdtOperator {
			public op_gt_2() : base(2) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() > GetOperand(1).AsNumber() ? 1 : 0;
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_not_1 : PdtOperator {
			public op_not_1() : base(1) { }
			protected override void Execute() {
				float result = GetOperand(0).AsNumber() <= 0 ? 1 : 0;
				GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(result);
			}
		}
		class op_arr : PdtOperator {
			public op_arr(int pc) : base(pc) { }
			protected override void Execute() {
				var o0 = GetOperand(0);
				int type = o0.Type;
				int len = o0.Length;
				bool blit = !IsBlittable(type);
				for (var i = 1; i < LoadedOperandCount; i++) {
					var o = GetOperand(i);
					if (o.Type != type) throw new InvalidOperationException("Cannot create variant type array");
					else if (!IsBlittable(o.Type)) blit = true;
					len += o.Length;
				}
				if (blit) GetReturnFrame(PdtInternalType.Array, len + 2 * sizeof(int)).SetArraySuffix(type, LoadedOperandCount);
				else GetReturnFrame(PdtInternalType.Vector, len + sizeof(int)).SetArraySuffix(type);
			}
			bool IsBlittable(int type) {
				return type == PdtInternalType.Number;
			}
		}
		class op_at_2 : PdtOperator {
			public op_at_2() : base(2) { }
			protected override void Execute() {
				int _;
				var op0 = GetOperand(0);
				var op1 = (int)Math.Round(GetOperand(1).AsNumber());
				if (op0.Type == PdtInternalType.Vector) {
					op0.GetArraySuffix(out _, out _);
					if (op1 >= (op0.Length - sizeof(int)) / sizeof(float)) throw new IndexOutOfRangeException();
					GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber(op1 * sizeof(float)));
				}
				else if (op0.Type == PdtInternalType.Number) {
					if (op1 != 0) throw new IndexOutOfRangeException();
					GetReturnFrame(PdtInternalType.Number, sizeof(float)).SetNumber(op0.AsNumber());
				}
				else throw new InvalidOperationException("Not a vector or number");
			}
		}
		#endregion
		#region Basic Functions
		class func_frame_seq : PdtOperator {
			public func_frame_seq() : base(3) { }
			protected override unsafe void Execute() {
				string pf = GetOperand(0).AsString();
				int f = (int)GetOperand(1).AsNumber();
				int t = (int)GetOperand(2).AsNumber();
				int pfl = pf.Length;
				int fc = t - f + 1;
				if (fc <= 0) throw new ArgumentException("Start index is greater than end index");
				int l = (f == 0 ? 1 : 0) + pfl * fc;
				for (int p = 1, i = 1; p < 4; p++, i *= 10) {
					int j = i * 10 - 1;
					if (f <= j && t >= i) {
						int m = Math.Max(f, i);
						int n = Math.Min(t, j);
						l += (n - m + 1) * i;
					}
				}
				l *= sizeof(char);
				l += sizeof(int) * (fc + 2);
				var ret = GetReturnFrame(PdtInternalType.Array, l);
				ret.SetArraySuffix(PdtInternalType.String, fc);
				int o = 0;
				for (int i = f; i <= t; i++) {
					var s = pf + i.ToString();
					ret.SetString(s, o);
					o += sizeof(int) + s.Length * sizeof(char);
				}
			}
		}
		class func_in_area : PdtOperator {
			public func_in_area() : base(1) { }
			protected override unsafe void Execute() {
				var arg = GetOperand(0);
				if (arg.Type == PdtInternalType.Error) {
					throw new InvalidOperationException("Error");
				}
				else if (arg.Type == PdtInternalType.Number && arg.AsNumber() <= 0) {
					GetReturnFrame(PdtInternalType.Null, 0);
				}
				else {
					var ret = GetReturnFrame(arg.Type, arg.Length);
					arg.CopyTo(ret);
				}
			}
		}
		class func_int_map : PdtOperator {
			public func_int_map(int pc) : base(pc) {
				if (pc < 4) throw new ArgumentOutOfRangeException("Too few parameters for int_map");
			}
			protected override unsafe void Execute() {
				var value = GetOperand(0).AsNumber();
				var offset = GetOperand(1).AsNumber();
				var step = GetOperand(2).AsNumber();
				var index = (int)((value - offset) / step);
				if (index < 0 || index >= LoadedOperandCount - 3) index = 0;
				var hit = GetOperand(index + 3);
				var ret = GetReturnFrame(hit.Type, hit.Length);
				hit.CopyTo(ret);
			}
		}
		#endregion
		#region Contextual Functions
		class func_screen_edge : PdtOperator {
			readonly Func<Transform> _ctxcb;
			public func_screen_edge(Func<Transform> ctxcb) : base(1) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ctx = _ctxcb();
				float dist;
				var ray = new Ray(ctx.position, ctx.rotation * Vector3.forward);
				ChartPlayer.frustumPlanes[(int)GetOperand(0).AsNumber()].Raycast(ray, out dist);
				var ret = GetReturnFrame(PdtInternalType.Vector, sizeof(Vector3) + sizeof(int));
				var ptr = (Vector3*)ret.TrustedAsOfLength(sizeof(Vector3) + sizeof(int));
				*ptr++ = ray.GetPoint(dist);
				*(int*)ptr = PdtInternalType.Number;
			}
		}
		class func_int : PdtOperator {
			readonly Func<PropSrc> _ctxcb;
			public func_int(Func<PropSrc> ctxcb) : base(1) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				float v;
				switch (LoadedOperandCount) {
					case 0: v = oputil.AsNumber(_ctxcb()); break;
					case 1: v = GetOperand(0).AsNumber(); break;
					default: throw new ArgumentException("Argument count not 0 or 1");
				}
				ret.SetNumber(Mathf.Floor(v));
			}
		}
		class func_clamp : PdtOperator {
			readonly Func<PropSrc> _ctxcb;
			public func_clamp(Func<PropSrc> ctxcb) : base(3) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				float min = GetOperand(0).AsNumber();
				float value, max;
				switch (LoadedOperandCount) {
					case 2:
						value = oputil.AsNumber(_ctxcb());
						max = GetOperand(1).AsNumber();
						break;
					case 3:
						value = GetOperand(1).AsNumber();
						max = GetOperand(2).AsNumber();
						break;
					default: throw new ArgumentException("Argument count not 2 or 3");
				}
				ret.SetNumber(Mathf.Clamp(value, min, max));
			}
		}
		class func_min : PdtOperator {
			readonly Func<PropSrc> _ctxcb;
			public func_min(Func<PropSrc> ctxcb) : base(2) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				float a = GetOperand(0).AsNumber();
				float b;
				switch (LoadedOperandCount) {
					case 1: b = oputil.AsNumber(_ctxcb()); break;
					case 2: b = GetOperand(1).AsNumber(); break;
					default: throw new ArgumentException("Argument count not 2 or 3");
				}
				ret.SetNumber(Mathf.Min(a, b));
			}
		}
		class func_max : PdtOperator {
			readonly Func<PropSrc> _ctxcb;
			public func_max(Func<PropSrc> ctxcb) : base(2) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				var a = GetOperand(0).AsNumber();
				float b;
				switch (LoadedOperandCount) {
					case 1: b = oputil.AsNumber(_ctxcb()); break;
					case 2: b = GetOperand(1).AsNumber(); break;
					default: throw new ArgumentException("Argument count not 2 or 3");
				}
				ret.SetNumber(Mathf.Max(a, b));
			}
		}
		class func_abs : PdtOperator {
			readonly Func<PropSrc> _ctxcb;
			public func_abs(Func<PropSrc> ctxcb) : base(1) {
				_ctxcb = ctxcb;
			}
			protected override unsafe void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				float arg;
				switch (LoadedOperandCount) {
					case 0: arg = oputil.AsNumber(_ctxcb()); break;
					case 1: arg = GetOperand(0).AsNumber(); break;
					default: throw new ArgumentException("Argument count not 0 or 1");
				}
				ret.SetNumber(Mathf.Abs(arg));
			}
		}
		#endregion
		#region Judge Functions
		static readonly int _var_fn = IdentifierManager.SharedInstance.Request("fn");
		static readonly int _var_tn = IdentifierManager.SharedInstance.Request("tn");
		static readonly int _var_ft = IdentifierManager.SharedInstance.Request("ft");
		static readonly int _var_tt = IdentifierManager.SharedInstance.Request("tt");
		static readonly int _var_fv = IdentifierManager.SharedInstance.Request("fv");
		static readonly int _var_tv = IdentifierManager.SharedInstance.Request("tv");
		abstract class JudgeFunction : PdtOperator {
			readonly Func<int, PropSrc> _ctxcb;
			protected JudgeFunction(int pc, Func<int, PropSrc> ctxcb) : base(pc) {
				_ctxcb = ctxcb;
			}
			protected sealed override void Execute() {
				var ret = GetReturnFrame(PdtInternalType.Number, sizeof(float));
				var fn = oputil.AsNumber(_ctxcb(_var_fn));
				var tn = oputil.AsNumber(_ctxcb(_var_tn));
				var ft = oputil.AsNumber(_ctxcb(_var_ft));
				var tt = oputil.AsNumber(_ctxcb(_var_tt));
				var fv = oputil.AsVector(_ctxcb(_var_fv));
				var tv = oputil.AsVector(_ctxcb(_var_tv));
				ret.SetNumber(ExecuteImpl(fn, tn, ft, tt, fv, tv) ? 1 : 0);
			}
			protected abstract bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv);
		}
		class func_attack_timing : JudgeFunction {
			public func_attack_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
			protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
				if (fv != null) return false;
				var t0 = GetOperand(0).AsNumber() + fn;
				var t1 = GetOperand(1).AsNumber() + tn;
				return tt > t0 && tt <= t1;
			}
		}
		class func_enter_timing : JudgeFunction {
			public func_enter_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
			protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
				if (fv == null || tv == null) return false;
				var t0 = GetOperand(0).AsNumber() + fn;
				return ft < t0 && tt >= t0;
			}
		}
		class func_release_timing : JudgeFunction {
			public func_release_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
			protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
				if (tv != null) return false;
				var t0 = GetOperand(0).AsNumber() + fn;
				var t1 = GetOperand(1).AsNumber() + tn;
				return ft > t0 && ft <= t1;
			}
		}
		class func_leave_timing : JudgeFunction {
			public func_leave_timing(Func<int, PropSrc> ctxcb) : base(1, ctxcb) { }
			protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
				if (fv == null || tv == null) return false;
				var t1 = GetOperand(0).AsNumber() + tn;
				return ft < t1 && tt >= t1;
			}
		}
		class func_contact_timing : JudgeFunction {
			public func_contact_timing(Func<int, PropSrc> ctxcb) : base(2, ctxcb) { }
			protected override bool ExecuteImpl(float fn, float tn, float ft, float tt, Vector3? fv, Vector3? tv) {
				var t0 = GetOperand(0).AsNumber() + fn;
				var t1 = GetOperand(1).AsNumber() + tn;
				return (fv == null || ft < t1) && (tv == null || tt >= t0);
			}
		}
		#endregion
		unsafe static class oputil {
			public static float AsNumber(PropSrc src) {
				if (src == null) throw new ArgumentNullException("src");
				int type; byte[] value;
				src.Get(out type, out value);
				if (type != PdtInternalType.Number)
					throw new ArgumentException("Not a number");
				fixed (byte* ptr = value) {
					return *(float*)ptr;
				}
			}
			public static Vector3? AsVector(PropSrc src) {
				if (src == null) throw new ArgumentNullException("src");
				int type; byte[] value;
				src.Get(out type, out value);
				if (type == PdtInternalType.Vector) {
					fixed (byte* ptr = value) {
						return *(Vector3*)ptr;
					}
				}
				else if (type == PdtInternalType.Number) {
					fixed (byte* ptr = value) {
						return new Vector3(*(float*)ptr, 0, 0);
					}
				}
				else if (type == PdtInternalType.Null) {
					return null;
				}
				else throw new ArgumentException("Not a number");
			}
		}
#pragma warning restore IDE1006
		#endregion
	}
}
