z_mirror/EditorExtensions
git clone https://git.raiguard.me/z_mirror/EditorExtensions
e65a4b6
Quezler/patch-1
1local gui =require ( "__flib__.gui" ) 2local math =require ( "__flib__.math" ) 3local table =require ( "__flib__.table" ) 4 5local util =require ( "scripts.util" ) 6 7local si_suffixes_joule ={ "kJ" , "MJ" , "GJ" , "TJ" , "PJ" , "EJ" , "ZJ" , "YJ" } 8local si_suffixes_watt ={ "kW" , "MW" , "GW" , "TW" , "PW" , "EW" , "ZW" , "YW" } 9 10--- @type InfinityAccumulatorMode[] 11local modes ={ "output" , "input" , "buffer" } 12--- @type InfinityAccumulatorPriority[] 13local priorities ={ "primary" , "secondary" , "tertiary" } 14 15local entity_names ={ 16[ "ee-infinity-accumulator-primary-input" ] =true , 17[ "ee-infinity-accumulator-primary-output" ] =true , 18[ "ee-infinity-accumulator-secondary-input" ] =true , 19[ "ee-infinity-accumulator-secondary-output" ] =true , 20[ "ee-infinity-accumulator-tertiary-buffer" ] =true , 21[ "ee-infinity-accumulator-tertiary-input" ] =true , 22[ "ee-infinity-accumulator-tertiary-output" ] =true , 23} 24 25--- @alias InfinityAccumulatorMode 26--- | "output" 27--- | "input" 28--- | "buffer" 29 30--- @alias InfinityAccumulatorPriority 31--- | "primary" 32--- | "secondary" 33--- | "tertiary" 34 35--- @param name string 36--- @return InfinityAccumulatorPriority, InfinityAccumulatorMode 37local function get_settings_from_name ( name ) 38local priority , mode =string . match ( name , "^ee%-infinity%-accumulator%-(%a+)%-(%a+)$" ) 39return priority , mode 40end 41 42--- @param entity LuaEntity 43--- @param mode string 44--- @param buffer_size double? 45local function set_entity_settings ( entity , mode , buffer_size ) 46local watts =util . parse_energy (( buffer_size * 60 ) .. "W" ) 47 48if mode == "output" then 49entity . power_production =watts 50entity . power_usage =0 51entity . electric_buffer_size =buffer_size 52elseif mode == "input" then 53entity . power_production =0 54entity . power_usage =watts 55entity . electric_buffer_size =buffer_size 56elseif mode == "buffer" then 57entity . power_production =0 58entity . power_usage =0 59entity . electric_buffer_size =buffer_size * 60 60end 61end 62 63--- @param entity LuaEntity 64--- @param priority string 65--- @param mode string 66--- @return LuaEntity? 67local function change_entity ( entity , priority , mode ) 68local new_entity =entity . surface . create_entity ( { 69name ="ee-infinity-accumulator-" .. priority .. "-" .. mode , 70position =entity . position , 71force =entity . force , 72last_user =entity . last_user , 73create_build_effect_smoke =false , 74} ) 75if not new_entity then 76return 77end 78 79-- Calculate new buffer size 80local buffer_size =entity . electric_buffer_size 81local _ , old_mode =get_settings_from_name ( entity . name ) 82if old_mode ~= mode and old_mode == "buffer" then 83-- coming from buffer, divide by 60 84buffer_size =buffer_size / 60 85end 86 87set_entity_settings ( new_entity , mode , buffer_size ) 88entity . destroy () 89 90return new_entity 91end 92 93--- Returns the power_slider value and dropdown selected index based on the entity's buffer size 94--- @param buffer_size double 95--- @param mode InfinityAccumulatorMode 96--- @return uint, uint 97local function get_slider_values ( buffer_size , mode ) 98if mode ~= "buffer" then 99-- The power_slider is controlling watts, so inflate the buffer size by 60x to get that value 100buffer_size =buffer_size * 60 101end 102-- Determine how many orders of magnitude there are 103local len =string . len ( string . format ( "%.0f" , math . floor ( buffer_size ))) 104-- `power` is the dropdown value - how many sets of three orders of magnitude there are, rounded down 105local power =math . floor (( len - 1 ) / 3 ) 106-- Slider value is the buffer size scaled to its base-three order of magnitude 107return buffer_size / 10 ^ ( power * 3 ), --[[@as uint]] 108math . max ( power , 1 ) --[[@as uint]] 109end 110 111--- Returns the entity buffer size based on the power_slider value and dropdown selected index 112local function calc_buffer_size ( slider_value , dropdown_index ) 113return util . parse_energy ( slider_value .. si_suffixes_joule [ dropdown_index ]) / 60 114end 115 116--- @param player_index uint 117local function destroy_gui ( player_index ) 118local self =storage . infinity_accumulator_gui [ player_index ] 119if not self then 120return 121end 122storage . infinity_accumulator_gui [ player_index ] =nil 123local window =self . elems . ee_infinity_accumulator_window 124if not window . valid then 125return 126end 127window . destroy () 128end 129 130--- @param self InfinityAccumulatorGui 131--- @param new_entity LuaEntity? 132local function update_gui ( self , new_entity ) 133if not new_entity and not self . entity . valid then 134destroy_gui ( self . player . index ) 135return 136end 137if new_entity then 138self . elems . entity_preview . entity =new_entity 139self . entity =new_entity 140end 141 142local entity =self . entity 143local priority , mode =get_settings_from_name ( entity . name ) 144 145local mode_dropdown =self . elems . mode_dropdown 146mode_dropdown . selected_index =table . find ( modes , mode ) --[[@as uint]] 147 148local priority_dropdown =self . elems . priority_dropdown 149priority_dropdown . selected_index =table . find ( priorities , priority ) --[[@as uint]] 150priority_dropdown . enabled =mode ~= "buffer" 151 152local slider_value , dropdown_index =get_slider_values ( entity . electric_buffer_size , mode ) 153 154local power_slider =self . elems . power_slider 155power_slider . slider_value =slider_value 156local textfield =self . elems . power_textfield 157textfield . text =tostring ( slider_value ) 158local dropdown =self . elems . power_dropdown 159if mode == "buffer" then 160dropdown . items =si_suffixes_joule 161else 162dropdown . items =si_suffixes_watt 163end 164dropdown . selected_index =dropdown_index 165end 166 167--- @param entity LuaEntity 168local function update_all_guis ( entity ) 169for _ , gui in pairs ( storage . infinity_accumulator_gui ) do 170if not gui . entity . valid or gui . entity == entity then 171update_gui ( gui , entity ) 172end 173end 174end 175 176local handlers ={ 177--- @param self InfinityAccumulatorGui 178--- @param e EventData.on_gui_closed|EventData.on_gui_click 179on_ia_gui_closed =function ( self , e ) 180destroy_gui ( e . player_index ) 181local player =self . player 182if not player . valid then 183return 184end 185player . play_sound ( { path ="entity-close/ee-infinity-accumulator-tertiary-buffer" } ) 186end , 187 188--- @param self InfinityAccumulatorGui 189--- @param e EventData.on_gui_selection_state_changed 190on_ia_gui_mode_dropdown_changed =function ( self , e ) 191local entity =self . entity 192local mode =modes [ e . element . selected_index ] 193local priority ="tertiary" 194if mode ~= "buffer" then 195priority =get_settings_from_name ( entity . name ) 196end 197local new_entity =change_entity ( entity , priority , mode ) 198if not new_entity then 199return 200end 201update_all_guis ( new_entity ) 202end , 203 204--- @param self InfinityAccumulatorGui 205--- @param e EventData.on_gui_selection_state_changed 206on_ia_gui_priority_dropdown_changed =function ( self , e ) 207local entity =self . entity 208local priority =priorities [ e . element . selected_index ] 209local _ , mode =get_settings_from_name ( entity . name ) 210local new_entity =change_entity ( entity , priority , mode ) 211if not new_entity then 212return 213end 214update_all_guis ( new_entity ) 215end , 216 217--- @param self InfinityAccumulatorGui 218--- @param e EventData.on_gui_selection_state_changed 219on_ia_gui_power_slider_changed =function ( self , e ) 220local entity =self . entity 221local slider_value =e . element . slider_value 222local dropdown_index =self . elems . power_dropdown . selected_index 223local buffer_size =calc_buffer_size ( slider_value , dropdown_index ) 224local _ , mode =get_settings_from_name ( entity . name ) 225set_entity_settings ( entity , mode , buffer_size ) 226update_all_guis ( entity ) 227end , 228 229--- @param self InfinityAccumulatorGui 230--- @param e EventData.on_gui_text_changed 231on_ia_gui_power_textfield_changed =function ( self , e ) 232local entity =self . entity 233local textfield =e . element 234local text =textfield . text 235local value =tonumber ( text ) 236if not value or value < 0 or value >= 1000 then 237textfield . style ="ee_invalid_slider_textfield" 238return 239end 240textfield . style ="ee_slider_textfield" 241if string . sub ( text , # text ) == "." then 242return 243end 244 245self . elems . power_slider . slider_value =value 246 247local _ , mode =get_settings_from_name ( entity . name ) 248local buffer_size =calc_buffer_size ( value , self . elems . power_dropdown . selected_index ) 249set_entity_settings ( entity , mode , buffer_size ) 250update_all_guis ( entity ) 251end , 252 253--- @param self InfinityAccumulatorGui 254--- @param e EventData.on_gui_selection_state_changed 255on_ia_gui_power_dropdown_changed =function ( self , e ) 256local entity =self . entity 257local _ , mode =get_settings_from_name ( entity . name ) 258local buffer_size =calc_buffer_size ( self . elems . power_slider . slider_value , e . element . selected_index ) 259set_entity_settings ( entity , mode , buffer_size ) 260update_all_guis ( entity ) 261end , 262} 263 264gui . add_handlers ( handlers , function ( e , handler ) 265local self =storage . infinity_accumulator_gui [ e . player_index ] 266if not self then 267return 268end 269if not self . entity . valid then 270return 271end 272 273handler ( self , e ) 274end ) 275 276--- @param player LuaPlayer 277--- @param entity LuaEntity 278local function create_gui ( player , entity ) 279destroy_gui ( player . index ) 280 281local elems =gui . add ( player . gui . screen , { 282type ="frame" , 283name ="ee_infinity_accumulator_window" , 284direction ="vertical" , 285elem_mods ={ auto_center =true } , 286handler ={ [ defines . events . on_gui_closed ] =handlers . on_ia_gui_closed } , 287{ 288type ="flow" , 289style ="flib_titlebar_flow" , 290drag_target ="ee_infinity_accumulator_window" , 291{ 292type ="label" , 293style ="flib_frame_title" , 294caption ={ "entity-name.ee-infinity-accumulator" } , 295ignored_by_interaction =true , 296} , 297{ type ="empty-widget" , style ="flib_titlebar_drag_handle" , ignored_by_interaction =true } , 298util . close_button ( handlers . on_ia_gui_closed ), 299} , 300{ 301type ="frame" , 302style ="entity_frame" , 303direction ="vertical" , 304{ 305type ="frame" , 306style ="deep_frame_in_shallow_frame" , 307{ 308type ="entity-preview" , 309name ="entity_preview" , 310style ="wide_entity_button" , 311elem_mods ={ entity =entity } , 312} , 313} , 314{ 315type ="flow" , 316style_mods ={ top_margin =4 , vertical_align ="center" } , 317{ type ="label" , caption ={ "gui.ee-mode" } } , 318util . pusher (), 319{ 320type ="drop-down" , 321name ="mode_dropdown" , 322items ={ { "gui.ee-output" } , { "gui.ee-input" } , { "gui.ee-buffer" } } , 323selected_index =0 , 324handler ={ 325[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_mode_dropdown_changed , 326} , 327} , 328} , 329{ type ="line" , direction ="horizontal" } , 330{ 331type ="flow" , 332style_mods ={ vertical_align ="center" } , 333{ 334type ="label" , 335caption ={ "" , { "gui.ee-priority" } , " [img=info]" } , 336tooltip ={ "gui.ee-ia-priority-description" } , 337} , 338util . pusher (), 339{ 340type ="drop-down" , 341name ="priority_dropdown" , 342items ={ { "gui.ee-primary" } , { "gui.ee-secondary" } , { "gui.ee-tertiary" } } , 343selected_index =0 , 344handler ={ 345[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_priority_dropdown_changed , 346} , 347} , 348} , 349{ type ="line" , direction ="horizontal" } , 350{ 351type ="flow" , 352style_mods ={ vertical_align ="center" } , 353{ 354type ="label" , 355style_mods ={ right_margin =6 } , 356caption ={ "gui.ee-power" } , 357} , 358{ 359type ="slider" , 360name ="power_slider" , 361style_mods ={ horizontally_stretchable =true } , 362minimum_value =0 , 363maximum_value =999 , 364value =0 , 365handler ={ [ defines . events . on_gui_value_changed ] =handlers . on_ia_gui_power_slider_changed } , 366} , 367{ 368type ="textfield" , 369name ="power_textfield" , 370style ="ee_slider_textfield" , 371text ="" , 372numeric =true , 373allow_decimal =true , 374clear_and_focus_on_right_click =true , 375handler ={ [ defines . events . on_gui_text_changed ] =handlers . on_ia_gui_power_textfield_changed } , 376} , 377{ 378type ="drop-down" , 379name ="power_dropdown" , 380style_mods ={ width =69 } , 381selected_index =0 , 382handler ={ 383[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_power_dropdown_changed , 384} , 385} , 386} , 387} , 388} ) 389 390player . opened =elems . ee_infinity_accumulator_window 391 392--- @class InfinityAccumulatorGui 393local self ={ 394elems =elems , 395entity =entity , 396player =player , 397} 398storage . infinity_accumulator_gui [ player . index ] =self 399 400update_gui ( self ) 401end 402 403--- @param e DestroyedEvent 404local function on_entity_destroyed ( e ) 405local entity =e . entity 406if not entity . valid or not entity_names [ entity . name ] then 407return 408end 409 410for player_index , gui in pairs ( storage . infinity_accumulator_gui ) do 411if gui . entity == entity then 412destroy_gui ( player_index ) 413end 414end 415end 416 417--- @param e EventData.on_entity_settings_pasted 418local function on_entity_settings_pasted ( e ) 419local source =e . source 420if not source . valid or not entity_names [ source . name ] then 421return 422end 423local destination =e . destination 424if not destination . valid or not entity_names [ destination . name ] then 425return 426end 427 428local source_priority , source_mode =get_settings_from_name ( source . name ) 429local destination_priority , destination_mode =get_settings_from_name ( destination . name ) 430if source_priority == destination_priority and source_mode == destination_mode then 431return 432end 433local new_entity =change_entity ( destination , source_priority , source_mode ) 434if not new_entity then 435return 436end 437 438update_all_guis ( new_entity ) 439end 440 441--- @param e EventData.on_gui_opened 442local function on_gui_opened ( e ) 443if e . gui_type ~= defines . gui_type . entity then 444return 445end 446local entity =e . entity 447if not entity or not entity . valid or not entity_names [ entity . name ] then 448return 449end 450local player =game . get_player ( e . player_index ) 451if not player then 452return 453end 454create_gui ( player , entity ) 455end 456 457local infinity_accumulator ={} 458 459infinity_accumulator . on_init =function () 460--- @type table<uint, InfinityAccumulatorGui> 461storage . infinity_accumulator_gui ={} 462end 463 464infinity_accumulator . on_configuration_changed =function () 465for player_index in pairs ( game . players ) do 466destroy_gui ( player_index --[[@as uint]] ) 467end 468end 469 470infinity_accumulator . events ={ 471[ defines . events . on_entity_died ] =on_entity_destroyed , 472[ defines . events . on_entity_settings_pasted ] =on_entity_settings_pasted , 473[ defines . events . on_gui_opened ] =on_gui_opened , 474[ defines . events . on_player_mined_entity ] =on_entity_destroyed , 475[ defines . events . on_robot_mined_entity ] =on_entity_destroyed , 476[ defines . events . script_raised_destroy ] =on_entity_destroyed , 477[ defines . events . on_space_platform_mined_entity ] =on_entity_destroyed , 478} 479 480return infinity_accumulator