Is there a way to download this version other than through the in-editor updater? My internet is pretty bad, so updating with the editor rarely works.
Played around with it a bit, and made one that just deletes the contents of the selected text file(s) for no reason.
Code
local M = {}
function M.get_commands()
return {
{
label = "Delete",
locations = {"Edit", "Assets", "Outline"},
query = {
selection = {type = "resource", cardinality = "many"}
},
active = function(opts)
return true
end,
run = function(opts)
local actions = {}
for _,id in ipairs(opts.selection) do
table.insert(actions, {action = "set", node_id = id, property = "text", value = ""})
end
return actions
end
}
}
end
return M
Splendid!
Pretty sad we cannot yet modify collection files. I tried to make an editor script that automatizes creating collection of levels, and catched this error:
ERROR:EXT: Pack levels's "run" in /main/collection_packer.editor_script failed:
ERROR:EXT: No method in multimethod 'transaction-action->txs' for dispatch value: ["set" :editor.collection/CollectionNode "text"]
The code:
local M = {}
M.target_file = nil
function M.get_commands()
return {
{
label = 'Pack levels',
locations = {'Assets'},
query = {
selection = { type = 'resource', cardinality = 'many' }
},
active = function(opts)
for _, node_id in ipairs(opts.selection) do
if not M.is_collection(node_id) then
return false
end
end
return true
end,
run = M.pack_collections,
},
{
label = 'Set as levels collection',
locations = {'Assets'},
query = {
selection = { type = 'resource', cardinality = 'one' }
},
active = function(opts)
return M.is_collection(opts.selection)
end,
run = function(opts)
local path = editor.get(opts.selection, 'path')
print('Pack target is set to '..path)
M.target_file = opts.selection
end,
}
}
end
function M.is_collection(node_id)
local path = editor.get(node_id, 'path')
return path:find('.collection', nil, true)
end
local function make_embedded_factory(path, exclude)
return [[embedded_instances {
id: "]]..path..[["
data: "embedded_components {\n"
" id: \"collectionproxy\"\n"
" type: \"collectionproxy\"\n"
" data: \"collection: \\\"]]..path..[[\\\"\\n"
"exclude: ]]..tostring(exclude)..[[\\n"
"\"\n"
" position {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" }\n"
" rotation {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" w: 1.0\n"
" }\n"
"}\n"
""
position {
x: 0.0
y: 0.0
z: 0.0
}
rotation {
x: 0.0
y: 0.0
z: 0.0
w: 1.0
}
scale3 {
x: 1.0
y: 1.0
z: 1.0
}
}
]]
end
function M.pack_collections(opts)
assert(M.target_file, 'No target file specified. Use "Set as levels collection" first')
local content = [[name: "pack"
scale_along_z: 0
]]
for _, node_id in ipairs(opts.selection) do
filename = editor.get(node_id, 'path')
content = content .. make_embedded_factory(filename, false)
end
return {
{
action = 'set',
node_id = M.target_file,
property = 'text',
value = content,
},
}
end
return M
Oooh, Iām excited to see that your guys are starting to use it already. @vlaaad will take a look at your specific issue @azotkirill
Hi! Error happens because from the point of view of an editor, collections are not text files: they are structured data structures. This allows editor to automatically fix references to collections from other collections while renaming them. We want to expand over time on what properties are available for different nodes, but for now you can just write to a collection file with io.open(M.target_file, "w"):write(...)
.
What are the chance of us getting our hands on the protobuf definitions? That could make creating files a bit neater
Thanks for explanations!
Itās cool that different file types have different scripting interfaces, shooting yourself in the foot became less handy (sigh). Editor scripting feels easy and handy unless you hit limitations. I already can make most things I planned, though it can take much more effort than I planned.
Some issues I faced this far:
-
editor.get(nil, 'text')
throws java.NullPointerException. - Is there any way to reload editor scripts without reloading editor?
- Filtering resources of specific type is cumbersome, and it will be used in most editor scripts.
Iāll improve error message for invalid input to editor.get
.
Project ā Reload Editor Scripts (itās mentioned in Editor Script Runtime section of a manual).
You can just write a function that receives node id and expected file extension and checks if path of this node has this extension, is it not enough? What else is cumbersome here?
Yes, thatās what I did, however almost every editor script I can imagine will contain this function, so maybe it could be part of editor module or query.selection?
Just pushed a couple of improvements (and updated manual to reflect the changes):
- better error reporting when invalid arguments are passed to
editor.get()
- added
os.remove
- allow resource paths as a
node_id
argument toeditor.get()
, like that:editor.get("/main/game.script", "text")
OK, Iām just messing around learning how this works, so Iām probably doing something wrong, but it seems like a command may not be run depending on what you have selected?
My Test Code...
local M = {}
local runIdx = 1
local commands = {
{
label = "Test Command",
locations = {"Edit", "Assets", "Outline"},
query = {
selection = { type = "resource", cardinality = "many" }
},
run = function(opts)
print("action run", runIdx)
runIdx = runIdx + 1
return {}
end
},
}
function M.get_commands()
print("Test Editor Extension Loaded.")
return commands
end
return M
With that, if I have an embedded (not from another file) game object or component selected, the run function doesnāt get called. If I have the root of the .go or .collection file selected, or anything instanced from another file, it does run.
Add new collection --> right-click base node and click custom command --> it runs.
ā¦in new collection --> press A to add new game object --> right click that go and click custom command --> nothing.
@ross.grams Thatās because currently selection query supports only resources, which are files on a file system. Root of a .go or .collection file has corresponding file, but embedded components do not have their own files, thatās why you canāt target them.
Got it, thanks. Makes sense. And uhh, I guess I should have read the manual more closely!
ā¦currently only
"resource"
is allowed. In Assets and Outline, resource is selected item. In menu bar (Edit or View), resource is a currently open file;
But now Iāve discovered if I add an āactiveā callback and always return true, then it does run on embedded game objects and I get an ID back (but of course thereās not much I can do with it yet).
I guess thatās my first feature request then: access to embedded game object and component properties. My main use for editor extensions would be to speed up and expand on the workflow for editing scenes. I guess you could maaaybe do this right now by parsing the collection file and editing it, but Iām not sure how you could specify which things to edit. I think it would be quite hard to make something convenient to use (which is the whole point).
For example consider a simple āAlign Verticallyā command. You select multiple objects, right click in the Outline, click āAlign Verticallyā, and boom, the selected objects have their positions changed so they line up. Being able to do things like that with editor extensions would be pretty amazing.
Some things I wish for down the roadā¦
- Input - Thereās only so much you can do with menu items. If extensions could work with keyboard input then you could really do cool stuff (at the press of a buttonā¦).
- ā¦and probably make a big mess with multiple extensions and conflicting, hard-coded keybindings, but thatās ok.
- Drawing stuff in the viewport - Lower priority, but if you really want to make custom editing tools I think you need some way to visually indicate whatās going on. Just something like the render script ādraw_lineā message, would do it.
- Viewport camera transforms - OK now this is really wishful thinking, but now that I am thinking about it, to make a custom editing gizmo you would need 1) The viewport camera matrices for collision checking, and 2) Be able to hijack mouse input before the editor uses it.
Anyway! The fact that editor extensions already work, are doable very easily with lua, can be reloaded instantly, and are so far bug-free, is really awesome!!!
Thank you very much for feedback! I agree, getting and setting transforms looks like a good next step for editor scripts, as well as keyboard shortcuts.
Also I want to point out that active callback is optional, and it will be more performant if you omit it.
Another question: How do I require lua modules from an editor_script? The usual require path doesnāt seem to work. The manual specifically mentions that itās possible.
This all seems like a great start from quickly playing with it. It feels powerful yet minimalist as well.
My personal requests:
- viewport interaction (manipulators custom drawing in the viewport). Want to draw splines directly in it.
- custom property panels.
I managed to get it to work, but I have no idea what I did . Going to play around with it some more.
Huh, used to work for me, although Iām not on Windows and we probably expect forward slashes, while lua on Windows asks backward slashesā¦
Ah, darn I thought I tried that. Sure enough, a forward slash instead of a dot works.