1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-12 10:13:58 +02:00

Merge pull request #227 from Oarcinae/170-add-custom-events-for-new-spawn-created-to-allow-other-modsscenarios-to-hook-into

170 add custom events for new spawn created to allow other modsscenarios to hook into
This commit is contained in:
Oarcinae 2024-10-27 18:13:39 -04:00 committed by GitHub
commit 388ada2b4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 267 additions and 125 deletions

View File

@ -110,10 +110,74 @@ end)
-- SeparateSpawnsPlayerChangedSurface(event)
-- end)
-- script.on_event(defines.events.on_rocket_launched, function(event)
-- log("Rocket launched!")
-- log(serpent.block(event))
-- end)
script.on_event(defines.events.on_rocket_launched, function(event)
log("Rocket launched!")
log(serpent.block(event))
end)
----------------------------------------
-- CUSTOM OARC Events (shown here for demo and logging purposes)
----------------------------------------
---@class OarcCustomEventBase
---@field mod_name string
---@field name integer --For custom events, this is the event ID
---@field tick integer
---@class OarcModOnSpawnCreatedEvent: OarcCustomEventBase
---@field spawn_data OarcUniqueSpawn
script.on_event("oarc-mod-on-spawn-created", function(event)
log("Custom event oarc-mod-on-spawn-created")
log(serpent.block(event --[[@as OarcModOnSpawnCreatedEvent]]))
end)
---@class OarcModOnSpawnRemoveRequestEvent: OarcCustomEventBase
---@field spawn_data OarcUniqueSpawn
script.on_event("oarc-mod-on-spawn-remove-request", function(event)
log("Custom event oarc-mod-on-spawn-remove-request")
log(serpent.block(event --[[@as OarcModOnSpawnRemoveRequestEvent]]))
end)
---@class OarcModOnPlayerResetEvent: OarcCustomEventBase
---@field player_index integer
script.on_event("oarc-mod-on-player-reset", function(event)
log("Custom event oarc-mod-on-player-reset")
log(serpent.block(event))
if (game.players[event.player_index]) then
log("Player is still valid: " .. game.players[event.player_index].name)
end
end)
---@class OarcModOnPlayerSpawnedEvent: OarcCustomEventBase
---@field player_index integer
script.on_event("oarc-mod-on-player-spawned", function(event)
log("Custom event oarc-mod-on-player-spawned")
log(serpent.block(event))
log("Player spawned: " .. game.players[event.player_index].name)
end)
---@class OarcModCharacterSurfaceChangedEvent: OarcCustomEventBase
---@field player_index integer
---@field old_surface_name string
---@field new_surface_name string
script.on_event("oarc-mod-character-surface-changed", function(event)
log("Custom event oarc-mod-character-surface-changed")
log(serpent.block(event))
local player = game.players[event.player_index]
SeparateSpawnsPlayerChangedSurface(player, event.old_surface_name, event.new_surface_name)
end)
-- I raise this event whenever teleporting the player!
script.on_event(defines.events.script_raised_teleported, function(event)
log("script_raised_teleported")
log(serpent.block(event))
local entity = event.entity
if entity.type == "character" and entity.player then
UpdatePlayerSurface(entity.player, entity.surface.name)
end
end)
----------------------------------------
-- Shared chat, so you don't have to type /s
@ -139,32 +203,8 @@ script.on_event(defines.events.on_tick, function(event)
RegrowthOnTick()
end
RegrowthForceRemovalOnTick() -- Allows for abandoned base cleanup without regrowth enabled.
TrackPlayerSurfacesOnTick() -- My work around for not having a proper event for changing surfaces.
end)
---This is a work around for not having a proper event for changing surfaces.
---Every tick, it checks the player's surface and if it changes from the previous tick it triggers an event.
---@return nil
function TrackPlayerSurfacesOnTick()
if (storage.player_surfaces == nil) then
storage.player_surfaces = {}
end
for _,player in pairs(game.players) do
if (player.connected and player.character) then
if (storage.player_surfaces[player.name] ~= player.surface.name) then
local previous_surface_name = storage.player_surfaces[player.name]
local new_surface_name = player.surface.name
SeparateSpawnsPlayerChangedSurface(player, previous_surface_name, new_surface_name)
storage.player_surfaces[player.name] = new_surface_name
-- script.raise_event(defines.events.on_player_changed_surface, {player_index=player.index})
end
end
end
end
----------------------------------------
-- Chunk Generation
----------------------------------------
@ -247,8 +287,67 @@ script.on_event(defines.events.on_player_driving_changed_state, function (event)
if storage.ocfg.regrowth.enable_regrowth then
RegrowthMarkAreaSafeGivenTilePos(event.entity.surface.name, event.entity.position, 1, false)
end
log("Player driving changed state")
log(serpent.block(event))
local player = game.players[event.player_index]
-- Track the surfaces whenever driving state changes.
if (event.entity ~= nil) then
UpdatePlayerSurface(player, entity.surface.name)
end
-- local entity = event.entity
-- if (entity ~= nil) and(entity.name == "cargo-pod") and
-- (entity.surface.name == "nauvis") and
-- (storage.player_surfaces[player.name] == "platform-1") then
-- log("Landing cargo pod on nauvis")
-- player.teleport({x=100,y=100})
-- end
-- --[[@type OarcPlayerSpawn]]
-- local respawn_info = storage.player_respawns[player.name][player.surface.name]
-- if (respawn_info == nil) then
-- log("ERROR: No respawn info for player: " .. player.name)
-- return
-- end
-- local respawn_surface_name = respawn_info.surface
-- local respawn_position = respawn_info.position
end)
---Updates the player's surface and raises an event if it changes.
---@param player LuaPlayer
---@param new_surface_name string
---@return nil
function UpdatePlayerSurface(player, new_surface_name)
if (storage.player_surfaces == nil) then
storage.player_surfaces = {}
end
local previous_surface_name = storage.player_surfaces[player.name]
if (previous_surface_name ~= new_surface_name) then
storage.player_surfaces[player.name] = new_surface_name
-- Raise event if previous surface isn't nil (avoids first spawn event)
if (previous_surface_name ~= nil) then
script.raise_event("oarc-mod-character-surface-changed", {
player_index=player.index,
old_surface_name=previous_surface_name,
new_surface_name=new_surface_name
})
end
end
end
----------------------------------------
-- On script_raised_built. This should help catch mods that
-- place items that don't count as player_built and robot_built.

