/// <summary> /// Inverts quaternion /// </summary> /// <returns> /// inverted quaternion /// </returns> public JsValue QuatInv(CpuBlock c, JsValue thizArg, JsValue[] x) { var thiz = ((ObjectInstance)thizArg); var q1 = BlockUtils.ToQuat(thiz); return(BlockUtils.Quat2Obj(c, Quaternion.Inverse(q1))); }
public ApiObjectConstructor(CpuBlock c, string name, List <CpuApiProperty> staticProps) : base(c.Interp, new JsString(name)) { cpu = c; Props = staticProps?.ToDictionary(x => x.Name); var properties = new PropertyDictionary(Props?.Count ?? 0, checkExistingKeys: false); if (Props != null) { foreach (var kp in Props) { if (kp.Value is CpuApiFunc f) { if (f.Name == ConstructorMethodName) { Constructor = f.Implementation; } else { properties[kp.Key] = new PropertyDescriptor(new ClrFunctionInstance(Engine, kp.Key, (t, a) => WrappedApi(t, a, f.Implementation), f.Arguments.Count, PropertyFlag.Configurable), PropertyFlag.Configurable); } } else if (kp.Value is CpuApiValue v) { properties[kp.Key] = new PropertyDescriptor(v.Value, PropertyFlag.Configurable); } } } SetProperties(properties); }
/// <summary> /// Magnitude of 3d Vector /// </summary> /// <param name="c"></param> /// <param name="thizArg"></param> /// <param name="x"></param> /// <returns> /// The magnitude of Vector3 /// </returns> public JsValue VecMag(CpuBlock c, JsValue thizArg, JsValue[] x) { var vobj = ((ObjectInstance)thizArg); Vector3 v = BlockUtils.ToVector3(vobj); return(v.magnitude); }
public JsValue Float(CpuBlock c, JsValue ctx, JsValue[] x) { if (x.Length < 1 || !BlockUtils.TryGetFloat(x[0], out float v)) { throw new Exception("Invalid value"); } return(v); }
public JsValue Str(CpuBlock c, JsValue ctx, JsValue[] x) { if (x.Length < 1) { throw new Exception("Invalid value"); } return(x[0]?.ToString()); }
// Legacy APIs public JsValue Int(CpuBlock c, JsValue ctx, JsValue[] x) { if (x.Length < 1 || !BlockUtils.TryGetLong(x[0], out long v)) { throw new Exception("Invalid value"); } return(v); }
public static ApiObjectPrototype CreatePrototypeObject(CpuBlock block, ApiObjectConstructor constructor, List <CpuApiProperty> props) { var obj = new ApiObjectPrototype(block, props) { _prototype = block.Interp.Object.PrototypeObject, _constructor = constructor }; return(obj); }
public static ApiObjectConstructor CreateApiConstructor(CpuBlock cpu, string name, List <CpuApiProperty> staticProps, List <CpuApiProperty> instanceProps) { var obj = new ApiObjectConstructor(cpu, name, staticProps) { _prototype = cpu.Interp.Function.PrototypeObject, }; obj.PrototypeObject = ApiObjectPrototype.CreatePrototypeObject(cpu, obj, instanceProps); obj._prototypeDescriptor = new PropertyDescriptor(obj.PrototypeObject, PropertyFlag.AllForbidden); return(obj); }
/// <summary> /// Calculates the vector cross product /// </summary> /// <param name="c"></param> /// <param name="thizArg"></param> /// <param name="x"></param> /// <returns> /// The cross product of two 3D vectors. /// </returns> public JsValue VecCross(CpuBlock c, JsValue thizArg, JsValue[] x) { if (x.Length < 1) { throw new Exception("Invalid value"); } var v1obj = ((ObjectInstance)thizArg); var v2obj = ((ObjectInstance)x[0]); Vector3 v1 = BlockUtils.ToVector3(v1obj); Vector3 v2 = BlockUtils.ToVector3(v2obj); return(BlockUtils.Vec2Obj(c, Vector3.Cross(v1, v2))); }
public JsValue CreateThis(CpuBlock c, JsValue thizArg, JsValue[] args) { var thiz = ((ObjectInstance)thizArg); var instf = InstanceFields; for (int i = 0; i < 3; ++i) { if (i >= args.Length) { return(thizArg); } float value = BlockUtils.TryGetFloat(args[i], out value) ? value : 0; thiz.Set(instf[i].Name, value); } return(thizArg); }
/// <summary> /// Multiply vector3 by scalar /// </summary> /// <param name="c"></param> /// <param name="thizArg"></param> /// <param name="x"></param> /// <returns> /// The result of a vector3 multiplied by scalar. /// </returns> public JsValue VecMul(CpuBlock c, JsValue thizArg, JsValue[] x) { if (x.Length < 1) { throw new Exception("Invalid value"); } var vobj = ((ObjectInstance)thizArg); float f; if (!BlockUtils.TryGetFloat(x[0], out f)) { throw new Exception("Invalid value"); } Vector3 v = BlockUtils.ToVector3(vobj); return(BlockUtils.Vec2Obj(c, v * f)); }
public void OnGUI() { if (Game.IsSimulating) { return; } if (textStyle == null) { InitFont(); } var mach = Machine.Active(); if (mach == null || !MachineHandlers.ContainsKey(mach)) { return; } SelectedCpu = MachineHandlers[mach].GetCpus().Where(x => x.Key.IsModifying).Select(x => x.Value).FirstOrDefault(); if (SelectedCpu != null) { if (PrevCpu != SelectedCpu) { PrevCpu = SelectedCpu; sourceScript = editedScript = SelectedCpu.Script.Value; lastScriptChangeTime = Time.time; editHistory = new HistoryBuffer <string>(50); editHistory.Add(sourceScript); } uiRect = GUILayout.Window(windowId, uiRect, GuiFunc, "CPU edit"); } else { if (KeyTexts.Count > 0) { KeyTexts = new Dictionary <MExtKey, string>(); } } }
/// <summary> /// Multiply quaternion with either another quaternion or a 3d vector. /// </summary> /// <returns> /// Vector if second argument is vector and quaternion if second argument is quaternion /// </returns> public JsValue QuatMult(CpuBlock c, JsValue thizArg, JsValue[] x) { if (x.Length < 1) { throw new Exception("Invalid value"); } var q1obj = ((ObjectInstance)thizArg); var q2obj = ((ObjectInstance)x[0]); var q1 = BlockUtils.ToQuat(q1obj); if (q2obj.HasProperty("w")) { var q2 = BlockUtils.ToQuat(q2obj); return(BlockUtils.Quat2Obj(c, q1 * q2)); } else { var v = BlockUtils.ToVector3(q2obj); return(BlockUtils.Vec2Obj(c, q1 * v)); } }
public void Attach(CpuBlock block) { foreach (var api in RootApi) { block.Interp.SetValue(api.Key, (t, a) => api.Value.Implementation(block, t, a)); } foreach (var kp in ApiNamespaces) { var obj = block.Interp.Global.Get(kp.Key) as ObjectInstance; if (obj != null) { throw new Exception($"Runtime error: namespace {kp.Key} already exists"); } obj = ApiObjectConstructor.CreateApiConstructor(block, kp.Key, kp.Value.StaticFields, kp.Value.InstanceFields); block.Interp.Global.Set(kp.Key, obj); } // Legacy crutch var math = block.Interp.Global.Get("Math") as ObjectInstance; math.Set("newton", block.Interp.Global.Get("MathExt").Get("newton")); }
public void Awake() { // Loading var engine = new Jint.Engine(); //var logic = new Interpreter(); Registers = new Dictionary <Type, Action <BlockBehaviour, KeyInputController> >(); Unregisters = new Dictionary <Type, Action <BlockBehaviour> >(); ModConsole.RegisterCommand("script", args => { var text = string.Join(" ", args); //var func = logic.PrepareScript(text); //logic.AddExtFunc(func, "print", (ctx, x) => { ModConsole.Log(x[0]?.ToString()); return null; }, true); //logic.SetScript(func); //var res = logic.ContinueScript(1000); Func <JsValue, JsValue[], JsValue> printCb = (thiz, x) => { ModConsole.Log(x[0]?.ToObject().ToString()); return(x[0]); }; JsValue curV = null; Func <JsValue, JsValue[], JsValue> irqv = (thiz, x) => { curV = x[0]; return(null); }; var script = new JavaScriptParser(text, Jint.Engine.DefaultParserOptions).ParseScript(); engine.SetValue("print", printCb); engine.SetValue("irqv", irqv); engine.SetScript(script); engine.Executor.OnLog = (x) => ModConsole.Log(x?.ToString()); bool cli = false; engine.Executor.OnNextStatement = () => { if (cli) { return; } cli = true; try { if (curV != null) { engine.Invoke(curV); } } finally { cli = false; } }; var res = engine.ContinueScript(1000); ModConsole.Log(res?.ToString()); }, "exec script"); ModConsole.RegisterCommand("cpuapi", args => { foreach (var line in SingleInstance <Blocks.Api.CpuApi> .Instance.GetHelp()) { ModConsole.Log(line); } }, "print cpu api list"); ModConsole.RegisterCommand("sensordbg", args => { DrawSensorDebug = args.Length < 1 ? false : args[0] == "true"; }, "print sensor debug points"); CpuBlock.Create(this); // These creator functions find corresponding block in game prefabs // and replace it with inheritor ExtLogicGate.Create(this); ExtAltimeterBlock.Create(this); ExtSpeedometerBlock.Create(this); ExtAnglometerBlock.Create(this); ExtSensorBlock.Create(this); ModConsole.Log($"Logic mod Awake"); Events.OnMachineSimulationToggle += Events_OnMachineSimulationToggle; LineMaterial = new Material(Shader.Find("Hidden/Internal-Colored")); LineMaterial.hideFlags = HideFlags.HideAndDontSave; LineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha); LineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); LineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off); LineMaterial.SetInt("_ZWrite", 0); Camera.onPostRender += DrawConnectingLines; Events.OnBlockInit += InitBlock; CpuInfoMessage = ModNetworking.CreateMessageType(new DataType[] { DataType.Block, DataType.ByteArray }); CpuLogMessage = ModNetworking.CreateMessageType(new DataType[] { DataType.Block, DataType.String }); ModNetworking.Callbacks[CpuInfoMessage] += (Action <Message>)((msg) => { Player localPlayer = Player.GetLocalPlayer(); if (msg == null || localPlayer == null || !localPlayer.IsHost) { return; } var block = msg.GetData(0) as Modding.Blocks.Block; if (!(block?.BlockScript is CpuBlock cpu)) { return; } if (block.Machine == localPlayer.Machine) { return; // don't read updates for MY machine! } cpu.AfterEdit_ServerRecv((byte[])msg.GetData(1)); }); ModNetworking.Callbacks[CpuLogMessage] += (Action <Message>)((msg) => { if (msg == null) { return; } var block = msg.GetData(0) as Modding.Blocks.Block; if (!(block?.BlockScript is CpuBlock cpu)) { return; } cpu.LogMessage((string)msg.GetData(1)); }); }
public void RemoveCpuBlock(CpuBlock c) { CpuBlocks.Remove(c.BlockBehaviour); }
public void AddCpuBlock(CpuBlock c) { CpuBlocks[c.BlockBehaviour] = c; }
// Find a zero of a real or complex function using the Newton-Raphson // (or secant or Halley’s) method. // // Math.newton(func, x0, fprime=null, tol=1.48e-08, maxiter=50, fprime2=null, // x1, rtol=0.0, full_output=false) // // Mimicks scipy's implementation of scipy.optimize.newton // // Parameters // func: function // The function whose zero is wanted. It must be a function of a // single variable // x0: float // An initial estimate of the zero that should be somewhere near // the actual zero. // fprime : function, optional // The derivative of the function when available and convenient. If it // is null (default), then the secant method is used. // tol : float, optional // The allowable error of the zero value. // maxiter : int, optional // Maximum number of iterations. // fprime2 : function, optional // The second order derivative of the function when available and // convenient. If it is null (default), then the normal Newton-Raphson // or the secant method is used. If it is not null, then Halley's method // is used. // x1 : float, optional // Another estimate of the zero that should be somewhere near the // actual zero. Used if `fprime` is not provided. // rtol : float, optional // Tolerance (relative) for termination. // full_output : bool, optional // If `full_output` is false (default), the root is returned. // If true, the dictionary {{"root": root}, {"converged": true/false}, // {"iter": numIter}} is returned. public JsValue Newton(CpuBlock cpu, JsValue ctx, JsValue[] x) { var eng = cpu.Interp; int l = x.Length; // Arguments and their default values: FunctionInstance func; float x0; JsValue fprime = null; float tol = 1.48e-08F; long maxiter = 50; JsValue fprime2 = null; float x1 = 0; float rtol = 0.0F; bool full_output = false; bool x1Provided = false; JsValue[] args = new JsValue[1]; if (l < 2) { throw new Exception("Invalid value"); } // Conditionally initialize the arguments void Parse() { int curArgIndex = 0; func = x[curArgIndex++] as FunctionInstance; if (!BlockUtils.TryGetFloat(x[curArgIndex++], out x0)) { throw new Exception("Invalid value"); } if (curArgIndex >= l) { return; } fprime = x[curArgIndex++]; if (curArgIndex >= l) { return; } if (!BlockUtils.TryGetFloat(x[curArgIndex++], out tol)) { throw new Exception("Invalid value"); } if (curArgIndex >= l) { return; } if (!BlockUtils.TryGetLong(x[curArgIndex++], out maxiter)) { throw new Exception("Invalid value"); } if (curArgIndex >= l) { return; } fprime2 = x[curArgIndex++]; if (curArgIndex >= l) { return; } x1Provided = BlockUtils.TryGetFloat(x[curArgIndex++], out x1); if (curArgIndex >= l) { return; } if (!BlockUtils.TryGetFloat(x[curArgIndex++], out rtol)) { throw new Exception("Invalid value"); } if (curArgIndex >= l) { return; } full_output = BlockUtils.GetBool(x[curArgIndex++]); } Parse(); if (tol <= 0) { throw new Exception("tol too small (" + tol + " <= 0)"); } if (maxiter < 1) { throw new Exception("maxiter must be greater than 0"); } float p0 = x0; long itr = 0; float p = 0; if (fprime is FunctionInstance fprimeFunc) { // Newton - Raphson method for (; itr < maxiter; ++itr) { // first evaluate fval args[0] = p0; float fval = (float)TypeConverter.ToNumber(func.Call(ctx, args)); // if fval is 0, a root has been found, then terminate if (fval == 0) { return(_newton_result_select(eng, full_output, p0, itr, converged: true)); } float fder = (float)TypeConverter.ToNumber(fprimeFunc.Call(ctx, args)); // stop iterating if the derivative is zero if (fder == 0) { return(_newton_result_select(eng, full_output, p0, itr + 1, converged: false)); } // Newton step float newton_step = fval / fder; if (fprime2 is FunctionInstance fp2func) { float fder2 = (float)TypeConverter.ToNumber(fp2func.Call(ctx, args)); // Halley's method: // newton_step /= (1.0 - 0.5 * newton_step * fder2 / fder) // Only do it if denominator stays close enough to 1 // Rationale: If 1-adj < 0, then Halley sends x in the // opposite direction to Newton. Doesn't happen if x is close // enough to root. float adj = newton_step * fder2 / fder / 2; if (Math.Abs(adj) < 1) { newton_step /= 1.0F - adj; } } p = p0 - newton_step; if (WithinTol(p, p0, atol: tol, rtol: rtol)) { return(_newton_result_select(eng, full_output, p, itr + 1, converged: true)); } p0 = p; } } else { // secant method float p1, q0, q1; if (x1Provided) { if (x1 == x0) { throw new Exception("x1 and x0 must be different"); } p1 = x1; } else { float eps = 1e-4F; p1 = x0 * (1 + eps); p1 += (p1 >= 0 ? eps : -eps); } args[0] = p0; q0 = (float)TypeConverter.ToNumber(func.Call(ctx, args)); args[0] = p1; q1 = (float)TypeConverter.ToNumber(func.Call(ctx, args)); if (Math.Abs(q1) < Math.Abs(q0)) { float temp = q1; q1 = q0; q0 = temp; temp = p0; p0 = p1; p1 = temp; } for (; itr < maxiter; ++itr) { if (q0 == q1) { p = (p1 + p0) / 2.0F; if (p1 != p0) { return(_newton_result_select(eng, full_output, p, itr + 1, converged: false)); } else { return(_newton_result_select(eng, full_output, p, itr + 1, converged: true)); } } else { // Secant Step if (Math.Abs(q1) > Math.Abs(q0)) { p = (-q0 / q1 * p1 + p0) / (1.0F - q0 / q1); } else { p = (-q1 / q0 * p0 + p1) / (1.0F - q1 / q0); } } if (WithinTol(p, p1, atol: tol, rtol: rtol)) { return(_newton_result_select(eng, full_output, p, itr + 1, converged: true)); } p0 = p1; q0 = q1; p1 = p; args[0] = p1; q1 = (float)TypeConverter.ToNumber(func.Call(ctx, args)); } } return(_newton_result_select(eng, full_output, p, itr + 1, converged: false)); }
private ApiObjectPrototype(CpuBlock block, List <CpuApiProperty> props) : base(block.Interp) { cpu = block; Props = props?.ToDictionary(x => x.Name); }