z_mirror/EditorExtensions
git clone https://git.raiguard.me/z_mirror/EditorExtensions
626d2b5
hidden-items
1local format =require ( "__flib__/format" ) 2local gui =require ( "__flib__/gui-lite" ) 3local math =require ( "__flib__/math" ) 4local table =require ( "__flib__/table" ) 5 6local shared_constants =require ( "__EditorExtensions__/shared-constants" ) 7 8local util =require ( "__EditorExtensions__/scripts/util" ) 9 10local crafter_snapping_types ={ 11[ "assembling-machine" ] =true , 12[ "furnace" ] =true , 13[ "rocket-silo" ] =true , 14} 15 16--- @alias InfinityPipeMode 17--- | "at-least", 18--- | "at-most", 19--- | "exactly", 20--- | "add", 21--- | "remove", 22 23--- @type table<string, uint> 24local defines_amount_type ={ 25percent =1 , 26units =2 , 27} 28 29--- @param entity LuaEntity 30--- @param amount_type uint? 31local function store_amount_type ( entity , amount_type ) 32global . infinity_pipe_amount_type [ entity . unit_number ] =amount_type 33end 34 35--- @param entity LuaEntity 36--- @return uint? 37local function get_stored_amount_type ( entity ) 38return global . infinity_pipe_amount_type [ entity . unit_number ] 39end 40 41--- @param entity LuaEntity 42--- @return uint? 43local function remove_stored_amount_type ( entity ) 44local value =global . infinity_pipe_amount_type [ entity . unit_number ] 45global . infinity_pipe_amount_type [ entity . unit_number ] =nil 46return value 47end 48 49--- @param entity LuaEntity 50--- @param new_capacity double 51--- @return LuaEntity? 52local function swap_entity ( entity , new_capacity ) 53local amount_type =remove_stored_amount_type ( entity ) 54local new_entity =entity . surface . create_entity ( { 55name ="ee-infinity-pipe-" .. new_capacity , 56position =entity . position , 57direction =entity . direction , 58force =entity . force , 59fast_replace =true , 60create_build_effect_smoke =false , 61spill =false , 62} ) 63if not new_entity then 64return 65end 66store_amount_type ( new_entity , amount_type ) 67return new_entity 68end 69 70--- @param entity BlueprintEntity|LuaEntity 71local function check_is_our_pipe ( entity ) 72return string . find ( entity . name , "^ee%-infinity%-pipe%-%d+$" ) 73end 74 75--- @param entity LuaEntity 76local function snap ( entity ) 77local own_id =entity . unit_number 78for _ , fluidbox in pairs ( entity . fluidbox . get_connections ( 1 )) do 79if crafter_snapping_types [ fluidbox . owner . type ] then 80for i =1 , # fluidbox do 81--- @cast i uint 82local connections =fluidbox . get_connections ( i ) 83local prototype =fluidbox . get_prototype ( i ) 84for j =1 , # connections do 85if prototype . production_type == "input" and connections [ j ]. owner . unit_number == own_id then 86local fluid =fluidbox . get_locked_fluid ( i ) 87if fluid then 88entity . set_infinity_pipe_filter ( { name =fluid , percentage =1 , mode ="at-least" } ) 89return 90end 91end 92end 93end 94end 95end 96end 97 98--- @param filter InfinityPipeFilter? 99--- @return double, double 100local function get_temperature_limits ( filter ) 101if filter and filter . name then 102local prototype =game . fluid_prototypes [ filter . name ] 103return prototype . default_temperature , prototype . max_temperature 104end 105return 0 , 100 106end 107 108-- GUI 109 110--- @class InfinityPipeGui 111--- @field elems InfinityPipeGuiElems 112--- @field entity LuaEntity 113--- @field mode InfinityPipeMode 114--- @field player LuaPlayer 115--- @field temperature double 116 117--- @class InfinityPipeGuiElems 118--- @field ee_infinity_pipe_window LuaGuiElement 119--- @field titlebar_flow LuaGuiElement 120--- @field drag_handle LuaGuiElement 121--- @field capacity_dropdown LuaGuiElement 122--- @field amount_progressbar LuaGuiElement 123--- @field entity_preview LuaGuiElement 124--- @field filter_button LuaGuiElement 125--- @field amount_slider LuaGuiElement 126--- @field amount_textfield LuaGuiElement 127--- @field amount_type_dropdown LuaGuiElement 128--- @field mode_radio_button_at_least LuaGuiElement 129--- @field mode_radio_button_at_most LuaGuiElement 130--- @field mode_radio_button_exactly LuaGuiElement 131--- @field mode_radio_button_add LuaGuiElement 132--- @field mode_radio_button_remove LuaGuiElement 133--- @field temperature_slider LuaGuiElement 134--- @field temperature_textfield LuaGuiElement 135 136--- @param player_index uint 137local function destroy_gui ( player_index ) 138local self =global . infinity_pipe_gui [ player_index ] 139if not self then 140return 141end 142global . infinity_pipe_gui [ player_index ] =nil 143local window =self . elems . ee_infinity_pipe_window 144if window . valid then 145window . destroy () 146end 147end 148 149--- @param self InfinityPipeGui 150local function update_fluid_content_bar ( self ) 151local bar =self . elems . amount_progressbar 152local fluidbox =self . entity . fluidbox 153local capacity =fluidbox . get_capacity ( 1 ) 154local content =fluidbox [ 1 ] or { amount =0 } 155 156local caption 157if content . amount < 100 then 158caption =string . format ( "%.1f" , content . amount ) 159else 160caption =format . number ( math . floor ( content . amount )) 161end 162bar . caption =caption 163bar . value =content . amount / capacity 164 165if not content . name then 166return 167end 168 169local bar_color =game . fluid_prototypes [ content . name ]. base_color 170-- Calculate luminance of the background color 171-- Source: https://stackoverflow.com/questions/596216/formula-to-determine-perceived-brightness-of-rgb-color 172local luminance =( 0.2126 * bar_color . r ) + ( 0.7152 * bar_color . g ) + ( 0.0722 * bar_color . b ) 173if luminance > 0.55 then 174bar . style ="ee_infinity_pipe_progressbar" 175else 176bar . style ="ee_infinity_pipe_progressbar_light_text" 177end 178bar . style . color =bar_color 179end 180 181--- @param self InfinityPipeGui 182--- @param new_entity LuaEntity? 183--- @param reset_temperature boolean? 184local function update_gui ( self , new_entity , reset_temperature ) 185if not new_entity and not self . entity . valid then 186destroy_gui ( self . player . index ) 187return 188end 189local elems =self . elems 190if new_entity then 191elems . entity_preview . entity =new_entity 192self . entity =new_entity 193end 194local entity =self . entity 195local filter =entity . get_infinity_pipe_filter () or {} 196if filter . mode then 197self . mode =filter . mode 198end 199if filter . temperature then 200self . temperature =filter . temperature 201elseif reset_temperature then 202self . temperature =0 203end 204 205local capacity =entity . fluidbox . get_capacity ( 1 ) 206elems . capacity_dropdown . selected_index =table . find ( shared_constants . infinity_pipe_capacities , capacity ) --[[@as uint]] 207 208elems . filter_button . elem_value =filter . name 209 210local amount_type =get_stored_amount_type ( entity ) or 1 211elems . amount_slider . slider_value =filter . percentage or 0 212elems . amount_textfield . style ="ee_slider_textfield" 213local percentage =filter . percentage or 0 214if amount_type == defines_amount_type . percent then 215elems . amount_textfield . text =tostring ( math . floor ( percentage * 100 )) 216else 217elems . amount_textfield . text =tostring ( math . floor ( percentage * capacity )) 218end 219elems . amount_type_dropdown . selected_index =amount_type 220 221local mode =self . mode 222elems . mode_radio_button_at_least . state =mode == "at-least" 223elems . mode_radio_button_at_most . state =mode == "at-most" 224elems . mode_radio_button_exactly . state =mode == "exactly" 225elems . mode_radio_button_add . state =mode == "add" 226elems . mode_radio_button_remove . state =mode == "remove" 227 228local min , max =get_temperature_limits ( filter ) 229if min == max then 230elems . temperature_slider . enabled =false 231elems . temperature_textfield . enabled =false 232elems . temperature_slider . set_slider_minimum_maximum ( min , max + 1 ) 233elems . temperature_slider . slider_value =min 234else 235elems . temperature_slider . enabled =true 236elems . temperature_textfield . enabled =true 237elems . temperature_slider . set_slider_minimum_maximum ( min , max ) 238elems . temperature_slider . slider_value =self . temperature 239end 240elems . temperature_textfield . style ="ee_slider_textfield" 241elems . temperature_textfield . text =tostring ( self . temperature ) 242 243update_fluid_content_bar ( self ) 244end 245 246--- @param entity LuaEntity 247--- @param reset_temperature boolean? 248local function update_all_guis ( entity , reset_temperature ) 249for _ , gui in pairs ( global . infinity_pipe_gui ) do 250if not gui . entity . valid then 251update_gui ( gui , entity , reset_temperature ) 252elseif gui . entity == entity then 253update_gui ( gui , nil , reset_temperature ) 254end 255end 256end 257 258local handlers ={ 259--- @param self InfinityPipeGui 260--- @param e EventData.on_gui_closed|EventData.on_gui_click 261on_ip_gui_closed =function ( self , e ) 262destroy_gui ( e . player_index ) 263local player =self . player 264if not player . valid then 265return 266end 267player . play_sound ( { path ="entity-close/ee-infinity-accumulator-tertiary-buffer" } ) 268end , 269 270--- @param self InfinityPipeGui 271--- @param e EventData.on_gui_selection_state_changed 272on_ip_gui_capacity_dropdown_selection_state_changed =function ( self , e ) 273local entity =self . entity 274local new_capacity =shared_constants . infinity_pipe_capacities [ e . element . selected_index ] 275if new_capacity == entity . fluidbox . get_capacity ( 1 ) then 276return 277end 278local new_entity =swap_entity ( entity , new_capacity ) 279if not new_entity then 280return 281end 282update_all_guis ( new_entity ) 283end , 284 285--- @param self InfinityPipeGui 286--- @param e EventData.on_gui_elem_changed 287on_ip_gui_filter_changed =function ( self , e ) 288local entity =self . entity 289local elem =e . element . elem_value --[[@as string?]] 290if elem then 291if not filter then 292filter ={ mode =self . mode , percentage =1 } 293end 294filter . name =elem 295entity . set_infinity_pipe_filter ( filter ) 296else 297entity . set_infinity_pipe_filter ( nil ) 298end 299update_all_guis ( entity , not elem ) 300end , 301 302--- @param self InfinityPipeGui 303--- @param e EventData.on_gui_elem_changed 304on_ip_gui_amount_slider_value_changed =function ( self , e ) 305local entity =self . entity 306local value =e . element . slider_value 307local filter =entity . get_infinity_pipe_filter () 308if not filter then 309-- Textfield should always match slider 310local textfield =self . elems . amount_textfield 311textfield . style ="ee_slider_textfield" 312textfield . text =tostring ( math . floor ( value * 100 )) 313return 314end 315filter . percentage =value 316entity . set_infinity_pipe_filter ( filter ) 317update_all_guis ( entity ) 318end , 319 320--- @param self InfinityPipeGui 321--- @param e EventData.on_gui_text_changed 322on_ip_gui_amount_textfield_changed =function ( self , e ) 323local entity =self . entity 324local textfield =e . element 325local text =textfield . text 326local value =tonumber ( text ) 327local max =100 328local amount_type =get_stored_amount_type ( entity ) 329if amount_type == defines_amount_type . units then 330max =entity . fluidbox . get_capacity ( 1 ) 331end 332if not value or value < 0 or value > max then 333textfield . style ="ee_invalid_slider_textfield" 334return 335end 336textfield . style ="ee_slider_textfield" 337 338local percentage =value / 100 339if amount_type == defines_amount_type . units then 340local capacity =entity . fluidbox . get_capacity ( 1 ) 341percentage =value / capacity 342end 343 344self . elems . amount_slider . slider_value =percentage 345 346local filter =entity . get_infinity_pipe_filter () 347if filter then 348filter . percentage =percentage 349entity . set_infinity_pipe_filter ( filter ) 350update_all_guis ( entity ) 351end 352end , 353 354--- @param self InfinityPipeGui 355--- @param e EventData.on_gui_selection_state_changed 356on_ip_gui_amount_type_changed =function ( self , e ) 357local amount_type =e . element . selected_index 358store_amount_type ( self . entity , amount_type ) 359update_all_guis ( self . entity ) 360end , 361 362--- @param self InfinityPipeGui 363--- @param e EventData.on_gui_checked_state_changed 364on_ip_gui_mode_radio_button_selected =function ( self , e ) 365local mode =e . element . tags . mode --[[@as string]] 366self . mode =mode 367 368local entity =self . entity 369local filter =entity . get_infinity_pipe_filter () 370if filter then 371filter . mode =mode 372entity . set_infinity_pipe_filter ( filter ) 373end 374 375update_all_guis ( entity ) 376end , 377 378--- @param self InfinityPipeGui 379--- @param e EventData.on_gui_value_changed 380on_ip_gui_temperature_slider_value_changed =function ( self , e ) 381local entity =self . entity 382local value =math . floor ( e . element . slider_value ) 383local filter =entity . get_infinity_pipe_filter () 384if not filter then 385-- Textfield should always match slider 386local textfield =self . elems . temperature_textfield 387textfield . style ="ee_slider_textfield" 388textfield . text =tostring ( value ) 389return 390end 391filter . temperature =value 392entity . set_infinity_pipe_filter ( filter ) 393update_all_guis ( entity ) 394end , 395 396--- @param self InfinityPipeGui 397--- @param e EventData.on_gui_text_changed 398on_ip_gui_temperature_textfield_changed =function ( self , e ) 399local entity =self . entity 400local textfield =e . element 401local text =textfield . text 402local value =tonumber ( text ) 403 404local filter =entity . get_infinity_pipe_filter () 405local min , max =get_temperature_limits ( filter ) 406 407if not value or value < min or value > max then 408textfield . style ="ee_invalid_slider_textfield" 409return 410end 411textfield . style ="ee_slider_textfield" 412 413self . elems . temperature_slider . slider_value =value 414 415if filter then 416filter . temperature =value 417entity . set_infinity_pipe_filter ( filter ) 418update_all_guis ( entity ) 419end 420end , 421} 422 423gui . add_handlers ( handlers , function ( e , handler ) 424local self =global . infinity_pipe_gui [ e . player_index ] 425if not self then 426return 427end 428if not self . entity . valid then 429return 430end 431handler ( self , e ) 432end ) 433 434--- @param player LuaPlayer 435--- @param entity LuaEntity 436local function create_gui ( player , entity ) 437destroy_gui ( player . index ) 438 439--- @type InfinityPipeGuiElems 440local elems =gui . add ( player . gui . screen , { 441type ="frame" , 442name ="ee_infinity_pipe_window" , 443direction ="vertical" , 444elem_mods ={ auto_center =true } , 445handler ={ [ defines . events . on_gui_closed ] =handlers . on_ip_gui_closed } , 446{ 447type ="flow" , 448name ="titlebar_flow" , 449style ="flib_titlebar_flow" , 450drag_target ="ee_infinity_pipe_window" , 451{ 452type ="label" , 453style ="frame_title" , 454caption ={ "entity-name.ee-infinity-pipe" } , 455ignored_by_interaction =true , 456} , 457{ type ="empty-widget" , style ="flib_titlebar_drag_handle" , ignored_by_interaction =true } , 458util . close_button ( handlers . on_ip_gui_closed ), 459} , 460{ 461type ="frame" , 462style ="entity_frame" , 463direction ="vertical" , 464{ 465type ="frame" , 466style ="deep_frame_in_shallow_frame" , 467style_mods ={ bottom_margin =4 } , 468{ 469type ="entity-preview" , 470name ="entity_preview" , 471style ="wide_entity_button" , 472elem_mods ={ entity =entity } , 473} , 474} , 475{ 476type ="flow" , 477style_mods ={ horizontal_spacing =8 , vertical_align ="center" } , 478{ 479type ="progressbar" , 480name ="amount_progressbar" , 481style ="ee_infinity_pipe_progressbar" , 482} , 483{ type ="label" , caption ="/" } , 484{ 485type ="drop-down" , 486name ="capacity_dropdown" , 487items =table . map ( shared_constants . infinity_pipe_capacities , function ( capacity ) 488return format . number ( capacity ) 489end ), 490selected_index =0 , 491handler ={ 492[ defines . events . on_gui_selection_state_changed ] =handlers . on_ip_gui_capacity_dropdown_selection_state_changed , 493} , 494} , 495} , 496{ type ="line" , direction ="horizontal" } , 497{ 498type ="flow" , 499style ="centering_horizontal_flow" , 500direction ="horizontal" , 501{ 502type ="choose-elem-button" , 503name ="filter_button" , 504style ="flib_standalone_slot_button_default" , 505elem_type ="fluid" , 506handler ={ [ defines . events . on_gui_elem_changed ] =handlers . on_ip_gui_filter_changed } , 507} , 508{ 509type ="slider" , 510name ="amount_slider" , 511style_mods ={ horizontally_stretchable =true , margin ={ 0 , 8 , 0 , 8 } } , 512minimum_value =0 , 513maximum_value =1 , 514value_step =0.01 , 515value =0 , 516handler ={ [ defines . events . on_gui_value_changed ] =handlers . on_ip_gui_amount_slider_value_changed } , 517} , 518{ 519type ="textfield" , 520name ="amount_textfield" , 521style ="slider_value_textfield" , 522numeric =true , 523allow_decimal =true , 524clear_and_focus_on_right_click =true , 525text ="0" , 526handler ={ [ defines . events . on_gui_text_changed ] =handlers . on_ip_gui_amount_textfield_changed } , 527} , 528{ 529type ="drop-down" , 530name ="amount_type_dropdown" , 531style_mods ={ width =55 } , 532items ={ { "gui-infinity-pipe.percent" } , { "gui-infinity-pipe.ee-units" } } , 533selected_index =1 , 534handler ={ [ defines . events . on_gui_selection_state_changed ] =handlers . on_ip_gui_amount_type_changed } , 535} , 536} , 537{ 538type ="flow" , 539style_mods ={ horizontal_spacing =0 } , 540direction ="horizontal" , 541util . mode_radio_button ( "at-least" , handlers . on_ip_gui_mode_radio_button_selected ), 542util . pusher (), 543util . mode_radio_button ( "at-most" , handlers . on_ip_gui_mode_radio_button_selected ), 544util . pusher (), 545util . mode_radio_button ( "exactly" , handlers . on_ip_gui_mode_radio_button_selected ), 546util . pusher (), 547util . mode_radio_button ( "add" , handlers . on_ip_gui_mode_radio_button_selected ), 548util . pusher (), 549util . mode_radio_button ( "remove" , handlers . on_ip_gui_mode_radio_button_selected ), 550} , 551{ type ="line" , direction ="horizontal" } , 552{ 553type ="flow" , 554style ="centering_horizontal_flow" , 555direction ="horizontal" , 556{ type ="label" , caption ={ "gui-infinity-pipe.temperature" } } , 557{ 558type ="slider" , 559name ="temperature_slider" , 560style_mods ={ horizontally_stretchable =true , margin ={ 0 , 8 , 0 , 8 } } , 561minimum_value =0 , 562maximum_value =100 , 563value =0 , 564handler ={ 565[ defines . events . on_gui_value_changed ] =handlers . on_ip_gui_temperature_slider_value_changed , 566} , 567} , 568{ 569type ="textfield" , 570name ="temperature_textfield" , 571style ="slider_value_textfield" , 572clear_and_focus_on_right_click =true , 573text ="0" , 574handler ={ 575[ defines . events . on_gui_text_changed ] =handlers . on_ip_gui_temperature_textfield_changed , 576} , 577} , 578} , 579} , 580} ) 581 582player . opened =elems . ee_infinity_pipe_window 583 584--- @type InfinityPipeGui 585local self ={ 586elems =elems , 587entity =entity , 588mode ="at-least" , 589temperature =0 , 590player =player , 591} 592global . infinity_pipe_gui [ player . index ] =self 593 594update_gui ( self ) 595end 596 597-- COPY/PASTE 598 599--- @param pipe LuaEntity 600--- @param combinator LuaEntity 601local function copy_from_pipe_to_combinator ( pipe , combinator ) 602local filter =pipe . get_infinity_pipe_filter () 603if not filter then 604return 605end 606local cb =combinator . get_or_create_control_behavior () --[[@as LuaConstantCombinatorControlBehavior]] 607cb . set_signal ( 1 , { 608signal ={ type ="fluid" , name =filter . name } , 609count =1 , 610} ) 611update_all_guis ( pipe ) 612end 613 614--- @param combinator LuaEntity 615--- @param pipe LuaEntity 616local function copy_from_combinator_to_pipe ( combinator , pipe ) 617local cb =combinator . get_control_behavior () --[[@as LuaConstantCombinatorControlBehavior?]] 618if not cb then 619return 620end 621local signal =cb . get_signal ( 1 ) 622if signal . signal and signal . signal . type == "fluid" then 623pipe . set_infinity_pipe_filter ( { type ="fluid" , name =signal . signal . name , percentage =1 } ) 624else 625pipe . set_infinity_pipe_filter ( nil ) 626end 627update_all_guis ( pipe ) 628end 629 630--- @param source LuaEntity 631--- @param destination LuaEntity 632local function copy_from_pipe_to_pipe ( source , destination ) 633if source . name ~= destination . name then 634local new_destination =swap_entity ( destination , source . fluidbox . get_capacity ( 1 )) 635if not new_destination then 636return 637end 638destination =new_destination 639end 640local source_amount_type =get_stored_amount_type ( source ) 641local destination_amount_type =get_stored_amount_type ( destination ) 642if source_amount_type ~= destination_amount_type then 643store_amount_type ( destination , source_amount_type ) 644end 645update_all_guis ( destination ) 646end 647 648-- EVENTS 649 650--- @param e BuiltEvent 651local function on_entity_built ( e ) 652local entity =e . created_entity or e . entity or e . destination 653if not entity or not entity . valid or not check_is_our_pipe ( entity ) then 654return 655end 656 657local tags =e . tags 658if tags and tags . EditorExtensions then 659store_amount_type ( entity , tags . EditorExtensions . amount_type --[[@as uint]] ) 660end 661 662if e . name == defines . events . on_built_entity then 663snap ( entity ) 664end 665end 666 667--- @param e DestroyedEvent 668local function on_entity_destroyed ( e ) 669local entity =e . entity 670if not entity . valid or not check_is_our_pipe ( entity ) then 671return 672end 673remove_stored_amount_type ( e . entity ) 674end 675 676--- @param e EventData.on_gui_opened 677local function on_gui_opened ( e ) 678local entity =e . entity 679if not entity or not entity . valid or not check_is_our_pipe ( entity ) then 680return 681end 682local player =game . get_player ( e . player_index ) 683if not player then 684return 685end 686create_gui ( player , entity ) 687end 688 689--- @param e EventData.on_player_setup_blueprint 690local function on_player_setup_blueprint ( e ) 691local blueprint =util . get_blueprint ( e ) 692if not blueprint then 693return 694end 695 696local entities =blueprint . get_blueprint_entities () 697if not entities then 698return 699end 700for i , entity in pairs ( entities ) do 701--- @cast i uint 702if not check_is_our_pipe ( entity ) then 703goto continue 704end 705local real_entity =e . surface . find_entity ( entity . name , entity . position ) 706if not real_entity then 707goto continue 708end 709blueprint . set_blueprint_entity_tag ( 710i , 711"EditorExtensions" , 712{ amount_type =global . infinity_pipe_amount_type [ real_entity . unit_number ] } 713) 714:: continue :: 715end 716end 717 718--- @param e EventData.on_entity_settings_pasted 719local function on_entity_settings_pasted ( e ) 720local source , destination =e . source , e . destination 721local source_is_pipe , destination_is_pipe =check_is_our_pipe ( source ), check_is_our_pipe ( destination ) 722if source_is_pipe and destination . name == "constant-combinator" then 723copy_from_pipe_to_combinator ( source , destination ) 724elseif source . name == "constant-combinator" and destination_is_pipe then 725copy_from_combinator_to_pipe ( source , destination ) 726elseif source_is_pipe and destination_is_pipe then 727copy_from_pipe_to_pipe ( source , destination ) 728end 729end 730 731local infinity_pipe ={} 732 733infinity_pipe . on_init =function () 734global . infinity_pipe_gui ={} 735--- @type table<uint, uint> 736global . infinity_pipe_amount_type ={} 737end 738 739infinity_pipe . on_configuration_changed =function () 740for player_index in pairs ( game . players ) do 741destroy_gui ( player_index --[[@as uint]] ) 742end 743end 744 745infinity_pipe . events ={ 746[ defines . events . on_built_entity ] =on_entity_built , 747[ defines . events . on_entity_cloned ] =on_entity_built , 748[ defines . events . on_entity_died ] =on_entity_destroyed , 749[ defines . events . on_entity_settings_pasted ] =on_entity_settings_pasted , 750[ defines . events . on_gui_opened ] =on_gui_opened , 751[ defines . events . on_player_mined_entity ] =on_entity_destroyed , 752[ defines . events . on_player_setup_blueprint ] =on_player_setup_blueprint , 753[ defines . events . on_robot_built_entity ] =on_entity_built , 754[ defines . events . on_robot_mined_entity ] =on_entity_destroyed , 755[ defines . events . script_raised_built ] =on_entity_built , 756[ defines . events . script_raised_destroy ] =on_entity_destroyed , 757[ defines . events . script_raised_revive ] =on_entity_built , 758} 759 760infinity_pipe . on_nth_tick ={ 761[ 1 ] =function () 762for _ , gui in pairs ( global . infinity_pipe_gui ) do 763update_fluid_content_bar ( gui ) 764end 765end , 766} 767 768return infinity_pipe