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