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.
 
 

234 lines
6.1 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. # print("[" + parsed_line["type"] + "]\n\t" + str(parsed_line))
  72. while not file.eof_reached():
  73. parsed_line = parse_line_body(file.get_line())
  74. var type = parsed_line["type"]
  75. # print("[" + type + "]\n\t" + str(parsed_line))
  76. if type == EMPTY:
  77. pass
  78. elif type == CONDITION_IF:
  79. current_block["body"].push_back(parse_condition_blocks(file, parsed_line))
  80. elif type == CONDITION_ELSEIF:
  81. condition_blocks["blocks"].push_back(current_block)
  82. current_block = {"condition":parsed_line["expression"], "body":[]}
  83. elif type == CONDITION_ELSE:
  84. condition_blocks["blocks"].push_back(current_block)
  85. current_block = {"condition":parsed_line["expression"], "body":[]}
  86. elif type == CONDITION_ENDIF:
  87. condition_blocks["blocks"].push_back(current_block)
  88. break
  89. else:
  90. current_block["body"].push_back(parsed_line)
  91. return condition_blocks
  92. # Lines Parsing
  93. func parse_line_header(raw_line : String):
  94. var parsed_line = {"type":"????", "raw":raw_line}
  95. if raw_line.strip_edges() == "":
  96. parsed_line["type"] = EMPTY
  97. elif raw_line.begins_with("---"):
  98. parsed_line["type"] = NODE_BODY_START
  99. else:
  100. var split = raw_line.split(':')
  101. if split.size() >= 2:
  102. parsed_line["type"] = NODE_TAG
  103. parsed_line["key"] = split[0]
  104. parsed_line["value"] = split[1].strip_edges()
  105. return parsed_line
  106. func parse_line_body(raw_line : String):
  107. #todo later, use indentation
  108. raw_line = raw_line.strip_edges()
  109. var parsed_line = {"type":"????", "raw":raw_line}
  110. if raw_line.strip_edges() == "":
  111. parsed_line["type"] = EMPTY
  112. elif raw_line.begins_with("==="):
  113. parsed_line["type"] = NODE_BODY_END
  114. elif raw_line.begins_with("[["):
  115. var split := raw_line.replace("[[", "").replace("]]", "").split("|")
  116. if split.size() > 1:
  117. parsed_line["type"] = CHOICE
  118. parsed_line["text"] = split[0]
  119. parsed_line["node"] = split[1]
  120. else:
  121. parsed_line["type"] = JUMP
  122. parsed_line["node"] = split[0]
  123. elif raw_line.begins_with("<<"):
  124. var split := raw_line.replace("<<", "").replace(">>", "").strip_edges().split(' ')
  125. if split.size() > 0:
  126. if split[0] == "if":
  127. parsed_line["type"] = CONDITION_IF
  128. var expr := ""
  129. for token in Array(split).slice(1, split.size() -1):
  130. if token == "False":
  131. token = "false"
  132. elif token == "True":
  133. token = "true"
  134. expr += token + " "
  135. parsed_line["expression"] = expr
  136. elif split[0] == "elseif":
  137. parsed_line["type"] = CONDITION_ELSEIF
  138. var expr := ""
  139. for token in Array(split).slice(1, split.size() -1):
  140. expr += token + " "
  141. parsed_line["expression"] = expr
  142. elif split[0] == "else":
  143. parsed_line["type"] = CONDITION_ELSE
  144. parsed_line["expression"] = "true" # add default expression always true
  145. elif split[0] == "endif":
  146. parsed_line["type"] = CONDITION_ENDIF
  147. else:
  148. parsed_line["type"] = COMMAND
  149. parsed_line["command"] = split[0]
  150. parsed_line["args"] = Array(split).slice(1, split.size() - 1)
  151. else:
  152. parsed_line["type"] = TEXT
  153. # use regex ?
  154. var separator_idx = raw_line.find(':')
  155. if separator_idx != -1:
  156. var chara = raw_line.substr(0, separator_idx).strip_edges()
  157. var text = raw_line.substr(separator_idx + 1 , -1).strip_edges()
  158. parsed_line["chara"] = chara
  159. parsed_line["text"] = text
  160. else:
  161. parsed_line["chara"] = ""
  162. parsed_line["text"] = raw_line.strip_edges()
  163. return parsed_line
  164. # Required editor functions
  165. func get_importer_name():
  166. return "yarn.script"
  167. func get_visible_name():
  168. return "Yarn Script"
  169. func get_recognized_extensions():
  170. return ["yarn", "txt"]
  171. func get_save_extension():
  172. return "res"
  173. func get_resource_type():
  174. return "Resource"
  175. func get_preset_count():
  176. return Presets.size()
  177. func get_preset_name(preset):
  178. match preset:
  179. Presets.DEFAULT:
  180. return "Default"
  181. _:
  182. return "Unknown"
  183. func get_import_options(preset):
  184. match preset:
  185. _:
  186. return []
  187. func get_option_visibility(option, options):
  188. return true