z_mirror/EditorExtensions
git clone https://git.raiguard.me/z_mirror/EditorExtensions
e65a4b6
Quezler/patch-1
1--- @class LabState 2--- @field lab StateData 3--- @field normal StateData 4--- @field player LuaPlayer 5--- @field refresh boolean? 6 7--- @class StateData 8--- @field force LuaForce 9--- @field position MapPosition 10--- @field surface LuaSurface 11--- @field vehicle LuaEntity? 12--- @field is_driver boolean? 13 14--- @alias LabSetting 15--- | "force" 16--- | "off" 17--- | "personal" 18 19local empty_map_gen_settings ={ 20default_enable_all_autoplace_controls =false , 21property_expression_names ={ cliffiness =0 } , 22autoplace_settings ={ 23tile ={ settings ={ [ "out-of-map" ] ={ frequency ="normal" , size ="normal" , richness ="normal" } } } , 24} , 25starting_area ="none" , 26} 27 28--- @param player LuaPlayer 29--- @param lab_setting LabSetting 30--- @return LabState? 31local function create_lab ( player , lab_setting ) 32local key 33if lab_setting == "personal" then 34key =player . index 35elseif game . forces [ "EE_TESTSURFACE_shared" ] then 36-- For versions prior to 1.13.0, all forces used the "shared" lab 37key ="shared" 38else 39-- Use the actual force name, not the testing lab force name 40key =string . gsub ( player . force . name , "EE_TESTFORCE_" , "" ) 41end 42local surface_name ="EE_TESTSURFACE_" .. key 43local force_name ="EE_TESTFORCE_" .. key 44 45local surface =game . get_surface ( surface_name ) 46if not surface then 47surface =game . create_surface ( surface_name , empty_map_gen_settings ) 48for force_name , force in pairs ( game . forces ) do 49if not string . find ( force_name , "EE_TESTFORCE_" ) then 50force . set_surface_hidden ( surface , true ) 51end 52end 53player . force . set_surface_hidden ( surface , true ) 54if not surface then 55player . ( "Could not create test surface" ) 56return 57end 58-- Lab conditions 59surface . generate_with_lab_tiles =true 60surface . freeze_daytime =true 61surface . show_clouds =false 62surface . daytime =0 63-- Warn the player about the passage of time 64player . ( { "message.ee-time-passes-in-lab" } ) 65end 66 67local force =game . forces [ force_name ] 68if not game . forces [ force_name ] then 69if # game . forces == 64 then 70player . ( 71"Cannot create a testing lab force. Factorio only supports up to 64 forces at once. Please use a shared lab." 72) 73return 74end 75 76force =game . create_force ( force_name ) 77if settings . global [ "ee-testing-lab-match-research" ]. value then 78-- Sync research techs with the parent force 79for name , tech in pairs ( player . force . technologies ) do 80force . technologies [ name ]. researched =tech . researched 81end 82else 83force . research_all_technologies () 84end 85end 86 87return { 88lab ={ force =force , position ={ x =0 , y =0 } , surface =surface } , 89normal ={ force =player . force , position =player . position , surface =player . surface } , 90player =player , 91} 92end 93 94--- @param player LuaPlayer 95--- @param to_state StateData 96local function transfer_player ( player , to_state ) 97if not to_state . force . valid or not to_state . surface . valid then 98return 99end 100 101-- Change force first to avoid spilling items into the real world on inventory size change - see #143 102player . force =to_state . force 103player . teleport ( to_state . position , to_state . surface ) 104end 105 106--- @param player LuaPlayer 107local function enter_lab ( player ) 108local lab_state =storage . testing_lab_state [ player . index ] 109if not lab_state then 110return 111end 112 113local normal_data =lab_state . normal 114normal_data . force =player . force --[[@as LuaForce]] 115normal_data . position =player . position 116normal_data . surface =player . surface 117 118transfer_player ( player , lab_state . lab ) 119end 120 121--- @param lab_state LabState 122local function exit_lab ( lab_state ) 123local lab_data =lab_state . lab 124if lab_state . player . surface == lab_data . surface then 125lab_data . position =lab_state . player . position 126end 127 128transfer_player ( lab_state . player , lab_state . normal ) 129end 130 131--- @param player LuaPlayer 132--- @return LabSetting 133local function get_lab_setting ( player ) 134return player . mod_settings [ "ee-testing-lab" ]. value --[[@as LabSetting]] 135end 136 137--- @param e EventData.on_pre_player_toggled_map_editor 138local function on_pre_player_toggled_map_editor ( e ) 139local player =game . get_player ( e . player_index ) 140if not player then 141return 142end 143 144local lab_setting =get_lab_setting ( player ) 145if lab_setting == "off" then 146return 147end 148 149local in_editor =player . physical_controller_type == defines . controllers . editor 150local lab_state =storage . testing_lab_state [ e . player_index ] 151if not lab_state and not in_editor then 152lab_state =create_lab ( player , lab_setting ) 153storage . testing_lab_state [ e . player_index ] =lab_state 154end 155if not lab_state then 156return 157end 158 159local current_state =in_editor and lab_state . lab or lab_state . normal 160current_state . vehicle =player . vehicle 161current_state . is_driver =player . driving 162 163if in_editor then 164exit_lab ( lab_state ) 165end 166end 167 168--- @param player LuaPlayer 169local function sync_vehicle_state ( player ) 170local lab_state =storage . testing_lab_state [ player . index ] 171if not lab_state then 172return 173end 174 175local in_editor =player . physical_controller_type == defines . controllers . editor 176local new_state =in_editor and lab_state . lab or lab_state . normal 177 178local vehicle =new_state . vehicle 179if not vehicle or not vehicle . valid then 180return 181end 182 183if new_state . is_driver and not vehicle . get_driver () then 184new_state . vehicle . set_driver ( player ) 185elseif not new_state . is_driver and not vehicle . get_passenger () then 186new_state . vehicle . set_passenger ( player ) 187end 188end 189 190--- @param e EventData.on_player_toggled_map_editor 191local function on_player_toggled_map_editor ( e ) 192local player =game . get_player ( e . player_index ) 193if not player then 194return 195end 196 197if get_lab_setting ( player ) == "off" then 198return 199end 200 201if player . physical_controller_type == defines . controllers . editor then 202enter_lab ( player ) 203end 204 205sync_vehicle_state ( player ) 206end 207 208--- @param e EventData.on_force_reset 209local function on_force_reset ( e ) 210local parent_force =e . force 211if string . find ( parent_force . name , "EE_TESTFORCE_" ) then 212return 213end 214if not settings . global [ "ee-testing-lab-match-research" ]. value then 215return 216end 217 218local testing_force =game . forces [ "EE_TESTFORCE_" .. parent_force . name ] 219if not testing_force then 220return 221end 222 223for name , tech in pairs ( parent_force . technologies ) do 224testing_force . technologies [ name ]. researched =tech . researched 225end 226testing_force . reset_technology_effects () 227end 228 229--- @param e EventData.on_research_reversed 230local function on_research_reversed ( e ) 231local parent_force =e . research . force 232if string . find ( parent_force . name , "EE_TESTFORCE_" ) then 233return 234end 235if not settings . global [ "ee-testing-lab-match-research" ]. value then 236return 237end 238 239local testing_force =game . forces [ "EE_TESTFORCE_" .. parent_force . name ] 240if testing_force then 241testing_force . technologies [ e . research . name ]. researched =false 242end 243 244for i in pairs ( parent_force . players ) do 245local testing_force =game . forces [ "EE_TESTFORCE_" .. i ] 246if testing_force then 247testing_force . technologies [ e . research . name ]. researched =false 248end 249end 250end 251 252--- @param e EventData.on_research_finished 253local function on_research_finished ( e ) 254local parent_force =e . research . force 255if string . find ( parent_force . name , "EE_TESTFORCE_" ) then 256return 257end 258if not settings . global [ "ee-testing-lab-match-research" ]. value then 259return 260end 261 262local testing_force =game . forces [ "EE_TESTFORCE_" .. parent_force . name ] 263if testing_force then 264testing_force . technologies [ e . research . name ]. researched =true 265end 266 267for i in pairs ( parent_force . players ) do 268local testing_force =game . forces [ "EE_TESTFORCE_" .. i ] 269if testing_force then 270testing_force . technologies [ e . research . name ]. researched =true 271end 272end 273end 274 275local function on_match_research_setting_changed () 276for _ , force in pairs ( game . forces ) do 277local _ , _ , force_key =string . find ( force . name , "EE_TESTFORCE_(.*)" ) 278if not force_key then 279goto continue 280end 281if not settings . global [ "ee-testing-lab-match-research" ]. value then 282force . research_all_technologies () 283goto continue 284end 285 286local parent_force 287local force_key_num =tonumber ( force_key ) --- @cast force_key_num uint? 288if force_key_num then 289local player =game . get_player ( force_key_num ) --[[@as LuaPlayer]] 290parent_force =remote . call ( "EditorExtensions" , "get_player_proper_force" , player ) 291else 292parent_force =game . forces [ force_key ] 293end 294if parent_force then 295-- Sync research techs with the parent force 296for name , tech in pairs ( parent_force . technologies ) do 297force . technologies [ name ]. researched =tech . researched 298end 299end 300force . reset_technology_effects () 301:: continue :: 302end 303end 304 305--- @param e EventData.on_runtime_mod_setting_changed 306local function on_testing_lab_setting_changed ( e ) 307local lab_state =storage . testing_lab_state [ e . player_index ] 308if lab_state then 309lab_state . refresh =true 310end 311end 312 313--- @param e EventData.on_runtime_mod_setting_changed 314local function on_runtime_mod_setting_changed ( e ) 315if e . setting == "ee-testing-lab-match-research" then 316on_match_research_setting_changed () 317elseif e . setting == "ee-testing-lab" then 318on_testing_lab_setting_changed ( e ) 319end 320end 321 322local testing_lab ={} 323 324testing_lab . on_init =function () 325--- @type table<uint, LabState?> 326storage . testing_lab_state ={} 327end 328 329testing_lab . events ={ 330[ defines . events . on_force_reset ] =on_force_reset , 331[ defines . events . on_player_toggled_map_editor ] =on_player_toggled_map_editor , 332[ defines . events . on_pre_player_toggled_map_editor ] =on_pre_player_toggled_map_editor , 333[ defines . events . on_research_finished ] =on_research_finished , 334[ defines . events . on_research_reversed ] =on_research_reversed , 335[ defines . events . on_runtime_mod_setting_changed ] =on_runtime_mod_setting_changed , 336} 337 338testing_lab . add_remote_interface =function () 339remote . add_interface ( "EditorExtensions" , { 340--- Get the force that the player is actually on, ignoring the testing lab force. 341--- @param player LuaPlayer 342--- @return ForceID 343get_player_proper_force =function ( player ) 344if not player or not player . valid then 345error ( "Did not pass a valid LuaPlayer" ) 346end 347local in_editor =player . physical_controller_type == defines . controllers . editor 348local ts_setting =player . mod_settings [ "ee-testing-lab" ]. value 349if 350ts_setting == "off" 351or not in_editor 352or not storage . testing_lab_state 353or not storage . testing_lab_state [ player . index ] 354then 355return player . force 356end 357 358return storage . testing_lab_state [ player . index ]. normal . force 359end , 360} ) 361end 362 363return testing_lab