writerecipegraph.lua 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. local graphml_header = '<?xml version="1.0" encoding="UTF-8"?>\n'
  2. ..'<graphml xmlns="http://graphml.graphdrawing.org/xmlns" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
  3. ..'xmlns:y="http://www.yworks.com/xml/graphml" xmlns:yed="http://www.yworks.com/xml/yed/3" xsi:schemaLocation="http://graphml.graphdrawing.org/xmlns http://graphml.graphdrawing.org/xmlns/1.0/graphml.xsd http://www.yworks.com/xml/schema/graphml/1.1/ygraphml.xsd"'
  4. ..'>\n'
  5. ..'<key id="quantity" for="edge" attr.name="quantity" attr.type="int"/>\n'
  6. ..'<key id="edge_type" for="edge" attr.name="edge_type" attr.type="string"/>\n'
  7. ..'<key id="node_type" for="node" attr.name="node_type" attr.type="string"/>\n'
  8. ..'<key id="craft_type" for="node" attr.name="craft_type" attr.type="string"/>\n'
  9. ..'<key id="recipe_extra_data" for="node" attr.name="recipe_extra_data" attr.type="string"/>\n'
  10. ..'<key id="item" for="node" attr.name="item" attr.type="string"/>\n'
  11. ..'<key id="mod" for="node" attr.name="mod" attr.type="string"/>\n'
  12. ..'<key id="nodegraphics" for="node" yfiles.type="nodegraphics"/>\n' --yEd
  13. ..'<key id="edgegraphics" for="edge" yfiles.type="edgegraphics"/>\n' --yEd
  14. local nodes_written
  15. local items_written
  16. local edge_id = 0
  17. local write_data_graphml = function(file, datatype, data)
  18. file:write('<data key="'..datatype..'">'..data..'</data>')
  19. end
  20. local write_item_graphml = function(file, craft_type, item)
  21. local node_id = item .. "_" .. craft_type -- craft type is added to the id to separate graphs
  22. if not nodes_written[node_id] then
  23. file:write('<node id="'..node_id..'">')
  24. local color
  25. local mod
  26. local colon_index = string.find(item, ":")
  27. if colon_index == nil then
  28. item = "group:" .. item
  29. colon_index = 6
  30. color = "#C0C0C0"
  31. mod = "group"
  32. else
  33. mod = string.sub(item, 1, colon_index-1)
  34. color = simplecrafting_lib.get_key_color(mod)
  35. end
  36. write_data_graphml(file, "node_type", "item")
  37. write_data_graphml(file, "item", item)
  38. write_data_graphml(file, "mod", mod)
  39. --yEd
  40. write_data_graphml(file, "nodegraphics", '<y:ShapeNode><y:Geometry height="30.0" width="60.0"/><y:Fill color="'
  41. ..color
  42. ..'" transparent="false"/><y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>'
  43. ..'<y:NodeLabel alignment="center" autoSizePolicy="node_width" configuration="CroppingLabel" fontFamily="Dialog" fontSize="8" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="26.125" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="60.0" xml:space="preserve">'
  44. ..item
  45. ..'</y:NodeLabel><y:Shape type="roundrectangle"/></y:ShapeNode>')
  46. file:write('</node>\n')
  47. nodes_written[node_id] = true
  48. items_written[item] = true
  49. end
  50. end
  51. local write_edge_graphml = function(file, source, target, edgetype, quantity)
  52. edge_id = edge_id + 1
  53. file:write('<edge id="e_'..tostring(edge_id).. '" source="' .. source .. '" target="' .. target ..'">')
  54. write_data_graphml(file, "edge_type", edgetype)
  55. write_data_graphml(file, "quantity", tostring(quantity))
  56. local targetarrow = "delta"
  57. local linecolor = "#000000"
  58. if edgetype == "returns" then
  59. targetarrow = "white_delta"
  60. linecolor = "#888888"
  61. end
  62. --yEd
  63. write_data_graphml(file, "edgegraphics", '<y:PolyLineEdge><y:Path sx="0.0" sy="0.0" tx="0.0" ty="0.0"/><y:LineStyle color="'..linecolor
  64. ..'" type="line" width="1.0"/><y:Arrows source="none" target="'..targetarrow
  65. ..'"/><y:EdgeLabel alignment="center" backgroundColor="#FFFFFF" distance="2.0" fontFamily="Dialog" fontSize="12" fontStyle="plain" horizontalTextPosition="center" iconTextGap="4" lineColor="#000000" modelName="centered" modelPosition="center" preferredPlacement="anywhere" ratio="0.5" textColor="#000000" verticalTextPosition="bottom" visible="true" xml:space="preserve">'
  66. ..tostring(quantity)
  67. ..'<y:PreferredPlacementDescriptor angle="0.0" angleOffsetOnRightSide="0" angleReference="absolute" angleRotationOnRightSide="co" distance="-1.0" frozen="true" placement="anywhere" side="anywhere" sideReference="relative_to_edge_flow"/></y:EdgeLabel><y:BendStyle smoothed="true"/></y:PolyLineEdge>')
  68. file:write('</edge>\n')
  69. end
  70. local write_recipe_graphml = function(file, craft_type, id, recipe)
  71. local recipe_id = "recipe_"..craft_type.."_"..tostring(id)
  72. local extra_data = {}
  73. local has_extra_data = false
  74. for k, v in pairs(recipe) do
  75. if type(v) == "function" then
  76. minetest.log("error", "[simplecrafting_lib] recipe write: " .. key .. "'s value is a function")
  77. elseif k ~= "output" and k ~= "input" and k ~= "returns" then
  78. extra_data[k] = v
  79. has_extra_data = true
  80. end
  81. end
  82. file:write('<node id="'..recipe_id..'">')
  83. write_data_graphml(file, "node_type", "recipe")
  84. write_data_graphml(file, "craft_type", craft_type)
  85. if has_extra_data then
  86. write_data_graphml(file, "recipe_extra_data", minetest.serialize(extra_data))
  87. end
  88. --yEd
  89. write_data_graphml(file, "nodegraphics", '<y:ShapeNode><y:Geometry height="30.0" width="30.0"/><y:Fill color="#FFCC00" transparent="false"/>'
  90. ..'<y:BorderStyle color="#000000" raised="false" type="line" width="1.0"/>'
  91. ..'<y:NodeLabel alignment="center" autoSizePolicy="node_width" fontFamily="Dialog" fontSize="10" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" horizontalTextPosition="center" iconTextGap="4" modelName="internal" modelPosition="c" textColor="#000000" verticalTextPosition="bottom" visible="true" width="30.0" xml:space="preserve">'
  92. ..craft_type
  93. ..'</y:NodeLabel><y:Shape type="diamond"/></y:ShapeNode>')
  94. file:write('</node>\n') -- recipe node
  95. if recipe.output then
  96. local outitem = ItemStack(recipe.output)
  97. write_item_graphml(file, craft_type, outitem:get_name())
  98. write_edge_graphml(file, recipe_id, outitem:get_name().."_"..craft_type, "output", outitem:get_count())
  99. end
  100. if recipe.input then
  101. for initem, incount in pairs(recipe.input) do
  102. write_item_graphml(file, craft_type, initem)
  103. write_edge_graphml(file, initem.."_"..craft_type, recipe_id, "input", incount)
  104. end
  105. end
  106. if recipe.returns then
  107. for returnitem, returncount in pairs(recipe.returns) do
  108. write_item_graphml(file, craft_type, returnitem)
  109. write_edge_graphml(file, recipe_id, returnitem.."_"..craft_type, "returns", returncount)
  110. end
  111. end
  112. simplecrafting_lib.save_key_colors()
  113. end
  114. return function(file, recipes, recipe_filter, show_unused)
  115. file:write(graphml_header)
  116. nodes_written = {}
  117. items_written = {}
  118. for craft_type, recipe_list in pairs(recipes) do
  119. file:write('<graph id="'..craft_type..'" edgedefault="directed">\n')
  120. for id, recipe in pairs(recipe_list.recipes) do
  121. if recipe_filter.filter(recipe) then
  122. write_recipe_graphml(file, craft_type, id, recipe)
  123. end
  124. end
  125. file:write('</graph>\n')
  126. end
  127. -- Write out nodes for everything that hasn't already had a node written for it, for convenience of hand-crafting new recipes
  128. if show_unused then
  129. items_written[""] = true
  130. items_written["ignore"] = true
  131. items_written["unknown"] = true
  132. items_written["air"] = true
  133. for item, item_def in pairs(minetest.registered_items) do
  134. if not items_written[item] then
  135. write_item_graphml(file, "", item)
  136. end
  137. end
  138. end
  139. nodes_written = nil
  140. items_written = nil
  141. file:write('</graphml>')
  142. file:flush()
  143. file:close()
  144. end