z_mirror/EditorExtensions
git clone https://git.raiguard.me/z_mirror/EditorExtensions
0ef36a1
1.14
1local gui =require ( "__flib__/gui-lite" ) 2local math =require ( "__flib__/math" ) 3local table =require ( "__flib__/table" ) 4 5local util =require ( "__EditorExtensions__/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 math . floor ( 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 =global . infinity_accumulator_gui [ player_index ] 119if not self then 120return 121end 122global . 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 ( global . 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" 241 242self . elems . power_slider . slider_value =value 243 244local _ , mode =get_settings_from_name ( entity . name ) 245local buffer_size =calc_buffer_size ( value , self . elems . power_dropdown . selected_index ) 246set_entity_settings ( entity , mode , buffer_size ) 247update_all_guis ( entity ) 248end , 249 250--- @param self InfinityAccumulatorGui 251--- @param e EventData.on_gui_selection_state_changed 252on_ia_gui_power_dropdown_changed =function ( self , e ) 253local entity =self . entity 254local _ , mode =get_settings_from_name ( entity . name ) 255local buffer_size =calc_buffer_size ( self . elems . power_slider . slider_value , e . element . selected_index ) 256set_entity_settings ( entity , mode , buffer_size ) 257update_all_guis ( entity ) 258end , 259} 260 261gui . add_handlers ( handlers , function ( e , handler ) 262local self =global . infinity_accumulator_gui [ e . player_index ] 263if not self then 264return 265end 266if not self . entity . valid then 267return 268end 269 270handler ( self , e ) 271end ) 272 273--- @param player LuaPlayer 274--- @param entity LuaEntity 275local function create_gui ( player , entity ) 276destroy_gui ( player . index ) 277 278local elems =gui . add ( player . gui . screen , { 279type ="frame" , 280name ="ee_infinity_accumulator_window" , 281direction ="vertical" , 282elem_mods ={ auto_center =true } , 283handler ={ [ defines . events . on_gui_closed ] =handlers . on_ia_gui_closed } , 284{ 285type ="flow" , 286style ="flib_titlebar_flow" , 287drag_target ="ee_infinity_accumulator_window" , 288{ 289type ="label" , 290style ="frame_title" , 291caption ={ "entity-name.ee-infinity-accumulator" } , 292ignored_by_interaction =true , 293} , 294{ type ="empty-widget" , style ="flib_titlebar_drag_handle" , ignored_by_interaction =true } , 295util . close_button ( handlers . on_ia_gui_closed ), 296} , 297{ 298type ="frame" , 299style ="entity_frame" , 300direction ="vertical" , 301{ 302type ="frame" , 303style ="deep_frame_in_shallow_frame" , 304{ 305type ="entity-preview" , 306name ="entity_preview" , 307style ="wide_entity_button" , 308elem_mods ={ entity =entity } , 309} , 310} , 311{ 312type ="flow" , 313style_mods ={ top_margin =4 , vertical_align ="center" } , 314{ type ="label" , caption ={ "gui.ee-mode" } } , 315util . pusher (), 316{ 317type ="drop-down" , 318name ="mode_dropdown" , 319items ={ { "gui.ee-output" } , { "gui.ee-input" } , { "gui.ee-buffer" } } , 320selected_index =0 , 321handler ={ 322[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_mode_dropdown_changed , 323} , 324} , 325} , 326{ type ="line" , direction ="horizontal" } , 327{ 328type ="flow" , 329style_mods ={ vertical_align ="center" } , 330{ 331type ="label" , 332caption ={ "" , { "gui.ee-priority" } , " [img=info]" } , 333tooltip ={ "gui.ee-ia-priority-description" } , 334} , 335util . pusher (), 336{ 337type ="drop-down" , 338name ="priority_dropdown" , 339items ={ { "gui.ee-primary" } , { "gui.ee-secondary" } , { "gui.ee-tertiary" } } , 340selected_index =0 , 341handler ={ 342[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_priority_dropdown_changed , 343} , 344} , 345} , 346{ type ="line" , direction ="horizontal" } , 347{ 348type ="flow" , 349style_mods ={ vertical_align ="center" } , 350{ 351type ="label" , 352style_mods ={ right_margin =6 } , 353caption ={ "gui.ee-power" } , 354} , 355{ 356type ="slider" , 357name ="power_slider" , 358style_mods ={ horizontally_stretchable =true } , 359minimum_value =0 , 360maximum_value =999 , 361value =0 , 362handler ={ [ defines . events . on_gui_value_changed ] =handlers . on_ia_gui_power_slider_changed } , 363} , 364{ 365type ="textfield" , 366name ="power_textfield" , 367style ="ee_slider_textfield" , 368text ="" , 369numeric =true , 370allow_decimal =true , 371clear_and_focus_on_right_click =true , 372handler ={ [ defines . events . on_gui_text_changed ] =handlers . on_ia_gui_power_textfield_changed } , 373} , 374{ 375type ="drop-down" , 376name ="power_dropdown" , 377style_mods ={ width =69 } , 378selected_index =0 , 379handler ={ 380[ defines . events . on_gui_selection_state_changed ] =handlers . on_ia_gui_power_dropdown_changed , 381} , 382} , 383} , 384} , 385} ) 386 387player . opened =elems . ee_infinity_accumulator_window 388 389--- @class InfinityAccumulatorGui 390local self ={ 391elems =elems , 392entity =entity , 393player =player , 394} 395global . infinity_accumulator_gui [ player . index ] =self 396 397update_gui ( self ) 398end 399 400--- @param e DestroyedEvent 401local function on_entity_destroyed ( e ) 402local entity =e . entity 403if not entity . valid or not entity_names [ entity . name ] then 404return 405end 406 407for player_index , gui in pairs ( global . infinity_accumulator_gui ) do 408if gui . entity == entity then 409destroy_gui ( player_index ) 410end 411end 412end 413 414--- @param e EventData.on_entity_settings_pasted 415local function on_entity_settings_pasted ( e ) 416local source =e . source 417if not source . valid or not entity_names [ source . name ] then 418return 419end 420local destination =e . destination 421if not destination . valid or not entity_names [ destination . name ] then 422return 423end 424 425local source_priority , source_mode =get_settings_from_name ( source . name ) 426local destination_priority , destination_mode =get_settings_from_name ( destination . name ) 427if source_priority == destination_priority and source_mode == destination_mode then 428return 429end 430local new_entity =change_entity ( destination , source_priority , source_mode ) 431if not new_entity then 432return 433end 434 435update_all_guis ( new_entity ) 436end 437 438--- @param e EventData.on_gui_opened 439local function on_gui_opened ( e ) 440if e . gui_type ~= defines . gui_type . entity then 441return 442end 443local entity =e . entity 444if not entity or not entity . valid or not entity_names [ entity . name ] then 445return 446end 447local player =game . get_player ( e . player_index ) 448if not player then 449return 450end 451create_gui ( player , entity ) 452end 453 454local infinity_accumulator ={} 455 456infinity_accumulator . on_init =function () 457--- @type table<uint, InfinityAccumulatorGui> 458global . infinity_accumulator_gui ={} 459end 460 461infinity_accumulator . on_configuration_changed =function () 462for player_index in pairs ( game . players ) do 463destroy_gui ( player_index --[[@as uint]] ) 464end 465end 466 467infinity_accumulator . events ={ 468[ defines . events . on_entity_died ] =on_entity_destroyed , 469[ defines . events . on_gui_opened ] =on_gui_opened , 470[ defines . events . on_player_mined_entity ] =on_entity_destroyed , 471[ defines . events . on_robot_mined_entity ] =on_entity_destroyed , 472[ defines . events . script_raised_destroy ] =on_entity_destroyed , 473[ defines . events . on_entity_settings_pasted ] =on_entity_settings_pasted , 474} 475 476return infinity_accumulator