built more assets and started playing with foliage painting
This commit is contained in:
613
addons/dreadpon.spatial_gardener/arborist/arborist.gd
Normal file
613
addons/dreadpon.spatial_gardener/arborist/arborist.gd
Normal file
@@ -0,0 +1,613 @@
|
||||
@tool
|
||||
extends Node3D
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Handles managing OctreeManager objects and changes applied when painting
|
||||
# Instigates updates to OctreeManager MutliMeshInstance (MMI) objects
|
||||
# To show the correct LOD variant when moving closer/further to plants
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
# It's worth considering to split this object into mutliple:
|
||||
# Octree management
|
||||
# Updating positions of individual plants (through painting)
|
||||
# Threaded updates to LODs (if possible)
|
||||
# However, these functions are very closely related, so maybe I'm overthinking this
|
||||
|
||||
|
||||
const Logger = preload("../utility/logger.gd")
|
||||
const Globals = preload("../utility/globals.gd")
|
||||
const FunLib = preload("../utility/fun_lib.gd")
|
||||
const Greenhouse_Plant = preload("../greenhouse/greenhouse_plant.gd")
|
||||
const Toolshed_Brush = preload("../toolshed/toolshed_brush.gd")
|
||||
const PaintingChanges = preload("painting_changes.gd")
|
||||
const MMIOctreeManager = preload("mmi_octree/mmi_octree_manager.gd")
|
||||
const UndoRedoInterface = preload("../utility/undo_redo_interface.gd")
|
||||
|
||||
const StrokeHandler = preload("stroke_handler/stroke_handler.gd")
|
||||
const SH_Paint = preload("stroke_handler/sh_paint.gd")
|
||||
const SH_Erase = preload("stroke_handler/sh_erase.gd")
|
||||
const SH_Single = preload("stroke_handler/sh_single.gd")
|
||||
const SH_Reapply = preload("stroke_handler/sh_reapply.gd")
|
||||
const SH_Manual = preload("stroke_handler/sh_manual.gd")
|
||||
|
||||
var MMI_container:Node3D = null
|
||||
var octree_managers:Array
|
||||
|
||||
var gardening_collision_mask:int = 0
|
||||
|
||||
# A manual override fot the camera (mainly used in Editor)
|
||||
var active_camera_override:Camera3D = null
|
||||
|
||||
var active_stroke_handler:StrokeHandler = null
|
||||
var active_painting_changes:PaintingChanges = null
|
||||
|
||||
# Threading LOD updates is not working for some reason. Gives error "Condition "!multimesh" is true." when closing a scene
|
||||
# This might be related to https://github.com/godotengine/godot/pull/54650
|
||||
# Possibly, there are some leftover references after closing a scene and idk how I'm supposed to clean them up
|
||||
#var mutex_placement:Mutex = null
|
||||
#var thread_instance_placement:Thread
|
||||
#var semaphore_instance_placement:Semaphore
|
||||
#var exit_instance_placement:bool
|
||||
#var done_instance_placement:bool
|
||||
|
||||
var _undo_redo = null
|
||||
|
||||
var debug_redraw_requested_managers:Array = []
|
||||
|
||||
var logger = null
|
||||
|
||||
|
||||
signal req_debug_redraw(octree_managers, requested_indexes)
|
||||
signal member_count_updated(octree_index, new_count)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Lifecycle and initialization
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _init():
|
||||
set_meta("class", "Arborist")
|
||||
|
||||
|
||||
|
||||
func _ready():
|
||||
# Workaround below fixes the problem of instanced nodes "sharing" exported arrays (and resources inside them)
|
||||
# When instanced in the editor
|
||||
# See https://github.com/godotengine/godot/issues/16478
|
||||
# This fix is needed, so we can have multiple instances of same terrain with same plant placement
|
||||
# But have LOD switch independently for each of these terrains
|
||||
if octree_managers == null:
|
||||
octree_managers = []
|
||||
else:
|
||||
var octree_managers_copy = octree_managers.duplicate()
|
||||
octree_managers = []
|
||||
for octree_manager in octree_managers_copy:
|
||||
octree_managers.append(octree_manager.duplicate_tree())
|
||||
|
||||
logger = Logger.get_for(self, name)
|
||||
|
||||
owner = get_tree().get_edited_scene_root()
|
||||
|
||||
MMI_container = get_node_or_null("MMI_container")
|
||||
if MMI_container && !is_instance_of(MMI_container, Node3D):
|
||||
remove_child(MMI_container)
|
||||
MMI_container.queue_free()
|
||||
MMI_container = null
|
||||
if !MMI_container:
|
||||
FunLib.free_children(self)
|
||||
MMI_container = Node3D.new()
|
||||
MMI_container.name = "MMI_container"
|
||||
add_child(MMI_container)
|
||||
|
||||
MMI_container.owner = owner
|
||||
|
||||
for octree_manager in octree_managers:
|
||||
octree_manager.restore_after_load(MMI_container)
|
||||
|
||||
|
||||
func _enter_tree():
|
||||
pass
|
||||
# thread_instance_placement = Thread.new()
|
||||
# mutex_placement = Mutex.new()
|
||||
# semaphore_instance_placement = Semaphore.new()
|
||||
#
|
||||
# exit_instance_placement = false
|
||||
# done_instance_placement = true
|
||||
#
|
||||
# thread_instance_placement.start(Callable(self,"thread_update_LODs"))
|
||||
|
||||
|
||||
func _notification(what):
|
||||
match what:
|
||||
NOTIFICATION_PREDELETE:
|
||||
for octree_manager in octree_managers:
|
||||
octree_manager.free_refs()
|
||||
|
||||
|
||||
func _exit_tree():
|
||||
pass
|
||||
# This is... weird
|
||||
# Apparently I need to free any Resources that are left after closing a scene
|
||||
# I'm not exactly sure why
|
||||
# And it *might* be destructive to do so in editor
|
||||
#if Engine.is_editor_hint(): return
|
||||
#for octree_manager in octree_managers:
|
||||
#octree_manager.destroy()
|
||||
# mutex_placement.lock()
|
||||
# exit_instance_placement = true
|
||||
# done_instance_placement = false
|
||||
# mutex_placement.unlock()
|
||||
#
|
||||
# semaphore_instance_placement.post()
|
||||
# thread_instance_placement.wait_to_finish()
|
||||
#
|
||||
# thread_instance_placement = null
|
||||
# mutex_placement = null
|
||||
# semaphore_instance_placement = null
|
||||
|
||||
|
||||
# Expected to be called inside or after a parent's _ready()
|
||||
func setup(plant_states):
|
||||
verify_all_plants(plant_states)
|
||||
|
||||
|
||||
# Restore all OctreeManager objects after load
|
||||
# Create missing ones
|
||||
func verify_all_plants(plant_states_to_verify:Array):
|
||||
if !is_inside_tree(): return
|
||||
debug_print_lifecycle("verifying for plant_states: " + str(plant_states_to_verify))
|
||||
|
||||
for plant_index in range(0, plant_states_to_verify.size()):
|
||||
if octree_managers.size() - 1 >= plant_index:
|
||||
octree_managers[plant_index].restore_after_load(MMI_container)
|
||||
connect_octree_manager(octree_managers[plant_index])
|
||||
else:
|
||||
add_plant_octree_manager(plant_states_to_verify[plant_index], plant_index)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Management of plant OctreeManager objects
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Instigate the OctreeManager adding process in response to an external signal
|
||||
func on_plant_added(plant_state, plant_index:int):
|
||||
debug_print_lifecycle("plant: %s added at plant_index %d" % [str(plant_state), plant_index])
|
||||
add_plant_octree_manager(plant_state, plant_index)
|
||||
request_debug_redraw_from_index(plant_index)
|
||||
call_deferred("emit_member_count", plant_index)
|
||||
|
||||
|
||||
# Instigate the OctreeManager removal process in response to an external signal
|
||||
func on_plant_removed(plant_state, plant_index:int):
|
||||
debug_print_lifecycle("plant: %s removed at plant_index %d" % [str(plant_state), plant_index])
|
||||
remove_plant_octree_manager(plant_state, plant_index)
|
||||
request_debug_redraw_from_index(plant_index)
|
||||
|
||||
|
||||
# Up-to-date LOD variants of an OctreeManager
|
||||
func on_LOD_variant_added(plant_index:int, mesh_index:int, LOD_variant):
|
||||
debug_print_lifecycle("LOD Variant: %s added at plant_index %d and mesh_index %d" % [str(LOD_variant), plant_index, mesh_index])
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.insert_LOD_variant(LOD_variant, mesh_index)
|
||||
octree_manager.set_LODs_to_active_index()
|
||||
|
||||
|
||||
# Up-to-date LOD variants of an OctreeManager
|
||||
func on_LOD_variant_removed(plant_index:int, mesh_index:int):
|
||||
debug_print_lifecycle("LOD Variant: removed at plant_index %d and mesh_index %d" % [plant_index, mesh_index])
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.remove_LOD_variant(mesh_index)
|
||||
octree_manager.set_LODs_to_active_index()
|
||||
|
||||
|
||||
# Up-to-date LOD variants of an OctreeManager
|
||||
func on_LOD_variant_set(plant_index:int, mesh_index:int, LOD_variant):
|
||||
debug_print_lifecycle("LOD Variant: %s set at plant_index %d and mesh_index %d" % [str(LOD_variant), plant_index, mesh_index])
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.set_LOD_variant(LOD_variant, mesh_index)
|
||||
octree_manager.set_LODs_to_active_index()
|
||||
|
||||
|
||||
# Up-to-date LOD variants of an OctreeManager
|
||||
func on_LOD_variant_prop_changed_spawned_spatial(plant_index:int, mesh_index:int, LOD_variant):
|
||||
debug_print_lifecycle("LOD Variant: %s spawned spatial changed at plant_index %d and mesh_index %d" % [str(LOD_variant), plant_index, mesh_index])
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.set_LOD_variant_spawned_spatial(LOD_variant, mesh_index)
|
||||
octree_manager.reset_member_spatials()
|
||||
|
||||
|
||||
# Make sure LODs in OctreeNodes correspond to their active_LOD_index
|
||||
# This is the preffered way to 'refresh' MMIs inside OctreeNodes
|
||||
func set_LODs_to_active_index(plant_index:int):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.set_LODs_to_active_index()
|
||||
|
||||
|
||||
# Initialize an OctreeManager for a given plant
|
||||
func add_plant_octree_manager(plant_state, plant_index:int):
|
||||
var octree_manager:MMIOctreeManager = MMIOctreeManager.new()
|
||||
octree_manager.init_octree(
|
||||
plant_state.plant.mesh_LOD_max_capacity, plant_state.plant.mesh_LOD_min_size,
|
||||
Vector3.ZERO, MMI_container, plant_state.plant.mesh_LOD_min_size)
|
||||
octree_manager.LOD_max_distance = plant_state.plant.mesh_LOD_max_distance
|
||||
octree_manager.LOD_kill_distance = plant_state.plant.mesh_LOD_kill_distance
|
||||
octree_managers.insert(plant_index, octree_manager)
|
||||
|
||||
for mesh_index in range (0, plant_state.plant.mesh_LOD_variants.size()):
|
||||
var LOD_variant = plant_state.plant.mesh_LOD_variants[mesh_index]
|
||||
octree_manager.insert_LOD_variant(LOD_variant, mesh_index)
|
||||
connect_octree_manager(octree_manager)
|
||||
|
||||
|
||||
# Remove an OctreeManager for a given plant
|
||||
func remove_plant_octree_manager(plant_state, plant_index:int):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
disconnect_octree_manager(octree_manager)
|
||||
octree_manager.prepare_for_removal()
|
||||
octree_managers.remove_at(plant_index)
|
||||
|
||||
|
||||
# A request to reconfigure an octree
|
||||
func reconfigure_octree(plant_state, plant_index:int):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.rebuild_octree(plant_state.plant.mesh_LOD_max_capacity, plant_state.plant.mesh_LOD_min_size)
|
||||
|
||||
|
||||
# A request to recenter an octree
|
||||
func recenter_octree(plant_state, plant_index:int):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.recenter_octree()
|
||||
|
||||
|
||||
# Connect all OctreeManager signals
|
||||
func connect_octree_manager(octree_manager:MMIOctreeManager):
|
||||
if !octree_manager.req_debug_redraw.is_connected(on_req_debug_redraw):
|
||||
octree_manager.req_debug_redraw.connect(on_req_debug_redraw.bind(octree_manager))
|
||||
|
||||
|
||||
# Disconnect all OctreeManager signals
|
||||
func disconnect_octree_manager(octree_manager:MMIOctreeManager):
|
||||
if octree_manager.req_debug_redraw.is_connected(on_req_debug_redraw):
|
||||
octree_manager.req_debug_redraw.disconnect(on_req_debug_redraw)
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Setting/updating variables to outside signals
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# To be called by a signal from Greenhouse_PlantState -> Gardener -> Arborist
|
||||
func update_plant_LOD_max_distance(plant_index, val):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.LOD_max_distance = val
|
||||
|
||||
|
||||
# To be called by a signal from Greenhouse_PlantState -> Gardener -> Arborist
|
||||
func update_plant_LOD_kill_distance(plant_index, val):
|
||||
var octree_manager:MMIOctreeManager = octree_managers[plant_index]
|
||||
octree_manager.LOD_kill_distance = val
|
||||
|
||||
|
||||
# To be called by a signal from Gardener -> Arborist
|
||||
func set_gardening_collision_mask(_gardening_collision_mask):
|
||||
gardening_collision_mask = _gardening_collision_mask
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Application of brushes and transform generation
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Create PaintingChanges and a StrokeHandler for this specific brush stroke
|
||||
func on_stroke_started(brush:Toolshed_Brush, plant_states:Array):
|
||||
var space_state := get_world_3d().direct_space_state
|
||||
var camera = get_camera_3d()
|
||||
active_painting_changes = PaintingChanges.new()
|
||||
match brush.behavior_brush_type:
|
||||
brush.BrushType.PAINT:
|
||||
active_stroke_handler = SH_Paint.new(brush, plant_states, octree_managers, space_state, camera, gardening_collision_mask)
|
||||
brush.BrushType.ERASE:
|
||||
active_stroke_handler = SH_Erase.new(brush, plant_states, octree_managers, space_state, camera, gardening_collision_mask)
|
||||
brush.BrushType.SINGLE:
|
||||
active_stroke_handler = SH_Single.new(brush, plant_states, octree_managers, space_state, camera, gardening_collision_mask)
|
||||
brush.BrushType.REAPPLY:
|
||||
active_stroke_handler = SH_Reapply.new(brush, plant_states, octree_managers, space_state, camera, gardening_collision_mask)
|
||||
_:
|
||||
active_stroke_handler = StrokeHandler.new(brush, plant_states, octree_managers, space_state, camera, gardening_collision_mask)
|
||||
|
||||
debug_print_lifecycle("Stroke %s started" % [active_stroke_handler.get_meta("class")])
|
||||
|
||||
|
||||
# Draw instances at the new brush position
|
||||
# And collect them all into one PaintingChanges object
|
||||
func on_stroke_updated(brush_data:Dictionary):
|
||||
assert(active_stroke_handler)
|
||||
assert(active_painting_changes)
|
||||
|
||||
debug_print_lifecycle("Stroke %s updating..." % [active_stroke_handler.get_meta("class")])
|
||||
var msec_start = FunLib.get_msec()
|
||||
|
||||
# mutex_placement.lock()
|
||||
var changes = active_stroke_handler.get_stroke_update_changes(brush_data, global_transform)
|
||||
apply_stroke_update_changes(changes)
|
||||
# mutex_placement.unlock()
|
||||
active_painting_changes.append_changes(changes)
|
||||
|
||||
var msec_end = FunLib.get_msec()
|
||||
debug_print_lifecycle("Total stroke %s update took: %s" % [active_stroke_handler.get_meta("class"), FunLib.msec_to_time(msec_end - msec_start)])
|
||||
|
||||
|
||||
# Use collected PaintingChanges to add UndoRedo actions
|
||||
func on_stroke_finished():
|
||||
assert(active_stroke_handler)
|
||||
assert(active_painting_changes)
|
||||
|
||||
UndoRedoInterface.create_action(_undo_redo, "Apply Arborist MMI changes", 0, false, self)
|
||||
UndoRedoInterface.add_do_method(_undo_redo, _action_apply_changes.bind(active_painting_changes))
|
||||
UndoRedoInterface.add_undo_method(_undo_redo, _action_apply_changes.bind(active_painting_changes.pop_opposite()))
|
||||
|
||||
# We toggle this flag to avoid reapplying already commited changes all over again
|
||||
UndoRedoInterface.commit_action(_undo_redo, false)
|
||||
|
||||
debug_print_lifecycle("Stroke %s finished, total changes made: %d" % [active_stroke_handler.get_meta("class"), active_painting_changes.changes.size()])
|
||||
|
||||
active_stroke_handler = null
|
||||
active_painting_changes = null
|
||||
|
||||
|
||||
# A wrapper for applying changes to avoid reaplying UndoRedo actions on commit_action()
|
||||
func _action_apply_changes(changes):
|
||||
# mutex_placement.lock()
|
||||
apply_stroke_update_changes(changes)
|
||||
# mutex_placement.unlock()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Updating OctreeManager objects
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Replace LOD_Variants inside of a shared array owned by this OctreeManager
|
||||
func refresh_octree_shared_LOD_variants(plant_index:int, LOD_variants:Array):
|
||||
if octree_managers.size() > plant_index:
|
||||
octree_managers[plant_index].set_LOD_variants(LOD_variants)
|
||||
|
||||
|
||||
# Add changes to corresponding OctreeManager queues
|
||||
# Then process them all at once
|
||||
func apply_stroke_update_changes(changes:PaintingChanges):
|
||||
debug_print_lifecycle(" Applying %d stroke changes" % [changes.changes.size()])
|
||||
var msec_start = FunLib.get_msec()
|
||||
|
||||
var affected_octree_managers := []
|
||||
|
||||
for change in changes.changes:
|
||||
var octree_manager:MMIOctreeManager = octree_managers[change.at_index]
|
||||
|
||||
match change.change_type:
|
||||
0:
|
||||
octree_manager.queue_placeforms_add(change.new_val)
|
||||
1:
|
||||
octree_manager.queue_placeforms_remove(change.new_val)
|
||||
2:
|
||||
octree_manager.queue_placeforms_set(change.new_val)
|
||||
|
||||
if !affected_octree_managers.has(change.at_index):
|
||||
affected_octree_managers.append(change.at_index)
|
||||
|
||||
for index in affected_octree_managers:
|
||||
var octree_manager = octree_managers[index]
|
||||
octree_manager.process_queues()
|
||||
emit_member_count(index)
|
||||
|
||||
var msec_end = FunLib.get_msec()
|
||||
debug_print_lifecycle(" Applying stroke changes took: %s" % [FunLib.msec_to_time(msec_end - msec_start)])
|
||||
|
||||
|
||||
func emit_member_count(octree_index:int):
|
||||
member_count_updated.emit(octree_index, octree_managers[octree_index].root_octree_node.get_nested_member_count())
|
||||
|
||||
|
||||
func _process(delta):
|
||||
# try_update_LODs()
|
||||
if visible:
|
||||
update_LODs()
|
||||
request_debug_redraw()
|
||||
|
||||
|
||||
# Trigger a threaded LOD update
|
||||
#func try_update_LODs():
|
||||
# var should_post = false
|
||||
#
|
||||
# mutex_placement.lock()
|
||||
# if done_instance_placement:
|
||||
# done_instance_placement = false
|
||||
# should_post = true
|
||||
# mutex_placement.unlock()
|
||||
#
|
||||
# if should_post:
|
||||
# semaphore_instance_placement.post()
|
||||
|
||||
|
||||
# A function that carries out threaded LOD updates
|
||||
#func thread_update_LODs(arg = null):
|
||||
# while true:
|
||||
# semaphore_instance_placement.wait()
|
||||
#
|
||||
# var should_exit = false
|
||||
# mutex_placement.lock()
|
||||
# if exit_instance_placement:
|
||||
# should_exit = true
|
||||
# mutex_placement.unlock()
|
||||
# if should_exit: break
|
||||
#
|
||||
# mutex_placement.lock()
|
||||
# update_LODs()
|
||||
# done_instance_placement = true
|
||||
# mutex_placement.unlock()
|
||||
|
||||
|
||||
# Instigate LOD updates in OctreeManager objects
|
||||
func update_LODs():
|
||||
var camera_to_use:Camera3D = get_camera_3d()
|
||||
if camera_to_use:
|
||||
var camera_pos := camera_to_use.global_transform.origin
|
||||
for octree_manager in octree_managers:
|
||||
octree_manager.update_LODs(camera_pos, global_transform)
|
||||
# This exists to properly render instances in editor even if there is no forwarded_input()
|
||||
else:
|
||||
for octree_manager in octree_managers:
|
||||
octree_manager.update_LODs_no_camera()
|
||||
|
||||
|
||||
# Add instances as a batch (mostly, as a result of importing Greenhouse data)
|
||||
func batch_add_instances(placeforms: Array, plant_idx: int):
|
||||
active_painting_changes = PaintingChanges.new()
|
||||
active_stroke_handler = SH_Manual.new()
|
||||
|
||||
for placeform in placeforms:
|
||||
active_stroke_handler.add_instance_placeform(placeform, plant_idx, active_painting_changes)
|
||||
|
||||
apply_stroke_update_changes(active_painting_changes)
|
||||
on_stroke_finished()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Input
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _unhandled_input(event):
|
||||
if is_instance_of(event, InputEventKey) && !event.pressed:
|
||||
if event.keycode == debug_get_dump_tree_key():
|
||||
for octree_manager in octree_managers:
|
||||
logger.info(octree_manager.root_octree_node.debug_dump_tree())
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Utility
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# A hack to get editor camera
|
||||
# active_camera_override should be set by a Gardener
|
||||
# In-game just gets an active viewport's camera
|
||||
func get_camera_3d():
|
||||
if is_instance_valid(active_camera_override):
|
||||
return active_camera_override
|
||||
else:
|
||||
active_camera_override = null
|
||||
return get_viewport().get_camera_3d()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Property export
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
func _get(property):
|
||||
match property:
|
||||
"octree_managers":
|
||||
return octree_managers
|
||||
return null
|
||||
|
||||
|
||||
func _set(property, val):
|
||||
var return_val = true
|
||||
|
||||
match property:
|
||||
"octree_managers":
|
||||
octree_managers = val
|
||||
_:
|
||||
return_val = false
|
||||
|
||||
return return_val
|
||||
|
||||
|
||||
func _get_property_list():
|
||||
var props := [
|
||||
{
|
||||
"name": "octree_managers",
|
||||
"type": TYPE_ARRAY,
|
||||
"usage": PROPERTY_USAGE_DEFAULT,
|
||||
"hint": PROPERTY_HINT_NONE
|
||||
},
|
||||
]
|
||||
return props
|
||||
|
||||
|
||||
func _get_configuration_warnings():
|
||||
var MMI_container_check = get_node("MMI_container")
|
||||
if MMI_container_check && is_instance_of(MMI_container_check, Node3D):
|
||||
return ""
|
||||
else:
|
||||
return "Arborist is missing a valid MMI_container child\nSince it should be created automatically, try reloading a scene or recreating a Gardener"
|
||||
|
||||
|
||||
func add_child(node:Node, legible_unique_name:bool = false, internal:InternalMode=0) -> void:
|
||||
super.add_child(node, legible_unique_name)
|
||||
update_configuration_warnings()
|
||||
|
||||
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Debug
|
||||
#-------------------------------------------------------------------------------
|
||||
|
||||
|
||||
# A wrapper to request debug redraw for a specific OctreeManager
|
||||
func request_debug_redraw_from_index(plant_index):
|
||||
for index in range(plant_index, octree_managers.size()):
|
||||
on_req_debug_redraw(octree_managers[index])
|
||||
|
||||
|
||||
# Add an OctreeManager to the debug redraw waiting list
|
||||
func on_req_debug_redraw(octree_manager:MMIOctreeManager):
|
||||
if debug_redraw_requested_managers.has(octree_manager): return
|
||||
debug_redraw_requested_managers.append(octree_manager)
|
||||
|
||||
|
||||
# Request a debug redraw for all OctreeManager objects in a waiting list using a signal
|
||||
# We manually get all indexes here instead of when an OctreeManager is added to the waiting list
|
||||
# Because we expect the order of managers might change and indexes will become inaccurate
|
||||
# Typically called from _process()
|
||||
func request_debug_redraw():
|
||||
if debug_redraw_requested_managers.is_empty(): return
|
||||
|
||||
var requested_indexes := []
|
||||
for octree_manager in debug_redraw_requested_managers:
|
||||
requested_indexes.append(octree_managers.find(octree_manager))
|
||||
|
||||
if !requested_indexes.is_empty():
|
||||
req_debug_redraw.emit(octree_managers)
|
||||
debug_redraw_requested_managers = []
|
||||
|
||||
|
||||
func debug_get_dump_tree_key():
|
||||
var key = FunLib.get_setting_safe("dreadpons_spatial_gardener/debug/dump_all_octrees_key", 0)
|
||||
return Globals.index_to_enum(key, Globals.KeyboardKey)
|
||||
|
||||
|
||||
func debug_print_lifecycle(string:String):
|
||||
if !FunLib.get_setting_safe("dreadpons_spatial_gardener/debug/arborist_log_lifecycle", false): return
|
||||
logger.info(string)
|
||||
Reference in New Issue
Block a user