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