View File

@ -21,8 +21,47 @@ data:extend({
width = 40,
height = 40
},
oarc_linked_chest, oarc_linked_power
oarc_linked_chest, oarc_linked_power,
})
data:extend({
-- A spawn area was created (and is finished generating)
{
type = "custom-event",
name = "oarc-mod-on-spawn-created",
-- Provides data table called spawn_data
},
-- A spawn area was REQUESTED to be removed. (Not that it has been removed already.)
{
type = "custom-event",
name = "oarc-mod-on-spawn-remove-request",
-- Provides data table called spawn_data
},
-- A player was reset (also called when a player is removed)
-- If you want just player removed, use native on_player_removed and/or on_pre_player_removed
{
type = "custom-event",
name = "oarc-mod-on-player-reset",
-- Provides player_index
},
-- A player was spawned (sent to a new spawn OR joined a shared spawn)
{
type = "custom-event",
name = "oarc-mod-on-player-spawned",
-- Provides player_index
},
-- A player moved from surface to space platform
{
type = "custom-event",
name = "oarc-mod-character-surface-changed",
-- Provides player_index, old_surface_name, new_surface_name
},
})
-- Make coins not hidden
data.raw["item"]["coin"].hidden = false

View File

@ -489,7 +489,8 @@ function SpawnCtrlTabGuiClick(event)
-- Spawn the player
local joining_player = game.players[join_queue_player_choice]
SetPlayerRespawn(joining_player.name, primary_spawn.surface_name, primary_spawn.position, true)
SendPlayerToSpawn(primary_spawn.surface_name, joining_player)
SendPlayerToSpawn(primary_spawn.surface_name, joining_player, true)
script.raise_event("oarc-mod-on-player-spawned", {player_index = joining_player.index})
GivePlayerStarterItems(joining_player)
table.insert(storage.unique_spawns[primary_spawn.surface_name][player.name].joiners, joining_player.name)
joining_player.force = game.players[player.name].force

