mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2025-12-27 11:35:22 +09:00
Merge pull request #211 from Cooldude2606/feature/spectate
Spectate and Follow
This commit is contained in:
@@ -30,6 +30,7 @@ return {
|
||||
'modules.commands.home',
|
||||
'modules.commands.connect',
|
||||
'modules.commands.last-location',
|
||||
'modules.commands.spectate',
|
||||
'modules.commands.search',
|
||||
|
||||
--- Addons
|
||||
|
||||
@@ -103,6 +103,8 @@ Roles.new_role('Trainee','TrMod')
|
||||
'command/unjail',
|
||||
'command/kick',
|
||||
'command/ban',
|
||||
'command/spectate',
|
||||
'command/follow',
|
||||
'command/search',
|
||||
'command/search-amount',
|
||||
'command/search-recent',
|
||||
@@ -120,6 +122,8 @@ Roles.new_role('Board Member','Board')
|
||||
:allow{
|
||||
'command/goto',
|
||||
'command/repair',
|
||||
'command/spectate',
|
||||
'command/follow',
|
||||
}
|
||||
|
||||
Roles.new_role('Senior Backer','Backer')
|
||||
|
||||
@@ -85,6 +85,9 @@ none-matching=No servers were found with that name, if you used an address pleas
|
||||
[expcom-lastlocation]
|
||||
response=Last location of __1__ was [gps=__2__,__3__]
|
||||
|
||||
[expcom-spectate]
|
||||
follow-self=You can not follow yourself
|
||||
|
||||
[expcom-admin-marker]
|
||||
exit=You have left admin marker mode, all new markers will not be protected.
|
||||
enter=You have entered admin marker mode, all new markers will be protected.
|
||||
|
||||
33
modules/commands/spectate.lua
Normal file
33
modules/commands/spectate.lua
Normal file
@@ -0,0 +1,33 @@
|
||||
--[[-- Commands Module - Spectate
|
||||
- Adds commands relating to spectate and follow
|
||||
@commands Spectate
|
||||
]]
|
||||
|
||||
local Spectate = require 'modules.control.spectate' --- @dep modules.control.spectate
|
||||
local Commands = require 'expcore.commands' --- @dep expcore.commands
|
||||
require 'config.expcore.command_general_parse'
|
||||
|
||||
--- Toggles spectator mode for the caller
|
||||
-- @command spectate
|
||||
Commands.new_command('spectate', 'Toggles spectator mode')
|
||||
:register(function(player)
|
||||
if Spectate.is_spectating(player) then
|
||||
Spectate.stop_spectate(player)
|
||||
else
|
||||
Spectate.start_spectate(player)
|
||||
end
|
||||
end)
|
||||
|
||||
--- Enters follow mode for the caller, following the given player.
|
||||
-- @command follow
|
||||
-- @tparam LuaPlayer player The player that will be followed
|
||||
Commands.new_command('follow', 'Start following a player in spectator')
|
||||
:add_alias('f')
|
||||
:add_param('player', false, 'player-online')
|
||||
:register(function(player, action_player)
|
||||
if player == action_player then
|
||||
return Commands.error{'expcom-spectate.follow-self'}
|
||||
else
|
||||
Spectate.start_follow(player, action_player)
|
||||
end
|
||||
end)
|
||||
168
modules/control/spectate.lua
Normal file
168
modules/control/spectate.lua
Normal file
@@ -0,0 +1,168 @@
|
||||
|
||||
local Event = require 'utils.event' --- @dep utils.event
|
||||
local Global = require 'utils.global' --- @dep utils.global
|
||||
local Gui = require 'expcore.gui' --- @dep expcore.gui
|
||||
|
||||
----- Locals -----
|
||||
local follow_label -- Gui constructor
|
||||
local following = {}
|
||||
local spectating = {}
|
||||
local Public = {}
|
||||
|
||||
----- Global data -----
|
||||
Global.register({
|
||||
following = following,
|
||||
spectating = spectating
|
||||
}, function(tbl)
|
||||
following = tbl.following
|
||||
spectating = tbl.spectating
|
||||
end)
|
||||
|
||||
----- Public Functions -----
|
||||
|
||||
--- Test if a player is in spectator mode
|
||||
-- @tparam LuaPlayer player The player to test the controller type of
|
||||
-- @treturn boolean Returns true if the player is in spectator mode
|
||||
function Public.is_spectating(player)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
return player.controller_type == defines.controllers.spectator
|
||||
end
|
||||
|
||||
--- Puts a player into spectator mode while maintaining an association to their character
|
||||
-- @tparam LuaPlayer player The player that will be placed into spectator mode
|
||||
-- @treturn boolean Returns false if the player was already in spectator mode
|
||||
function Public.start_spectate(player)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
if spectating[player.index] or not player.character then return false end
|
||||
local character = player.character
|
||||
player.set_controller{ type = defines.controllers.spectator }
|
||||
player.associate_character(character)
|
||||
spectating[player.index] = character
|
||||
return true
|
||||
end
|
||||
|
||||
--- Return a player from spectator mode back to their character, if their character was killed then respawn them
|
||||
-- @tparam LuaPlayer player The player that will leave spectator mode
|
||||
function Public.stop_spectate(player)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
local character = spectating[player.index]
|
||||
spectating[player.index] = nil
|
||||
if character and character.valid then
|
||||
local opened = player.opened
|
||||
player.teleport(character.position, character.surface)
|
||||
player.set_controller{ type = defines.controllers.character, character = character }
|
||||
if opened then player.opened = opened end -- Maintain opened after controller change
|
||||
else
|
||||
player.ticks_to_respawn = 300
|
||||
end
|
||||
end
|
||||
|
||||
--- Test if a player is in follow mode
|
||||
-- @tparam LuaPlayer player The player to test the follow mode of
|
||||
-- @treturn boolean Returns true if the player is in follow mode
|
||||
function Public.is_following(player)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
return following[player.index] ~= nil
|
||||
end
|
||||
|
||||
--- Puts a player into spectator mode and follows an entity as it moves
|
||||
-- @tparam LuaPlayer player The player that will follow the entity
|
||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity that will be followed
|
||||
function Public.start_follow(player, entity)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
assert(entity and entity.valid, 'Invalid entity given to follower')
|
||||
local spectate = Public.start_spectate(player)
|
||||
|
||||
player.close_map()
|
||||
follow_label(player.gui.screen, entity)
|
||||
player.teleport(entity.position, entity.surface)
|
||||
following[player.index] = { player, entity, entity.position, spectate }
|
||||
end
|
||||
|
||||
--- Returns camera control to the player, will return a player to their character if start_follow placed them into spectator mode
|
||||
-- @tparam LuaPlayer player The player that will regain control of their camera
|
||||
function Public.stop_follow(player)
|
||||
assert(player and player.valid, 'Invalid player given to follower')
|
||||
if following[player.index] and following[player.index][4] then Public.stop_spectate(player) end
|
||||
|
||||
Gui.destroy_if_valid(player.gui.screen[follow_label.name])
|
||||
following[player.index] = nil
|
||||
end
|
||||
|
||||
--- Returns camera control to all players, will return a player to their character if start_follow placed them into spectator mode
|
||||
function Public.stop_all()
|
||||
for key, data in pairs(following) do
|
||||
Public.stop_follow(data[1])
|
||||
end
|
||||
end
|
||||
|
||||
----- Gui -----
|
||||
|
||||
--- Label used to show that the player is following, also used to allow esc to stop following
|
||||
-- @element follow_label
|
||||
follow_label =
|
||||
Gui.element(function(event_trigger, parent, target)
|
||||
Gui.destroy_if_valid(parent[event_trigger])
|
||||
|
||||
local label = parent.add{
|
||||
name = event_trigger,
|
||||
type = 'label',
|
||||
style = 'heading_1_label',
|
||||
caption = 'Following '..target.name..'.\nClick here or press esc to stop following.'
|
||||
}
|
||||
|
||||
local player = Gui.get_player_from_element(parent)
|
||||
local res = player.display_resolution
|
||||
label.location = {0, res.height-150}
|
||||
label.style.width = res.width
|
||||
label.style.horizontal_align = 'center'
|
||||
player.opened = label
|
||||
|
||||
return label
|
||||
end)
|
||||
:on_click(Public.stop_follow)
|
||||
:on_close(function(player)
|
||||
-- Don't call set_controller during on_close as it invalidates the controller
|
||||
-- Setting an invalid position (as to not equal their current) will call stop_follow on the next tick
|
||||
following[player.index][3] = {}
|
||||
end)
|
||||
|
||||
----- Events -----
|
||||
|
||||
--- Updates the location of the player as well as doing some sanity checks
|
||||
-- @tparam LuaPlayer player The player to update the position of
|
||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity being followed
|
||||
local function update_player_location(player, entity, old_position)
|
||||
if player.character or not entity.valid then
|
||||
Public.stop_follow(player)
|
||||
elseif player.position.x ~= old_position.x or player.position.y ~= old_position.y then
|
||||
Public.stop_follow(player)
|
||||
else
|
||||
player.teleport(entity.position, entity.surface)
|
||||
end
|
||||
end
|
||||
|
||||
--- Updates the locations of all players currently following something
|
||||
local function update_all()
|
||||
for _, data in pairs(following) do
|
||||
update_player_location(data[1], data[2], data[3])
|
||||
data[3] = data[1].position
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the location of all players each tick
|
||||
Event.add(defines.events.on_tick, update_all)
|
||||
|
||||
-- Check for player leaving
|
||||
Event.add(defines.events.on_pre_player_left_game, function(event)
|
||||
local player = game.players[event.player_index]
|
||||
Public.stop_follow(player)
|
||||
for _, data in pairs(following) do
|
||||
if data[2] == player then
|
||||
Public.stop_follow(data[1])
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
----- Module Return -----
|
||||
return Public
|
||||
Reference in New Issue
Block a user