/// <summary> /// Replaces CompiledData instance. /// </summary> public void ReplaceCompiledData(CompiledData cd) { lock (_locker) { _compiledDataToBeReplaced = cd; } }
/// <summary> /// Compiles game class code. /// </summary> private void CompileInternal(string code, bool saveState) { var linesOffset = Header.Length; var compiledSuccessfully = false; var compilationErrorOnLine = -1; string compilationErrorText = null; string finalCode = $"{string.Join("\n", Header)}\n{code}\n{string.Join("\n", Footer)}\n{string.Join("\n", WpfWrapper)}"; var results = _compiler.CompileAssemblyFromSource(_compilerParameters, finalCode); if (results.Errors.Count == 0) { var asem = results.CompiledAssembly; var types = asem.GetTypes(); Type type = null; for (var i = 0; i < types.Length; ++i) { var attrs = types[i].CustomAttributes; foreach (var attr in attrs) { if (attr.AttributeType.Name == "MainClass") { type = types[i]; break; } } } if (type != null) { var inst = Activator.CreateInstance(type); var fs = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var compiledData = new CompiledData { Instance = inst, Fields = fs, NeedToSaveState = saveState, DrawTrackDelegates = new List<Action<DrawingContext>>() }; var methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); for (var i = 0; i < methods.Length; ++i) { foreach (var attr in methods[i].CustomAttributes) { if (attr.AttributeType.Name == "InitMethod" && IsInitMethodSignature(methods[i])) compiledData.InitDelegate = (Action) Delegate.CreateDelegate(typeof (Action), inst, methods[i]); if (attr.AttributeType.Name == "DrawMethod" && IsDrawMethodSignature(methods[i])) compiledData.DrawDelegate = (Action<DrawingContext>) Delegate.CreateDelegate(typeof (Action<DrawingContext>), inst, methods[i]); if (attr.AttributeType.Name == "DrawTrackMethod" && IsDrawTrackMethodSignature(methods[i])) compiledData.DrawTrackDelegates.Add((Action<DrawingContext>) Delegate.CreateDelegate(typeof (Action<DrawingContext>), inst, methods[i])); if (attr.AttributeType.Name == "TickMethod" && IsTickMethodSignature(methods[i])) compiledData.TickDelegate = (Action<double, Dictionary<char, bool>>) Delegate.CreateDelegate(typeof (Action<double, Dictionary<char, bool>>), inst, methods[i]); } } compiledSuccessfully = true; if (Compiled != null) { var tmpCompiled = Compiled; _synchronizationContext.Send( o => tmpCompiled(this, new CompiledEventArgs(compiledData)), null); } } } else { compilationErrorOnLine = results.Errors[0].Line - linesOffset; compilationErrorText = results.Errors[0].ErrorText; } if (!compiledSuccessfully && CompilationError != null) { _synchronizationContext.Send( o => CompilationError(this, new CompilationErrorEventArgs(compilationErrorOnLine, compilationErrorText)), null); } lock (_locker) { _compilingTask = null; if (_pendingCode != null) { var tmp = string.Copy(_pendingCode); _compilingTask = Task.Factory.StartNew(() => CompileInternal(tmp, _saveState)); _pendingCode = null; } } }
public CompiledEventArgs(CompiledData compiledData) { CompiledData = compiledData; }
/// <summary> /// Game tick method. /// </summary> private void GameTick() { var dtStopwatch = new Stopwatch(); var gameTickStopwatch = new Stopwatch(); var fieldsChangedStopwacth = new Stopwatch(); var immediateFieldsChanged = false; uint ii = 0; fieldsChangedStopwacth.Start(); while (!_evExit.WaitOne(SettingsForm.Instance.DesiredDt)) { // copy values to local variables in case they change during game tick bool justPausedLocal; bool pausedLocal; bool needToSimulateTimelapseSceneLocal; Dictionary<char, bool> inputLocal; CompiledData compiledDataToBeReplacedLocal; int currentTrackBarValueLocal; lock (_locker) { justPausedLocal = _justPaused; _justPaused = false; pausedLocal = Paused; needToSimulateTimelapseSceneLocal = _needToSimulateTimelapseScene; _needToSimulateTimelapseScene = false; inputLocal = new Dictionary<char, bool>(_input); compiledDataToBeReplacedLocal = _compiledDataToBeReplaced; _compiledDataToBeReplaced = null; currentTrackBarValueLocal = CurrentTrackBarValue; } gameTickStopwatch.Restart(); // react to StoreLastFrames value change in pause mode if (pausedLocal && _dynamicGameSimulator.Snapshots.Count != SettingsForm.Instance.StoreLastFrames) { if (_dynamicGameSimulator.Snapshots.Count > SettingsForm.Instance.StoreLastFrames) { var count = _dynamicGameSimulator.Snapshots.Count - SettingsForm.Instance.StoreLastFrames; _dynamicGameSimulator.RemoveSnapshotsFromEnd(count); currentTrackBarValueLocal = Math.Min(currentTrackBarValueLocal, _dynamicGameSimulator.Snapshots.Count); CurrentTrackBarValue = currentTrackBarValueLocal; } else { var count = SettingsForm.Instance.StoreLastFrames - _dynamicGameSimulator.Snapshots.Count; if (justPausedLocal) { currentTrackBarValueLocal = _dynamicGameSimulator.Snapshots.Count; CurrentTrackBarValue = currentTrackBarValueLocal; } _dynamicGameSimulator.AddDummySnapshots(count); _dynamicGameSimulator.SimulateGame(_dynamicGameSimulator.Snapshots.Count - count - 1); if (justPausedLocal) { CurrentTrackBarValueChanged?.Invoke(this, EventArgs.Empty); } } GraphicsControl.Dispatcher.Invoke(_dynamicGameSimulator.RenderTimelapseScene); } // perform hot code swapping if (compiledDataToBeReplacedLocal != null) { var canGoOn = true; if (SettingsForm.Instance.CheckInfiniteLoops) { var state = compiledDataToBeReplacedLocal.DumpGameState(); canGoOn = compiledDataToBeReplacedLocal.CheckWhileTrue(16, inputLocal); compiledDataToBeReplacedLocal.SetGameState(state); } if (canGoOn) { if (compiledDataToBeReplacedLocal.NeedToSaveState) { var state = CompiledData.DumpGameState(); CompiledData = compiledDataToBeReplacedLocal; CompiledData.SetGameState(state); } else { CompiledData = compiledDataToBeReplacedLocal; CompiledData.TryInvokeInitDelegate(); Paused = false; pausedLocal = false; needToSimulateTimelapseSceneLocal = false; _dynamicGameSimulator.RemoveSnapshotsFromEnd(_dynamicGameSimulator.Snapshots.Count); PausedChanged?.Invoke(this, EventArgs.Empty); } } } // simulate game if (needToSimulateTimelapseSceneLocal) { _dynamicGameSimulator.SimulateGame(currentTrackBarValueLocal - 1); } // call move delegate dtStopwatch.Stop(); var dt = 1000.0*dtStopwatch.ElapsedTicks/Stopwatch.Frequency; var b = currentTrackBarValueLocal < _dynamicGameSimulator.Snapshots.Count && !pausedLocal; MoveScene(b ? _dynamicGameSimulator.Snapshots[currentTrackBarValueLocal].Dt : dt, b && SettingsForm.Instance.UseTrackedInput ? _dynamicGameSimulator.Snapshots[currentTrackBarValueLocal].Input : inputLocal, currentTrackBarValueLocal - 1); dtStopwatch.Restart(); // take snapshot if (!pausedLocal) { if (currentTrackBarValueLocal < _dynamicGameSimulator.Snapshots.Count) { CurrentTrackBarValue = currentTrackBarValueLocal + 1; CurrentTrackBarValueChanged?.Invoke(this, EventArgs.Empty); } else { _dynamicGameSimulator.TakeSnapshot(inputLocal, dt, SettingsForm.Instance.StoreLastFrames); } } // render TimelapseScene if (needToSimulateTimelapseSceneLocal) { GraphicsControl.Dispatcher.Invoke(_dynamicGameSimulator.RenderTimelapseScene); } // call draw delegate if (!GraphicsControl.IsRendering) { GraphicsControl.Dispatcher.BeginInvoke(DispatcherPriority.Render, (MethodInvoker) GraphicsControl.InvalidateVisual); } // fire FieldsChanged event if (fieldsChangedStopwacth.ElapsedMilliseconds >= 100 || immediateFieldsChanged) { fieldsChangedStopwacth.Restart(); immediateFieldsChanged = !FireFieldsChangedEvent(); } // wait if (SettingsForm.Instance.WaitAfterEachTick) { dtStopwatch.Stop(); Thread.Sleep(SettingsForm.Instance.WaitAfterEachTickMsec); dtStopwatch.Start(); } gameTickStopwatch.Stop(); // log if (ii++%40 == 0) { _logLabel.Owner.BeginInvoke((MethodInvoker) (() => _logLabel.Text = $"GameTick = {1000.0*gameTickStopwatch.ElapsedTicks/Stopwatch.Frequency:F3}; dt = {dt:F3}")); } } }