You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

228 lines
5.9 KiB

  1. tool
  2. extends EditorImportPlugin
  3. var YarnScript = preload("yarn_script.gd")
  4. enum Presets { DEFAULT }
  5. # types
  6. const EMPTY = "empty"
  7. const NODE_BODY_END = "node_body_end"
  8. const NODE_BODY_START = "node_body_start"
  9. const NODE_TAG = "node_tag"
  10. const JUMP = "jump"
  11. const TEXT = "text"
  12. const CHOICE = "choice"
  13. const CHOICE_BLOCKS = "choice_blocks"
  14. const CONDITION_IF = "if"
  15. const CONDITION_ELSE = "else"
  16. const CONDITION_ELSEIF = "elseif"
  17. const CONDITION_ENDIF = "endif"
  18. const CONDITION_BLOCKS = "condition_blocks"
  19. const COMMAND = "command"
  20. # Entry point
  21. func import(source_file, save_path, options, r_platform_variants, r_gen_files):
  22. var file : File = File.new()
  23. var err := file.open(source_file, File.READ)
  24. if err != OK:
  25. return err
  26. var yarn = (YarnScript).new()
  27. yarn.nodes = {}
  28. while not file.eof_reached():
  29. var node = parse_header(file)
  30. node["body"] = parse_body(file)
  31. if node["title"] != "":
  32. yarn.nodes[node["title"]] = node
  33. file.close()
  34. return ResourceSaver.save("%s.%s" % [save_path, get_save_extension()], yarn)
  35. # Nodes parsing
  36. func parse_header(file : File):
  37. var new_node = {"title": "", "tags": "", "body":[]}
  38. while not file.eof_reached():
  39. var parsed_line = parse_line_header(file.get_line())
  40. var type = parsed_line["type"]
  41. # print("[" + type + "]\n\t" + str(parsed_line))
  42. if type == EMPTY:
  43. pass
  44. elif type == NODE_BODY_START:
  45. break
  46. elif type == NODE_TAG:
  47. new_node[parsed_line["key"]] = parsed_line["value"]
  48. return new_node
  49. func parse_body(file):
  50. var body = []
  51. while not file.eof_reached():
  52. var parsed_line = parse_line_body(file.get_line())
  53. var type = parsed_line["type"]
  54. # print("[" + type + "]\n\t" + str(parsed_line))
  55. if type == EMPTY:
  56. pass
  57. elif type == NODE_BODY_END:
  58. break
  59. elif type == CONDITION_IF:
  60. body.push_back(parse_condition_blocks(file, parsed_line))
  61. elif type == CHOICE:
  62. if body.size() == 0 or body[body.size() - 1]["type"] != CHOICE_BLOCKS:
  63. body.push_back({"type":CHOICE_BLOCKS, "blocks":[]})
  64. body[body.size() -1]["blocks"].push_back(parsed_line)
  65. else:
  66. body.push_back(parsed_line)
  67. return body
  68. func parse_condition_blocks(file, parsed_line):
  69. var condition_blocks = {"type":CONDITION_BLOCKS, "blocks":[]}
  70. var current_block = {"condition":parsed_line["expression"], "body":[]}
  71. while not file.eof_reached():
  72. parsed_line = parse_line_body(file.get_line())
  73. var type = parsed_line["type"]
  74. # print("[" + type + "]\n\t" + str(parsed_line))
  75. if type == EMPTY:
  76. pass
  77. elif type == CONDITION_IF:
  78. current_block["body"].push_back(parse_condition_blocks(file, parsed_line))
  79. elif type == CONDITION_ELSEIF:
  80. condition_blocks["blocks"].push_back(current_block)
  81. current_block = {"condition":parsed_line["expression"], "body":[]}
  82. elif type == CONDITION_ELSE:
  83. condition_blocks["blocks"].push_back(current_block)
  84. current_block = {"condition":parsed_line["expression"], "body":[]}
  85. elif type == CONDITION_ENDIF:
  86. condition_blocks["blocks"].push_back(current_block)
  87. break
  88. else:
  89. current_block["body"].push_back(parsed_line)
  90. return condition_blocks
  91. # Lines Parsing
  92. func parse_line_header(raw_line : String):
  93. var parsed_line = {"type":"????", "raw":raw_line}
  94. if raw_line.strip_edges() == "":
  95. parsed_line["type"] = EMPTY
  96. elif raw_line.begins_with("---"):
  97. parsed_line["type"] = NODE_BODY_START
  98. else:
  99. var split = raw_line.split(':')
  100. if split.size() >= 2:
  101. parsed_line["type"] = NODE_TAG
  102. parsed_line["key"] = split[0]
  103. parsed_line["value"] = split[1].strip_edges()
  104. return parsed_line
  105. func parse_line_body(raw_line : String):
  106. #todo later, use indentation
  107. raw_line = raw_line.strip_edges()
  108. var parsed_line = {"type":"????", "raw":raw_line}
  109. if raw_line.strip_edges() == "":
  110. parsed_line["type"] = EMPTY
  111. elif raw_line.begins_with("==="):
  112. parsed_line["type"] = NODE_BODY_END
  113. elif raw_line.begins_with("[["):
  114. var split := raw_line.replace("[[", "").replace("]]", "").split("|")
  115. if split.size() > 1:
  116. parsed_line["type"] = CHOICE
  117. parsed_line["text"] = split[0]
  118. parsed_line["node"] = split[1]
  119. else:
  120. parsed_line["type"] = JUMP
  121. parsed_line["node"] = split[0]
  122. elif raw_line.begins_with("<<"):
  123. var split := raw_line.replace("<<", "").replace(">>", "").strip_edges().split(' ')
  124. if split.size() > 0:
  125. if split[0] == "if":
  126. parsed_line["type"] = CONDITION_IF
  127. var expr := ""
  128. for token in Array(split).slice(1, split.size() -1):
  129. expr += token + " "
  130. parsed_line["expression"] = expr
  131. elif split[0] == "elseif":
  132. parsed_line["type"] = CONDITION_ELSEIF
  133. var expr := ""
  134. for token in Array(split).slice(1, split.size() -1):
  135. expr += token + " "
  136. parsed_line["expression"] = expr
  137. elif split[0] == "else":
  138. parsed_line["type"] = CONDITION_ELSE
  139. parsed_line["expression"] = "true" # add default expression always true
  140. elif split[0] == "endif":
  141. parsed_line["type"] = CONDITION_ENDIF
  142. else:
  143. parsed_line["type"] = COMMAND
  144. parsed_line["command"] = split[0]
  145. parsed_line["args"] = Array(split).slice(1, split.size() - 1)
  146. else:
  147. parsed_line["type"] = TEXT
  148. # use regex ?
  149. var separator_idx = raw_line.find(':')
  150. if separator_idx != -1:
  151. var chara = raw_line.substr(0, separator_idx).strip_edges()
  152. var text = raw_line.substr(separator_idx + 1 , -1).strip_edges()
  153. parsed_line["chara"] = chara
  154. parsed_line["text"] = text
  155. else:
  156. parsed_line["chara"] = ""
  157. parsed_line["text"] = raw_line.strip_edges()
  158. return parsed_line
  159. # Required editor functions
  160. func get_importer_name():
  161. return "yarn.script"
  162. func get_visible_name():
  163. return "Yarn Script"
  164. func get_recognized_extensions():
  165. return ["yarn", "txt"]
  166. func get_save_extension():
  167. return "res"
  168. func get_resource_type():
  169. return "Resource"
  170. func get_preset_count():
  171. return Presets.size()
  172. func get_preset_name(preset):
  173. match preset:
  174. Presets.DEFAULT:
  175. return "Default"
  176. _:
  177. return "Unknown"
  178. func get_import_options(preset):
  179. match preset:
  180. _:
  181. return []
  182. func get_option_visibility(option, options):
  183. return true