diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index 2e60e570..8a1e73a3 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -14,7 +14,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: [ '8.1', '8.2', '8.3' ] + php-versions: [ '8.1', '8.2', '8.3', '8.4' ] steps: - name: "Checkout" uses: "actions/checkout@v4" diff --git a/.gitignore b/.gitignore index b198856f..15c069b1 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ Thumbs.db # /.htaccess -lua +/lua # composer composer.phar diff --git a/CHANGELOG-1.x.md b/CHANGELOG-1.x.md index c6feb09d..b8c57ce7 100644 --- a/CHANGELOG-1.x.md +++ b/CHANGELOG-1.x.md @@ -1,5 +1,195 @@ # Changelog +## [1.8.4 - 27.10.2025] + +### Changed +* Reimport myaac_ tables on every install, this fixes errors when one table is missing or is duplicated (https://github.com/slawkens/myaac/commit/2580edadf84779f09fd395c21f92019b2c762f83) +* Use custom env init on migrate, migrate:run and migrate:to (https://github.com/slawkens/myaac/commit/13ea68cc0c9349380c8e4051d702a6c2c8256f44, https://github.com/slawkens/myaac/commit/07fd034fe4cb0ffdb88667b1e400f414d0c6d06f) + +### Fixed +* Show if there is mysql error on import schema (https://github.com/slawkens/myaac/commit/44110a9496b4385e42c31b75de301037e711b6c3) +* Fix the premium checks, introduced in v1.8.3 (https://github.com/slawkens/myaac/commit/9d92a11fb7cb6d7a1619d79c12faaa0b1c01f980) + +## [1.8.3 - 21.10.2025] + +### Added +* Feature: resend email verify (https://github.com/slawkens/myaac/commit/fe821c58085483e70491dcf76376ad5b96de3fdd) +* New config: hooks_debug (To view where hooks are located in .twig files) (https://github.com/slawkens/myaac/commit/8c3cb0e06f9709c1de3398b48221241e7cbdd310) +* Functions: Add db->getColumnInfo(table, column) (https://github.com/slawkens/myaac/commit/c898fe25efff6793a01d11c26fc153cb23fcb858) +* Plugins: Add option to use ?subtopic=x for plugins pages (https://github.com/slawkens/myaac/commit/97f9d3d6f6c28aef6d824973058d7133f56e09c4) +* getTopPlayers() Function - Add lookmount & promotion (https://github.com/slawkens/myaac/commit/2da0024c68f1cedc38a16ebbc6f52ffa55e65f7a, https://github.com/slawkens/myaac/commit/901df48d134079d648a18f9d82b60182e818ac02) +* New hooks for account/change-password (https://github.com/slawkens/myaac/commit/470555f2687809a0c12491bbb27597e64b8929c1) + +### Changed +* Feature: show vip days in account management (https://github.com/slawkens/myaac/commit/c88b08eb1ec1f560cbfdaaa16b24e3a0f26da7b3, by @andreoam) +* Allow links in error_box.html.twig (https://github.com/slawkens/myaac/commit/9acad15451071639acf7a7d4e81619b0a9742b12) +* Canary - Comment code to update lastday in login.php (https://github.com/slawkens/myaac/commit/38902c30d114fdbce259467f5820f97037b393e9) +* Cache::remember $ttl = -1 = infinite (https://github.com/slawkens/myaac/commit/64acf70d3854182d88aaf0b67f77cea2a254f179) + +### Fixed +* Online - Allow for html code (example - img) in online_datacenter (https://github.com/slawkens/myaac/commit/3bb272ebbbd2eb7769d174b7082061d14a17bd44) +* Guilds - Fix guild create with freePremium enabled (https://github.com/slawkens/myaac/commit/c91bb5d4097647dca2196d3dea87bc90c89181d2) +* Canary - Fix premDays count (https://github.com/slawkens/myaac/commit/3e61692780d4add93b7b0e9f12f7a283bd8f4b7a) +* Template Change: Ignore set last visit for AJAX pages - Fixes template change redirect (https://github.com/slawkens/myaac/commit/89fae38caa7e4f645957fcf1a9330a36358ac04f) +* Admin Panel - Accounts: Fix lastip v6 (TFS master) (https://github.com/slawkens/myaac/commit/f54b1bdd2af4c16c64ddff0e87a6c96bc4cf9eeb) +* Functions - Prevent injection in $db->hasColumn (https://github.com/slawkens/myaac/commit/56bd7ec5ed904666074492f2e4f13e4fce226bee) +* Compat Config: Add missing config: email_lai_sec_interval (https://github.com/slawkens/myaac/commit/2eae44e0755e624a91be68b4d1ec26d01eb4d9a1) + +## [1.8.2 - 26.09.2025] + +### Added +* Routes: Possibility to override routes with plugins pages, like characters.php - No need to define routes in plugin.json anymore (https://github.com/slawkens/myaac/commit/3f24f961b1cdeff5c60387e837ae454448bc5e1b) + +### Changed +* Style: Better look for myaac-table (https://github.com/slawkens/myaac/commit/a6032093b21e5bb3f0e75d2704da87d6dea6469d, https://github.com/slawkens/myaac/commit/5aa9bbf1c8e580d973ec82ac012489f8e7bc437e) + +### Fixed +* Install: Fix when config.local.php cannot be saved (https://github.com/slawkens/myaac/commit/4eab805d26d8c5562b29ed699769919d77dabced) +* Create Account: Fix an exception when email cannot be sent (https://github.com/slawkens/myaac/commit/d0112d1a67e8b854b65ad131f0375b79305df8d3) +* Login Page: Add missing csrf() - fix create account button (https://github.com/slawkens/myaac/commit/3c0cb53e17dd0b85394cfa0fdc9cf9ad8d4551df) +* tibiacom template: Fix account lost menu (https://github.com/slawkens/myaac/commit/ed9beaf2b6ca069e304e569c52e5b9188b58f05c) +* tibiacom template: Fix Menu div wrong tag/closing (#329) (https://github.com/slawkens/myaac/commit/85e7005fd3f0be51466151a3c122b96085fdfe68) +* tibiacom template: Replace firstChild with firstElementChild (Thanks to @un000000) (https://github.com/slawkens/myaac/commit/df7b6e29fb8875da97f431468c81ee99116271d9) + +## [1.8.1 - 05.09.2025] + +### Added +* New Commands: plugin:enable/disable/uninstall {plugin-name} (https://github.com/slawkens/myaac/commit/7a08f91d3fc0897c1ff76089ef3c649a2c6d2003, https://github.com/slawkens/myaac/commit/fec773ba4b740f35c0a3ef92ca8444a4c7d02082) +* Gifts: Added Transferable Coins to the store dropdown menu in the admin area (by @andreoam, #321) (https://github.com/slawkens/myaac/commit/42671c5c199dd9e91c774d8c9d30da9e12f1b695) + +### Changed +* Commands: Allow settings to be changed/reset by plugin name (https://github.com/slawkens/myaac/commit/f8c4332e03e838d285ea0afb4b72b7c23e324d45, https://github.com/slawkens/myaac/commit/4b948e9510f7ba69d00f84d7fdaea8b3bf05b630) +* Templates: Menus should be saved for each template separately (https://github.com/slawkens/myaac/commit/482f4067b2a2e7513d9ba214274a361ffaf123d8) + +### Fixed +* Online: Fix skulls display (#320) (https://github.com/slawkens/myaac/commit/98073a110ae13f9592ec9d2c4d1d1aace87587a9) +* Online: Fix if there is no world_id in the server_record table (https://github.com/slawkens/myaac/commit/b6e1620f14c20eecfc9001a7d86dfb67942985c6) (Reported by @gesior in #318) +* tibiacom: some fixes to menus (https://github.com/slawkens/myaac/commit/20f99903ae80c74ad66c1cf5a5ea8d0b0fc2fd70, https://github.com/slawkens/myaac/commit/11dae90fa94fbbf47447017db5e5847c33d6aadf) +* Guilds: Fix for some servers that don't have guild_invites table (https://github.com/slawkens/myaac/commit/9725a3c2bdb7003f5cb48febb77604c31a9b805b) + +## [1.8 - 02.08.2025] + +### Added +* Templates - Kathrine: Possibility to add custom menu categories (https://github.com/slawkens/myaac/commit/ec11c1402417c25980582467546d1c1e9bb8267f) +* Admin Panel - Accounts Editor: Add Coins Transferable (https://github.com/slawkens/myaac/commit/45d6047031c9c3a0e7e512dc5d15c75629aec5a2, https://github.com/slawkens/myaac/commit/bb097b69ce106500a49686d6f4fe604348eaa310) +* Highscores: + * Revamped: (https://github.com/slawkens/myaac/commit/d8132d4d76e03d5aa0c042be426320655a601392) + * Show real rank, if 2 or more players have the same skill, show them with same rank + * New setting: highscores_online_status + * Additional fields passed to twig: updatedAt, totalResults, page, baseLink + * Add new Setting: Display Skills Box (https://github.com/slawkens/myaac/commit/36ca755243ef1c83f6ac87465b426d4d8d3b0bb9) +* Functions: Add getExperienceForLevel (level) (https://github.com/slawkens/myaac/commit/1566deb84a082176b8c683fda205d828bc38fbcc) +* Commands - cache:clear : Add warning about APCu clear in CLI (https://github.com/slawkens/myaac/commit/83f84172e02e8ea2ccb6dca29bc033e44c35aebc) +* Models - PlayerOnline: Add missing $fillable into model (https://github.com/slawkens/myaac/commit/43415cf35db1c1307f2684c1728693d65065ffff) +* Twig: add cache variable (https://github.com/slawkens/myaac/commit/0efe47ce71c4b364a9e96bc5a55b1655326ae6da) + +### Changed +* pages/online: add cache, resulting in 20x performance boost + * (for an example server with 2k players) (https://github.com/slawkens/myaac/commit/c8363086015cbb6e8786c398c7b9ac3959a26ec4) +* Admin Bar: Move admin bar code into body_start place_holder (https://github.com/slawkens/myaac/commit/f17269e44ce9dd38447bd2e2a8e1bdb065d4161f) +* Cache::remember: $ttl = 0 means no cache (https://github.com/slawkens/myaac/commit/3b47e9df2f4051807c5ff87892f7fa3d348f9c55) +* Templates: Load config.ini with $process_sections set to true (https://github.com/slawkens/myaac/commit/a89f9a84847630eb75b4890fdcc8b7a7bfa6b8ac) +* Twig: Allow for timestamp as integer in the timeago twig function + (https://github.com/slawkens/myaac/commit/34fead906ea13b9f09d7a3c41ed88109d34d386c) + +### Fixed +* Settings: Fixed two exceptions (https://github.com/slawkens/myaac/commit/6e5a4ff8c78ff5373aba091baa66cae029557643, https://github.com/slawkens/myaac/commit/20d69a641c0a933d14889a89da6d32f6a4bc6c7d) +* Models\Account + OTS_Account -> isPremium -> ignore config.freePremium (https://github.com/slawkens/myaac/commit/5271633bdbfbbfed0b1d59c403093ce6fc2b7d20) +* Admin Panel - Mailer: + * Fix send to email link redirecting from accounts page (https://github.com/slawkens/myaac/commit/080cc2781f034c844af658229e495e9a47fd2298) + * Option to send only to verified accounts - only if setting('core.account_mail_verify') enabled (https://github.com/slawkens/myaac/commit/cf7fd20452e863980045bb5d6012ec86c6e8e01f) + +### Internal +* Rewrite to use constants (account transferable coins) (https://github.com/slawkens/myaac/commit/bccf8e056df985bbe1bab5f7ab5492f714d6b62b) +* Refactor to use HAS_ACCOUNT_COINS (https://github.com/slawkens/myaac/commit/caf326a6584a234775ebc6c8000ea02b3fecd160) + +## [1.7.1 - 27.06.2025] + +### Changed +* Rename plugin:install:install to plugin:setup, also add alias to previous command (https://github.com/slawkens/myaac/commit/13d33822b59df349199e885a78a3d6beb0863d0b) + +### Fixed +* Fix commands: setup + cache:clear (https://github.com/slawkens/myaac/commit/0da524fefe93b3028392e9014550eea3324d3a22, https://github.com/slawkens/myaac/commit/fe8281594e989f00280ba1adc734a9198c6b5cc1) +* Fix polls link in tibiacom template (https://github.com/slawkens/myaac/commit/d90fa323d7c77d81768df60feeb1c374b1650a0c) + +## [1.7 - 22.06.2025] + +### Added +* Feature: plugins versions check (#310) +* New hooks: HOOK_ACCOUNT_MANAGE_AFTER_CHARACTERS, HOOK_GUILDS_AFTER_MANAGE_BUTTON (https://github.com/slawkens/myaac/commit/c074a48f245df55646b6705737f667b6a84149b2, https://github.com/slawkens/myaac/commit/e6100a1b72de8695bba1dae9ba4e28bfdce47b10) +* Add OTS_Toolbox::getVocationName(id, promotion) + OTS_Player->isNameLocked() (https://github.com/slawkens/myaac/commit/e222957893c4a1de0dc8dbba55bce1a43418d275, https://github.com/slawkens/myaac/commit/522f6c11d835afd36fd07a07074d96d7e219b488) +* Add missing csrf in more places, causing white page with error about Request (https://github.com/slawkens/myaac/commit/dca904e61d21d856bf809070e7652803a2df0f58, https://github.com/slawkens/myaac/commit/c720ccc451ff90ef40b2a1595468d061ffd7e1e4) + +### Changed +* Revamped online page (https://github.com/slawkens/myaac/commit/9a90e4aae280e607430511c6727d9a714b11f4c5, https://github.com/slawkens/myaac/commit/4767120043b09141870383e249f3729638d53dc2) +* Better $title inventing (https://github.com/slawkens/myaac/commit/0c95bcfd06b68b21512e477646ef7bd3a0d4912b) + +### Fixed +* Use apcu cache clear (https://github.com/slawkens/myaac/commit/b329da52aae9d0e21120a6444d3caf442420ce50, https://github.com/slawkens/myaac/commit/566c2a9151ab6392286f74e26853faa19a1b4f24) +* fix: boostedcreatures for 13.40 (by @GooseWithAKnife) (#307) + +## [1.6.1 - 11.06.2025] + +### Fixed +* Fixed "Request has been cancelled due to security reasons", cause of missing csrf() in twig files (https://github.com/slawkens/myaac/commit/10cd71a6630ffec91b43a26a6d685b66c5836a6a) +* Fix: Ignore duplicated route exception (https://github.com/slawkens/myaac/commit/9d8e9d27bd87167d8d4005942a6af62bfe4c0892) + +### Changed +* Move counter & visitors code before router (In case someone wants to include that info on page) (https://github.com/slawkens/myaac/commit/f78285030708ad3c74ab048711f73bbf3ee5281e) +* Set TinyMCE license key to gpl (Avoid warning message in browser console) (https://github.com/slawkens/myaac/commit/8d29fdb98b92dbc3d2853ef88a185c67036b4a77) + +### Removed +* Remove deprecated TinyMCE plugin - template (https://github.com/slawkens/myaac/commit/309c1fb715b882e67cb673b1544a03befbf64a22) + +## [1.6 - 03.06.2025] + +### Added +* Add new setting/configurable: site_url, prevents domain spoofing (https://github.com/slawkens/myaac/commit/d8a6090be382c35c19117cfef964b594ed02b8d4) +* Add new account coins setting (https://github.com/slawkens/myaac/commit/28886551e86fe562172c4c7f2afb89a2e7672c2e) +* autoload: settings/install/init.php (https://github.com/slawkens/myaac/commit/e5749437074c3b3556628a2aeb5bad2edf97bde0, https://github.com/slawkens/myaac/commit/7d213f479a7e40c6254069b5fc4e578dc32bf8d9, https://github.com/slawkens/myaac/commit/207d6bc69120aba1af2b51808f17e0059b571fed) +* Protect against csrf in more places (accounts & guilds & forums pages) (https://github.com/slawkens/myaac/commit/6eda38603c8ed7e99b92a78a4600b1245377f74d, https://github.com/slawkens/myaac/commit/e776bd52beb3064a9e694efd1b9021ec972ee2f6, https://github.com/slawkens/myaac/commit/84d502bf105f2a789481fba1acc820d236b4de66) +* Added two new hooks for pages loaded from database (custom pages): HOOK_BEFORE_PAGE_CUSTOM, HOOK_AFTER_PAGE_CUSTOM (https://github.com/slawkens/myaac/commit/c961a1ebf837f2ab1734a825ff2c57b4937610c9) +* Add global variables into $hooks->executeFilter (https://github.com/slawkens/myaac/commit/8fdea943768b20193eede99d60313ee84511a0be) +* Add getNPCsCount() to OTS_InfoRespond (https://github.com/slawkens/myaac/commit/7d435ff6433ef1fb2295ee79ed043ee10dc725e9) + +### Fixed +* Allow [] in character name (https://github.com/slawkens/myaac/commit/de6603a51347b9e656c58637ed9971fffdd7cedd) +* Do not allow access to tools/ folder after install (https://github.com/slawkens/myaac/commit/6e0f5913831f8dba69fd2d1505be3e2a303c6324) +* Fix CHANGELOG-1.x.md loading in admin panel (https://github.com/slawkens/myaac/commit/4a30fb495dbfbe1d434e8d52419eaf44fe517aee) +* Fix links not working in admin dashboard modules (https://github.com/slawkens/myaac/commit/be7b27c31aa3bbd6c0289c34d1e61139a3fe015c) +* Fix twig variables: logged + account_logged being not set directly after login (https://github.com/slawkens/myaac/commit/1e9b10d6489c488cadf7f6ed17b42f1ea6c767a8) + +### Changed +* OTS_ServerInfo -> move setTimeout out of class - Possibility to use the class without MyAAC (https://github.com/slawkens/myaac/commit/40d65a6613149fda51bdceb82c807e5301a3388b) + +## [1.5 - 14.05.2025] + +### Added +* Feature/twig hooks filters (#258) +* Add latest client versions (14.00 - 15.01) (https://github.com/slawkens/myaac/commit/5367df23812c6182863353c9a39fd7fb0b743f4b) +* db variable to twig (https://github.com/slawkens/myaac/commit/5ed1aec28e146b871a75597411d12e42a067f4e6) +* New filter: HOOK_FILTER_ROUTES (https://github.com/slawkens/myaac/commit/9b75011224f385db8b27e109bfeb28e75b9d779c) +* Allow optionally separate folder for views (thanks @Scrollog for idea) (https://github.com/slawkens/myaac/commit/03e275213901a89edb0ebb8974b776a992ab391f) +* Add float & double types to the Settings (https://github.com/slawkens/myaac/commit/67ab425bb9796d9d123296e3fda542fa8f7f05ee) +* Add optional param _page_only for single-page apps etc. (https://github.com/slawkens/myaac/commit/113473f2560aab6d364c301cc14a8b5ba8f309f4) + +### Changed +* Change OTS_Account->getPremDays to not return -1 in case of freePremium (https://github.com/slawkens/myaac/commit/3befde2a1e4d24a011311e785f15185db57e19b8) +* Add note about highscores being updated x minutes + allow ttl 0 to disable cache (https://github.com/slawkens/myaac/commit/a161cff00329da6f970f3a70967fe8346fe92bbc) +* Better monster images (no image not found anymore) + use cache (https://github.com/slawkens/myaac/commit/73a5829974ceca3f02d7925d5cfbd5fa50b1bbd2) +* Rename server-info -> ots-info, changelog -> change-log (Due to conflict with apache2 server-info mod) (https://github.com/slawkens/myaac/commit/3949d84e5d7631f332111b6d00278bddbd0ad10a) +* Move rules page to admin panel (https://github.com/slawkens/myaac/commit/3949d84e5d7631f332111b6d00278bddbd0ad10a) + +### Fixed +* php 8.4 warnings +* Visitors counter not working properly on dev mode (https://github.com/slawkens/myaac/commit/da151051186c913dd0dd091aabe893649c2b9ee7) +* Fix login.php boosted creature & boss (not sure exact version, but should be 14.12 or around) (https://github.com/slawkens/myaac/commit/c48b8006319f6c3b5f082befd16785420bb98110) +* Fix installMenus when theme/template was removed from disc (https://github.com/slawkens/myaac/commit/c24c580796bccd54bf9e95b864763f4642684d55) +* Fix if user removes the menu category (https://github.com/slawkens/myaac/commit/dbea69f31478391dacfbbc02c8353c39b4245daf) + +### Updated: +* Update cypress from version ^13.17.0 to ^14.3.3 (https://github.com/slawkens/myaac/commit/629fd18ea166860d5898a822f44f9277da6ce43d) + ## [1.4 - 22.04.2025] ### Added diff --git a/README.md b/README.md index e34e806a..54b27d07 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Pull requests should be made to the *develop* branch as that is the working bran Bug fixes to current release should be done to master branch. -Look: [Contributing](https://github.com/otsoft/myaac/wiki/Contributing) in our wiki. +Look: [Contributing](https://docs.my-aac.org/misc/contributing) in our wiki. ### Other Notes @@ -95,4 +95,4 @@ Many thanks to Jetbrains for kindly providing a license for me to work on this a ### License This program and all associated files are released under the GNU Public License. -See [LICENSE](https://github.com/slawkens/myaac/blob/master/LICENSE) for details. +See [LICENSE](https://github.com/slawkens/myaac/blob/main/LICENSE) for details. diff --git a/aac b/aac index d4ce7b7d..8f213136 100644 --- a/aac +++ b/aac @@ -25,7 +25,9 @@ foreach ($commandsGlob as $item) { } $commandPre = '\\MyAAC\Commands\\'; - $application->add(new ($commandPre . $name)); + if (!trait_exists($class = $commandPre . $name)) { + $application->add(new $class); + } } $pluginCommands = Plugins::getCommands(); diff --git a/admin/pages/accounts.php b/admin/pages/accounts.php index 67381b5e..8a20aa62 100644 --- a/admin/pages/accounts.php +++ b/admin/pages/accounts.php @@ -27,7 +27,6 @@ if (setting('core.account_country')) $nameOrNumberColumn = getAccountIdentityColumn(); $hasSecretColumn = $db->hasColumn('accounts', 'secret'); -$hasCoinsColumn = $db->hasColumn('accounts', 'coins'); $hasPointsColumn = $db->hasColumn('accounts', 'premium_points'); $hasTypeColumn = $db->hasColumn('accounts', 'type'); $hasGroupColumn = $db->hasColumn('accounts', 'group_id'); @@ -137,11 +136,18 @@ else if (isset($_REQUEST['search'])) { if (!Validator::email($email)) $errors['email'] = Validator::getLastError(); - //tibia coins - if ($hasCoinsColumn) { + // tibia coins + if (HAS_ACCOUNT_COINS) { $t_coins = $_POST['t_coins']; verify_number($t_coins, 'Tibia coins', 12); } + + // transferable tibia coins + if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) { + $t_coins_transferable = $_POST['t_coins_transferable']; + verify_number($t_coins_transferable, 'Transferable Tibia coins', 12); + } + // prem days $p_days = (int)$_POST['p_days']; verify_number($p_days, 'Prem days', 11); @@ -186,12 +192,18 @@ else if (isset($_REQUEST['search'])) { if ($hasSecretColumn) { $account->setCustomField('secret', $secret); } + $account->setCustomField('key', $key); $account->setEMail($email); - if ($hasCoinsColumn) { + + if (HAS_ACCOUNT_COINS) { $account->setCustomField('coins', $t_coins); } + if (HAS_ACCOUNT_COINS_TRANSFERABLE || HAS_ACCOUNT_TRANSFERABLE_COINS) { + $account->setCustomField(ACCOUNT_COINS_TRANSFERABLE_COLUMN, $t_coins_transferable); + } + $lastDay = 0; if($p_days != 0 && $p_days != OTS_Account::GRATIS_PREMIUM_DAYS) { $lastDay = time(); @@ -224,9 +236,6 @@ else if (isset($_REQUEST['search'])) { $password = encrypt($password); $account->setPassword($password); - - if (USE_ACCOUNT_SALT) - $account->setCustomField('salt', $salt); } $account->save(); @@ -396,12 +405,18 @@ else if (isset($_REQUEST['search'])) { getEMail() . '">Send Mail)' : ''); ?> - +
$config['visitors_counter'] = true;
+ You can enable it in Settings -> General -> Visitors Counter.* Note: as this class extends DOMDocument class and contains exacly respond XML tree you can work on it as on normal DOM tree. *
- * + * * @package POT * @version 0.1.0 * @property-read string $tspqVersion Root element version. @@ -48,252 +48,257 @@ class OTS_InfoRespond extends DOMDocument { /** * Returns version of root element. - * + * * @return string TSPQ version. * @throws DOMException On DOM operation error. */ - public function getTSPQVersion() - { - return $this->documentElement->getAttribute('version'); - } + public function getTSPQVersion() + { + return $this->documentElement->getAttribute('version'); + } /** * Returns server uptime. - * + * * @return int Uptime. * @throws DOMException On DOM operation error. */ - public function getUptime() - { - return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('uptime'); - } + public function getUptime() + { + return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('uptime'); + } /** * Returns server IP. - * + * * @return string IP. * @throws DOMException On DOM operation error. */ - public function getIP() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('ip'); - } + public function getIP() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('ip'); + } /** * Returns server name. - * + * * @return string Name. * @throws DOMException On DOM operation error. */ - public function getName() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('servername'); - } + public function getName() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('servername'); + } /** * Returns server port. - * + * * @return int Port. * @throws DOMException On DOM operation error. */ - public function getPort() - { - return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('port'); - } + public function getPort() + { + return (int) $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('port'); + } /** * Returns server location. - * + * * @return string Location. * @throws DOMException On DOM operation error. */ - public function getLocation() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('location'); - } + public function getLocation() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('location'); + } /** * Returns server website. - * + * * @return string Website URL. * @throws DOMException On DOM operation error. */ - public function getURL() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('url'); - } + public function getURL() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('url'); + } /** * Returns server attribute. - * + * * I have no idea what the hell is it representing :P. - * + * * @return string Attribute value. * @throws DOMException On DOM operation error. */ - public function getServer() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('server'); - } + public function getServer() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('server'); + } /** * Returns server version. - * + * * @return string Version. * @throws DOMException On DOM operation error. */ - public function getServerVersion() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('version'); - } + public function getServerVersion() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('version'); + } /** * Returns dedicated version of client. - * + * * @return string Version. * @throws DOMException On DOM operation error. */ - public function getClientVersion() - { - return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('client'); - } + public function getClientVersion() + { + return $this->documentElement->getElementsByTagName('serverinfo')->item(0)->getAttribute('client'); + } /** * Returns owner name. - * + * * @return string Owner name. * @throws DOMException On DOM operation error. */ - public function getOwner() - { - return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('name'); - } + public function getOwner() + { + return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('name'); + } /** * Returns owner e-mail. - * + * * @return string Owner e-mail. * @throws DOMException On DOM operation error. */ - public function getEMail() - { - return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('email'); - } + public function getEMail() + { + return $this->documentElement->getElementsByTagName('owner')->item(0)->getAttribute('email'); + } /** * Returns current amount of players online. - * + * * @return int Count of players. * @throws DOMException On DOM operation error. */ - public function getOnlinePlayers() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('online'); - } + public function getOnlinePlayers() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('online'); + } /** * Returns maximum amount of players online. - * + * * @return int Maximum allowed count of players. * @throws DOMException On DOM operation error. */ - public function getMaxPlayers() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('max'); - } + public function getMaxPlayers() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('max'); + } /** * Returns record of online players. - * + * * @return int Players online record. * @throws DOMException On DOM operation error. */ - public function getPlayersPeak() - { - return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('peak'); - } + public function getPlayersPeak() + { + return (int) $this->documentElement->getElementsByTagName('players')->item(0)->getAttribute('peak'); + } /** * Returns number of all monsters on map. - * + * * @return int Count of monsters. * @throws DOMException On DOM operation error. */ - public function getMonstersCount() - { - return (int) $this->documentElement->getElementsByTagName('monsters')->item(0)->getAttribute('total'); - } + public function getMonstersCount(): int + { + return (int) $this->documentElement->getElementsByTagName('monsters')->item(0)->getAttribute('total'); + } + + public function getNPCsCount(): int + { + return (int) $this->documentElement->getElementsByTagName('npcs')->item(0)->getAttribute('total'); + } /** * Returns map name. - * + * * @return string Map name. * @throws DOMException On DOM operation error. */ - public function getMapName() - { - return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('name'); - } + public function getMapName() + { + return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('name'); + } /** * Returns map author. - * + * * @return string Mapper name. * @throws DOMException On DOM operation error. */ - public function getMapAuthor() - { - return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('author'); - } + public function getMapAuthor() + { + return $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('author'); + } /** * Returns map width. - * + * * @return int Map width. * @throws DOMException On DOM operation error. */ - public function getMapWidth() - { - return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('width'); - } + public function getMapWidth() + { + return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('width'); + } /** * Returns map height. - * + * * @return int Map height. * @throws DOMException On DOM operation error. */ - public function getMapHeight() - { - return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('height'); - } + public function getMapHeight() + { + return (int) $this->documentElement->getElementsByTagName('map')->item(0)->getAttribute('height'); + } /** * Returns server's Message Of The Day - * + * * @version 0.1.0 * @return string Server MOTD. * @throws DOMException On DOM operation error. */ - public function getMOTD() - { - // look for text node child - foreach( $this->documentElement->getElementsByTagName('motd')->item(0)->childNodes as $child) - { - if($child->nodeType == XML_TEXT_NODE) - { - // found - return $child->nodeValue; - } - } + public function getMOTD() + { + // look for text node child + foreach( $this->documentElement->getElementsByTagName('motd')->item(0)->childNodes as $child) + { + if($child->nodeType == XML_TEXT_NODE) + { + // found + return $child->nodeValue; + } + } - // strange... - return ''; - } + // strange... + return ''; + } /** * Magic PHP5 method. - * + * * @version 0.1.0 * @since 0.1.0 * @param string $name Property name. @@ -301,89 +306,89 @@ class OTS_InfoRespond extends DOMDocument * @throws OutOfBoundsException For non-supported properties. * @throws DOMException On DOM operation error. */ - public function __get($name) - { - switch($name) - { - case 'tspqVersion': - return $this->getTSPQVersion(); + public function __get($name) + { + switch($name) + { + case 'tspqVersion': + return $this->getTSPQVersion(); - case 'uptime': - return $this->getUptime(); + case 'uptime': + return $this->getUptime(); - case 'ip': - return $this->getIP(); + case 'ip': + return $this->getIP(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'port': - return $this->getPort(); + case 'port': + return $this->getPort(); - case 'location': - return $this->getLocation(); + case 'location': + return $this->getLocation(); - case 'url': - return $this->getURL(); + case 'url': + return $this->getURL(); - case 'server': - return $this->getServer(); + case 'server': + return $this->getServer(); - case 'serverVersion': - return $this->getServerVersion(); + case 'serverVersion': + return $this->getServerVersion(); - case 'clientVersion': - return $this->getClientVersion(); + case 'clientVersion': + return $this->getClientVersion(); - case 'owner': - return $this->getOwner(); + case 'owner': + return $this->getOwner(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'onlinePlayers': - return $this->getOnlinePlayers(); + case 'onlinePlayers': + return $this->getOnlinePlayers(); - case 'maxPlayers': - return $this->getMaxPlayers(); + case 'maxPlayers': + return $this->getMaxPlayers(); - case 'playersPeak': - return $this->getPlayersPeak(); + case 'playersPeak': + return $this->getPlayersPeak(); - case 'monstersCount': - return $this->getMonstersCount(); + case 'monstersCount': + return $this->getMonstersCount(); - case 'mapName': - return $this->getMapName(); + case 'mapName': + return $this->getMapName(); - case 'mapAuthor': - return $this->getMapAuthor(); + case 'mapAuthor': + return $this->getMapAuthor(); - case 'mapWidth': - return $this->getMapWidth(); + case 'mapWidth': + return $this->getMapWidth(); - case 'mapHeight': - return $this->getMapHeight(); + case 'mapHeight': + return $this->getMapHeight(); - case 'motd': - return $this->getMOTD(); + case 'motd': + return $this->getMOTD(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } /** * Returns string representation of XML. - * + * * @version 0.1.0 * @since 0.1.0 * @return string String representation of object. */ - public function __toString() - { - return $this->saveXML(); - } + public function __toString() + { + return $this->saveXML(); + } } /**#@-*/ diff --git a/system/libs/pot/OTS_Player.php b/system/libs/pot/OTS_Player.php index 7b688d1c..099f5db1 100644 --- a/system/libs/pot/OTS_Player.php +++ b/system/libs/pot/OTS_Player.php @@ -2919,6 +2919,32 @@ class OTS_Player extends OTS_Row_DAO $this->data['banned'] = $ban['active']; $this->data['banned_time'] = $ban['expires']; } + + public function isNameLocked(): bool + { + // nothing can't be banned + if( !$this->isLoaded() ) { + throw new E_OTS_NotLoaded(); + } + + if($this->db->hasTable('player_namelocks')) { + $ban = $this->db->query('SELECT 1 FROM `player_namelocks` WHERE `player_id` = ' . $this->data['id'])->fetch(PDO::FETCH_ASSOC); + return (isset($ban['1'])); + } + else if($this->db->hasTable('bans')) { + if($this->db->hasColumn('bans', 'active')) { + $ban = $this->db->query('SELECT `active`, `expires` FROM `bans` WHERE `type` = 2 AND `active` = 1 AND `value` = ' . $this->data['id'] . ' AND (`expires` > ' . time() .' OR `expires` = -1) ORDER BY `expires` DESC')->fetch(); + return isset($ban['active']); + } + else { // tfs 0.2 + $ban = $this->db->query('SELECT `time` FROM `bans` WHERE `type` = 2 AND `account` = ' . $this->data['account_id'] . ' AND (`time` > ' . time() .' OR `time` = -1) ORDER BY `time` DESC')->fetch(); + + return isset($ban['time']) && ($ban['time'] == -1 || $ban['time'] > 0); + } + } + + return false; + } /** * Deletes player. * @@ -2953,21 +2979,14 @@ class OTS_Player extends OTS_Row_DAO * @return string Player proffesion name. * @throws E_OTS_NotLoaded If player is not loaded or global vocations list is not loaded. */ - public function getVocationName() + public function getVocationName(): string { if( !isset($this->data['vocation']) ) { throw new E_OTS_NotLoaded(); } - global $config; - $voc = $this->getVocation(); - if(!isset($config['vocations'][$voc])) { - return 'Unknown'; - } - - return $config['vocations'][$voc]; - //return POT::getInstance()->getVocationsList()->getVocationName($this->data['vocation']); + return OTS_Toolbox::getVocationName($this->data['vocation'], $this->data['promotion'] ?? 0); } /** diff --git a/system/libs/pot/OTS_ServerInfo.php b/system/libs/pot/OTS_ServerInfo.php index eebe0d2e..76ebcaf7 100644 --- a/system/libs/pot/OTS_ServerInfo.php +++ b/system/libs/pot/OTS_ServerInfo.php @@ -26,14 +26,19 @@ class OTS_ServerInfo * * @var string */ - private $server; + private string $server; /** * Connection port. * * @var int */ - private $port; + private int $port; + + /** + * Status timeout + */ + private float $timeout = 2.0; /** * Creates handler for new server. @@ -41,11 +46,11 @@ class OTS_ServerInfo * @param string $server Server IP/domain. * @param int $port OTServ port. */ - public function __construct($server, $port) - { - $this->server = $server; - $this->port = $port; - } + public function __construct($server, $port) + { + $this->server = $server; + $this->port = $port; + } /** * Sends packet to server. @@ -54,46 +59,46 @@ class OTS_ServerInfo * @return OTS_Buffer|null Respond buffer (null if server is offline). * @throws E_OTS_OutOfBuffer When there is read attemp after end of packet stream. */ - private function send(OTS_Buffer $packet) - { - // connects to server - $socket = @fsockopen($this->server, $this->port, $error, $message, setting('core.status_timeout')); + private function send(OTS_Buffer $packet) + { + // connects to server + $socket = @fsockopen($this->server, $this->port, $error, $message, $this->timeout); - // if connected then checking statistics - if($socket) - { - // sets 5 second timeout for reading and writing - stream_set_timeout($socket, 5); + // if connected then checking statistics + if($socket) + { + // sets 5 second timeout for reading and writing + stream_set_timeout($socket, 5); - // creates real packet - $packet = $packet->getBuffer(); - $packet = pack('v', strlen($packet) ) . $packet; + // creates real packet + $packet = $packet->getBuffer(); + $packet = pack('v', strlen($packet) ) . $packet; - // sends packet with request - // 06 - length of packet, 255, 255 is the comamnd identifier, 'info' is a request - fwrite($socket, $packet); + // sends packet with request + // 06 - length of packet, 255, 255 is the comamnd identifier, 'info' is a request + fwrite($socket, $packet); - // reads respond - //$data = stream_get_contents($socket); + // reads respond + //$data = stream_get_contents($socket); $data = ''; while (!feof($socket)) $data .= fgets($socket, 1024); - // closing connection to current server - fclose($socket); + // closing connection to current server + fclose($socket); - // sometimes server returns empty info - if( empty($data) ) - { - // returns offline state - return false; - } + // sometimes server returns empty info + if( empty($data) ) + { + // returns offline state + return false; + } - return new OTS_Buffer($data); - } + return new OTS_Buffer($data); + } - return false; - } + return false; + } /** * Queries server status. @@ -108,30 +113,30 @@ class OTS_ServerInfo * @example examples/info.php info.php * @tutorial POT/Server_status.pkg */ - public function status() - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(255); - $request->putString('info', false); + public function status() + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(255); + $request->putString('info', false); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - // loads respond XML - $info = new OTS_InfoRespond(); - if(!$info->loadXML( $status->getBuffer())) + // checks if server is online + if($status) + { + // loads respond XML + $info = new OTS_InfoRespond(); + if(!$info->loadXML( $status->getBuffer())) return false; - return $info; - } + return $info; + } - // offline - return false; - } + // offline + return false; + } /** * Queries server information. @@ -146,26 +151,26 @@ class OTS_ServerInfo * @example examples/server.php info.php * @tutorial POT/Server_status.pkg */ - public function info($flags) - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(1); - $request->putShort($flags); + public function info($flags) + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(1); + $request->putShort($flags); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - // loads respond - return new OTS_ServerStatus($status); - } + // checks if server is online + if($status) + { + // loads respond + return new OTS_ServerStatus($status); + } - // offline - return false; - } + // offline + return false; + } /** * Checks player online status. @@ -180,27 +185,27 @@ class OTS_ServerInfo * @example examples/server.php info.php * @tutorial POT/Server_status.pkg */ - public function playerStatus($name) - { - // request packet - $request = new OTS_Buffer(); - $request->putChar(255); - $request->putChar(1); - $request->putShort(OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); - $request->putString($name); + public function playerStatus($name) + { + // request packet + $request = new OTS_Buffer(); + $request->putChar(255); + $request->putChar(1); + $request->putShort(OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); + $request->putString($name); - $status = $this->send($request); + $status = $this->send($request); - // checks if server is online - if($status) - { - $status->getChar(); - return (bool) $status->getChar(); - } + // checks if server is online + if($status) + { + $status->getChar(); + return (bool) $status->getChar(); + } - // offline - return false; - } + // offline + return false; + } /** * Magic PHP5 method. @@ -210,20 +215,24 @@ class OTS_ServerInfo * @throws OutOfBoundsException For non-supported properties. * @throws E_OTS_OutOfBuffer When there is read attemp after end of packet stream. */ - public function __get($name) - { - switch($name) - { - case 'status': - return $this->status(); + public function __get($name) + { + switch($name) + { + case 'status': + return $this->status(); - case 'info': - return $this->info(OTS_ServerStatus::REQUEST_BASIC_SERVER_INFO | OTS_ServerStatus::REQUEST_OWNER_SERVER_INFO | OTS_ServerStatus::REQUEST_MISC_SERVER_INFO | OTS_ServerStatus::REQUEST_PLAYERS_INFO | OTS_ServerStatus::REQUEST_MAP_INFO | OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); + case 'info': + return $this->info(OTS_ServerStatus::REQUEST_BASIC_SERVER_INFO | OTS_ServerStatus::REQUEST_OWNER_SERVER_INFO | OTS_ServerStatus::REQUEST_MISC_SERVER_INFO | OTS_ServerStatus::REQUEST_PLAYERS_INFO | OTS_ServerStatus::REQUEST_MAP_INFO | OTS_ServerStatus::REQUEST_PLAYER_STATUS_INFO); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } + + public function setTimeout($timeout) { + $this->timeout = $timeout; + } } /**#@-*/ diff --git a/system/libs/pot/OTS_ServerStatus.php b/system/libs/pot/OTS_ServerStatus.php index e13a0f5b..4ba0035c 100644 --- a/system/libs/pot/OTS_ServerStatus.php +++ b/system/libs/pot/OTS_ServerStatus.php @@ -40,175 +40,175 @@ class OTS_ServerStatus /** * Basic server info. */ - const REQUEST_BASIC_SERVER_INFO = 1; + const REQUEST_BASIC_SERVER_INFO = 1; /** * Server owner info. */ - const REQUEST_OWNER_SERVER_INFO = 2; + const REQUEST_OWNER_SERVER_INFO = 2; /** * Server extra info. */ - const REQUEST_MISC_SERVER_INFO = 4; + const REQUEST_MISC_SERVER_INFO = 4; /** * Players stats info. */ - const REQUEST_PLAYERS_INFO = 8; + const REQUEST_PLAYERS_INFO = 8; /** * Map info. */ - const REQUEST_MAP_INFO = 16; + const REQUEST_MAP_INFO = 16; /** * Extended players info. */ - const REQUEST_EXT_PLAYERS_INFO = 32; + const REQUEST_EXT_PLAYERS_INFO = 32; /** * Player status info. */ - const REQUEST_PLAYER_STATUS_INFO = 64; + const REQUEST_PLAYER_STATUS_INFO = 64; /** * Server software info. */ - const REQUEST_SERVER_SOFTWARE_INFO = 128; + const REQUEST_SERVER_SOFTWARE_INFO = 128; /** * Basic server respond. */ - const RESPOND_BASIC_SERVER_INFO = 0x10; + const RESPOND_BASIC_SERVER_INFO = 0x10; /** * Server owner respond. */ - const RESPOND_OWNER_SERVER_INFO = 0x11; + const RESPOND_OWNER_SERVER_INFO = 0x11; /** * Server extra respond. */ - const RESPOND_MISC_SERVER_INFO = 0x12; + const RESPOND_MISC_SERVER_INFO = 0x12; /** * Players stats respond. */ - const RESPOND_PLAYERS_INFO = 0x20; + const RESPOND_PLAYERS_INFO = 0x20; /** * Map respond. */ - const RESPOND_MAP_INFO = 0x30; + const RESPOND_MAP_INFO = 0x30; /** * Extended players info. */ - const RESPOND_EXT_PLAYERS_INFO = 0x21; + const RESPOND_EXT_PLAYERS_INFO = 0x21; /** * Player status info. */ - const RESPOND_PLAYER_STATUS_INFO = 0x22; + const RESPOND_PLAYER_STATUS_INFO = 0x22; /** * Server software info. */ - const RESPOND_SERVER_SOFTWARE_INFO = 0x23; + const RESPOND_SERVER_SOFTWARE_INFO = 0x23; /** * Server name. * * @var string */ - private $name; + private $name; /** * Server IP. * * @var string */ - private $ip; + private $ip; /** * Server port. * * @var string */ - private $port; + private $port; /** * Owner name. * * @var string */ - private $owner; + private $owner; /** * Owner's e-mail. * * @var string */ - private $eMail; + private $eMail; /** * Message of the day. * * @var string */ - private $motd; + private $motd; /** * Server location. * * @var string */ - private $location; + private $location; /** * Website URL. * * @var string */ - private $url; + private $url; /** * Uptime. * * @var int */ - private $uptime; + private $uptime; /** * Status version. * * @var string */ - private $version; + private $version; /** * Players online. * * @var int */ - private $online; + private $online; /** * Maximum players. * * @var int */ - private $max; + private $max; /** * Players peak. * * @var int */ - private $peak; + private $peak; /** * Map name. * * @var string */ - private $map; + private $map; /** * Map author. * * @var string */ - private $author; + private $author; /** * Map width. * * @var int */ - private $width; + private $width; /** * Map height. * * @var int */ - private $height; + private $height; /** * Players online list. * * @var array */ - private $players = array(); + private $players = array(); /** * Server software. @@ -224,277 +224,277 @@ class OTS_ServerStatus * * @param OTS_Buffer $info Information packet. */ - public function __construct(OTS_Buffer $info) - { - // skips packet length - $info->getShort(); + public function __construct(OTS_Buffer $info) + { + // skips packet length + $info->getShort(); - while( $info->isValid() ) - { - switch( $info->getChar() ) - { - case self::RESPOND_BASIC_SERVER_INFO: - $this->name = $info->getString(); - $this->ip = $info->getString(); - $this->port = (int) $info->getString(); - break; + while( $info->isValid() ) + { + switch( $info->getChar() ) + { + case self::RESPOND_BASIC_SERVER_INFO: + $this->name = $info->getString(); + $this->ip = $info->getString(); + $this->port = (int) $info->getString(); + break; - case self::RESPOND_OWNER_SERVER_INFO: - $this->owner = $info->getString(); - $this->eMail = $info->getString(); - break; + case self::RESPOND_OWNER_SERVER_INFO: + $this->owner = $info->getString(); + $this->eMail = $info->getString(); + break; - case self::RESPOND_MISC_SERVER_INFO: - $this->motd = $info->getString(); - $this->location = $info->getString(); - $this->url = $info->getString(); + case self::RESPOND_MISC_SERVER_INFO: + $this->motd = $info->getString(); + $this->location = $info->getString(); + $this->url = $info->getString(); - $uptime = $info->getLong() << 32; + $uptime = $info->getLong() << 32; - $this->uptime += $info->getLong() + $uptime; - $this->version = $info->getString(); - break; + $this->uptime += $info->getLong() + $uptime; + $this->version = $info->getString(); + break; - case self::RESPOND_PLAYERS_INFO: - $this->online = $info->getLong(); - $this->max = $info->getLong(); - $this->peak = $info->getLong(); - break; + case self::RESPOND_PLAYERS_INFO: + $this->online = $info->getLong(); + $this->max = $info->getLong(); + $this->peak = $info->getLong(); + break; - case self::RESPOND_MAP_INFO: - $this->map = $info->getString(); - $this->author = $info->getString(); - $this->width = $info->getShort(); - $this->height = $info->getShort(); - break; + case self::RESPOND_MAP_INFO: + $this->map = $info->getString(); + $this->author = $info->getString(); + $this->width = $info->getShort(); + $this->height = $info->getShort(); + break; - case self::RESPOND_EXT_PLAYERS_INFO: - $count = $info->getLong(); + case self::RESPOND_EXT_PLAYERS_INFO: + $count = $info->getLong(); - for($i = 0; $i < $count; $i++) - { - $name = $info->getString(); - $this->players[$name] = $info->getLong(); - } - break; + for($i = 0; $i < $count; $i++) + { + $name = $info->getString(); + $this->players[$name] = $info->getLong(); + } + break; case self::RESPOND_SERVER_SOFTWARE_INFO: $this->softwareName = $info->getString(); $this->softwareVersion = $info->getString(); $this->softwareProtocol = $info->getString(); break; - } - } - } + } + } + } /** * Returns server uptime. * * @return int Uptime. */ - public function getUptime() - { - return $this->uptime; - } + public function getUptime() + { + return $this->uptime; + } /** * Returns server IP. * * @return string IP. */ - public function getIP() - { - return $this->ip; - } + public function getIP() + { + return $this->ip; + } /** * Returns server name. * * @return string Name. */ - public function getName() - { - return $this->name; - } + public function getName() + { + return $this->name; + } /** * Returns server port. * * @return int Port. */ - public function getPort() - { - return $this->port; - } + public function getPort() + { + return $this->port; + } /** * Returns server location. * * @return string Location. */ - public function getLocation() - { - return $this->location; - } + public function getLocation() + { + return $this->location; + } /** * Returns server website. * * @return string Website URL. */ - public function getURL() - { - return $this->url; - } + public function getURL() + { + return $this->url; + } /** * Returns server version. * * @return string Version. */ - public function getServerVersion() - { - return $this->version; - } + public function getServerVersion() + { + return $this->version; + } /** * Returns owner name. * * @return string Owner name. */ - public function getOwner() - { - return $this->owner; - } + public function getOwner() + { + return $this->owner; + } /** * Returns owner e-mail. * * @return string Owner e-mail. */ - public function getEMail() - { - return $this->eMail; - } + public function getEMail() + { + return $this->eMail; + } /** * Returns current amount of players online. * * @return int Count of players. */ - public function getOnlinePlayers() - { - return $this->online; - } + public function getOnlinePlayers() + { + return $this->online; + } /** * Returns maximum amount of players online. * * @return int Maximum allowed count of players. */ - public function getMaxPlayers() - { - return $this->max; - } + public function getMaxPlayers() + { + return $this->max; + } /** * Returns record of online players. * * @return int Players online record. */ - public function getPlayersPeak() - { - return $this->peak; - } + public function getPlayersPeak() + { + return $this->peak; + } /** * Returns map name. * * @return string Map name. */ - public function getMapName() - { - return $this->map; - } + public function getMapName() + { + return $this->map; + } /** * Returns map author. * * @return string Mapper name. */ - public function getMapAuthor() - { - return $this->author; - } + public function getMapAuthor() + { + return $this->author; + } /** * Returns map width. * * @return int Map width. */ - public function getMapWidth() - { - return $this->width; - } + public function getMapWidth() + { + return $this->width; + } /** * Returns map height. * * @return int Map height. */ - public function getMapHeight() - { - return $this->height; - } + public function getMapHeight() + { + return $this->height; + } /** * Returns server's Message Of The Day * * @return string Server MOTD. */ - public function getMOTD() - { - return $this->motd; - } + public function getMOTD() + { + return $this->motd; + } /** * Returns list of players currently online. * * @return array List of players in format 'name' => level. */ - public function getPlayers() - { - } + public function getPlayers() + { + } /** * Returns software name. * * @return string Software name. */ - public function getSoftwareName() - { - return $this->softwareName; - } + public function getSoftwareName() + { + return $this->softwareName; + } /** * Returns software version. * * @return string Software version. */ - public function getSoftwareVersion() - { - return $this->softwareVersion; - } + public function getSoftwareVersion() + { + return $this->softwareVersion; + } /** * Returns software protocol. * * @return string Software protocol. */ - public function getSoftwareProtocol() - { - return $this->softwareProtocol; - } + public function getSoftwareProtocol() + { + return $this->softwareProtocol; + } /** * Magic PHP5 method. @@ -503,68 +503,68 @@ class OTS_ServerStatus * @return mixed Property value. * @throws OutOfBoundsException For non-supported properties. */ - public function __get($name) - { - switch($name) - { - case 'uptime': - return $this->getUptime(); + public function __get($name) + { + switch($name) + { + case 'uptime': + return $this->getUptime(); - case 'ip': - return $this->getIP(); + case 'ip': + return $this->getIP(); - case 'name': - return $this->getName(); + case 'name': + return $this->getName(); - case 'port': - return $this->getPort(); + case 'port': + return $this->getPort(); - case 'location': - return $this->getLocation(); + case 'location': + return $this->getLocation(); - case 'url': - return $this->getURL(); + case 'url': + return $this->getURL(); - case 'serverVersion': - return $this->getServerVersion(); + case 'serverVersion': + return $this->getServerVersion(); - case 'owner': - return $this->getOwner(); + case 'owner': + return $this->getOwner(); - case 'eMail': - return $this->getEMail(); + case 'eMail': + return $this->getEMail(); - case 'onlinePlayers': - return $this->getOnlinePlayers(); + case 'onlinePlayers': + return $this->getOnlinePlayers(); - case 'maxPlayers': - return $this->getMaxPlayers(); + case 'maxPlayers': + return $this->getMaxPlayers(); - case 'playersPeak': - return $this->getPlayersPeak(); + case 'playersPeak': + return $this->getPlayersPeak(); - case 'mapName': - return $this->getMapName(); + case 'mapName': + return $this->getMapName(); - case 'mapAuthor': - return $this->getMapAuthor(); + case 'mapAuthor': + return $this->getMapAuthor(); - case 'mapWidth': - return $this->getMapWidth(); + case 'mapWidth': + return $this->getMapWidth(); - case 'mapHeight': - return $this->getMapHeight(); + case 'mapHeight': + return $this->getMapHeight(); - case 'motd': - return $this->getMOTD(); + case 'motd': + return $this->getMOTD(); - case 'players': - return $this->getPlayers(); + case 'players': + return $this->getPlayers(); - default: - throw new OutOfBoundsException(); - } - } + default: + throw new OutOfBoundsException(); + } + } } /**#@-*/ diff --git a/system/libs/pot/OTS_Toolbox.php b/system/libs/pot/OTS_Toolbox.php index 980e5cb5..575dba6f 100644 --- a/system/libs/pot/OTS_Toolbox.php +++ b/system/libs/pot/OTS_Toolbox.php @@ -15,7 +15,7 @@ /** * Toolbox for common operations. - * + * * @package POT * @version 0.1.5 */ @@ -23,41 +23,41 @@ class OTS_Toolbox { /** * Calculates experience points needed for given level. - * + * * @param int $level Level for which experience should be calculated. * @param int $experience Current experience points. * @return int Experience points for level. */ public static function experienceForLevel($level, $experience = 0) - { - //return 50 * ($level - 1) * ($level * $level - 5 * $level + 12) / 3 - $experience; + { + //return 50 * ($level - 1) * ($level * $level - 5 * $level + 12) / 3 - $experience; $level = $level - 1; return ((50 * $level * $level * $level) - (150 * $level * $level) + (400 * $level)) / 3; - } + } /** * Finds out which level user have basing on his/her experience. - * + * ** PHP doesn't support complex numbers natively so solving third-level polynomials would be quite hard. Rather then doing this, this method iterates calculating experience for next levels until it finds one which requires enought experience we have. Because of that, for high experience values this function can take relatively long time to be executed. *
- * + * * @param int $experience Current experience points. * @return int Experience level. */ - public static function levelForExperience($experience) - { - // default level - $level = 1; + public static function levelForExperience($experience) + { + // default level + $level = 1; - // until we will find level which requires more experience then we have we will step to next - while( self::experienceForLevel($level + 1) <= $experience) - { - $level++; - } + // until we will find level which requires more experience then we have we will step to next + while( self::experienceForLevel($level + 1) <= $experience) + { + $level++; + } - return $level; - } + return $level; + } /** * @version 0.1.5 @@ -65,25 +65,25 @@ class OTS_Toolbox * @return OTS_Players_List Filtered list. * @deprecated 0.1.5 Use OTS_PlayerBans_List. */ - public static function bannedPlayers() - { - // creates filter - $filter = new OTS_SQLFilter(); - $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_PLAYER); - $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); - $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'players') ); + public static function bannedPlayers() + { + // creates filter + $filter = new OTS_SQLFilter(); + $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_PLAYER); + $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); + $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'players') ); - // selects only active bans - $actives = new OTS_SQLFilter(); - $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); - $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); - $filter->addFilter($actives); + // selects only active bans + $actives = new OTS_SQLFilter(); + $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); + $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); + $filter->addFilter($actives); - // creates list and aplies filter - $list = new OTS_Players_List(); - $list->setFilter($filter); - return $list; - } + // creates list and aplies filter + $list = new OTS_Players_List(); + $list->setFilter($filter); + return $list; + } /** * @version 0.1.5 @@ -91,25 +91,34 @@ class OTS_Toolbox * @return OTS_Accounts_List Filtered list. * @deprecated 0.1.5 Use OTS_AccountBans_List. */ - public static function bannedAccounts() - { - // creates filter - $filter = new OTS_SQLFilter(); - $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_ACCOUNT); - $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); - $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'accounts') ); + public static function bannedAccounts() + { + // creates filter + $filter = new OTS_SQLFilter(); + $filter->addFilter( new OTS_SQLField('type', 'bans'), POT::BAN_ACCOUNT); + $filter->addFilter( new OTS_SQLField('active', 'bans'), 1); + $filter->addFilter( new OTS_SQLField('value', 'bans'), new OTS_SQLField('id', 'accounts') ); - // selects only active bans - $actives = new OTS_SQLFilter(); - $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); - $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); - $filter->addFilter($actives); + // selects only active bans + $actives = new OTS_SQLFilter(); + $actives->addFilter( new OTS_SQLField('expires', 'bans'), 0); + $actives->addFilter( new OTS_SQLField('time', 'bans'), time(), OTS_SQLFilter::OPERATOR_GREATER, OTS_SQLFilter::CRITERIUM_OR); + $filter->addFilter($actives); - // creates list and aplies filter - $list = new OTS_Accounts_List(); - $list->setFilter($filter); - return $list; - } + // creates list and aplies filter + $list = new OTS_Accounts_List(); + $list->setFilter($filter); + return $list; + } + + public static function getVocationName($id, $promotion = 0): string + { + if($promotion > 0) { + $id = ($id + ($promotion * config('vocations_amount'))); + } + + return config('vocations')[$id] ?? 'Unknown'; + } } /**#@-*/ diff --git a/system/locale/de/install.php b/system/locale/de/install.php index ad354609..351f6009 100644 --- a/system/locale/de/install.php +++ b/system/locale/de/install.php @@ -48,6 +48,8 @@ $locale['step_config'] = 'Konfiguration'; $locale['step_config_title'] = 'Grundkonfiguration'; $locale['step_config_server_path'] = 'Serverpfad'; $locale['step_config_server_path_desc'] = 'Pfad zu Ihrem TFS-Hauptverzeichnis, in dem sich die config.lua befinden.'; +$locale['step_config_site_url'] = 'Website URL'; +$locale['step_config_site_url_desc'] = 'Ihre Website-Adresse.'; $locale['step_config_mail_admin'] = 'Admin E-Mail'; $locale['step_config_mail_admin_desc'] = 'Adresse, an die E-Mails aus dem Kontaktformular gesendet werden, z. B. admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'Admin E-Mail ist nicht korrekt.'; @@ -76,6 +78,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL ist nicht richtig konfig $locale['step_database_error_mysql_connect_4'] = 'MySQL-Server läuft nicht.'; $locale['step_database_error_schema'] = 'Fehler beim Importieren des Schemas:'; $locale['step_database_success_schema'] = '$PREFIX$ Tabellen wurden erfolgreich installiert.'; +$locale['step_database_success_import_data'] = 'Import von Daten für Tabellen was erfolgreich.'; $locale['step_database_error_file'] = '$FILE$ konnte nicht geöffnet werden. Bitte kopieren Sie diesen Inhalt und fügen Sie ihn dort ein:'; $locale['step_database_adding_field'] = 'Folgendes Feld wurde hinzugefügt: '; $locale['step_database_modifying_field'] = 'Folgendes Feld wurde geändert: '; diff --git a/system/locale/en/install.php b/system/locale/en/install.php index 0cbd29ad..c623035c 100644 --- a/system/locale/en/install.php +++ b/system/locale/en/install.php @@ -52,6 +52,8 @@ $locale['step_config'] = 'Configuration'; $locale['step_config_title'] = 'Basic configuration'; $locale['step_config_server_path'] = 'Server path'; $locale['step_config_server_path_desc'] = 'Path to your TFS main directory, where you have config.lua located.'; +$locale['step_config_site_url'] = 'Website URL'; +$locale['step_config_site_url_desc'] = 'Your website address.'; $locale['step_config_mail_admin'] = 'Admin Email'; $locale['step_config_mail_admin_desc'] = 'Address where emails from contact form will be delivered, for example admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'Admin Email is not correct.'; @@ -81,6 +83,7 @@ $locale['step_database_error_mysql_connect_3'] = 'MySQL is not configured proper $locale['step_database_error_mysql_connect_4'] = 'MySQL server is not running.'; $locale['step_database_error_schema'] = 'Error while importing schema:'; $locale['step_database_success_schema'] = 'Successfully installed $PREFIX$ tables.'; +$locale['step_database_success_import_data'] = 'Successfully imported base data for tables.'; $locale['step_database_error_file'] = '$FILE$ couldn\'t be opened. Please copy this content and paste there:'; $locale['step_database_adding_field'] = 'Adding field'; $locale['step_database_modifying_field'] = 'Modifying field'; diff --git a/system/locale/pl/install.php b/system/locale/pl/install.php index 5b6725cf..a8ea0cf6 100644 --- a/system/locale/pl/install.php +++ b/system/locale/pl/install.php @@ -52,6 +52,8 @@ $locale['step_config'] = 'Konfiguracja'; $locale['step_config_title'] = 'Podstawowa konfiguracja'; $locale['step_config_server_path'] = 'Ścieżka do serwera'; $locale['step_config_server_path_desc'] = 'Ścieżka do Twojego folderu z TFS, gdzie znajduje się plik config.lua.'; +$locale['step_config_server_url'] = 'Adres strony'; +$locale['step_config_server_url_desc'] = 'Adres tej strony www.'; $locale['step_config_mail_admin'] = 'E-Mail admina'; $locale['step_config_mail_admin_desc'] = 'Na ten adres będą dostarczane E-Maile z formularza kontaktowego, przykładowo admin@gmail.com'; $locale['step_config_mail_admin_error'] = 'E-Mail admina jest niepoprawny.'; @@ -79,7 +81,8 @@ $locale['step_database_error_mysql_connect_2'] = 'Możliwe przyczyny:'; $locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w config.lua.'; $locale['step_database_error_mysql_connect_4'] = 'Serwer MySQL nie jest uruchomiony.'; $locale['step_database_error_schema'] = 'Błąd podczas importowania struktury bazy danych:'; -$locale['step_database_success_schema'] = 'Pomyślnie zainstalowano tabele $PREFIX$.'; +$locale['step_database_success_schema'] = 'Pomyślnie zaimportowano tabele $PREFIX$.'; +$locale['step_database_success_import_data'] = 'Pomyślnie załadowano bazowe dane dla tabel.'; $locale['step_database_error_file'] = '$FILE$ nie mógł zostać otwarty. Proszę skopiować zawartość pola tekstowego i wkleić do tego pliku:'; $locale['step_database_adding_field'] = 'Dodawanie pola'; $locale['step_database_modifying_field'] = 'Modyfikacja pola'; diff --git a/system/login.php b/system/login.php index 42a96111..335177e7 100644 --- a/system/login.php +++ b/system/login.php @@ -34,8 +34,10 @@ if($logged) { $twig->addGlobal('account_logged', $account_logged); } -setSession('last_visit', time()); -if(defined('PAGE')) { - setSession('last_page', PAGE); +if (!defined('IGNORE_SET_LAST_VISIT') || !IGNORE_SET_LAST_VISIT) { + setSession('last_visit', time()); + if(defined('PAGE')) { + setSession('last_page', PAGE); + } + setSession('last_uri', $_SERVER['REQUEST_URI']); } -setSession('last_uri', $_SERVER['REQUEST_URI']); diff --git a/system/migrate.php b/system/migrate.php index 2199fd73..2bbb3786 100644 --- a/system/migrate.php +++ b/system/migrate.php @@ -9,6 +9,8 @@ */ defined('MYAAC') or die('Direct access not allowed!'); +global $db; + // database migrations $tmp = ''; if(fetchDatabaseConfig('database_version', $tmp)) { // we got version diff --git a/system/migrations/44.php b/system/migrations/44.php index ea98d6f2..6db23412 100644 --- a/system/migrations/44.php +++ b/system/migrations/44.php @@ -1,27 +1,20 @@ query("ALTER TABLE `myaac_account_actions` DROP KEY `account_id`;"); - $db->query("ALTER TABLE `myaac_account_actions` ADD COLUMN `id` INT(11) NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`id`);"); +// 2025-05-14 +// update pages links +// server-info conflicts with apache2 mod +// Changelog conflicts with changelog files - $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "VARCHAR(45) NOT NULL DEFAULT ''"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_NTOA(`ip`) WHERE `ip` != '0';"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET6_NTOA(`ipv6`) WHERE `ip` = '0';"); - $db->dropColumn(TABLE_PREFIX . 'account_actions', 'ipv6'); +use MyAAC\Models\Menu; +use MyAAC\Models\Pages; + +$up = function() { + Menu::where('link', 'server-info')->update(['link' => 'ots-info']); + Menu::where('link', 'changelog')->update(['link' => 'change-log']); }; -$down = function () use ($db) { - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` DROP `id`;"); - $db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` ADD KEY (`account_id`);"); - - $db->addColumn(TABLE_PREFIX . 'account_actions', 'ipv6', "BINARY(16) NOT NULL DEFAULT 0x00000000000000000000000000000000 AFTER ip"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ipv6` = INET6_ATON(ip) WHERE NOT IS_IPV4(`ip`);"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = INET_ATON(`ip`) WHERE IS_IPV4(`ip`);"); - $db->query("UPDATE `" . TABLE_PREFIX . "account_actions` SET `ip` = 0 WHERE `ipv6` != 0x00000000000000000000000000000000;"); - $db->modifyColumn(TABLE_PREFIX . 'account_actions', 'ip', "INT(11) UNSIGNED NOT NULL DEFAULT 0;"); +$down = function() { + Menu::where('link', 'ots-info')->update(['link' => 'server-info']); + Menu::where('link', 'change-log')->update(['link' => 'changelog']); }; + diff --git a/system/migrations/45.php b/system/migrations/45.php new file mode 100644 index 00000000..c2d8aaec --- /dev/null +++ b/system/migrations/45.php @@ -0,0 +1,32 @@ +update(['hide' => 1]); + + $rules = Pages::where('name', 'rules')->first(); + if (!$rules) { + Pages::create([ + 'name' => 'rules', + 'title' => 'Server Rules', + 'body' => '{{ config.lua.serverName }} RulesAn error occurred while sending email ({$email} )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log
"; + } + } + else { + $message = "| ';
 		if(Forum::isModerator()) {
-			echo '[MOVE]';
-			echo '[REMOVE]  ';
+			echo '  ';
+			$twig->display('forum.remove_post.html.twig', ['post' => $thread]);
 		}
 
 		$player->load($thread['player_id']);
@@ -82,10 +82,13 @@ if(isset($last_threads[0])) {
 		echo ''.htmlspecialchars($thread['post_topic']). ' '.($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50))).'... | ' . getPlayerLink($thread['name']) . ' | '.(int) $thread['replies'].' | '.(int) $thread['views'].' | ';
 		if($thread['last_post'] > 0) {
 			$last_post = $db->query("SELECT `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread['id']." AND `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` ORDER BY `post_date` DESC LIMIT 1")->fetch();
-			if(isset($last_post['name']))
-				echo date('d.m.y H:i:s', $last_post['post_date']).' by ' . getPlayerLink($last_post['name']); - else + + if(isset($last_post['name'])) { + echo date('d.m.y H:i:s', $last_post['post_date']) . ' by ' . getPlayerLink($last_post['name']); + } + else { echo 'No posts.'; + } } else { echo date('d.m.y H:i:s', $thread['post_date']) . ' by ' . getPlayerLink($thread['name']); diff --git a/system/pages/forum/show_thread.php b/system/pages/forum/show_thread.php index e4c53f16..ceeb2602 100644 --- a/system/pages/forum/show_thread.php +++ b/system/pages/forum/show_thread.php @@ -35,7 +35,7 @@ if(!Forum::hasAccess($thread_starter['section'])) { return; } -$posts_count = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS posts_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread_id)->fetch(); +$posts_count = $db->query("SELECT COUNT(`" . FORUM_TABLE_PREFIX . "forum`.`id`) AS posts_count FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id)->fetch(); for($i = 0; $i < $posts_count['posts_count'] / setting('core.forum_threads_per_page'); $i++) { if($i != $_page) $links_to_pages .= ''.($i + 1).' '; @@ -46,7 +46,7 @@ for($i = 0; $i < $posts_count['posts_count'] / setting('core.forum_threads_per_p $posts = $db->query("SELECT `players`.`id` as `player_id`, `" . FORUM_TABLE_PREFIX . "forum`.`id`,`" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`section`,`" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` AS `date`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`post_html`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`last_edit_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`edit_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`post_date` LIMIT " . setting('core.forum_posts_per_page') . " OFFSET ".($_page * setting('core.forum_posts_per_page')))->fetchAll(); if(isset($posts[0]['player_id'])) { - $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `views`=`views`+1 WHERE `id` = ".(int) $thread_id); + $db->query("UPDATE `" . FORUM_TABLE_PREFIX . "forum` SET `views`=`views`+1 WHERE `id` = " . $thread_id); } $lookaddons = $db->hasColumn('players', 'lookaddons'); diff --git a/system/pages/guilds/accept_invite.php b/system/pages/guilds/accept_invite.php index bc782480..14c55c25 100644 --- a/system/pages/guilds/accept_invite.php +++ b/system/pages/guilds/accept_invite.php @@ -12,11 +12,11 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; -//set rights in guild +// set rights in guild $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; $name = isset($_REQUEST['name']) ? stripslashes($_REQUEST['name']) : null; if(!$logged) { - $errors[] = 'You are not logged in. You can\'t accept invitations.'; + $errors[] = "You are not logged in. You can't accept invitations."; } if(!Validator::guildName($guild_name)) { @@ -27,11 +27,11 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -51,7 +51,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { } } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(empty($errors)) { $is_invited = false; include(SYSTEM . 'libs/pot/InvitesDriver.php'); @@ -104,7 +104,7 @@ if(!empty($errors)) { )); } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->acceptInvite($player); $twig->display('success.html.twig', array( 'title' => 'Accept invitation', diff --git a/system/pages/guilds/add_rank.php b/system/pages/guilds/add_rank.php index e66ba49e..b24ff03d 100644 --- a/system/pages/guilds/add_rank.php +++ b/system/pages/guilds/add_rank.php @@ -13,7 +13,7 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -$rank_name = isset($_REQUEST['rank_name']) ? $_REQUEST['rank_name'] : null; +$rank_name = $_POST['rank_name'] ?? null; if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); } @@ -35,7 +35,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; diff --git a/system/pages/guilds/base.php b/system/pages/guilds/base.php index 07fc432d..e096c56e 100644 --- a/system/pages/guilds/base.php +++ b/system/pages/guilds/base.php @@ -15,3 +15,5 @@ else define('GUILD_MEMBERS_TABLE', 'guild_membership'); define('MOTD_EXISTS', $db->hasColumn('guilds', 'motd')); + +csrfProtect(); diff --git a/system/pages/guilds/change_description.php b/system/pages/guilds/change_description.php index 765665bf..e3c24522 100644 --- a/system/pages/guilds/change_description.php +++ b/system/pages/guilds/change_description.php @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -42,8 +42,8 @@ if(empty($errors)) { $saved = false; if($guild_leader) { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { - $description = htmlspecialchars(stripslashes(substr(trim($_REQUEST['description']),0, setting('core.guild_description_chars_limit')))); + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { + $description = htmlspecialchars(stripslashes(substr(trim($_POST['description']),0, setting('core.guild_description_chars_limit')))); $guild->setCustomField('description', $description); $saved = true; } diff --git a/system/pages/guilds/change_logo.php b/system/pages/guilds/change_logo.php index d8257e66..7fa72d99 100644 --- a/system/pages/guilds/change_logo.php +++ b/system/pages/guilds/change_logo.php @@ -30,7 +30,7 @@ if(empty($errors)) { if($logged) { $guild_leader_char = $guild->getOwner(); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { @@ -40,14 +40,13 @@ if(empty($errors)) { } } - if($guild_leader) - { + if($guild_leader) { $max_image_size_b = setting('core.guild_image_size_kb') * 1024; $allowed_ext = array('image/gif', 'image/jpg', 'image/pjpeg', 'image/jpeg', 'image/bmp', 'image/png', 'image/x-png'); $ext_name = array('image/gif' => 'gif', 'image/jpg' => 'jpg', 'image/jpeg' => 'jpg', 'image/pjpeg' => 'jpg', 'image/bmp' => 'bmp', 'image/png' => 'png', 'image/x-png' => 'png'); $save_file_name = str_replace(' ', '_', strtolower($guild->getName())); $save_path = GUILD_IMAGES_DIR . $save_file_name; - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $file = $_FILES['newlogo']; if(is_uploaded_file($file['tmp_name'])) @@ -97,13 +96,13 @@ if(empty($errors)) { $guild_logo = $guild->getCustomField('logo_name'); if(empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) { - $guild_logo = "default.gif"; + $guild_logo = 'default.gif'; } $twig->display('guilds.change_logo.html.twig', array( 'guild_logo' => $guild_logo, 'guild' => $guild, - 'max_image_size_b' => $max_image_size_b + //'max_image_size_b' => $max_image_size_b )); } diff --git a/system/pages/guilds/change_motd.php b/system/pages/guilds/change_motd.php index babb806c..8d478377 100644 --- a/system/pages/guilds/change_motd.php +++ b/system/pages/guilds/change_motd.php @@ -34,7 +34,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -45,8 +45,8 @@ if(empty($errors)) { $saved = false; if($guild_leader) { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { - $motd = htmlspecialchars(stripslashes(substr($_REQUEST['motd'],0, setting('core.guild_motd_chars_limit')))); + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { + $motd = htmlspecialchars(stripslashes(substr($_POST['motd'],0, setting('core.guild_motd_chars_limit')))); $guild->setCustomField('motd', $motd); $saved = true; } diff --git a/system/pages/guilds/change_nick.php b/system/pages/guilds/change_nick.php index bf773124..5016ef3e 100644 --- a/system/pages/guilds/change_nick.php +++ b/system/pages/guilds/change_nick.php @@ -20,17 +20,15 @@ if(!$logged) { } $name = isset($_REQUEST['name']) ? stripslashes($_REQUEST['name']) : null; -$new_nick = isset($_REQUEST['nick']) ? stripslashes($_REQUEST['nick']) : null; +$new_nick = isset($_POST['nick']) ? stripslashes($_POST['nick']) : null; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; if(!$name) { $errors[] = 'Please enter new name.'; - return; } if(!$new_nick) { $errors[] = 'Please enter new nick.'; - return; } if(empty($errors)) diff --git a/system/pages/guilds/change_rank.php b/system/pages/guilds/change_rank.php index 4341db16..6d36bdf1 100644 --- a/system/pages/guilds/change_rank.php +++ b/system/pages/guilds/change_rank.php @@ -17,8 +17,9 @@ if(!$logged) { } else { $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; - if(!Validator::guildName($guild_name)) + if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); + } } if(empty($errors)) @@ -42,7 +43,7 @@ $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; -$account_players = $account_logged->getPlayers(); +$account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); @@ -65,22 +66,23 @@ foreach($account_players as $player) } } -if($guild_vice) -{ - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] === 'save') - { +if($guild_vice) { + if(isset($_POST['todo']) && $_POST['todo'] === 'save') { $player_name = stripslashes($_REQUEST['name']); - $new_rank = (int) $_REQUEST['rankid']; - if(!Validator::characterName($player_name)) + $new_rank = (int) $_POST['rankid']; + + if(!Validator::characterName($player_name)) { $errors[] = 'Invalid player name format.'; + } + $rank = new OTS_GuildRank(); $rank->load($new_rank); if(!$rank->isLoaded()) $errors[] = "Rank with this ID doesn't exist."; if($level_in_guild <= $rank->getLevel() && !$guild_leader) $errors[] = "You can't set ranks with equal or higher level than your."; - if(empty($errors)) - { + + if(empty($errors)) { $player_to_change = new OTS_Player(); $player_to_change->find($player_name); if(!$player_to_change->isLoaded()) @@ -108,8 +110,7 @@ if($guild_vice) $errors[] = 'This player has higher rank in guild than you. You can\'t change his/her rank.'; } - if(empty($errors)) - { + if(empty($errors)) { $player_to_change->setRank($rank); $twig->display('success.html.twig', array( 'title' => 'Rank Changed', @@ -125,7 +126,7 @@ if($guild_vice) $result = getPlayersWithLowerRank($rank_list, $guild_leader, $db, $level_in_guild, $guild); $twig->display('guilds.change_rank.html.twig', array( - 'players' => isset($result['players']) ? $result['players'] : array(), + 'players' => $result['players'] ?? [], 'guild_name' => $guild->getName(), 'ranks' => $result['ranks'] )); diff --git a/system/pages/guilds/cleanup_players.php b/system/pages/guilds/cleanup_players.php index 7e02fbeb..ad110feb 100644 --- a/system/pages/guilds/cleanup_players.php +++ b/system/pages/guilds/cleanup_players.php @@ -12,33 +12,27 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; -if(!$logged) -{ +if(!$logged) { echo "You are not logged in."; $twig->display('guilds.back_button.html.twig'); return; } -if(admin()) -{ +if(admin()) { $players_list = new OTS_Players_List(); $players_list->init(); } -else +else { $players_list = $account_logged->getPlayersList(); +} -if(count($players_list) > 0) -{ - foreach($players_list as $player) - { +if(count($players_list) > 0) { + foreach($players_list as $player) { $player_rank = $player->getRank(); - if($player_rank->isLoaded()) - { - if($player_rank->isLoaded()) - { + if($player_rank->isLoaded()) { + if($player_rank->isLoaded()) { $rank_guild = $player_rank->getGuild(); - if(!$rank_guild->isLoaded()) - { + if(!$rank_guild->isLoaded()) { $player->setRank(); $player->setGuildNick(''); $changed_ranks_of[] = $player->getName(); @@ -46,8 +40,7 @@ if(count($players_list) > 0) $player_rank->delete(); } } - else - { + else { $player->setRank(); $player->setGuildNick(''); $changed_ranks_of[] = $player->getName(); @@ -55,14 +48,20 @@ if(count($players_list) > 0) } } + echo "Deleted ranks (this ranks guilds doesn't exist [bug fix]):"; - if(!empty($deleted_ranks)) - foreach($deleted_ranks as $rank) - echo " Changed ranks of players (rank or guild of rank doesn't exist [bug fix]):"; - if(!empty($changed_ranks_of)) - foreach($changed_ranks_of as $name) - echo " - ', + ', 'custom_buttons' => $twig->render('guilds.back_button.html.twig') )); } diff --git a/system/pages/guilds/delete_guild.php b/system/pages/guilds/delete_guild.php index 978ac513..0e4bd0ba 100644 --- a/system/pages/guilds/delete_guild.php +++ b/system/pages/guilds/delete_guild.php @@ -21,7 +21,7 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { diff --git a/system/pages/guilds/delete_invite.php b/system/pages/guilds/delete_invite.php index 7bf4067a..485ca9d0 100644 --- a/system/pages/guilds/delete_invite.php +++ b/system/pages/guilds/delete_invite.php @@ -15,47 +15,43 @@ require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; $name = stripslashes($_REQUEST['name']); -if(!$logged) +if(!$logged) { $errors[] = 'You are not logged in. You can\'t delete invitations.'; +} -if(!Validator::guildName($guild_name)) +if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); +} -if(!Validator::characterName($name)) +if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; +} -if(empty($errors)) -{ +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) $errors[] = "Guild with name " . $guild_name . " doesn't exist."; } -if(empty($errors)) -{ +if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); - foreach($account_players as $player) - { + $account_players = $account_logged->getPlayersList(); + foreach($account_players as $player) { $player_rank = $player->getRank(); - if($player_rank->isLoaded()) - { - foreach($rank_list as $rank_in_guild) - { - if($rank_in_guild->getId() == $player_rank->getId()) - { + if($player_rank->isLoaded()) { + foreach($rank_list as $rank_in_guild) { + if($rank_in_guild->getId() == $player_rank->getId()) { $players_from_account_in_guild[] = $player->getName(); - if($player_rank->getLevel() > 1) - { + if($player_rank->getLevel() > 1) { $guild_vice = true; $level_in_guild = $player_rank->getLevel(); } - if($guild->getOwner()->getId() == $player->getId()) - { + + if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; $guild_leader = true; } @@ -64,44 +60,46 @@ if(empty($errors)) } } - if(!$guild_vice) + if(!$guild_vice) { $errors[] = 'You are not a leader or vice leader of guild ' . $guild_name . '.'; -} -if(empty($errors)) -{ - $player = new OTS_Player(); - $player->find($name); - if(!$player->isLoaded()) - $errors[] = 'Player with name ' . $name . ' doesn\'t exist.'; + } } -if(empty($errors)) -{ +if(empty($errors)) { + $player = new OTS_Player(); + $player->find($name); + if(!$player->isLoaded()) { + $errors[] = "Player with name $name doesn't exist."; + } +} + +if(empty($errors)) { include(SYSTEM . 'libs/pot/InvitesDriver.php'); new InvitesDriver($guild); $invited_list = $guild->listInvites(); - if(count($invited_list) > 0) - { + if(count($invited_list) > 0) { $is_invited = false; - foreach($invited_list as $invited) - if($invited->getName() == $player->getName()) + foreach($invited_list as $invited) { + if ($invited->getName() == $player->getName()) { $is_invited = true; - if(!$is_invited) - $errors[] = ''.$player->getName().' isn\'t invited to your guild.'; + } + } + if(!$is_invited) { + $errors[] = '' . $player->getName() . ' isn\'t invited to your guild.'; + } } - else + else { $errors[] = 'No one is invited to your guild.'; + } } -if(!empty($errors)) -{ + +if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig', array('action' => getLink('guilds') . '?action=show&guild=' . $guild_name)); } -else -{ - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') - { +else { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->deleteInvite($player); $twig->display('success.html.twig', array( 'title' => 'Deleted player invitation', diff --git a/system/pages/guilds/delete_rank.php b/system/pages/guilds/delete_rank.php index 56322cd9..ce783137 100644 --- a/system/pages/guilds/delete_rank.php +++ b/system/pages/guilds/delete_rank.php @@ -13,25 +13,27 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -$rank_to_delete = isset($_REQUEST['rankid']) ? (int) $_REQUEST['rankid'] : null; +$rank_to_delete = isset($_POST['rankid']) ? (int) $_POST['rankid'] : null; if(!Validator::guildName($guild_name)) { - $guild_errors[] = Validator::getLastError(); + $errors[] = Validator::getLastError(); } -if(empty($guild_errors)) { + +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $guild_errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; } } -if(empty($guild_errors)) { + +if(empty($errors)) { if($logged) { $guild_leader_char = $guild->getOwner(); $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild->getOwner()->getId() == $player->getId()) { $guild_vice = true; @@ -39,21 +41,21 @@ if(empty($guild_errors)) { $level_in_guild = 3; } } + if($guild_leader) { $rank = new OTS_GuildRank(); $rank->load($rank_to_delete); if(!$rank->isLoaded()) { - $guild_errors2[] = 'Rank with ID '.$rank_to_delete.' doesn\'t exist.'; + $errors2[] = 'Rank with ID '.$rank_to_delete.' doesn\'t exist.'; } - else - { + else { if($rank->getGuild()->getId() != $guild->getId()) { - $guild_errors2[] = 'Rank with ID '.$rank_to_delete.' isn\'t from your guild.'; + $errors2[] = 'Rank with ID '.$rank_to_delete.' isn\'t from your guild.'; } else { if(count($rank_list) < 2) { - $guild_errors2[] = 'You have only 1 rank in your guild. You can\'t delete this rank.'; + $errors2[] = 'You have only 1 rank in your guild. You can\'t delete this rank.'; } else { @@ -87,19 +89,21 @@ if(empty($guild_errors)) { $player->setRank($new_rank); } } + $rank->delete(); $saved = true; } } } - if($saved) { + + if(isset($saved) && $saved) { $twig->display('success.html.twig', array( 'title' => 'Rank Deleted', 'description' => 'Rank '.$rank->getName().' has been deleted. Players with this rank has now other rank.', 'custom_buttons' => '' )); } else { - $twig->display('error_box.html.twig', array('errors' => $guild_errors2)); + $twig->display('error_box.html.twig', array('errors' => $errors2)); } $twig->display('guilds.back_button.html.twig', array( @@ -107,18 +111,16 @@ if(empty($guild_errors)) { 'action' => getLink('guilds') . '?guild='.$guild->getName().'&action=manager' )); } - else - { - $guild_errors[] = 'You are not a leader of guild!'; + else { + $errors[] = 'You are not a leader of guild!'; } } - else - { - $guild_errors[] = 'You are not logged. You can\'t manage guild.'; + else { + $errors[] = 'You are not logged. You can\'t manage guild.'; } } -if(!empty($guild_errors)) { - $twig->display('error_box.html.twig', array('errors' => $guild_errors)); +if(!empty($errors)) { + $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig', array( 'new_line' => true, diff --git a/system/pages/guilds/invite.php b/system/pages/guilds/invite.php index 8fae8e27..0984fd0a 100644 --- a/system/pages/guilds/invite.php +++ b/system/pages/guilds/invite.php @@ -23,6 +23,12 @@ if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); } +if (!$db->hasTableAndColumns('guild_invites', ['player_id'])) { + $errors[] = "Guild invite is not possible on this website."; + $twig->display('error_box.html.twig', ['errors' => $errors]); + return; +} + if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); @@ -36,7 +42,7 @@ if(empty($errors)) { $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); if($player_rank->isLoaded()) { @@ -58,11 +64,11 @@ if(empty($errors)) { } } -if(!$guild_vice) { +if(empty($errors) && !$guild_vice) { $errors[] = 'You are not a leader or vice leader of guild '.$guild_name.'.'.$level_in_guild; } -if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { +if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -71,7 +77,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { $player = new OTS_Player(); $player->find($name); if(!$player->isLoaded()) { - $errors[] = 'Player with name ' . $name . ' doesn\'t exist.'; + $errors[] = "Player with name $name doesn't exist."; } else if ($player->isDeleted()) { $errors[] = "Character with name $name has been deleted."; } @@ -84,6 +90,7 @@ if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { } } } + if(empty($errors)) { include(SYSTEM . 'libs/pot/InvitesDriver.php'); new InvitesDriver($guild); @@ -102,8 +109,9 @@ if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $guild->invite($player); + $twig->display('success.html.twig', array( 'title' => 'Invite player', 'description' => 'Player with name ' . $player->getName() . ' has been invited to your guild.', diff --git a/system/pages/guilds/kick_player.php b/system/pages/guilds/kick_player.php index 5ce79187..736617b0 100644 --- a/system/pages/guilds/kick_player.php +++ b/system/pages/guilds/kick_player.php @@ -41,7 +41,7 @@ if(empty($errors)) { $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; $guild_vice = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $player_rank = $player->getRank(); if($player_rank->isLoaded()) { @@ -102,7 +102,7 @@ if(!empty($errors)) { } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $player->setRank(); $twig->display('success.html.twig', array( diff --git a/system/pages/guilds/leave.php b/system/pages/guilds/leave.php index 9a11595d..50f52a6c 100644 --- a/system/pages/guilds/leave.php +++ b/system/pages/guilds/leave.php @@ -34,7 +34,7 @@ if(empty($errors)) { $array_of_player_ig = array(); if(empty($errors)) { $guild_owner_name = $guild->getOwner()->getName(); - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($name)) { $errors[] = 'Invalid name format.'; } @@ -72,7 +72,7 @@ if(empty($errors)) { } else { - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player_fac) { $player_rank = $player_fac->getRank(); if($player_rank->isLoaded()) { @@ -94,7 +94,7 @@ if(!empty($errors)) { } else { - if(isset($_REQUEST['todo']) && $_REQUEST['todo'] == 'save') { + if(isset($_POST['todo']) && $_POST['todo'] == 'save') { $player->setRank(); $twig->display('success.html.twig', array( 'title' => 'Leave guild', diff --git a/system/pages/guilds/list.php b/system/pages/guilds/list.php index 96d7bf08..94c49854 100644 --- a/system/pages/guilds/list.php +++ b/system/pages/guilds/list.php @@ -14,31 +14,31 @@ defined('MYAAC') or die('Direct access not allowed!'); require __DIR__ . '/base.php'; $guilds_list = new OTS_Guilds_List(); -$guilds_list->orderBy("name"); +$guilds_list->orderBy('name'); $guilds = array(); -if(count($guilds_list) > 0) -{ +if(count($guilds_list) > 0) { /** * @var OTS_Guild $guild */ foreach ($guilds_list as $guild) { $guild_logo = $guild->getCustomField('logo_name'); - if (empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) - $guild_logo = "default.gif"; + if (empty($guild_logo) || !file_exists(GUILD_IMAGES_DIR . $guild_logo)) { + $guild_logo = 'default.gif'; + } $description = $guild->getCustomField('description'); $description_with_lines = str_replace(array("\r\n", "\n", "\r"), ' ', $description, $count); - if ($count < setting('core.guild_description_lines_limit')) + if ($count < setting('core.guild_description_lines_limit')) { $description = nl2br($description); + } $guildName = $guild->getName(); $guilds[] = array('name' => $guildName, 'logo' => $guild_logo, 'link' => getGuildLink($guildName, false), 'description' => $description); } -}; +} $twig->display('guilds.list.html.twig', array( 'guilds' => $guilds, - 'logged' => isset($logged) ? $logged : false, 'isAdmin' => admin(), )); diff --git a/system/pages/guilds/manager.php b/system/pages/guilds/manager.php index 4d59c22e..cfcc00c6 100644 --- a/system/pages/guilds/manager.php +++ b/system/pages/guilds/manager.php @@ -21,7 +21,7 @@ if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; + $errors[] = "Guild with name $guild_name doesn't exist."; } } @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; @@ -39,22 +39,22 @@ if(empty($errors)) { $level_in_guild = 3; } } + if($guild_leader) { $twig->display('guilds.manager.html.twig', array( 'guild' => $guild, 'rank_list' => $rank_list )); } - else - { + else { $errors[] = 'You are not a leader of guild!'; } } - else - { - $errors[] = 'You are not logged. You can\'t manage guild.'; + else { + $errors[] = "You are not logged. You can't manage guild."; } } + if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); } diff --git a/system/pages/guilds/pass_leadership.php b/system/pages/guilds/pass_leadership.php index c09b4285..40633b8a 100644 --- a/system/pages/guilds/pass_leadership.php +++ b/system/pages/guilds/pass_leadership.php @@ -15,51 +15,52 @@ require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : NULL; $pass_to = isset($_REQUEST['player']) ? stripslashes($_REQUEST['player']) : NULL; if(!Validator::guildName($guild_name)) { - $guild_errors[] = Validator::getLastError(); + $errors[] = Validator::getLastError(); } -if(empty($guild_errors)) { +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) { - $guild_errors[] = "Guild with name " . $guild_name . " doesn't exist."; + $errors[] = "Guild with name " . $guild_name . " doesn't exist."; } } -if(empty($guild_errors)) { + +if(empty($errors)) { if(isset($_POST['todo']) && $_POST['todo'] == 'save') { if(!Validator::characterName($pass_to)) { - $guild_errors2[] = 'Invalid player name format.'; + $errors2[] = 'Invalid player name format.'; } - if(empty($guild_errors2)) { + if(empty($errors2)) { $to_player = new OTS_Player(); $to_player->find($pass_to); if(!$to_player->isLoaded()) { - $guild_errors2[] = 'Player with name '.$pass_to.' doesn\'t exist.'; + $errors2[] = 'Player with name '.$pass_to.' doesn\'t exist.'; } else if ($to_player->isDeleted()) { - $guild_errors2[] = "Character with name $pass_to has been deleted."; + $errors2[] = "Character with name $pass_to has been deleted."; } - if(empty($guild_errors2)) { + if(empty($errors2)) { $to_player_rank = $to_player->getRank(); if($to_player_rank->isLoaded()) { $to_player_guild = $to_player_rank->getGuild(); if($to_player_guild->getId() != $guild->getId()) { - $guild_errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; + $errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; } } else { - $guild_errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; + $errors2[] = 'Player with name '.$to_player->getName().' isn\'t from your guild.'; } } } } } -if(empty($guild_errors) && empty($guild_errors2)) { +if(empty($errors) && empty($errors2)) { if($logged) { $guild_leader_char = $guild->getOwner(); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { $guild_vice = true; @@ -99,23 +100,23 @@ if(empty($guild_errors) && empty($guild_errors2)) { } } else { - $guild_errors[] = 'You are not a leader of guild!'; + $errors[] = 'You are not a leader of guild!'; } } else { - $guild_errors[] = "You are not logged. You can't manage guild."; + $errors[] = "You are not logged. You can't manage guild."; } } -if(empty($guild_errors) && !empty($guild_errors2)) { - $twig->display('error_box.html.twig', array('errors' => $guild_errors2)); +if(empty($errors) && !empty($errors2)) { + $twig->display('error_box.html.twig', array('errors' => $errors2)); echo ' '; } -if(!empty($guild_errors)) { - if(!empty($guild_errors2)) { - $guild_errors = array_merge($guild_errors, $guild_errors2); +if(!empty($errors)) { + if(!empty($errors2)) { + $errors = array_merge($errors, $errors2); } - $twig->display('error_box.html.twig', array('errors' => $guild_errors)); + $twig->display('error_box.html.twig', array('errors' => $errors)); echo ' '; } diff --git a/system/pages/guilds/save_ranks.php b/system/pages/guilds/save_ranks.php index e1483659..2a36e595 100644 --- a/system/pages/guilds/save_ranks.php +++ b/system/pages/guilds/save_ranks.php @@ -31,7 +31,7 @@ if(empty($errors)) { $rank_list = $guild->getGuildRanksList(); $rank_list->orderBy('level', POT::ORDER_DESC); $guild_leader = false; - $account_players = $account_logged->getPlayers(); + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { if($guild_leader_char->getId() == $player->getId()) { @@ -61,6 +61,7 @@ if(empty($errors)) { $rank->save(); } + //show errors or redirect if(empty($errors)) { header("Location: " . getLink('guilds') . "?action=manager&guild=".$guild->getName()); @@ -73,10 +74,10 @@ if(empty($errors)) { } else { - $errors[] = 'You are not logged. You can\'t manage guild.'; + $errors[] = "You are not logged. You can't manage guild."; } } if(!empty($errors)) { - $twig->display('error_box.html.twig', array('errors' => $errors)); + $twig->display('error_box.html.twig', ['errors' => $errors]); } diff --git a/system/pages/guilds/show.php b/system/pages/guilds/show.php index 33039ad3..99ac6599 100644 --- a/system/pages/guilds/show.php +++ b/system/pages/guilds/show.php @@ -16,19 +16,18 @@ $title = 'Guilds'; require __DIR__ . '/base.php'; $guild_name = isset($_REQUEST['guild']) ? urldecode($_REQUEST['guild']) : null; -if(!Validator::guildName($guild_name)) +if(!Validator::guildName($guild_name)) { $errors[] = Validator::getLastError(); +} -if(empty($errors)) -{ +if(empty($errors)) { $guild = new OTS_Guild(); $guild->find($guild_name); if(!$guild->isLoaded()) $errors[] = 'Guild with name '.$guild_name.' doesn\'t exist.'; } -if(!empty($errors)) -{ +if(!empty($errors)) { $twig->display('error_box.html.twig', array('errors' => $errors)); $twig->display('guilds.back_button.html.twig'); return; @@ -47,9 +46,8 @@ $level_in_guild = 0; $players_from_account_in_guild = array(); $players_from_account_ids = array(); -if($logged) -{ - $account_players = $account_logged->getPlayers(); +if($logged) { + $account_players = $account_logged->getPlayersList(); foreach($account_players as $player) { $players_from_account_ids[] = $player->getId(); @@ -123,25 +121,28 @@ foreach($rank_list as $rank) } } -include(SYSTEM . 'libs/pot/InvitesDriver.php'); -new InvitesDriver($guild); -$invited_list = $guild->listInvites(); +$invited_list = []; $show_accept_invite = 0; -if($logged && count($invited_list) > 0) -{ - foreach($invited_list as $invited_player) - { - if(count($account_players) > 0) - { - foreach($account_players as $player_from_acc) - { - if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) - $show_accept_invite++; + +if ($db->hasTableAndColumns('guild_invites', ['player_id'])) { + include(SYSTEM . 'libs/pot/InvitesDriver.php'); + new InvitesDriver($guild); + $invited_list = $guild->listInvites(); + + if($logged && count($invited_list) > 0) { + foreach($invited_list as $invited_player) { + if(count($account_players) > 0) { + foreach($account_players as $player_from_acc) { + if($player_from_acc->isLoaded() && $invited_player->isLoaded() && $player_from_acc->getName() == $invited_player->getName()) { + $show_accept_invite++; + } + } } } } } + $useGuildNick = $db->hasTable('guild_members') || $db->hasTable('guild_membership') || $db->hasColumn('players', 'guildnick'); $twig->display('guilds.view.html.twig', array( diff --git a/system/pages/highscores.php b/system/pages/highscores.php index 91ba2e2b..cec95d15 100644 --- a/system/pages/highscores.php +++ b/system/pages/highscores.php @@ -18,8 +18,11 @@ defined('MYAAC') or die('Direct access not allowed!'); $title = 'Highscores'; $settingHighscoresCountryBox = setting('core.highscores_country_box'); -if(config('account_country') && $settingHighscoresCountryBox) +if(config('account_country') && $settingHighscoresCountryBox) { require SYSTEM . 'countries.conf.php'; +} + +$highscoresTTL = setting('core.highscores_cache_ttl'); $list = urldecode($_GET['list'] ?? 'experience'); $page = $_GET['page'] ?? 1; @@ -120,16 +123,10 @@ if($db->hasColumn('players', 'promotion')) $promotion = ',players.promotion'; $outfit_addons = false; -$outfit = ''; - -$settingHighscoresOutfit = setting('core.highscores_outfit'); - -if($settingHighscoresOutfit) { - $outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; - if($db->hasColumn('players', 'lookaddons')) { - $outfit .= ', lookaddons'; - $outfit_addons = true; - } +$outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; +if($db->hasColumn('players', 'lookaddons')) { + $outfit .= ', lookaddons'; + $outfit_addons = true; } $configHighscoresPerPage = setting('core.highscores_per_page'); @@ -140,20 +137,27 @@ $needReCache = true; $cacheKey = 'highscores_' . $skill . '_' . $vocation . '_' . $page . '_' . $configHighscoresPerPage; $cache = Cache::getInstance(); -if ($cache->enabled()) { +if ($cache->enabled() && $highscoresTTL > 0) { $tmp = ''; if ($cache->fetch($cacheKey, $tmp)) { - $highscores = unserialize($tmp); + $data = unserialize($tmp); + $totalResults = $data['totalResults']; + $highscores = $data['highscores']; + $updatedAt = $data['updatedAt']; $needReCache = false; } } $offset = ($page - 1) * $configHighscoresPerPage; -$query->join('accounts', 'accounts.id', '=', 'players.account_id') - ->withOnlineStatus() +$query->withOnlineStatus() ->whereNotIn('players.id', setting('core.highscores_ids_hidden')) ->notDeleted() - ->where('players.group_id', '<', setting('core.highscores_groups_hidden')) + ->where('players.group_id', '<', setting('core.highscores_groups_hidden')); + +$totalResultsQuery = clone $query; + +$query + ->join('accounts', 'accounts.id', '=', 'players.account_id') ->limit($limit) ->offset($offset) ->selectRaw('accounts.country, players.id, players.name, players.account_id, players.level, players.vocation' . $outfit . $promotion) @@ -212,17 +216,24 @@ if (empty($highscores)) { return $tmp; })->toArray(); + + $updatedAt = time(); + $totalResults = $totalResultsQuery->count(); } -if ($cache->enabled() && $needReCache) { - $cache->set($cacheKey, serialize($highscores), setting('core.highscores_cache_ttl') * 60); +if ($highscoresTTL > 0 && $cache->enabled() && $needReCache) { + $cache->set($cacheKey, serialize( + [ + 'totalResults' => $totalResults, + 'highscores' => $highscores, + 'updatedAt' => $updatedAt, + ] + ), $highscoresTTL * 60); } $show_link_to_next_page = false; $i = 0; -$settingHighscoresVocation = setting('core.highscores_vocation'); - foreach($highscores as $id => &$player) { if(++$i <= $configHighscoresPerPage) @@ -236,10 +247,22 @@ foreach($highscores as $id => &$player) $player['link'] = getPlayerLink($player['name'], false); $player['flag'] = getFlagImage($player['country']); - if($settingHighscoresOutfit) { - $player['outfit'] = ' '; +} + /** @var Twig\Environment $twig */ $twig->display('highscores.html.twig', [ 'highscores' => $highscores, @@ -290,4 +319,8 @@ $twig->display('highscores.html.twig', [ 'types' => $types, 'linkPreviousPage' => $linkPreviousPage, 'linkNextPage' => $linkNextPage, + 'totalResults' => $totalResults, + 'page' => $page, + 'baseLink' => $baseLink, + 'updatedAt' => $updatedAt, ]); diff --git a/system/pages/online.php b/system/pages/online.php index 4f0baa7d..21f2ee0d 100644 --- a/system/pages/online.php +++ b/system/pages/online.php @@ -9,123 +9,140 @@ * @link https://my-aac.org */ +use MyAAC\Cache\Cache; use MyAAC\Models\ServerConfig; use MyAAC\Models\ServerRecord; defined('MYAAC') or die('Direct access not allowed!'); $title = 'Who is online?'; -if (setting('core.account_country')) +if (setting('core.account_country')) { require SYSTEM . 'countries.conf.php'; +} $promotion = ''; -if($db->hasColumn('players', 'promotion')) +if($db->hasColumn('players', 'promotion')) { $promotion = '`promotion`,'; - -$order = $_GET['order'] ?? 'name'; -if(!in_array($order, array('country', 'name', 'level', 'vocation'))) - $order = $db->fieldName('name'); -else if($order == 'country') - $order = $db->tableName('accounts') . '.' . $db->fieldName('country'); -else if($order == 'vocation') - $order = $promotion . 'vocation ASC'; - -$skull_type = 'skull'; -if($db->hasColumn('players', 'skull_type')) { - $skull_type = 'skull_type'; } -$skull_time = 'skulltime'; -if($db->hasColumn('players', 'skull_time')) { - $skull_time = 'skull_time'; +$order = $_GET['order'] ?? 'name_asc'; +if(!in_array($order, ['country_asc', 'country_desc', 'name_asc', 'name_desc', 'level_asc', 'level_desc', 'vocation_asc', 'vocation_desc'])) { + $order = 'name_asc'; +} +else if($order == 'vocation_asc' || $order == 'vocation_desc') { + $order = $promotion . 'vocation_' . (str_contains($order, 'asc') ? 'asc' : 'desc'); } -$outfit_addons = false; -$outfit = ''; -if (setting('core.online_outfit')) { +$cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60, function() use($db, $promotion, $order) { + $orderExplode = explode('_', $order); + $orderSql = $orderExplode[0] . ' ' . $orderExplode[1]; + + $skull_type = 'skull'; + if($db->hasColumn('players', 'skull_type')) { + $skull_type = 'skull_type'; + } + + $skull_time = 'skulltime'; + if($db->hasColumn('players', 'skull_time')) { + $skull_time = 'skull_time'; + } + + $outfit_addons = false; $outfit = ', lookbody, lookfeet, lookhead, looklegs, looktype'; if($db->hasColumn('players', 'lookaddons')) { $outfit .= ', lookaddons'; $outfit_addons = true; } -} -$vocs = []; -if (setting('core.online_vocations')) { - foreach($config['vocations'] as $id => $name) { - $vocs[$id] = 0; - } -} + $vocations = array_map(function ($name) { + return 0; + }, setting('core.vocations')); -if($db->hasTable('players_online')) // tfs 1.0 - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); -else - $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $order); + if($db->hasTable('players_online')) // tfs 1.0 + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players`, `players_online` WHERE `players`.`id` = `players_online`.`player_id` AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); + else + $playersOnline = $db->query('SELECT `accounts`.`country`, `players`.`name`, `players`.`level`, `players`.`vocation`' . $outfit . ', ' . $promotion . ' `' . $skull_time . '` as `skulltime`, `' . $skull_type . '` as `skull` FROM `accounts`, `players` WHERE `players`.`online` > 0 AND `accounts`.`id` = `players`.`account_id` ORDER BY ' . $orderSql); -$players_data = array(); -$players = 0; -$data = ''; -foreach($playersOnline as $player) { - $skull = ''; - if (setting('core.online_skulls')) - { - if($player['skulltime'] > 0) - { - if($player['skull'] == 3) + $settingVocations = setting('core.vocations'); + $settingVocationsAmount = setting('core.vocations_amount'); + + $players = []; + foreach($playersOnline as $player) { + $skull = ''; + if($player['skulltime'] > 0) { + if($player['skull'] == 3) { $skull = '  ';
-			elseif($player['skull'] == 4)
+			}
+			elseif($player['skull'] == 4) {
 				$skull = '  ';
-			elseif($player['skull'] == 5)
+			}
+			elseif($player['skull'] == 5) {
 				$skull = '  ';
-		}
-	}
-
-	if(isset($player['promotion'])) {
-		if((int)$player['promotion'] > 0)
-			$player['vocation'] += ($player['promotion'] * $config['vocations_amount']);
-	}
-
-	$players_data[] = array(
-		'name' => getPlayerLink($player['name']),
-		'player' => $player,
-		'level' => $player['level'],
-		'vocation' => $config['vocations'][$player['vocation']],
-		'country_image' => setting('core.account_country') ? getFlagImage($player['country']) : null,
-		'outfit' => setting('core.online_outfit') ? setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'] : null
-	);
-
-	if (setting('core.online_vocations')) {
-		$vocs[($player['vocation'] > $config['vocations_amount'] ? $player['vocation'] - $config['vocations_amount'] : $player['vocation'])]++;
-	}
-}
-
-$record = '';
-if(count($players_data) > 0) {
-	if( setting('core.online_record')) {
-		$result = null;
-		$timestamp = false;
-		if($db->hasTable('server_record')) {
-			$timestamp = true;
-			$result = ServerRecord::where('world_id', $config['lua']['worldId'])->orderByDesc('record')->first()->toArray();
-		} else if($db->hasTable('server_config')) { // tfs 1.0
-			$row = ServerConfig::where('config', 'players_record')->first();
-			if ($row) {
-				$result = ['record' => $row->value];
 			}
 		}
 
-		if($result) {
-			$record = 'The maximum on this game world was ' . $result['record'] . ' players' . ($timestamp ? ' on ' . date("M d Y, H:i:s", $result['timestamp']) . '.' : '.');
+		if(isset($player['promotion'])) {
+			if((int)$player['promotion'] > 0)
+				$player['vocation'] += ($player['promotion'] * $settingVocationsAmount);
+		}
+
+		$players[] = array(
+			'name' => getPlayerLink($player['name']),
+			'player' => $player,
+			'level' => $player['level'],
+			'vocation' => $settingVocations[$player['vocation']],
+			'skull' => $skull,
+			'country_image' => getFlagImage($player['country']),
+			'outfit' => setting('core.outfit_images_url') . '?id=' . $player['looktype'] . ($outfit_addons ? '&addons=' . $player['lookaddons'] : '') . '&head=' . $player['lookhead'] . '&body=' . $player['lookbody'] . '&legs=' . $player['looklegs'] . '&feet=' . $player['lookfeet'],
+		);
+
+		$vocations[($player['vocation'] > $settingVocationsAmount ? $player['vocation'] - $settingVocationsAmount : $player['vocation'])]++;
+	}
+
+	$record = '';
+	if(count($players) > 0) {
+		if( setting('core.online_record')) {
+			$result = null;
+			$timestamp = false;
+			if($db->hasTable('server_record')) {
+				$timestamp = $db->hasColumn('server_record', 'timestamp');
+				$serverRecordQuery = ServerRecord::query();
+
+				if ($db->hasColumn('server_record', 'world_id')) {
+					$serverRecordQuery->where('world_id', configLua('worldId'));
+				}
+
+				$result = $serverRecordQuery->orderByDesc('record')->first();
+				if ($result) {
+					$result = $result->toArray();
+				}
+			} else if($db->hasTable('server_config')) { // tfs 1.0
+				$row = ServerConfig::where('config', 'players_record')->first();
+				if ($row) {
+					$result = ['record' => $row->value];
+				}
+			}
+
+			if($result) {
+				$record = $result['record'] . ' player' . ($result['record'] > 1 ? 's' : '') . ($timestamp ? ' (on ' . date("M d Y, H:i:s", $result['timestamp']) . ')' : '');
+			}
 		}
 	}
-}
+
+	return [
+		'players' => $players,
+		'record' => $record,
+		'vocations' => $vocations,
+	];
+});
 
 $twig->display('online.html.twig', array(
-	'players' => $players_data,
-	'record' => $record,
-	'vocs' => $vocs,
+	'players' => $cached['players'],
+	'record' => $cached['record'],
+	'vocations' => $cached['vocations'],
+	'vocs' => $cached['vocations'], // deprecated, to be removed
+	'order' => $order,
 ));
 
-//search bar
-$twig->display('online.form.html.twig');
-?>
+// search bar
+$twig->display('characters.form.html.twig');
diff --git a/system/pages/ots-info.php b/system/pages/ots-info.php
new file mode 100644
index 00000000..b750c3ee
--- /dev/null
+++ b/system/pages/ots-info.php
@@ -0,0 +1,110 @@
+
+ * @author    Slawkens '; - var_dump($route[1], $route[3], $route[2]); + var_dump($pluginRoute[1], $pluginRoute[3], $pluginRoute[2]); echo '/ |