Try to keep the terrain UI visible when editing generator and graph settings. Hacky stuff.

master
Marc Gilleron 2020-08-15 21:19:14 +01:00
parent 23ce65d789
commit 464bb734ba
3 changed files with 79 additions and 11 deletions

View File

@ -1,11 +1,9 @@
#ifndef VOXEL_GRAPH_NODE_INSPECTOR_WRAPPER_H
#define VOXEL_GRAPH_NODE_INSPECTOR_WRAPPER_H
#include "../../generators/graph/program_graph.h"
#include "../../generators/graph/voxel_generator_graph.h"
#include <core/reference.h>
class VoxelGeneratorGraph;
// Nodes aren't resources so this translates them into a form the inspector can understand.
// This makes it easier to support undo/redo and sub-resources.
// WARNING: `AnimationPlayer` will allow to keyframe properties, but there really is no support for that.

View File

@ -1,6 +1,8 @@
#include "voxel_terrain_editor_plugin.h"
#include "../../generators/voxel_generator.h"
#include "../../terrain/voxel_lod_terrain.h"
#include "../../terrain/voxel_terrain.h"
#include "../graph/voxel_graph_node_inspector_wrapper.h"
VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
_restart_stream_button = memnew(Button);
@ -10,25 +12,78 @@ VoxelTerrainEditorPlugin::VoxelTerrainEditorPlugin(EditorNode *p_node) {
add_control_to_container(CONTAINER_SPATIAL_EDITOR_MENU, _restart_stream_button);
}
bool VoxelTerrainEditorPlugin::handles(Object *p_object) const {
static Node *get_as_terrain(Object *p_object) {
VoxelTerrain *terrain = Object::cast_to<VoxelTerrain>(p_object);
if (terrain != nullptr) {
return true;
return terrain;
}
VoxelLodTerrain *terrain2 = Object::cast_to<VoxelLodTerrain>(p_object);
return terrain2 != nullptr;
if (terrain2 != nullptr) {
return terrain2;
}
return nullptr;
}
// Things the plugin doesn't directly work on, but still handles to keep things visible.
// This is basically a hack because it's not easy to express that with EditorPlugin API.
// The use case being, as long as we edit an object NESTED within a voxel terrain, we should keep things visible.
static bool is_side_handled(Object *p_object) {
// Handle stream too so we can leave some controls visible while we edit a stream or generator
VoxelGenerator *generator = Object::cast_to<VoxelGenerator>(p_object);
if (generator != nullptr) {
return true;
}
// And have to account for this hack as well
VoxelGraphNodeInspectorWrapper *wrapper = Object::cast_to<VoxelGraphNodeInspectorWrapper>(p_object);
if (wrapper != nullptr) {
return true;
}
return false;
}
bool VoxelTerrainEditorPlugin::handles(Object *p_object) const {
if (get_as_terrain(p_object) != nullptr) {
return true;
}
if (_node != nullptr) {
return is_side_handled(p_object);
}
return false;
}
void VoxelTerrainEditorPlugin::edit(Object *p_object) {
_node = Object::cast_to<Node>(p_object);
Node *node = get_as_terrain(p_object);
if (node != nullptr) {
set_node(node);
} else {
if (!is_side_handled(p_object)) {
set_node(nullptr);
}
}
}
void VoxelTerrainEditorPlugin::set_node(Node *node) {
if (_node != nullptr) {
// Using this to know when the node becomes really invalid, because ObjectID is unreliable in Godot 3.x,
// and we may want to keep access to the node when we select some different kinds of objects.
// Also moving the node around in the tree triggers exit/enter so have to listen for both.
_node->disconnect("tree_entered", this, "_on_terrain_tree_entered");
_node->disconnect("tree_exited", this, "_on_terrain_tree_exited");
}
_node = node;
if (_node != nullptr) {
_node->connect("tree_entered", this, "_on_terrain_tree_entered", varray(_node));
_node->connect("tree_exited", this, "_on_terrain_tree_exited", varray(_node));
}
}
void VoxelTerrainEditorPlugin::make_visible(bool visible) {
_restart_stream_button->set_visible(visible);
if (!visible) {
_node = nullptr;
}
// Can't use `make_visible(false)` to reset our reference to the node,
// because of https://github.com/godotengine/godot/issues/40166
// So we'll need to check if _node is null all over the place
}
void VoxelTerrainEditorPlugin::_on_restart_stream_button_pressed() {
@ -43,7 +98,18 @@ void VoxelTerrainEditorPlugin::_on_restart_stream_button_pressed() {
terrain2->restart_stream();
}
void VoxelTerrainEditorPlugin::_on_terrain_tree_entered(Node *node) {
// If the node exited the tree because it was deleted, signals we connected should automatically disconnect.
_node = node;
}
void VoxelTerrainEditorPlugin::_on_terrain_tree_exited(Node *node) {
_node = nullptr;
}
void VoxelTerrainEditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("_on_restart_stream_button_pressed"),
&VoxelTerrainEditorPlugin::_on_restart_stream_button_pressed);
ClassDB::bind_method(D_METHOD("_on_terrain_tree_entered"), &VoxelTerrainEditorPlugin::_on_terrain_tree_entered);
ClassDB::bind_method(D_METHOD("_on_terrain_tree_exited"), &VoxelTerrainEditorPlugin::_on_terrain_tree_exited);
}

View File

@ -15,7 +15,11 @@ public:
void make_visible(bool visible) override;
private:
void set_node(Node *node);
void _on_restart_stream_button_pressed();
void _on_terrain_tree_entered(Node *node);
void _on_terrain_tree_exited(Node *node);
static void _bind_methods();