diff --git a/Beu/GuestlistManager.php b/Beu/GuestlistManager.php
index 8f8c1f8..aa99981 100644
--- a/Beu/GuestlistManager.php
+++ b/Beu/GuestlistManager.php
@@ -2,35 +2,43 @@
namespace Beu;
-use ManiaControl\Commands\CommandListener;
+use ManiaControl\ManiaControl;
use ManiaControl\Logger;
+use ManiaControl\Admin\AuthenticationManager;
+use ManiaControl\Callbacks\CallbackListener;
+use ManiaControl\Callbacks\TimerListener;
+use ManiaControl\Commands\CommandListener;
use ManiaControl\Players\Player;
use ManiaControl\Players\PlayerManager;
use ManiaControl\Plugins\Plugin;
-use ManiaControl\ManiaControl;
+use ManiaControl\Settings\SettingManager;
/**
* Plugin Description
*
* @author Beu
- * @version 1.1
*/
-class GuestlistManager implements CommandListener, Plugin {
+class GuestlistManager implements CommandListener, CallbackListener, TimerListener, Plugin {
/*
* Constants
*/
const PLUGIN_ID = 154;
- const PLUGIN_VERSION = 1.3;
+ const PLUGIN_VERSION = 2.0;
const PLUGIN_NAME = 'Guestlist Manager';
const PLUGIN_AUTHOR = 'Beu';
const SETTING_GUESTLIST_FILE = 'Guestlist file';
+ const SETTING_LOAD_AT_START = 'Load Guestlist at Maniacontrol start';
+ const SETTING_ADD_ADMINS = 'Automatically add admins to the guestlist';
+ const SETTING_ADMIN_LEVEL = 'Minimum Admin level to automatically add admin to the guestlist';
+ const SETTING_ENFORCE_GUESTLIST = 'Kick all non-guestlisted players';
/**
* Private Properties
*/
/** @var ManiaControl $maniaControl */
private $maniaControl = null;
+ private $checkNonGuestlistedPlayers = true;
/**
* @see \ManiaControl\Plugins\Plugin::prepare()
@@ -79,17 +87,40 @@ class GuestlistManager implements CommandListener, Plugin {
public function load(ManiaControl $maniaControl) {
$this->maniaControl = $maniaControl;
- $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_GUESTLIST_FILE, "guestlist.txt", 'guestlist file');
- $this->maniaControl->getCommandManager()->registerCommandListener('addalltogl', $this, 'doaddalltogl', true, 'Add all connected players to the guestlist');
- $this->maniaControl->getCommandManager()->registerCommandListener('addtogl', $this, 'doaddtogl', true, 'Add someone to the guestlist');
- $this->maniaControl->getCommandManager()->registerCommandListener('savegl', $this, 'dosavegl', true, 'Save the guestlist');
- $this->maniaControl->getCommandManager()->registerCommandListener('loadgl', $this, 'doloadgl', true, 'Load the guestlist');
- $this->maniaControl->getCommandManager()->registerCommandListener('cleangl', $this, 'docleangl', true, 'Clean the guestlist');
+ $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_GUESTLIST_FILE, "guestlist.txt", 'guestlist file', 10);
+ $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_LOAD_AT_START, false, 'Load guestlist file at maniacontrol start', 20);
+ $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_ADD_ADMINS, false, 'Due to a bug, player can join a server without being guestlisted. This setting is to prevent this.', 90);
+ $this->maniaControl->getAuthenticationManager()->definePluginPermissionLevel($this, self::SETTING_ADMIN_LEVEL, AuthenticationManager::AUTH_LEVEL_MODERATOR);
+ $this->maniaControl->getSettingManager()->initSetting($this, self::SETTING_ENFORCE_GUESTLIST, false, 'Due to a bug, player can join a server without being guestlisted. This setting is to prevent this.', 110);
+
+ $this->maniaControl->getCommandManager()->registerCommandListener(['gladdall', 'addalltogl'], $this, 'handleAddAll', true, 'Add all connected players to the guestlist');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['gladd', 'addtogl'], $this, 'handleAdd', true, 'Add player to the guestlist');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['glremove', 'gldelete', 'removefromgl', 'deletefromgl'], $this, 'handleRemove', true, 'Remove player to the guestlist');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['glsave', 'savegl'], $this, 'handleSave', true, 'Save the guestlist file');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['glload', 'loadgl'], $this, 'handleLoad', true, 'Load the guestlist file');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['glclear', 'glclean', 'cleangl'], $this, 'handleClear', true, 'Clear the guestlist');
+ $this->maniaControl->getCommandManager()->registerCommandListener(['glkickall'], $this, 'handleKickAll', true, 'Kick non-guestlisted players');
- $guestlist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_GUESTLIST_FILE);
- if ($guestlist === "" || is_file($this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist)) {
- $this->maniaControl->getClient()->loadGuestList($guestlist);
+ $this->maniaControl->getCallbackManager()->registerCallbackListener(AuthenticationManager::CB_AUTH_LEVEL_CHANGED, $this, 'handleAuthLevelChanged');
+ $this->maniaControl->getCallbackManager()->registerCallbackListener(PlayerManager::CB_PLAYERCONNECT, $this, 'handlePlayerConnect');
+ $this->maniaControl->getCallbackManager()->registerCallbackListener(SettingManager::CB_SETTING_CHANGED, $this, 'handleSettingChanged');
+
+
+ if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_LOAD_AT_START)) {
+ $guestlist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_GUESTLIST_FILE);
+ if ($guestlist === "" || is_file($this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist)) {
+ $this->maniaControl->getClient()->loadGuestList($guestlist);
+ }
}
+ $this->addAdminsToGuestlist();
+
+ $this->maniaControl->getTimerManager()->registerTimerListening($this, function () {
+ if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ENFORCE_GUESTLIST)) return;
+ if (!$this->checkNonGuestlistedPlayers) return;
+ $this->checkNonGuestlistedPlayers = false;
+ $this->kickNonGuestlistedPlayers();
+
+ }, 1000);
}
/**
@@ -99,12 +130,12 @@ class GuestlistManager implements CommandListener, Plugin {
}
/**
- * Add all connected players to the guestlist
+ * handle Add All to GL command
*
* @param array $chat
* @param \ManiaControl\Players\Player $player
- */
- public function doaddalltogl(Array $chat, Player $player) {
+ */
+ public function handleAddAll(Array $chat, Player $player) {
$players = $this->maniaControl->getPlayerManager()->getPlayers();
$guestlist = $this->maniaControl->getClient()->getGuestList();
$i = 0;
@@ -113,44 +144,48 @@ class GuestlistManager implements CommandListener, Plugin {
$i++;
}
}
- $this->maniaControl->getChat()->sendSuccess( "All connected players have been added to the Guestlist");
+ Logger::log('Adding all connected players to the guestlist by '. $player->nickname);
+ $this->maniaControl->getChat()->sendSuccess("All connected players have been added to the Guestlist");
$this->maniaControl->getChat()->sendSuccess( "Added: " . $i . "/" . count($players), $player);
}
/**
- * Add players to the guestlist
+ * handle Add GL command
*
* @param array $chat
* @param \ManiaControl\Players\Player $player
- */
- public function doaddtogl(Array $chat, Player $player) {
+ */
+ public function handleAdd(Array $chat, Player $player) {
$command = explode(" ", $chat[1][2]);
- $peopletoadd = $command[1];
+ $playerToAdd = $command[1];
- if (empty($peopletoadd)) {
- $this->maniaControl->getChat()->sendError("You must set the nickname as argument", $player);
+ if (empty($playerToAdd)) {
+ $this->maniaControl->getChat()->sendError("You must set the login or the nickname as argument", $player);
} else {
$mysqli = $this->maniaControl->getDatabase()->getMysqli();
- $query = 'SELECT login FROM `' . PlayerManager::TABLE_PLAYERS . '` WHERE nickname LIKE "' . $peopletoadd . '"';
- $result = $mysqli->query($query);
+ $stmt = $mysqli->prepare('SELECT `login` FROM `' . PlayerManager::TABLE_PLAYERS . '` WHERE nickname LIKE ? LIMIT 1;');
+ $stmt->bind_param('s', $playerToAdd);
+ $stmt->execute();
+ $result = $stmt->get_result();
$array = mysqli_fetch_array($result);
if (isset($array[0])) {
$login = $array[0];
- } elseif (strlen($peopletoadd) == 22) {
- $login = $peopletoadd ;
+ } elseif (strlen($playerToAdd) == 22) {
+ $login = $playerToAdd;
}
if ($mysqli->error) {
trigger_error($mysqli->error, E_USER_ERROR);
}
if (!isset($login)) {
- $this->maniaControl->getChat()->sendError( "Login not found. FYI The player must be connected" , $player);
+ $this->maniaControl->getChat()->sendError("Player not found. Use the nickname of already connected player or just their login", $player);
} else {
if ($this->addLoginToGL($login)) {
- $this->maniaControl->getChat()->sendSuccess( "Player " . $peopletoadd . " added to the Guestlist" , $player);
+ Logger::log('Player "'. $playerToAdd .'" added to the guestlist by '. $player->nickname);
+ $this->maniaControl->getChat()->sendSuccess('Player "' . $playerToAdd . '" added to the Guestlist', $player);
} else {
- $this->maniaControl->getChat()->sendSuccess( "Player " . $peopletoadd . " already in the Guestlist" , $player);
+ $this->maniaControl->getChat()->sendSuccess('Player "' . $playerToAdd . '" already in the Guestlist', $player);
}
}
}
@@ -161,15 +196,16 @@ class GuestlistManager implements CommandListener, Plugin {
*
* @param string $login
* @param array $guestlist
- */
- public function addLoginToGL(String $login, array $guestlist = []) {
- if (empty($guestlist)) {
+ */
+ public function addLoginToGL(String $login, ?array $guestlist = null) {
+ if ($guestlist === null) {
$guestlist = $this->maniaControl->getClient()->getGuestList();
}
- $logintoadd = "";
- $logintoadd = array_search($login ,array_column($guestlist, 'login'));
- if (strlen($logintoadd) == 0) {
+
+ if (!in_array($login, array_column($guestlist, 'login'))) {
+ Logger::log('Player "'. $login .'" added to the guestlist');
$this->maniaControl->getClient()->addGuest($login);
+ $this->checkNonGuestlistedPlayers = true;
return true;
} else {
return false;
@@ -177,12 +213,78 @@ class GuestlistManager implements CommandListener, Plugin {
}
/**
- * load from the guestlist file
+ * handle Remove from GL command
+ *
+ * @param array $chat
+ * @param Player $player
+ * @return void
+ */
+ public function handleRemove(Array $chat, Player $player) {
+ $command = explode(" ", $chat[1][2]);
+ $playerToRemove = $command[1];
+
+ if (empty($playerToRemove)) {
+ $this->maniaControl->getChat()->sendError("You must set the login or the nickname as argument", $player);
+ } else {
+ $mysqli = $this->maniaControl->getDatabase()->getMysqli();
+ $stmt = $mysqli->prepare('SELECT `login` FROM `' . PlayerManager::TABLE_PLAYERS . '` WHERE nickname LIKE ? LIMIT 1;');
+ $stmt->bind_param('s', $playerToRemove);
+ $stmt->execute();
+ $result = $stmt->get_result();
+ $array = mysqli_fetch_array($result);
+
+ if (isset($array[0])) {
+ $login = $array[0];
+ } elseif (strlen($playerToRemove) == 22) {
+ $login = $playerToRemove;
+ }
+ if ($mysqli->error) {
+ trigger_error($mysqli->error, E_USER_ERROR);
+ }
+
+ if (!isset($login)) {
+ $this->maniaControl->getChat()->sendError('Player not found. Use the nickname of already connected player or just their login', $player);
+ } else {
+ if ($this->removeLoginFromGL($login)) {
+ Logger::log('Player "'. $playerToRemove .'" removed from the guestlist by '. $player->nickname);
+ $this->maniaControl->getChat()->sendSuccess('Player "' . $playerToRemove . '" removed to the Guestlist', $player);
+ } else {
+ $this->maniaControl->getChat()->sendSuccess('Player "' . $playerToRemove . '" not in the Guestlist', $player);
+ }
+ }
+ }
+ }
+
+ /**
+ * Remove login from the guestlist
+ *
+ * @param string $login
+ * @param array $guestlist
+ */
+ public function removeLoginFromGL(String $login, ?array $guestlist = null) {
+ if ($guestlist === null) {
+ $guestlist = $this->maniaControl->getClient()->getGuestList();
+ }
+
+ if (in_array($login, array_column($guestlist, 'login'))) {
+ Logger::log('Player "'. $login .'" removed from the guestlist');
+ $this->maniaControl->getClient()->removeGuest($login);
+ $this->checkNonGuestlistedPlayers = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * hangle Load GL command
*
* @param array $chat
* @param \ManiaControl\Players\Player $player
- */
- public function doloadgl(Array $chat, Player $player) {
+ */
+ public function handleLoad(Array $chat, Player $player) {
+ $guestlist = '';
+
$text = explode(" ",$chat[1][2]);
if (count($text) > 1 && $text[1] != "") {
$guestlist = $text[1];
@@ -193,30 +295,69 @@ class GuestlistManager implements CommandListener, Plugin {
} else {
$guestlist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_GUESTLIST_FILE);
}
- if ($guestlist === "" || is_file($this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist)) {
- $this->maniaControl->getClient()->loadGuestList($guestlist);
- $this->maniaControl->getChat()->sendSuccess( "Guestlist loaded!" , $player);
- } else {
- $this->maniaControl->getChat()->sendError("Impossible to load the guestlist file" , $player);
+
+ try {
+ if ($guestlist === "") {
+ Logger::log('Player "'. $player->nickname .'" loaded default guestlist');
+ $this->maniaControl->getClient()->loadGuestList();
+ $this->checkNonGuestlistedPlayers = true;
+ } else {
+ $filepath = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist;
+ if (is_file($filepath)) {
+ Logger::log('Player "'. $player->nickname .'" loaded guestlist file: '. $guestlist);
+ $this->maniaControl->getClient()->loadGuestList($guestlist);
+ $this->checkNonGuestlistedPlayers = true;
+ } else {
+ $this->maniaControl->getChat()->sendError("No guestlist file: ". $filepath, $player);
+ Logger::logError("Can't load guestlist, no file: ". $filepath);
+ }
+ }
+
+ $this->maniaControl->getChat()->sendSuccess("Guestlist loaded!", $player);
+ } catch (\Throwable $th) {
+ $this->maniaControl->getChat()->sendError("Can't load guestlist: ". $th->getMessage(), $player);
+ Logger::logError("Can't load guestlist: ". $th->getMessage());
}
}
/**
- * save to the guestlist file
+ * handle Save GL command
*
* @param array $chat
* @param \ManiaControl\Players\Player $player
- */
- public function dosavegl(Array $chat, Player $player) {
- try {
- $guestlist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_GUESTLIST_FILE);
-
- if ($guestlist !== "") {
- $filepath = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist;
+ */
+ public function handleSave(Array $chat, Player $player) {
+ $guestlist = '';
+ $text = explode(" ",$chat[1][2]);
+ if (count($text) > 1 && $text[1] != "") {
+ $guestlist = $text[1];
- if (!is_file($filepath)) {
- file_put_contents($filepath, '');
- }
+ if (substr($guestlist , -4) != ".txt" && substr($guestlist , -4) != ".xml") {
+ $guestlist .= ".txt";
+ }
+ } else {
+ $guestlist = $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_GUESTLIST_FILE);
+ }
+
+ if ($guestlist === "") {
+ $this->maniaControl->getChat()->sendError('No guestlist file provided');
+ return;
+ }
+
+ try {
+ $filepath = $this->maniaControl->getServer()->getDirectory()->getUserDataFolder() . DIRECTORY_SEPARATOR . "Config" . DIRECTORY_SEPARATOR . $guestlist;
+ $directory = dirname($filepath);
+
+ /**
+ * The server can't save a file if it was not loaded before: https://forum.nadeo.com/viewtopic.php?p=11976
+ * this is a workaround
+ */
+ if (!is_dir($directory)) {
+ mkdir($directory, 0755, true);
+ }
+
+ if (!is_file($filepath)) {
+ file_put_contents($filepath, '');
}
// Workaround when the file was never loaded by the server
@@ -228,9 +369,11 @@ class GuestlistManager implements CommandListener, Plugin {
$this->maniaControl->getClient()->addGuest($guest->login);
}
+ Logger::log('Player "'. $player->nickname .'" saved guestlist file: '. $guestlist);
$this->maniaControl->getClient()->saveGuestList($guestlist);
+ $this->checkNonGuestlistedPlayers = true;
- $this->maniaControl->getChat()->sendSuccess("Guestlist saved!" , $player);
+ $this->maniaControl->getChat()->sendSuccess("Guestlist saved!", $player);
} catch (\Exception $e) {
Logger::logError("Impossible to save guestlist: " . $e->getMessage());
$this->maniaControl->getChat()->sendError("Impossible to save guestlist: " . $e->getMessage(), $player);
@@ -238,13 +381,107 @@ class GuestlistManager implements CommandListener, Plugin {
}
/**
- * clean the guestlist
+ * handle Clear GL command
*
* @param array $chat
* @param \ManiaControl\Players\Player $player
- */
- public function docleangl(Array $chat, Player $player) {
+ */
+ public function handleClear(Array $chat, Player $player) {
+ Logger::log('Guestlist cleared by '. $player->nickname);
$this->maniaControl->getClient()->cleanGuestList();
- $this->maniaControl->getChat()->sendSuccess( "Guestlist cleaned!" , $player);
+ $this->checkNonGuestlistedPlayers = true;
+ $this->maniaControl->getChat()->sendSuccess("Guestlist cleaned!", $player);
+ if ($this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ADD_ADMINS)) {
+ $this->maniaControl->getChat()->sendSuccess("Re-adding admins to the guestlist", $player);
+ $this->addAdminsToGuestlist();
+ }
+ }
+
+ /**
+ * handle Kick non-guestlisted players command
+ *
+ * @param array $chat
+ * @param \ManiaControl\Players\Player $player
+ */
+ public function handleKickAll(Array $chat, Player $player) {
+ Logger::log('All non-guestlisted players kicked by '. $player->nickname);
+ $kicked = $this->kickNonGuestlistedPlayers();
+ $this->maniaControl->getChat()->sendSuccess($kicked . ' players kicked', $player);
+ }
+
+ /**
+ * Kick non-guestlist players from the server
+ *
+ * @return int
+ */
+ private function kickNonGuestlistedPlayers() {
+ $kicked = 0;
+ $guests = array_column($this->maniaControl->getClient()->getGuestList(), 'login');
+ foreach ($this->maniaControl->getPlayerManager()->getPlayers() as $player) {
+ if (!in_array($player->login, $guests)) {
+ try {
+ Logger::log('Player "'. $player->nickname .'" kicked from the server as not guestlisted');
+ $this->maniaControl->getClient()->kick($player->nickname, "You are not guestlisted on the server");
+ $kicked++;
+ } catch (\Throwable $th) {
+ Logger::logError("Can't kick ". $player->nickname .": ". $th->getMessage());
+ }
+ }
+ }
+ return $kicked;
+ }
+
+ /**
+ * add Admins to GL
+ *
+ * @param \ManiaControl\Players\Player $player
+ */
+ private function addAdminsToGuestlist() {
+ if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ADD_ADMINS)) return;
+
+ $guestlist = $this->maniaControl->getClient()->getGuestList();
+
+ foreach ($this->maniaControl->getAuthenticationManager()->getAdmins() as $admin) {
+ if ($this->maniaControl->getAuthenticationManager()->checkRight($admin, $this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ADMIN_LEVEL))) continue;
+ $this->addLoginToGL($admin->login, $guestlist);
+ }
+ }
+
+ /**
+ * handle Auth Level changed callback
+ *
+ * @param \ManiaControl\Players\Player $player
+ */
+ public function handleAuthLevelChanged(Player $player) {
+ if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ADD_ADMINS)) return;
+
+ $guestlist = $this->maniaControl->getClient()->getGuestList();
+
+ $isGuestlisted = in_array($player->login, array_column($guestlist, 'login'));
+ $isAdmin = $this->maniaControl->getAuthenticationManager()->checkRight($player,$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ADMIN_LEVEL));
+
+ if (!$isGuestlisted && $isAdmin) {
+ $this->addLoginToGL($player->login, $guestlist);
+ $this->maniaControl->getChat()->sendSuccessToAdmins('New admin "'. $player->nickname . '" automatically added to the guestlist');
+ Logger::log('New admin "'. $player->nickname . '" automatically added to the guestlist');
+ } else if ($isGuestlisted && !$isAdmin) {
+ $this->maniaControl->getChat()->sendErrorToAdmins('Non-admin "'. $player->nickname . '" is still in the guestlist. Remove them manually if needed');
+ }
+ }
+
+ /**
+ * handle Player connect callback
+ */
+ public function handlePlayerConnect() {
+ if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ENFORCE_GUESTLIST)) return;
+ $this->checkNonGuestlistedPlayers = true;
+ }
+
+ /**
+ * handle Setting changed callback
+ */
+ public function handleSettingChanged() {
+ if (!$this->maniaControl->getSettingManager()->getSettingValue($this, self::SETTING_ENFORCE_GUESTLIST)) return;
+ $this->checkNonGuestlistedPlayers = true;
}
}