built more assets and started playing with foliage painting
This commit is contained in:
778
addons/dreadpon.spatial_gardener/gardener/gardener.gd
Normal file
778
addons/dreadpon.spatial_gardener/gardener/gardener.gd
Normal file
@@ -0,0 +1,778 @@
|
||||
@tool
|
||||
extends Node3D
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Manages the lifecycles and connection of all components:
|
||||
# Greenhouse plants, Toolshed brushes, Painter controller
|
||||
# And the Arborist plant placement manager
|
||||
#
|
||||
# A lot of these connections go through the Gardener
|
||||
# Because some signal receivers need additional data the signal senders don't know about
|
||||
# E.g. painter doesn't know about plant states, but arborist needs them to apply painting changes
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
const FunLib = preload("../utility/fun_lib.gd")
|
||||
const Logger = preload("../utility/logger.gd")
|
||||
const Defaults = preload("../utility/defaults.gd")
|
||||
const Greenhouse = preload("../greenhouse/greenhouse.gd")
|
||||
const Toolshed = preload("../toolshed/toolshed.gd")
|
||||
const Painter = preload("painter.gd")
|
||||
const Arborist = preload("../arborist/arborist.gd")
|
||||
const DebugViewer = preload("debug_viewer.gd")
|
||||
const UI_SidePanel_SCN = preload("../controls/side_panel/ui_side_panel.tscn")
|
||||
const UI_SidePanel = preload("../controls/side_panel/ui_side_panel.gd")
|
||||
const Globals = preload("../utility/globals.gd")
|
||||
const DataImportExport = preload("data_import_export.gd")
|
||||
|
||||
const PropAction = preload("../utility/input_field_resource/prop_action.gd")
|
||||
const PA_PropSet = preload("../utility/input_field_resource/pa_prop_set.gd")
|
||||
const PA_PropEdit = preload("../utility/input_field_resource/pa_prop_edit.gd")
|
||||
const PA_ArrayInsert = preload("../utility/input_field_resource/pa_array_insert.gd")
|
||||
const PA_ArrayRemove = preload("../utility/input_field_resource/pa_array_remove.gd")
|
||||
const PA_ArraySet = preload("../utility/input_field_resource/pa_array_set.gd")
|
||||
|
||||
|
||||
|
||||
var plugin_version: String = ""
|
||||
var storage_version: int = 0
|
||||
#export
|
||||
var refresh_octree_shared_LOD_variants:bool = false : set = set_refresh_octree_shared_LOD_variants
|
||||
|
||||
# file_management
|
||||
var garden_work_directory:String : set = set_garden_work_directory
|
||||
# gardening
|
||||
var gardening_collision_mask := pow(2, 0) : set = set_gardening_collision_mask
|
||||
|
||||
var initialized_for_edit:bool = false : set = set_initialized_for_edit
|
||||
var is_edited: bool = false
|
||||
|
||||
var toolshed:Toolshed = null
|
||||
var greenhouse:Greenhouse = null
|
||||
var painter:Painter = null
|
||||
var arborist:Arborist = null
|
||||
var debug_viewer:DebugViewer = null
|
||||
|
||||
var _resource_previewer = null
|
||||
var _base_control:Control = null
|
||||
var _undo_redo = null
|
||||
|
||||
var _side_panel:UI_SidePanel = null
|
||||
var ui_category_brushes:Control = null
|
||||
var ui_category_plants:Control = null
|
||||
|
||||
var painting_node:Node3D = null
|
||||
|
||||
var logger = null
|
||||
var forward_input_events:bool = true
|
||||
|
||||
|
||||
signal changed_initialized_for_edit(state)
|
||||
signal greenhouse_prop_action_executed(prop_action, final_val)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Lifecycle
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init():
|
||||
set_meta("class", "Gardener")
|
||||
|
||||
|
||||
# Update plugin/storage versions that might have been stored inside a .tscn file for this Gardener
|
||||
# In case it was created in an older version of this plugin
|
||||
func update_plugin_ver():
|
||||
plugin_version = get_plugin_ver()
|
||||
storage_version = get_storage_ver()
|
||||
|
||||
|
||||
static func get_plugin_ver():
|
||||
return '1.3.3'
|
||||
|
||||
|
||||
static func get_storage_ver():
|
||||
return 3
|
||||
|
||||
|
||||
func _ready():
|
||||
update_plugin_ver()
|
||||
|
||||
logger = Logger.get_for(self, name)
|
||||
|
||||
# Without editor we only care about an Arborist
|
||||
# But it is already self-sufficient, so no need to initialize it
|
||||
if !Engine.is_editor_hint(): return
|
||||
|
||||
if has_node('painting'):
|
||||
painting_node = get_node('painting')
|
||||
else:
|
||||
painting_node = Node3D.new()
|
||||
painting_node.name = "painting"
|
||||
add_child(painting_node)
|
||||
|
||||
if has_node('debug_viewer'):
|
||||
debug_viewer = get_node('debug_viewer')
|
||||
else:
|
||||
debug_viewer = DebugViewer.new()
|
||||
debug_viewer.name = "debug_viewer"
|
||||
add_child(debug_viewer)
|
||||
|
||||
init_painter()
|
||||
painter.set_brush_collision_mask(gardening_collision_mask)
|
||||
|
||||
reload_resources()
|
||||
init_arborist()
|
||||
|
||||
set_gardening_collision_mask(gardening_collision_mask)
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
pass
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
if !Engine.is_editor_hint(): return
|
||||
|
||||
_apply_changes()
|
||||
stop_editing()
|
||||
|
||||
|
||||
func _process(delta):
|
||||
if painter:
|
||||
painter.update(delta)
|
||||
|
||||
|
||||
func _apply_changes():
|
||||
if !Engine.is_editor_hint(): return
|
||||
if !FunLib.is_dir_valid(garden_work_directory): return
|
||||
|
||||
save_toolshed()
|
||||
save_greenhouse()
|
||||
toolshed.set_undo_redo(_undo_redo)
|
||||
greenhouse.set_undo_redo(_undo_redo)
|
||||
|
||||
|
||||
func add_child(node:Node, legible_unique_name:bool = false, internal:InternalMode = 0):
|
||||
super.add_child(node, legible_unique_name)
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Input
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func forwarded_input(camera, event):
|
||||
if !forward_input_events: return false
|
||||
|
||||
var handled = painter.forwarded_input(camera, event)
|
||||
if !handled:
|
||||
handled = toolshed.forwarded_input(camera, event)
|
||||
if !handled:
|
||||
handled = arborist._unhandled_input(event)
|
||||
|
||||
return handled
|
||||
|
||||
|
||||
# A hack to propagate editor camera
|
||||
# Should be called by plugin.gd
|
||||
func propagate_camera(camera:Camera3D):
|
||||
if arborist:
|
||||
arborist.active_camera_override = camera
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Initialization
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# This is supposed to address a problem decribed in "start_gardener_edit()" of "plugin.gd"
|
||||
# Instead of recalculating everything, we hope it's enough to just restore the member references
|
||||
func restore_references():
|
||||
logger = Logger.get_for(self, name)
|
||||
if !Engine.is_editor_hint(): return
|
||||
|
||||
if has_node('painting'):
|
||||
painting_node = get_node('painting')
|
||||
if has_node('debug_viewer'):
|
||||
debug_viewer = get_node('debug_viewer')
|
||||
|
||||
init_painter()
|
||||
painter.set_brush_collision_mask(gardening_collision_mask)
|
||||
|
||||
reload_resources()
|
||||
|
||||
if has_node("Arborist") && is_instance_of(get_node("Arborist"), Arborist):
|
||||
arborist = get_node("Arborist")
|
||||
|
||||
set_gardening_collision_mask(gardening_collision_mask)
|
||||
|
||||
|
||||
# Initialize a Painter
|
||||
# Assumed to be the first manager to initialize
|
||||
func init_painter():
|
||||
FunLib.free_children(painting_node)
|
||||
painter = Painter.new(painting_node)
|
||||
painter.stroke_updated.connect(on_painter_stroke_updated)
|
||||
painter.changed_active_brush_prop.connect(on_changed_active_brush_prop)
|
||||
painter.stroke_started.connect(on_painter_stroke_started)
|
||||
painter.stroke_finished.connect(on_painter_stroke_finished)
|
||||
|
||||
|
||||
# Initialize the Arborist and connect it to other objects
|
||||
# Won't be called without editor, as Arborist is already self-sufficient
|
||||
func init_arborist():
|
||||
# A fancy way of saying
|
||||
# "Make sure there is a correct node with a correct name"
|
||||
if has_node("Arborist") && is_instance_of(get_node("Arborist"), Arborist):
|
||||
arborist = get_node("Arborist")
|
||||
logger.info("Found existing Arborist")
|
||||
else:
|
||||
if has_node("Arborist"):
|
||||
var old_arborist = get_node("Arborist")
|
||||
old_arborist.owner = null
|
||||
remove_child(old_arborist)
|
||||
old_arborist.queue_free()
|
||||
logger.info("Removed invalid Arborist")
|
||||
arborist = Arborist.new()
|
||||
arborist.name = "Arborist"
|
||||
add_child(arborist)
|
||||
logger.info("Added new Arborist")
|
||||
|
||||
if greenhouse:
|
||||
pair_arborist_greenhouse()
|
||||
pair_debug_viewer_arborist()
|
||||
pair_debug_viewer_greenhouse()
|
||||
|
||||
|
||||
# Initialize a Greenhouse and a Toolshed
|
||||
# Rebuild UI if needed
|
||||
func reload_resources():
|
||||
var last_toolshed = toolshed
|
||||
var last_greenhouse = greenhouse
|
||||
|
||||
var created_new_toolshed := false
|
||||
var created_new_greenhouse := false
|
||||
|
||||
if !FunLib.is_dir_valid(garden_work_directory):
|
||||
logger.warn("Skipped loading Toolshed and Greenhouse, please specify a working directory for this Gardener (%s)" % [str(self)])
|
||||
else:
|
||||
toolshed = FunLib.load_res(garden_work_directory, "toolshed.tres", false)
|
||||
greenhouse = FunLib.load_res(garden_work_directory, "greenhouse.tres", false)
|
||||
if !toolshed:
|
||||
logger.warn("Unable to load Toolshed, created a new one")
|
||||
toolshed = Defaults.DEFAULT_TOOLSHED()
|
||||
created_new_toolshed = true
|
||||
if !greenhouse:
|
||||
logger.warn("Unable to load Greenhouse, created a new one")
|
||||
greenhouse = Greenhouse.new()
|
||||
created_new_greenhouse = true
|
||||
|
||||
toolshed.set_undo_redo(_undo_redo)
|
||||
greenhouse.set_undo_redo(_undo_redo)
|
||||
|
||||
if last_toolshed:
|
||||
last_toolshed.prop_action_executed.disconnect(on_toolshed_prop_action_executed)
|
||||
last_toolshed.prop_action_executed_on_brush.disconnect(on_toolshed_prop_action_executed_on_brush)
|
||||
FunLib.ensure_signal(toolshed.prop_action_executed, on_toolshed_prop_action_executed)
|
||||
FunLib.ensure_signal(toolshed.prop_action_executed_on_brush, on_toolshed_prop_action_executed_on_brush)
|
||||
|
||||
if last_greenhouse:
|
||||
last_greenhouse.prop_action_executed.disconnect(on_greenhouse_prop_action_executed)
|
||||
last_greenhouse.prop_action_executed_on_plant_state.disconnect(on_greenhouse_prop_action_executed_on_plant_state)
|
||||
last_greenhouse.prop_action_executed_on_plant_state_plant.disconnect(on_greenhouse_prop_action_executed_on_plant_state_plant)
|
||||
last_greenhouse.prop_action_executed_on_LOD_variant.disconnect(on_greenhouse_prop_action_executed_on_LOD_variant)
|
||||
last_greenhouse.req_octree_reconfigure.disconnect(on_greenhouse_req_octree_reconfigure)
|
||||
last_greenhouse.req_octree_recenter.disconnect(on_greenhouse_req_octree_recenter)
|
||||
last_greenhouse.req_import_plant_data.disconnect(on_greenhouse_req_import_plant_data)
|
||||
last_greenhouse.req_export_plant_data.disconnect(on_greenhouse_req_export_plant_data)
|
||||
last_greenhouse.req_import_greenhouse_data.disconnect(on_greenhouse_req_import_greenhouse_data)
|
||||
last_greenhouse.req_export_greenhouse_data.disconnect(on_greenhouse_req_export_greenhouse_data)
|
||||
FunLib.ensure_signal(greenhouse.prop_action_executed, on_greenhouse_prop_action_executed)
|
||||
FunLib.ensure_signal(greenhouse.prop_action_executed_on_plant_state, on_greenhouse_prop_action_executed_on_plant_state)
|
||||
FunLib.ensure_signal(greenhouse.prop_action_executed_on_plant_state_plant, on_greenhouse_prop_action_executed_on_plant_state_plant)
|
||||
FunLib.ensure_signal(greenhouse.prop_action_executed_on_LOD_variant, on_greenhouse_prop_action_executed_on_LOD_variant)
|
||||
FunLib.ensure_signal(greenhouse.req_octree_reconfigure, on_greenhouse_req_octree_reconfigure)
|
||||
FunLib.ensure_signal(greenhouse.req_octree_recenter, on_greenhouse_req_octree_recenter)
|
||||
FunLib.ensure_signal(greenhouse.req_import_plant_data, on_greenhouse_req_import_plant_data)
|
||||
FunLib.ensure_signal(greenhouse.req_export_plant_data, on_greenhouse_req_export_plant_data)
|
||||
FunLib.ensure_signal(greenhouse.req_import_greenhouse_data, on_greenhouse_req_import_greenhouse_data)
|
||||
FunLib.ensure_signal(greenhouse.req_export_greenhouse_data, on_greenhouse_req_export_greenhouse_data)
|
||||
|
||||
if arborist:
|
||||
pair_arborist_greenhouse()
|
||||
|
||||
if toolshed && toolshed != last_toolshed && _side_panel:
|
||||
ui_category_brushes = toolshed.create_ui(_base_control, _resource_previewer)
|
||||
_side_panel.set_tool_ui(ui_category_brushes, 0)
|
||||
if greenhouse && greenhouse != last_greenhouse && _side_panel:
|
||||
ui_category_plants = greenhouse.create_ui(_base_control, _resource_previewer)
|
||||
_side_panel.set_tool_ui(ui_category_plants, 1)
|
||||
|
||||
if arborist:
|
||||
for i in range(0, arborist.octree_managers.size()):
|
||||
arborist.emit_member_count(i)
|
||||
|
||||
if created_new_toolshed:
|
||||
save_toolshed()
|
||||
if created_new_greenhouse:
|
||||
save_greenhouse()
|
||||
|
||||
|
||||
# It's possible we load a different Greenhouse while an Arborist is already initialized
|
||||
# So collapse that into a function
|
||||
func pair_arborist_greenhouse():
|
||||
if !arborist || !greenhouse:
|
||||
if !arborist: logger.warn("Arborist->Greenhouse: Arborist is not initialized!")
|
||||
if !greenhouse: logger.warn("Arborist->Greenhouse: Greenhouse is not initialized!")
|
||||
return
|
||||
# We could duplicate an array, but that's additional overhead so we assume Arborist won't change it
|
||||
arborist.setup(greenhouse.greenhouse_plant_states)
|
||||
|
||||
if !arborist.member_count_updated.is_connected(greenhouse.plant_count_updated):
|
||||
arborist.member_count_updated.connect(greenhouse.plant_count_updated)
|
||||
|
||||
|
||||
func pair_debug_viewer_greenhouse():
|
||||
if !debug_viewer || !greenhouse:
|
||||
if !debug_viewer: logger.warn("DebugViewer->Greenhouse: DebugViewer is not initialized!")
|
||||
if !greenhouse: logger.warn("DebugViewer->Greenhouse: Greenhouse is not initialized!")
|
||||
return
|
||||
|
||||
debug_viewer.set_prop_edit_selected_plant(greenhouse.greenhouse_plant_states.find(greenhouse.selected_for_edit_resource))
|
||||
reinit_debug_draw_brush_active()
|
||||
|
||||
|
||||
func pair_debug_viewer_arborist():
|
||||
if !debug_viewer || !arborist:
|
||||
if !debug_viewer: logger.warn("DebugViewer->Arborist: DebugViewer is not initialized!")
|
||||
if !arborist: logger.warn("DebugViewer->Arborist: Arborist is not initialized!")
|
||||
return
|
||||
|
||||
if !arborist.req_debug_redraw.is_connected(debug_viewer.request_debug_redraw):
|
||||
arborist.req_debug_redraw.connect(debug_viewer.request_debug_redraw)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Start/stop editing lifecycle
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Start editing (painting) a scene
|
||||
func start_editing(__base_control:Control, __resource_previewer, __undoRedo, __side_panel:UI_SidePanel):
|
||||
_base_control = __base_control
|
||||
_resource_previewer = __resource_previewer
|
||||
_undo_redo = __undoRedo
|
||||
|
||||
_side_panel = __side_panel
|
||||
changed_initialized_for_edit.connect(_side_panel.set_main_control_state)
|
||||
|
||||
ui_category_brushes = toolshed.create_ui(_base_control, _resource_previewer)
|
||||
ui_category_plants = greenhouse.create_ui(_base_control, _resource_previewer)
|
||||
_side_panel.set_tool_ui(ui_category_brushes, 0)
|
||||
_side_panel.set_tool_ui(ui_category_plants, 1)
|
||||
toolshed.set_undo_redo(_undo_redo)
|
||||
greenhouse.set_undo_redo(_undo_redo)
|
||||
|
||||
arborist._undo_redo = _undo_redo
|
||||
|
||||
# # Making sure we and UI are on the same page (setting property values and checkboxes/tabs)
|
||||
painter_update_to_active_brush(toolshed.active_brush)
|
||||
_side_panel.set_main_control_state(initialized_for_edit)
|
||||
|
||||
painter.start_editing()
|
||||
|
||||
for i in range(0, arborist.octree_managers.size()):
|
||||
arborist.emit_member_count(i)
|
||||
# Make sure LOD_Variants in a shared Octree array are up-to-date
|
||||
set_refresh_octree_shared_LOD_variants(true)
|
||||
is_edited = true
|
||||
|
||||
|
||||
# Stop editing (painting) a scene
|
||||
func stop_editing():
|
||||
if is_instance_valid(_side_panel):
|
||||
changed_initialized_for_edit.disconnect(_side_panel.set_main_control_state)
|
||||
_side_panel = null
|
||||
|
||||
if is_instance_valid(painter):
|
||||
painter.stop_editing()
|
||||
is_edited = false
|
||||
|
||||
|
||||
# We can properly start editing only when a workDirectory is set
|
||||
func validate_initialized_for_edit():
|
||||
var work_directory_valid = FunLib.is_dir_valid(garden_work_directory)
|
||||
|
||||
# Originally there were two conditions to fulfill, not just the workDirectory
|
||||
# Keeping this in case it will be needed in the future
|
||||
var _initialized_for_edit = work_directory_valid
|
||||
if initialized_for_edit != _initialized_for_edit:
|
||||
set_initialized_for_edit(_initialized_for_edit)
|
||||
|
||||
|
||||
# Pass a request for updating a debug view menu
|
||||
func up_to_date_debug_view_menu(debug_view_menu:MenuButton):
|
||||
assert(debug_viewer)
|
||||
debug_viewer.up_to_date_debug_view_menu(debug_view_menu)
|
||||
debug_viewer.request_debug_redraw(arborist.octree_managers)
|
||||
|
||||
|
||||
# Pass a request for checking a debug view menu flag
|
||||
func debug_view_flag_checked(debug_view_menu:MenuButton, flag:int):
|
||||
assert(debug_viewer)
|
||||
debug_viewer.flag_checked(debug_view_menu, flag)
|
||||
debug_viewer.request_debug_redraw(arborist.octree_managers)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Handle changes in owned properties
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func set_gardening_collision_mask(val):
|
||||
gardening_collision_mask = val
|
||||
if painter:
|
||||
painter.set_brush_collision_mask(gardening_collision_mask)
|
||||
if arborist:
|
||||
arborist.set_gardening_collision_mask(gardening_collision_mask)
|
||||
|
||||
|
||||
func set_garden_work_directory(val):
|
||||
if !val.is_empty() && !val.ends_with("/"):
|
||||
val += "/"
|
||||
|
||||
var changed = garden_work_directory != val
|
||||
garden_work_directory = val
|
||||
|
||||
if !Engine.is_editor_hint(): return
|
||||
# If we changed a directory, reload everything that resides there
|
||||
if changed:
|
||||
if is_inside_tree():
|
||||
reload_resources()
|
||||
validate_initialized_for_edit()
|
||||
|
||||
|
||||
func set_initialized_for_edit(val):
|
||||
initialized_for_edit = val
|
||||
changed_initialized_for_edit.emit(initialized_for_edit)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Handle communication with the Greenhouse
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# When Greenhouse properties are changed
|
||||
func on_greenhouse_prop_action_executed(prop_action:PropAction, final_val):
|
||||
if is_instance_of(prop_action, PA_ArrayInsert):
|
||||
arborist.on_plant_added(final_val[prop_action.index], prop_action.index)
|
||||
reinit_debug_draw_brush_active()
|
||||
elif is_instance_of(prop_action, PA_ArrayRemove):
|
||||
arborist.on_plant_removed(prop_action.val, prop_action.index)
|
||||
reinit_debug_draw_brush_active()
|
||||
elif is_instance_of(prop_action, PA_PropSet) && prop_action.prop == "plant_types/selected_for_edit_resource":
|
||||
debug_viewer.set_prop_edit_selected_plant(greenhouse.greenhouse_plant_states.find(final_val))
|
||||
debug_viewer.request_debug_redraw(arborist.octree_managers)
|
||||
|
||||
greenhouse_prop_action_executed.emit(prop_action, final_val)
|
||||
|
||||
|
||||
# When Greenhouse_PlantState properties are changed
|
||||
func on_greenhouse_prop_action_executed_on_plant_state(prop_action:PropAction, final_val, plant_state):
|
||||
var plant_index = greenhouse.greenhouse_plant_states.find(plant_state)
|
||||
|
||||
match prop_action.prop:
|
||||
"plant/plant_brush_active":
|
||||
if is_instance_of(prop_action, PA_PropSet) || is_instance_of(prop_action, PA_PropEdit):
|
||||
debug_viewer.set_brush_active_plant(plant_state.plant_brush_active, plant_index)
|
||||
debug_viewer.request_debug_redraw(arborist.octree_managers)
|
||||
|
||||
|
||||
# When Greenhouse_Plant properties are changed
|
||||
func on_greenhouse_prop_action_executed_on_plant_state_plant(prop_action:PropAction, final_val, plant, plant_state):
|
||||
var plant_index = greenhouse.greenhouse_plant_states.find(plant_state)
|
||||
|
||||
match prop_action.prop:
|
||||
"mesh/mesh_LOD_variants":
|
||||
if is_instance_of(prop_action, PA_ArrayInsert):
|
||||
var mesh_index = prop_action.index
|
||||
arborist.on_LOD_variant_added(plant_index, mesh_index, final_val[mesh_index])
|
||||
elif is_instance_of(prop_action, PA_ArrayRemove):
|
||||
var mesh_index = prop_action.index
|
||||
arborist.on_LOD_variant_removed(plant_index, mesh_index)
|
||||
elif is_instance_of(prop_action, PA_ArraySet):
|
||||
var mesh_index = prop_action.index
|
||||
arborist.on_LOD_variant_set(plant_index, mesh_index, final_val[mesh_index])
|
||||
|
||||
"mesh/mesh_LOD_max_distance":
|
||||
if is_instance_of(prop_action, PA_PropSet) || is_instance_of(prop_action, PA_PropEdit):
|
||||
arborist.update_plant_LOD_max_distance(plant_index, final_val)
|
||||
|
||||
"mesh/mesh_LOD_kill_distance":
|
||||
if is_instance_of(prop_action, PA_PropSet) || is_instance_of(prop_action, PA_PropEdit):
|
||||
arborist.update_plant_LOD_kill_distance(plant_index, final_val)
|
||||
|
||||
|
||||
# When Greenhouse_LODVariant properties are changed
|
||||
func on_greenhouse_prop_action_executed_on_LOD_variant(prop_action:PropAction, final_val, LOD_variant, plant, plant_state):
|
||||
var plant_index = greenhouse.greenhouse_plant_states.find(plant_state)
|
||||
var mesh_index = plant.mesh_LOD_variants.find(LOD_variant)
|
||||
|
||||
match prop_action.prop:
|
||||
"spawned_spatial":
|
||||
if is_instance_of(prop_action, PA_PropSet) || is_instance_of(prop_action, PA_PropEdit):
|
||||
arborist.on_LOD_variant_prop_changed_spawned_spatial(plant_index, mesh_index, final_val)
|
||||
"cast_shadow":
|
||||
if is_instance_of(prop_action, PA_PropSet) || is_instance_of(prop_action, PA_PropEdit):
|
||||
arborist.set_LODs_to_active_index(plant_index)
|
||||
|
||||
|
||||
# A request to reconfigure an octree
|
||||
func on_greenhouse_req_octree_reconfigure(plant, plant_state):
|
||||
if !is_edited: return
|
||||
var plant_index = greenhouse.greenhouse_plant_states.find(plant_state)
|
||||
arborist.reconfigure_octree(plant_state, plant_index)
|
||||
|
||||
|
||||
# A request to recenter an octree
|
||||
func on_greenhouse_req_octree_recenter(plant, plant_state):
|
||||
if !is_edited: return
|
||||
var plant_index = greenhouse.greenhouse_plant_states.find(plant_state)
|
||||
arborist.recenter_octree(plant_state, plant_index)
|
||||
|
||||
|
||||
# Update brush active indexes for DebugViewer
|
||||
func reinit_debug_draw_brush_active():
|
||||
debug_viewer.reset_brush_active_plants()
|
||||
for plant_index in range(0, greenhouse.greenhouse_plant_states.size()):
|
||||
var plant_state = greenhouse.greenhouse_plant_states[plant_index]
|
||||
debug_viewer.set_brush_active_plant(plant_state.plant_brush_active, plant_index)
|
||||
debug_viewer.request_debug_redraw(arborist.octree_managers)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Importing/exporting data
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# A request to import plant data
|
||||
func on_greenhouse_req_import_plant_data(file_path: String, plant_idx: int):
|
||||
if !is_edited: return
|
||||
var import_export = DataImportExport.new(arborist, greenhouse)
|
||||
import_export.import_plant_data(file_path, plant_idx)
|
||||
|
||||
|
||||
# A request to export plant data
|
||||
func on_greenhouse_req_export_plant_data(file_path: String, plant_idx: int):
|
||||
if !is_edited: return
|
||||
var import_export = DataImportExport.new(arborist, greenhouse)
|
||||
import_export.export_plant_data(file_path, plant_idx)
|
||||
|
||||
|
||||
# A request to import entire greenhouse data
|
||||
func on_greenhouse_req_import_greenhouse_data(file_path: String):
|
||||
if !is_edited: return
|
||||
var import_export = DataImportExport.new(arborist, greenhouse)
|
||||
import_export.import_greenhouse_data(file_path)
|
||||
|
||||
|
||||
# A request to export entire greenhouse data
|
||||
func on_greenhouse_req_export_greenhouse_data(file_path: String):
|
||||
if !is_edited: return
|
||||
var import_export = DataImportExport.new(arborist, greenhouse)
|
||||
import_export.export_greenhouse_data(file_path)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Painter stroke lifecycle
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func on_painter_stroke_started(brush_data:Dictionary):
|
||||
var active_brush = toolshed.active_brush
|
||||
arborist.on_stroke_started(active_brush, greenhouse.greenhouse_plant_states)
|
||||
|
||||
|
||||
func on_painter_stroke_finished(brush_data:Dictionary):
|
||||
arborist.on_stroke_finished()
|
||||
|
||||
|
||||
func on_painter_stroke_updated(brush_data:Dictionary):
|
||||
arborist.on_stroke_updated(brush_data)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Painter - Toolshed relations
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Changed active brush from Toolshed. Update the painter
|
||||
func on_toolshed_prop_action_executed(prop_action:PropAction, final_val):
|
||||
assert(painter)
|
||||
if prop_action.prop != "brush/active_brush": return
|
||||
if !(is_instance_of(prop_action, PA_PropSet)) && !(is_instance_of(prop_action, PA_PropEdit)): return
|
||||
if final_val != toolshed.active_brush:
|
||||
logger.error("Passed final_val is not equal to toolshed.active_brush!")
|
||||
return
|
||||
|
||||
painter_update_to_active_brush(final_val)
|
||||
|
||||
|
||||
func painter_update_to_active_brush(active_brush):
|
||||
assert(active_brush)
|
||||
painter.queue_call_when_camera('update_all_props_to_active_brush', [active_brush])
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Quick edit for brush properties
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Property change instigated by Painter
|
||||
func on_changed_active_brush_prop(prop: String, val, final:bool):
|
||||
var prop_action: PropAction = null
|
||||
if final:
|
||||
prop_action = PA_PropSet.new(prop, val)
|
||||
else:
|
||||
prop_action = PA_PropEdit.new(prop, val)
|
||||
|
||||
if prop_action:
|
||||
toolshed.active_brush.request_prop_action(prop_action)
|
||||
|
||||
|
||||
# Propagate active_brush property changes to Painter
|
||||
func on_toolshed_prop_action_executed_on_brush(prop_action:PropAction, final_val, brush):
|
||||
assert(painter)
|
||||
if !(is_instance_of(prop_action, PA_PropSet)) && !(is_instance_of(prop_action, PA_PropEdit)): return
|
||||
if brush != toolshed.active_brush: return
|
||||
|
||||
match prop_action.prop:
|
||||
"shape/shape_volume_size":
|
||||
painter.set_active_brush_size(final_val)
|
||||
"shape/shape_projection_size":
|
||||
painter.set_active_brush_size(final_val)
|
||||
"behavior/behavior_strength":
|
||||
painter.set_active_brush_strength(final_val)
|
||||
"behavior/behavior_overlap_mode":
|
||||
painter_update_to_active_brush(brush)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Saving, loading and file management
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func save_toolshed():
|
||||
if FunLib.is_dir_valid(garden_work_directory):
|
||||
FunLib.save_res(toolshed, garden_work_directory, "toolshed.tres")
|
||||
|
||||
|
||||
func save_greenhouse():
|
||||
if FunLib.is_dir_valid(garden_work_directory):
|
||||
FunLib.save_res(greenhouse, garden_work_directory, "greenhouse.tres")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property export
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Writing this by hand THRICE for each property is honestly tiring
|
||||
# Built-in Godot reflection would go a long way
|
||||
func _get(property):
|
||||
match property:
|
||||
"file_management/garden_work_directory":
|
||||
return garden_work_directory
|
||||
"gardening/gardening_collision_mask":
|
||||
return gardening_collision_mask
|
||||
"plugin_version":
|
||||
return
|
||||
"storage_version":
|
||||
return storage_version
|
||||
|
||||
|
||||
func _set(property, val):
|
||||
var return_val = true
|
||||
|
||||
match property:
|
||||
"file_management/garden_work_directory":
|
||||
set_garden_work_directory(val)
|
||||
"gardening/gardening_collision_mask":
|
||||
set_gardening_collision_mask(val)
|
||||
_:
|
||||
return_val = false
|
||||
|
||||
return return_val
|
||||
|
||||
|
||||
func _get_property_list():
|
||||
return [
|
||||
{
|
||||
"name": "file_management/garden_work_directory",
|
||||
"type": TYPE_STRING,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_DIR
|
||||
},
|
||||
{
|
||||
"name": "gardening/gardening_collision_mask",
|
||||
"type": TYPE_INT,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_LAYERS_3D_PHYSICS
|
||||
},
|
||||
{
|
||||
"name": "plugin_version",
|
||||
"type": TYPE_STRING,
|
||||
"usage": PROPERTY_USAGE_NO_EDITOR,
|
||||
},
|
||||
{
|
||||
"name": "storage_version",
|
||||
"type": TYPE_STRING,
|
||||
"usage": PROPERTY_USAGE_NO_EDITOR,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Warning to be displayed in editor SceneTree
|
||||
func _get_configuration_warnings():
|
||||
var arborist_check = get_node("Arborist")
|
||||
if arborist_check && is_instance_of(arborist_check, Arborist):
|
||||
return ""
|
||||
else:
|
||||
return "Gardener is missing a valid Arborist child\nSince it should be created automatically, try reloading a scene or recreating a Gardener"
|
||||
|
||||
|
||||
func set_refresh_octree_shared_LOD_variants(val):
|
||||
refresh_octree_shared_LOD_variants = false
|
||||
if val && arborist && greenhouse:
|
||||
for i in range(0, greenhouse.greenhouse_plant_states.size()):
|
||||
arborist.refresh_octree_shared_LOD_variants(i, greenhouse.greenhouse_plant_states[i].plant.mesh_LOD_variants)
|
||||
Reference in New Issue
Block a user