using QFramework; using System; using System.Collections.Generic; using System.Linq; using System.Xml; using System.Xml.Linq; using UnityEngine; using UnityEngine.Assertions.Must; namespace XMLTool { public class AppData { public List Modules { get; set; } } public class Module { public string type { get; set; } public string Scene { get; set; } public string ModuleName { get; set; } public List Operations { get; set; } public List Devices { get; set; } public Dictionary FSM = new Dictionary(); public Dictionary ActionDict { get; set; } public Score score; } public class Device { public string Name { get; set; } public string Icon { get; set; } public string HighColor { get; set; } public string Path { get; set; } public string Tip { get; set; } public string BoxColliderSize { get; set; } public string BoxColliderCenter { get; set; } public bool MeshCollider { get; set; } } public class Score { public List scores; } public class ScoreStep { public string step; public string name; public string sum; public string bind; public float value; } public class ActionItem { public string Name { get; set; } public string Type { get; set; } public string Value { get; set; } public List SubActions { get; set; } } public class Action : ActionItem { } public class Condition : ActionItem { } public class FSM { public string Name { get; set; } public List Transisions { get; set; } public Dictionary StateDict { get; set; } } public class State { public string Name { get; set; } public StatePart Enter { get; set; } public StatePart Exit { get; set; } } public class StatePart { public Action Action { get; set; } } public class Transision { public string Name { get; set; } public string From { get; set; } public string To { get; set; } public Condition Action { get; set; } } public class Operation { public string moduleType { get; set; } public List Steps { get; set; } } public class Step { public Step Parent { get; set; } public string Name { get; set; } public Action Reset { get; set; } public Action Start { get; set; } public Action Finished { get; set; } public bool isFinished = false; public List SubSteps { get; set; } } public class XmlParser { public static AppData ParseXml(string xmlString) { // 加载XML XDocument doc = XDocument.Parse(xmlString); // 获取根元素 XElement appDataElement = doc.Root; // 初始化AppData对象 AppData appData = new AppData { Modules = new List(), }; // 获取模块元素 foreach (XElement moduleElement in appDataElement.Elements("Module")) { if (moduleElement != null) { Module module = new Module() { Devices = new List(), ActionDict = new Dictionary(), Operations = new List(), }; appData.Modules.Add(module); // 解析模块名称 module.type = moduleElement.Element("Type")?.Value; module.ModuleName = moduleElement.Element("Name")?.Value; module.Scene = moduleElement.Element("Scene")?.Value; // 解析设备 foreach (XElement deviceElement in moduleElement.Elements("Device")) { Device device = new Device { Name = deviceElement.Element("Name")?.Value, Icon = deviceElement.Element("Icon")?.Value, HighColor = deviceElement.Element("HighLight")?.Attribute("color")?.Value, Path = deviceElement.Element("Path")?.Value, Tip = deviceElement.Element("Tip")?.Value, MeshCollider = deviceElement.Element("MeshCollider") != null, BoxColliderCenter = deviceElement.Element("BoxCollider")?.Attribute("center")?.Value, BoxColliderSize = deviceElement.Element("BoxCollider")?.Attribute("size")?.Value, }; module.Devices.Add(device); } // 解析动作 foreach (XElement actionElement in moduleElement.Elements("Action")) { var action = ParseAction(actionElement); // 解析动作 module.ActionDict.Add(action.Name, action); } // 解析状态机 foreach (XElement fsmElement in moduleElement.Elements("FSM")) { FSM fsm = new FSM() { Name = fsmElement.Attribute("name")?.Value, StateDict = new Dictionary(), Transisions = new List(), }; // 解析状态 foreach (var stateNode in fsmElement.Elements("State")) { State state = new State() { Name = stateNode.Attribute("name")?.Value, }; fsm.StateDict.Add(state.Name, state); XElement enterElement = stateNode.Element("Enter"); XElement exitElement = stateNode.Element("Exit"); if (enterElement != null) { state.Enter = new StatePart(); state.Enter.Action = ParseAction(enterElement.Element("Action")); } if (exitElement != null) { state.Exit = new StatePart(); state.Exit.Action = ParseAction(exitElement.Element("Action")); } } // 解析状态转换 foreach (var transNode in fsmElement.Elements("Transision")) { Transision trans = new Transision() { Name = transNode.Attribute("name")?.Value, From = transNode.Attribute("from")?.Value, To = transNode.Attribute("to")?.Value, }; trans.Action = ParseCondition(transNode.Element("Condition")); fsm.Transisions.Add(trans); } module.FSM.Add(fsm.Name, fsm); } foreach (var operationNode in moduleElement.Elements("Operation")) { //module.Operations // 解析操作步骤 var op = new Operation() { Steps = new List(), }; op.moduleType = operationNode.Attribute("moduleType")?.Value; foreach (XElement stepNode in operationNode.Elements("Step")) { op.Steps.Add(ParserStep(stepNode, null)); } module.Operations.Add(op); } XElement scoreNode = moduleElement.Element("Score"); if (scoreNode != null) { module.score = new Score() { scores = new List() }; foreach (var item in scoreNode.Elements("Item")) { module.score.scores.Add( new ScoreStep() { step = item.Attribute("step")?.Value, name = item.Attribute("name")?.Value, sum = item.Attribute("sum")?.Value, bind = item.Attribute("bind")?.Value, }); } } } } return appData; } public static Step ParserStep(XElement stepNode, Step parent) { Step step = new Step(); step.Name = stepNode.Attribute("name")?.Value; step.Reset = ParseAction(stepNode.Element("Reset")?.Element("Action")); step.Start = ParseAction(stepNode.Element("Start")?.Element("Action")); step.Finished = ParseAction(stepNode.Element("Finished")?.Element("Action")); step.SubSteps = ParserSteps(stepNode, step); step.Parent = parent; return step; } public static List ParserSteps(XElement step, Step parent) { List steps = new List(); if (step.Elements("Step").Any()) { foreach (var item in step.Elements("Step")) { steps.Add(ParserStep(item, parent)); } } return steps; } public static Action ParseAction(XElement action) { if (action == null) { return null; } string type = action.Attribute("type").Value; Action newAction = null; // 这里是用于扩展Action的字段 switch (type) { case "Move": case "Rotate": { var act = new MoveOrAction(); act.to = Utility.GetVector3FromStrArray(action.Attribute("to").Value); act.time = float.Parse(action.Attribute("time").Value); newAction = act; } break; case "Anim": { var act = new AnimationAction(); act.animName = action.Attribute("animName").Value; newAction = act; } break; case "UITools": { var act = new StringListAction(); act.args.Add(action.Attribute("devices").Value); act.args.Add(action.Attribute("answers").Value); var setActive = action.Attribute("setActive"); if (setActive != null) { act.args.Add(setActive.Value); } else { act.args.Add("true"); } var rightLabel = action.Attribute("rightLabel"); if (rightLabel != null) { act.args.Add(rightLabel.Value); } else { act.args.Add(""); } var wrongLabel = action.Attribute("wrongLabel"); if (wrongLabel != null) { act.args.Add(wrongLabel.Value); } else { act.args.Add(""); } var rightEvent = action.Attribute("rightEvent"); if (rightEvent != null) { act.args.Add(rightEvent.Value); } else { act.args.Add(""); } var wrongEvent = action.Attribute("wrongEvent"); if (wrongEvent != null) { act.args.Add(wrongEvent.Value); } else { act.args.Add(""); } var rightScore = action.Attribute("rightScore"); if (rightScore != null) { act.args.Add(rightScore.Value); } else { act.args.Add(""); } var wrongScore = action.Attribute("wrongScore"); if (wrongScore != null) { act.args.Add(wrongScore.Value); } else { act.args.Add(""); } var scoreStepName = action.Attribute("scoreStepName"); if (scoreStepName != null) { act.args.Add(scoreStepName.Value); } else { act.args.Add(""); } newAction = act; } break; case "TextQuestion": { var act = new StringListAction(); act.args.Add(action.Attribute("title").Value); act.args.Add(action.Attribute("options").Value); act.args.Add(action.Attribute("answers").Value); act.args.Add(action.Attribute("btns").Value); act.args.Add(action.Attribute("wait").Value); act.args.Add(action.Attribute("showAnswer").Value); newAction = act; } break; case "UIShow": { var act = new StringListAction(); XAttribute isShow = action.Attribute("isShow"); if (isShow == null) { act.args.Add("true"); } else { act.args.Add(isShow.Value); } newAction = act; } break; case "Hint": { var act = new StringListAction(); XAttribute time = action.Attribute("time"); if (time != null) { act.args.Add(time.Value); } else { act.args.Add("-1"); } XAttribute icon = action.Attribute("icon"); if (icon != null) { act.args.Add(icon.Value); } else { act.args.Add("true"); } XAttribute audio = action.Attribute("audio"); if (audio != null) { act.args.Add(audio.Value); } else { act.args.Add(""); } newAction = act; } break; case "Show": { var act = new StringListAction(); XAttribute isShow = action.Attribute("isShow"); if (isShow != null) { act.args.Add(isShow.Value); } else { act.args.Add("true"); } newAction = act; } break; case "CameraSwitch": { var act = new StringListAction(); XAttribute isShow = action.Attribute("nearPos"); if (isShow != null) { act.args.Add(isShow.Value); } else { act.args.Add("0,0,0"); } XAttribute nearRot = action.Attribute("nearRot"); if (nearRot != null) { act.args.Add(nearRot.Value); } else { act.args.Add("0,0,0"); } XAttribute nearTime = action.Attribute("nearTime"); if (nearTime != null) { act.args.Add(nearTime.Value); } else { act.args.Add("0"); } XAttribute normalPos = action.Attribute("normalPos"); if (normalPos != null) { act.args.Add(normalPos.Value); } else { act.args.Add("0,0,0"); } XAttribute normalRot = action.Attribute("normalRot"); if (normalRot != null) { act.args.Add(normalRot.Value); } else { act.args.Add("0,0,0"); } XAttribute farTime = action.Attribute("farTime"); if (farTime != null) { act.args.Add(farTime.Value); } else { act.args.Add("0"); } XAttribute isNear = action.Attribute("isNear"); if (isNear != null) { act.args.Add(isNear.Value); } else { act.args.Add("false"); } newAction = act; } break; case "TextTip": { var act = new StringListAction(); XAttribute audio = action.Attribute("audio"); if (audio != null) { act.args.Add(audio.Value); } else { act.args.Add(""); } XAttribute btns = action.Attribute("btns"); if (btns != null) { act.args.Add(btns.Value); } else { act.args.Add(""); } newAction = act; } break; default: newAction = new Action(); break; } newAction.Type = action.Attribute("type")?.Value; newAction.Name = action.Attribute("name")?.Value; newAction.Value = action.Attribute("value")?.Value; newAction.SubActions = ParseActions(action); return newAction; } public static Condition ParseCondition(XElement action) { Condition newAction = new Condition { Type = action.Attribute("type")?.Value, Name = action.Attribute("name")?.Value, Value = action.Attribute("value")?.Value, SubActions = ParseActions(action) }; return newAction; } public static ActionItem ParserActionItem(XElement element) { ActionItem actItem = null; switch (element.Name.LocalName) { case "Action": actItem = ParseAction(element); break; case "Condition": actItem = ParseCondition(element); break; } return actItem; } private static List ParseActions(XElement actionElement) { List actions = new List(); foreach (XElement action in actionElement.Elements()) { actions.Add(ParserActionItem(action)); } return actions; } } }