Skip to content

Commit

Permalink
Feat/csv-import (#3)
Browse files Browse the repository at this point in the history
* feat: starts working on the csv importer

* feat: adds CSV resource importer

* feat: adds export to csv

---------

Co-authored-by: OctoD <[email protected]>
  • Loading branch information
OctoD and OctoD authored Jun 6, 2024
1 parent b773926 commit fe773e6
Show file tree
Hide file tree
Showing 12 changed files with 296 additions and 137 deletions.
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,13 @@
"options": {
"env": {
"RUST_BACKTRACE": "1"
},
}
},
"runOptions": {
"instanceLimit": 1
},
"detail": "Run the built addon in Godot",
"command": "godot godot/project.godot"
"command": "godot godot/project.godot",
},
{
"type": "cargo",
Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "godot_gameplay_tags"
version = "0.1.0"
version = "0.3.0"
edition = "2021"

[lib]
Expand All @@ -9,4 +9,4 @@ crate-type = ["cdylib"] # Compile this crate to a dynamic C library.
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
godot = { git = "https://github.com/godot-rust/gdext", branch = "master" }
godot = { git = "https://github.com/godot-rust/gdext", branch = "master", features = ["experimental-threads"] }
21 changes: 10 additions & 11 deletions src/editor/docks/node_tagging_dock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,10 @@ impl NodeTaggingDock {

#[func]
fn render_tag_trees(&mut self) {
// let's start with cleaning up child elements
for mut child in self.to_gd().get_children().iter_shared() {
child.queue_free();
}
// let's start with cleaning up child elements
for mut child in self.to_gd().get_children().iter_shared() {
child.queue_free();
}

let mut tag_dictionary_fs = TagDictionaryFs::new_gd();
let tag_manager = TagManager::new_alloc();
Expand Down Expand Up @@ -100,12 +100,11 @@ impl IVBoxContainer for NodeTaggingDock {
fn ready(&mut self) {
self.to_gd().set_name("Node tags".into());

if let Some(mut selection) = EditorInterface::singleton().get_selection() {
selection.connect(
"selection_changed".into(),
Callable::from_object_method(&self.to_gd(), "render_tag_trees"),
);
}

if let Some(mut selection) = EditorInterface::singleton().get_selection() {
selection.connect(
"selection_changed".into(),
Callable::from_object_method(&self.to_gd(), "render_tag_trees"),
);
}
}
}
112 changes: 112 additions & 0 deletions src/editor/editor_import_plugins/csv_import_plugin.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
use godot::{
engine::{file_access::ModeFlags, FileAccess, IEditorImportPlugin, ResourceSaver},
global::Error,
prelude::*,
};

use crate::tag_dictionary::TagDictionary;

#[derive(GodotClass)]
#[class(tool, hidden, init, base = EditorImportPlugin)]
pub struct CsvImportPlugin {}

#[godot_api]
impl IEditorImportPlugin for CsvImportPlugin {
fn get_import_options(&self, _path: GString, _preset_index: i32) -> Array<Dictionary> {
Array::new() as Array<Dictionary>
}

fn get_import_order(&self) -> i32 {
0
}

fn get_importer_name(&self) -> GString {
"ggt_importer_csv".into()
}

fn get_recognized_extensions(&self) -> PackedStringArray {
let mut out = PackedStringArray::new();
out.push("csv".into());
out
}

fn get_option_visibility(
&self,
_path: GString,
_option_name: StringName,
_options: Dictionary,
) -> bool {
true
}

fn get_preset_count(&self) -> i32 {
0
}

fn get_preset_name(&self, _preset_index: i32) -> GString {
"".into()
}

fn get_priority(&self) -> f32 {
1_000.0
}

fn get_resource_type(&self) -> GString {
"TagDictionary".into()
}

fn get_save_extension(&self) -> GString {
"".into()
}

fn get_visible_name(&self) -> GString {
"Gameplay Tags Importer".into()
}

fn import(
&self,
source_file: GString,
_save_path: GString,
_options: Dictionary,
_platform_variants: Array<GString>,
mut gen_files: Array<GString>,
) -> Error {
let mut tag_dictionary = TagDictionary::new_gd();
let resource_save_path = source_file.to_string() + ".tres";

tag_dictionary.take_over_path(resource_save_path.clone().into());

if let Some(file_contents) = FileAccess::open(source_file.clone(), ModeFlags::READ) {
let text_content = file_contents.get_as_text();
let text_content_str = text_content.to_string();
let lines = text_content_str.lines();
let mut imported_line_count = 0;

if lines.clone().count() == 0 {
return Error::OK;
}

lines.for_each(|line| {
let binding = line.replace(",", ".").replace("..", "");
let mut tag = binding;

if tag.ends_with(".") {
tag = tag[0..tag.len() - 1].to_string();
}

if !tag.is_empty() && tag_dictionary.bind_mut().add_tag(tag.into()) {
imported_line_count += 1;
}
});

if imported_line_count > 0 {
gen_files.push(resource_save_path.into());
return ResourceSaver::singleton().save(tag_dictionary.upcast());
}

return Error::OK;
}

Error::ERR_CANT_OPEN
}
}
1 change: 1 addition & 0 deletions src/editor/editor_import_plugins/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod csv_import_plugin;
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use godot::engine::box_container::AlignmentMode;
use godot::engine::control::{LayoutPreset, SizeFlags};
use godot::engine::file_access::ModeFlags;
use godot::engine::{
EditorInspectorPlugin, IEditorInspectorPlugin, ResourceSaver
Button, EditorInspectorPlugin, FileAccess, HBoxContainer, IEditorInspectorPlugin,
ResourceSaver, VBoxContainer,
};
use godot::prelude::*;

Expand All @@ -11,6 +14,7 @@ use crate::tag_dictionary::TagDictionary;
#[class(tool, init, base = EditorInspectorPlugin)]
pub struct TagDictionaryEditorInspectorPlugin {
base: Base<EditorInspectorPlugin>,
tag_dictionary: Option<Gd<TagDictionary>>,
}

#[godot_api]
Expand All @@ -19,6 +23,41 @@ impl TagDictionaryEditorInspectorPlugin {
pub fn handle_tag_dictionary_changed(tag_dictionary: Gd<TagDictionary>) {
ResourceSaver::singleton().save(tag_dictionary.to_variant().to());
}

#[func]
pub fn handle_tag_dictionary_export(&self) {
if let Some(td) = self.tag_dictionary.clone() {
let tags = td.bind().get_tags();
let mut output = String::from("");

for tag in tags.as_slice() {
output.push_str(&format!("{}\n", tag));
}

if let Some(mut f) = FileAccess::open(
td.get_path().to_string().replace("tres", "csv").into(),
ModeFlags::WRITE,
) {
f.store_string(GString::from(output));
f.close();
godot::global::print(&[
"Exported tag dictionary to: ".to_variant(),
td.get_path()
.to_string()
.replace("tres", "csv")
.to_variant(),
]);
} else {
godot::global::printerr(&[
"Failed to open file for writing: ".to_variant(),
td.get_path()
.to_string()
.replace("tres", "csv")
.to_variant(),
]);
}
}
}
}

#[godot_api]
Expand All @@ -41,23 +80,36 @@ impl IEditorInspectorPlugin for TagDictionaryEditorInspectorPlugin {
return false;
}

let mut export_button = Button::new_alloc();

export_button.connect(
"pressed".into(),
Callable::from_object_method(&self.to_gd(), "handle_tag_dictionary_export"),
);
export_button.set_text("Export to CVS".into());

let mut footer_container = HBoxContainer::new_alloc();

footer_container.add_child(export_button.to_variant().to());
footer_container.set_alignment(AlignmentMode::END);

let mut tag_tree = TagTree::new_alloc();
let mut tag_dictionary = _object
.try_cast::<TagDictionary>()
.expect("Failed to cast to TagDictionary");
let mut callable_args = VariantArray::new();

self.tag_dictionary = Some(tag_dictionary.clone());

callable_args.push(tag_dictionary.clone().to_variant());

let callable = Callable::from_object_method(&self.to_gd(), "handle_tag_dictionary_changed").bindv(callable_args);

let callable = Callable::from_object_method(&self.to_gd(), "handle_tag_dictionary_changed")
.bindv(callable_args);

if !tag_dictionary.is_connected("changed".into(), callable.clone()) {
tag_dictionary.connect(
"changed".into(),
callable
);
tag_dictionary.connect("changed".into(), callable);
}

tag_tree.bind_mut().set_tag_dictionary(Some(tag_dictionary));

tag_tree.set_hide_root(false);
Expand All @@ -68,7 +120,15 @@ impl IEditorInspectorPlugin for TagDictionaryEditorInspectorPlugin {
tag_tree.set_v_size_flags(SizeFlags::EXPAND_FILL);

// done this because of this https://github.com/godot-rust/gdext/issues/156
self.to_gd().add_custom_control(tag_tree.to_variant().to());
let mut vbox_container = VBoxContainer::new_alloc();

vbox_container.add_child(tag_tree.to_variant().to());
vbox_container.add_spacer(false);
vbox_container.add_child(footer_container.to_variant().to());
vbox_container.set_anchors_and_offsets_preset(LayoutPreset::FULL_RECT);

self.to_gd()
.add_custom_control(vbox_container.to_variant().to());

true
}
Expand Down
17 changes: 14 additions & 3 deletions src/editor/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod docks;
mod editor_import_plugins;
mod inspector_plugins;
mod tag_dictionary_fs;
pub mod ui;
Expand All @@ -15,6 +16,7 @@ use self::inspector_plugins::tag_dictionary_editor_inspector_plugin;
pub struct GameplayTagsEditorPlugin {
base: Base<EditorPlugin>,
node_tagging_dock: Option<Gd<docks::node_tagging_dock::NodeTaggingDock>>,
import_plugin_csv: Gd<editor_import_plugins::csv_import_plugin::CsvImportPlugin>,
tag_dictionary_editor_inspector_plugin:
Gd<tag_dictionary_editor_inspector_plugin::TagDictionaryEditorInspectorPlugin>,
}
Expand All @@ -23,8 +25,14 @@ pub struct GameplayTagsEditorPlugin {
impl IEditorPlugin for GameplayTagsEditorPlugin {
fn enter_tree(&mut self) {
self.node_tagging_dock = Some(docks::node_tagging_dock::NodeTaggingDock::new_alloc());
self.import_plugin_csv =
editor_import_plugins::csv_import_plugin::CsvImportPlugin::new_gd();

self.to_gd().add_control_to_dock(DockSlot::RIGHT_UL, self.node_tagging_dock.to_variant().to());
self.to_gd()
.add_control_to_dock(DockSlot::RIGHT_UL, self.node_tagging_dock.to_variant().to());

self.to_gd()
.add_import_plugin(self.import_plugin_csv.clone().upcast());

self.tag_dictionary_editor_inspector_plugin =
tag_dictionary_editor_inspector_plugin::TagDictionaryEditorInspectorPlugin::new_gd();
Expand All @@ -34,7 +42,6 @@ impl IEditorPlugin for GameplayTagsEditorPlugin {
.to_variant()
.to(),
);

}

fn exit_tree(&mut self) {
Expand All @@ -44,7 +51,11 @@ impl IEditorPlugin for GameplayTagsEditorPlugin {
.to(),
);

self.to_gd().remove_control_from_docks(self.node_tagging_dock.to_variant().to());
self.to_gd()
.remove_import_plugin(self.import_plugin_csv.to_variant().to());

self.to_gd()
.remove_control_from_docks(self.node_tagging_dock.to_variant().to());
}

fn get_plugin_name(&self) -> GString {
Expand Down
Loading

0 comments on commit fe773e6

Please sign in to comment.