├── .gitignore ├── plugin.yml ├── resources ├── config.yml ├── messages.yml ├── mysql_tickets.sql └── mysql_users.sql └── src └── ProjectInfinity └── ReportRTS ├── ReportRTS.php ├── command ├── ReportRTSCommand.php ├── TicketCommand.php └── sub │ ├── AssignTicket.php │ ├── BroadcastMessage.php │ ├── ClaimTicket.php │ ├── CloseTicket.php │ ├── HoldTicket.php │ ├── ListStaff.php │ ├── OpenTicket.php │ ├── ReadTicket.php │ ├── ReopenTicket.php │ ├── TeleportTicket.php │ └── UnclaimTicket.php ├── data └── Ticket.php ├── lib └── flintstone │ ├── Flintstone.php │ ├── FlintstoneDB.php │ ├── FlintstoneException.php │ └── depend │ ├── FormatterInterface.php │ ├── JsonFormatter.php │ └── SerializeFormatter.php ├── listener └── RTSListener.php ├── persistence ├── DataProvider.php ├── FlintstoneDataProvider.php └── MySQLDataProvider.php ├── task ├── LoginTask.php └── MySQLKeepAliveTask.php └── util ├── MessageHandler.php ├── PermissionHandler.php └── ToolBox.php /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse stuff 2 | /.classpath 3 | /.project 4 | /.settings 5 | 6 | # NetBeans 7 | /nbproject 8 | 9 | # IntelliJ stuff 10 | /*.eml 11 | /*.iml 12 | /.idea 13 | 14 | # vim 15 | .*.sw[a-p] 16 | 17 | # Mac filesystem dust 18 | .DS_Store 19 | 20 | # Ignore scripts. 21 | *.sh 22 | 23 | # Ignore RTS flat files. 24 | *.dat.gz -------------------------------------------------------------------------------- /plugin.yml: -------------------------------------------------------------------------------- 1 | name: ReportRTS 2 | main: ProjectInfinity\ReportRTS\ReportRTS 3 | version: 1.1.4 4 | api: [3.0.0] 5 | author: ProjectInfinity 6 | commands: 7 | ticket: 8 | description: "General ticket cmd for ReportRTS" 9 | usage: "/ticket " 10 | permission: "reportrts.ticket" 11 | aliases: [report] 12 | default: op 13 | reportrts: 14 | description: "General ReportRTS management command" 15 | usage: "/reportrts " 16 | permission: "reportrts.rts" 17 | aliases: [rts] 18 | default: op 19 | -------------------------------------------------------------------------------- /resources/config.yml: -------------------------------------------------------------------------------- 1 | command: 2 | readTicket: "read" 3 | openTicket: "open" 4 | closeTicket: "close" 5 | reopenTicket: "reopen" 6 | claimTicket: "claim" 7 | assignTicket: "assign" 8 | unclaimTicket: "unclaim" 9 | holdTicket: "hold" 10 | teleportToTicket: "tp" 11 | broadcastToStaff: "broadcast" 12 | listStaff: "staff" 13 | 14 | ticket: 15 | delay: 60 16 | max: 5 17 | hideOffline: false 18 | perPage: 5 19 | preventDuplicates: true 20 | nag: 5 21 | nagHeld: false 22 | minimumWords: 3 23 | 24 | storage: 25 | type: flintstone 26 | host: "127.0.0.1" 27 | port: 3306 28 | username: "username" 29 | password: "password" 30 | database: "minecraft" 31 | 32 | general: 33 | hideInvisibleStaff: true 34 | debug: false -------------------------------------------------------------------------------- /resources/messages.yml: -------------------------------------------------------------------------------- 1 | broadcastMessage: '%white%[%red%Staff%white%] %red%{0}: %green%{1}' 2 | 3 | generalPermissionError: '%yellow%You need permission to do that: {0}' 4 | generalError: '%red%An error occurred. Reference: {0}' 5 | generalOpenTickets: '%green%There are {0} open tickets. Type /{1} to see them.' 6 | generalOpenHeldTicket: '%green%There are {0} open tickets and {1} tickets on hold. Type /{2} to see them.' 7 | generalNoTickets: '%white%There are no tickets at this time.' 8 | generalRequestNotFound: '%red%Ticket #{0} was not found.' 9 | generalSetupNotDone: '%red%ReportRTS has not been set up! Use /reportrts setup.' 10 | 11 | banUser: '%gold%{0} has banned {1} from opening tickets.' 12 | unbanUser: '%gold%{0} has unbanned {1} from opening tickets.' 13 | 14 | checkNoTickets: '%gold%There are no tickets right now.' 15 | closedNoTickets: '%gold%There are no closed tickets.' 16 | 17 | assignTicket: '%gold%{0} has been assigned to ticket #{1}.' 18 | assignNotOpen: '%red%You may only assign open tickets to someone.' 19 | assignUser: '%gold%Your ticket has been assigned to {0}.' 20 | assignText: '%gold%Ticket text: %yellow%{0}' 21 | claimTicket: '%gold%{0} is now handling ticket #{1}.' 22 | claimNotOpen: '%red%You may only claim open tickets.' 23 | claimUser: '%gold%{0} is now handling your ticket.' 24 | claimText: '%gold%Ticket text: %yellow%{0}' 25 | unclaimTicMod: '%gold%{0} is no longer handling ticket #{1}.' 26 | unclaimTicSelf: '%gold%Ticket #{0} has been unclaimed.' 27 | unclaimNotClaimed: '%red%You may only unclaim tickets that are claimed.' 28 | unclaimUser: '%gold%{0} is no longer handling your ticket.' 29 | unclaimText: '%gold%Ticket text: %yellow%{0}' 30 | 31 | completedTic: '%gold%Ticket #{0} was closed by {1}.' 32 | completedTicMulti: '%gold%While you were gone, {0} tickets were closed. Use /{1} to check your currently open tickets.' 33 | completedUser: '%gold%{0} completed your ticket.' 34 | completedUserOffline: '%gold%One of your tickets have been completed while you were offline.' 35 | completedText: '%gold%Ticket text: %yellow%{0} %gold%Comment: %yellow%{1}' 36 | 37 | holdTicket: '%gold%Ticket #{0} was put on hold by {1}' 38 | holdNoTickets: '%gold%There are no tickets on hold right now.' 39 | holdUser: '%gold%Your ticket was put on hold by {0}' 40 | holdText: '%gold%Ticket text: %yellow%{0} %gold%Reason: %yellow%{1}' 41 | 42 | ticketOpenedUser: '%gold%You opened a ticket. A staff member should be with you soon.' 43 | ticketOpenedMod: '%green%A new ticket has been opened by {0}, id assigned #{1}.' 44 | ticketTooManyOpen: '%red%You have too many open tickets, please wait before opening more.' 45 | ticketTooFast: '%red%You need to wait {0} seconds before attempting to open another ticket.' 46 | ticketTooShort: '%red%Your ticket needs to contain at least {0} words.' 47 | ticketDuplicate: '%red%Your ticket has not been opened because it was detected as a duplicate.' 48 | 49 | staffListMessage: '%aqua%Staff online: %yellow%{0}' 50 | staffListMessageSeparator: '%yellow%, ' 51 | staffListNoStaff: '%yellow%There are no staff members online.' 52 | 53 | reopenedTicket: '%gold%{0} has reopened ticket #{1}' 54 | reopenedTicketSelf: '%gold%Ticket #{0} has been reopened.' 55 | 56 | teleportToTicket: '%blue%Teleported to ticket #{0}.' 57 | teleportedUser: '%gold%You were teleported to a different server to handle a ticket. Type {0} to teleport again.' 58 | outdatedPlugin: '[ReportRTS] %red%You are not running the latest recommended build! Recommended build is: %gold%{0}' -------------------------------------------------------------------------------- /resources/mysql_tickets.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `reportrts_tickets` ( 2 | `id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT , 3 | `userId` int(10) UNSIGNED NOT NULL DEFAULT 0 , 4 | `staffId` int(10) UNSIGNED NULL DEFAULT 0 , 5 | `timestamp` int(10) UNSIGNED NOT NULL DEFAULT 0 , 6 | `staffTime` int(10) UNSIGNED NULL DEFAULT 0 , 7 | `comment` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL , 8 | `world` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' , 9 | `x` int(10) NOT NULL DEFAULT 0 , 10 | `y` int(10) NOT NULL DEFAULT 0 , 11 | `z` int(10) NOT NULL DEFAULT 0 , 12 | `yaw` smallint(6) NOT NULL DEFAULT 0 , 13 | `pitch` smallint(6) NOT NULL DEFAULT 0 , 14 | `text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' , 15 | `status` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 , 16 | `notified` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 , 17 | PRIMARY KEY (`id`) 18 | ); -------------------------------------------------------------------------------- /resources/mysql_users.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `reportrts_users` ( 2 | `uid` int(10) UNSIGNED NOT NULL AUTO_INCREMENT , 3 | `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL , 4 | `banned` tinyint(1) UNSIGNED NULL DEFAULT 0 , 5 | PRIMARY KEY (`uid`) 6 | ); -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/ReportRTS.php: -------------------------------------------------------------------------------- 1 | saveDefaultConfig(); 50 | 51 | # Set up MessageHandler. 52 | MessageHandler::load(); 53 | 54 | if($this->isDefault()) { 55 | $this->getLogger()->info("**** You need to set up your storage settings! You can start by typing /rts setup. OPs will automatically be welcomed with the setup screen until you have finished it. ****"); 56 | } else { 57 | # Server is not running on default settings that prevent the plugin from operating, therefore load settings. 58 | $this->reloadSettings(); 59 | } 60 | 61 | # Register commands. 62 | $this->getCommand("ticket")->setExecutor(new TicketCommand($this)); 63 | $this->getCommand("reportrts")->setExecutor(new ReportRTSCommand($this)); 64 | 65 | # Register event listeners. 66 | $this->getServer()->getPluginManager()->registerEvents(new RTSListener($this), $this); 67 | } 68 | 69 | public function onDisable() { 70 | # Close data provider connection. 71 | if($this->provider !== null) $this->provider->close(); 72 | 73 | # Cleanup, in case of a reload. 74 | unset($this->staff); 75 | unset($this->notifications); 76 | unset($this->commands); 77 | ReportRTS::$tickets = null; 78 | } 79 | 80 | public function reloadSettings() { 81 | $this->saveDefaultConfig(); 82 | $this->reloadConfig(); 83 | 84 | # Shows debug information in the plugin if enabled. 85 | $this->debug = (boolean) $this->getConfig()->getNested("general.debug"); 86 | # Should the plugin hide invisible staff from the list command? 87 | $this->vanish = (boolean) $this->getConfig()->getNested("general.hideInvisibleStaff"); 88 | 89 | # Ticket configuration. 90 | $this->ticketMax = $this->getConfig()->get("ticket")["max"]; 91 | $this->ticketDelay = $this->getConfig()->get("ticket")["delay"]; 92 | $this->ticketMinWords = $this->getConfig()->get("ticket")["minimumWords"]; 93 | $this->ticketPerPage = $this->getConfig()->get("ticket")["perPage"]; 94 | $this->ticketPreventDuplicates = $this->getConfig()->get("ticket")["preventDuplicates"]; 95 | $this->ticketNag = $this->getConfig()->get("ticket")["nag"]; 96 | $this->ticketNagHeld = $this->getConfig()->get("ticket")["nagHeld"]; 97 | $this->ticketHideOffline= $this->getConfig()->get("ticket")["hideOffline"]; 98 | 99 | # Set up ticket array. 100 | self::$tickets = []; 101 | 102 | # Set up storage. 103 | $provider = $this->getConfig()->get("storage")["type"]; 104 | unset($this->provider); 105 | switch(strtoupper($provider)) { 106 | 107 | case "MEMORY": 108 | case "NOSQL": 109 | case "FLINTSTONE": 110 | if($this->debug) $this->getLogger()->info("Using Flintstone data provider."); 111 | $provider = new FlintstoneDataProvider($this); 112 | break; 113 | 114 | case "MYSQL": 115 | if($this->debug) $this->getLogger()->info("Using MySQL data provider."); 116 | $provider = new MySQLDataProvider($this); 117 | break; 118 | 119 | default: 120 | # Dummy provider not provided. So let's disable the plugin. 121 | $this->getLogger()->warning("Unrecognized storage type, disabling plugin to avoid errors."); 122 | $this->getPluginLoader()->disablePlugin($this); 123 | break; 124 | } 125 | 126 | if(!isset($this->provider) or !($this->provider instanceof DataProvider)) { 127 | $this->provider = $provider; 128 | } 129 | 130 | # Make sure the array is sorted correctly, later this should be done after loading all data from a database. 131 | ksort(ReportRTS::$tickets); 132 | 133 | # Command configuration. 134 | $this->commands = []; 135 | $this->commands['readTicket'] = strtoupper($this->getConfig()->get("command")["readTicket"]); 136 | $this->commands['openTicket'] = strtoupper($this->getConfig()->get("command")["openTicket"]); 137 | $this->commands['holdTicket'] = strtoupper($this->getConfig()->get("command")["holdTicket"]); 138 | $this->commands['closeTicket'] = strtoupper($this->getConfig()->get("command")["closeTicket"]); 139 | $this->commands['reopenTicket'] = strtoupper($this->getConfig()->get("command")["reopenTicket"]); 140 | $this->commands['claimTicket'] = strtoupper($this->getConfig()->get("command")["claimTicket"]); 141 | $this->commands['assignTicket'] = strtoupper($this->getConfig()->get("command")["assignTicket"]); 142 | $this->commands['unclaimTicket'] = strtoupper($this->getConfig()->get("command")["unclaimTicket"]); 143 | $this->commands['teleportToTicket'] = strtoupper($this->getConfig()->get("command")["teleportToTicket"]); 144 | $this->commands['broadcastToStaff'] = strtoupper($this->getConfig()->get("command")["broadcastToStaff"]); 145 | $this->commands['listStaff'] = strtoupper($this->getConfig()->get("command")["listStaff"]); 146 | 147 | # Setup notification array. 148 | $this->notifications = []; 149 | 150 | # Setup staff array. 151 | $this->staff = []; 152 | 153 | } 154 | 155 | /** @return Ticket[] */ 156 | public static function getTickets() { 157 | return self::$tickets; 158 | } 159 | 160 | public function messageStaff($message) { 161 | foreach($this->staff as $staff) { 162 | $player = $this->getServer()->getPlayer($staff); 163 | if($player == null) continue; 164 | $player->sendMessage($message); 165 | } 166 | $this->getLogger()->info($message); 167 | } 168 | 169 | /** @param DataProvider $provider */ 170 | public function setDataProvider(DataProvider $provider) { 171 | $this->provider = $provider; 172 | } 173 | 174 | /** @return DataProvider */ 175 | public function getDataProvider() { 176 | return $this->provider; 177 | } 178 | 179 | private function isDefault() { 180 | return ( 181 | strtoupper($this->getConfig()->get("storage")["type"]) === "MYSQL" && 182 | strtoupper($this->getConfig()->get("storage")["host"]) === "127.0.0.1" && 183 | $this->getConfig()->get("storage")["port"] === 3306 && 184 | strtoupper($this->getConfig()->get("storage")["username"]) === "USERNAME" && 185 | strtoupper($this->getConfig()->get("storage")["password"]) === "PASSWORD" && 186 | strtoupper($this->getConfig()->get("storage")["database"]) === "MINECRAFT" 187 | ); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/ReportRTSCommand.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 28 | $this->data = $plugin->getDataProvider(); 29 | } 30 | 31 | public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool { 32 | if(count($args) == 0) return false; 33 | 34 | switch(strtoupper($args[0])) { 35 | 36 | case "RELOAD": 37 | if(!$sender->hasPermission(PermissionHandler::canReload)) { 38 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReload)); 39 | return true; 40 | } 41 | $this->plugin->reloadSettings(); 42 | break; 43 | 44 | case "BAN": 45 | if(!$sender->hasPermission(PermissionHandler::canBan)) { 46 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canBan)); 47 | return true; 48 | } 49 | if(count($args) < 2) { 50 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Please specify a player.")); 51 | return true; 52 | } 53 | 54 | # Attempt to get the target that you wish to ban. 55 | $target = $this->plugin->getServer()->getPlayer($args[1]); 56 | if($target === null) { 57 | # User is not online, let's see if they exist in the database. 58 | $target = $this->data->getUser($args[1]); 59 | if($target['id'] == 0) { 60 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $args[1])); 61 | return true; 62 | } 63 | } 64 | 65 | # Check if target was gotten through getPlayer or using getUser. 66 | if($target instanceof Player) { 67 | $result = $this->data->setUserStatus($target->getName(), true); 68 | } else { 69 | $result = $this->data->setUserStatus($target['username'], true); 70 | } 71 | 72 | # Check if user status was set. 73 | if($result < 1) { 74 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "No affected users. User may already be banned.")); 75 | return true; 76 | } 77 | 78 | $this->plugin->messageStaff(sprintf(MessageHandler::$userBanned, $sender->getName(), $args[1])); 79 | 80 | break; 81 | 82 | case "UNBAN": 83 | if(!$sender->hasPermission(PermissionHandler::canBan)) { 84 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canBan)); 85 | return true; 86 | } 87 | if(count($args) < 2) { 88 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Please specify a player.")); 89 | return true; 90 | } 91 | 92 | # Attempt to get the target that you wish to unban. 93 | $target = $this->plugin->getServer()->getPlayer($args[1]); 94 | if($target === null) { 95 | # User is not online, let's see if they exist in the database. 96 | $target = $this->data->getUser($args[1]); 97 | if($target['id'] == 0) { 98 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $args[1])); 99 | return true; 100 | } 101 | } 102 | 103 | # Check if target was gotten through getPlayer or using getUser. 104 | if($target instanceof Player) { 105 | $result = $this->data->setUserStatus($target->getName(), false); 106 | } else { 107 | $result = $this->data->setUserStatus($target['username'], false); 108 | } 109 | 110 | # Check if user status was set. 111 | if($result < 1) { 112 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "No affected users. This shouldn't happen.")); 113 | return true; 114 | } 115 | 116 | $this->plugin->messageStaff(sprintf(MessageHandler::$userUnbanned, $args[1])); 117 | 118 | break; 119 | 120 | case "RESET": 121 | if(!$sender->isOp()) { 122 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You need to be OP to do that.")); 123 | return true; 124 | } 125 | 126 | $this->data->reset(); 127 | 128 | $sender->sendMessage(TextFormat::RED."[ReportRTS] You deleted all tickets and users."); 129 | $this->plugin->getLogger()->alert($sender->getName()." deleted all tickets and users from ReportRTS."); 130 | 131 | break; 132 | 133 | case "STATS": 134 | if(!$sender->hasPermission(PermissionHandler::canSeeStats)) { 135 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canSeeStats)); 136 | return true; 137 | } 138 | 139 | $data = $this->data->getTop(10); 140 | # Check if data is empty. This may happen when the passed $limit variable is not an integer. 141 | if(count($data) == 0) { 142 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "getTop() returned an empty array.")); 143 | return true; 144 | } 145 | 146 | $sender->sendMessage(TextFormat::YELLOW."---- Top 10 ----"); 147 | $sender->sendMessage(TextFormat::YELLOW.". : "); 148 | $i = 0; 149 | foreach($data as $array => $value) { 150 | $i++; 151 | $sender->sendMessage(TextFormat::YELLOW.$i.". ". $array." : ".$value); 152 | } 153 | 154 | break; 155 | 156 | case "FIND": 157 | case "SEARCH": 158 | if(!$sender->hasPermission(PermissionHandler::canSearch)) { 159 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canSearch)); 160 | return true; 161 | } 162 | if(count($args) < 3) { 163 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Syntax is /rts search ")); 164 | return true; 165 | } 166 | 167 | $action = $args[2]; 168 | $player = $args[1]; 169 | # If page is specified, we should use that as opposed to the default. 170 | if(count($args) === 4) 171 | $page = $args[3]; 172 | else 173 | $page = 1; 174 | 175 | if($page < 1) $page = 1; 176 | 177 | # Set cursor start position. 178 | $i = ($page * $this->plugin->ticketPerPage) - $this->plugin->ticketPerPage; 179 | 180 | $tickets = null; 181 | 182 | if(strtoupper($action) === "CLOSED") { 183 | $tickets = $this->data->getHandledBy($player, $i, $this->plugin->ticketPerPage); 184 | } 185 | if(strtoupper($action) === "OPENED") { 186 | $tickets = $this->data->getOpenedBy($player, $i, $this->plugin->ticketPerPage); 187 | } 188 | 189 | # The player specified does not exist! 190 | if($tickets === false) { 191 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $player)); 192 | return true; 193 | } 194 | 195 | # No tickets were returned somehow or the user specified an invalid action. 196 | if($tickets === null) { 197 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Tickets are null! /rts search ")); 198 | return true; 199 | } 200 | 201 | # Send a message explaining which page we're on. 202 | $sender->sendMessage(TextFormat::AQUA."--------- Page ".$page." -".TextFormat::YELLOW." ".strtoupper($action)." ".TextFormat::AQUA."---------"); 203 | 204 | foreach($tickets as $ticket) { 205 | $substring = ToolBox::shortenMessage($ticket->getMessage()); 206 | # If the ticket is claimed, we should specify so by altering the text and colour of it. 207 | $substring = ($ticket->getStatus() == 1) ? TextFormat::LIGHT_PURPLE."Claimed by ".$ticket->getStaffName() : TextFormat::GRAY.$substring; 208 | # Send final message. 209 | $sender->sendMessage(TextFormat::GOLD."#".$ticket->getId()." ".ToolBox::timeSince($ticket->getTimestamp())." by ". 210 | (ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED).$ticket->getName().TextFormat::GOLD." - ".$substring); 211 | } 212 | break; 213 | 214 | case "HELP": 215 | if(!PermissionHandler::canSeeHelp) { 216 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canSeeHelp)); 217 | return true; 218 | } 219 | 220 | # Start messaging the player. 221 | $sender->sendMessage(TextFormat::GREEN."====[ ".TextFormat::GOLD."ReportRTS Help ".TextFormat::GREEN."]===="); 222 | $sender->sendMessage(TextFormat::GOLD."/ticket read ".TextFormat::RESET."-".TextFormat::YELLOW." See ticket details"); 223 | $sender->sendMessage(TextFormat::GOLD."/ticket claim ".TextFormat::RESET."-".TextFormat::YELLOW." Claim a ticket, no toe stepping"); 224 | $sender->sendMessage(TextFormat::GOLD."/ticket unclaim ".TextFormat::RESET."-".TextFormat::YELLOW." Unlaim a ticket"); 225 | $sender->sendMessage(TextFormat::GOLD."/ticket close ".TextFormat::RESET."-".TextFormat::YELLOW." Closes a ticket, optional comment"); 226 | $sender->sendMessage(TextFormat::GOLD."/ticket hold ".TextFormat::RESET."-".TextFormat::YELLOW." Put ticket on hold, optional reason"); 227 | $sender->sendMessage(TextFormat::GOLD."/ticket open ".TextFormat::RESET."-".TextFormat::YELLOW." Opens a ticket"); 228 | $sender->sendMessage(TextFormat::GOLD."/ticket reopen ".TextFormat::RESET."-".TextFormat::YELLOW." Reopens specified ticket"); 229 | $sender->sendMessage(TextFormat::GOLD."/ticket staff ".TextFormat::RESET."-".TextFormat::YELLOW." See online staff"); 230 | $sender->sendMessage(TextFormat::GOLD."/ticket tp ".TextFormat::RESET."-".TextFormat::YELLOW." Teleport to ticket"); 231 | $sender->sendMessage(TextFormat::GOLD."/ticket broadcast ".TextFormat::RESET."-".TextFormat::YELLOW." Message online staff"); 232 | $sender->sendMessage(TextFormat::GOLD."/reportrts ".TextFormat::RESET."-".TextFormat::YELLOW." General ReportRTS command."); 233 | break; 234 | 235 | case "DUTY": 236 | if(!($sender instanceof Player)) { 237 | $sender->sendMessage(TextFormat::RED."Only players can change duty status."); 238 | return true; 239 | } 240 | if(!$sender->hasPermission(PermissionHandler::isStaff)) { 241 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::isStaff)); 242 | return true; 243 | } 244 | 245 | # Show current duty status if there are less than 2 arguments. 246 | if(count($args) < 2) { 247 | if(($staff = array_search($sender->getName(), $this->plugin->staff)) !== false) 248 | $sender->sendMessage(TextFormat::GREEN."You are currently on duty."); 249 | else 250 | $sender->sendMessage(TextFormat::RED."You are currently off duty."); 251 | return true; 252 | } 253 | 254 | $duty = strtoupper($args[1]); 255 | if(!$duty === "ON" and !$duty === "OFF") { 256 | $sender->sendMessage(TextFormat::RED."Syntax is /rts duty on|off"); 257 | } 258 | 259 | if($duty === "ON") { 260 | if(($staff = array_search($sender->getName(), $this->plugin->staff)) === false) { 261 | array_push($this->plugin->staff, $sender->getName()); 262 | $sender->sendMessage(TextFormat::GREEN."You are now on duty."); 263 | return true; 264 | } 265 | $sender->sendMessage(TextFormat::YELLOW."You are already on duty."); 266 | } 267 | if($duty === "OFF") { 268 | if(($staff = array_search($sender->getName(), $this->plugin->staff)) !== false) { 269 | unset($this->plugin->staff[$staff]); 270 | $sender->sendMessage(TextFormat::GREEN."You are no longer on duty."); 271 | return true; 272 | } 273 | $sender->sendMessage(TextFormat::YELLOW."You are already off duty."); 274 | } 275 | break; 276 | 277 | case "NOTIF": 278 | case "NOTIFICATIONS": 279 | if(!$sender->hasPermission(PermissionHandler::canManageNotifications)) { 280 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canManageNotifications)); 281 | return true; 282 | } 283 | # Display a message with pending notifications if no arguments are given. 284 | if(count($args) <= 1) { 285 | $sender->sendMessage(TextFormat::YELLOW."There are currently ".count($this->plugin->notifications)." pending notifications."); 286 | $sender->sendMessage(TextFormat::YELLOW."Reset them using /rts notif reset"); 287 | return true; 288 | } 289 | # Incorrect syntax. Inform the user. 290 | if(strtoupper($args[1]) !== "RESET") { 291 | $sender->sendMessage(TextFormat::RED."Syntax incorrect! The correct syntax is /rts notif reset"); 292 | return true; 293 | } 294 | 295 | if(!$this->data->resetNotifications()) { 296 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Failed to reset notifications!")); 297 | return true; 298 | } 299 | 300 | $sender->sendMessage(TextFormat::GREEN."You have marked all notifications as read."); 301 | 302 | # Clean up after ourselves. 303 | unset($this->plugin->notifications); 304 | $this->plugin->notifications = []; 305 | break; 306 | 307 | case "SETUP": 308 | if(!$sender->isOp()) { 309 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You have to be OP to use this command.")); 310 | return true; 311 | } 312 | if(count($args) <= 1) { 313 | $sender->sendMessage(TextFormat::GREEN."Welcome to the ReportRTS setup! Below you will see valid actions for this command. /rts "); 314 | $sender->sendMessage("Actions: TYPE, HOST, PORT, DATABASE, USERNAME, PASSWORD"); 315 | $sender->sendMessage("When you are done, type /rts setup save. Type /rts setup to view this message again."); 316 | return true; 317 | } 318 | 319 | switch(strtoupper($args[1])) { 320 | 321 | case "TYPE": 322 | if(count($args) < 3 or $args[2] === null or $args[2] == "") { 323 | $sender->sendMessage(TextFormat::RED."Type cannot be empty or null! Supported types are: MYSQL"); 324 | return true; 325 | } 326 | if(strtoupper($args[2]) !== "MYSQL") { 327 | $sender->sendMessage(TextFormat::RED."No valid type was specified. Valid types are: MYSQL"); 328 | return true; 329 | } 330 | $this->dpType = "MYSQL"; 331 | $this->plugin->getConfig()->setNested("storage.type", "mysql"); 332 | $this->plugin->saveConfig(); 333 | $this->plugin->reloadConfig(); 334 | 335 | $sender->sendMessage(TextFormat::GREEN."Type has been set to ".$this->dpType.". Continue with /rts setup HOST "); 336 | break; 337 | 338 | case "HOST": 339 | if(count($args) < 3 or $args[2] === null or $args[2] == "" or $this->dpType !== "MYSQL") { 340 | $sender->sendMessage(TextFormat::RED."Host cannot be empty, null or specified on unsupported types. Default is likely localhost or 127.0.0.1"); 341 | return true; 342 | } 343 | 344 | $this->dpHost = $args[2]; 345 | $this->plugin->getConfig()->setNested("storage.host", $this->dpHost); 346 | $this->plugin->saveConfig(); 347 | $this->plugin->reloadConfig(); 348 | 349 | $sender->sendMessage(TextFormat::GREEN."Host has been set to ".$this->dpHost.". Continue with /rts setup PORT "); 350 | break; 351 | 352 | case "PORT": 353 | if(count($args) < 3 or !is_int((int)$args[2]) or $this->dpType !== "MYSQL") { 354 | $sender->sendMessage(TextFormat::RED."Port cannot be null, not a number or specified on unsupported types. Default is likely 3306 for MySQL"); 355 | return true; 356 | } 357 | 358 | $this->dpPort = intval($args[2]); 359 | $this->plugin->getConfig()->setNested("storage.port", $this->dpPort); 360 | $this->plugin->saveConfig(); 361 | $this->plugin->reloadConfig(); 362 | 363 | $sender->sendMessage(TextFormat::GREEN."Port has been set to ".$this->dpPort.". Continue with /rts setup USERNAME "); 364 | break; 365 | 366 | case "USERNAME": 367 | if(count($args) < 3 or $args[2] === null or $args[2] == "" or $this->dpType !== "MYSQL") { 368 | $sender->sendMessage(TextFormat::RED."Username cannot be empty, null or specified on unsupported types."); 369 | return true; 370 | } 371 | 372 | $this->dpUser = $args[2]; 373 | $this->plugin->getConfig()->setNested("storage.username", $this->dpUser); 374 | $this->plugin->saveConfig(); 375 | $this->plugin->reloadConfig(); 376 | 377 | $sender->sendMessage(TextFormat::GREEN."Username has been set to ".$this->dpUser.". Continue with /rts setup PASSWORD "); 378 | break; 379 | 380 | case "PASSWORD": 381 | if(count($args) < 3 or $args[2] === null or $args[2] == "" or $this->dpType !== "MYSQL") { 382 | $sender->sendMessage(TextFormat::RED."Password cannot be empty, null or specified on unsupported types."); 383 | return true; 384 | } 385 | 386 | $this->dpPass = $args[2]; 387 | $this->plugin->getConfig()->setNested("storage.password", $this->dpPass); 388 | $this->plugin->saveConfig(); 389 | $this->plugin->reloadConfig(); 390 | 391 | $sender->sendMessage(TextFormat::GREEN."Password has been set to ".$this->dpPass.". Continue with /rts setup DATABASE "); 392 | break; 393 | 394 | case "DATABASE": 395 | if(count($args) < 3 or $args[2] === null or $args[2] == "" or $this->dpType !== "MYSQL") { 396 | $sender->sendMessage(TextFormat::RED."Database cannot be empty, null or specified on unsupported types."); 397 | return true; 398 | } 399 | 400 | $this->dpDb = $args[2]; 401 | $this->plugin->getConfig()->setNested("storage.database", $this->dpDb); 402 | $this->plugin->saveConfig(); 403 | $this->plugin->reloadConfig(); 404 | 405 | $sender->sendMessage(TextFormat::GREEN."Database has been set to ".$this->dpDb.". Finish by typing /rts setup SAVE"); 406 | break; 407 | 408 | case "SAVE": 409 | 410 | if($this->dpType === "MYSQL") { 411 | $failed = false; 412 | 413 | if(!isset($this->dpHost)) { 414 | $failed = true; 415 | $sender->sendMessage(TextFormat::RED."Hostname is not set. /rts setup HOST "); 416 | } 417 | 418 | if(!isset($this->dpDb)) { 419 | $failed = true; 420 | $sender->sendMessage(TextFormat::RED."Database is not set. /rts setup DATABASE "); 421 | } 422 | 423 | if(!isset($this->dpPort)) { 424 | $failed = true; 425 | $sender->sendMessage(TextFormat::RED."Port is not set. /rts setup PORT "); 426 | } 427 | 428 | if(!isset($this->dpPass)) { 429 | $failed = true; 430 | $sender->sendMessage(TextFormat::RED."Password is not set. /rts setup PASSWORD "); 431 | } 432 | 433 | if(!isset($this->dpUser)) { 434 | $failed = true; 435 | $sender->sendMessage(TextFormat::RED."Username is not set. /rts setup USERNAME "); 436 | } 437 | 438 | if($failed) { 439 | $sender->sendMessage(TextFormat::RED."Some settings are not correct. Make sure they are all correct."); 440 | return true; 441 | } 442 | 443 | $this->plugin->reloadSettings(); 444 | } 445 | 446 | break; 447 | 448 | default: 449 | $sender->sendMessage("Valid actions: TYPE, HOST, PORT, DATABASE, USERNAME, PASSWORD"); 450 | $sender->sendMessage("When you are done, type /rts setup save. Type /rts setup to view this message again."); 451 | return true; 452 | } 453 | 454 | break; 455 | 456 | default: 457 | $sender->sendMessage(MessageHandler::$generalError, "No valid action specified, see /rts help."); 458 | return false; 459 | } 460 | return true; 461 | } 462 | } 463 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/TicketCommand.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 41 | 42 | # Set up sub-commands. 43 | $this->readCommand = new ReadTicket($plugin); 44 | $this->openCommand = new OpenTicket($plugin); 45 | $this->closeCommand = new CloseTicket($plugin); 46 | $this->claimCommand = new ClaimTicket($plugin); 47 | $this->holdCommand = new HoldTicket($plugin); 48 | $this->unclaimCommand = new UnclaimTicket($plugin); 49 | $this->staffCommand = new ListStaff($plugin); 50 | $this->teleportCommand = new TeleportTicket($plugin); 51 | $this->broadcastCommand = new BroadcastMessage($plugin); 52 | $this->assignCommand = new AssignTicket($plugin); 53 | $this->reopenCommand = new ReopenTicket($plugin); 54 | } 55 | 56 | public function onCommand(CommandSender $sender, Command $command, string $label, array $args): bool { 57 | 58 | if($this->plugin->debug) { 59 | /** Argument checker, ONLY FOR DEBUG MODE! */ 60 | $i = -1; 61 | foreach($args as $arg) { 62 | $i++; 63 | $this->plugin->getLogger()->info("Position: " . $i . " | Actual Position: " . ($i + 1) . " | Argument: " . $arg); 64 | } 65 | /** LOOK ABOVE **/ 66 | } 67 | 68 | if(count($args) == 0) return false; 69 | $start = 0.00; 70 | if($this->plugin->debug) $start = microtime(true) * 1000; 71 | $result = false; 72 | 73 | # Oh snap gurl. Here comes the command statements. Wish this could be a switch though... 74 | 75 | /** Read ticket. **/ 76 | if(strtoupper($args[0]) == $this->plugin->commands['readTicket']) { 77 | $result = $this->readCommand->handleCommand($sender, $args); 78 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 79 | } 80 | /** Open a ticket. **/ 81 | if(strtoupper($args[0]) == $this->plugin->commands['openTicket']) { 82 | $result = $this->openCommand->handleCommand($sender, $args); 83 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 84 | } 85 | /** Closes a ticket. **/ 86 | if(strtoupper($args[0]) == $this->plugin->commands['closeTicket']) { 87 | $result = $this->closeCommand->handleCommand($sender, $args); 88 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 89 | } 90 | /** Claim a ticket. **/ 91 | if(strtoupper($args[0]) == $this->plugin->commands['claimTicket']) { 92 | $result = $this->claimCommand->handleCommand($sender, $args); 93 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 94 | } 95 | /** Teleport to a ticket. **/ 96 | if(strtoupper($args[0]) == $this->plugin->commands['teleportToTicket']) { 97 | $result = $this->teleportCommand->handleCommand($sender, $args); 98 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 99 | } 100 | /** Unclaim a ticket. **/ 101 | if(strtoupper($args[0]) == $this->plugin->commands['unclaimTicket']) { 102 | $result = $this->unclaimCommand->handleCommand($sender, $args); 103 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 104 | } 105 | /** Hold a ticket. **/ 106 | if(strtoupper($args[0]) == $this->plugin->commands['holdTicket']) { 107 | $result = $this->holdCommand->handleCommand($sender, $args); 108 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 109 | } 110 | /** List staff. **/ 111 | if(strtoupper($args[0]) == $this->plugin->commands['listStaff']) { 112 | $result = $this->staffCommand->handleCommand($sender); 113 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 114 | } 115 | /** Broadcast to staff **/ 116 | if(strtoupper($args[0]) == $this->plugin->commands['broadcastToStaff']) { 117 | $result = $this->broadcastCommand->handleCommand($sender, $args); 118 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 119 | } 120 | /** Assign a ticket. **/ 121 | if(strtoupper($args[0]) == $this->plugin->commands['assignTicket']) { 122 | $result = $this->assignCommand->handleCommand($sender, $args); 123 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 124 | } 125 | /** Reopen a ticket. **/ 126 | if(strtoupper($args[0]) == $this->plugin->commands['reopenTicket']) { 127 | $result = $this->reopenCommand->handleCommand($sender, $args); 128 | if($this->plugin->debug) $this->plugin->getLogger()->info($sender->getName()." ".get_class($this)." took ".ToolBox::getTimeSpent($start)."ms, ".$command->getName()." ".implode(" ", $args)); 129 | } 130 | return $result; 131 | } 132 | 133 | } 134 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/AssignTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->data = $plugin->getDataProvider(); 19 | } 20 | 21 | public function handleCommand(CommandSender $sender, $args) { 22 | 23 | if(!$sender->hasPermission(PermissionHandler::canAssign)) { 24 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canAssign)); 25 | return true; 26 | } 27 | 28 | if(count($args) < 3) { 29 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You need to specify a ticket ID then a player.")); 30 | return true; 31 | } 32 | 33 | if(!ToolBox::isNumber($args[1])) { 34 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket ID must be a number. Provided: ".$args[1])); 35 | return true; 36 | } 37 | 38 | $ticketId = intval($args[1]); 39 | 40 | if(!isset(ReportRTS::$tickets[$ticketId]) or ReportRTS::$tickets[$ticketId]->getStatus() == 1) { 41 | # The ticket that the user is trying to claim is not in the array or is already claimed (not open). 42 | $sender->sendMessage(MessageHandler::$ticketNotOpen); 43 | return true; 44 | } 45 | $user = $this->data->getUser($args[2]); 46 | 47 | if($user['id'] == 0) { 48 | # Try to get the player from files. 49 | $player = $this->plugin->getServer()->getOfflinePlayer($args[2]); 50 | 51 | if($player->getFirstPlayed() === null) { 52 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $player->getName())); 53 | return true; 54 | } 55 | # Create the user since it does not exist but is online. 56 | $this->data->createUser($player->getName()); 57 | $user = $this->data->getUser($player->getName()); 58 | } 59 | 60 | $ticket = ReportRTS::$tickets[$args[1]]; 61 | 62 | $timestamp = round(microtime(true)); 63 | 64 | if($resultCode = $this->data->setTicketStatus($ticketId, $user['username'], 1, null, 0, $timestamp) and $resultCode != 1) { 65 | 66 | if($resultCode == -1) { 67 | # Username is invalid or does not exist. 68 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $user['username'])); 69 | return true; 70 | } 71 | if($resultCode == -2) { 72 | # Ticket status incompatibilities. 73 | $sender->sendMessage(MessageHandler::$ticketStatusError); 74 | return true; 75 | } 76 | if($resultCode == -3) { 77 | # Ticket does not exist. 78 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 79 | return true; 80 | } 81 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to assign ticket #".$ticketId." to ".$args[2])); 82 | return true; 83 | } 84 | 85 | # Set ticket info in the ticket array too. 86 | $ticket->setStatus(1); 87 | $ticket->setStaffName($user['username']); 88 | $ticket->setStaffId($user['id']); 89 | $ticket->setStaffTimestamp($timestamp); 90 | ReportRTS::$tickets[$args[1]] = $ticket; 91 | 92 | $player = $this->plugin->getServer()->getPlayer($ticket->getName()); 93 | if($player != null) { 94 | $player->sendMessage(sprintf(MessageHandler::$ticketAssignUser, $user['username'])); 95 | $player->sendMessage(sprintf(MessageHandler::$ticketClaimText, $ticket->getMessage())); 96 | } 97 | 98 | # Let staff know about this change. 99 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketAssign, $user['username'], $ticketId)); 100 | 101 | return true; 102 | } 103 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/BroadcastMessage.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 16 | } 17 | 18 | public function handleCommand(CommandSender $sender, $args) { 19 | 20 | if(!$sender->hasPermission(PermissionHandler::canBroadcast)) { 21 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canBroadcast)); 22 | return true; 23 | } 24 | 25 | if(count($args) < 2) { 26 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Not enough arguments.")); 27 | return true; 28 | } 29 | 30 | $args[0] = null; 31 | $message = sprintf(MessageHandler::$broadcast, $sender->getName(), trim(implode(" ", $args))); 32 | 33 | $this->plugin->messageStaff($message); 34 | # Let console know too! Otherwise he gets lonely. 35 | $this->plugin->getLogger()->info($message); 36 | 37 | return true; 38 | } 39 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/ClaimTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->data = $plugin->getDataProvider(); 19 | } 20 | 21 | public function handleCommand(CommandSender $sender, $args) { 22 | 23 | ### Check if anything is wrong with the provided input before going further. ### 24 | if(!$sender->hasPermission(PermissionHandler::canClaimTicket)) { 25 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canClaimTicket)); 26 | return true; 27 | } 28 | 29 | if(count($args) < 2) { 30 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You need to specify a ticket ID.")); 31 | return true; 32 | } 33 | 34 | if(!ToolBox::isNumber($args[1])) { 35 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket ID must be a number. Provided: ".$args[1])); 36 | return true; 37 | } 38 | 39 | $ticketId = intval($args[1]); 40 | 41 | if(!isset(ReportRTS::$tickets[$ticketId]) or ReportRTS::$tickets[$ticketId]->getStatus() == 1) { 42 | # The ticket that the user is trying to claim is not in the array or is already claimed (not open). 43 | $sender->sendMessage(MessageHandler::$ticketNotOpen); 44 | return true; 45 | } 46 | ### We're done! Let's start processing stuff. ### 47 | 48 | $ticket = ReportRTS::$tickets[$args[1]]; 49 | 50 | $timestamp = round(microtime(true)); 51 | 52 | if($resultCode = $this->data->setTicketStatus($ticketId, $sender->getName(), 1, null, 0, $timestamp) and $resultCode != 1) { 53 | 54 | if($resultCode == -1) { 55 | # Username is invalid or does not exist. 56 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $sender->getName())); 57 | return true; 58 | } 59 | if($resultCode == -2) { 60 | # Ticket status incompatibilities. 61 | $sender->sendMessage(MessageHandler::$ticketStatusError); 62 | return true; 63 | } 64 | if($resultCode == -3) { 65 | # Ticket does not exist. 66 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 67 | return true; 68 | } 69 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to claim ticket #".$ticketId)); 70 | return true; 71 | } 72 | 73 | # Set ticket info in the ticket array too. 74 | $ticket->setStatus(1); 75 | $ticket->setStaffName($sender->getName()); 76 | $ticket->setStaffId($this->data->getUser($sender->getName(), 0, true)['id']); 77 | $ticket->setStaffTimestamp($timestamp); 78 | unset(ReportRTS::$tickets[$ticketId]); 79 | ReportRTS::$tickets[$args[1]] = $ticket; 80 | 81 | $player = $this->plugin->getServer()->getPlayer($ticket->getName()); 82 | if($player != null) { 83 | $player->sendMessage(sprintf(MessageHandler::$ticketClaimUser, $sender->getName())); 84 | $player->sendMessage(sprintf(MessageHandler::$ticketClaimText, $ticket->getMessage())); 85 | } 86 | 87 | # Let staff know about this change. 88 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketClaim, $sender->getName(), $ticketId)); 89 | 90 | return true; 91 | } 92 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/CloseTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->data = $plugin->getDataProvider(); 19 | } 20 | 21 | public function handleCommand(CommandSender $sender, $args) { 22 | 23 | # TODO: Add close self. 24 | 25 | if(!$sender->hasPermission(PermissionHandler::canCloseTicket)) { 26 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canCloseTicket)); 27 | return true; 28 | } 29 | 30 | if(count($args) < 2 or !ToolBox::isNumber($args[1])) { 31 | $sender->sendMessage(sprintf(MessageHandler::$generalError, 'Correct syntax is: "/ "')); 32 | return true; 33 | } 34 | 35 | $ticketId = intval($args[1]); 36 | 37 | $ticket = null; 38 | 39 | if(isset(ReportRTS::$tickets[$ticketId])) { 40 | $ticket = ReportRTS::$tickets[$ticketId]; 41 | } else { 42 | $ticket = $this->data->getTicket($ticketId); 43 | } 44 | 45 | # Ticket does not exist. 46 | if($ticket === null) { 47 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 48 | return true; 49 | } 50 | 51 | # Check if ticket is claimed and if the user that sent the command is the same user as the one that opened the ticket. 52 | $isClaimed = $ticket->getStatus() == 1 ? strtoupper($ticket->getStaffName()) != strtoupper($sender->getName()) : false; 53 | 54 | if($isClaimed && !$sender->hasPermission(PermissionHandler::bypassTicketClaim)) { 55 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket #".$ticketId." is claimed by another player.")); 56 | return true; 57 | } 58 | 59 | # Get rid of arguments we do not want in the text. 60 | $args[0] = null; 61 | $args[1] = null; 62 | 63 | $comment = implode(" ", array_filter($args)); 64 | 65 | if($resultCode = $this->data->setTicketStatus($ticketId, $sender->getName(), 3, $comment, 0, round(microtime(true))) and $resultCode != 1) { 66 | if($resultCode == -1) { 67 | # Username is invalid or does not exist. 68 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $sender->getName())); 69 | return true; 70 | } 71 | if($resultCode == -2) { 72 | # Ticket status incompatibilities. 73 | $sender->sendMessage(MessageHandler::$ticketStatusError); 74 | return true; 75 | } 76 | if($resultCode == -3) { 77 | # Ticket does not exist. 78 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 79 | return true; 80 | } 81 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to close ticket #".$ticketId)); 82 | return true; 83 | } 84 | 85 | $ticket->setStaffName($sender->getName()); 86 | $ticket->setComment($comment); 87 | 88 | $player = $this->plugin->getServer()->getPlayer($ticket->getName()); 89 | if($player != null) { 90 | # User is online! Let's message them. 91 | $player->sendMessage(sprintf(MessageHandler::$ticketCloseUser, $sender->getName())); 92 | $player->sendMessage(sprintf(MessageHandler::$ticketCloseText, $ticket->getMessage(), trim($comment))); 93 | } else { 94 | $this->plugin->notifications[$ticketId] = $ticket; 95 | } 96 | 97 | # Let staff know about the ticket change. 98 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketClose, $ticketId, $sender->getName())); 99 | 100 | # Remove the ticket if it is located in the ticket array. 101 | if(isset(ReportRTS::$tickets[$ticketId])) { 102 | unset(ReportRTS::$tickets[$ticketId]); 103 | } 104 | 105 | return true; 106 | } 107 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/HoldTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 19 | $this->data = $plugin->getDataProvider(); 20 | } 21 | 22 | public function handleCommand(CommandSender $sender, $args) { 23 | 24 | if(!$sender->hasPermission(PermissionHandler::canHoldTicket)) { 25 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canHoldTicket)); 26 | return true; 27 | } 28 | 29 | if(count($args) < 2 or !ToolBox::isNumber($args[1])) { 30 | $sender->sendMessage(sprintf(MessageHandler::$generalError, 'Correct syntax is: "/ "')); 31 | return true; 32 | } 33 | 34 | $ticketId = intval($args[1]); 35 | 36 | # Check if ticket is open or not. You can't put a held or closed ticket on hold. 37 | if(!isset(ReportRTS::$tickets[$ticketId])) { 38 | $sender->sendMessage(MessageHandler::$ticketNotOpen); 39 | return true; 40 | } 41 | 42 | # Check if ticket is claimed and if the user that sent the command is the same user as the one that opened the ticket. 43 | $isClaimed = ReportRTS::$tickets[$ticketId]->getStatus() == 1 ? strtoupper(ReportRTS::$tickets[$ticketId]->getStaffName()) != strtoupper($sender->getName()) : false; 44 | 45 | if($isClaimed && !$sender->hasPermission(PermissionHandler::bypassTicketClaim)) { 46 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket #".$ticketId." is claimed by another player.")); 47 | return true; 48 | } 49 | 50 | # Get rid of arguments we do not want in the text. 51 | $args[0] = null; 52 | $args[1] = null; 53 | 54 | $reason = implode(" ", array_filter($args)); 55 | 56 | if($resultCode = $this->data->setTicketStatus($ticketId, $sender->getName(), 2, $reason, 0, round(microtime(true))) and $resultCode != 1) { 57 | if($resultCode == -1) { 58 | # Username is invalid or does not exist. 59 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $sender->getName())); 60 | return true; 61 | } 62 | if($resultCode == -2) { 63 | # Ticket status incompatibilities. 64 | $sender->sendMessage(MessageHandler::$ticketStatusError); 65 | return true; 66 | } 67 | if($resultCode == -3) { 68 | # Ticket does not exist. 69 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 70 | return true; 71 | } 72 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to put ticket #".$ticketId." on hold.")); 73 | return true; 74 | } 75 | 76 | $player = $this->plugin->getServer()->getPlayer(ReportRTS::$tickets[$ticketId]->getName()); 77 | if($player != null) { 78 | # User is online! Let's message them. 79 | $player->sendMessage(sprintf(MessageHandler::$ticketHoldUser, $sender->getName())); 80 | $player->sendMessage(sprintf(MessageHandler::$ticketHoldText, ReportRTS::$tickets[$ticketId]->getMessage(), trim($reason))); 81 | } 82 | 83 | # Remove the ticket from the array! 84 | unset(ReportRTS::$tickets[$ticketId]); 85 | 86 | # Let staff know that you put a ticket on hold. 87 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketHold, $ticketId, $sender->getName())); 88 | 89 | return true; 90 | } 91 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/ListStaff.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 17 | } 18 | 19 | public function handleCommand(CommandSender $sender) { 20 | 21 | if(!$sender->hasPermission(PermissionHandler::canSeeStaff)) { 22 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canSeeStaff)); 23 | return true; 24 | } 25 | 26 | $list = ""; 27 | 28 | foreach($this->plugin->staff as $staff) { 29 | $player = $this->plugin->getServer()->getPlayer($staff); 30 | if($player == null) continue; 31 | if($this->plugin->vanish and $sender instanceof Player) { 32 | if(!$sender->canSee($player)) continue; 33 | } 34 | $list .= $player->getDisplayName().MessageHandler::$separator; 35 | } 36 | 37 | # No staff is online. 38 | if(strlen($list) == 0) { 39 | $sender->sendMessage(MessageHandler::$noStaff); 40 | return true; 41 | } 42 | 43 | $sender->sendMessage(sprintf(MessageHandler::$staffList, substr($list, 0, strlen($list) - strlen(MessageHandler::$separator)))); 44 | return true; 45 | } 46 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/OpenTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 20 | $this->data = $plugin->getDataProvider(); 21 | } 22 | 23 | public function handleCommand(CommandSender $sender, $args) { 24 | 25 | if(!$sender->hasPermission(PermissionHandler::canOpenTicket)) { 26 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canOpenTicket)); 27 | return true; 28 | } 29 | if(count($args) < 2) { 30 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You have to enter a message.")); 31 | return true; 32 | } 33 | 34 | # Check if ticket message is too short. 35 | if($this->plugin->ticketMinWords > (count($args) - 1)) { 36 | $sender->sendMessage(sprintf(MessageHandler::$ticketTooShort, $this->plugin->ticketMinWords)); 37 | return true; 38 | } 39 | 40 | # Check if the sender has too many open tickets. If we do it here, we skip the DB calls. 41 | if(ToolBox::countOpenTickets($sender->getName()) >= $this->plugin->ticketMax && !($sender->hasPermission(PermissionHandler::bypassTicketLimit))) { 42 | $sender->sendMessage(MessageHandler::$ticketTooMany); 43 | return true; 44 | } 45 | 46 | # Check if the sender is opening tickets too quickly. If we do it here we skip the DB calls. 47 | if($this->plugin->ticketDelay > 0) { 48 | if(!$sender->hasPermission(PermissionHandler::bypassTicketLimit)) { 49 | $wait = ToolBox::timeDifference($sender->getName(), $this->plugin->ticketDelay); 50 | if($wait > 0) { 51 | $sender->sendMessage(sprintf(MessageHandler::$ticketTooFast, $wait)); 52 | return true; 53 | } 54 | } 55 | } 56 | 57 | if(!($sender instanceof Player)) { 58 | # Sender is more than likely console. 59 | $location = $this->plugin->getServer()->getDefaultLevel()->getSpawnLocation(); 60 | # Yaw & Pitch needs to be confirmed. 61 | $yaw = 0.0; 62 | $pitch = 0.0; 63 | } else { 64 | $location = $sender->getPosition(); 65 | $yaw = $sender->yaw; 66 | $pitch = $sender->pitch; 67 | } 68 | 69 | $args[0] = null; 70 | $message = implode(" ", array_filter($args)); 71 | 72 | if($this->plugin->ticketPreventDuplicates) { 73 | # TODO: Make this percentage based? 74 | foreach(ReportRTS::$tickets as $ticket) { 75 | if(strtolower($ticket->getName()) != strtolower($sender->getName())) continue; 76 | if(strtolower($ticket->getMessage()) != strtolower($message)) continue; 77 | $sender->sendMessage(MessageHandler::$ticketDuplicate); 78 | return true; 79 | } 80 | } 81 | 82 | $timestamp = round(microtime(true)); 83 | $ticketId = $this->data->createTicket($sender->getName(), $location->getLevel()->getName(), $location, $yaw, $pitch, $message, $timestamp); 84 | 85 | if($ticketId <= 0) { 86 | # Something went wrong. Let's see if they are banned. 87 | if($ticketId == -1) { 88 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You are banned from opening tickets.")); 89 | return true; 90 | } 91 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Could not open ticket.")); 92 | return true; 93 | } 94 | 95 | $sender->sendMessage(MessageHandler::$ticketOpenedUser); 96 | $this->plugin->getLogger()->info($sender->getName()." opened a ticket with the ID #".$ticketId."."); 97 | 98 | # Notify all staff members of the newly opened ticket. 99 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketOpenedStaff, $sender->getName(), $ticketId)); 100 | 101 | ReportRTS::$tickets[$ticketId] = new Ticket($ticketId, 0, $location->getX(), $location->getY(), $location->getZ(), null, 102 | $yaw, $pitch, $timestamp, null, $message, $sender->getName(), $location->getLevel()->getName(), null, null); 103 | 104 | return true; 105 | } 106 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/ReadTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 20 | $this->data = $plugin->getDataProvider(); 21 | } 22 | 23 | public function handleCommand(CommandSender $sender, $args) { 24 | 25 | # Not enough arguments to be anything but "/ticket read". 26 | if(count($args) < 2) { 27 | return $this->viewPage($sender, 1); 28 | } 29 | 30 | switch(strtoupper($args[1])) { 31 | case "P": 32 | case "PAGE": 33 | if(count($args) < 3) return $this->viewPage($sender, 1); 34 | return $this->viewPage($sender, ToolBox::isNumber($args[2]) ? (int) $args[2] : 1); 35 | 36 | case "H": 37 | case "HELD": 38 | if(count($args) < 3) return $this->viewHeld($sender, 1); 39 | return $this->viewHeld($sender, ToolBox::isNumber($args[2]) ? (int) $args[2] : 1); 40 | 41 | case "C": 42 | case "CLOSED": 43 | if(count($args) < 3) return $this->viewClosed($sender, 1); 44 | return $this->viewClosed($sender, ToolBox::isNumber($args[2]) ? (int) $args[2] : 1); 45 | 46 | case "SELF": 47 | return $this->viewSelf($sender); 48 | 49 | default: 50 | # Defaults to this if an action is not found. In this case we need to figure out what the user is trying to do. 51 | if(ToolBox::isNumber($args[1])) return $this->viewId($sender, (int) $args[1]); 52 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "No valid action specified.")); 53 | break; 54 | } 55 | return true; 56 | } 57 | 58 | /** 59 | * View the specified page. Defaults to 1. 60 | * @param CommandSender $sender 61 | * @param $page 62 | * @return bool 63 | */ 64 | private function viewPage(CommandSender $sender, $page) { 65 | 66 | if(!$sender->hasPermission(PermissionHandler::canReadAll)) { 67 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::isStaff)); 68 | return true; 69 | } 70 | 71 | if($page < 0) $page = 1; 72 | $a = $page * $this->plugin->ticketPerPage; 73 | # Compile a response to the user. 74 | $sender->sendMessage(TextFormat::AQUA."--------- ".count($this->plugin->getTickets())." Tickets -".TextFormat::YELLOW." Open ".TextFormat::AQUA."---------"); 75 | if(count($this->plugin->getTickets()) == 0) $sender->sendMessage(MessageHandler::$noTickets); 76 | 77 | # (page * ticketPerPage) - ticketPerPage = Sets the start location of the "cursor". 78 | for($i = ($page * $this->plugin->ticketPerPage) - $this->plugin->ticketPerPage; $i < $a && $i < count($this->plugin->getTickets()); $i++) { 79 | /* @var $ticket Ticket */ 80 | if($i < 0) $i = 1; 81 | $ticket = array_values($this->plugin->getTickets())[$i]; 82 | 83 | if($ticket == null) { 84 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket object is NULL!")); 85 | continue; 86 | } 87 | # Check if plugin hides tickets from offline players and if the player is offline. 88 | if($this->plugin->ticketHideOffline && !ToolBox::isOnline($sender->getName())) { 89 | $a++; 90 | continue; 91 | } 92 | 93 | $substring = ToolBox::shortenMessage($ticket->getMessage()); 94 | # If the ticket is claimed, we should specify so by altering the text and colour of it. 95 | $substring = ($ticket->getStatus() == 1) ? TextFormat::LIGHT_PURPLE."Claimed by ".$ticket->getStaffName() : TextFormat::GRAY.$substring; 96 | # Send final message. 97 | $sender->sendMessage(TextFormat::GOLD."#".$ticket->getId()." ".ToolBox::timeSince($ticket->getTimestamp())." by ". 98 | (ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED).$ticket->getName().TextFormat::GOLD." - ".$substring); 99 | } 100 | return true; 101 | } 102 | 103 | /** 104 | * View the specified page of held tickets. 105 | * @param CommandSender $sender 106 | * @param $page 107 | * @return bool 108 | */ 109 | private function viewHeld(CommandSender $sender, $page) { 110 | 111 | if(!$sender->hasPermission(PermissionHandler::canReadAll)) { 112 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReadAll)); 113 | return true; 114 | } 115 | 116 | # Set cursor start position. 117 | $i = ($page * $this->plugin->ticketPerPage) - $this->plugin->ticketPerPage; 118 | 119 | $heldCount = $this->data->countTickets(2); 120 | $data = $this->data->getTickets($i, $this->plugin->ticketPerPage, 2); 121 | 122 | $sender->sendMessage(TextFormat::AQUA."--------- ".$heldCount." Tickets -".TextFormat::YELLOW." Held ".TextFormat::AQUA."---------"); 123 | if($heldCount == 0) { 124 | $sender->sendMessage(MessageHandler::$holdNoTickets); 125 | return true; 126 | } 127 | 128 | # Loop tickets if any. 129 | foreach($data as $ticket) { 130 | $online = ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED; 131 | $substring = ToolBox::shortenMessage($ticket->getMessage()); 132 | 133 | $sender->sendMessage(TextFormat::GOLD."#".$ticket->getId()." ".date("d-m-Y h:i:s", $ticket->getTimestamp())." by ".$online.$ticket->getName().TextFormat::GOLD." - ".TextFormat::GRAY.$substring); 134 | } 135 | 136 | return true; 137 | } 138 | 139 | /** 140 | * View closed tickets. 141 | * @param CommandSender $sender 142 | * @param $page 143 | * @return bool 144 | */ 145 | private function viewClosed(CommandSender $sender, $page) { 146 | 147 | if(!$sender->hasPermission(PermissionHandler::canReadAll)) { 148 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReadAll)); 149 | return true; 150 | } 151 | 152 | # Set cursor start position. 153 | $i = ($page * $this->plugin->ticketPerPage) - $this->plugin->ticketPerPage; 154 | 155 | $count = $this->data->countTickets(3); 156 | $data = $this->data->getTickets($i, $this->plugin->ticketPerPage, 3); 157 | 158 | $sender->sendMessage(TextFormat::AQUA."--------- ".$count." Tickets -".TextFormat::YELLOW." Closed ".TextFormat::AQUA."---------"); 159 | if($count == 0) { 160 | $sender->sendMessage(MessageHandler::$noTickets); 161 | return true; 162 | } 163 | 164 | # Loop tickets if any. 165 | foreach($data as $ticket) { 166 | $online = ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED; 167 | $substring = ToolBox::shortenMessage($ticket->getMessage()); 168 | 169 | $sender->sendMessage(TextFormat::GOLD."#".$ticket->getId()." ".date("d-m-Y h:i:s", $ticket->getTimestamp())." by ".$online.$ticket->getName().TextFormat::GOLD." - ".TextFormat::GRAY.$substring); 170 | } 171 | 172 | return true; 173 | } 174 | 175 | /** 176 | * Views the 5 most recent unresolved tickets of 177 | * the player sending the command. 178 | * @param CommandSender $sender 179 | * @return bool 180 | */ 181 | private function viewSelf(CommandSender $sender) { 182 | 183 | if(!$sender->hasPermission(PermissionHandler::canReadSelf)) { 184 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReadSelf)); 185 | return true; 186 | } 187 | 188 | $open = 0; 189 | $i = 0; 190 | foreach($this->plugin->getTickets() as $ticket) if(strtoupper($sender->getName()) == strtoupper($ticket->getName())) $open++; 191 | 192 | $sender->sendMessage(TextFormat::AQUA."--------- ".TextFormat::YELLOW."You have ".$open." unresolved tickets".TextFormat::AQUA."---------"); 193 | if($open == 0) $sender->sendMessage(TextFormat::GOLD."You have no open tickets at this time."); 194 | 195 | foreach($this->plugin->getTickets() as $ticket) { 196 | $i++; 197 | if($i > 5) break; 198 | 199 | $substring = ToolBox::shortenMessage($ticket->getMessage()); 200 | # If the ticket is claimed, we should specify so by altering the text and colour of it. 201 | $substring = ($ticket->getStatus() == 1) ? TextFormat::LIGHT_PURPLE."Claimed by ".$ticket->getStaffName() : TextFormat::GRAY.$substring; 202 | # Send final message. 203 | $sender->sendMessage(TextFormat::GOLD."#".$ticket->getId()." ".ToolBox::timeSince($ticket->getTimestamp())." by ". 204 | (ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED).$ticket->getName().TextFormat::GOLD." - ".$substring); 205 | } 206 | 207 | 208 | return true; 209 | } 210 | 211 | /** 212 | * View a specific ticket. 213 | * @param CommandSender $sender 214 | * @param $id 215 | * @return bool 216 | */ 217 | private function viewId(CommandSender $sender, $id) { 218 | 219 | if(!$sender->hasPermission(PermissionHandler::canReadAll)) { 220 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReadAll)); 221 | return true; 222 | } 223 | 224 | if(!ToolBox::isNumber($id)) { 225 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket ID has to be a number.")); 226 | return true; 227 | } 228 | 229 | $ticket = null; 230 | 231 | if(isset(ReportRTS::$tickets[$id])) 232 | $ticket = ReportRTS::$tickets[$id]; 233 | else 234 | $ticket = $this->data->getTicket($id); 235 | 236 | if($ticket == null) { 237 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $id)); 238 | return true; 239 | } 240 | 241 | $online = ToolBox::isOnline($ticket->getName()) ? TextFormat::GREEN : TextFormat::RED; 242 | $date = date("d-m-Y h:i:s", $ticket->getTimestamp()); 243 | 244 | $status = null; 245 | $statusColor = null; 246 | 247 | if($ticket->getStatus() == 0) { 248 | $status = "Open"; 249 | $statusColor = TextFormat::YELLOW; 250 | } 251 | if($ticket->getStatus() == 1) { 252 | $status = "Claimed"; 253 | $statusColor = TextFormat::RED; 254 | } 255 | if($ticket->getStatus() == 2) { 256 | $status = "On Hold"; 257 | $statusColor = TextFormat::LIGHT_PURPLE; 258 | } 259 | if($ticket->getStatus() == 3) { 260 | $status = "Closed"; 261 | $statusColor = TextFormat::GREEN; 262 | } 263 | 264 | # Compile response. 265 | $sender->sendMessage(TextFormat::AQUA."--------- ".TextFormat::YELLOW."Ticket #".$ticket->getId()." - ".$statusColor.$status.TextFormat::AQUA." ---------"); 266 | $sender->sendMessage(TextFormat::YELLOW."Opened by ".$online.$ticket->getName().TextFormat::YELLOW." at ".TextFormat::GREEN.$date. 267 | TextFormat::YELLOW." at X:".TextFormat::GREEN.$ticket->getX().TextFormat::YELLOW.", Y:".TextFormat::GREEN.$ticket->getY().TextFormat::YELLOW.", Z:". 268 | TextFormat::GREEN.$ticket->getZ()); 269 | $sender->sendMessage(TextFormat::GRAY.$ticket->getMessage()); 270 | 271 | if($ticket->getStatus() == 1) { 272 | $time = round(microtime(true)) - $ticket->getStaffTimestamp(); 273 | $sender->sendMessage(sprintf(TextFormat::LIGHT_PURPLE."Claimed for: %u hours, %u minutes, %u seconds by %s", 274 | $time/(60*60), ($time%(60*60))/(60), (($time%(60*60))%(60)), $ticket->getStaffName())); 275 | } 276 | 277 | if($ticket->getComment() != null and $ticket->getStatus() >= 2) $sender->sendMessage(TextFormat::YELLOW."Comment: ".TextFormat::DARK_GREEN.$ticket->getComment()); 278 | 279 | return true; 280 | } 281 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/ReopenTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->data = $plugin->getDataProvider(); 19 | } 20 | 21 | public function handleCommand(CommandSender $sender, $args) { 22 | 23 | if(!$sender->hasPermission(PermissionHandler::canReopenTicket)) { 24 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canReopenTicket)); 25 | return true; 26 | } 27 | 28 | if(count($args) < 2 or !ToolBox::isNumber($args[1])) { 29 | $sender->sendMessage(sprintf(MessageHandler::$generalError, 'Correct syntax is: "/ "')); 30 | return true; 31 | } 32 | 33 | $ticketId = intval($args[1]); 34 | 35 | if($resultCode = $this->data->setTicketStatus($ticketId, $sender->getName(), 0, "", 0, round(microtime(true))) and $resultCode != 1) { 36 | if($resultCode == -1) { 37 | # Username is invalid or does not exist. 38 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $sender->getName())); 39 | return true; 40 | } 41 | if($resultCode == -2) { 42 | # Ticket status incompatibilities. 43 | $sender->sendMessage(MessageHandler::$ticketStatusError); 44 | return true; 45 | } 46 | if($resultCode == -3) { 47 | # Ticket does not exist. 48 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 49 | return true; 50 | } 51 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to reopen ticket #".$ticketId)); 52 | return true; 53 | } 54 | 55 | ReportRTS::$tickets[$ticketId] = $this->data->getTicket($ticketId); 56 | 57 | # Check if ticket has been assigned to the array. 58 | if(!isset(ReportRTS::$tickets[$ticketId])) { 59 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Something went wrong! Ticket did not enter the ticket array.")); 60 | return true; 61 | } 62 | 63 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketReopen, $sender->getName(), $ticketId)); 64 | $sender->sendMessage(sprintf(MessageHandler::$ticketReopenSelf, $ticketId)); 65 | 66 | return true; 67 | } 68 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/TeleportTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 21 | $this->data = $plugin->getDataProvider(); 22 | } 23 | 24 | public function handleCommand(CommandSender $sender, $args) { 25 | 26 | if(!($sender instanceof Player)) { 27 | $sender->sendMessage("[ReportRTS] You need a body to teleport. Players only."); 28 | } 29 | 30 | if(!$sender->hasPermission(PermissionHandler::canTeleport)) { 31 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canTeleport)); 32 | return true; 33 | } 34 | 35 | if(count($args) < 2 or !ToolBox::isNumber($args[1])) { 36 | $sender->sendMessage(sprintf(MessageHandler::$generalError, 'Correct syntax is: "/ "')); 37 | return true; 38 | } 39 | 40 | $id = intval($args[1]); 41 | 42 | $ticket = null; 43 | 44 | # Loads ticket from array or data-provider. 45 | if(isset(ReportRTS::$tickets[$id])) 46 | $ticket = ReportRTS::$tickets[$id]; 47 | else 48 | $ticket = $this->data->getTicket($id); 49 | 50 | # Check if ticket exists or not. 51 | if($ticket == null) { 52 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $id)); 53 | return true; 54 | } 55 | 56 | $position = new Position($ticket->getX(), $ticket->getY(), $ticket->getZ(), $this->plugin->getServer()->getLevelByName($ticket->getWorld())); 57 | 58 | if($position->getLevel() == null) { 59 | $sender->sendMessage(TextFormat::RED."[ReportRTS] Level is null! Attempting to teleport to that ticket will cause an error."); 60 | return true; 61 | } 62 | 63 | $sender->teleport($position, $ticket->getYaw(), $ticket->getPitch()); 64 | $sender->sendMessage(sprintf(MessageHandler::$ticketTeleport, $id)); 65 | 66 | return true; 67 | } 68 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/command/sub/UnclaimTicket.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 19 | $this->data = $plugin->getDataProvider(); 20 | } 21 | 22 | public function handleCommand(CommandSender $sender, $args) { 23 | 24 | ### Check if anything is wrong with the provided input before going further. ### 25 | if(!$sender->hasPermission(PermissionHandler::canClaimTicket)) { 26 | $sender->sendMessage(sprintf(MessageHandler::$permissionError, PermissionHandler::canClaimTicket)); 27 | return true; 28 | } 29 | 30 | if(count($args) < 2) { 31 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "You need to specify a ticket ID.")); 32 | return true; 33 | } 34 | 35 | if(!ToolBox::isNumber($args[1])) { 36 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Ticket ID must be a number. Provided: ".$args[1])); 37 | return true; 38 | } 39 | 40 | $ticketId = intval($args[1]); 41 | 42 | if(!isset(ReportRTS::$tickets[$ticketId])) { 43 | # The ticket that the user is trying to claim is not in the array (not open). 44 | $sender->sendMessage(MessageHandler::$ticketNotClaimed); 45 | return true; 46 | } 47 | 48 | if($sender instanceof Player) { 49 | if(strtoupper($sender->getName()) != ReportRTS::$tickets[$ticketId]->getStaffName() and !$sender->hasPermission(PermissionHandler::bypassTicketClaim)) { 50 | $sender->sendMessage("You need ".PermissionHandler::bypassTicketClaim." to do that."); 51 | return true; 52 | } 53 | } 54 | ### We're done! Let's start processing stuff. ### 55 | 56 | $ticket = ReportRTS::$tickets[$args[1]]; 57 | 58 | $timestamp = round(microtime(true)); 59 | 60 | if($resultCode = $this->data->setTicketStatus($ticketId, $sender->getName(), 0, null, 0, $timestamp) and $resultCode != 1) { 61 | 62 | if($resultCode == -1) { 63 | # Username is invalid or does not exist. 64 | $sender->sendMessage(sprintf(MessageHandler::$userNotExists, $sender->getName())); 65 | return true; 66 | } 67 | if($resultCode == -2) { 68 | # Ticket status incompatibilities. 69 | $sender->sendMessage(MessageHandler::$ticketStatusError); 70 | return true; 71 | } 72 | if($resultCode == -3) { 73 | # Ticket does not exist. 74 | $sender->sendMessage(sprintf(MessageHandler::$ticketNotExists, $ticketId)); 75 | return true; 76 | } 77 | $sender->sendMessage(sprintf(MessageHandler::$generalError, "Unable to unclaim ticket #".$ticketId)); 78 | return true; 79 | } 80 | 81 | # Set ticket info in the ticket array too. 82 | $ticket->setStatus(0); 83 | $ticket->setStaffName(null); 84 | $ticket->setStaffId(0); 85 | $ticket->setStaffTimestamp(null); 86 | ReportRTS::$tickets[$args[1]] = $ticket; 87 | 88 | $player = $this->plugin->getServer()->getPlayer($ticket->getName()); 89 | if($player != null) { 90 | $player->sendMessage(sprintf(MessageHandler::$ticketUnclaimUser, $sender->getName())); 91 | $player->sendMessage(sprintf(MessageHandler::$ticketClaimText, $ticket->getMessage())); 92 | } 93 | 94 | # Let staff know about this change. 95 | $this->plugin->messageStaff(sprintf(MessageHandler::$ticketUnclaim, $sender->getName(), $ticketId)); 96 | 97 | return true; 98 | } 99 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/data/Ticket.php: -------------------------------------------------------------------------------- 1 | id = $id; 11 | $this->status = $status; 12 | $this->x = $x; 13 | $this->y = $y; 14 | $this->z = $z; 15 | $this->staffId = $staffId; 16 | $this->yaw = $yaw; 17 | $this->pitch = $pitch; 18 | $this->timestamp = $timestamp; 19 | $this->stafftstamp = $stafftsstamp; 20 | $this->text = $text; 21 | $this->name = $name; 22 | $this->world = $world; 23 | $this->staffName = $staffName; 24 | $this->comment = $comment; 25 | } 26 | 27 | /** 28 | * Returns the message of the ticket. 29 | * @return String 30 | */ 31 | public function getMessage() { 32 | return $this->text; 33 | } 34 | 35 | /** 36 | * Returns the name of the sender. 37 | * @return String 38 | */ 39 | public function getName() { 40 | return $this->name; 41 | } 42 | 43 | /** 44 | * Return the ID of the ticket. 45 | * @return Integer 46 | */ 47 | public function getId() { 48 | return $this->id; 49 | } 50 | 51 | /** 52 | * Returns the ticket status. 53 | * @return Integer 54 | */ 55 | public function getStatus() { 56 | return $this->status; 57 | } 58 | 59 | /** 60 | * Returns the timestamp when the ticket was created. 61 | * @return Float 62 | */ 63 | public function getTimestamp() { 64 | return $this->timestamp; 65 | } 66 | 67 | /** 68 | * Returns the timestamp when the ticket was last interacted with by staff. 69 | * @return Float 70 | */ 71 | public function getStaffTimestamp() { 72 | return $this->stafftstamp; 73 | } 74 | 75 | /** 76 | * Returns X where the ticket was created. 77 | * @return Float 78 | */ 79 | public function getX() { 80 | return $this->x; 81 | } 82 | 83 | /** 84 | * Returns Y where the ticket was created. 85 | * @return Float 86 | */ 87 | public function getY() { 88 | return $this->y; 89 | } 90 | 91 | /** 92 | * Returns Z where the ticket was created. 93 | * @return Float 94 | */ 95 | public function getZ() { 96 | return $this->z; 97 | } 98 | 99 | /** 100 | * Returns Yaw where the ticket was created. 101 | * @return Float 102 | */ 103 | public function getYaw() { 104 | return $this->yaw; 105 | } 106 | 107 | /** 108 | * Returns Pitch where the ticket was created. 109 | * @return Float 110 | */ 111 | public function getPitch() { 112 | return $this->pitch; 113 | } 114 | 115 | /** 116 | * Returns the name of the world where the ticket was created. 117 | * @return String 118 | */ 119 | public function getWorld() { 120 | return $this->world; 121 | } 122 | 123 | /** 124 | * Returns the name of the staff that handled the ticket, if any. 125 | * @return String 126 | */ 127 | public function getStaffName() { 128 | return $this->staffName; 129 | } 130 | 131 | /** 132 | * Returns the ID of the staff member that last interacted 133 | * with the ticket, if any. 134 | * @return Int|null 135 | */ 136 | public function getStaffId() { 137 | return $this->staffId; 138 | } 139 | 140 | /** 141 | * Returns the comment that was made when handling the ticket, if any. 142 | * @return String 143 | */ 144 | public function getComment() { 145 | return $this->comment; 146 | } 147 | 148 | /** 149 | * Sets the message of the ticket to $text. 150 | * @param $text 151 | */ 152 | public function setMessage($text) { 153 | $this->text = $text; 154 | } 155 | 156 | /** 157 | * Sets the provided name as the user that opened the ticket. 158 | * @param $name 159 | */ 160 | public function setName($name) { 161 | $this->name = $name; 162 | } 163 | 164 | /** 165 | * Sets the provided ID as the user that opened the ticket. 166 | * @param $id 167 | */ 168 | public function setId($id) { 169 | $this->id = $id; 170 | } 171 | 172 | public function setStatus($status) { 173 | $this->status = $status; 174 | } 175 | 176 | public function setTimestamp($timestamp) { 177 | $this->timestamp = $timestamp; 178 | } 179 | 180 | public function setStaffTimestamp($staffTimestamp) { 181 | $this->stafftstamp = $staffTimestamp; 182 | } 183 | 184 | public function setStaffName($staffName) { 185 | $this->staffName = $staffName; 186 | } 187 | 188 | public function setStaffId($staffId) { 189 | $this->staffId = $staffId; 190 | } 191 | 192 | public function setX($x) { 193 | $this->x = $x; 194 | } 195 | 196 | public function setY($y) { 197 | $this->y = $y; 198 | } 199 | 200 | public function setZ($z) { 201 | $this->z = $z; 202 | } 203 | 204 | public function setYaw($yaw) { 205 | $this->yaw = $yaw; 206 | } 207 | 208 | public function setPitch($pitch) { 209 | $this->pitch = $pitch; 210 | } 211 | 212 | public function setWorld($world) { 213 | $this->world = $world; 214 | } 215 | 216 | public function setComment($comment) { 217 | $this->comment = $comment; 218 | } 219 | 220 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/lib/flintstone/Flintstone.php: -------------------------------------------------------------------------------- 1 | array( 49 | 'mode' => 'rb', 50 | 'operation' => LOCK_SH 51 | ), 52 | self::FILE_WRITE => array( 53 | 'mode' => 'wb', 54 | 'operation' => LOCK_EX, 55 | ), 56 | self::FILE_APPEND => array( 57 | 'mode' => 'ab', 58 | 'operation' => LOCK_EX, 59 | ), 60 | ); 61 | 62 | /** 63 | * Database Memory cache 64 | * 65 | * @var array 66 | */ 67 | private $cache = array(); 68 | 69 | /** 70 | * Tell whether the cache is enabled or not 71 | * 72 | * @var boolean 73 | */ 74 | private $cache_enabled = true; 75 | 76 | /** 77 | * Tell whether gzip is enabled or not 78 | * 79 | * @var boolean 80 | */ 81 | private $gzip_enabled = false; 82 | 83 | /** 84 | * Database File Path 85 | * 86 | * @var string 87 | */ 88 | private $file; 89 | 90 | /** 91 | * Swap Memory Limit 92 | * 93 | * @var integer 94 | */ 95 | private $swap_memory_limit; 96 | 97 | /** 98 | * Formatter 99 | * 100 | * @var object 101 | */ 102 | private $formatter; 103 | 104 | /** 105 | * Flintstone options: 106 | * 107 | * - string $dir the directory where the database files are stored 108 | * - string $ext the database file extension to use 109 | * - boolean $gzip use gzip to compress the database 110 | * - boolean $cache store get() results in memory 111 | * - object $depend the depend class used to encode/decode data 112 | * - integer $swap_memory_limit amount of memory to use before writing to a temporary file 113 | * 114 | * @var array 115 | */ 116 | private $default_options = array( 117 | 'dir' => '', 118 | 'ext' => '.dat', 119 | 'gzip' => false, 120 | 'cache' => true, 121 | 'depend' => null, 122 | 'swap_memory_limit' => 1048576, 123 | ); 124 | 125 | /** 126 | * Flintstone constructor 127 | * 128 | * @param string $database the database name 129 | * @param array $options an array of options 130 | * 131 | * @throws FlintstoneException when database cannot be loaded 132 | * 133 | */ 134 | public function __construct($database, array $options = array()) 135 | { 136 | if (! preg_match("/^[A-Za-z0-9_\-]+$/", $database)) { 137 | throw new FlintstoneException('Invalid characters in database name'); 138 | } 139 | 140 | $options = array_merge($this->default_options, $options); 141 | $dir = rtrim($options['dir'], '/\\') . DIRECTORY_SEPARATOR; 142 | if (!is_dir($dir)) { 143 | throw new FlintstoneException($dir.' is not a valid directory'); 144 | } 145 | 146 | $this->swap_memory_limit = filter_var( 147 | $options['swap_memory_limit'], 148 | FILTER_VALIDATE_INT, 149 | array('options' => array('min_range' => 0, 'default' => $this->default_options['swap_memory_limit'])) 150 | ); 151 | 152 | if ($options['cache'] !== $this->default_options['cache']) { 153 | $this->cache_enabled = !$this->cache_enabled; 154 | } 155 | 156 | if ($options['gzip'] !== $this->default_options['gzip']) { 157 | $this->gzip_enabled = !$this->gzip_enabled; 158 | } 159 | 160 | $extension = filter_var( 161 | $options['ext'], 162 | FILTER_SANITIZE_STRING, 163 | array('flags' => FILTER_FLAG_STRIP_LOW|FILTER_FLAG_STRIP_HIGH) 164 | ); 165 | 166 | $this->setFormatter($options['depend']); 167 | $this->setFile($dir, $database, $extension); 168 | } 169 | 170 | /** 171 | * Get a key from the database 172 | * 173 | * @param string $key the key 174 | * 175 | * @throws FlintstoneException when key is invalid 176 | * 177 | * @return mixed the data 178 | */ 179 | public function get($key) 180 | { 181 | $key = $this->normalizeKey($key); 182 | 183 | $data = false; 184 | if ($this->cache_enabled && array_key_exists($key, $this->cache)) { 185 | return $this->cache[$key]; 186 | } 187 | 188 | $filepointer = $this->openFile(self::FILE_READ); 189 | foreach ($filepointer as $line) { 190 | $data = $this->getDataFromLine($line, $key); 191 | if (false !== $data) { 192 | $data = $this->decodeData($data); 193 | break; 194 | } 195 | } 196 | 197 | $this->closeFile($filepointer); 198 | if ($this->cache_enabled && false !== $data) { 199 | $this->cache[$key] = $data; 200 | } 201 | 202 | return $data; 203 | } 204 | 205 | /** 206 | * Set a key to store in the database 207 | * 208 | * @param string $key the key 209 | * @param mixed $data the data to store 210 | * 211 | * @return boolean successful set 212 | * 213 | * @throws FlintstoneException when key or data is invalid 214 | */ 215 | public function set($key, $data) 216 | { 217 | $this->validateData($data); 218 | $key = $this->normalizeKey($key); 219 | 220 | if ($this->get($key) !== false) { 221 | return $this->replace($key, $data); 222 | } 223 | 224 | if ($this->cache_enabled) { 225 | $this->cache[$key] = $data; 226 | } 227 | 228 | $data = $this->encodeData($data); 229 | $line = "$key=$data\n"; 230 | $filepointer = $this->openFile(self::FILE_APPEND); 231 | $filepointer->fwrite($line); 232 | $this->closeFile($filepointer); 233 | 234 | return true; 235 | } 236 | 237 | /** 238 | * Replace a key in the database 239 | * 240 | * @param string $key the key 241 | * @param mixed $data the data to store 242 | * 243 | * @throws FlintstoneException when key or data is invalid 244 | * 245 | * @return boolean successful replace 246 | */ 247 | public function replace($key, $data) 248 | { 249 | $key = $this->normalizeKey($key); 250 | 251 | $tmp = new SplTempFileObject($this->swap_memory_limit); 252 | $filepointer = $this->openFile(self::FILE_READ); 253 | foreach ($filepointer as $line) { 254 | $line = $this->replaceLine($line, $key, $data); 255 | if (!empty($line)) { 256 | $tmp->fwrite($line); 257 | } 258 | } 259 | $this->closeFile($filepointer); 260 | $tmp->rewind(); 261 | 262 | $filepointer = $this->openFile(self::FILE_WRITE); 263 | foreach ($tmp as $line) { 264 | $filepointer->fwrite($line); 265 | } 266 | $tmp = null; 267 | $this->closeFile($filepointer); 268 | 269 | return true; 270 | } 271 | 272 | /** 273 | * Delete a key from the database 274 | * 275 | * @param string $key the key 276 | * 277 | * @throws FlintstoneException when key is invalid 278 | * 279 | * @return boolean successful delete 280 | */ 281 | public function delete($key) 282 | { 283 | if ($this->get($key) !== false && $this->replace($key, false)) { 284 | unset($this->cache[$key]); 285 | 286 | return true; 287 | } 288 | 289 | return false; 290 | } 291 | 292 | /** 293 | * Flush the database 294 | * 295 | * @throws FlintstoneException when something goes wrong 296 | * 297 | * @return boolean successful flush 298 | */ 299 | public function flush() 300 | { 301 | $filepointer = $this->openFile(self::FILE_WRITE); 302 | $this->closeFile($filepointer); 303 | $this->cache = array(); 304 | 305 | return true; 306 | } 307 | 308 | /** 309 | * Get all keys from the database 310 | * 311 | * @throws FlintstoneException when something goes wrong 312 | * 313 | * @return array list of keys 314 | */ 315 | public function getKeys() 316 | { 317 | $keys = array(); 318 | $filepointer = $this->openFile(self::FILE_READ); 319 | foreach ($filepointer as $line) { 320 | $pieces = explode("=", $line); 321 | $keys[] = $pieces[0]; 322 | } 323 | $this->closeFile($filepointer); 324 | 325 | return $keys; 326 | } 327 | 328 | /** 329 | * Get the database file 330 | * 331 | * @return string file path 332 | */ 333 | public function getFile() 334 | { 335 | return $this->file; 336 | } 337 | 338 | /** 339 | * Set the depend used to encode/decode data 340 | * 341 | * @param object $formatter the depend class 342 | * 343 | * @throws FlintstoneException when class does not implement Flintstone\Formatter\FormatterInterface 344 | * 345 | * @return void 346 | */ 347 | private function setFormatter($formatter) 348 | { 349 | if (!is_object($formatter)) { 350 | $this->formatter = new SerializeFormatter(); 351 | } else { 352 | if ($formatter instanceof FormatterInterface) { 353 | $this->formatter = $formatter; 354 | } else { 355 | throw new FlintstoneException('Formatter class does not implement Flintstone\\Formatter\\FormatterInterface'); 356 | } 357 | } 358 | } 359 | 360 | /** 361 | * Set the file 362 | * 363 | * @param string $directory file directory 364 | * @param string $basename file basename 365 | * @param string $ext file extension 366 | * 367 | */ 368 | private function setFile($directory, $basename, $ext) 369 | { 370 | if (substr($ext, 0, 1) !== ".") { 371 | $ext = ".$ext"; 372 | } 373 | if ($this->gzip_enabled && substr($ext, -3) !== ".gz") { 374 | $ext .= ".gz"; 375 | } 376 | 377 | $this->file = $directory.$basename.$ext; 378 | } 379 | 380 | /** 381 | * Open the database file 382 | * 383 | * @param integer $mode the file mode 384 | * 385 | * @throws FlintstoneException when database cannot be opened or locked 386 | * 387 | * @return \SplFileObject 388 | */ 389 | private function openFile($mode) 390 | { 391 | $path = $this->file; 392 | 393 | if (!file_exists($path) && !@touch($path)) { 394 | throw new FlintstoneException('Could not create file ' . $path); 395 | } elseif (!is_readable($path)) { 396 | throw new FlintstoneException('Could not read file ' . $path); 397 | } elseif (!is_writable($path)) { 398 | throw new FlintstoneException('Could not write to file ' . $path); 399 | } 400 | 401 | if ($this->gzip_enabled) { 402 | $path = 'compress.zlib://' . $path; 403 | } 404 | $res = $this->file_access_mode[$mode]; 405 | 406 | $file = new SplFileObject($path, $res['mode']); 407 | if (self::FILE_READ == $mode) { 408 | $file->setFlags(SplFileObject::DROP_NEW_LINE|SplFileObject::SKIP_EMPTY|SplFileObject::READ_AHEAD); 409 | } 410 | if (! $this->gzip_enabled && !$file->flock($res['operation'])) { 411 | throw new FlintstoneException('Could not lock file ' . $path); 412 | } 413 | 414 | return $file; 415 | } 416 | 417 | /** 418 | * Close the database file 419 | * 420 | * @param object $file the file pointer 421 | * 422 | * @throws FlintstoneException when database cannot be unlocked 423 | * 424 | * @return void 425 | */ 426 | private function closeFile($file) 427 | { 428 | if (! $this->gzip_enabled && ! $file->flock(LOCK_UN)) { 429 | $file = null; 430 | throw new FlintstoneException('Could not unlock file'); 431 | } 432 | $file = null; 433 | } 434 | 435 | /** 436 | * Check the database has been loaded and valid key 437 | * 438 | * @param string $key the key 439 | * 440 | * @return string 441 | * @throws FlintstoneException when key is invalid 442 | */ 443 | private function normalizeKey($key) 444 | { 445 | if (! is_string($key)) { 446 | throw new FlintstoneException('Key must be an string'); 447 | } elseif (strlen($key) > 1024) { 448 | throw new FlintstoneException('Maximum key length is 1024 characters'); 449 | } elseif (strpos($key, '=') !== false) { 450 | throw new FlintstoneException('Key may not contain the equals character'); 451 | } 452 | 453 | return $key; 454 | } 455 | 456 | /** 457 | * Check the data type is valid 458 | * 459 | * @param mixed $data the data 460 | * 461 | * @throws FlintstoneException when data is invalid 462 | */ 463 | private function validateData($data) 464 | { 465 | if (!is_string($data) && !is_int($data) && !is_float($data) && !is_array($data)) { 466 | throw new FlintstoneException('Invalid data type'); 467 | } 468 | } 469 | 470 | /** 471 | * Encode data into a string 472 | * 473 | * @param mixed $data the data to encode 474 | * 475 | * @return string the encoded string or false 476 | */ 477 | private function encodeData($data) 478 | { 479 | if ($data !== false) { 480 | return $this->formatter->encode($data); 481 | } 482 | 483 | return $data; 484 | } 485 | 486 | /** 487 | * Decode a string into data 488 | * 489 | * @param string $data the encoded string 490 | * 491 | * @return mixed the decoded data 492 | */ 493 | private function decodeData($data) 494 | { 495 | return $this->formatter->decode($data); 496 | } 497 | 498 | /** 499 | * update line content depending on the key and data 500 | * 501 | * @param string $line file line 502 | * @param string $key cache key 503 | * @param mixed $data raw data 504 | * 505 | * @return boolean 506 | */ 507 | private function replaceLine($line, $key, $data) 508 | { 509 | $encodeData = $this->encodeData($data); 510 | $pieces = explode("=", $line); 511 | if ($pieces[0] == $key) { 512 | if (false === $encodeData) { 513 | return null; 514 | } 515 | $line = "$key=$encodeData"; 516 | if ($this->cache_enabled) { 517 | $this->cache[$key] = $data; 518 | } 519 | } 520 | 521 | return $line."\n"; 522 | } 523 | 524 | /** 525 | * Retrieve data from a given line 526 | * 527 | * @param string $line file line 528 | * @param string $key cache key 529 | * 530 | * @return string|boolean 531 | */ 532 | private function getDataFromLine($line, $key) 533 | { 534 | $pieces = explode("=", $line); 535 | if ($pieces[0] != $key) { 536 | return false; 537 | } 538 | $data = $pieces[1]; 539 | if (count($pieces) > 2) { 540 | array_shift($pieces); 541 | $data = implode("=", $pieces); 542 | } 543 | 544 | return $data; 545 | } 546 | } 547 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/lib/flintstone/FlintstoneException.php: -------------------------------------------------------------------------------- 1 | preserveLines($data, false)); 25 | } 26 | 27 | /** 28 | * Decode a string into data 29 | * 30 | * @param string $data the encoded string 31 | * 32 | * @return mixed the decoded data 33 | */ 34 | public function decode($data) 35 | { 36 | return $this->preserveLines(unserialize($data), true); 37 | } 38 | 39 | /** 40 | * Preserve new lines, recursive function 41 | * 42 | * @param mixed $data the data 43 | * 44 | * @param boolean $reverse to reverse the replacement order 45 | * 46 | * @return mixed the data 47 | */ 48 | private function preserveLines($data, $reverse) 49 | { 50 | $search = array("\n", "\r"); 51 | $replace = array("\\n", "\\r"); 52 | if ($reverse) { 53 | $search = array("\\n", "\\r"); 54 | $replace = array("\n", "\r"); 55 | } 56 | 57 | if (is_string($data)) { 58 | $data = str_replace($search, $replace, $data); 59 | } elseif (is_array($data)) { 60 | foreach ($data as &$value) { 61 | $value = $this->preserveLines($value, $reverse); 62 | } 63 | unset($value); 64 | } 65 | 66 | return $data; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/listener/RTSListener.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 26 | $this->data = $plugin->getDataProvider(); 27 | } 28 | 29 | public function onPlayerJoin(PlayerJoinEvent $event) { 30 | 31 | if($this->plugin->isDefault) { 32 | if($event->getPlayer()->isOp()) { 33 | $event->getPlayer()->sendMessage(TextFormat::RED."You need to set up ReportRTS! Use /rts setup "); 34 | $this->plugin->getServer()->dispatchCommand($event->getPlayer(), "reportrts setup"); 35 | } 36 | return; 37 | } 38 | 39 | if(count($this->plugin->notifications) > 0) { 40 | /** @var Ticket[] $found */ 41 | $found = []; 42 | foreach($this->plugin->notifications as $ticket) { 43 | if(strtoupper($ticket->getName()) != strtoupper($event->getPlayer()->getName())) continue; 44 | # Store found ticket for later use. 45 | array_push($found, $ticket); 46 | } 47 | 48 | if(count($found) > 1) $event->getPlayer()->sendMessage(sprintf(MessageHandler::$ticketCloseMulti, count($found), "ticket ".$this->plugin->commands['readTicket']." self")); 49 | 50 | foreach($found as $ticket) { 51 | $this->plugin->getScheduler()->scheduleDelayedTask(new LoginTask($this->plugin, $ticket), 100); 52 | } 53 | } 54 | 55 | # Check if player is staff and add to array if true. 56 | if($event->getPlayer()->hasPermission(PermissionHandler::isStaff)) { 57 | array_push($this->plugin->staff, $event->getPlayer()->getName()); 58 | $this->plugin->staff = array_unique($this->plugin->staff); 59 | } 60 | } 61 | 62 | public function onPlayerQuit(PlayerQuitEvent $event) { 63 | 64 | if(($staff = array_search($event->getPlayer()->getName(), $this->plugin->staff)) !== false) unset($this->plugin->staff[$staff]); 65 | } 66 | 67 | public function onSignChange(SignChangeEvent $event) { 68 | if($event->getBlock()->getID() != 63 && $event->getBlock()->getID() != 68) return; 69 | $block = $event->getBlock(); 70 | if(!($block instanceof Sign)) return; 71 | $sign = $block->getText(); 72 | if($sign[0] != "[help]") return; 73 | 74 | $message = ToolBox::cleanSign($sign); 75 | if(strlen($message) == 0) { 76 | $event->getPlayer()->sendMessage(sprintf(MessageHandler::$generalError, "Sign syntax is invalid.")); 77 | # Break the block because it is invalid. 78 | $event->getBlock()->level->useBreakOn($event->getBlock(), $item = null, null); 79 | return; 80 | } 81 | 82 | # Fire command. 83 | $this->plugin->getServer()->dispatchCommand($event->getPlayer(), "ticket ".$this->plugin->commands['openTicket']." ".$message); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/persistence/DataProvider.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 21 | $this->tickets = Flintstone::load('tickets', ['dir' => $plugin->getDataFolder(), 'gzip' => true]); 22 | $this->users = Flintstone::load('users', ['dir' => $plugin->getDataFolder(), 'gzip' => true]); 23 | ReportRTS::$tickets = $this->load(); 24 | } 25 | 26 | private function buildTicketFromData($key, $ticketData) { 27 | 28 | $ticket = new Ticket(intval($key), $ticketData['status'], $ticketData['x'], $ticketData['y'], $ticketData['z'], null, 29 | $ticketData['yaw'], $ticketData['pitch'], $ticketData['timestamp'], null, $ticketData['text'], $this->getUser(null, $ticketData['userId'])['username'], 30 | $ticketData['world'], null, null); 31 | 32 | if($ticket->getStatus() > 0) { 33 | $ticket->setStaffName($this->getUser(null, $ticket->getStaffId())['username']); 34 | $ticket->setStaffTimestamp($ticketData['staffTime'] > 0 ? $ticketData['staffTime'] : null); 35 | $ticket->setComment(strlen($ticketData['comment']) > 0 ? $ticketData['comment'] : null); 36 | } 37 | 38 | return $ticket; 39 | } 40 | 41 | /** @return Ticket[] */ 42 | private function load() { 43 | 44 | /** @var Ticket[] $tickets */ 45 | $tickets = []; 46 | 47 | foreach($this->tickets->getKeys() as $key) { 48 | $ticket = $this->tickets->get($key); 49 | # Ticket is of incorrect status, let's skip it. 50 | if($ticket['status'] > 1) continue; 51 | 52 | $ticketClass = new Ticket(intval($key), $ticket['status'], $ticket['x'], $ticket['y'], $ticket['z'], null, 53 | $ticket['yaw'], $ticket['pitch'], $ticket['timestamp'], null, $ticket['text'], $this->getUser(null, $ticket['userId'])['username'], 54 | $ticket['world'], null, null); 55 | 56 | if($ticketClass->getStatus() > 0) { 57 | $ticketClass->setStaffName($this->getUser(null, $ticket['staffId'])['username']); 58 | $ticketClass->setStaffTimestamp($ticket['staffTime'] > 0 ? $ticket['staffTime'] : null); 59 | $ticketClass->setComment(strlen($ticket['comment']) > 0 ? $ticket['comment'] : null); 60 | } 61 | $tickets[$key] = $ticketClass; 62 | } 63 | 64 | return $tickets; 65 | 66 | } 67 | 68 | public function close() { 69 | Flintstone::unload('tickets'); 70 | Flintstone::unload('users'); 71 | } 72 | 73 | public function reset() { 74 | $this->tickets->flush(); 75 | $this->users->flush(); 76 | } 77 | 78 | public function resetNotifications() { 79 | 80 | foreach($this->tickets->getKeys() as $key) { 81 | 82 | $ticket = $this->tickets->get($key); 83 | 84 | if($ticket['notified'] == 1) continue; 85 | 86 | $ticket['notified'] = 1; 87 | 88 | $this->tickets->replace($key, $ticket); 89 | 90 | } 91 | 92 | return true; 93 | } 94 | 95 | public function createUser($username) { 96 | 97 | $player = $this->plugin->getServer()->getPlayer($username); 98 | if($player == null and strtoupper($username) != "CONSOLE") return 0; 99 | 100 | $this->users->set($username, ['uid' => count($this->users->getKeys()) + 1, 'name' => $username, 'banned' => false]); 101 | 102 | return $this->users->get($username)['uid']; 103 | 104 | } 105 | 106 | /** 107 | * @param $sender 108 | * @param $world 109 | * @param Position $location 110 | * @param $yaw 111 | * @param $pitch 112 | * @param $message 113 | * @param $timestamp 114 | * @return mixed 115 | */ 116 | public function createTicket($sender, $world, Position $location, $yaw, $pitch, $message, $timestamp) { 117 | 118 | # Retrieve user data. 119 | $user = $this->getUser($sender); 120 | # Check if user exists. 121 | if($user['id'] == 0) { 122 | # Create the user since it does not exist. 123 | $this->createUser($sender); 124 | $user = $this->getUser($sender); 125 | } 126 | # Check if user is banned before processing further. 127 | if($user['isBanned'] == 1) { 128 | return -1; 129 | } 130 | 131 | $world = $location->getLevel()->getName(); $x = $location->getX(); $y = $location->getY(); $z = $location->getZ(); 132 | $data = [ 133 | 'userId' => $user['id'], 134 | 'staffId' => 0, 135 | 'staffTime' => 0.00, 136 | 'status' => 0, 137 | 'notified' => 0, 138 | 'timestamp' => $timestamp, 139 | 'world' => $world, 140 | 'x' => $x, 141 | 'y' => $y, 142 | 'z' => $z, 143 | 'yaw' => $yaw, 144 | 'pitch' => $pitch, 145 | 'comment' => "", 146 | 'text' => $message, 147 | ]; 148 | 149 | $id = count($this->tickets->getKeys()) + 1; 150 | $this->tickets->set((String) $id, $data); 151 | 152 | return $id; 153 | } 154 | 155 | /** 156 | * Gets a number quoting the amount of tickets of current status. 157 | * If no status is specified it defaults to 4 which is a non-valid 158 | * status, and should be parsed as ALL tickets. 159 | * @param int $status 160 | * @return int 161 | */ 162 | public function countTickets($status = 4) { 163 | 164 | $i = 0; 165 | 166 | if($status < 4) { 167 | 168 | foreach($this->tickets->getKeys() as $key) { 169 | if($this->tickets->get($key)['status'] != $status) continue; 170 | $i++; 171 | } 172 | 173 | } else { 174 | $i = count($this->tickets->getKeys()); 175 | } 176 | 177 | return $i; 178 | } 179 | 180 | /** 181 | * @param int $cursor 182 | * @param int $limit 183 | * @param int $status 184 | * @return Ticket[] 185 | */ 186 | public function getTickets($cursor, $limit, $status = 0) { 187 | 188 | $tickets = []; 189 | 190 | $i = 0; 191 | $l = 0; 192 | 193 | $keys = $this->tickets->getKeys(); 194 | if($status == 3) arsort($keys); 195 | 196 | foreach($keys as $key) { 197 | $ticket = $this->tickets->get($key); 198 | 199 | # Return array because we have reached the limit. 200 | if($l >= $limit) return $tickets; 201 | 202 | ## Debug line for pagination ## 203 | #echo PHP_EOL."i:".$i."/".$cursor." l:".$l."/".$limit.PHP_EOL; 204 | 205 | # Ticket is of incorrect status, let's skip it. 206 | if($ticket['status'] != $status) continue; 207 | 208 | # Increment the counter because the cursor is higher than the counter. 209 | if($cursor > $i) { 210 | $i++; 211 | continue; 212 | } 213 | 214 | $tickets[$key] = $this->buildTicketFromData($key, $ticket); 215 | if($status == 3) arsort($tickets); 216 | 217 | if($i < $limit) $i++; 218 | $l++; 219 | 220 | } 221 | return $tickets; 222 | } 223 | 224 | /** 225 | * @param $id 226 | * @return Ticket 227 | */ 228 | public function getTicket($id) { 229 | 230 | if(!ToolBox::isNumber($id) or array_key_exists($id, $this->tickets->getKeys())) return null; 231 | 232 | return $this->buildTicketFromData($id, $this->tickets->get((String) $id)); 233 | 234 | } 235 | 236 | private function getTicketsBy($username, $cursor, $limit, $creator) { 237 | 238 | $user = $this->getUser($username); 239 | if ($user['id'] === 0) { 240 | return false; 241 | } 242 | 243 | $return = null; 244 | 245 | if($creator) { 246 | 247 | $result = []; 248 | $i = 0; 249 | $l = 0; 250 | foreach($this->tickets->getKeys() as $key) { 251 | 252 | $ticket = $this->tickets->get($key); 253 | 254 | # Return array because we have reached the limit. 255 | if($l >= $limit) return $result; 256 | 257 | ## Debug line for pagination ## 258 | #echo PHP_EOL."i:".$i."/".$cursor." l:".$l."/".$limit.PHP_EOL; 259 | 260 | # Continue because the ticket is not opened by the user we are looking for. 261 | if($ticket['userId'] != $user['id']) continue; 262 | 263 | # Increment the counter because the cursor is higher than the counter. 264 | if($cursor > $i) { 265 | $i++; 266 | continue; 267 | } 268 | 269 | $result[intval($key)] = $this->buildTicketFromData($key, $ticket); 270 | 271 | if($i < $limit) $i++; 272 | $l++; 273 | 274 | } 275 | 276 | } else { 277 | 278 | $result = []; 279 | 280 | $i = 0; 281 | $l = 0; 282 | 283 | $invertedKeys = $this->tickets->getKeys(); 284 | arsort($invertedKeys); 285 | foreach($invertedKeys as $key) { 286 | 287 | $ticket = $this->tickets->get($key); 288 | 289 | # Continue if ticket is NOT closed. 290 | if($ticket['status'] < 3) continue; 291 | 292 | # Return array because we have reached the limit. 293 | if($l >= $limit) { 294 | arsort($result); 295 | return $result; 296 | } 297 | 298 | ## Debug line for pagination ## 299 | #echo PHP_EOL."i:".$i."/".$cursor." l:".$l."/".$limit.PHP_EOL; 300 | 301 | # Continue because the ticket is not closed by the user we are looking for. 302 | if($ticket['staffId'] != $user['id']) continue; 303 | 304 | # Increment the counter because the cursor is higher than the counter. 305 | if($cursor > $i) { 306 | $i++; 307 | continue; 308 | } 309 | 310 | $result[intval($key)] = $this->buildTicketFromData($key, $ticket); 311 | 312 | if($i < $limit) $i++; 313 | $l++; 314 | 315 | } 316 | } 317 | return $result; 318 | } 319 | 320 | /** 321 | * @param $username 322 | * @param $cursor 323 | * @param $limit 324 | * @return Ticket[]|mixed 325 | */ 326 | public function getHandledBy($username, $cursor, $limit) { 327 | return $this->getTicketsBy($username, $cursor, $limit, false); 328 | } 329 | 330 | /** 331 | * @param $username 332 | * @param $cursor 333 | * @param $limit 334 | * @return Ticket[]|mixed 335 | */ 336 | public function getOpenedBy($username, $cursor, $limit) { 337 | return $this->getTicketsBy($username, $cursor, $limit, true); 338 | } 339 | 340 | /** 341 | * @param int $limit 342 | * @return Array 343 | */ 344 | public function getTop($limit) { 345 | 346 | if(!is_int($limit)) return []; 347 | 348 | $result = []; 349 | 350 | foreach($this->tickets->getKeys() as $key) { 351 | $ticket = $this->tickets->get($key); 352 | 353 | # We only want tickets that are closed. 354 | if($ticket['status'] != 3) continue; 355 | 356 | $user = $this->getUser(null, $ticket['staffId']); 357 | 358 | # Ensure that array key exists, we don't want any errors. 359 | if(!array_key_exists($user['username'], $result)) $result[$user['username']] = 0; 360 | 361 | $result[$user['username']] = $result[$user['username']] + 1; 362 | } 363 | 364 | arsort($result); 365 | # Sorts the array by value, descending. 366 | return array_slice($result, 0, $limit, true); 367 | } 368 | 369 | /** 370 | * @param $username 371 | * @param $id 372 | * @param $createIfNotExists 373 | * @return Array 374 | */ 375 | public function getUser($username = null, $id = 0, $createIfNotExists = false) { 376 | 377 | if($username != null) { 378 | # Create user if it does not exist. 379 | if(!array_key_exists($username, $this->users->getKeys()) and $createIfNotExists === true) $this->createUser($username); 380 | $user = $this->users->get($username); 381 | return [ 382 | "id" => (int) $user['uid'], 383 | "username" => $user['name'], 384 | "isBanned" => $user['banned'] == 1 ? true : false 385 | ]; 386 | } 387 | if($username == null and $id > 0) { 388 | foreach($this->users->getKeys() as $key) { 389 | # UID didn't match ID, continue. 390 | if($this->users->get($key)['uid'] === $id) { 391 | # We found our user! Let's return it. 392 | $user = [ 393 | 'uid' => $id, 394 | 'name' => $this->users->get($key)['name'], 395 | 'banned' => $this->users->get($key)['banned'] == 1 ? true : false 396 | ]; 397 | return [ 398 | "id" => (int) $user['uid'], 399 | "username" => $user['name'], 400 | "isBanned" => $user['banned'] == 1 ? true : false 401 | ]; 402 | } 403 | } 404 | } 405 | 406 | return [ 407 | "id" => 0, 408 | "username" => "", 409 | "banned" => false 410 | ]; 411 | } 412 | 413 | public function setTicketStatus($id, $username, $status, $comment, $notified, $timestamp) { 414 | 415 | if(!isset(ReportRTS::$tickets[$id])) { 416 | # Ticket is not of status OPEN(1). 417 | $ticket = $this->getTicket($id); 418 | if($ticket == null) return -3; 419 | } else { 420 | # Retrieve ticket from ticket array. 421 | $ticket = ReportRTS::$tickets[$id]; 422 | } 423 | 424 | # Make sure username is alphanumeric. 425 | if(!ctype_alnum($username)) return -1; 426 | 427 | # Check if user exists. Array_filter might be necessary, we'll find out. 428 | $user = $this->getUser($username, 0 , true); 429 | if(empty($user)) { 430 | return -1; 431 | } 432 | 433 | # Make sure ticket statuses don't clash. 434 | if($ticket->getStatus() == $status or ($status == 2 && $ticket->getStatus() == 3)) return -2; 435 | 436 | return $this->tickets->replace((String) $id, [ 437 | 'userId' => $this->getUser($ticket->getName())['id'], 438 | 'staffId' => $user['id'], 439 | 'staffTime' => $timestamp, 440 | 'status' => $status, 441 | 'notified' => 0, 442 | 'timestamp' => $timestamp, 443 | 'world' => $ticket->getWorld(), 444 | 'x' => $ticket->getX(), 445 | 'y' => $ticket->getY(), 446 | 'z' => $ticket->getZ(), 447 | 'yaw' => $ticket->getYaw(), 448 | 'pitch' => $ticket->getPitch(), 449 | 'comment' => $comment, 450 | 'text' => $ticket->getMessage(), 451 | ]) ? 1 : 0; 452 | 453 | } 454 | 455 | public function setNotificationStatus($id, $status) { 456 | 457 | # If -1 is returned then either the ID is not a number or the status is not a boolean. 458 | if(!ToolBox::isNumber($id) or !is_bool($status)) return -1; 459 | 460 | $id = intval($id); 461 | $status = $status ? 1 : 0 ; 462 | 463 | $ticket = $this->tickets->get((String) $id); 464 | $ticket['notified'] = $status; 465 | $this->tickets->replace((String) $id, $ticket); 466 | $ticket = $this->tickets->get((String) $id); 467 | 468 | return $status == $ticket['notified'] ? 0 : 1; 469 | 470 | } 471 | 472 | public function setUserStatus($username, $status) { 473 | 474 | # User status has to be a boolean. 475 | if(!is_bool($status)) return 0; 476 | 477 | $user = $this->users->get($username); 478 | 479 | # Return if status is the same as the one provided. 480 | if($status == $user['banned']) return 0; 481 | $user['banned'] = $status; 482 | 483 | $this->users->replace($username, $user); 484 | $user = $this->users->get($username); 485 | 486 | return $status == $user['banned'] ? 1 : 0; 487 | } 488 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/persistence/MySQLDataProvider.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 24 | $config = $this->plugin->getConfig()->get("storage"); 25 | 26 | $this->userCache = []; 27 | 28 | if(!isset($config["host"]) or !isset($config["username"]) or !isset($config["password"]) 29 | or !isset($config["database"])) { 30 | $this->plugin->getLogger()->critical("Your MySQL settings are invalid! Please check your config.yml"); 31 | # Do as SimpleAuth and provide a dummy provider? 32 | } 33 | $this->database = new \mysqli($config["host"], $config["username"], $config["password"], $config["database"], isset($config["port"]) ? $config["port"] : 3306); 34 | if($this->database->connect_error) { 35 | $this->plugin->getLogger()->critical("Could not connect to MySQL! Cause: ".$this->database->connect_error); 36 | # Do as SimpleAuth and provide a dummy provider? 37 | return; 38 | } 39 | 40 | # Set up tickets table. 41 | $resource = $this->plugin->getResource("mysql_tickets.sql"); 42 | $this->database->query(stream_get_contents($resource)); 43 | fclose($resource); 44 | # Set up users table. 45 | $resource = $this->plugin->getResource("mysql_users.sql"); 46 | $this->database->query(stream_get_contents($resource)); 47 | fclose($resource); 48 | 49 | # Make sure connection stays alive. 50 | $this->plugin->getScheduler()->scheduleRepeatingTask(new MySQLKeepAliveTask($this->plugin, $this->database), 600); 51 | 52 | $this->plugin->getLogger()->info("Connected using MySQL"); 53 | 54 | ReportRTS::$tickets = $this->load(); 55 | } 56 | 57 | public function close() { 58 | $this->database->close(); 59 | } 60 | 61 | /** @return Ticket[] */ 62 | private function load() { 63 | $result = $this->database->query("SELECT * FROM `reportrts_tickets` AS `ticket` INNER JOIN `reportrts_users` AS `user` ON ticket.userId = user.uid WHERE ticket.status < '2' ORDER BY ticket.id ASC"); 64 | $temp = []; 65 | while($row = $result->fetch_assoc()) { 66 | $ticket = new Ticket($row['id'], $row['status'], $row['x'], $row['y'], $row['z'], $row['staffId'], $row['yaw'], 67 | $row['pitch'], $row['timestamp'], $row['staffTime'], $row['text'], $row['name'], $row['world'], null, $row['comment']); 68 | if($ticket->getStatus() > 0) $ticket->setStaffName($this->getUser(null, $ticket->getStaffId())['username']); 69 | $temp[$row['id']] = $ticket; 70 | } 71 | 72 | $result->close(); 73 | return $temp; 74 | } 75 | 76 | public function createUser($username) { 77 | $id = 0; 78 | 79 | $player = $this->plugin->getServer()->getPlayer($username); 80 | if($player == null and strtoupper($username) != "CONSOLE") return 0; 81 | 82 | $sql = $this->database->prepare("INSERT INTO `reportrts_users` (`name`, `banned`) VALUES (?, '0')"); 83 | $sql->bind_param("s", $username); 84 | $sql->execute(); 85 | $id = $sql->insert_id; 86 | $sql->close(); 87 | return $id; 88 | } 89 | 90 | public function createTicket($sender, $world, Position $location, $yaw, $pitch, $message, $timestamp) { 91 | 92 | # Retrieve user data. 93 | $user = $this->getUser($sender); 94 | # Check if user exists. 95 | if($user['id'] == 0) { 96 | # Create the user since it does not exist. 97 | $this->createUser($sender); 98 | $user = $this->getUser($sender); 99 | } 100 | # Check if user is banned before processing further. 101 | if($user['isBanned'] == 1) { 102 | return -1; 103 | } 104 | 105 | $world = $location->getLevel()->getName(); $x = $location->getX(); $y = $location->getY(); $z = $location->getZ(); 106 | $stmt = $this->database->prepare("INSERT INTO `reportrts_tickets` (`userId`, `timestamp`, `world`, `x`, `y`, `z`, `yaw`, `pitch`, `text`) VALUES(".$user['id'].",?,?,?,?,?,?,?,?)"); 107 | $stmt->bind_param('isiiiiis', $timestamp, $world, $x, $y, $z, $yaw, $pitch, $message); 108 | $stmt->execute(); 109 | if($stmt->affected_rows == 0) { 110 | $stmt->close(); 111 | return 0; 112 | } 113 | $id = $stmt->insert_id; 114 | # We're done here, time to close up shop. 115 | $stmt->close(); 116 | 117 | return $id; 118 | } 119 | 120 | /** 121 | * Gets a number quoting the amount of tickets of current status. 122 | * If no status is specified it defaults to 4 which is a non-valid 123 | * status, and should be parsed as ALL tickets. 124 | * @param int $status 125 | * @return int 126 | */ 127 | public function countTickets($status = 4) { 128 | 129 | $query = null; 130 | if($status < 4) { 131 | $query = $this->database->query("SELECT COUNT(*) FROM `reportrts_tickets` WHERE `status` = '$status'"); 132 | } else { 133 | $query = $this->database->query("SELECT COUNT(*) FROM `reportrts_tickets`"); 134 | } 135 | 136 | $result = $query->fetch_row(); 137 | $query->close(); 138 | 139 | return intval($result[0]); 140 | } 141 | 142 | public function getTickets($cursor, $limit, $status = 0) { 143 | 144 | $tickets = []; 145 | $query = $this->database->query("SELECT * FROM `reportrts_tickets` AS `ticket` INNER JOIN `reportrts_users` AS `user` ON ticket.userId = user.uid WHERE ticket.status = '".$status."' ORDER BY ticket.id ".($status > 2 ? "DESC" : "ASC")." LIMIT ".$cursor.",".$limit); 146 | 147 | while($row = $query->fetch_assoc()) { 148 | $tickets[$row['id']] = new Ticket($row['id'], $row['status'], $row['x'], $row['y'], $row['z'], $row['staffId'], $row['yaw'], 149 | $row['pitch'], $row['timestamp'], $row['staffTime'], $row['text'], $row['name'], $row['world'], null, $row['comment']); 150 | } 151 | 152 | $query->close(); 153 | 154 | return $tickets; 155 | } 156 | 157 | /** 158 | * @param $id 159 | * @return Ticket 160 | */ 161 | public function getTicket($id) { 162 | if(!ToolBox::isNumber($id)) return null; 163 | $row = $this->database->query("SELECT * FROM `reportrts_tickets` AS `ticket` INNER JOIN `reportrts_users` AS `user` ON ticket.userId = user.uid WHERE ticket.id = '$id' LIMIT 1")->fetch_assoc(); 164 | $ticket = new Ticket($row['id'], $row['status'], $row['x'], $row['y'], $row['z'], $row['staffId'], $row['yaw'], 165 | $row['pitch'], $row['timestamp'], $row['staffTime'], $row['text'], $row['name'], $row['world'], null, $row['comment']); 166 | if($ticket->getId() == null) return null; 167 | return $ticket; 168 | } 169 | 170 | public function getHandledBy($username, $cursor, $limit) { 171 | return $this->getTicketsBy($username, $cursor, $limit, false); 172 | } 173 | 174 | public function getOpenedBy($username, $cursor, $limit) { 175 | return $this->getTicketsBy($username, $cursor, $limit, true); 176 | } 177 | 178 | private function getTicketsBy($username, $cursor, $limit, $creator) { 179 | 180 | $user = $this->getUser($username); 181 | if($user['id'] === 0) { 182 | return false; 183 | } 184 | $result = null; 185 | 186 | # TODO: Make this more DRY. 187 | if($creator) { 188 | 189 | $stmt = $this->database->prepare("SELECT * FROM `reportrts_tickets` AS `ticket` INNER JOIN `reportrts_users` AS `user` ON `ticket`.userId = `user`.uid 190 | WHERE `ticket`.userId = ? ORDER BY `ticket`.timestamp DESC LIMIT ?, ?"); 191 | $stmt->bind_param("iii", $user['id'], $cursor, $limit); 192 | $stmt->execute(); 193 | $temp = $stmt->get_result(); 194 | $result = []; 195 | if (!$temp) { 196 | echo "Database Error [{$this->database->errno}] {$this->database->error}".PHP_EOL; 197 | return null; 198 | } 199 | while($row = $temp->fetch_array(1)) { 200 | $ticket = new Ticket($row['id'], $row['status'], $row['x'], $row['y'], $row['z'], $row['staffId'], $row['yaw'], 201 | $row['pitch'], $row['timestamp'], $row['staffTime'], $row['text'], $row['name'], $row['world'], null, $row['comment']); 202 | if($ticket->getStatus() > 0) $ticket->setStaffName($this->getUser(null, $ticket->getStaffId())['username']); 203 | $result[$row['id']] = $ticket; 204 | } 205 | 206 | $stmt->close(); 207 | return $result; 208 | } else { 209 | 210 | $stmt = $this->database->prepare("SELECT * FROM `reportrts_tickets` AS `ticket` INNER JOIN `reportrts_users` AS `user` ON `ticket`.userId = `user`.uid 211 | WHERE `ticket`.staffId = ? ORDER BY `ticket`.staffTime DESC LIMIT ?, ?"); 212 | $stmt->bind_param("iii", $user['id'], $cursor, $limit); 213 | $stmt->execute(); 214 | $temp = $stmt->get_result(); 215 | $result = []; 216 | if (!$temp) { 217 | echo "Database Error [{$this->database->errno}] {$this->database->error}".PHP_EOL; 218 | return null; 219 | } 220 | while($row = $temp->fetch_array(1)) { 221 | $ticket = new Ticket($row['id'], $row['status'], $row['x'], $row['y'], $row['z'], $row['staffId'], $row['yaw'], 222 | $row['pitch'], $row['timestamp'], $row['staffTime'], $row['text'], $row['name'], $row['world'], null, $row['comment']); 223 | if($ticket->getStatus() > 0) $ticket->setStaffName($this->getUser(null, $ticket->getStaffId())['username']); 224 | $result[$row['id']] = $ticket; 225 | } 226 | } 227 | return $result; 228 | } 229 | 230 | public function getTop($limit) { 231 | 232 | if(!is_int($limit)) return []; 233 | 234 | $query = $this->database->query("SELECT `reportrts_users`.name, COUNT(`reportrts_tickets`.staffId) AS tickets FROM `reportrts_tickets` 235 | LEFT JOIN `reportrts_users` ON `reportrts_tickets`.staffId = `reportrts_users`.uid WHERE `reportrts_tickets`.status = 3 236 | GROUP BY `name` ORDER BY tickets DESC LIMIT ".$limit); 237 | 238 | $result = []; 239 | 240 | while($row = $query->fetch_assoc()) $result[$row['name']] = (int) $row['tickets']; 241 | 242 | return $result; 243 | } 244 | 245 | public function setTicketStatus($id, $username, $status, $comment, $notified, $timestamp) { 246 | 247 | if(!isset(ReportRTS::$tickets[$id])) { 248 | # Ticket is not of status OPEN(1). 249 | $ticket = $this->getTicket($id); 250 | if($ticket == null) return -3; 251 | } else { 252 | # Retrieve ticket from ticket array. 253 | $ticket = ReportRTS::$tickets[$id]; 254 | } 255 | 256 | # Make sure username is alphanumeric. 257 | if(!ctype_alnum($username)) return -1; 258 | 259 | # Check if user exists. Array_filter might be necessary, we'll find out. 260 | $user = $this->getUser($username, 0 , true); 261 | if(empty($user)) { 262 | return -1; 263 | } 264 | 265 | # Make sure ticket statuses don't clash. 266 | if($ticket->getStatus() == $status or ($status == 2 && $ticket->getStatus() == 3)) return -2; 267 | 268 | $stmt = $this->database->prepare("UPDATE `reportrts_tickets` SET `status` = ?, `staffId` = ?, `staffTime` = ?, `comment` = ?, `notified` = ? WHERE `id` = ?"); 269 | $stmt->bind_param('iiisii', $status, $user['id'], $timestamp, $comment, $notified, $id); 270 | $stmt->execute(); 271 | $result = $stmt->affected_rows > 0 ? 1 : 0; 272 | $stmt->close(); 273 | 274 | return $result; 275 | } 276 | 277 | public function setNotificationStatus($id, $status) { 278 | 279 | # If -1 is returned then either the ID is not a number or the status is not a boolean. 280 | if(!ToolBox::isNumber($id) or !is_bool($status)) return -1; 281 | 282 | $id = intval($id); 283 | $status = $status ? 1 : 0 ; 284 | 285 | $stmt = $this->database->prepare("UPDATE `reportrts_tickets` SET `notified` = ? WHERE `id` = ?"); 286 | $stmt->bind_param('ii', $id, $status); 287 | $stmt->execute(); 288 | $result = $stmt->affected_rows > 0 ? 1 : 0; 289 | $stmt->close(); 290 | 291 | return $result; 292 | } 293 | 294 | public function setUserStatus($username, $status) { 295 | 296 | # User status has to be a boolean. 297 | if(!is_bool($status)) return 0; 298 | 299 | $user = null; 300 | 301 | # Check if user is in cache, and set isBanned to status. 302 | if(array_key_exists($username, $this->userCache)) { 303 | $user = $this->userCache[$username]; 304 | $user['isBanned'] = $status; 305 | } 306 | 307 | $status = $status ? 1 : 0; 308 | 309 | $stmt = $this->database->prepare("UPDATE `reportrts_users` SET `banned` = ? WHERE `name` = ? LIMIT 1"); 310 | $stmt->bind_param("is", $status, $username); 311 | $stmt->execute(); 312 | $result = $stmt->affected_rows; 313 | $stmt->close(); 314 | 315 | # Update cache. 316 | if($result > 0 and $user != null) $this->userCache[$username] = $user; 317 | 318 | return $result; 319 | } 320 | 321 | /** 322 | * @param $username 323 | * @param $id; 324 | * @param $createIfNotExists 325 | * @return Array 326 | */ 327 | public function getUser($username = null, $id = 0, $createIfNotExists = false) { 328 | $sql = null; 329 | if($username != null) { 330 | 331 | # Get the user from the cache if it exists. TODO: Add expiry. 332 | if(array_key_exists($username, $this->userCache)) return $this->userCache[$username]; 333 | 334 | $sql = $this->database->prepare("SELECT * FROM `reportrts_users` WHERE `name` = ? LIMIT 1"); 335 | $sql->bind_param("s", $username); 336 | } 337 | if($username == null and $id > 0) { 338 | $sql = $this->database->prepare("SELECT * FROM `reportrts_users` WHERE `uid` = ?"); 339 | $sql->bind_param("i", $id); 340 | } 341 | 342 | $sql->execute(); 343 | $sql->bind_result($id, $name, $banned); 344 | $sql->fetch(); 345 | 346 | # Create the user if it does not exist. 347 | if($createIfNotExists === true and $id === 0) { 348 | $id = $this->createUser($username); 349 | $name = $username; 350 | $banned = 0; 351 | } 352 | 353 | $array = [ 354 | "id" => (int) $id, 355 | "username" => $name, 356 | "isBanned" => ($banned == 1) ? true : false 357 | ]; 358 | 359 | $sql->close(); 360 | 361 | if(!array_key_exists($username, $this->userCache)) $this->userCache[$username] = $array; 362 | 363 | return $array; 364 | } 365 | 366 | public function reset() { 367 | $this->database->multi_query("TRUNCATE TABLE `reportrts_users`; TRUNCATE TABLE `reportrts_tickets`;"); 368 | } 369 | 370 | public function resetNotifications() { 371 | $query = $this->database->query("UPDATE `reportrts_tickets` SET `notified` = 1 WHERE `notified` = 0"); 372 | return $query; 373 | } 374 | } 375 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/task/LoginTask.php: -------------------------------------------------------------------------------- 1 | plugin = $plugin; 18 | $this->data = $plugin->getDataProvider(); 19 | $this->ticket = $ticket; 20 | } 21 | 22 | public function onRun(int $currentTick) { 23 | 24 | # Attempt to get player, this has the potential to fail. 25 | $player = $this->plugin->getServer()->getPlayer($this->ticket->getName()); 26 | # Player is online, so we send him/her some messages. 27 | if ($player != null) { 28 | $player->sendMessage(MessageHandler::$ticketCloseOffline); 29 | $player->sendMessage(sprintf(MessageHandler::$ticketCloseText, $this->ticket->getMessage(), trim($this->ticket->getComment()))); 30 | } 31 | 32 | $this->data->setNotificationStatus($this->ticket->getId(), true); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/task/MySQLKeepAliveTask.php: -------------------------------------------------------------------------------- 1 | database = $database; 17 | } 18 | 19 | public function onRun(int $currentTick) { 20 | $this->database->ping(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/util/MessageHandler.php: -------------------------------------------------------------------------------- 1 | getConstants(); 60 | self::$broadcast = self::parseColors('%white%[%red%Staff%white%] %red%%s: %green%%s'); 61 | self::$generalError = self::parseColors('%red%An error occurred. Reference: %s'); 62 | self::$permissionError = self::parseColors('%yellow%You need permission "%s" to do that'); 63 | self::$noTickets = self::parseColors('%white%There are no tickets at this time.'); 64 | self::$noStaff = self::parseColors('%yellow%There are no staff members online.'); 65 | self::$holdNoTickets = self::parseColors('%gold%There are no tickets on hold right now.'); 66 | self::$ticketAssign = self::parseColors('%gold%%s has been assigned to ticket #%u.'); 67 | self::$ticketAssignUser = self::parseColors('%gold%Your ticket has been assigned to %s.'); 68 | self::$ticketTooShort = self::parseColors('%red%Your ticket needs to contain at least %s words.'); 69 | self::$ticketTooMany = self::parseColors('%red%You have too many open tickets, please wait before opening more.'); 70 | self::$ticketTooFast = self::parseColors('%red%You need to wait %s seconds before attempting to open another ticket.'); 71 | self::$ticketDuplicate = self::parseColors('%red%Your ticket has not been opened because it was detected as a duplicate.'); 72 | self::$ticketOpenedUser = self::parseColors('%gold%You opened a ticket. A staff member should be with you soon.'); 73 | self::$ticketOpenedStaff = self::parseColors('%green%A new ticket has been opened by %s, id assigned #%u.'); 74 | self::$ticketNotOpen = self::parseColors('%red%Specified ticket is not open.'); 75 | self::$ticketNotClaimed = self::parseColors('%red%You may only unclaim tickets that are claimed.'); 76 | self::$ticketNotExists = self::parseColors('%red%Ticket #%u does not exist.'); 77 | self::$ticketClose = self::parseColors('%gold%Ticket #%u was closed by %s.'); 78 | self::$ticketCloseMulti = self::parseColors('%gold%While you were gone, %u tickets were closed. Use /%s to check your currently open tickets.'); 79 | self::$ticketCloseUser = self::parseColors('%gold%%s completed your ticket.'); 80 | self::$ticketCloseText = self::parseColors('%gold%Ticket text: %yellow%%s %gold%Comment: %yellow%%s'); 81 | self::$ticketCloseOffline = self::parseColors('%gold%One of your tickets have been closed while you were offline.'); 82 | self::$ticketClaim = self::parseColors('%gold%%s is now handling ticket #%u.'); 83 | self::$ticketClaimUser = self::parseColors('%gold%%s is now handling your ticket.'); 84 | self::$ticketUnclaim = self::parseColors('%gold%%s is no longer handling ticket #%u.'); 85 | self::$ticketUnclaimUser = self::parseColors('%gold%%s is no longer handling your ticket.'); 86 | self::$ticketClaimText = self::parseColors('%gold%Ticket text: %yellow%%s'); 87 | self::$ticketHold = self::parseColors('%gold%Ticket #%u was put on hold by %s'); 88 | self::$ticketHoldUser = self::parseColors('%gold%Your ticket was put on hold by %s'); 89 | self::$ticketHoldText = self::parseColors('%gold%Ticket text: %yellow%%s %gold%Reason: %yellow%%s'); 90 | self::$userNotExists = self::parseColors('%red%The specified user %s does not exist or contains invalid characters.'); 91 | self::$userBanned = self::parseColors('%gold%%s has forbid %s from opening new tickets.'); 92 | self::$userUnbanned = self::parseColors('%gold%%s has been pardoned and may open new tickets again.'); 93 | self::$ticketStatusError = self::parseColors('%red%Unable to set ticket status. Check that the status of the ticket does not collide.'); 94 | self::$ticketTeleport = self::parseColors('%blue%Teleported to ticket #%u.'); 95 | self::$separator = self::parseColors('%yellow%, '); 96 | self::$staffList = self::parseColors('%aqua%Staff online: %yellow%%s'); 97 | self::$ticketReopen = self::parseColors('%gold%%s has reopened ticket #%u'); 98 | self::$ticketReopenSelf = self::parseColors('%gold%Ticket #%u has been reopened.'); 99 | } 100 | 101 | /** 102 | * Iterates the color array and replaces the color codes from the provided String. 103 | * @param $message 104 | * @return String 105 | */ 106 | private static function parseColors($message) { 107 | $msg = $message; 108 | foreach(self::$colors as $color => $value) { 109 | $key = "%".strtolower($color)."%"; 110 | if(strpos($msg, $key) !== false) { 111 | $msg = str_replace($key, $value, $msg); 112 | } 113 | } 114 | return $msg; 115 | } 116 | } -------------------------------------------------------------------------------- /src/ProjectInfinity/ReportRTS/util/PermissionHandler.php: -------------------------------------------------------------------------------- 1 | 0) $result .= trim($line); 26 | } 27 | return $result; 28 | } 29 | 30 | public static function countOpenTickets($player) { 31 | $i = 0; 32 | foreach(ReportRTS::$tickets as $ticket) { 33 | if($ticket->getName() == $player) $i++; 34 | } 35 | return $i; 36 | } 37 | 38 | 39 | /** 40 | * Returns a float representing the amount of time in millis it took to execute command 41 | * from start to finish. 42 | * @param $start 43 | * @return float 44 | */ 45 | public static function getTimeSpent($start) { 46 | return (float) number_format((microtime(true) * 1000) - $start, 2, ".", ""); 47 | } 48 | 49 | public static function timeSince($time) { 50 | 51 | # If time is given in seconds as opposed to milliseconds, convert. 52 | if($time < 1000000000000) $time *= 1000; 53 | 54 | $now = microtime(true) * 1000; 55 | if($time > $now || $time <= 0) return null; 56 | $diff = $now - $time; 57 | if($diff < self::MINUTE_MILLIS) { 58 | return TextFormat::GREEN . "just now" . TextFormat::GOLD; 59 | } else if($diff < 2 * self::MINUTE_MILLIS) { 60 | return TextFormat::GREEN . "1 minute ago" . TextFormat::GOLD; // a minute ago 61 | } else if($diff < 50 * self::MINUTE_MILLIS) { 62 | return "" . TextFormat::GREEN . round($diff / self::MINUTE_MILLIS) . " min ago" . TextFormat::GOLD; 63 | } else if($diff < 90 * self::MINUTE_MILLIS) { 64 | return TextFormat::GREEN . "1 hour ago" . TextFormat::GOLD; 65 | } else if ($diff < 24 * self::HOUR_MILLIS) { 66 | return "" . TextFormat::YELLOW . round($diff / self::HOUR_MILLIS) . " hours ago" . TextFormat::GOLD; 67 | } else if ($diff < 48 * self::HOUR_MILLIS) { 68 | return TextFormat::RED . "yesterday" . TextFormat::GOLD; 69 | } else { 70 | return "" . TextFormat::RED . round($diff / self::DAY_MILLIS) . " days ago" . TextFormat::GOLD; 71 | } 72 | } 73 | 74 | /** 75 | * Checks whether the provided String is a Integer or not 76 | * and returns a boolean representing the result. 77 | * @param $number 78 | * @return bool 79 | */ 80 | public static function isNumber($number) { 81 | if(is_numeric($number)) $number = intval($number); 82 | if(!is_int($number) || $number <= 0) { 83 | return false; 84 | } 85 | return true; 86 | } 87 | 88 | /** 89 | * Checks if a user with the provided name is online. 90 | * @param $name 91 | * @return bool 92 | */ 93 | public static function isOnline($name) { 94 | foreach(Server::getInstance()->getOnlinePlayers() as $player) { 95 | if($player->getName() == $name) return true; 96 | } 97 | return false; 98 | } 99 | 100 | /** 101 | * Returns a shortened String in the event that the provided 102 | * String is above 20 characters long. 103 | * @param $message 104 | * @return string 105 | */ 106 | public static function shortenMessage($message) { 107 | if(strlen($message) >= 20) { 108 | $message = substr($message, 0, 20)."..."; 109 | } 110 | return $message; 111 | } 112 | 113 | /** 114 | * Checks if the provided user has a open ticket with a timestamp 115 | * higher than the current time minus the ticket delay. 116 | * @param $username 117 | * @param $delay 118 | * @return Float|int 119 | */ 120 | public static function timeDifference($username, $delay) { 121 | foreach(ReportRTS::$tickets as $ticket) { 122 | if($ticket->getName() == $username) { 123 | if($ticket->getTimestamp() > (microtime(true) - $delay)) { 124 | return $ticket->getTimestamp() - ((microtime(true) - $delay)); 125 | } 126 | } 127 | } 128 | return 0; 129 | } 130 | } --------------------------------------------------------------------------------