Skip to content

Commit d24c1ab

Browse files
committed
routine commit
too many changes and too late to write a proper message.
1 parent 6ec2717 commit d24c1ab

14 files changed

+500
-1
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ export_presets.cfg
77
# Mono-specific ignores
88
.mono/
99
data_*/
10+
11+
# Plugins used for development
12+
addons/editor_icon_previewer
13+
addons/godot-plugin-refresher

.vscode/settings.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"files.exclude": {
3+
"**/.git": true,
4+
"**/.svn": true,
5+
"**/.hg": true,
6+
"**/CVS": true,
7+
"**/.DS_Store": true,
8+
"**/*.tscn": true
9+
},
10+
"explorerExclude.backup": null
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
## Manages one script. Maintains a list of nodes using that script,
2+
## and can replace their script.
3+
extends Resource
4+
5+
6+
signal errors(errors)
7+
8+
9+
export var nodes: Array
10+
export var file_path := ""
11+
export var original_script := ""
12+
export var name := ""
13+
var _current_index := 0
14+
var _scene: Node
15+
16+
17+
func _init(scene:Node, initial_script: GDScript) -> void:
18+
nodes = []
19+
_scene = scene
20+
file_path = initial_script.resource_path
21+
name = file_path.get_file().get_basename()
22+
original_script = initial_script.source_code
23+
24+
25+
func _to_string():
26+
return '`%s`' % [file_path]
27+
28+
29+
func _iterator_is_valid() -> bool:
30+
return _current_index < nodes.size()
31+
32+
33+
func _iter_init(_arg) -> bool:
34+
_current_index = 0
35+
return _iterator_is_valid()
36+
37+
38+
func _iter_next(_arg) -> bool:
39+
_current_index += 1
40+
return _iterator_is_valid()
41+
42+
43+
func _iter_get(_arg):
44+
return current()
45+
46+
47+
func size() -> int:
48+
return nodes.size()
49+
50+
func get_by_index(index: int) -> NodePath:
51+
return nodes[index]
52+
53+
func current() -> NodePath:
54+
return get_by_index(_current_index)
55+
56+
func append(node: Node) -> void:
57+
var path := String(node.get_path()).replace(_scene.get_path(),"")
58+
prints("adding node %s to script %s"%[path, file_path])
59+
nodes.append(NodePath(path))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
extends Resource
2+
3+
const SceneScript := preload("./SceneScript.gd")
4+
5+
export var repository: Dictionary
6+
var _scene: Node
7+
var _current_index := 0
8+
var _current_array := []
9+
10+
func _init(scene: Node) -> void:
11+
repository = {}
12+
_scene = scene
13+
14+
## If the provided script is new, adds a script file to the repository.
15+
## Otherwise, adds the provided node as a dependency of this script.
16+
func add_node(script: GDScript, node: Node) -> void:
17+
var script_path := script.resource_path
18+
if not (script_path in repository):
19+
prints("new script:", script_path)
20+
var scene_script := SceneScript.new(_scene, script)
21+
repository[script_path] = scene_script
22+
(repository[script_path] as SceneScript).append(node)
23+
24+
25+
func _to_string():
26+
return '(scripts: %s)' % [PoolStringArray(repository.values()).join(", ")]
27+
28+
29+
func _iterator_is_valid() -> bool:
30+
return _current_index < _current_array.size()
31+
32+
33+
func _iter_init(_arg) -> bool:
34+
_current_index = 0
35+
_current_array = repository.values()
36+
return _iterator_is_valid()
37+
38+
39+
func _iter_next(_arg) -> bool:
40+
_current_index += 1
41+
return _iterator_is_valid()
42+
43+
44+
func _iter_get(_arg):
45+
return current()
46+
47+
48+
func size() -> int:
49+
return repository.size()
50+
51+
52+
func keys() -> Array:
53+
return repository.keys()
54+
55+
56+
func values() -> Array:
57+
return repository.values()
58+
59+
func current() -> SceneScript:
60+
return _current_array[_current_index]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
tool
2+
extends EditorPlugin
3+
4+
const LiveEditorExporterUtilsPath = "res://addons/exporter-for-live-editor/utils/LiveEditorExporterUtils.gd"
5+
const LiveEditorExporterUtils := preload(LiveEditorExporterUtilsPath)
6+
var live_editor_exporter_utils = LiveEditorExporterUtils.new()
7+
var file_dialog := preload("./ui/file_dialog.gd").new()
8+
var container := preload("./ui/container.gd").new()
9+
var config := preload("./utils/config.gd").new(self)
10+
11+
const SceneScriptsRepository := preload("./collection/SceneScriptsRepository.gd")
12+
const SceneScript := SceneScriptsRepository.SceneScript
13+
14+
func _enter_tree() -> void:
15+
add_autoload_singleton("LiveEditorExporterUtils", LiveEditorExporterUtilsPath)
16+
17+
connect("scene_changed", self, "_on_scene_changed")
18+
connect("main_screen_changed", self, "_on_screen_changed")
19+
config.load_settings()
20+
21+
container.scene_path = config.scene_path
22+
container.file_browser_button.icon = config.get_icon("File")
23+
container.run_button.icon = config.get_icon("Play")
24+
container.remove_button.icon = config.get_icon("Close")
25+
container.pin_button.icon = config.get_icon("Pin")
26+
container.pin_button.pressed = config.was_manually_set
27+
28+
container.connect("scene_path_changed", self, "_on_scene_path_changed")
29+
container.connect("file_browser_requested", file_dialog, "popup_centered_ratio")
30+
container.connect("run_button_pressed", self, "_on_run_button_pressed")
31+
container.connect("pin_button_toggled", config, "set_was_manually_set")
32+
33+
add_control_to_container(CONTAINER_TOOLBAR, container)
34+
35+
file_dialog.connect("file_selected", self, "_on_file_dialog_file_selected")
36+
get_editor_interface().get_base_control().add_child(file_dialog)
37+
38+
func _exit_tree() -> void:
39+
remove_control_from_container(CONTAINER_TOOLBAR, container)
40+
container.queue_free()
41+
file_dialog.queue_free()
42+
remove_autoload_singleton("LiveEditorExporterUtils")
43+
44+
func _on_file_dialog_file_selected(path: String) -> void:
45+
if path:
46+
container.scene_path = path
47+
config.scene_path = path
48+
config.was_manually_set = true
49+
container.pin_button.pressed = true
50+
else:
51+
container.scene_path = get_current_scene_path()
52+
config.was_manually_set = false
53+
container.pin_button.pressed = false
54+
55+
func get_current_scene_path() -> String:
56+
var current_scene: Node = get_editor_interface().get_edited_scene_root()
57+
if current_scene:
58+
return current_scene.filename
59+
return ""
60+
61+
func _on_scene_path_changed(new_text: String) -> void:
62+
if new_text == "":
63+
config.was_manually_set = false
64+
container.pin_button.pressed = false
65+
config.scene_path = ""
66+
67+
func _on_scene_changed(new_scene: Node):
68+
if config.was_manually_set:
69+
return
70+
container.scene_path = new_scene.filename
71+
config.scene_path = new_scene.filename
72+
73+
func _on_screen_changed(new_screen: String) -> void:
74+
if new_screen == "2D" or new_screen == "3D":
75+
container.show()
76+
else:
77+
pass
78+
#container.hide()
79+
80+
func _on_run_button_pressed() -> void:
81+
if not config.scene_path:
82+
return
83+
var packed_scene: PackedScene = load(config.scene_path)
84+
var scene = packed_scene.instance()
85+
scene.hide()
86+
add_child(scene)
87+
var collector:SceneScriptsRepository = live_editor_exporter_utils.collect_script(scene)
88+
for _repo in collector:
89+
var repo: SceneScript = collector.current()
90+
print(repo)
91+
for _nodePath in repo:
92+
var nodePath: NodePath = repo.current()
93+
print(nodePath)
94+
var file_name = config.scene_path.get_basename()+".live-editor.tres"
95+
ResourceSaver.save(file_name, collector)
96+
remove_child(scene)
97+
scene.queue_free()
98+
#get_editor_interface().play_main_scene()
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[plugin]
2+
3+
name="Exporter for Live Editor"
4+
description="""Exports scripts and scenes to be used with the live editor.
5+
All this plugin does is build resources to be used by the live editor. It doesn't by itself enable any
6+
run-time editing of scenes.
7+
"""
8+
author="GDQuest"
9+
version="1.0"
10+
script="exporter-for-live-editor.gd"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
extends HBoxContainer
2+
3+
var scene_path_control := LineEdit.new()
4+
var file_browser_button := ToolButton.new()
5+
var run_button := ToolButton.new()
6+
var remove_button := ToolButton.new()
7+
var pin_button := ToolButton.new()
8+
var scene_path: String setget set_scene_path, get_scene_path
9+
10+
signal scene_path_changed(text)
11+
signal file_browser_requested()
12+
signal run_button_pressed()
13+
signal pin_button_toggled()
14+
15+
func _init() -> void:
16+
scene_path_control.rect_min_size = Vector2(250, 20)
17+
pin_button.toggle_mode = true
18+
19+
add_child(scene_path_control)
20+
add_child(file_browser_button)
21+
add_child(remove_button)
22+
add_child(pin_button)
23+
add_child(run_button)
24+
25+
scene_path_control.connect("text_changed", self, "_on_scene_path_text_changed")
26+
file_browser_button.connect("pressed", self, "emit_signal", ["file_browser_requested"])
27+
remove_button.connect("pressed", self, "_on_remove_button_pressed")
28+
pin_button.connect("toggled", self, "_on_pin_button_toggled")
29+
run_button.connect("pressed", self, "emit_signal", ["run_button_pressed"])
30+
31+
func _on_scene_path_text_changed(new_text: String):
32+
emit_signal("scene_path_changed", new_text)
33+
34+
func _on_remove_button_pressed():
35+
scene_path_control.text = ""
36+
_on_scene_path_text_changed("")
37+
38+
func _on_pin_button_toggled(button_pressed: bool) -> void:
39+
emit_signal("pin_button_toggled", button_pressed)
40+
41+
func set_scene_path(new_path: String) -> void:
42+
scene_path_control.text = new_path
43+
44+
func get_scene_path() -> String:
45+
return scene_path_control.text
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
extends FileDialog
2+
3+
func _init() -> void:
4+
mode = FileDialog.MODE_OPEN_FILE
5+
access = FileDialog.ACCESS_RESOURCES
6+
set_filters(PoolStringArray(["*.tscn ; Godot Scenes"]))
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
extends Node
2+
3+
const SceneScriptsRepository := preload("../collection/SceneScriptsRepository.gd")
4+
const SceneScript := SceneScriptsRepository.SceneScript
5+
6+
7+
const SETTINGS_KEY = preload("./config.gd").SETTINGS_KEY
8+
9+
const REGEX_PRINTS = "\\bprints\\((.*?)\\)"
10+
const REGEX_PRINT = "\\bprint\\((.*?)\\)"
11+
const REGEX_PUSH_ERROR = "\\bpush_error\\((.*?)\\)"
12+
const REGEX_PUSH_WARNING = "\\bpush_warning\\((.*?)\\)"
13+
const REGEX_EXPORT = "(?m)^(\\s*)#\\s(EXPORT)(?:(?:\\s+)(.*?))?(?:\\s|$)"
14+
15+
var _replacements = {
16+
REGEX_PRINTS: "EventBus.print_log([$1])",
17+
REGEX_PRINT: "EventBus.print_log([$1])",
18+
REGEX_PUSH_ERROR: "EventBus.print_error($1)",
19+
REGEX_PUSH_WARNING: "EventBus.print_warning($1)",
20+
}
21+
22+
var export_key_regex = RegEx.new()
23+
24+
func _init() -> void:
25+
var regexes = _replacements.keys()
26+
export_key_regex.compile(REGEX_EXPORT)
27+
for key in regexes:
28+
var replacement = _replacements[key]
29+
var regex = RegEx.new()
30+
regex.compile(key)
31+
_replacements.erase(key)
32+
_replacements[regex] = replacement
33+
34+
func replace_code(text: String) -> String:
35+
for regex in _replacements:
36+
var replacement = _replacements[regex]
37+
text = regex.sub(text, replacement, true)
38+
return text
39+
40+
41+
# Returns a string representing the current scene,
42+
# or an empty string
43+
static func get_scene() -> String:
44+
var path = ProjectSettings.get_setting(SETTINGS_KEY)
45+
if path:
46+
return path
47+
return ""
48+
49+
# loads the selected scene. Accepts an optional `from`
50+
# argument which checks that the loaded scene isn't itself
51+
static func load_scene(from:Node = null) -> Node:
52+
var scene_path = get_scene()
53+
if scene_path:
54+
if from and from.filename == scene_path:
55+
return null
56+
var packed_scene: PackedScene = load(scene_path)
57+
var scene = packed_scene.instance()
58+
return scene
59+
return null
60+
61+
# Tests a script to ensure it has no errors.
62+
# Only works at runtime
63+
static func test(current_file_name: String) -> bool:
64+
var test_file: Resource = load(current_file_name)
65+
var test_instance = test_file.new()
66+
return test_instance != null
67+
68+
69+
func script_is_valid(script: GDScript) -> bool:
70+
print("is "+script.resource_path+" valid?")
71+
var result = export_key_regex.search(script.source_code)
72+
if result:
73+
print("it's valid")
74+
return true
75+
print("it's invalid")
76+
return false
77+
78+
79+
func _collect_scripts(scene: Node, node: Node, repository: SceneScriptsRepository, limit: int):
80+
var maybe_script: Reference = node.get_script()
81+
if maybe_script != null and maybe_script is GDScript:
82+
var script: GDScript = maybe_script
83+
if script_is_valid(script):
84+
repository.add_node(script, node)
85+
if limit > 0:
86+
limit -= 1
87+
for child in node.get_children():
88+
_collect_scripts(scene, child, repository, limit)
89+
90+
func collect_script(scene: Node, limit:=1000) -> SceneScriptsRepository:
91+
var repository := SceneScriptsRepository.new(scene)
92+
_collect_scripts(scene, scene, repository, limit)
93+
return repository

0 commit comments

Comments
 (0)