11# Blender FLIP Fluids Add-on
2- # Copyright (C) 2024 Ryan L. Guy
2+ # Copyright (C) 2025 Ryan L. Guy & Dennis Fassbaender
33#
44# This program is free software: you can redistribute it and/or modify
55# it under the terms of the GNU General Public License as published by
@@ -617,6 +617,15 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos
617617 source_id_data_file = os .path .join (d , autosave_info ['marker_particle_source_id_filedata' ])
618618 load_source_id_data = True
619619
620+ is_uid_attribute_enabled = data .domain_data .particles .enable_fluid_particle_uid_attribute .data
621+ load_uid_data = False
622+ if is_uid_attribute_enabled :
623+ uid_path = 'marker_particle_uid_filedata'
624+ is_uid_data_available = (uid_path in autosave_info ) and autosave_info [uid_path ]
625+ if is_uid_data_available :
626+ uid_data_file = os .path .join (d , autosave_info ['marker_particle_uid_filedata' ])
627+ load_uid_data = True
628+
620629 is_viscosity_attribute_enabled = data .domain_data .surface .enable_viscosity_attribute .data
621630 load_viscosity_data = False
622631 if is_viscosity_attribute_enabled :
@@ -639,20 +648,24 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos
639648 bytes_per_vector = 12
640649 bytes_per_float = 4
641650 bytes_per_int = 4
651+ bytes_per_ulong_long_int = 8
642652 bytes_per_short = 2
643653 max_vector_byte = bytes_per_vector * num_particles
644654 max_float_byte = bytes_per_float * num_particles
645655 max_int_byte = bytes_per_int * num_particles
656+ max_ulong_long_int_byte = bytes_per_ulong_long_int * num_particles
646657 max_short_byte = bytes_per_short * num_particles
647658 num_reads = int ((num_particles // particles_per_read ) + 1 )
648659 for i in range (num_reads ):
649660 start_vector_byte = i * bytes_per_vector * particles_per_read
650661 start_float_byte = i * bytes_per_float * particles_per_read
651662 start_int_byte = i * bytes_per_int * particles_per_read
663+ start_ulong_long_int_byte = i * bytes_per_ulong_long_int * particles_per_read
652664 start_short_byte = i * bytes_per_short * particles_per_read
653665 end_vector_byte = min ((i + 1 ) * bytes_per_vector * particles_per_read , max_vector_byte )
654666 end_float_byte = min ((i + 1 ) * bytes_per_float * particles_per_read , max_float_byte )
655667 end_int_byte = min ((i + 1 ) * bytes_per_int * particles_per_read , max_int_byte )
668+ end_ulong_long_int_byte = min ((i + 1 ) * bytes_per_ulong_long_int * particles_per_read , max_ulong_long_int_byte )
656669 end_short_byte = min ((i + 1 ) * bytes_per_short * particles_per_read , max_short_byte )
657670 particle_count = int ((end_vector_byte - start_vector_byte ) // bytes_per_vector )
658671
@@ -682,6 +695,10 @@ def __load_save_state_marker_particle_data(fluidsim, save_state_directory, autos
682695 source_id_data = __read_save_state_file_data (source_id_data_file , start_int_byte , end_int_byte )
683696 fluidsim .load_marker_particle_source_id_data (particle_count , source_id_data )
684697
698+ if load_uid_data :
699+ uid_data = __read_save_state_file_data (uid_data_file , start_int_byte , end_int_byte )
700+ fluidsim .load_marker_particle_uid_data (particle_count , uid_data )
701+
685702 if load_viscosity_data :
686703 viscosity_data = __read_save_state_file_data (viscosity_data_file , start_float_byte , end_float_byte )
687704 fluidsim .load_marker_particle_viscosity_data (particle_count , viscosity_data )
@@ -742,6 +759,10 @@ def __load_save_state_simulator_data(fluidsim, autosave_info):
742759 next_frame = autosave_info ["frame_id" ] + 1
743760 fluidsim .set_current_frame (next_frame )
744761
762+ if "current_fluid_particle_uid" in autosave_info :
763+ current_uid = int (autosave_info ["current_fluid_particle_uid" ])
764+ fluidsim .set_current_fluid_particle_uid (current_uid )
765+
745766
746767def __delete_outdated_savestates (cache_directory , savestate_id ):
747768 savestate_directory = os .path .join (cache_directory , "savestates" )
@@ -1151,6 +1172,12 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
11511172 enable_source_id_attribute = __get_parameter_data (particles .enable_fluid_particle_source_id_attribute , frameno )
11521173 fluidsim .enable_fluid_particle_source_id_attribute = enable_source_id_attribute
11531174
1175+ enable_uid_attribute = __get_parameter_data (particles .enable_fluid_particle_uid_attribute , frameno )
1176+ fluidsim .enable_fluid_particle_uid_attribute = enable_uid_attribute
1177+
1178+ reused_uid_attribute = __get_parameter_data (particles .enable_fluid_particle_uid_attribute_reuse , frameno )
1179+ fluidsim .enable_fluid_particle_uid_attribute_reuse = reused_uid_attribute
1180+
11541181 # Surface Settings
11551182
11561183 surface = dprops .surface
@@ -1184,10 +1211,11 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
11841211 meshing_offset = __get_obstacle_meshing_offset (meshing_mode )
11851212 fluidsim .obstacle_meshing_offset = meshing_offset
11861213
1187- fluidsim .enable_remove_surface_near_domain = \
1188- __get_parameter_data (surface .remove_mesh_near_domain , frameno )
1189- fluidsim .remove_surface_near_domain_distance = \
1190- __get_parameter_data (surface .remove_mesh_near_domain_distance , frameno ) - 1
1214+ fluidsim .enable_remove_surface_near_domain = __get_parameter_data (surface .remove_mesh_near_domain , frameno )
1215+ fluidsim .remove_surface_near_domain_distance = __get_parameter_data (surface .remove_mesh_near_domain_distance , frameno ) - 1
1216+
1217+ domain_sides = __get_parameter_data (surface .remove_mesh_near_domain_sides , frameno )
1218+ fluidsim .remove_surface_near_domain_sides = domain_sides
11911219
11921220 fluidsim .enable_inverted_contact_normals = \
11931221 __get_parameter_data (surface .invert_contact_normals , frameno )
@@ -1239,8 +1267,7 @@ def __initialize_fluid_simulation_settings(fluidsim, data):
12391267 else :
12401268 fluidsim .enable_mixbox = False
12411269
1242- fluidsim .enable_surface_source_id_attribute = \
1243- __get_parameter_data (surface .enable_source_id_attribute , frameno )
1270+ fluidsim .enable_surface_source_id_attribute = __get_parameter_data (surface .enable_source_id_attribute , frameno )
12441271
12451272 is_viscosity_enabled = __get_parameter_data (world .enable_viscosity , frameno )
12461273 if is_viscosity_enabled :
@@ -2146,6 +2173,9 @@ def __update_animatable_domain_properties(fluidsim, data, frameno):
21462173 __set_property (fluidsim , 'enable_remove_surface_near_domain' , remove_near_domain )
21472174 __set_property (fluidsim , 'remove_surface_near_domain_distance' , near_domain_distance )
21482175
2176+ domain_sides = __get_parameter_data (surface .remove_mesh_near_domain_sides , frameno )
2177+ __set_property (fluidsim , 'remove_surface_near_domain_sides' , domain_sides )
2178+
21492179 invert_contact = __get_parameter_data (surface .invert_contact_normals , frameno )
21502180 __set_property (fluidsim , 'enable_inverted_contact_normals' , invert_contact )
21512181
@@ -2588,6 +2618,19 @@ def __write_fluid_particle_data(cache_directory, fluidsim, frameno):
25882618 with open (source_id_filepath , 'wb' ) as f :
25892619 f .write (filedata )
25902620
2621+ if fluidsim .enable_fluid_particle_uid_attribute :
2622+ uid_filename = "fluidparticlesuid" + fstring + ".ffp3"
2623+ uid_filepath = os .path .join (cache_directory , "bakefiles" , uid_filename )
2624+ filedata = fluidsim .get_fluid_particle_uid_attribute_data ()
2625+ with open (uid_filepath , 'wb' ) as f :
2626+ f .write (filedata )
2627+
2628+ uid_max_filename = "fluidparticlesuidmax" + fstring + ".txt"
2629+ uid_max_filepath = os .path .join (cache_directory , "bakefiles" , uid_max_filename )
2630+ max_uid_value = fluidsim .get_current_fluid_particle_uid () - 1
2631+ with open (uid_max_filepath , 'w' ) as f :
2632+ f .write (str (max_uid_value ))
2633+
25912634
25922635def __write_fluid_particle_debug_data (cache_directory , fluidsim , frameno ):
25932636 fstring = __frame_number_to_string (frameno )
@@ -2701,6 +2744,7 @@ def __get_frame_stats_dict(cstats):
27012744 stats ["dustlifetime" ] = __get_mesh_stats_dict (cstats .dustlifetime )
27022745 stats ["fluidparticles" ] = __get_mesh_stats_dict (cstats .fluidparticles )
27032746 stats ["fluidparticlesid" ] = __get_mesh_stats_dict (cstats .fluidparticlesid )
2747+ stats ["fluidparticlesuid" ] = __get_mesh_stats_dict (cstats .fluidparticlesuid )
27042748 stats ["fluidparticlesvelocity" ] = __get_mesh_stats_dict (cstats .fluidparticlesvelocity )
27052749 stats ["fluidparticlesspeed" ] = __get_mesh_stats_dict (cstats .fluidparticlesspeed )
27062750 stats ["fluidparticlesvorticity" ] = __get_mesh_stats_dict (cstats .fluidparticlesvorticity )
@@ -2745,6 +2789,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
27452789 lifetime_data_path = os .path .join (autosave_dir , "marker_particle_lifetime.data" )
27462790 color_data_path = os .path .join (autosave_dir , "marker_particle_color.data" )
27472791 source_id_data_path = os .path .join (autosave_dir , "marker_particle_source_id.data" )
2792+ uid_data_path = os .path .join (autosave_dir , "marker_particle_uid.data" )
27482793 viscosity_data_path = os .path .join (autosave_dir , "marker_particle_viscosity.data" )
27492794 id_data_path = os .path .join (autosave_dir , "marker_particle_id.data" )
27502795
@@ -2778,6 +2823,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
27782823 autosave_source_id_filepaths = [
27792824 source_id_data_path
27802825 ]
2826+ autosave_uid_filepaths = [
2827+ uid_data_path
2828+ ]
27812829 autosave_viscosity_filepaths = [
27822830 viscosity_data_path
27832831 ]
@@ -2831,6 +2879,10 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
28312879 data = fluidsim .get_marker_particle_source_id_data_range (start_idx , end_idx )
28322880 __write_save_state_file_data (source_id_data_path + temp_extension , data , is_appending_data = is_appending )
28332881
2882+ if fluidsim .enable_fluid_particle_uid_attribute :
2883+ data = fluidsim .get_marker_particle_uid_data_range (start_idx , end_idx )
2884+ __write_save_state_file_data (uid_data_path + temp_extension , data , is_appending_data = is_appending )
2885+
28342886 if fluidsim .enable_surface_viscosity_attribute :
28352887 data = fluidsim .get_marker_particle_viscosity_data_range (start_idx , end_idx )
28362888 __write_save_state_file_data (viscosity_data_path + temp_extension , data , is_appending_data = is_appending )
@@ -2873,6 +2925,8 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
28732925 autosave_info ['frame_id' ] = fluidsim .get_current_frame () - 1
28742926 autosave_info ['last_frame_id' ] = frame_end - frame_start
28752927 autosave_info ['num_marker_particles' ] = fluidsim .get_num_marker_particles ()
2928+ autosave_info ['current_fluid_particle_uid' ] = str (fluidsim .get_current_fluid_particle_uid ())
2929+
28762930 autosave_info ['marker_particle_position_filedata' ] = "marker_particle_position.data"
28772931 autosave_info ['marker_particle_velocity_filedata' ] = "marker_particle_velocity.data"
28782932 autosave_info ['num_diffuse_particles' ] = fluidsim .get_num_diffuse_particles ()
@@ -2885,6 +2939,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
28852939 autosave_info ['marker_particle_lifetime_filedata' ] = ""
28862940 autosave_info ['marker_particle_color_filedata' ] = ""
28872941 autosave_info ['marker_particle_source_id_filedata' ] = ""
2942+ autosave_info ['marker_particle_uid_filedata' ] = ""
28882943 autosave_info ['marker_particle_viscosity_filedata' ] = ""
28892944 autosave_info ['marker_particle_id_filedata' ] = ""
28902945
@@ -2911,6 +2966,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
29112966 if fluidsim .enable_surface_source_id_attribute or fluidsim .enable_fluid_particle_source_id_attribute :
29122967 autosave_info ['marker_particle_source_id_filedata' ] = "marker_particle_source_id.data"
29132968
2969+ if fluidsim .enable_fluid_particle_uid_attribute :
2970+ autosave_info ['marker_particle_uid_filedata' ] = "marker_particle_uid.data"
2971+
29142972 if fluidsim .enable_surface_viscosity_attribute :
29152973 autosave_info ['marker_particle_viscosity_filedata' ] = "marker_particle_viscosity.data"
29162974
@@ -2942,6 +3000,7 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
29423000 autosave_lifetime_filepaths +
29433001 autosave_color_filepaths +
29443002 autosave_source_id_filepaths +
3003+ autosave_uid_filepaths +
29453004 autosave_viscosity_filepaths +
29463005 autosave_id_filepaths +
29473006 autosave_diffuse_filepaths
@@ -2973,6 +3032,9 @@ def __write_autosave_data(domain_data, cache_directory, fluidsim, frameno):
29733032 if fluidsim .enable_surface_source_id_attribute or fluidsim .enable_fluid_particle_source_id_attribute :
29743033 for filepath in autosave_source_id_filepaths :
29753034 os .rename (filepath + temp_extension , filepath )
3035+ if fluidsim .enable_fluid_particle_uid_attribute :
3036+ for filepath in autosave_uid_filepaths :
3037+ os .rename (filepath + temp_extension , filepath )
29763038 if fluidsim .enable_surface_viscosity_attribute :
29773039 for filepath in autosave_viscosity_filepaths :
29783040 os .rename (filepath + temp_extension , filepath )
0 commit comments