-- simply use /where ::LuaPlayerName to locate them local Color = require 'utils.color_presets' local Event = require 'utils.event' local Global = require 'utils.global' local Gui = require 'utils.gui' local SpamProtection = require 'utils.spam_protection' local Commands = require 'utils.commands' local this = { players = {}, module_disabled = false } Global.register( this, function (t) this = t end ) local Public = {} local locate_player_frame_name = Gui.uid_name() local player_frame_name = Gui.uid_name() local function create_player_data(player) local player_data = this.players[player.index] if player_data then return this.players[player.index] else this.players[player.index] = {} return this.players[player.index] end end local function remove_player_data(player) if not player then return end if not player.index then return end local player_data = this.players[player.index] if player_data then if player_data.render_object then player_data.render_object.destroy() end this.players[player.index] = nil end end local function remove_camera_frame(player) if player.gui.screen[locate_player_frame_name] then player.gui.screen[locate_player_frame_name].destroy() remove_player_data(player) return end end local function validate_frame(frame) if not frame then return false end if not frame.valid then return false end return true end local function create_mini_camera_gui(player, target, zoom, render, tooltip) if not player or not player.valid then return end if player.gui.screen[locate_player_frame_name] then player.gui.screen[locate_player_frame_name].destroy() remove_player_data(player) return end local player_data if target and target.valid and player.admin or target and target.valid then player_data = create_player_data(player) player_data.target = target else remove_player_data(player) return end local frame = player.gui.screen[locate_player_frame_name] if not validate_frame(frame) then frame = player.gui.screen.add({ type = 'frame', name = locate_player_frame_name, caption = target.name }) end frame.force_auto_center() local surface = tonumber(target.surface.index) if frame[player_frame_name] and frame[player_frame_name].valid then frame[player_frame_name].destroy() end if render then local render_object = rendering.draw_text { text = '▼', surface = target.surface, target = { target.position.x, target.position.y - 3 }, color = { r = 0.98, g = 0.66, b = 0.22 }, scale = 3, players = { player.index }, font = 'heading-1', alignment = 'center', scale_with_zoom = false } if player_data then player_data.render_object = render_object end end local camera = frame.add( { type = 'camera', name = player_frame_name, position = target.position, zoom = zoom or 0.4, surface_index = surface, tooltip = tooltip or '' } ) camera.style.minimal_width = 740 camera.style.minimal_height = 580 player_data = create_player_data(player) player_data.camera_frame = camera return frame end Commands.new('where', 'Locates a player') :add_parameter('player', false, 'player-online') :callback( function (player, target) if this.module_disabled then return false end if target and target.valid then local player_data = create_player_data(player) player_data.target = target create_mini_camera_gui(player, target) else remove_player_data(player) player.print('[Where] Please type a name of a player who is connected.', { color = Color.warning }) end end ) local function on_nth_tick() for p, data in pairs(this.players) do if data and data.target and data.target.valid then local target = data.target local camera_frame = data.camera_frame local player = game.get_player(p) if not (player and player.valid or target and target.valid) then remove_player_data(player) goto continue end if not validate_frame(camera_frame) then remove_player_data(player) goto continue end camera_frame.position = target.position camera_frame.surface_index = target.surface.index ::continue:: end end end Gui.on_click( locate_player_frame_name, function (event) local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Where Locate Player') if is_spamming then return end remove_camera_frame(event.player) end ) Gui.on_custom_close( locate_player_frame_name, function (event) local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Where Locate Player') if is_spamming then return end remove_camera_frame(event.player) end ) Gui.on_click( player_frame_name, function (event) local is_spamming = SpamProtection.is_spamming(event.player, nil, 'Where Player Frame') if is_spamming then return end local button = event.button local shift = event.shift if button == defines.mouse_button_type.left and shift then return end remove_camera_frame(event.player) end ) --- Disables the module. ---@param state boolean function Public.module_disabled(state) this.module_disabled = state or false end Public.create_mini_camera_gui = create_mini_camera_gui Public.remove_camera_frame = remove_camera_frame Public.locate_player_frame_name = locate_player_frame_name Public.player_frame_name = player_frame_name Event.on_nth_tick(2, on_nth_tick) return Public