VicToMeyeZR Posted January 18, 2010 Share Posted January 18, 2010 Here is a Lua only Parser. test.xml <?xml version="1.0" encoding="utf-8"?> <animations> <start> <idle value="infiltrator">460</idle> <run value="infiltrator">1155</run> </start> <end> <idle value="infiltrator">850</idle> <run value="infiltrator">1195</run> </end> </animations> xml.lua XmlParser = {}; function XmlParser:ToXmlString(value) value = string.gsub (value, "&", "&"); -- '&' -> "&" value = string.gsub (value, "<", "<"); -- '<' -> "<" value = string.gsub (value, ">", ">"); -- '>' -> ">" --value = string.gsub (value, "'", "'"); -- '\'' -> "'" value = string.gsub (value, "\"", """); -- '"' -> """ -- replace non printable char -> " " value = string.gsub(value, "([^%w%&%;%p%\t% ])", function (c) return string.format("%X;", string.byte(c)) --return string.format("%02X;", string.byte(c)) --return string.format("%02d;", string.byte(c)) end); return value; end function XmlParser:FromXmlString(value) value = string.gsub(value, "([%x]+)%;", function(h) return string.char(tonumber(h,16)) end); value = string.gsub(value, "([0-9]+)%;", function(h) return string.char(tonumber(h,10)) end); value = string.gsub (value, """, "\""); value = string.gsub (value, "'", "'"); value = string.gsub (value, ">", ">"); value = string.gsub (value, "<", "<"); value = string.gsub (value, "&", "&"); return value; end function XmlParser:ParseArgs(s) local arg = {} string.gsub(s, "(%w+)=([\"'])(.-)%2", function (w, _, a) arg[w] = self:FromXmlString(a); end) return arg end function XmlParser:ParseXmlText(xmlText) local stack = {} local top = {Name=nil,Value=nil,Attributes={},ChildNodes={}} table.insert(stack, top) local ni,c,label,xarg, empty local i, j = 1, 1 while true do ni,j,c,label,xarg, empty = string.find(xmlText, "<(%/?)([%w:]+)(.-)(%/?)>", i) if not ni then break end local text = string.sub(xmlText, i, ni-1); if not string.find(text, "^%s*$") then top.Value=(top.Value or "")..self:FromXmlString(text); end if empty == "/" then -- empty element tag table.insert(top.ChildNodes, {Name=label,Value=nil,Attributes=self:ParseArgs(xarg),ChildNodes={}}) elseif c == "" then -- start tag top = {Name=label, Value=nil, Attributes=self:ParseArgs(xarg), ChildNodes={}} table.insert(stack, top) -- new level --log("openTag ="..top.Name); else -- end tag local toclose = table.remove(stack) -- remove top --log("closeTag="..toclose.Name); top = stack[#stack] if #stack < 1 then error("XmlParser: nothing to close with "..label) end if toclose.Name ~= label then error("XmlParser: trying to close "..toclose.Name.." with "..label) end table.insert(top.ChildNodes, toclose) end i = j+1 end local text = string.sub(xmlText, i); if not string.find(text, "^%s*$") then stack[#stack].Value=(stack[#stack].Value or "")..self:FromXmlString(text); end if #stack > 1 then error("XmlParser: unclosed "..stack[stack.n].Name) end return stack[1].ChildNodes[1]; end function XmlParser:ParseXmlFile(xmlFileName) local hFile,err = io.open(xmlFileName,"r"); if (not err) then local xmlText=hFile:read("*a"); -- read file content io.close(hFile); return self:ParseXmlText(xmlText),nil; else return nil,err; end end Run this file: require("Scripts/XML/xml") local obj,err = XmlParser:ParseXmlFile("Scripts/test.xml") if(not err) then for i,xmlNode in pairs(obj.ChildNodes) do if(xmlNode.Name=="start") then for i,subXmlNode in pairs(xmlNode.ChildNodes) do if(subXmlNode.Name) then Notify(subXmlNode.Name.." value=\""..subXmlNode.Attributes.value.."\""); if(subXmlNode.Value) then Notify(" Content=\""..subXmlNode.Value.."\""); end end end end end else Notify("ERROR: "..err); end It will return: idle value="infiltrator" content="460" run value="infiltrator" content="1155" With this I can have it run a dynamic menu for the object, as well as pass the deafult values based on the XML file information. I will post the scrip to run this part as soon as I have it. Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 18, 2010 Author Share Posted January 18, 2010 ok. My character script. This way I won't have to change much with it. XML FILE: <?xml version="1.0" encoding="utf-8"?> <animations> <start> <idle value="Idle Start Frame">460</idle> <run value="Run Start Frame">1155</run> </start> <end> <idle value="Idle End Frame">850</idle> <run value="Run End Frame">1195</run> </end> </animations> MODEL LUA FILE: require("scripts/class") require("scripts/XML/XML") local class=CreateClass(...) local obj,err = XmlParser:ParseXmlFile("Models/characters/Cyber/character_visor_full.xml") function class:InitDialog(grid) self.super:InitDialog(grid) group = grid:AddGroup("Animations") //This adds a property field based off the XML file data structure. This file MUST meet the data structure set by my post, or you will have to modify this script if (not err) then for i,xmlNode in pairs(obj.ChildNodes) do if(xmlNode.Name=="start") then for i,subXmlNode in pairs(xmlNode.ChildNodes) do if(subXmlNode.Name) then group:AddProperty(subXmlNode.Name.."_start", PROPERTY_INTEGER, "", ""..subXmlNode.Attributes.value.."") end end end end for i,xmlNode in pairs(obj.ChildNodes) do if(xmlNode.Name=="end") then for i,subXmlNode in pairs(xmlNode.ChildNodes) do if(subXmlNode.Name) then group:AddProperty(subXmlNode.Name.."_end", PROPERTY_INTEGER, "", ""..subXmlNode.Attributes.value.."") end end end end end group:Expand(1) end Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
Rick Posted January 18, 2010 Share Posted January 18, 2010 With this I can have it run a dynamic menu for the object, as well as pass the deafult values based on the XML file information. hmm, I think the issue is that the settings dialog will be the same for them all though. The InitDialog() runs the same for all instances. So if you wanted to have a character that had a different animation name than another character you couldn't. I guess I was thinking that the xml file would describe animations for that given instance of the character thingoid instead of being a file that describes how the settings dialog box should look. In this case I get the fact that it wouldn't be the easiest because instead of settings in the dialog box they need to edit an xml file, BUT, follow me on my journey of thinking just now, I wonder if we could have the properties from the editor shell out to a custom exe that we create that makes editing the xml file easier. It could be a small little properties window that is more flexible in adding animations to the xml file. The result would be the xml file that the user selects into the editor settings dialog. [edit] Then in the setkey method, when the xml file gets selected, you parse it out and store the information in a lua table variable to that object. I'm curious to hear where you are going with this more though. Quote Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 hmm, I think the issue is that the settings dialog will be the same for them all though. The InitDialog() runs the same for all instances. So if you wanted to have a character that had a different animation name than another character you couldn't. I guess I was thinking that the xml file would describe animations for that given instance of the character thingoid instead of being a file that describes how the settings dialog box should look. In this case I get the fact that it wouldn't be the easiest because instead of settings in the dialog box they need to edit an xml file, BUT, follow me on my journey of thinking just now, I wonder if we could have the properties from the editor shell out to a custom exe that we create that makes editing the xml file easier. It could be a small little properties window that is more flexible in adding animations to the xml file. The result would be the xml file that the user selects into the editor settings dialog. [edit] Then in the setkey method, when the xml file gets selected, you parse it out and store the information in a lua table variable to that object. I'm curious to hear where you are going with this more though. Yeah, my thinking in this, and of course it will progress, is that no matter WHAT animations the character has, this character file will work for EVERY character/NPC. You make the XML file based of that model, and as soon as you post each one in the editor, the properties fields are set. If I could find out how to automatically pull the XML file name based off the model instance, then the file WOULD be fully automated. the model lua file, and the model file name match, so if there was a way to tell the script the the XML file is the same, sure would help out a bunch. (*hint) I will post a video, so you can see. Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2010 Share Posted January 19, 2010 I get where you are going and I see it often in AAA games. I was looking through the WoW data files and was looking at the animation names and you see stuff like Attack1, Attack2, etc. and all the models are based off that. That's valid. Quote Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2010 Share Posted January 19, 2010 How's local test = objecttable[model].class.name Notify(test) Where model is from the one being passed to CreateObject() Quote Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 Yeah, that gives me the name, but not the path. Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2010 Share Posted January 19, 2010 ah, look at the class.lua file in scripts. Right under the first CreateObject() function. The path is getting taken out and the file is assign to the class.name like I posted above. You should be able to get the full path. Quote Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 Thanks, I was looking at that. Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
flachdrache Posted January 19, 2010 Share Posted January 19, 2010 The WoW data you noticed seams to be a hint of splitanimations e.g. many small *.gmf`s which are just contain one single animation. If the characters are sharing the same skeleton and one can call the animation "clip" from that specific gmf to use on a (all) character i dont see a reason why not using split animations - guess its more a question of maintaining/sorting a lot of animation clips w/o having to look into a text file for which clip starts/ends where and for what character etc.. Quote AMD 64 X2 Dual 5k - 4GB - XFX GForce9800GT - nv196.21 - WinXP Sp3 zBrush4R2 - Silo2Pro - Unwrap3DPro - Gile - MaPZone2.5 Xxploration FPS in progress ... Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 ok. I had to add a little to the class.lua file to get this to work. Name the XML file the same as your GMF model file. change to Class.lua --Creates a class from a model reference object function CreateClass(modelreference) local class={} local super={} class.instances={} classtable[modelreference]=class class.modelreference=modelreference class.name=string.lower(StripAll(modelreference.path)) classnametable[class.name]=class Print("Creating class "..class.name) super.class=class CHANGE TO: --Creates a class from a model reference object function CreateClass(modelreference) local class={} local super={} class.instances={} classtable[modelreference]=class class.modelreference=modelreference class.name=string.lower(StripAll(modelreference.path)) class.path=string.lower(StripExt(modelreference.path)) classnametable[class.name]=class classnametable[class.path]=class.path Print("Creating class "..class.name) super.class=class Then change the top of my file from : local obj,err = XmlParser:ParseXmlFile("Models/characters/Cyber/character_visor_full.xml") CHANGE TO: local obj,err = XmlParser:ParseXmlFile(class.path..".xml") Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
Rick Posted January 19, 2010 Share Posted January 19, 2010 I don't think you want to go that route. Changing the class.lua file will cause portability/resyncing issues. You should be able to do that in the Thingoid lua file and it'll be much more portable and won't get overwritten when Josh changes the class.lua file and people resync. Try: string.lower(StripExt(objecttable[model].class.modelreference.path)) or local cls = objecttable[model].class string.lower(StripExt(cls.modelreference.path)) Quote Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 Not if josh, puts that in his core. lol. I will try that also. Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
VicToMeyeZR Posted January 19, 2010 Author Share Posted January 19, 2010 ahh. ok. Thats it. I just needed to look a little deeper. I was trying modelreference but couldn't get anything from it, but class is the table I needed. local test = string.lower(StripExt(class.modelreference.path)) Thanks Rick Quote AMD Phenom II x6 1100T - 16GB RAM - ATI 5870 HD - OCZ Vertex 2 60GB SSD Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.