z_mirror/PipeVisualizer
git clone https://git.raiguard.me/z_mirror/PipeVisualizer
9371b54
2.0
1local flib_bounding_box =require ( "__flib__/bounding-box" ) 2local flib_position =require ( "__flib__/position" ) 3 4--- @alias RenderObjectID uint64 5 6--- @param id RenderObjectID 7local function destroy_if_valid ( id ) 8if rendering . is_valid ( id ) then 9rendering . destroy ( id ) 10end 11end 12 13local layers ={ 14arrow ="195" , 15line ="194" , 16underground ="193" , 17entity ="192" , 18} 19 20local pipe_types ={ 21[ "infinity-pipe" ] =true , 22[ "pipe-to-ground" ] =true , 23[ "pipe" ] =true , 24} 25 26local encoded_directions ={ 27[ defines . direction . north ] =1 , 28[ defines . direction . east ] =2 , 29[ defines . direction . south ] =4 , 30[ defines . direction . west ] =8 , 31} 32 33--- @type Color 34local default_color ={ r =0.32 , g =0.32 , b =0.32 , a =0.4 } 35 36local renderer ={} 37 38--- @param it Iterator 39--- @param entity_data EntityData 40function renderer . draw ( it , entity_data ) 41local is_complex_type =not pipe_types [ entity_data . entity . type ] 42-- TODO: Build and cache boxes for all entities ahead of time 43if is_complex_type then 44local box =flib_bounding_box . resize ( entity_data . entity . selection_box , - 0.1 ) 45entity_data . shape =rendering . draw_sprite ( { 46sprite ="pv-entity-box" , 47tint =default_color , 48x_scale =flib_bounding_box . width ( box ), 49y_scale =flib_bounding_box . height ( box ), 50render_layer =layers . entity , 51target =entity_data . entity . position , 52surface =entity_data . entity . surface_index , 53players ={ it . player_index } , 54} ) 55else 56local box =flib_bounding_box . ceil ( entity_data . entity . selection_box ) 57entity_data . shape =rendering . draw_sprite ( { 58sprite ="pv-pipe-connections-0" , 59tint =default_color , 60x_scale =flib_bounding_box . width ( box ), 61y_scale =flib_bounding_box . height ( box ), 62render_layer =layers . line , 63target =entity_data . entity . position , 64surface =entity_data . entity . surface_index , 65players ={ it . player_index } , 66} ) 67end 68--- @type Color? 69local shape_color 70local highest_id =0 71local encoded_connections =0 72for id , connections in pairs ( entity_data . connections ) do 73local color =it . systems [ id ] 74if not color then 75goto continue 76end 77if id > highest_id then 78shape_color =color 79highest_id =id 80end 81local objects =entity_data . connection_objects [ id ] 82if not objects then 83objects ={} 84entity_data . connection_objects [ id ] =objects 85end 86for _ , connection in pairs ( connections ) do 87if not connection . target then 88goto inner_continue 89end 90 91local direction =connection . direction 92if is_complex_type then 93if connection . flow_direction == "input" then 94direction =( direction + 4 ) % 8 -- Opposite 95end 96local sprite ="pv-fluid-arrow-" .. connection . flow_direction 97if connection . flow_direction ~= "input-output" and not pipe_types [ connection . target_owner . type ] then 98sprite ="pv-fluid-arrow" 99end 100objects [ # objects + 1 ] =rendering . draw_sprite ( { 101sprite =sprite , 102tint =color , 103render_layer =layers . arrow , 104orientation =direction / 8 , 105target =connection . shape_position , 106surface =entity_data . entity . surface_index , 107players ={ it . player_index } , 108} ) 109else 110encoded_connections =bit32 . bor ( encoded_connections , encoded_directions [ direction ]) 111end 112 113-- TODO: Investigate using a beam entity to avoid making N render objects 114if connection . connection_type == "underground" then 115if it . entities [ connection . target_owner . unit_number ] then 116goto inner_continue 117end 118local target_connection_data = 119connection . target . get_pipe_connections ( connection . target_fluidbox_index )[ connection . target_pipe_connection_index ] 120local target_position =target_connection_data . position 121local distance =flib_position . distance ( connection . position , target_connection_data . position ) 122if distance > 1 then 123for i =1 , distance - 1 do 124local target =flib_position . lerp ( connection . position , target_position , i / distance ) 125objects [ # objects + 1 ] =rendering . draw_sprite ( { 126sprite ="pv-underground-connection" , 127tint =color , 128render_layer =layers . underground , 129orientation =direction / 8 , 130target =target , 131surface =entity_data . entity . surface_index , 132players ={ it . player_index } , 133} ) 134end 135break 136end 137end 138 139:: inner_continue :: 140end 141 142:: continue :: 143end 144if entity_data . shape and shape_color then 145rendering . set_color ( entity_data . shape , shape_color ) 146end 147if encoded_connections > 0 then 148rendering . set_sprite ( entity_data . shape , "pv-pipe-connections-" .. encoded_connections ) 149end 150end 151 152--- @param entity_data EntityData 153function renderer . clear ( entity_data ) 154destroy_if_valid ( entity_data . shape ) 155entity_data . shape =nil 156for _ , objects in pairs ( entity_data . connection_objects ) do 157for _ , id in pairs ( objects ) do 158destroy_if_valid ( id ) 159end 160end 161entity_data . connection_objects ={} 162end 163 164--- @param iterator Iterator 165--- @param entity_data EntityData 166--- @param fluid_system_id FluidSystemID 167--- @return boolean should_remove 168function renderer . clear_system ( iterator , entity_data , fluid_system_id ) 169local objects =entity_data . connection_objects [ fluid_system_id ] 170if objects then 171for _ , id in pairs ( objects ) do 172destroy_if_valid ( id ) 173end 174entity_data . connection_objects [ fluid_system_id ] =nil 175end 176local should_remove =not next ( entity_data . connection_objects ) 177if should_remove then 178destroy_if_valid ( entity_data . shape ) 179entity_data . shape =nil 180else 181renderer . update_shape_color ( iterator , entity_data ) 182end 183return should_remove 184end 185 186--- @param iterator Iterator 187--- @param entity_data EntityData 188function renderer . update_shape_color ( iterator , entity_data ) 189local highest_id =0 190for fluid_system_id in pairs ( entity_data . connection_objects ) do 191if fluid_system_id > highest_id then 192highest_id =fluid_system_id 193end 194end 195rendering . set_color ( entity_data . shape , highest_id > 0 and iterator . systems [ highest_id ] or default_color ) 196end 197 198return renderer