z_mirror/PipeVisualizer
git clone https://git.raiguard.me/z_mirror/PipeVisualizer
eb997d6
main
1local flib_bounding_box =require ( "__flib__.bounding-box" ) 2local flib_math =require ( "__flib__.math" ) 3local flib_position =require ( "__flib__.position" ) 4local flib_queue =require ( "__flib__.queue" ) 5 6--- @alias RenderObjectID uint64 7 8local function reset () 9rendering . clear ( script . mod_name ) 10--- @type Queue<RenderObjectID> 11global . render_objects =flib_queue . new () 12end 13 14--- @param id RenderObjectID 15local function clear_sprite ( id ) 16if not rendering . is_valid ( id ) then 17return 18end 19rendering . set_visible ( id , false ) 20flib_queue . push_back ( global . render_objects , id ) 21end 22 23--- @param args LuaRendering.draw_sprite_param 24--- @return RenderObjectID 25local function draw_sprite ( args ) 26--- @type RenderObjectID? 27local id 28repeat 29id =flib_queue . pop_front ( global . render_objects ) 30until not id or rendering . is_valid ( id ) and rendering . get_surface ( id ). index == args . surface 31 32if not id then 33return rendering . draw_sprite ( args ) 34end 35 36rendering . set_sprite ( id , args . sprite ) 37rendering . set_color ( id , args . tint ) 38rendering . set_x_scale ( id , args . x_scale or 1 ) 39rendering . set_y_scale ( id , args . y_scale or 1 ) 40rendering . set_render_layer ( id , args . render_layer ) 41rendering . set_orientation ( id , args . orientation or 0 ) 42rendering . set_target ( id , args . target ) 43rendering . set_players ( id , args . players ) 44rendering . set_visible ( id , true ) 45 46return id 47end 48 49local layers ={ 50arrow ="195" , 51line ="194" , 52underground ="193" , 53entity ="192" , 54} 55 56local pipe_types ={ 57[ "infinity-pipe" ] =true , 58[ "pipe-to-ground" ] =true , 59[ "pipe" ] =true , 60} 61 62local encoded_directions ={ 63[ defines . direction . north ] =1 , 64[ defines . direction . east ] =2 , 65[ defines . direction . south ] =4 , 66[ defines . direction . west ] =8 , 67} 68 69--- @type Color 70local default_color ={ r =0.4 , g =0.4 , b =0.4 } 71--- @type FluidSystemData 72local default_fluid_system ={ color =default_color , from_hover =false , order =flib_math . max_uint } 73 74local renderer ={} 75 76--- @param it Iterator 77--- @param entity_data EntityData 78function renderer . draw ( it , entity_data ) 79local is_complex_type =not pipe_types [ entity_data . entity . type ] 80if is_complex_type then 81local box =flib_bounding_box . resize ( entity_data . entity . selection_box , - 0.1 ) 82entity_data . shape =draw_sprite ( { 83sprite ="pv-entity-box" , 84tint =default_color , 85x_scale =flib_bounding_box . width ( box ), 86y_scale =flib_bounding_box . height ( box ), 87render_layer =layers . entity , 88target =flib_bounding_box . center ( box ), 89surface =entity_data . entity . surface_index , 90players ={ it . player_index } , 91} ) 92else 93local box =flib_bounding_box . ceil ( entity_data . entity . selection_box ) 94entity_data . shape =draw_sprite ( { 95sprite ="pv-pipe-connections-0" , 96tint =default_color , 97x_scale =flib_bounding_box . width ( box ), 98y_scale =flib_bounding_box . height ( box ), 99render_layer =layers . line , 100target =entity_data . entity . position , 101surface =entity_data . entity . surface_index , 102players ={ it . player_index } , 103} ) 104end 105local shape_fluid_system =default_fluid_system 106local encoded_connections =0 107for fluid_system_id , connections in pairs ( entity_data . connections ) do 108local fluid_system_data =it . systems [ fluid_system_id ] 109if not fluid_system_data then 110goto continue 111end 112if fluid_system_data . order < shape_fluid_system . order then 113shape_fluid_system =fluid_system_data 114end 115local objects =entity_data . connection_objects [ fluid_system_id ] 116if not objects then 117objects ={} 118entity_data . connection_objects [ fluid_system_id ] =objects 119end 120for _ , connection in pairs ( connections ) do 121if not connection . target then 122goto inner_continue 123end 124 125local direction =connection . direction 126if is_complex_type then 127if connection . flow_direction == "input" then 128direction =( direction + 4 ) % 8 -- Opposite 129end 130local sprite ="pv-fluid-arrow-" .. connection . flow_direction 131if connection . flow_direction ~= "input-output" and not pipe_types [ connection . target_owner . type ] then 132sprite ="pv-fluid-arrow" 133end 134objects [ # objects + 1 ] =draw_sprite ( { 135sprite =sprite , 136tint =fluid_system_data . color , 137render_layer =layers . arrow , 138orientation =direction / 8 , 139target =connection . shape_position , 140surface =entity_data . entity . surface_index , 141players ={ it . player_index } , 142} ) 143else 144encoded_connections =bit32 . bor ( encoded_connections , encoded_directions [ direction ]) 145end 146 147if connection . connection_type == "underground" then 148local target_data =it . entities [ 149connection . target_owner . unit_number --[[@as uint]] 150] 151if not target_data then 152goto inner_continue 153end 154local target_fluid_system_connections =target_data . connections [ fluid_system_id ] 155if not target_fluid_system_connections then 156goto inner_continue 157end 158local target_connection_data =target_fluid_system_connections [ connection . target_pipe_connection_index ] 159 160local target_position =target_connection_data . position 161local distance =flib_position . distance ( connection . position , target_connection_data . position ) 162for i =1 , distance - 1 do 163local target =flib_position . lerp ( connection . position , target_position , i / distance ) 164objects [ # objects + 1 ] =draw_sprite ( { 165sprite ="pv-underground-connection" , 166tint =fluid_system_data . color , 167render_layer =layers . underground , 168orientation =direction / 8 , 169target =target , 170surface =entity_data . entity . surface_index , 171players ={ it . player_index } , 172} ) 173end 174end 175 176:: inner_continue :: 177end 178 179:: continue :: 180end 181if entity_data . shape then 182rendering . set_color ( entity_data . shape , shape_fluid_system . color ) 183if encoded_connections > 0 then 184rendering . set_sprite ( entity_data . shape , "pv-pipe-connections-" .. encoded_connections ) 185end 186end 187end 188 189--- @param entity_data EntityData 190function renderer . clear ( entity_data ) 191clear_sprite ( entity_data . shape ) 192entity_data . shape =nil 193for _ , objects in pairs ( entity_data . connection_objects ) do 194for _ , id in pairs ( objects ) do 195clear_sprite ( id ) 196end 197end 198entity_data . connection_objects ={} 199end 200 201--- @param iterator Iterator 202--- @param entity_data EntityData 203--- @param fluid_system_id FluidSystemID 204--- @return boolean should_remove 205function renderer . clear_system ( iterator , entity_data , fluid_system_id ) 206local objects =entity_data . connection_objects [ fluid_system_id ] 207if objects then 208for _ , id in pairs ( objects ) do 209clear_sprite ( id ) 210end 211entity_data . connection_objects [ fluid_system_id ] =nil 212end 213local should_remove =not next ( entity_data . connection_objects ) 214if should_remove then 215clear_sprite ( entity_data . shape ) 216entity_data . shape =nil 217else 218renderer . update_shape_color ( iterator , entity_data ) 219end 220return should_remove 221end 222 223--- @param iterator Iterator 224--- @param entity_data EntityData 225function renderer . update_shape_color ( iterator , entity_data ) 226--- @type FluidSystemData 227local shape_fluid_system ={ color =default_color , from_hover =false , order =flib_math . max_uint } 228for fluid_system_id in pairs ( entity_data . connection_objects ) do 229local fluid_system_data =iterator . systems [ fluid_system_id ] 230if fluid_system_data and fluid_system_data . order < shape_fluid_system . order then 231shape_fluid_system =fluid_system_data 232end 233end 234rendering . set_color ( entity_data . shape , shape_fluid_system . color ) 235end 236 237renderer . on_init =reset 238renderer . on_configuration_changed =reset 239 240renderer . reset =reset 241 242return renderer