View File

@ -199,4 +199,36 @@ function CreateTestSurfaces()
game.create_surface("gleba")
game.create_surface("aquilo")
end
---Searchs a 3x3 chunk around the map origin for "cargo-pod-container" entities and if they are on the same force
---as the player it will teleport the cargo pod to the player.
---@param player LuaPlayer
---@return nil
function DudeWheresMyCargoPod(player)
if not player.character then
player.print("Your character needs to be valid to use this! Make sure you are not inside a vehicle or dead!")
return
end
local surface = player.character.surface
local radius = CHUNK_SIZE*3
local search_area = {{-radius,-radius},{radius,radius}}
local pods = surface.find_entities_filtered{area=search_area, name="cargo-pod-container", force=player.force}
for _,cargo_pod in pairs(pods) do
local new_position = surface.find_non_colliding_position("cargo-pod-container", player.character.position, CHUNK_SIZE, 1)
if new_position == nil then
player.print("Could not find a safe place to teleport the cargo pod!")
return
end
cargo_pod.teleport(new_position)
player.print("Teleported cargo pod to you!")
end
end

View File

@ -514,25 +514,14 @@ end
---@param surface LuaSurface
---@param target_pos MapPosition
function SafeTeleport(player, surface, target_pos)
local safe_pos = surface.find_non_colliding_position("character", target_pos, 15, 1)
local safe_pos = surface.find_non_colliding_position("character", target_pos, CHUNK_SIZE, 1)
if (not safe_pos) then
player.teleport(target_pos, surface)
player.teleport(target_pos, surface, true)
else
player.teleport(safe_pos, surface)
player.teleport(safe_pos, surface, true)
end
end
-- Duplicate function ??
-- -- Create area given point and radius-distance
-- function GetAreaFromPointAndDistance(point, dist)
-- local area = {left_top=
-- {x=point.x-dist,
-- y=point.y-dist},
-- right_bottom=
-- {x=point.x+dist,
-- y=point.y+dist}}
-- return area
-- end
---Check if given position is in area bounding box
---@param point MapPosition

View File

