built more assets and started playing with foliage painting
This commit is contained in:
390
addons/dreadpon.spatial_gardener/greenhouse/greenhouse.gd
Normal file
390
addons/dreadpon.spatial_gardener/greenhouse/greenhouse.gd
Normal file
@@ -0,0 +1,390 @@
|
||||
@tool
|
||||
extends "../utility/input_field_resource/input_field_resource.gd"
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# The manager of all plant types for a given Gardener
|
||||
# Handles interfacing between Greenhouse_PlantState, UI and plant placement
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
const Greenhouse_PlantState = preload("greenhouse_plant_state.gd")
|
||||
const ui_category_greenhouse_SCN = preload("../controls/side_panel/ui_category_greenhouse.tscn")
|
||||
|
||||
# All the plants (plant states) we have
|
||||
var greenhouse_plant_states:Array = []
|
||||
# Keep a reference to selected resource to easily display it
|
||||
var selected_for_edit_resource:Resource = null
|
||||
|
||||
var ui_category_greenhouse: Control = null
|
||||
var scroll_container_plant_thumbnails_nd:Control = null
|
||||
var scroll_container_properties_nd: Control = null
|
||||
var panel_container_category_nd:Control = null
|
||||
|
||||
var grid_container_plant_thumbnails_nd:UI_IF_ThumbnailArray = null
|
||||
var vbox_container_properties_nd:Control = null
|
||||
var _base_control:Control = null
|
||||
var _resource_previewer = null
|
||||
var _file_dialog: ConfirmationDialog = null
|
||||
|
||||
|
||||
signal prop_action_executed_on_plant_state(prop_action, final_val, plant_state)
|
||||
signal prop_action_executed_on_plant_state_plant(prop_action, final_val, plant, plant_state)
|
||||
signal prop_action_executed_on_LOD_variant(prop_action, final_val, LOD_variant, plant, plant_stat)
|
||||
signal req_octree_reconfigure(plant, plant_state)
|
||||
signal req_octree_recenter(plant, plant_state)
|
||||
signal req_import_plant_data(plant_idx, file)
|
||||
signal req_export_plant_data(plant_idx, file)
|
||||
signal req_import_greenhouse_data(file)
|
||||
signal req_export_greenhouse_data(file)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Initialization
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init():
|
||||
super()
|
||||
set_meta("class", "Greenhouse")
|
||||
resource_name = "Greenhouse"
|
||||
|
||||
_add_res_edit_source_array("plant_types/greenhouse_plant_states", "plant_types/selected_for_edit_resource")
|
||||
|
||||
if Engine.is_editor_hint():
|
||||
# Editor raises error everytime you run the game with F5 because of "abstract native class"
|
||||
# https://github.com/godotengine/godot/issues/73525
|
||||
_file_dialog = DPON_FM.ED_EditorFileDialog.new()
|
||||
else:
|
||||
_file_dialog = FileDialog.new()
|
||||
_file_dialog.close_requested.connect(on_file_dialog_hide)
|
||||
|
||||
|
||||
func _notification(what):
|
||||
match what:
|
||||
NOTIFICATION_PREDELETE:
|
||||
if is_instance_valid(_file_dialog):
|
||||
# Avoid memory leaks
|
||||
_file_dialog.queue_free()
|
||||
|
||||
|
||||
# The UI is created here because we need to manage it afterwards
|
||||
# And I see no reason to get lost in a signal spaghetti of delegating it
|
||||
func create_ui(__base_control:Control, __resource_previewer):
|
||||
_base_control = __base_control
|
||||
_resource_previewer = __resource_previewer
|
||||
|
||||
# Avoid memory leaks
|
||||
if is_instance_valid(ui_category_greenhouse):
|
||||
ui_category_greenhouse.queue_free()
|
||||
if is_instance_valid(grid_container_plant_thumbnails_nd):
|
||||
grid_container_plant_thumbnails_nd.queue_free()
|
||||
if is_instance_valid(vbox_container_properties_nd):
|
||||
vbox_container_properties_nd.queue_free()
|
||||
|
||||
ui_category_greenhouse = ui_category_greenhouse_SCN.instantiate()
|
||||
scroll_container_plant_thumbnails_nd = ui_category_greenhouse.find_child('ScrollContainer_PlantThumbnails')
|
||||
scroll_container_properties_nd = ui_category_greenhouse.find_child('ScrollContainer_Properties')
|
||||
panel_container_category_nd = ui_category_greenhouse.find_child('Label_Category_Plants')
|
||||
|
||||
panel_container_category_nd.theme_type_variation = "PropertyCategory"
|
||||
scroll_container_plant_thumbnails_nd.theme_type_variation = "InspectorPanelContainer"
|
||||
scroll_container_properties_nd.theme_type_variation = "InspectorPanelContainer"
|
||||
ui_category_greenhouse.theme_type_variation = "InspectorPanelContainer"
|
||||
|
||||
grid_container_plant_thumbnails_nd = create_input_field(_base_control, _resource_previewer, "plant_types/greenhouse_plant_states")
|
||||
grid_container_plant_thumbnails_nd.label.visible = false
|
||||
grid_container_plant_thumbnails_nd.name = "GridContainer_PlantThumbnails"
|
||||
grid_container_plant_thumbnails_nd.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
grid_container_plant_thumbnails_nd.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
grid_container_plant_thumbnails_nd.requested_check.connect(on_plant_state_check)
|
||||
grid_container_plant_thumbnails_nd.requested_label_edit.connect(on_plant_label_edit)
|
||||
|
||||
vbox_container_properties_nd = create_input_field(_base_control, _resource_previewer, "plant_types/selected_for_edit_resource")
|
||||
|
||||
scroll_container_plant_thumbnails_nd.add_child(grid_container_plant_thumbnails_nd)
|
||||
scroll_container_properties_nd.add_child(vbox_container_properties_nd)
|
||||
|
||||
return ui_category_greenhouse
|
||||
|
||||
|
||||
func _create_input_field(_base_control:Control, _resource_previewer, prop:String) -> UI_InputField:
|
||||
var input_field:UI_InputField = null
|
||||
match prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
var settings := {
|
||||
"add_create_inst_button": true,
|
||||
"accepted_classes": [Greenhouse_PlantState],
|
||||
"element_display_size": 100 * FunLib.get_setting_safe("dreadpons_spatial_gardener/input_and_ui/greenhouse_thumbnail_scale", 1.0),
|
||||
"element_interaction_flags": UI_IF_ThumbnailArray.PRESET_PLANT_STATE,
|
||||
}
|
||||
input_field = UI_IF_ThumbnailArray.new(greenhouse_plant_states, "Plant Types", prop, settings)
|
||||
"plant_types/selected_for_edit_resource":
|
||||
var settings := {
|
||||
"label_visibility": false,
|
||||
"tab": 0}
|
||||
input_field = UI_IF_Object.new(selected_for_edit_resource, "Plant State", prop, settings)
|
||||
|
||||
return input_field
|
||||
|
||||
|
||||
func add_plant_from_dict(plant_data: Dictionary, str_version: int = 1) -> int:
|
||||
var new_idx = greenhouse_plant_states.size()
|
||||
request_prop_action(PA_ArrayInsert.new(
|
||||
"plant_types/greenhouse_plant_states",
|
||||
Greenhouse_PlantState.new().ifr_from_dict(plant_data, true, str_version),
|
||||
new_idx
|
||||
))
|
||||
return new_idx
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# UI management
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Select a Greenhouse_PlantState for painting
|
||||
func on_plant_state_check(index:int, state:bool):
|
||||
var plant_state = greenhouse_plant_states[index]
|
||||
var prop_action = PA_PropSet.new("plant/plant_brush_active", state)
|
||||
plant_state.request_prop_action(prop_action)
|
||||
|
||||
|
||||
# Edit Greenhouse_PlantState's label
|
||||
func on_plant_label_edit(index:int, label_text:String):
|
||||
var plant_state = greenhouse_plant_states[index]
|
||||
var prop_action = PA_PropSet.new("plant/plant_label", label_text)
|
||||
plant_state.request_prop_action(prop_action)
|
||||
|
||||
|
||||
func select_plant_state_for_brush(index:int, state:bool):
|
||||
if is_instance_valid(grid_container_plant_thumbnails_nd):
|
||||
grid_container_plant_thumbnails_nd.set_thumb_interaction_feature_with_data(UI_ActionThumbnail_GD.InteractionFlags.CHECK, state, {"index": index})
|
||||
|
||||
|
||||
func set_plant_state_label(index:int, label_text:String):
|
||||
if is_instance_valid(grid_container_plant_thumbnails_nd):
|
||||
grid_container_plant_thumbnails_nd.set_thumb_interaction_feature_with_data(UI_ActionThumbnail_GD.InteractionFlags.EDIT_LABEL, label_text, {"index": index})
|
||||
|
||||
|
||||
func on_if_tree_entered(input_field:UI_InputField):
|
||||
super.on_if_tree_entered(input_field)
|
||||
|
||||
if input_field.prop_name == "plant_types/greenhouse_plant_states":
|
||||
for i in range(0, greenhouse_plant_states.size()):
|
||||
select_plant_state_for_brush(i, greenhouse_plant_states[i].plant_brush_active)
|
||||
set_plant_state_label(i, greenhouse_plant_states[i].plant_label)
|
||||
|
||||
|
||||
func plant_count_updated(plant_index, new_count):
|
||||
if is_instance_valid(grid_container_plant_thumbnails_nd) && grid_container_plant_thumbnails_nd.flex_grid.get_child_count() > plant_index:
|
||||
grid_container_plant_thumbnails_nd.flex_grid.get_child(plant_index).set_counter_val(new_count)
|
||||
|
||||
|
||||
func show_transform_import(type: String):
|
||||
if _file_dialog.get_parent() != _base_control:
|
||||
_base_control.add_child(_file_dialog)
|
||||
_file_dialog.popup_centered_ratio(0.5)
|
||||
_file_dialog.access = FileDialog.ACCESS_FILESYSTEM
|
||||
_file_dialog.filters = PackedStringArray(['*.json ; JSON'])
|
||||
match type:
|
||||
'import':
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
'export':
|
||||
_file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
||||
|
||||
|
||||
func on_file_dialog_hide():
|
||||
FunLib.disconnect_all(_file_dialog.file_selected)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Signal forwarding
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func on_changed_plant_state():
|
||||
emit_changed()
|
||||
|
||||
func on_req_octree_reconfigure(plant, plant_state):
|
||||
req_octree_reconfigure.emit(plant, plant_state)
|
||||
|
||||
func on_req_octree_recenter(plant, plant_state):
|
||||
req_octree_recenter.emit(plant, plant_state)
|
||||
|
||||
func on_req_import_plant_data(plant, plant_state):
|
||||
show_transform_import('import')
|
||||
var plant_idx = greenhouse_plant_states.find(plant_state)
|
||||
FunLib.disconnect_all(_file_dialog.file_selected)
|
||||
_file_dialog.file_selected.connect(on_req_import_export_plant_data_file.bind(req_import_plant_data, plant_idx))
|
||||
|
||||
func on_req_export_plant_data(plant, plant_state):
|
||||
show_transform_import('export')
|
||||
var plant_idx = greenhouse_plant_states.find(plant_state)
|
||||
FunLib.disconnect_all(_file_dialog.file_selected)
|
||||
_file_dialog.file_selected.connect(on_req_import_export_plant_data_file.bind(req_export_plant_data, plant_idx))
|
||||
|
||||
func on_req_import_greenhouse_data():
|
||||
show_transform_import('import')
|
||||
FunLib.disconnect_all(_file_dialog.file_selected)
|
||||
_file_dialog.file_selected.connect(on_req_import_export_greenhouse_data_file.bind(req_import_greenhouse_data))
|
||||
|
||||
func on_req_export_greenhouse_data():
|
||||
show_transform_import('export')
|
||||
FunLib.disconnect_all(_file_dialog.file_selected)
|
||||
_file_dialog.file_selected.connect(on_req_import_export_greenhouse_data_file.bind(req_export_greenhouse_data))
|
||||
|
||||
func on_req_import_export_plant_data_file(file_path: String, signal_obj: Signal, plant_idx: int):
|
||||
signal_obj.emit(file_path, plant_idx)
|
||||
|
||||
func on_req_import_export_greenhouse_data_file(file_path: String, signal_obj: Signal):
|
||||
signal_obj.emit(file_path)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Prop Actions
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func on_prop_action_executed(prop_action:PropAction, final_val):
|
||||
var prop_action_class = prop_action.get_meta("class")
|
||||
|
||||
match prop_action.prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
match prop_action_class:
|
||||
"PA_ArrayInsert":
|
||||
select_plant_state_for_brush(prop_action.index, final_val[prop_action.index].plant_brush_active)
|
||||
set_plant_state_label(prop_action.index, final_val[prop_action.index].plant_label)
|
||||
|
||||
|
||||
|
||||
func on_prop_action_executed_on_plant_state(prop_action, final_val, plant_state):
|
||||
if is_instance_of(prop_action, PA_PropSet):
|
||||
var plant_index = greenhouse_plant_states.find(plant_state)
|
||||
match prop_action.prop:
|
||||
"plant/plant_brush_active":
|
||||
select_plant_state_for_brush(plant_index, final_val)
|
||||
"plant/plant_label":
|
||||
set_plant_state_label(plant_index, final_val)
|
||||
|
||||
prop_action_executed_on_plant_state.emit(prop_action, final_val, plant_state)
|
||||
|
||||
|
||||
func on_prop_action_executed_on_plant_state_plant(prop_action, final_val, plant, plant_state):
|
||||
var plant_index = greenhouse_plant_states.find(plant_state)
|
||||
|
||||
# Any prop action on LOD variants - update thumbnail
|
||||
var update_thumbnail = prop_action.prop == "mesh/mesh_LOD_variants"
|
||||
if update_thumbnail && grid_container_plant_thumbnails_nd:
|
||||
grid_container_plant_thumbnails_nd._update_thumbnail(plant_state, plant_index)
|
||||
|
||||
prop_action_executed_on_plant_state_plant.emit(prop_action, final_val, plant, plant_state)
|
||||
|
||||
|
||||
func on_prop_action_executed_on_LOD_variant(prop_action, final_val, LOD_variant, plant, plant_state):
|
||||
prop_action_executed_on_LOD_variant.emit(prop_action, final_val, LOD_variant, plant, plant_state)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property export
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func set_undo_redo(val):
|
||||
super.set_undo_redo(val)
|
||||
for plant_state in greenhouse_plant_states:
|
||||
plant_state.set_undo_redo(_undo_redo)
|
||||
|
||||
|
||||
func _get(prop):
|
||||
match prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
return greenhouse_plant_states
|
||||
"plant_types/selected_for_edit_resource":
|
||||
return selected_for_edit_resource
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func _modify_prop(prop:String, val):
|
||||
match prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
for i in range(0, val.size()):
|
||||
if !is_instance_of(val[i], Greenhouse_PlantState):
|
||||
val[i] = Greenhouse_PlantState.new()
|
||||
|
||||
FunLib.ensure_signal(val[i].changed, on_changed_plant_state)
|
||||
FunLib.ensure_signal(val[i].prop_action_executed, on_prop_action_executed_on_plant_state, [val[i]])
|
||||
FunLib.ensure_signal(val[i].prop_action_executed_on_plant, on_prop_action_executed_on_plant_state_plant, [val[i]])
|
||||
FunLib.ensure_signal(val[i].prop_action_executed_on_LOD_variant, on_prop_action_executed_on_LOD_variant, [val[i]])
|
||||
FunLib.ensure_signal(val[i].req_octree_reconfigure, on_req_octree_reconfigure, [val[i]])
|
||||
FunLib.ensure_signal(val[i].req_octree_recenter, on_req_octree_recenter, [val[i]])
|
||||
FunLib.ensure_signal(val[i].req_import_plant_data, on_req_import_plant_data, [val[i]])
|
||||
FunLib.ensure_signal(val[i].req_export_plant_data, on_req_export_plant_data, [val[i]])
|
||||
FunLib.ensure_signal(val[i].req_import_greenhouse_data, on_req_import_greenhouse_data)
|
||||
FunLib.ensure_signal(val[i].req_export_greenhouse_data, on_req_export_greenhouse_data)
|
||||
|
||||
if val[i]._undo_redo != _undo_redo:
|
||||
val[i].set_undo_redo(_undo_redo)
|
||||
return val
|
||||
|
||||
|
||||
func _set(prop, val):
|
||||
var return_val = true
|
||||
val = _modify_prop(prop, val)
|
||||
|
||||
match prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
greenhouse_plant_states = val
|
||||
"plant_types/selected_for_edit_resource":
|
||||
selected_for_edit_resource = val
|
||||
_:
|
||||
return_val = false
|
||||
|
||||
if return_val:
|
||||
emit_changed()
|
||||
return return_val
|
||||
|
||||
|
||||
func _get_prop_dictionary():
|
||||
return {
|
||||
"plant_types/greenhouse_plant_states":
|
||||
{
|
||||
"name": "plant_types/greenhouse_plant_states",
|
||||
"type": TYPE_ARRAY,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE
|
||||
},
|
||||
"plant_types/selected_for_edit_resource":
|
||||
{
|
||||
"name": "plant_types/selected_for_edit_resource",
|
||||
"type": TYPE_OBJECT,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _fix_duplicate_signals(copy):
|
||||
copy._modify_prop("plant_types/greenhouse_plant_states", copy.greenhouse_plant_states)
|
||||
copy.selected_for_edit_resource = null
|
||||
|
||||
|
||||
func get_prop_tooltip(prop:String) -> String:
|
||||
match prop:
|
||||
"plant_types/greenhouse_plant_states":
|
||||
return "All the plants in this Greenhouse"
|
||||
"plant_types/selected_for_edit_resource":
|
||||
return "The plant currently selected for edit"
|
||||
|
||||
return ""
|
||||
@@ -0,0 +1,140 @@
|
||||
@tool
|
||||
extends "../utility/input_field_resource/input_field_resource.gd"
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# A storage object for meshes to be shown as plants
|
||||
# And spatials to be spawned at their position (typically a StaticBody3D)
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
var Globals = preload("../utility/globals.gd")
|
||||
|
||||
var mesh:Mesh = null
|
||||
var spawned_spatial:PackedScene = null
|
||||
# Toggle for shadow casting mode on multimeshes
|
||||
var cast_shadow:int = GeometryInstance3D.SHADOW_CASTING_SETTING_ON
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Initialization
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init(__mesh:Mesh = null, __spawned_spatial:PackedScene = null):
|
||||
super()
|
||||
set_meta("class", "Greenhouse_LODVariant")
|
||||
resource_name = "Greenhouse_LODVariant"
|
||||
|
||||
mesh = __mesh
|
||||
spawned_spatial = __spawned_spatial
|
||||
|
||||
|
||||
func _create_input_field(_base_control:Control, _resource_previewer, prop:String) -> UI_InputField:
|
||||
var input_field:UI_InputField = null
|
||||
|
||||
match prop:
|
||||
"mesh":
|
||||
var settings := {
|
||||
"accepted_classes": [Mesh],
|
||||
"element_display_size": 75 * FunLib.get_setting_safe("dreadpons_spatial_gardener/input_and_ui/greenhouse_thumbnail_scale", 1.0),
|
||||
"element_interaction_flags": UI_IF_ThumbnailArray.PRESET_RESOURCE,
|
||||
}
|
||||
input_field = UI_IF_ThumbnailObject.new(mesh, "Mesh", prop, settings)
|
||||
"spawned_spatial":
|
||||
var settings := {
|
||||
"accepted_classes": [PackedScene],
|
||||
"element_display_size": 75 * FunLib.get_setting_safe("dreadpons_spatial_gardener/input_and_ui/greenhouse_thumbnail_scale", 1.0),
|
||||
"element_interaction_flags": UI_IF_ThumbnailArray.PRESET_RESOURCE,
|
||||
}
|
||||
input_field = UI_IF_ThumbnailObject.new(spawned_spatial, "Spawned Node3D", prop, settings)
|
||||
"cast_shadow":
|
||||
var settings := {"enum_list": ["Off", "On", "Double-Sided", "Shadows Only"]}
|
||||
input_field = UI_IF_Enum.new(cast_shadow, "Shadow Casting Mode", prop, settings)
|
||||
|
||||
return input_field
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property export
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _set(prop, val):
|
||||
var return_val = true
|
||||
val = _modify_prop(prop, val)
|
||||
|
||||
match prop:
|
||||
"mesh":
|
||||
mesh = val
|
||||
"spawned_spatial":
|
||||
spawned_spatial = val
|
||||
"cast_shadow":
|
||||
cast_shadow = val
|
||||
_:
|
||||
return_val = false
|
||||
|
||||
if return_val:
|
||||
emit_changed()
|
||||
|
||||
return return_val
|
||||
|
||||
|
||||
func _get(prop):
|
||||
match prop:
|
||||
"mesh":
|
||||
return mesh
|
||||
"spawned_spatial":
|
||||
return spawned_spatial
|
||||
"cast_shadow":
|
||||
return cast_shadow
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func _get_prop_dictionary():
|
||||
return {
|
||||
"mesh" : {
|
||||
"name": "mesh",
|
||||
"type": TYPE_OBJECT,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE,
|
||||
},
|
||||
"spawned_spatial" : {
|
||||
"name": "spawned_spatial",
|
||||
"type": TYPE_OBJECT,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE,
|
||||
},
|
||||
"cast_shadow":
|
||||
{
|
||||
"name": "cast_shadow",
|
||||
"type": TYPE_INT,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_ENUM,
|
||||
"hint_string": "Off,On,Double-Sided,Shadows Only"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func get_prop_tooltip(prop:String) -> String:
|
||||
match prop:
|
||||
"mesh":
|
||||
return "The mesh (.mesh) resource used to display the plant"
|
||||
"spawned_spatial":
|
||||
return "The PackedScene (assumed to be Node3D) that spawns alongside the mesh\n" \
|
||||
+ "They are separate because mesh rendering is optimized using Godot's MultiMesh\n" \
|
||||
+ "Spawned Spatials are used to define custom behavior (excluding rendering) for each instance, mainly collision\n" \
|
||||
+ "This should be used sparingly, as thousands of physics bodies will surely approach a limit of what Godot can handle\n" \
|
||||
+ "\n" \
|
||||
+ "NOTE: switching LODs with Spawned Spatials can be expensive due to removing and adding hundreds of nodes at once\n" \
|
||||
+ "But if all your LODs reference the same PackedScene - they will persist across the LOD changes and won't cause any lag spikes\n" \
|
||||
+ "The alternative would be to optimise yout octrees to contain only a small amount of Spawned Spatials - 10-20 at most\n" \
|
||||
+ "Then the process of switching LODs will go a lot smoother"
|
||||
"cast_shadow":
|
||||
return "Shadow casting mode for this specific LOD\n" \
|
||||
+ "Disabling shadow casting slightly improves performance and is recommended for higher LODs (those further away)"
|
||||
return ""
|
||||
1032
addons/dreadpon.spatial_gardener/greenhouse/greenhouse_plant.gd
Normal file
1032
addons/dreadpon.spatial_gardener/greenhouse/greenhouse_plant.gd
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,194 @@
|
||||
@tool
|
||||
extends "../utility/input_field_resource/input_field_resource.gd"
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# A middle-man between the plant and the UI/painting/placement logic
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
const Greenhouse_Plant = preload("greenhouse_plant.gd")
|
||||
|
||||
|
||||
var plant_brush_active:bool = false
|
||||
var plant_label:String = ''
|
||||
var plant:Greenhouse_Plant = null
|
||||
|
||||
|
||||
signal prop_action_executed_on_plant(prop_action, final_val, plant)
|
||||
signal prop_action_executed_on_LOD_variant(prop_action, final_val, LOD_variant, plant)
|
||||
signal req_octree_reconfigure(plant)
|
||||
signal req_octree_recenter(plant)
|
||||
signal req_import_plant_data(plant)
|
||||
signal req_export_plant_data(plant)
|
||||
signal req_import_greenhouse_data()
|
||||
signal req_export_greenhouse_data()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Initialization
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init():
|
||||
super()
|
||||
set_meta("class", "Greenhouse_PlantState")
|
||||
resource_name = "Greenhouse_PlantState"
|
||||
# A workaround to trigger the initial creation of a plant
|
||||
_set("plant/plant", plant)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Signal forwarding
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func on_changed_plant():
|
||||
emit_changed()
|
||||
|
||||
func on_prop_action_executed_on_plant(prop_action, final_val, plant):
|
||||
prop_action_executed_on_plant.emit(prop_action, final_val, plant)
|
||||
|
||||
func on_req_octree_reconfigure(plant):
|
||||
req_octree_reconfigure.emit(plant)
|
||||
|
||||
func on_req_octree_recenter(plant):
|
||||
req_octree_recenter.emit(plant)
|
||||
|
||||
func on_req_import_plant_data(plant):
|
||||
req_import_plant_data.emit(plant)
|
||||
|
||||
func on_req_export_plant_data(plant):
|
||||
req_export_plant_data.emit(plant)
|
||||
|
||||
func on_req_import_greenhouse_data():
|
||||
req_import_greenhouse_data.emit()
|
||||
|
||||
func on_req_export_greenhouse_data():
|
||||
req_export_greenhouse_data.emit()
|
||||
|
||||
func on_prop_action_executed_on_LOD_variant(prop_action, final_val, LOD_variant, plant):
|
||||
prop_action_executed_on_LOD_variant.emit(prop_action, final_val, LOD_variant, plant)
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property management
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _modify_prop(prop:String, val):
|
||||
match prop:
|
||||
"plant/plant":
|
||||
if !is_instance_of(val, Greenhouse_Plant):
|
||||
val = Greenhouse_Plant.new()
|
||||
|
||||
FunLib.ensure_signal(val.changed, on_changed_plant)
|
||||
FunLib.ensure_signal(val.prop_action_executed, on_prop_action_executed_on_plant, [val])
|
||||
FunLib.ensure_signal(val.prop_action_executed_on_LOD_variant, on_prop_action_executed_on_LOD_variant, [val])
|
||||
FunLib.ensure_signal(val.req_octree_reconfigure, on_req_octree_reconfigure, [val])
|
||||
FunLib.ensure_signal(val.req_octree_recenter, on_req_octree_recenter, [val])
|
||||
FunLib.ensure_signal(val.req_import_plant_data, on_req_import_plant_data, [val])
|
||||
FunLib.ensure_signal(val.req_export_plant_data, on_req_export_plant_data, [val])
|
||||
FunLib.ensure_signal(val.req_import_greenhouse_data, on_req_import_greenhouse_data)
|
||||
FunLib.ensure_signal(val.req_export_greenhouse_data, on_req_export_greenhouse_data)
|
||||
|
||||
if val._undo_redo != _undo_redo:
|
||||
val.set_undo_redo(_undo_redo)
|
||||
return val
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property export
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func set_undo_redo(val):
|
||||
super.set_undo_redo(val)
|
||||
plant.set_undo_redo(_undo_redo)
|
||||
|
||||
|
||||
func _get(prop):
|
||||
match prop:
|
||||
"plant/plant_brush_active":
|
||||
return plant_brush_active
|
||||
"plant/plant_label":
|
||||
return plant_label
|
||||
"plant/plant":
|
||||
return plant
|
||||
|
||||
return null
|
||||
|
||||
|
||||
func _set(prop, val):
|
||||
var return_val = true
|
||||
val = _modify_prop(prop, val)
|
||||
|
||||
match prop:
|
||||
"plant/plant_brush_active":
|
||||
plant_brush_active = val
|
||||
"plant/plant_label":
|
||||
plant_label = val
|
||||
"plant/plant":
|
||||
plant = val
|
||||
_:
|
||||
return_val = false
|
||||
|
||||
if return_val:
|
||||
emit_changed()
|
||||
return return_val
|
||||
|
||||
|
||||
func _get_prop_dictionary():
|
||||
return {
|
||||
"plant/plant_brush_active":
|
||||
{
|
||||
"name": "plant/plant_brush_active",
|
||||
"type": TYPE_BOOL,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE
|
||||
},
|
||||
"plant/plant_label":
|
||||
{
|
||||
"name": "plant/plant_label",
|
||||
"type": TYPE_STRING,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE
|
||||
},
|
||||
"plant/plant":
|
||||
{
|
||||
"name": "plant/plant",
|
||||
"type": TYPE_OBJECT ,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_RESOURCE_TYPE
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func create_input_fields(_base_control:Control, _resource_previewer, whitelist:Array = []) -> Dictionary:
|
||||
if plant:
|
||||
return plant.create_input_fields(_base_control, _resource_previewer, whitelist)
|
||||
return {}
|
||||
|
||||
|
||||
func _fix_duplicate_signals(copy):
|
||||
copy._modify_prop("plant/plant", copy.plant)
|
||||
|
||||
|
||||
func get_prop_tooltip(prop:String) -> String:
|
||||
match prop:
|
||||
"plant/plant_brush_active":
|
||||
return "The flag that defines if plant will be used during painting or not"
|
||||
"plant/plant_brush_active":
|
||||
return "The label to be displayed on top of the plant's thumbnail"
|
||||
"plant/plant":
|
||||
return "The contained plant itself"
|
||||
|
||||
return ""
|
||||
Reference in New Issue
Block a user