object ICloneable.Clone() { FrameState clone = this.MemberwiseClone() as FrameState; clone.Parameters = this.Parameters.ToList(); clone.StateParameters = this.StateParameters.ToList(); return(clone); }
protected virtual void WriteActorStateMachine(Actor actor) { Random r = new Random(); var jumpTargetLabelsByState = actor.StateMachine.States.OfType <GoToState>().ToDictionary(p => p, p => "__j" + r.Next(0, int.MaxValue)); var labelsFromJumpTargets = jumpTargetLabelsByState.ToLookup(p => p.Key.Target, p => p.Value); ILookup <State, string> labelsByState = actor.StateMachine.Labels.ToLookup(p => p.Value, p => p.Key).Union(labelsFromJumpTargets); foreach (State state in actor.StateMachine.States) { if (labelsByState.Contains(state)) { foreach (string label in labelsByState[state].Where(p => !p.Contains(':'))) { this.writer.WriteLine(label + ":"); } } if (state is FrameState) { FrameState frameState = state as FrameState; this.writer.WriteLine(frameState.Sprite + " " + frameState.Frame + " " + frameState.Duration + (frameState.IsBright ? " BRIGHT " : " ") + frameState.CodePointer); } else if (state is GoToState) { this.writer.WriteLine("goto " + jumpTargetLabelsByState[state as GoToState]); } else if (state is FailState) { this.writer.WriteLine("fail"); } else if (state is StopState) { this.writer.WriteLine("stop"); } } }
protected StateMachine ParseStateMachine(Actor actor) { string[] lines = actor.StatesText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); var states = new List<State>(); var labels = new Dictionary<string, State>(); // non-root actors inheirit state machine from their parents if (actor.Parent != null) { StateMachine parentMachine = actor.Parent.StateMachine.CloneForChild(actor.Parent.Name); states = parentMachine.States.ToList(); labels = parentMachine.Labels.ToDictionary(p => p.Key, p => p.Value); } var openGoTos = new Dictionary<GoToState, KeyValuePair<string, int>>(); List<string> openLabels = new List<string>(); string lastLabel = string.Empty; foreach (string line in lines) { string trimmed = line.Trim(); if (trimmed == string.Empty) { continue; } string framePattern = @" ([A-Za-z0-9_\-""#]{4,6}) # sprite name \s+ ([A-Za-z\[\]\\""#]+) # frame list \s+ (-?\d+) # duration (\s+bright\s+) # bright yes/no ?(.*) # code pointer "; Match labelMatch = Regex.Match(line, "([A-Za-z0-9_.]+):", RegexOptions.IgnoreCase); Match gotoMatch = Regex.Match(line, @"goto\s+([A-Za-z0-9_:.]+)?(\s*\+\s*(\d+))?", RegexOptions.IgnoreCase); Match frameMatch = Regex.Match(line, framePattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); List<State> currentLineStates = new List<State>(); if (trimmed.Equals("fail", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new FailState()); } else if (trimmed.Equals("stop", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new StopState()); } else if (trimmed.Equals("loop", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); openGoTos.Add(state, new KeyValuePair<string, int>(lastLabel, 0)); currentLineStates.Add(state); } else if (trimmed.Equals("wait", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); state.Target = states.Last(); currentLineStates.Add(state); } else if (gotoMatch.Success) { int offset = 0; int.TryParse(gotoMatch.Groups[3].Value, out offset); State state = new GoToState(); openGoTos.Add(state as GoToState, new KeyValuePair<string, int>(gotoMatch.Groups[1].Value.ToLower(), offset)); currentLineStates.Add(state); } else if (labelMatch.Success) { openLabels.Add(labelMatch.Groups[1].Value.ToLower()); lastLabel = labelMatch.Groups[1].Value.ToLower(); } else if (frameMatch.Success) { foreach (char frame in frameMatch.Groups[2].Value.TrimQuotes()) { FrameState newState = new FrameState() { Sprite = frameMatch.Groups[1].Value, Frame = frame, Duration = int.Parse(frameMatch.Groups[3].Value), IsBright = frameMatch.Groups[4].Value != string.Empty, CodePointer = frameMatch.Groups[5].Value }; currentLineStates.Add(newState); } } else { throw new Exception("Could not parse state line \"" + trimmed + "\" in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } if (currentLineStates.Count > 0) { foreach (string label in openLabels) { labels[label] = currentLineStates[0]; } openLabels.Clear(); } states.AddRange(currentLineStates); } foreach (var openGoTo in openGoTos) { GoToState state = openGoTo.Key; string targetLabel = openGoTo.Value.Key; int offset = openGoTo.Value.Value; State targetState = null; if (targetLabel == string.Empty) { targetState = state; } else { if (!labels.ContainsKey(targetLabel)) { throw new Exception("Jump target \"" + targetLabel + "\" not found in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } targetState = labels[targetLabel]; } int stateIndex = states.IndexOf(targetState); Debug.Assert(stateIndex >= 0, "Goto target state not found!"); state.Target = states[stateIndex + offset]; // only FrameStates count towards the offset int numStatesToSkip = offset; int i = stateIndex; state.Target = states[i]; while (numStatesToSkip >= 1) { i++; state.Target = states[i]; if (state.Target.CountsAsState) { numStatesToSkip--; } } } return new StateMachine(states, labels); }
protected StateMachine ParseStateMachine(Actor actor) { string[] lines = actor.StatesText.Split(new string[] { "\r\n", "\n" }, StringSplitOptions.None); var states = new List <State>(); var labels = new Dictionary <string, State>(); // non-root actors inheirit state machine from their parents if (actor.Parent != null) { StateMachine parentMachine = actor.Parent.StateMachine.CloneForChild(actor.Parent.Name); states = parentMachine.States.ToList(); labels = parentMachine.Labels.ToDictionary(p => p.Key, p => p.Value); } var openGoTos = new Dictionary <GoToState, KeyValuePair <string, int> >(); List <string> openLabels = new List <string>(); string lastLabel = string.Empty; foreach (string line in lines) { string trimmed = line.Trim(); if (trimmed == string.Empty) { continue; } string framePattern = @" ([A-Za-z0-9_\-""#]{4,6}) # sprite name \s+ ([A-Za-z\[\]\\""#]+) # frame list \s+ (-?\d+) # duration (\s+bright\s+) # bright yes/no ?(.*) # code pointer "; Match labelMatch = Regex.Match(line, "([A-Za-z0-9_.]+):", RegexOptions.IgnoreCase); Match gotoMatch = Regex.Match(line, @"goto\s+([A-Za-z0-9_:.]+)?(\s*\+\s*(\d+))?", RegexOptions.IgnoreCase); Match frameMatch = Regex.Match(line, framePattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); List <State> currentLineStates = new List <State>(); if (trimmed.Equals("fail", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new FailState()); } else if (trimmed.Equals("stop", StringComparison.OrdinalIgnoreCase)) { currentLineStates.Add(new StopState()); } else if (trimmed.Equals("loop", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); openGoTos.Add(state, new KeyValuePair <string, int>(lastLabel, 0)); currentLineStates.Add(state); } else if (trimmed.Equals("wait", StringComparison.OrdinalIgnoreCase)) { GoToState state = new GoToState(); state.Target = states.Last(); currentLineStates.Add(state); } else if (gotoMatch.Success) { int offset = 0; int.TryParse(gotoMatch.Groups[3].Value, out offset); State state = new GoToState(); openGoTos.Add(state as GoToState, new KeyValuePair <string, int>(gotoMatch.Groups[1].Value.ToLower(), offset)); currentLineStates.Add(state); } else if (labelMatch.Success) { openLabels.Add(labelMatch.Groups[1].Value.ToLower()); lastLabel = labelMatch.Groups[1].Value.ToLower(); } else if (frameMatch.Success) { foreach (char frame in frameMatch.Groups[2].Value.TrimQuotes()) { FrameState newState = new FrameState() { Sprite = frameMatch.Groups[1].Value, Frame = frame, Duration = int.Parse(frameMatch.Groups[3].Value), IsBright = frameMatch.Groups[4].Value != string.Empty, CodePointer = frameMatch.Groups[5].Value }; currentLineStates.Add(newState); } } else { throw new Exception("Could not parse state line \"" + trimmed + "\" in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } if (currentLineStates.Count > 0) { foreach (string label in openLabels) { labels[label] = currentLineStates[0]; } openLabels.Clear(); } states.AddRange(currentLineStates); } foreach (var openGoTo in openGoTos) { GoToState state = openGoTo.Key; string targetLabel = openGoTo.Value.Key; int offset = openGoTo.Value.Value; State targetState = null; if (targetLabel == string.Empty) { targetState = state; } else { if (!labels.ContainsKey(targetLabel)) { throw new Exception("Jump target \"" + targetLabel + "\" not found in actor \"" + actor.Name + "\" in file \"" + actor.File.FullName + "\"."); } targetState = labels[targetLabel]; } int stateIndex = states.IndexOf(targetState); Debug.Assert(stateIndex >= 0, "Goto target state not found!"); state.Target = states[stateIndex + offset]; // only FrameStates count towards the offset int numStatesToSkip = offset; int i = stateIndex; state.Target = states[i]; while (numStatesToSkip >= 1) { i++; state.Target = states[i]; if (state.Target.CountsAsState) { numStatesToSkip--; } } } return(new StateMachine(states, labels)); }