@ -213,9 +213,13 @@ function SeparateSpawnsPlayerRespawned(event)
if (player.surface.name == HOLDING_PEN_SURFACE_NAME) then return end
-- If the mod isn't active on this surface, then ignore it.
if (storage.oarc_surfaces[surface_name] == nil) then return end
local surface_config = storage.oarc_surfaces[surface_name]
if (surface_config == nil) or
(not surface_config.primary and not surface_config.secondary) then
return
end
SendPlayerToSpawn(surface_name, player)
SendPlayerToSpawn(surface_name, player, false)
GivePlayerRespawnItems(player)
end
@ -239,41 +243,46 @@ end
---@return nil
function SeparateSpawnsPlayerChangedSurface(player, previous_surface_name, new_surface_name)
if (previous_surface_name == nil) then
log("SeparateSpawnsPlayerChangedSurface - No previous surface name!")
return
end
if (previous_surface_name == nil) then return end
log("SeparateSpawnsPlayerChangedSurface from " .. previous_surface_name .. " to " .. new_surface_name)
-- If previous surface was a platform
local arriving_from_space = StringStartsWith(previous_surface_name, "platform-")
if (not storage.ocfg.gameplay.enable_secondary_spawns) then return end
-- local player = game.players[event.player_index]
-- local surface_name = player.surface.name
-- Check if player has been init'd yet. If not, then ignore it.
if (storage.player_respawns[player.name] == nil) then return end
-- If the mod isn't active on this surface, then ignore it.
if (storage.oarc_surfaces[new_surface_name] == nil) then return end
-- If the mod is configured to not allow secondary spawns here, then ignore it.
if (not storage.oarc_surfaces[new_surface_name].secondary) then return end
-- Check if there is already a spawn for them on this surface
-- Could be a buddy spawn, or a shared spawn, or a unique spawn.
local player_spawn = FindPlayerSpawnOnSurface(player.name, new_surface_name)
if (player_spawn == nil) then
log("WARNING - THIS IS NOT FULLY IMPLEMENTED YET!!")
SecondarySpawn(player, player.surface)
local surface_config = storage.oarc_surfaces[new_surface_name]
if (surface_config == nil) or
(not surface_config.primary and not surface_config.secondary) then
return
end
--TODO: Check if they are near a cargo-landing-pad entity and if they are NOT, teleport them home to their spawn?
-- If previous surface was a platform
-- local arriving_from_space = StringStartsWith(previous_surface_name, "platform-")
-- If we are NOT arriving from space, then ignore the rest of this??
-- if (not arriving_from_space) then return end
local player_spawn = FindPlayerSpawnOnSurface(player.name, new_surface_name) -- Either they are host or joiner.
-- If there IS a spawn for them on their new surface, then just send them there.
if (player_spawn ~= nil) then
SendPlayerToSpawn(new_surface_name, player, false)
return
end
-- If there is no spawn for them on their new surface, generate one based on previous choices.
-- Check if secondary spawns are enabled (both globally and on this surface)
if (not storage.ocfg.gameplay.enable_secondary_spawns) or
(not storage.oarc_surfaces[new_surface_name].secondary) then
return
end
-- TODO: Need to figure out buddy spawns and other stuff still!
log("WARNING - THIS IS NOT FULLY IMPLEMENTED YET!!")
SecondarySpawn(player, player.surface)
end
--[[
@ -486,7 +495,7 @@ function SendPlayerToNewSpawnAndCreateIt(delayed_spawn)
-- Send the player to that position
local player = game.players[delayed_spawn.playerName]
SendPlayerToSpawn(delayed_spawn.surface, player)
SendPlayerToSpawn(delayed_spawn.surface, player, delayed_spawn.primary)
GivePlayerStarterItems(player)
-- Render some welcoming text...
@ -496,16 +505,24 @@ function SendPlayerToNewSpawnAndCreateIt(delayed_spawn)
ChartArea(player.force, delayed_spawn.position, math.ceil(storage.ocfg.spawn_general.spawn_radius_tiles / CHUNK_SIZE),
player.surface)
-- Remove waiting dialog
if (player.gui.screen.wait_for_spawn_dialog ~= nil) then
player.gui.screen.wait_for_spawn_dialog.destroy()
end
-- Create crash site if configured
if (ocfg.surfaces_config[delayed_spawn.surface].starting_items.crashed_ship) then
crash_site.create_crash_site(game.surfaces[delayed_spawn.surface],
{ x = delayed_spawn.position.x + 15, y = delayed_spawn.position.y - 25 },
ocfg.surfaces_config[delayed_spawn.surface].starting_items.crashed_ship_resources,
ocfg.surfaces_config[delayed_spawn.surface].starting_items.crashed_ship_wreakage)
end
-- Trigger the event that the spawn was created.
script.raise_event("oarc-mod-on-spawn-created", {spawn_data = storage.unique_spawns[delayed_spawn.surface][delayed_spawn.playerName]})
-- Trigger the event that player was spawned too.
script.raise_event("oarc-mod-on-player-spawned", {player_index = player.index})
end
---Displays some welcoming text at the spawn point on the ground. Fades out over time.
@ -765,7 +782,7 @@ function RemoveOrResetPlayer(player, remove_player)
-- If this player is staying in the game, lets make sure we don't delete them along with the map chunks being
-- cleared.
player.teleport({x=0,y=0}, HOLDING_PEN_SURFACE_NAME)
SafeTeleport(player, game.surfaces[HOLDING_PEN_SURFACE_NAME], {x=0,y=0})
local player_old_force = player.force
player.force = storage.ocfg.gameplay.main_force_name
@ -781,6 +798,9 @@ function RemoveOrResetPlayer(player, remove_player)
game.merge_forces(player_old_force, "neutral")
end
-- Trigger the event that the player was reset.
script.raise_event("oarc-mod-on-player-reset", {player_index = player.index})
-- Remove the character completely
if (remove_player and not player.connected) then
game.remove_offline_players({ player })
@ -884,6 +904,8 @@ function UniqueSpawnCleanupRemove(player_name)
local clear_radius = storage.ocfg.gameplay.minimum_distance_to_existing_chunks - 2 -- Bring in a bit for safety.
RegrowthMarkAreaForRemoval(primary_spawn.surface_name, spawn_position, clear_radius)
TriggerCleanup()
-- Trigger event
script.raise_event("oarc-mod-on-spawn-remove-request", {spawn_data = primary_spawn})
end
storage.unique_spawns[primary_spawn.surface_name][player_name] = nil
@ -1167,30 +1189,6 @@ function IsSharedSpawnFull(surface_name, owner_name)
return (GetOnlinePlayersAtSharedSpawn(surface_name, owner_name) >= storage.ocfg.gameplay.number_of_players_per_shared_spawn)
end
-- ---Checks if player has a custom spawn point set.
-- ---@param player LuaPlayer
-- ---@return boolean
-- function DoesPlayerHaveCustomSpawn(player)
-- for name,_ in pairs(storage.player_respawns --[[@as OarcPlayerRespawnsTable]]) do
-- if (player.name == name) then
-- return true
-- end
-- end
-- return false
-- end
-- ---Gets the custom spawn point for a player if they have one.
-- ---@param player LuaPlayer
-- ---@return OarcPlayerSpawn?
-- function GetPlayerCustomSpawn(player)
-- for name, player_spawn in pairs(storage.player_respawns --[[@as OarcPlayerRespawnsTable]]) do
-- if (player.name == name) then
-- return player_spawn
-- end
-- end
-- return nil
-- end
---Sets the custom spawn point for a player. They can have one per surface.
---@param player_name string
---@param surface_name string
@ -1384,38 +1382,22 @@ end
---Send player to their custom spawn point
---@param surface_name string
---@param player LuaPlayer
---@param first_spawn boolean
---@return nil
function SendPlayerToSpawn(surface_name, player)
function SendPlayerToSpawn(surface_name, player, first_spawn)
local spawn = storage.player_respawns[player.name][surface_name]
if (spawn == nil) then
log("ERROR - SendPlayerToSpawn - No spawn point for player: " .. player.name .. " on surface: " .. surface_name .. " first_spawn: " .. tostring(first_spawn))
return
end
SafeTeleport(player, game.surfaces[surface_name], spawn.position)
player.permission_group = game.permissions.get_group("Default")
if first_spawn then
player.permission_group = game.permissions.get_group("Default")
end
end
-- ---Send player to a random spawn point.
-- ---@param player LuaPlayer
-- ---@return nil
-- function SendPlayerToRandomSpawn(player)
-- local numSpawns = #storage.oc--ore.unique--Spawns
-- local rndSpawn = math.random(0, numSpawns)
-- local counter = 0
-- if (rndSpawn == 0) then
-- local gameplayConfig = storage.ocfg.gameplay --[[@as OarcConfigGameplaySettings]]
-- player.teleport(
-- game.forces[gameplayConfig.main_force_name].get_spawn_position(gameplayConfig.default_surface),
-- gameplayConfig.default_surface)
-- else
-- counter = counter + 1
-- for name, spawn in pairs(storage.oc--ore.unique--Spawns --[[@as OarcUnique--SpawnsTable]]) do
-- if (counter == rndSpawn) then
-- player.teleport(spawn.position)
-- break
-- end
-- counter = counter + 1
-- end
-- end
-- end
---Check if a player has a delayed spawn
---@param player_name string
---@return boolean