Compare commits

..

13 Commits

Author SHA1 Message Date
slawkens
abee4b3962 Add spomky-labs/otphp 2025-09-14 13:01:51 +02:00
slawkens
fbdb6890b9 Working two factor email authentication 2025-09-14 11:38:01 +02:00
slawkens
041f58ed11 Merge branch 'main' into feature/2fa 2025-09-14 09:53:34 +02:00
slawkens
03c7dd0002 Merge branch 'main' into feature/2fa 2025-08-12 14:36:29 +02:00
slawkens
e435062025 [WIP] 2fa 2025-07-05 08:20:58 +02:00
slawkens
ecc9bd4042 Merge branch 'main' into feature/2fa 2025-07-01 14:18:38 +02:00
slawkens
797377e428 Replace TwoFactorAuth with self 2025-06-22 22:34:36 +02:00
slawkens
96b5df9d74 Merge branch 'main' into feature/2fa 2025-06-22 18:51:32 +02:00
slawkens
b3dfc56c96 [WIP] Working 2fa email auth 2025-06-22 18:50:54 +02:00
slawkens
96d6e04bd2 Update 46-account_email_codes.sql 2025-06-22 13:19:29 +02:00
slawkens
9146eee327 Move 2025-06-22 11:55:34 +02:00
slawkens
3d97fa0719 Merge branch 'main' into feature/2fa 2025-06-22 11:45:21 +02:00
slawkens
a66cafceab 2fa: first draft 2025-06-22 08:34:30 +02:00
165 changed files with 5266 additions and 2465 deletions

View File

@@ -1,9 +1,9 @@
name: Cypress
on:
pull_request:
branches: [develop]
branches: [main]
push:
branches: [develop]
branches: [main]
jobs:
cypress:
@@ -22,7 +22,7 @@ jobs:
strategy:
fail-fast: false
matrix:
php-versions: [ '8.1', '8.2', '8.3', '8.4', '8.5' ]
php-versions: [ '8.1', '8.2', '8.3', '8.4' ]
ots: ['tfs-1.4', 'canary-3.1.2'] # TODO: add 'tfs-master' (actually doesn't work cause AAC doesn't support reading .env configuration)
name: Cypress (PHP ${{ matrix.php-versions }}, ${{ matrix.ots }})
steps:

View File

@@ -1,9 +1,9 @@
name: PHP Linting
on:
pull_request:
branches: [develop]
branches: [main]
push:
branches: [develop]
branches: [main]
jobs:
phplint:

View File

@@ -2,9 +2,9 @@ name: "PHPStan"
on:
pull_request:
branches: [develop]
branches: [main]
push:
branches: [develop]
branches: [main]
jobs:
tests:

3
.gitignore vendored
View File

@@ -4,7 +4,7 @@ Thumbs.db
#
/.htaccess
/lua
lua
# composer
composer.phar
@@ -24,7 +24,6 @@ releases
tmp
config.local.php
config2.local.php
# all custom templates
templates/*

View File

@@ -1,97 +1,5 @@
# Changelog
## [1.8.7 - 04.01.2026]
### Fixed
* Fixed [player/guild/house] bb code in forum (https://github.com/slawkens/myaac/commit/8ec9bf10682c73f1fe40967a106ccda2a5073ed0)
### Changed
* Settings: better responsiveness on mobile (https://github.com/slawkens/myaac/commit/c65d4e4b62ef26fb4e24ecb1d2bcc4556d746adf)
* Signatures: Return 404 when the signature player is not found (https://github.com/slawkens/myaac/commit/7e6480b380799add7a2b1b7ce1d3c1f2b6819ff1)
### Removed
* Remove setting: outfit_images_wrong_looktypes - is obsolete, the bug doesn't exist in the latest outfit images (https://github.com/slawkens/myaac/commit/cc220bedc1f01535eaac23f6961135e2e7a6e310)
## [1.8.6 - 14.12.2025]
### Added
* Added hook for adding custom rules to validate new character name (https://github.com/slawkens/myaac/commit/8e6749c59984631288e8e9803819b2f0ff389761)
### Fixed
* Highscores: Fix ordering by different skills (Adjust order by desc: skill_tries, manaspent, experience) - More exact results (https://github.com/slawkens/myaac/commit/c86257e6dacbad773aa09c0958eeaa106a967f2d)
* Fix exception shown on first install, when there is no vendor - Before it displayed 500 white page, now it display the exception (https://github.com/slawkens/myaac/commit/18a1178e4b93607a350259679e0366cb83fb4126)
* Fix typo $up -> $down, in migration nr 7, was failing due that (https://github.com/slawkens/myaac/commit/fd74f01291d0e9cdb92ee1b95021c9d7b591ad7c)
### Changed
* Ini set html_errors = 0, to show html code in exceptions (https://github.com/slawkens/myaac/commit/9ed06782e67772826d927ad847a077b99df5060d)
## [1.8.5 - 21.11.2025]
### Added
* New Setting: Account Countries Most Popular (https://github.com/slawkens/myaac/commit/946364f59d7cd01472877108ab27ec78fb28307a)
### Changed
* Status: Write to status-error.log if there is connection error (https://github.com/slawkens/myaac/commit/780d4ccef741c1dd45a00bfc121fba9f1a175313)
* Settings: escapeHtml in values (support for html code) (https://github.com/slawkens/myaac/commit/5861efdbe900ccd35309913af0c0a5f3d4cdc1a8)
* News Page: Don't display hidden news for admin - it's confusing (https://github.com/slawkens/myaac/commit/175e97828b9a08ec3080cc8d3fb4eb3f1c08649f)
* Plugins System: Add plugin:remove + plugin:delete as alias for plugin:uninstall + plugin:activate/deactivate (https://github.com/slawkens/myaac/commit/6367054487368c92741bfd1dc7c70c52aea9ee87, https://github.com/slawkens/myaac/commit/baec6c9ebf5c342b3b2f7123427c6ba21dbb93bc)
### Fixed
* Status: Fix $status['uptimeReadable'], was totally wrong (https://github.com/slawkens/myaac/commit/0a6d44bf21417562491aabc93543a2bc3a44b2df)
* Guilds: Detect "deletion" column in guilds show/delete (https://github.com/slawkens/myaac/commit/6775a061bebc9ff449522f0173556d4a7a44fa5e, https://github.com/slawkens/myaac/commit/603d860b56bc7418db09e206f40aa06d0682c00e)
* General: Ensure some cache folders & index.html exists (https://github.com/slawkens/myaac/commit/730a0f29124811f525207c24c06eb0d088fa3434)
## [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

View File

@@ -1,12 +0,0 @@
## [2.0-dev - x.x.2025]
### Added
* Add an "access" option to Menus (#340)
* Possibility to hide menus for unauthorized users
* Add the possibility to fetch skills in the getTopPlayers function
### Changed
* Better handling of vocations: (#345)
* Load from vocations.xml (No need to manually set)
* Support for Monk vocation
* Reworked account action logs to use a single IP column as varchar(45) for both ipv4 and ipv6 (#289)

4
aac
View File

@@ -25,9 +25,7 @@ foreach ($commandsGlob as $item) {
}
$commandPre = '\\MyAAC\Commands\\';
if (!trait_exists($class = $commandPre . $name)) {
$application->add(new $class);
}
$application->add(new ($commandPre . $name));
}
$pluginCommands = Plugins::getCommands();

View File

@@ -9,7 +9,6 @@
*/
use MyAAC\Models\Account as AccountModel;
use MyAAC\Models\AccountAction;
use MyAAC\Models\Player;
defined('MYAAC') or die('Direct access not allowed!');
@@ -482,8 +481,9 @@ else if (isset($_REQUEST['search'])) {
</thead>
<tbody>
<?php
$accountActions = AccountAction::where('account_id', $account->getId())->orderByDesc('date')->get();
$accountActions = \MyAAC\Models\AccountAction::where('account_id', $account->getId())->orderByDesc('date')->get();
foreach ($accountActions as $i => $log):
$log->ip = ($log->ip != 0 ? long2ip($log->ip) : inet_ntop($log->ipv6));
?>
<tr>
<td><?php echo $i + 1; ?></td>

View File

@@ -6,7 +6,6 @@
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @author Lee
* @author gpedro
* @copyright 2020 MyAAC
* @link https://my-aac.org
*/
@@ -20,9 +19,9 @@ $title = 'Mass Account Actions';
csrfProtect();
$hasPointsColumn = $db->hasColumn('accounts', 'premium_points');
$freePremium = getBoolean(configLua('freePremium'));
$freePremium = $config['lua']['freePremium'];
function admin_give_points($points): void
function admin_give_points($points)
{
global $hasPointsColumn;
@@ -38,7 +37,7 @@ function admin_give_points($points): void
displayMessage($points . ' points added to all accounts.', true);
}
function admin_give_coins($coins): void
function admin_give_coins($coins)
{
if (!HAS_ACCOUNT_COINS) {
displayMessage('Coins not supported.');
@@ -53,7 +52,7 @@ function admin_give_coins($coins): void
displayMessage($coins . ' coins added to all accounts.', true);
}
function admin_give_premdays($days): void
function admin_give_premdays($days)
{
global $db, $freePremium;
@@ -64,7 +63,6 @@ function admin_give_premdays($days): void
$value = $days * 86400;
$now = time();
// othire
if ($db->hasColumn('accounts', 'premend')) {
// append premend
@@ -72,11 +70,14 @@ function admin_give_premdays($days): void
// set premend
if (Account::where('premend', '<=', $now)->update(['premend' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {
displayMessage('Failed to execute set query.');
return;
}
} else {
displayMessage('Failed to execute append query.');
return;
}
return;
@@ -91,14 +92,20 @@ function admin_give_premdays($days): void
// set lastday
if (Account::where('lastday', '<=', $now)->update(['lastday' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {
displayMessage('Failed to execute set query.');
return;
}
return;
} else {
displayMessage('Failed to execute append query.');
return;
}
} else {
displayMessage('Failed to execute set days query.');
return;
}
return;
@@ -111,11 +118,14 @@ function admin_give_premdays($days): void
// set premium_ends_at
if (Account::where('premium_ends_at', '<=', $now)->update(['premium_ends_at' => $now + $value])) {
displayMessage($days . ' premium days added to all accounts.', true);
return;
} else {
displayMessage('Failed to execute set query.');
return;
}
} else {
displayMessage('Failed to execute append query.');
return;
}
return;
@@ -160,8 +170,7 @@ else {
));
}
function displayMessage($message, $success = false): void
{
function displayMessage($message, $success = false) {
global $twig, $hasPointsColumn, $freePremium;
$success ? success($message): error($message);

View File

@@ -23,7 +23,6 @@ if (!hasFlag(FLAG_CONTENT_MENUS) && !superAdmin()) {
}
$pluginThemes = Plugins::getThemes();
$groups = new OTS_Groups_List();
if (isset($_POST['template'])) {
$template = $_POST['template'];
@@ -33,8 +32,6 @@ if (isset($_POST['template'])) {
$post_menu_link = $_POST['menu_link'] ?? [];
$post_menu_blank = $_POST['menu_blank'] ?? [];
$post_menu_color = $_POST['menu_color'] ?? [];
$post_menu_access = $_POST['menu_access'] ?? [];
if (count($post_menu) != count($post_menu_link)) {
echo 'Menu count is not equal menu links. Something went wrong when sending form.';
return;
@@ -53,7 +50,6 @@ if (isset($_POST['template'])) {
'link' => $post_menu_link[$category][$i],
'blank' => $post_menu_blank[$category][$i] == 'on' ? 1 : 0,
'color' => str_replace('#', '', $post_menu_color[$category][$i]),
'access' => $post_menu_access[$category][$i],
'category' => $category,
'ordering' => $i
]);
@@ -126,7 +122,7 @@ if (isset($_POST['template'])) {
?>
<?php
$menus = Menu::query()
->select('name', 'link', 'access', 'blank', 'color', 'category', 'ordering')
->select('name', 'link', 'blank', 'color', 'category', 'ordering')
->where('enabled', 1)
->where('template', $template)
->orderBy('ordering')
@@ -155,34 +151,11 @@ if (isset($_POST['template'])) {
foreach ($menus[$id] as $menu):
$color = (empty($menu['color']) ? ($cat['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'))) : '#' . $menu['color']);
?>
<li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>">
<label class="label_menu_name">Name: <input type="text" name="menu[<?php echo $id ?>][]" class="form-control menu-name" value="<?php echo escapeHtml($menu['name']); ?>"/>
</label>
<label class="label_menu_link">Link: <input type="text" name="menu_link[<?= $id ?>][]" class="form-control menu-link" value="<?php echo $menu['link'] ?>"/>
</label>
<br/>
<div class="menu-options-row">
<label>Access:
<select name="menu_access[<?= $id ?>][]" class="form-control menu-access">
<option value="0" <?= ($menu['access'] == 0 ? 'selected' : ''); ?>>Guest*</option>
<?php foreach ($groups->getGroups() as $group): ?>
<option value="<?= $group->getId(); ?>" <?= ($menu['access'] == $group->getId() ? 'selected' : ''); ?>><?= ucfirst($group->getName()); ?></option>
<?php endforeach; ?>
</select>
</label>
<label>Color: <input class="menu-color" type="color" name="menu_color[<?php echo $id ?>][]" value="<?php echo $color; ?>"/>
</label>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" class="menu-blank" value="0"/>
<label><input type="checkbox" class="menu-blank-checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
</div>
<li class="ui-state-default" id="list-<?php echo $id ?>-<?php echo $i ?>"><label>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/>
<label>Link:</label> <input type="text" name="menu_link[<?php echo $id ?>][]" value="<?php echo $menu['link'] ?>"/>
<input type="hidden" name="menu_blank[<?php echo $id ?>][]" value="0"/>
<label><input class="blank-checkbox" type="checkbox" <?php echo($menu['blank'] == 1 ? 'checked' : '') ?>/><span title="Open in New Window">New Window</span></label>
<input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo $color; ?>"/>
<a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li>
<?php $i++; $last_id[$id] = $i;
endforeach;

View File

@@ -10,7 +10,6 @@
use MyAAC\Forum;
use MyAAC\Models\Player;
use MyAAC\Server\XML\Vocations;
defined('MYAAC') or die('Direct access not allowed!');
@@ -35,7 +34,6 @@ $skills = array(
$hasBlessingsColumn = $db->hasColumn('players', 'blessings');
$hasBlessingColumn = $db->hasColumn('players', 'blessings1');
$hasLookAddons = $db->hasColumn('players', 'lookaddons');
$hasCapColumn = $db->hasColumn('players', 'cap');
$skull_type = array("None", "Yellow", "Green", "White", "Red", "Black", "Orange");
?>
@@ -168,11 +166,8 @@ else if (isset($_REQUEST['search'])) {
$town = $_POST['town'];
verify_number($town, 'Town', 11);
if ($hasCapColumn) {
$capacity = $_POST['capacity'];
verify_number($capacity, 'Capacity', 11);
}
$capacity = $_POST['capacity'];
verify_number($capacity, 'Capacity', 11);
$sex = $_POST['sex'];
verify_number($sex, 'Sex', 1);
@@ -242,30 +237,7 @@ else if (isset($_REQUEST['search'])) {
$player->setGroup($groups->getGroup($group));
$player->setLevel($level);
$player->setExperience($experience);
if ($db->hasColumn('players', 'promotion')) {
$promotion = 0;
$vocationOriginal = Vocations::getOriginal($vocation);
if ($vocation != $vocationOriginal) {
$tmpId = $vocationOriginal;
while($promoted = Vocations::getPromoted($tmpId)) {
$promotion++;
$tmpId = $promoted;
if ($promoted == $vocation) {
break;
}
}
$vocation = $vocationOriginal;
}
$player->setPromotion($promotion);
}
$player->setVocation($vocation);
$player->setHealth($health);
$player->setHealthMax($health_max);
$player->setMagLevel($magic_level);
@@ -277,20 +249,16 @@ else if (isset($_REQUEST['search'])) {
$player->setLookHead($look_head);
$player->setLookLegs($look_legs);
$player->setLookType($look_type);
if ($hasLookAddons) {
if ($hasLookAddons)
$player->setLookAddons($look_addons);
}
if ($db->hasColumn('players', 'offlinetraining_time'))
$player->setCustomField('offlinetraining_time', $offlinetraining);
$player->setPosX($pos_x);
$player->setPosY($pos_y);
$player->setPosZ($pos_z);
$player->setSoul($soul);
$player->setTownId($town);
if ($hasCapColumn) {
$player->setCap($capacity);
}
$player->setCap($capacity);
$player->setSex($sex);
$player->setLastLogin($lastlogin);
$player->setLastLogout($lastlogout);
@@ -307,11 +275,23 @@ else if (isset($_REQUEST['search'])) {
if ($hasBlessingsColumn)
$player->setBlessings($blessings);
if ($hasBlessingColumn) {
for ($i = 1; $i <= $bless_count; $i++) {
$a = 'blessing' . $i;
$player->setCustomField('blessings' . $i, ${'blessing' . $i} ? '1' : '0');
}
}
$player->setBalance($balance);
if ($db->hasColumn('players', 'stamina'))
$player->setStamina($stamina);
$player->setDeleted($deleted ? '1' : '0');
if ($db->hasColumn('players', 'deletion'))
$player->setCustomField('deletion', $deleted ? '1' : '0');
else
$player->setCustomField('deleted', $deleted ? '1' : '0');
$player->setCustomField('hide', $hide ? '1' : '0');
$player->setCustomField('created', $created);
if (isset($comment))
$player->setCustomField('comment', $comment);
foreach ($_POST['skills'] as $skill => $value) {
$player->setSkill($skill, $value);
@@ -320,24 +300,6 @@ else if (isset($_REQUEST['search'])) {
$player->setSkillTries($skill, $value);
}
$player->save();
if ($db->hasColumn('players', 'offlinetraining_time')) {
$player->setCustomField('offlinetraining_time', $offlinetraining);
}
if ($hasBlessingColumn) {
for ($i = 1; $i <= $bless_count; $i++) {
$a = 'blessing' . $i;
$player->setCustomField('blessings' . $i, ${'blessing' . $i} ? '1' : '0');
}
}
$player->setCustomField('hide', $hide ? '1' : '0');
$player->setCustomField('created', $created);
if (isset($comment)) {
$player->setCustomField('comment', $comment);
}
echo_success('Player saved at: ' . date('G:i'));
$player->load($id);
}
@@ -569,12 +531,10 @@ else if (isset($_REQUEST['search'])) {
</div>
</div>
<div class="form-group row">
<?php if($hasCapColumn): ?>
<div class="col-12 col-sm-12 col-lg-6">
<label for="capacity" class="control-label">Capacity:</label>
<input type="text" class="form-control" id="capacity" name="capacity" autocomplete="off" size="3" maxlength="11" value="<?php echo $player->getCap(); ?>"/>
</div>
<?php endif; ?>
<div class="col-12 col-sm-12 col-lg-6">
<label for="soul" class="control-label">Soul:</label>
<input type="text" class="form-control" id="soul" name="soul" autocomplete="off" size="3" maxlength="10" value="<?php echo $player->getSoul(); ?>"/>
@@ -709,17 +669,11 @@ else if (isset($_REQUEST['search'])) {
<div class="col-12 col-sm-12 col-lg-6">
<label for="lastip" class="control-label">Last IP:</label>
<input type="text" class="form-control" id="lastip" name="lastip" autocomplete="off" maxlength="10" value="<?php
$lastIPColumnInfo = $db->getColumnInfo('players', 'lastip');
if ($lastIPColumnInfo && is_array($lastIPColumnInfo)) {
if (str_contains($lastIPColumnInfo['type'], 'varbinary')) {
echo inet_ntop($player->getLastIP());
}
else {
echo longToIp($player->getLastIP());
}
if (strlen($player->getLastIP()) > 11) {
echo inet_ntop($player->getLastIP());
}
else {
echo 'Error';
echo longToIp($player->getLastIP());
}
?>" readonly/>
</div>

View File

@@ -60,7 +60,7 @@ usort($menus, function ($a, $b) {
foreach ($menus as $i => $menu) {
if (isset($menu['link']) && is_array($menu['link'])) {
usort($menu['link'], function ($a, $b) {
usort($menus[$i]['link'], function ($a, $b) {
return $a['order'] - $b['order'];
});
}

View File

@@ -19,14 +19,14 @@
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700,300italic,400italic,600italic">
<?php $hooks->trigger(HOOK_ADMIN_HEAD_END); ?>
</head>
<body class="sidebar-mini <?= (session('admin.menu-collapse') ? 'sidebar-collapse' : ''); ?>">
<body class="sidebar-mini ">
<?php $hooks->trigger(HOOK_ADMIN_BODY_START); ?>
<?php if ($logged && admin()) { ?>
<div class="wrapper">
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link sidebar-toggle" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
<a class="nav-link" data-widget="pushmenu" href="#"><i class="fas fa-bars"></i></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="<?php echo ADMIN_URL; ?>" class="nav-link">Home</a>
@@ -198,7 +198,6 @@ if ($logged && admin()) {
<script src="<?php echo BASE_URL; ?>tools/js/datatables.bs.min.js"></script>
<?php } ?>
<script src="<?php echo BASE_URL; ?>tools/js/adminlte.min.js"></script>
<?php $twig->display('admin.menu-collapse.html.twig'); ?>
<?php $hooks->trigger(HOOK_ADMIN_BODY_END); ?>
</body>
</html>

View File

@@ -1,23 +0,0 @@
<?php
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php';
require SYSTEM . 'functions.php';
require SYSTEM . 'init.php';
require SYSTEM . 'login.php';
if(!admin()) {
http_response_code(500);
die('You are not logged in. Probably session expired. Please login again.');
}
if (!isset($_POST['collapse'])) {
http_response_code(500);
die('Something went wrong.');
}
csrfProtect();
setSession('admin.menu-collapse', $_POST['collapse'] == 'true');

View File

@@ -1,6 +1,5 @@
<?php
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
define('MYAAC_ADMIN', true);
require '../../common.php';
require SYSTEM . 'functions.php';

View File

@@ -26,7 +26,6 @@
use MyAAC\DataLoader;
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php';
require SYSTEM . 'functions.php';

View File

@@ -3,7 +3,6 @@
use MyAAC\Settings;
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
require '../../common.php';
require SYSTEM . 'functions.php';
@@ -12,7 +11,7 @@ require SYSTEM . 'login.php';
if(!admin()) {
http_response_code(500);
die('You are not logged in. Probably session expired. Please login again.');
die('Access denied.');
}
csrfProtect();
@@ -40,6 +39,3 @@ if (count($errors) > 0) {
if ($success) {
echo 'Saved at ' . date('H:i');
}
else {
echo 'Something unexpected happened - it was impossible to save the settings, please try again later. If problem persists - contact MyAAC developers.';
}

View File

@@ -1,6 +1,5 @@
<?php
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
define('MYAAC_ADMIN', true);
require '../../common.php';
require SYSTEM . 'init.php';

View File

@@ -1,6 +1,5 @@
<?php
const MYAAC_ADMIN = true;
const IGNORE_SET_LAST_VISIT = true;
define('MYAAC_ADMIN', true);
require '../../common.php';
require SYSTEM . 'functions.php';

View File

@@ -26,8 +26,8 @@
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true;
const MYAAC_VERSION = '2.0-dev';
const DATABASE_VERSION = 48;
const MYAAC_VERSION = '1.8.2-dev';
const DATABASE_VERSION = 46;
const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));
@@ -148,17 +148,16 @@ if(!IS_CLI) {
/** @var array $config */
ini_set('log_errors', 1);
if(isset($config['env']) && $config['env'] !== 'dev' && !defined('MYAAC_INSTALL')) {
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
}
else {
ini_set('html_errors', 0);
if(@$config['env'] === 'dev' || defined('MYAAC_INSTALL')) {
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
}
else {
ini_set('display_errors', 0);
ini_set('display_startup_errors', 0);
error_reporting(E_ALL & ~E_DEPRECATED & ~E_STRICT);
}
$autoloadFile = VENDOR . 'autoload.php';
if (!is_file($autoloadFile)) {

View File

@@ -19,7 +19,8 @@
"symfony/var-dumper": "^6.4",
"filp/whoops": "^2.15",
"maximebf/debugbar": "1.*",
"guzzlehttp/guzzle": "7.9.3"
"guzzlehttp/guzzle": "7.9.3",
"spomky-labs/otphp": "^11.3"
},
"require-dev": {
"phpstan/phpstan": "^1.10"

151
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5317e97a5025ebc2a977214bd3fa964c",
"content-hash": "07419f6fe133f9bebc99557f3df843c8",
"packages": [
{
"name": "brick/math",
@@ -1556,6 +1556,73 @@
},
"time": "2018-02-13T20:26:39+00:00"
},
{
"name": "paragonie/constant_time_encoding",
"version": "v3.0.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/constant_time_encoding.git",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/constant_time_encoding/zipball/df1e7fde177501eee2037dd159cf04f5f301a512",
"reference": "df1e7fde177501eee2037dd159cf04f5f301a512",
"shasum": ""
},
"require": {
"php": "^8"
},
"require-dev": {
"phpunit/phpunit": "^9",
"vimeo/psalm": "^4|^5"
},
"type": "library",
"autoload": {
"psr-4": {
"ParagonIE\\ConstantTime\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com",
"role": "Maintainer"
},
{
"name": "Steve 'Sc00bz' Thomas",
"email": "steve@tobtu.com",
"homepage": "https://www.tobtu.com",
"role": "Original Developer"
}
],
"description": "Constant-time Implementations of RFC 4648 Encoding (Base-64, Base-32, Base-16)",
"keywords": [
"base16",
"base32",
"base32_decode",
"base32_encode",
"base64",
"base64_decode",
"base64_encode",
"bin2hex",
"encoding",
"hex",
"hex2bin",
"rfc4648"
],
"support": {
"email": "info@paragonie.com",
"issues": "https://github.com/paragonie/constant_time_encoding/issues",
"source": "https://github.com/paragonie/constant_time_encoding"
},
"time": "2024-05-08T12:36:18+00:00"
},
{
"name": "peppeocchi/php-cron-scheduler",
"version": "v4.0",
@@ -2102,6 +2169,88 @@
},
"time": "2019-03-08T08:55:37+00:00"
},
{
"name": "spomky-labs/otphp",
"version": "11.3.0",
"source": {
"type": "git",
"url": "https://github.com/Spomky-Labs/otphp.git",
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Spomky-Labs/otphp/zipball/2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
"reference": "2d8ccb5fc992b9cc65ef321fa4f00fefdb3f4b33",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"paragonie/constant_time_encoding": "^2.0 || ^3.0",
"php": ">=8.1",
"psr/clock": "^1.0",
"symfony/deprecation-contracts": "^3.2"
},
"require-dev": {
"ekino/phpstan-banned-code": "^1.0",
"infection/infection": "^0.26|^0.27|^0.28|^0.29",
"php-parallel-lint/php-parallel-lint": "^1.3",
"phpstan/phpstan": "^1.0",
"phpstan/phpstan-deprecation-rules": "^1.0",
"phpstan/phpstan-phpunit": "^1.0",
"phpstan/phpstan-strict-rules": "^1.0",
"phpunit/phpunit": "^9.5.26|^10.0|^11.0",
"qossmic/deptrac-shim": "^1.0",
"rector/rector": "^1.0",
"symfony/phpunit-bridge": "^6.1|^7.0",
"symplify/easy-coding-standard": "^12.0"
},
"type": "library",
"autoload": {
"psr-4": {
"OTPHP\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Florent Morselli",
"homepage": "https://github.com/Spomky"
},
{
"name": "All contributors",
"homepage": "https://github.com/Spomky-Labs/otphp/contributors"
}
],
"description": "A PHP library for generating one time passwords according to RFC 4226 (HOTP Algorithm) and the RFC 6238 (TOTP Algorithm) and compatible with Google Authenticator",
"homepage": "https://github.com/Spomky-Labs/otphp",
"keywords": [
"FreeOTP",
"RFC 4226",
"RFC 6238",
"google authenticator",
"hotp",
"otp",
"totp"
],
"support": {
"issues": "https://github.com/Spomky-Labs/otphp/issues",
"source": "https://github.com/Spomky-Labs/otphp/tree/11.3.0"
},
"funding": [
{
"url": "https://github.com/Spomky",
"type": "github"
},
{
"url": "https://www.patreon.com/FlorentMorselli",
"type": "patreon"
}
],
"time": "2024-06-12T11:22:32+00:00"
},
{
"name": "symfony/console",
"version": "v6.4.17",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 718 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

BIN
images/news/delete.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1005 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

View File

@@ -1,69 +0,0 @@
<?php
defined('MYAAC') or die('Direct access not allowed!');
use MyAAC\Models\Changelog;
use MyAAC\Models\Config;
use MyAAC\Models\ForumBoard;
use MyAAC\Models\Gallery;
use MyAAC\Models\NewsCategory;
if (Changelog::count() === 0) {
Changelog::create([
'type' => 3,
'where' => 2,
'date' => time(),
'body' => 'MyAAC installed. (:',
'hide' => 0,
]);
}
if (Config::where('name', 'database_version')->count() === 0) {
Config::create([
'name' => 'database_version',
'value' => DATABASE_VERSION,
]);
}
if (ForumBoard::count() === 0) {
$forumBoards = [
['name' => 'News', 'description' => 'News commenting', 'closed' => 1],
['name' => 'Trade', 'description' => 'Trade offers.', 'closed' => 0],
['name' => 'Quests', 'description' => 'Quest making.', 'closed' => 0],
['name' => 'Pictures', 'description' => 'Your pictures.', 'closed' => 0],
['name' => 'Bug Report', 'description' => 'Report bugs there.', 'closed' => 0],
];
$i = 0;
foreach ($forumBoards as $forumBoard) {
ForumBoard::create([
'name' => $forumBoard['name'],
'description' => $forumBoard['description'],
'ordering' => $i++,
'closed' => $forumBoard['closed'],
]);
}
}
if (NewsCategory::count() === 0) {
$newsCategoriesIcons = [
0, 1, 2, 3, 4
];
foreach ($newsCategoriesIcons as $iconId) {
NewsCategory::create([
'icon_id' => $iconId,
]);
}
}
if (Gallery::count() === 0) {
Gallery::create([
'comment' => 'Demon',
'image' => 'images/gallery/demon.jpg',
'thumb' => 'images/gallery/demon_thumb.gif',
'author' => 'MyAAC',
'ordering' => 0,
]);
}
success($locale['step_database_success_import_data']);

View File

@@ -1,23 +1,25 @@
CREATE TABLE IF NOT EXISTS `myaac_account_actions`
SET @myaac_database_version = 45;
CREATE TABLE `myaac_account_actions`
(
`id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`ip` varchar(45) NOT NULL DEFAULT '',
`ip` int unsigned NOT NULL DEFAULT 0,
`ipv6` binary(16) NOT NULL DEFAULT 0,
`date` int NOT NULL DEFAULT 0,
`action` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
KEY (`account_id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_account_emails_verify`
CREATE TABLE `myaac_account_email_codes`
(
`id` int NOT NULL AUTO_INCREMENT,
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`hash` varchar(32) NOT NULL,
`sent_at` int NOT NULL DEFAULT 0,
`code` varchar(6) NOT NULL,
`created_at` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_admin_menu`
CREATE TABLE `myaac_admin_menu`
(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
@@ -28,7 +30,7 @@ CREATE TABLE IF NOT EXISTS `myaac_admin_menu`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_changelog`
CREATE TABLE `myaac_changelog`
(
`id` int NOT NULL AUTO_INCREMENT,
`body` varchar(500) NOT NULL DEFAULT '',
@@ -40,7 +42,9 @@ CREATE TABLE IF NOT EXISTS `myaac_changelog`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_config`
INSERT INTO `myaac_changelog` (`id`, `type`, `where`, `date`, `body`, `hide`) VALUES (1, 3, 2, UNIX_TIMESTAMP(), 'MyAAC installed. (:', 0);
CREATE TABLE `myaac_config`
(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
@@ -49,7 +53,9 @@ CREATE TABLE IF NOT EXISTS `myaac_config`
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_faq`
INSERT INTO `myaac_config` (`name`, `value`) VALUES ('database_version', @myaac_database_version);
CREATE TABLE `myaac_faq`
(
`id` int NOT NULL AUTO_INCREMENT,
`question` varchar(255) NOT NULL DEFAULT '',
@@ -59,7 +65,7 @@ CREATE TABLE IF NOT EXISTS `myaac_faq`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_forum_boards`
CREATE TABLE `myaac_forum_boards`
(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
@@ -71,8 +77,13 @@ CREATE TABLE IF NOT EXISTS `myaac_forum_boards`
`hide` tinyint NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`, `closed`) VALUES (NULL, 'News', 'News commenting', 0, 1);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Trade', 'Trade offers.', 1);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Quests', 'Quest making.', 2);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Pictures', 'Your pictures.', 3);
INSERT INTO `myaac_forum_boards` (`id`, `name`, `description`, `ordering`) VALUES (NULL, 'Bug Report', 'Report bugs there.', 4);
CREATE TABLE IF NOT EXISTS `myaac_forum`
CREATE TABLE `myaac_forum`
(
`id` int NOT NULL AUTO_INCREMENT,
`first_post` int NOT NULL DEFAULT 0,
@@ -96,13 +107,12 @@ CREATE TABLE IF NOT EXISTS `myaac_forum`
KEY `section` (`section`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_menu`
CREATE TABLE `myaac_menu`
(
`id` int NOT NULL AUTO_INCREMENT,
`template` varchar(255) NOT NULL,
`name` varchar(255) NOT NULL,
`link` varchar(255) NOT NULL,
`access` tinyint NOT NULL DEFAULT 0,
`blank` tinyint NOT NULL DEFAULT 0,
`color` varchar(6) NOT NULL DEFAULT '',
`category` int NOT NULL DEFAULT 1,
@@ -111,7 +121,7 @@ CREATE TABLE IF NOT EXISTS `myaac_menu`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_monsters` (
CREATE TABLE `myaac_monsters` (
`id` int NOT NULL AUTO_INCREMENT,
`hide` tinyint NOT NULL DEFAULT 0,
`name` varchar(255) NOT NULL,
@@ -144,7 +154,7 @@ CREATE TABLE IF NOT EXISTS `myaac_monsters` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_news`
CREATE TABLE `myaac_news`
(
`id` int NOT NULL AUTO_INCREMENT,
`title` varchar(100) NOT NULL,
@@ -162,7 +172,7 @@ CREATE TABLE IF NOT EXISTS `myaac_news`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_news_categories`
CREATE TABLE `myaac_news_categories`
(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(50) NOT NULL DEFAULT "",
@@ -172,7 +182,13 @@ CREATE TABLE IF NOT EXISTS `myaac_news_categories`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_notepad`
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 0);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 1);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 2);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 3);
INSERT INTO `myaac_news_categories` (`id`, `icon_id`) VALUES (NULL, 4);
CREATE TABLE `myaac_notepad`
(
`id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
@@ -182,7 +198,7 @@ CREATE TABLE IF NOT EXISTS `myaac_notepad`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_pages`
CREATE TABLE `myaac_pages`
(
`id` INT NOT NULL AUTO_INCREMENT,
`name` varchar(30) NOT NULL,
@@ -198,7 +214,7 @@ CREATE TABLE IF NOT EXISTS `myaac_pages`
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_gallery`
CREATE TABLE `myaac_gallery`
(
`id` int NOT NULL AUTO_INCREMENT,
`comment` varchar(255) NOT NULL DEFAULT '',
@@ -210,7 +226,9 @@ CREATE TABLE IF NOT EXISTS `myaac_gallery`
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_settings`
INSERT INTO `myaac_gallery` (`id`, `ordering`, `comment`, `image`, `thumb`, `author`) VALUES (NULL, 1, 'Demon', 'images/gallery/demon.jpg', 'images/gallery/demon_thumb.gif', 'MyAAC');
CREATE TABLE `myaac_settings`
(
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL DEFAULT '',
@@ -220,7 +238,7 @@ CREATE TABLE IF NOT EXISTS `myaac_settings`
KEY `key` (`key`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_spells`
CREATE TABLE `myaac_spells`
(
`id` int NOT NULL AUTO_INCREMENT,
`spell` varchar(255) NOT NULL DEFAULT '',
@@ -243,7 +261,7 @@ CREATE TABLE IF NOT EXISTS `myaac_spells`
UNIQUE (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_visitors`
CREATE TABLE `myaac_visitors`
(
`ip` varchar(45) NOT NULL,
`lastvisit` int NOT NULL DEFAULT 0,
@@ -252,7 +270,7 @@ CREATE TABLE IF NOT EXISTS `myaac_visitors`
UNIQUE (`ip`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;
CREATE TABLE IF NOT EXISTS `myaac_weapons`
CREATE TABLE `myaac_weapons`
(
`id` int NOT NULL,
`level` int NOT NULL DEFAULT 0,

View File

@@ -30,22 +30,26 @@ if(!$error) {
}
}
// import schema
try {
$locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']);
$db->exec(file_get_contents(BASE . 'install/includes/schema.sql'));
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
success($locale['step_database_success_schema']);
}
catch(PDOException $error_) {
error($locale['step_database_error_schema'] . ' ' . $error_);
return;
if($db->hasTable(TABLE_PREFIX . 'account_actions')) {
$locale['step_database_error_table_exist'] = str_replace('$TABLE$', TABLE_PREFIX . 'account_actions', $locale['step_database_error_table_exist']);
warning($locale['step_database_error_table_exist']);
}
else {
// import schema
try {
$locale['step_database_importing'] = str_replace('$DATABASE_NAME$', config('database_name'), $locale['step_database_importing']);
success($locale['step_database_importing']);
require BASE . 'install/includes/import_base_data.php';
$db->query(file_get_contents(BASE . 'install/includes/schema.sql'));
$locale['step_database_success_schema'] = str_replace('$PREFIX$', TABLE_PREFIX, $locale['step_database_success_schema']);
success($locale['step_database_success_schema']);
}
catch(PDOException $error_) {
error($locale['step_database_error_schema'] . ' ' . $error_);
return;
}
}
if(!$db->hasColumn('accounts', 'email')) {
if(query("ALTER TABLE `accounts` ADD `email` varchar(255) NOT NULL DEFAULT '';"))
@@ -98,13 +102,18 @@ if(!$db->hasColumn('accounts', 'web_flags')) {
success($locale['step_database_adding_field'] . ' accounts.web_flags...');
}
if(!$db->hasColumn('accounts', 'email_hash')) {
if(query("ALTER TABLE `accounts` ADD `email_hash` VARCHAR(32) NOT NULL DEFAULT '' AFTER `web_flags`;"))
success($locale['step_database_adding_field'] . ' accounts.email_hash...');
}
if(!$db->hasColumn('accounts', 'email_verified')) {
if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `web_flags`;"))
if(query("ALTER TABLE `accounts` ADD `email_verified` TINYINT(1) NOT NULL DEFAULT 0 AFTER `email_hash`;"))
success($locale['step_database_adding_field'] . ' accounts.email_verified...');
}
if(!$db->hasColumn('accounts', 'email_new')) {
if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_verified`;"))
if(query("ALTER TABLE `accounts` ADD `email_new` VARCHAR(255) NOT NULL DEFAULT '' AFTER `email_hash`;"))
success($locale['step_database_adding_field'] . ' accounts.email_new...');
}

View File

@@ -37,46 +37,8 @@ if ($db->hasTable('players')) {
$query = $db->query('SELECT `id` FROM `players` WHERE `name` = ' . $db->quote($p['name']));
if ($query->rowCount() == 0) {
$player = new OTS_Player();
$player->setData([
'name' => $p['name'],
'group_id' => 1,
'account_id' => getSession('account'),
'level' => $p['level'],
'vocation' => $p['vocation_id'],
'health' => $p['health'],
'healthmax' => $p['healthmax'],
'experience' => $p['experience'],
'lookbody' => 118,
'lookfeet' => 114,
'lookhead' => 38,
'looklegs' => 57,
'looktype' => $p['looktype'],
'maglevel' => 0,
'mana' => $p['mana'],
'manamax' => $p['manamax'],
'manaspent' => 0,
'soul' => $p['soul'],
'town_id' => 1,
'posx' => 1000,
'posy' => 1000,
'posz' => 7,
'conditions' => '',
'cap' => $p['cap'],
'sex' => 1,
'lastlogin' => $time,
'lastip' => 2130706433,
'save' => 1,
'lastlogout' => $time,
'balance' => 0,
$deleted => 0,
'created' => $time,
'hide' => 1,
'comment' => '',
]);
$player->save();
if (!query("INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `lastlogout`, `balance`, `$deleted`, `created`, `hide`, `comment`) VALUES (null, " . $db->quote($p['name']) . ", 1, " . getSession('account') . ", " . $p['level'] . ", " . $p['vocation_id'] . ", " . $p['health'] . ", " . $p['healthmax'] . ", " . $p['experience'] . ", 118, 114, 38, 57, " . $p['looktype'] . ", 0, " . $p['mana'] . ", " . $p['manamax'] . ", 0, " . $p['soul'] . ", 1, 1000, 1000, 7, '', " . $p['cap'] . ", 1, " . $time . ", 2130706433, 1, " . $time . ", 0, 0, " . $time . ", 1, '');"))
$success = false;
}
}

View File

@@ -220,8 +220,6 @@ switch ($action) {
}
}
/*
* not needed anymore?
if (fieldExist('premdays', 'accounts') && fieldExist('lastday', 'accounts')) {
$save = false;
$timeNow = time();
@@ -258,7 +256,6 @@ switch ($action) {
$account->save();
}
}
*/
$worlds = [$world];
$playdata = compact('worlds', 'characters');

View File

@@ -5,6 +5,8 @@ $deprecatedConfig = [
'genders',
'template',
'template_allow_change',
'vocations_amount',
'vocations',
'client',
'session_prefix',
'friendly_urls',
@@ -19,6 +21,7 @@ $deprecatedConfig = [
'visitors_counter_ttl',
'views_counter',
'outfit_images_url',
'outfit_images_wrong_looktypes',
'item_images_url',
'account_country',
'towns',
@@ -49,7 +52,6 @@ $deprecatedConfig = [
'online_skulls',
'online_outfit',
'online_afk',
'team_style',
'team_display_outfit' => 'team_outfit',
'team_display_status' => 'team_status',
'team_display_world' => 'team_world',
@@ -79,7 +81,6 @@ $deprecatedConfig = [
'account_change_character_name_points' => 'account_change_character_name_price',
'account_change_character_sex',
'account_change_character_sex_points' => 'account_change_character_name_price',
'email_lai_sec_interval' => 'mail_lost_account_interval',
];
foreach ($deprecatedConfig as $key => $value) {

View File

@@ -17,8 +17,6 @@ use MyAAC\Models\Guild;
use MyAAC\Models\House;
use MyAAC\Models\Pages;
use MyAAC\Models\Player;
use MyAAC\Models\PlayerDeath;
use MyAAC\Models\PlayerKillers;
use MyAAC\News;
use MyAAC\Plugins;
use MyAAC\Settings;
@@ -435,22 +433,16 @@ function delete_guild($id)
$rank_list->orderBy('level');
global $db;
$deletedColumn = 'deleted';
if ($db->hasColumn('players', 'deletion')) {
$deletedColumn = 'deletion';
}
/**
* @var OTS_GuildRank $rank_in_guild
*/
foreach($rank_list as $rank_in_guild) {
if($db->hasTable('guild_members'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` AND `' . $deletedColumn . '` = 0 ORDER BY `name`;');
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_members`.`rank_id` as `rank_id` FROM `players`, `guild_members` WHERE `guild_members`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_members`.`player_id` ORDER BY `name`;');
else if($db->hasTable('guild_membership'))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` AND `' . $deletedColumn . '` = 0 ORDER BY `name`;');
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `guild_membership`.`rank_id` as `rank_id` FROM `players`, `guild_membership` WHERE `guild_membership`.`rank_id` = ' . $rank_in_guild->getId() . ' AND `players`.`id` = `guild_membership`.`player_id` ORDER BY `name`;');
else
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank_in_guild->getId() . ' AND `' . $deletedColumn . '` = 0;');
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank_in_guild->getId() . ' AND `deleted` = 0;');
$players_with_rank_number = $players_with_rank->rowCount();
if($players_with_rank_number > 0) {
@@ -1137,44 +1129,11 @@ function csrfProtect(): void
}
}
function getSkillIdByName(string $name): int|null
{
$skills = [
'level' => POT::SKILL_LEVEL,
'experience' => POT::SKILL_LEVEL,
'magic' => POT::SKILL_MAGIC,
'maglevel' => POT::SKILL_MAGIC,
'balance' => SKILL_BALANCE,
'frags' => SKILL_FRAGS,
'club' => POT::SKILL_CLUB,
'sword' => POT::SKILL_SWORD,
'axe' => POT::SKILL_AXE,
'dist' => POT::SKILL_DIST,
'distance' => POT::SKILL_DIST,
'shield' => POT::SKILL_SHIELD,
'shielding' => POT::SKILL_SHIELD,
'fish' => POT::SKILL_FISH,
'fishing' => POT::SKILL_FISH,
];
return $skills[$name] ?? null;
}
function getTopPlayers($limit = 5, $skill = POT::SKILL_LEVEL)
{
function getTopPlayers($limit = 5, $skill = 'level') {
global $db;
$skillOriginal = $skill;
if (is_string($skill)) {
$skill = getSkillIdByName($skill);
}
if (!is_numeric($skill)) {
throw new RuntimeException("getTopPlayers: Invalid skill: $skillOriginal");
if ($skill === 'level') {
$skill = 'experience';
}
return Cache::remember("top_{$limit}_{$skill}", 2 * 60, function () use ($db, $limit, $skill) {
@@ -1183,76 +1142,19 @@ function getTopPlayers($limit = 5, $skill = POT::SKILL_LEVEL)
'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet'
];
if ($db->hasColumn('players', 'promotion')) {
$columns[] = 'promotion';
}
if ($db->hasColumn('players', 'lookaddons')) {
$columns[] = 'lookaddons';
}
if ($db->hasColumn('players', 'lookmount')) {
$columns[] = 'lookmount';
}
$query = Player::query()
return Player::query()
->select($columns)
->withOnlineStatus()
->notDeleted()
->where('group_id', '<', setting('core.highscores_groups_hidden'))
->whereNotIn('id', setting('core.highscores_ids_hidden'))
->where('account_id', '!=', 1)
->orderByDesc('value');
if ($limit > 0) {
$query->limit($limit);
}
if ($skill >= POT::SKILL_FIRST && $skill <= POT::SKILL_LAST) { // skills
if ($db->hasColumn('players', 'skill_fist')) {// tfs 1.0
$skill_ids = array(
POT::SKILL_FIST => 'skill_fist',
POT::SKILL_CLUB => 'skill_club',
POT::SKILL_SWORD => 'skill_sword',
POT::SKILL_AXE => 'skill_axe',
POT::SKILL_DIST => 'skill_dist',
POT::SKILL_SHIELD => 'skill_shielding',
POT::SKILL_FISH => 'skill_fishing',
);
$query
->addSelect($skill_ids[$skill] . ' as value')
->orderByDesc($skill_ids[$skill] . '_tries');
} else {
$query
->join('player_skills', 'player_skills.player_id', '=', 'players.id')
->where('skillid', $skill)
->addSelect('player_skills.value as value');
}
} else if ($skill == SKILL_FRAGS) // frags
{
if ($db->hasTable('player_killers')) {
$query->addSelect(['value' => PlayerKillers::whereColumn('player_killers.player_id', 'players.id')->selectRaw('COUNT(*)')]);
} else {
$query->addSelect(['value' => PlayerDeath::unjustified()->whereColumn('player_deaths.killed_by', 'players.name')->selectRaw('COUNT(*)')]);
}
} else if ($skill == SKILL_BALANCE) // balance
{
$query
->addSelect('players.balance as value');
} else {
if ($skill == POT::SKILL_MAGIC) {
$query
->addSelect('players.maglevel as value', 'players.maglevel')
->orderByDesc('manaspent');
} else { // level
$query
->addSelect('players.level as value', 'players.experience')
->orderByDesc('experience');
}
}
return $query
->orderByDesc($skill)
->limit($limit)
->get()
->map(function ($e, $i) {
$row = $e->toArray();
@@ -1267,8 +1169,7 @@ function getTopPlayers($limit = 5, $skill = POT::SKILL_LEVEL)
});
}
function deleteDirectory($dir, $ignore = array(), $contentOnly = false): bool
{
function deleteDirectory($dir, $ignore = array(), $contentOnly = false) {
if(!file_exists($dir)) {
return true;
}
@@ -1294,21 +1195,6 @@ function deleteDirectory($dir, $ignore = array(), $contentOnly = false): bool
return rmdir($dir);
}
function ensureFolderExists($dir): void
{
if (!file_exists($dir)) {
mkdir($dir, 0777, true);
}
}
function ensureIndexExists($dir): void
{
$dir = rtrim($dir, '/');
if (!file_exists($file = $dir . '/index.html')) {
touch($file);
}
}
function config($key) {
global $config;
if (is_array($key)) {
@@ -1746,14 +1632,13 @@ function camelCaseToUnderscore($input)
return ltrim(strtolower(preg_replace('/[A-Z]([A-Z](?![a-z]))*/', '_$0', $input)), '_');
}
function removeIfFirstSlash(&$text): void
{
function removeIfFirstSlash(&$text) {
if(strpos($text, '/') === 0) {
$text = str_replace_first('/', '', $text);
}
};
function escapeHtml($html): string {
function escapeHtml($html) {
return htmlspecialchars($html);
}
@@ -1767,7 +1652,7 @@ function getGuildNameById($id)
return false;
}
function getGuildLogoById($id): string
function getGuildLogoById($id)
{
$logo = 'default.gif';
@@ -1783,8 +1668,7 @@ function getGuildLogoById($id): string
return BASE_URL . GUILD_IMAGES_DIR . $logo;
}
function displayErrorBoxWithBackButton($errors, $action = null): void
{
function displayErrorBoxWithBackButton($errors, $action = null) {
global $twig;
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [
@@ -1812,49 +1696,6 @@ function getAccountIdentityColumn(): string
return 'id';
}
function isCanary(): bool
{
$vipSystemEnabled = configLua('vipSystemEnabled');
return isset($vipSystemEnabled);
}
function getStatusUptimeReadable(int $uptime): string
{
$fullMinute = 60;
$fullHour = (60 * $fullMinute);
$fullDay = (24 * $fullHour);
$fullMonth = (30 * $fullDay);
$fullYear = (365 * $fullDay);
// years
$years = floor($uptime / $fullYear);
$y = ($years > 1 ? "$years years, " : ($years == 1 ? 'year, ' : ''));
$uptime -= $years * $fullYear;
// months
$months = floor($uptime / $fullMonth);
$m = ($months > 1 ? "$months months, " : ($months == 1 ? 'month, ' : ''));
$uptime -= $months * $fullMonth;
// days
$days = floor($uptime / $fullDay);
$d = ($days > 1 ? "$days days, " : ($days == 1 ? 'day, ' : ''));
$uptime -= $days * $fullDay;
// hours
$hours = floor($uptime / $fullHour);
$uptime -= $hours * $fullHour;
// minutes
$min = floor($uptime / $fullMinute);
return "{$y}{$m}{$d}{$hours}h {$min}m";
}
// validator functions
require_once SYSTEM . 'compat/base.php';

View File

@@ -14,14 +14,10 @@ use MyAAC\CsrfToken;
use MyAAC\Hooks;
use MyAAC\Plugins;
use MyAAC\Models\Town;
use MyAAC\Server\XML\Vocations;
use MyAAC\Settings;
defined('MYAAC') or die('Direct access not allowed!');
ensureIndexExists(CACHE);
ensureIndexExists(CACHE . 'twig/');
global $config;
if(!isset($config['installed']) || !$config['installed']) {
throw new RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
@@ -215,5 +211,3 @@ if (count($towns) <= 0) {
config(['towns', $towns]);
unset($towns);
new Vocations();

File diff suppressed because it is too large Load Diff

View File

@@ -26,12 +26,10 @@ use MyAAC\Cache\Cache;
*/
class OTS_DB_MySQL extends OTS_Base_DB
{
private bool $hasCacheChanged = false;
private array $has_table_cache = [];
private array $has_column_cache = [];
private array $get_column_info_cache = [];
private $has_table_cache = array();
private $has_column_cache = array();
private bool $clearCacheAfter = false;
private $clearCacheAfter = false;
/**
* Creates database connection.
*
@@ -121,11 +119,6 @@ class OTS_DB_MySQL extends OTS_Base_DB
if($cache->fetch('database_columns', $tmp) && $tmp) {
$this->has_column_cache = unserialize($tmp);
}
$tmp = null;
if($cache->fetch('database_columns_info', $tmp) && $tmp) {
$this->get_column_info_cache = unserialize($tmp);
}
}
}
@@ -162,13 +155,11 @@ class OTS_DB_MySQL extends OTS_Base_DB
if ($this->clearCacheAfter) {
$cache->delete('database_tables');
$cache->delete('database_columns');
$cache->delete('database_columns_info');
$cache->delete('database_checksum');
}
else if ($this->hasCacheChanged) {
else {
$cache->set('database_tables', serialize($this->has_table_cache), 3600);
$cache->set('database_columns', serialize($this->has_column_cache), 3600);
$cache->set('database_columns_info', serialize($this->get_column_info_cache), 3600);
$cache->set('database_checksum', serialize(sha1($config['database_host'] . '.' . $config['database_name'])), 3600);
}
}
@@ -218,8 +209,7 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $sql;
}
public function hasTable($name): bool
{
public function hasTable($name) {
if(isset($this->has_table_cache[$name])) {
return $this->has_table_cache[$name];
}
@@ -227,15 +217,12 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasTableInternal($name);
}
private function hasTableInternal($name): bool
{
$this->hasCacheChanged = true;
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote(config('database_name')) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
private function hasTableInternal($name) {
global $config;
return ($this->has_table_cache[$name] = $this->query('SELECT `TABLE_NAME` FROM `information_schema`.`tables` WHERE `TABLE_SCHEMA` = ' . $this->quote($config['database_name']) . ' AND `TABLE_NAME` = ' . $this->quote($name) . ' LIMIT 1;')->rowCount() > 0);
}
public function hasColumn($table, $column): bool
{
public function hasColumn($table, $column) {
if(isset($this->has_column_cache[$table . '.' . $column])) {
return $this->has_column_cache[$table . '.' . $column];
}
@@ -243,10 +230,8 @@ class OTS_DB_MySQL extends OTS_Base_DB
return $this->hasColumnInternal($table, $column);
}
private function hasColumnInternal($table, $column): bool {
$this->hasCacheChanged = true;
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column))->fetchAll()) > 0);
private function hasColumnInternal($table, $column) {
return $this->hasTable($table) && ($this->has_column_cache[$table . '.' . $column] = count($this->query('SHOW COLUMNS FROM `' . $table . "` LIKE '" . $column . "'")->fetchAll()) > 0);
}
public function hasTableAndColumns(string $table, array $columns = []): bool
@@ -262,56 +247,7 @@ class OTS_DB_MySQL extends OTS_Base_DB
return true;
}
public function getColumnInfo(string $table, string $column): bool|array
{
if(isset($this->get_column_info_cache[$table . '.' . $column])) {
return $this->get_column_info_cache[$table . '.' . $column];
}
return $this->getColumnInfoInternal($table, $column);
}
private function getColumnInfoInternal(string $table, string $column): bool|array
{
if (!$this->hasTable($table) || !$this->hasColumn($table, $column)) {
return false;
}
$this->hasCacheChanged = true;
$formatResult = function ($result) {
return [
'field' => $result['Field'],
'type' => $result['Type'],
'null' => strtolower($result['Null']),
'key' => strtolower($result['Key'] ?? ''),
'default' => $result['Default'],
'extra' => $result['Extra'],
];
};
$query = $this->query('SHOW COLUMNS FROM `' . $table . "` LIKE " . $this->quote($column));
$rowCount = $query->rowCount();
if ($rowCount > 1) {
$tmp = [];
$results = $query->fetchAll(PDO::FETCH_ASSOC);
foreach ($results as $result) {
$tmp[] = $formatResult($result);
}
return ($this->get_column_info_cache[$table . '.' . $column] = $tmp);
}
else if ($rowCount == 1) {
$result = $query->fetch(PDO::FETCH_ASSOC);
return ($this->get_column_info_cache[$table . '.' . $column] = $formatResult($result));
}
return [];
}
public function revalidateCache(): void
{
public function revalidateCache() {
foreach($this->has_table_cache as $key => $value) {
$this->hasTableInternal($key);
}
@@ -326,21 +262,6 @@ class OTS_DB_MySQL extends OTS_Base_DB
$this->hasColumnInternal($explode[0], $explode[1]);
}
}
foreach($this->get_column_info_cache as $key => $value) {
$explode = explode('.', $key);
if(!isset($this->has_table_cache[$explode[0]])) { // first check if table exist
$this->hasTableInternal($explode[0]);
}
if($this->has_table_cache[$explode[0]]) {
$this->hasColumnInternal($explode[0], $explode[1]);
}
if($this->has_table_cache[$explode[0]]) {
$this->getColumnInfoInternal($explode[0], $explode[1]);
}
}
}
public function setClearCacheAfter($clearCache)

View File

@@ -1,6 +1,20 @@
<?php
use MyAAC\Models\Player as PlayerModel;
$__load = array();
/*
'loss_experience' => NULL,
'loss_items' => NULL,
'guild_info' => NULL,
'skull_type' => NULL,
'skull_time' => NULL,
'blessings' => NULL,
'direction' => NULL,
'stamina' => NULL,
'world_id' => NULL,
'online' => NULL,
'deletion' => NULL,
'promotion' => NULL,
'marriage' => NULL
);*/
/**#@+
* @version 0.0.1
@@ -95,10 +109,6 @@ class OTS_Player extends OTS_Row_DAO
POT::SKILL_FISH => array('value' => 0, 'tries' => 0)
);
private array $columns = ['name', 'account_id', 'group_id', 'sex', 'vocation', 'experience', 'level', 'maglevel', 'health', 'healthmax', 'mana', 'manamax', 'manaspent', 'soul', 'lookbody', 'lookfeet', 'lookhead', 'looklegs', 'looktype', 'posx', 'posy', 'posz', 'lastlogin', 'lastlogout', 'lastip', 'town_id', 'balance', 'created', 'comment', 'hide'];
private array $optionalColumns = ['cap', 'skull', 'skull_type', 'skull_time', 'loss_experience', 'loss_mana', 'loss_skills', 'loss_items', 'loss_containers', 'guildnick', 'rank_id', 'promotion', 'direction', 'blessings', 'stamina', 'lookaddons', 'save', 'conditions', 'world_id', 'online', 'deletion', 'deleted', 'marriage'];
private static array $playersOnline;
/**
* Magic PHP5 method.
@@ -123,14 +133,90 @@ class OTS_Player extends OTS_Row_DAO
*/
public function load($id, $fields = null, $load_skills = true)
{
$columns = $this->columns;
foreach ($this->optionalColumns as $column) {
if ($this->db->hasColumn('players', $column)) {
$columns[] = $column;
global $__load;
if(!isset($__load['loss_experience']))
{
$loss = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience`, `loss_mana`, `loss_skills`';
}
$__load['loss_experience'] = $loss;
}
if(!isset($__load['loss_items']))
{
$loss_items = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items`, `loss_containers`';
}
$__load['loss_items'] = $loss_items;
}
if(!isset($__load['guild_info']))
{
$guild_info = '';
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick`, `rank_id`';
}
$__load['guild_info'] = $guild_info;
}
if(!isset($__load['skull_type']))
{
$skull_type = 'skull';
if($this->db->hasColumn('players', 'skull_type')) {
$skull_type = 'skull_type';
}
$__load['skull_type'] = $skull_type;
}
if(!isset($__load['skull_time']))
{
$skull_time = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$skull_time = 'skull_time';
}
$__load['skull_time'] = $skull_time;
}
if(!isset($__load['blessings'])) {
$__load['blessings'] = $this->db->hasColumn('players', 'blessings');
}
if(!isset($__load['direction'])) {
$__load['direction'] = $this->db->hasColumn('players', 'direction');
}
if(!isset($__load['stamina'])) {
$__load['stamina'] = $this->db->hasColumn('players', 'stamina');
}
if(!isset($__load['world_id'])) {
$__load['world_id'] = $this->db->hasColumn('players', 'world_id');
}
if(!isset($__load['online'])) {
$__load['online'] = $this->db->hasColumn('players', 'online');
}
if(!isset($__load['deletion'])) {
$__load['deletion'] = $this->db->hasColumn('players', 'deletion');
}
if(!isset($__load['promotion'])) {
$__load['promotion'] = $this->db->hasColumn('players', 'promotion');
}
if(!isset($__load['marriage'])) {
$__load['marriage'] = $this->db->hasColumn('players', 'marriage');
}
if(isset($fields)) { // load only what we wish
if(in_array('promotion', $fields)) {
if(!$this->db->hasColumn('players', 'promotion')) {
unset($fields[array_search('promotion', $fields)]);
}
}
if(in_array('deleted', $fields)) {
if($this->db->hasColumn('players', 'deletion')) {
unset($fields[array_search('deleted', $fields)]);
@@ -138,21 +224,21 @@ class OTS_Player extends OTS_Row_DAO
}
}
$columns = [];
foreach ($fields as $field) {
if ($this->db->hasColumn('players', $field)) {
$columns[] = $field;
if(in_array('online', $fields)) {
if(!$this->db->hasColumn('players', 'online')) {
unset($fields[array_search('online', $fields)]);
}
}
$this->data = $this->db->query('SELECT ' . implode(', ', $fields) . ' FROM `players` WHERE `id` = ' . (int)$id)->fetch();
}
else {
// SELECT query on database
$this->data = $this->db->query('SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`' . ($this->db->hasColumn('players', 'lookaddons') ? ', `lookaddons`' : '') . ', `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `save`, `conditions`, `' . $__load['skull_time'] . '` as `skulltime`, `' . $__load['skull_type'] . '` as `skull`' . $__load['guild_info'] . ', `town_id`' . $__load['loss_experience'] . $__load['loss_items'] . ', `balance`' . ($__load['blessings'] ? ', `blessings`' : '') . ($__load['direction'] ? ', `direction`' : '') . ($__load['stamina'] ? ', `stamina`' : '') . ($__load['world_id'] ? ', `world_id`' : '') . ($__load['online'] ? ', `online`' : '') . ', `' . ($__load['deletion'] ? 'deletion' : 'deleted') . '`' . ($__load['promotion'] ? ', `promotion`' : '') . ($__load['marriage'] ? ', `marriage`' : '') . ', `comment`, `created`, `hide` FROM `players` WHERE `id` = ' . (int)$id)->fetch();
}
array_unshift($columns, 'id');
$query = PlayerModel::where('id', $id)->first($columns);
$this->data = $query ? $query->toArray() : [];
// loads skills
if( $this->isLoaded() && $load_skills) {
if( $this->isLoaded() && $load_skills)
{
if($this->db->hasColumn('players', 'skill_fist')) {
$skill_ids = array(
@@ -232,57 +318,153 @@ class OTS_Player extends OTS_Row_DAO
*/
public function save()
{
$defaultValues = [
'loss_experience' => 100,
'loss_mana' => 100,
'loss_skills' => 100,
'loss_items' => 100,
'loss_containers' => 100,
'guildnick' => '',
'rank_id' => 0,
'promotion' => 0,
'direction' => 0,
'blessings' => 0,
'conditions' => '',
'town_id' => 1,
'deletion' => 0,
'deleted' => 0,
'stamina' => 0,
'marriage' => 0,
];
foreach ($defaultValues as $key => $value) {
if (!isset($this->data[$key])) {
$this->data[$key] = $value;
}
$skull_type = 'skull';
if($this->db->hasColumn('players', 'skull_type')) {
$skull_type = 'skull_type';
}
$columns = $this->columns;
foreach ($this->optionalColumns as $column) {
if ($this->db->hasColumn('players', $column)) {
$columns[] = $column;
}
$skull_time = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$skull_time = 'skull_time';
}
$values = [];
foreach ($columns as $column) {
$value = $this->data[$column];
if(!isset($this->data['loss_experience']))
$this->data['loss_experience'] = 100;
$values[$column] = $value;
}
if(!isset($this->data['loss_mana']))
$this->data['loss_mana'] = 100;
if(!isset($this->data['loss_skills']))
$this->data['loss_skills'] = 100;
if(!isset($this->data['loss_items']))
$this->data['loss_items'] = 10;
if(!isset($this->data['loss_containers']))
$this->data['loss_containers'] = 100;
if(!isset($this->data['guildnick']))
$this->data['guildnick'] = '';
if(!isset($this->data['rank_id']))
$this->data['rank_id'] = 0;
if(!isset($this->data['promotion']))
$this->data['promotion'] = 0;
if(!isset($this->data['direction']))
$this->data['direction'] = 0;
if(!isset($this->data['conditions']))
$this->data['conditions'] = '';
if(!isset($this->data['town_id']))
$this->data['town_id'] = 1;
// updates existing player
if( isset($this->data['id']) ) {
PlayerModel::where('id', $this->data['id'])->update($values);
if( isset($this->data['id']) )
{
$loss = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience` = ' . $this->data['loss_experience'] . ', `loss_mana` = ' . $this->data['loss_mana'] . ', `loss_skills` = ' . $this->data['loss_skills'];
}
$loss_items = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items` = ' . $this->data['loss_items'] . ', `loss_containers` = ' . $this->data['loss_containers'];
}
$guild_info = '';
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick` = ' . $this->db->quote($this->data['guildnick']) . ', ' . $this->db->fieldName('rank_id') . ' = ' . $this->data['rank_id'];
}
$direction = '';
if($this->db->hasColumn('players', 'direction')) {
$direction = ', `direction` = ' . $this->db->quote($this->data['direction']);
}
$blessings = '';
if($this->db->hasColumn('players', 'blessings')) {
$blessings = ', `blessings` = ' . $this->db->quote($this->data['blessings']);
}
$stamina = '';
if($this->db->hasColumn('players', 'stamina')) {
$stamina = ', `stamina` = ' . $this->db->quote($this->data['stamina']);
}
$lookaddons = '';
if($this->db->hasColumn('players', 'lookaddons')) {
$lookaddons = ', `lookaddons` = ' . $this->db->quote($this->data['lookaddons']);
}
// UPDATE query on database
$this->db->query('UPDATE ' . $this->db->tableName('players') . ' SET ' . $this->db->fieldName('name') . ' = ' . $this->db->quote($this->data['name']) . ', ' . $this->db->fieldName('account_id') . ' = ' . $this->data['account_id'] . ', ' . $this->db->fieldName('group_id') . ' = ' . $this->data['group_id'] . ', ' . $this->db->fieldName('sex') . ' = ' . $this->data['sex'] . ', ' . $this->db->fieldName('vocation') . ' = ' . $this->data['vocation'] . ', ' . $this->db->fieldName('experience') . ' = ' . $this->data['experience'] . ', ' . $this->db->fieldName('level') . ' = ' . $this->data['level'] . ', ' . $this->db->fieldName('maglevel') . ' = ' . $this->data['maglevel'] . ', ' . $this->db->fieldName('health') . ' = ' . $this->data['health'] . ', ' . $this->db->fieldName('healthmax') . ' = ' . $this->data['healthmax'] . ', ' . $this->db->fieldName('mana') . ' = ' . $this->data['mana'] . ', ' . $this->db->fieldName('manamax') . ' = ' . $this->data['manamax'] . ', ' . $this->db->fieldName('manaspent') . ' = ' . $this->data['manaspent'] . ', ' . $this->db->fieldName('soul') . ' = ' . $this->data['soul'] . ', ' . $this->db->fieldName('lookbody') . ' = ' . $this->data['lookbody'] . ', ' . $this->db->fieldName('lookfeet') . ' = ' . $this->data['lookfeet'] . ', ' . $this->db->fieldName('lookhead') . ' = ' . $this->data['lookhead'] . ', ' . $this->db->fieldName('looklegs') . ' = ' . $this->data['looklegs'] . ', ' . $this->db->fieldName('looktype') . ' = ' . $this->data['looktype'] . $lookaddons . ', ' . $this->db->fieldName('posx') . ' = ' . $this->data['posx'] . ', ' . $this->db->fieldName('posy') . ' = ' . $this->data['posy'] . ', ' . $this->db->fieldName('posz') . ' = ' . $this->data['posz'] . ', ' . $this->db->fieldName('cap') . ' = ' . $this->data['cap'] . ', ' . $this->db->fieldName('lastlogin') . ' = ' . $this->data['lastlogin'] . ', ' . $this->db->fieldName('lastlogout') . ' = ' . $this->data['lastlogout'] . ', ' . $this->db->fieldName('lastip') . ' = ' . $this->db->quote($this->data['lastip']) . ', ' . $this->db->fieldName('save') . ' = ' . (int) $this->data['save'] . ', ' . $this->db->fieldName('conditions') . ' = ' . $this->db->quote($this->data['conditions']) . ', `' . $skull_time . '` = ' . $this->data['skulltime'] . ', `' . $skull_type . '` = ' . (int) $this->data['skull'] . $guild_info . ', ' . $this->db->fieldName('town_id') . ' = ' . $this->data['town_id'] . $loss . $loss_items . ', ' . $this->db->fieldName('balance') . ' = ' . $this->data['balance'] . $blessings . $stamina . $direction . ' WHERE ' . $this->db->fieldName('id') . ' = ' . $this->data['id']);
}
// creates new player
else {
$values['created'] = time();
else
{
$loss = '';
$loss_data = '';
if($this->db->hasColumn('players', 'loss_experience')) {
$loss = ', `loss_experience`, `loss_mana`, `loss_skills`';
$loss_data = ', ' . $this->data['loss_experience'] . ', ' . $this->data['loss_mana'] . ', ' . $this->data['loss_skills'];
}
$player = PlayerModel::create($values);
$loss_items = '';
$loss_items_data = '';
if($this->db->hasColumn('players', 'loss_items')) {
$loss_items = ', `loss_items`, `loss_containers`';
$loss_items_data = ', ' . $this->data['loss_items'] . ', ' . $this->data['loss_containers'];
}
$guild_info = '';
$guild_info_data = '';
if(!$this->db->hasTable('guild_members') && $this->db->hasColumn('players', 'guildnick')) {
$guild_info = ', `guildnick`, `rank_id`';
$guild_info_data = ', ' . $this->db->quote($this->data['guildnick']) . ', ' . $this->data['rank_id'];
}
$promotion = '';
$promotion_data = '';
if($this->db->hasColumn('players', 'promotion')) {
$promotion = ', `promotion`';
$promotion_data = ', ' . $this->data['promotion'];
}
$direction = '';
$direction_data = '';
if($this->db->hasColumn('players', 'direction')) {
$direction = ', `direction`';
$direction_data = ', ' . $this->data['direction'];
}
$blessings = '';
$blessings_data = '';
if($this->db->hasColumn('players', 'blessings')) {
$blessings = ', `blessings`';
$blessings_data = ', ' . $this->data['blessings'];
}
$stamina = '';
$stamina_data = '';
if($this->db->hasColumn('players', 'stamina')) {
$stamina = ', `stamina`';
$stamina_data = ', ' . $this->data['stamina'];
}
$lookaddons = '';
$lookaddons_data = '';
if($this->db->hasColumn('players', 'lookaddons')) {
$lookaddons = ', `lookaddons`';
$lookaddons_data = ', ' . $this->data['lookaddons'];
}
// INSERT query on database
$this->db->query('INSERT INTO `players` (`name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`' . $lookaddons . ', `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `save`, `conditions`, `' . $skull_time . '`, `' . $skull_type . '`' . $guild_info . ', `town_id`' . $loss . $loss_items . ', `balance`' . $blessings . $stamina . $direction . ', `created`' . $promotion . ', `comment`) VALUES (' . $this->db->quote($this->data['name']) . ', ' . $this->data['account_id'] . ', ' . $this->data['group_id'] . ', ' . $this->data['sex'] . ', ' . $this->data['vocation'] . ', ' . $this->data['experience'] . ', ' . $this->data['level'] . ', ' . $this->data['maglevel'] . ', ' . $this->data['health'] . ', ' . $this->data['healthmax'] . ', ' . $this->data['mana'] . ', ' . $this->data['manamax'] . ', ' . $this->data['manaspent'] . ', ' . $this->data['soul'] . ', ' . $this->data['lookbody'] . ', ' . $this->data['lookfeet'] . ', ' . $this->data['lookhead'] . ', ' . $this->data['looklegs'] . ', ' . $this->data['looktype'] . $lookaddons_data . ', ' . $this->data['posx'] . ', ' . $this->data['posy'] . ', ' . $this->data['posz'] . ', ' . $this->data['cap'] . ', ' . $this->data['lastlogin'] . ', ' . $this->data['lastlogout'] . ', ' . $this->data['lastip'] . ', ' . (int) $this->data['save'] . ', ' . $this->db->quote($this->data['conditions']) . ', ' . $this->data['skulltime'] . ', ' . (int) $this->data['skull'] . $guild_info_data . ', ' . $this->data['town_id'] . $loss_data . $loss_items_data . ', ' . $this->data['balance'] . $blessings_data . $stamina_data . $direction_data . ', ' . time() . $promotion_data . ', "")');
// ID of new group
$this->data['id'] = $player->id;
$this->data['id'] = $this->db->lastInsertId();
}
// updates skills - doesn't matter if we have just created character - trigger inserts new skills
@@ -308,7 +490,7 @@ class OTS_Player extends OTS_Row_DAO
$set .= ',';
}
$this->db->query('UPDATE `players` SET ' . $set . ' WHERE `id` = ' . $this->data['id']);
$skills = $this->db->query('UPDATE `players` SET ' . $set . ' WHERE `id` = ' . $this->data['id']);
}
else if($this->db->hasTable('player_skills')) {
foreach($this->skills as $id => $skill)
@@ -566,25 +748,21 @@ class OTS_Player extends OTS_Row_DAO
public function isDeleted()
{
$column = 'deleted';
$field = 'deleted';
if($this->db->hasColumn('players', 'deletion'))
$column = 'deletion';
$field = 'deletion';
if( !isset($this->data[$column]) )
if( !isset($this->data[$field]) )
{
throw new E_OTS_NotLoaded();
}
return $this->data[$column] > 0;
return $this->data[$field] > 0;
}
public function setDeleted($deleted)
{
$column = 'deleted';
if($this->db->hasColumn('players', 'deletion'))
$column = 'deletion';
$this->data[$column] = (int) $deleted;
$this->data['deleted'] = (int) $deleted;
}
public function isOnline()
@@ -674,7 +852,13 @@ class OTS_Player extends OTS_Row_DAO
throw new E_OTS_NotLoaded();
}
return \OTS_Toolbox::getVocationFromPromotion($this->data['vocation'], $this->data['promotion'] ?? 0);
if(isset($this->data['promotion'])) {
global $config;
if((int)$this->data['promotion'] > 0)
return ($this->data['vocation'] + ($this->data['promotion'] * $config['vocations_amount']));
}
return $this->data['vocation'];
}
@@ -1390,7 +1574,12 @@ class OTS_Player extends OTS_Row_DAO
*/
public function getCap()
{
return $this->data['cap'] ?? 0;
if( !isset($this->data['cap']) )
{
throw new E_OTS_NotLoaded();
}
return $this->data['cap'];
}
/**
@@ -1603,12 +1792,12 @@ class OTS_Player extends OTS_Row_DAO
*/
public function getSkullTime()
{
$column = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$column = 'skull_time';
if( !isset($this->data['skulltime']) )
{
throw new E_OTS_NotLoaded();
}
return $this->data[$column] ?? 0;
return $this->data['skulltime'];
}
/**
@@ -1622,12 +1811,7 @@ class OTS_Player extends OTS_Row_DAO
*/
public function setSkullTime($skulltime)
{
$column = 'skulltime';
if($this->db->hasColumn('players', 'skull_time')) {
$column = 'skull_time';
}
$this->data[$column] = (int) $skulltime;
$this->data['skulltime'] = (int) $skulltime;
}
/**
@@ -3066,10 +3250,6 @@ class OTS_Player extends OTS_Row_DAO
return 0;
}
public function setData(array $data): void{
$this->data = $data;
}
/**
* Magic PHP5 method.
*

View File

@@ -97,8 +97,6 @@ class OTS_ServerInfo
return new OTS_Buffer($data);
}
log_append('status-error.log', "Cannot connect to {$this->server}:{$this->port} - Error code: $error, message: $message");
return false;
}

View File

@@ -13,8 +13,6 @@
* @license http://www.gnu.org/licenses/lgpl-3.0.txt GNU Lesser General Public License, Version 3
*/
use MyAAC\Server\XML\Vocations;
/**
* Toolbox for common operations.
*
@@ -112,21 +110,14 @@ class OTS_Toolbox
$list->setFilter($filter);
return $list;
}
public static function getVocationFromPromotion($id, $promotion = 0): int
public static function getVocationName($id, $promotion = 0): string
{
if($promotion > 0) {
for ($i = 0; $i < $promotion; $i++) {
if ($_id = Vocations::getPromoted($id)) {
$id = $_id;
}
}
$id = ($id + ($promotion * config('vocations_amount')));
}
return $id;
}
public static function getVocationName($id, $promotion = 0): string {
return config('vocations')[self::getVocationFromPromotion($id, $promotion)] ?? 'Unknown';
return config('vocations')[$id] ?? 'Unknown';
}
}

View File

@@ -78,7 +78,6 @@ $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: ';

View File

@@ -83,7 +83,6 @@ $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';

View File

@@ -81,8 +81,7 @@ $locale['step_database_error_mysql_connect_2'] = 'Możliwe przyczyny:';
$locale['step_database_error_mysql_connect_3'] = 'MySQL nie jest poprawnie skonfigurowane w <i>config.lua</i>.';
$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 zaimportowano tabele $PREFIX$.';
$locale['step_database_success_import_data'] = 'Pomyślnie załadowano bazowe dane dla tabel.';
$locale['step_database_success_schema'] = 'Pomyślnie zainstalowano tabele $PREFIX$.';
$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';

View File

@@ -34,10 +34,8 @@ if($logged) {
$twig->addGlobal('account_logged', $account_logged);
}
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_visit', time());
if(defined('PAGE')) {
setSession('last_page', PAGE);
}
setSession('last_uri', $_SERVER['REQUEST_URI']);

View File

@@ -9,8 +9,6 @@
*/
defined('MYAAC') or die('Direct access not allowed!');
global $db;
// database migrations
$tmp = '';
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version

View File

@@ -0,0 +1,8 @@
CREATE TABLE `myaac_account_email_codes`
(
`id` int(11) NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`code` varchar(6) NOT NULL,
`created_at` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;

View File

@@ -1,8 +0,0 @@
CREATE TABLE `myaac_account_emails_verify`
(
`id` int NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`hash` varchar(32) NOT NULL,
`sent_at` int NOT NULL DEFAULT 0,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8mb4;

View File

@@ -1,24 +1,27 @@
<?php
// add the myaac_account_email_codes
/**
* @var OTS_DB_MySQL $db
*/
$up = function () use ($db) {
if ($db->hasColumn('accounts', 'email_hash')) {
$db->dropColumn('accounts', 'email_hash');
if (!$db->hasColumn('accounts', '2fa_type')) {
$db->addColumn('accounts', '2fa_type', "tinyint NOT NULL DEFAULT 0 AFTER `web_flags`");
}
if (!$db->hasTable(TABLE_PREFIX . 'account_emails_verify')) {
$db->query(file_get_contents(__DIR__ . '/46-account_emails_verify.sql'));
// add myaac_account_email_codes table
if (!$db->hasTable(TABLE_PREFIX . 'account_email_codes')) {
$db->exec(file_get_contents(__DIR__ . '/46-account_email_codes.sql'));
}
};
$down = function () use ($db) {
if (!$db->hasColumn('accounts', 'email_hash')) {
$db->addColumn('accounts', 'email_hash', "varchar(32) NOT NULL DEFAULT ''");
if ($db->hasColumn('accounts', '2fa_type')) {
$db->dropColumn('accounts', '2fa_type');
}
if ($db->hasTable(TABLE_PREFIX . 'account_emails_verify')) {
$db->dropTable(TABLE_PREFIX . 'account_emails_verify');
}
//if ($db->hasTable(TABLE_PREFIX . 'account_email_codes')) {
// $db->dropTable(TABLE_PREFIX . 'account_email_codes');
//}
};

View File

@@ -1,42 +0,0 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
// 2025-02-27
// remove ipv6, change to ip (for both ipv4 + ipv6) as VARCHAR(45)
$up = function () use ($db) {
$accountActionsInfo = $db->getColumnInfo(TABLE_PREFIX . 'account_actions', 'account_id');
if ($accountActionsInfo && is_array($accountActionsInfo) && $accountActionsInfo['key'] == 'pri') {
$db->query("ALTER TABLE `myaac_account_actions` DROP KEY `account_id`;");
}
if (!$db->hasColumn(TABLE_PREFIX . 'account_actions', 'id')) {
$db->addColumn(TABLE_PREFIX . 'account_actions', 'id', 'INT NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`id`)');
}
$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';");
if ($db->hasColumn(TABLE_PREFIX . 'account_actions', 'ipv6')) {
$db->dropColumn(TABLE_PREFIX . 'account_actions', 'ipv6');
}
};
$down = function () use ($db) {
if ($db->hasColumn(TABLE_PREFIX . 'account_actions', 'id')) {
$db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` DROP `id`;");
}
$db->query("ALTER TABLE `" . TABLE_PREFIX . "account_actions` ADD KEY (`account_id`);");
if (!$db->hasColumn(TABLE_PREFIX . 'account_actions', 'ipv6')) {
$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;");
};

View File

@@ -1,16 +0,0 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
$up = function () use ($db) {
if (!$db->hasColumn(TABLE_PREFIX . 'menu', 'access')) {
$db->addColumn(TABLE_PREFIX . 'menu', 'access', 'TINYINT NOT NULL DEFAULT 0 AFTER `link`');
}
};
$down = function () use ($db) {
if ($db->hasColumn(TABLE_PREFIX . 'menu', 'access')) {
$db->dropColumn(TABLE_PREFIX . 'menu', 'access');
}
};

View File

@@ -9,7 +9,7 @@ $up = function () use ($db) {
}
};
$down = function () use ($db) {
$up = function () use ($db) {
if (!$db->hasColumn(TABLE_PREFIX . 'screenshots', 'name')) {
$db->addColumn(TABLE_PREFIX . 'screenshots', 'name', 'VARCHAR(30) NOT NULL');
}

View File

@@ -1,29 +0,0 @@
<?php
/**
* Example of using getTopPlayers() function
* to display the best players for each skill
*/
defined('MYAAC') or die('Direct access not allowed!');
$skills = [
'magic', 'level',
'balance', 'frags',
POT::SKILL_FIST, POT::SKILL_CLUB,
POT::SKILL_SWORD, POT::SKILL_AXE,
POT::SKILL_DISTANCE, POT::SKILL_SHIELD,
POT::SKILL_FISH
];
foreach ($skills as $skill) {?>
<ul>
<?php
echo '<strong>' . ucwords(is_string($skill) ? $skill : getSkillName($skill)) . '</strong>';
foreach (getTopPlayers(5, $skill) as $player) {?>
<li><?= $player['rank'] . '. ' . $player['name'] . ' - ' . $player['value']; ?></li>
<?php
}
?>
</ul>
<?php
}

View File

@@ -0,0 +1,124 @@
<?php
/**
* 2-factor authentication
*
* @package MyAAC
* @author Slawkens <slawkens@gmail.com>
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Two Factor Authentication';
require __DIR__ . '/base.php';
csrfProtect();
/**
* @var OTS_Account $account_logged
*/
$step = $_REQUEST['step'] ?? '';
$code = $_REQUEST['auth-code'] ?? '';
if ((!setting('core.mail_enabled')) && ACTION == 'email-code') {
$twig->display('error_box.html.twig', ['errors' => ['Account two-factor e-mail authentication disabled.']]);
return;
}
if (!isset($account_logged) || !$account_logged->isLoaded()) {
$current_session = getSession('account');
if($current_session) {
$account_logged = new OTS_Account();
$account_logged->load($current_session);
}
}
$twoFactorAuth = TwoFactorAuth::getInstance($account_logged);
$twig->addGlobal('account_logged', $account_logged);
if (ACTION == 'email-code') {
if ($step == 'resend') {
if ($twoFactorAuth->hasRecentEmailCode(15 * 60)) {
$errors = ['Sorry, one email per 15 minutes'];
}
else {
$twoFactorAuth->resendEmailCode();
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email.login.html.twig');
}
else if ($step == 'activate') {
if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) {
$twoFactorAuth->resendEmailCode();
}
if (isset($_POST['save'])) {
if (!empty($code)) {
$twoFactorAuth->setAuthGateway(TwoFactorAuth::TYPE_EMAIL);
if ($twoFactorAuth->getAuthGateway()->verifyCode($code)) {
$serverName = configLua('serverName');
$twoFactorAuth->enable(TwoFactorAuth::TYPE_EMAIL);
$twoFactorAuth->deleteOldCodes();
$twig->display('success.html.twig', [
'title' => 'Email Code Authentication Activated',
'description' => sprintf('You have successfully activated <b>email code authentication</b> for your account. This means an <b>email code</b> will be sent to the email address assigned to your account whenever you try to log in to the %s client or the %s website. In order to log in, you will need to enter the <b>most recent email code</b> you have received.', $serverName, $serverName)
]);
return;
}
else {
$errors[] = 'Invalid email code!';
}
}
}
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email_code.html.twig', ['wrongCode' => count($errors) > 0]);
}
else if ($step == 'deactivate') {
//if (!$twoFactorAuth->hasRecentEmailCode(15 * 60)) {
// $twoFactorAuth->resendEmailCode();
//}
/*if (isset($_POST['save'])) {
if (!empty($code)) {
if ($twoFactorAuth->getAuthGateway()->verifyCode($code)) {
*/
$twoFactorAuth->disable();
$twoFactorAuth->deleteOldCodes();
$twig->display('success.html.twig',
[
'title' => 'Email Code Authentication Deactivated',
'description' => 'You have successfully <b>deactivated</b> the <b>Email Code Authentication</b> for your account.'
]
);
/*
}
else {
$errors[] = 'Invalid email code!';
}
}
}*/
/*
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
}
$twig->display('account.2fa.email.deactivate.html.twig', ['wrongCode' => count($errors) > 0]);
*/
}
}

View File

@@ -17,6 +17,10 @@ if(!$logged)
if(!empty($errors))
$twig->display('error_box.html.twig', array('errors' => $errors));
if (defined('HIDE_LOGIN_BOX') && HIDE_LOGIN_BOX) {
return;
}
$twig->display('account.login.html.twig', array(
'redirect' => $_REQUEST['redirect'] ?? null,
'account' => USE_ACCOUNT_NAME ? 'Name' : 'Number',

View File

@@ -19,17 +19,18 @@ if(!$logged) {
csrfProtect();
$new_password = $_POST['new_password'] ?? null;
$new_password_confirm = $_POST['new_password_confirm'] ?? null;
$old_password = $_POST['old_password'] ?? null;
if(is_null($new_password) && is_null($new_password_confirm) && is_null($old_password)) {
$new_password = $_POST['newpassword'] ?? NULL;
$new_password_confirm = $_POST['newpassword_confirm'] ?? NULL;
$old_password = $_POST['oldpassword'] ?? NULL;
if(empty($new_password) && empty($new_password_confirm) && empty($old_password)) {
$twig->display('account.change-password.html.twig');
}
else {
else
{
if(empty($new_password) || empty($new_password_confirm) || empty($old_password)){
$errors[] = 'Please fill in form.';
}
$password_strlen = strlen($new_password);
if($new_password != $new_password_confirm) {
$errors[] = 'The new passwords do not match!';
}
@@ -40,13 +41,10 @@ else {
}
/** @var OTS_Account $account_logged */
$old_password_hashed = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password);
if($old_password_hashed != $account_logged->getPassword()) {
$old_password = encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $old_password);
if($old_password != $account_logged->getPassword()) {
$errors[] = 'Current password is incorrect!';
}
else if ($old_password == $new_password) {
$errors[] = 'The old password is same as the new password!';
}
$hooks->trigger(HOOK_ACCOUNT_CHANGE_PASSWORD_POST);
}

View File

@@ -9,7 +9,6 @@
*/
use MyAAC\Models\Account;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!');
@@ -21,20 +20,16 @@ if(empty($hash)) {
return;
}
// by default link is valid for 30 days
$accountEmailVerify = AccountEmailVerify::where('hash', $hash)->where('sent_at', '>', time() - 30 * 24 * 60 * 60)->first();
if(!$accountEmailVerify) {
note("Wrong link or link has expired.");
if(!Account::where('email_hash', $hash)->exists()) {
note("Your email couldn't be verified. Please contact staff to do it manually.");
}
else
{
$accountModel = Account::where('id', $accountEmailVerify->account_id)->where('email_verified', 0)->first();
$accountModel = Account::where('email_hash', $hash)->where('email_verified', 0)->first();
if ($accountModel) {
$accountModel->email_verified = 1;
$accountModel->save();
AccountEmailVerify::where('account_id', $accountModel->id)->delete();
success('You have now verified your e-mail, this will increase the security of your account. Thank you for doing this. You can now <a href=' . getLink('account/manage') . '>log in</a>.');
$account = new OTS_Account();
@@ -44,6 +39,6 @@ else
}
}
else {
error('Your account is already verified.');
error('Link has expired.');
}
}

View File

@@ -10,7 +10,6 @@
*/
use MyAAC\CreateCharacter;
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Create Account';
@@ -245,12 +244,7 @@ if($save)
if(setting('core.mail_enabled') && setting('core.account_mail_verify'))
{
$hash = md5(generateRandomString(16, true, true) . $email);
AccountEmailVerify::create([
'account_id' => $new_account->getId(),
'hash' => $hash,
'sent_at' => time(),
]);
$new_account->setCustomField('email_hash', $hash);
$verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.verify.html.twig', array(
@@ -274,10 +268,8 @@ if($save)
}
else
{
error('An error occurred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
error('An error occorred while sending email! Account not created. Try again. For Admin: More info can be found in system/logs/mailer-error.log');
$new_account->delete();
return;
}
}
else
@@ -367,7 +359,7 @@ if(!empty($errors))
if (setting('core.account_country')) {
$countries = array();
foreach (setting('core.account_countries_most_popular') ?? [] as $c)
foreach (array('pl', 'se', 'br', 'us', 'gb') as $c)
$countries[$c] = $config['countries'][$c];
$countries['--'] = '----------';

View File

@@ -10,6 +10,7 @@
*/
use MyAAC\RateLimit;
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!');
@@ -48,12 +49,16 @@ if(!empty($login_account) && !empty($login_password))
)
{
if (setting('core.account_mail_verify') && (int)$account_logged->getCustomField('email_verified') !== 1) {
$link = getLink('account/resend-email-verify');
$errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.<br/>' .
'You can resend the Email here: <a href="' . $link . '">' . $link . '</a>';
$errors[] = 'Your account is not verified. Please verify your email address. If the message is not coming check the SPAM folder in your E-Mail client.';
} else {
session_regenerate_id();
setSession('account', $account_logged->getId());
$twoFactorAuth = TwoFactorAuth::getInstance($account_logged);
if (!$twoFactorAuth->process($login_account, $login_password, $remember_me, $_POST['auth-code'] ?? '')) {
return;
}
session_regenerate_id();
setSession('password', encrypt((USE_ACCOUNT_SALT ? $account_logged->getCustomField('salt') : '') . $login_password));
if($remember_me) {
setSession('remember_me', true);

View File

@@ -8,6 +8,9 @@
* @copyright 2019 MyAAC
* @link https://my-aac.org
*/
use MyAAC\TwoFactorAuth\TwoFactorAuth;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Account Management';
@@ -38,24 +41,15 @@ csrfProtect();
$groups = new OTS_Groups_List();
$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $account_logged->getPremDays() == OTS_Account::GRATIS_PREMIUM_DAYS;
$dayOrDays = $account_logged->getPremDays() == 1 ? 'day' : 'days';
/**
* @var OTS_Account $account_logged
*/
$premDays = $account_logged->getPremDays();
$freePremium = isset($config['lua']['freePremium']) && getBoolean($config['lua']['freePremium']) || $premDays == OTS_Account::GRATIS_PREMIUM_DAYS;
$dayOrDays = ($premDays == 1 ? 'day' : 'days');
$vipSystemEnabled = isset($config['lua']['vipSystemEnabled']) && getBoolean($config['lua']['vipSystemEnabled']);
$premiumLabel = $vipSystemEnabled ? 'VIP' : 'Premium Account';
if ($freePremium && !$vipSystemEnabled) {
$account_status = '<b><span style="color: green">Gratis Premium Account</span></b>';
} else if(!$account_logged->isPremium()) {
if(!$account_logged->isPremium())
$account_status = '<b><span style="color: red">Free Account</span></b>';
} else {
$account_status = '<b><span style="color: green">' . $premiumLabel . ', ' . $premDays . ' '.$dayOrDays.' left</span></b>';
}
else
$account_status = '<b><span style="color: green">' . ($freePremium ? 'Gratis Premium Account' : 'Premium Account, ' . $account_logged->getPremDays() . ' '.$dayOrDays.' left') . '</span></b>';
$recovery_key = $account_logged->getCustomField('key');
if(empty($recovery_key))
@@ -96,8 +90,12 @@ if($email_new_time > 1)
}
}
$actions = $account_logged->getActionsLog(1000);
$actions = array();
foreach($account_logged->getActionsLog(0, 1000) as $action) {
$actions[] = array('action' => $action['action'], 'date' => $action['date'], 'ip' => $action['ip'] != 0 ? long2ip($action['ip']) : inet_ntop($action['ipv6']));
}
$players = array();
/** @var OTS_Players_List $account_players */
$account_players = $account_logged->getPlayersList();
$account_players->orderBy('id');
@@ -116,6 +114,8 @@ $twig->display('account.management.html.twig', array(
'account_registered' => $account_registered,
'account_rlname' => $account_rlname,
'account_location' => $account_location,
'twoFactorViews' => TwoFactorAuth::getInstance($account_logged)->getAccountManageViews(),
'actions' => $actions,
'players' => $account_players
'players' => $account_players,
));

View File

@@ -48,7 +48,7 @@ else
$account_logged->setCustomField('key', $new_rec_key);
$account_logged->setCustomField(setting('core.donate_column'), $account_logged->getCustomField(setting('core.donate_column')) - setting('core.account_generate_new_reckey_price'));
$account_logged->logAction('Generated new recovery key for ' . setting('core.account_generate_new_reckey_price') . ' premium points.');
$message = '<br />Your recovery key was sent on email address <b>'.$account_logged->getEMail().'</b> for '.setting('core.account_generate_new_reckey_price').' premium points.';
$message = '<br />Your recovery key were send on email address <b>'.$account_logged->getEMail().'</b> for '.setting('core.account_generate_new_reckey_price').' premium points.';
}
else
$message = '<br /><p class="error">An error occurred while sending email ( <b>'.$account_logged->getEMail().'</b> ) with recovery key! Recovery key not changed. Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>';

View File

@@ -1,94 +0,0 @@
<?php
use MyAAC\Models\AccountEmailVerify;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Resend Email';
$errorWithBackButton = function ($msg) use ($twig) {
$errors = [$msg];
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [
'action' => getLink('account/resend-email-verify'),
]);
};
if (!setting('core.mail_enabled') || !setting('core.account_mail_verify')) {
$errorWithBackButton('Resending email is not possible on this server.');
return;
}
$showForm = true;
if (isset($_POST['submit']) && $_POST['submit'] == '1') {
$email = $_REQUEST['email'];
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errorWithBackButton('Please enter valid Email.');
return;
}
$account = new OTS_Account();
$account->findByEMail($email);
if ($account->isLoaded()) {
if ($account->getCustomField('email_verified') == '1') {
$errorWithBackButton('This account is already verified! You can <a href=' . getLink('account/manage') . '>log in</a> on the website.');
return;
}
$accountEmailVerify = AccountEmailVerify::where('account_id', $account->getId())->orderBy('sent_at', 'DESC')->first();
if ($accountEmailVerify && time() - $accountEmailVerify->sent_at < 60) {
$errorWithBackButton('Only one Email per minute is allowed. Please try again later.');
return;
}
$tmp_account = $email;
if (!config('account_login_by_email')) {
$tmp_account = (USE_ACCOUNT_NAME ? $account->getName() : $account->getId());
}
$hash = md5(generateRandomString(16, true, true) . $email);
AccountEmailVerify::create([
'account_id' => $account->getId(),
'hash' => $hash,
'sent_at' => time(),
]);
$verify_url = getLink('account/confirm-email/' . $hash);
$body_html = $twig->render('mail.account.resend-email-verify.html.twig', array(
'account' => $tmp_account,
'verify_url' => generateLink($verify_url, $verify_url, true)
));
if (_mail($account->getEMail(), configLua('serverName') . ' - Verify Account', $body_html)) {
$message = "If account with this email exists - you will become an email with verification link.";
$showForm = false;
} else {
$message = "<p class='error'>An error occurred while sending email (<b>{$email}</b> )! Try again later. For Admin: More info can be found in system/logs/mailer-error.log</p>";
}
}
else {
$message = "<br />If account with this email exists - you will become an email with verification link.";
$showForm = false;
}
$twig->display('success.html.twig', array(
'title' => 'Verify Email Sent',
'description' => $message,
));
}
//show errors if not empty
if (!empty($errors)) {
$twig->display('error_box.html.twig', ['errors' => $errors]);
$twig->display('account.back_button.html.twig', [
'action' => getLink('account/resend-email-verify'),
]);
}
if ($showForm) {
$twig->display('account.resend-email-verify.html.twig');
}

View File

@@ -202,37 +202,35 @@ if($player->isLoaded() && !$player->isDeleted())
unset($storage);
}
if ($db->hasTableAndColumns('player_items', ['pid', 'sid', 'itemtype'])) {
if($db->hasTable('player_items') && $db->hasColumn('player_items', 'pid') && $db->hasColumn('player_items', 'sid') && $db->hasColumn('player_items', 'itemtype')) {
$eq_sql = $db->query('SELECT `pid`, `itemtype` FROM player_items WHERE player_id = '.$player->getId().' AND (`pid` >= 1 and `pid` <= 10)');
$equipment = [];
foreach($eq_sql as $eq) {
$equipment = array();
foreach($eq_sql as $eq)
$equipment[$eq['pid']] = $eq['itemtype'];
}
$empty_slots = ["", "no_helmet", "no_necklace", "no_backpack", "no_armor", "no_handleft", "no_handright", "no_legs", "no_boots", "no_ring", "no_ammo"];
for($i = 0; $i <= 10; $i++) {
$empty_slots = array("", "no_helmet", "no_necklace", "no_backpack", "no_armor", "no_handleft", "no_handright", "no_legs", "no_boots", "no_ring", "no_ammo");
for($i = 0; $i <= 10; $i++)
{
if(!isset($equipment[$i]) || $equipment[$i] == 0)
$equipment[$i] = $empty_slots[$i];
}
for($i = 1; $i < 11; $i++) {
if(Validator::number($equipment[$i])) {
for($i = 1; $i < 11; $i++)
{
if(Validator::number($equipment[$i]))
$equipment[$i] = getItemImage($equipment[$i]);
}
else {
else
$equipment[$i] = '<img src="images/items/' . $equipment[$i] . '.gif" width="32" height="32" border="0" alt=" ' . $equipment[$i] . '" />';
}
}
}
$skulls = [
1 => 'yellow_skull',
2 => 'green_skull',
3 => 'white_skull',
4 => 'red_skull',
5 => 'black_skull',
];
$skulls = array(
1 => 'yellow_skull',
2 => 'green_skull',
3 => 'white_skull',
4 => 'red_skull',
5 => 'black_skull'
);
}
$dead_add_content = '';
$deaths = array();
@@ -452,8 +450,10 @@ WHERE killers.death_id = '".$death['id']."' ORDER BY killers.final_hit DESC, kil
if($query->rowCount() > 0) {
echo 'Did you mean:<ul>';
foreach($query as $player) {
$player['vocation'] = OTS_Toolbox::getVocationFromPromotion($player['vocation'], $player['promotion'] ?? 0);
if(isset($player['promotion'])) {
if((int)$player['promotion'] > 0)
$player['vocation'] += ($player['promotion'] * $config['vocations_amount']);
}
echo '<li>' . getPlayerLink($player['name']) . ' (<small><strong>level ' . $player['level'] . ', ' . $config['vocations'][$player['vocation']] . '</strong></small>)</li>';
}
echo '</ul>';

View File

@@ -42,12 +42,35 @@ for($i = 0; $i < $threads_count['threads_count'] / setting('core.forum_threads_p
$links_to_pages .= '<b>'.($i + 1).' </b>';
}
echo '<a href="' . getLink('forum') . '">Boards</a> >> <b>'.$sections[$section_id]['name'].'</b>';
if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) {
echo '<br /><br />
<a href="' . getLink('forum') . '?action=new_thread&section_id='.$section_id.'"><img src="images/forum/topic.gif" border="0" /></a>';
}
echo '<br /><br />Page: '.$links_to_pages.'<br />';
$last_threads = $db->query("SELECT `players`.`id` as `player_id`, `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`last_post`, `" . FORUM_TABLE_PREFIX . "forum`.`replies`, `" . FORUM_TABLE_PREFIX . "forum`.`views`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` AND `" . FORUM_TABLE_PREFIX . "forum`.`section` = ".$section_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = `" . FORUM_TABLE_PREFIX . "forum`.`id` ORDER BY `" . FORUM_TABLE_PREFIX . "forum`.`last_post` DESC LIMIT ".setting('core.forum_threads_per_page')." OFFSET ".($_page * setting('core.forum_threads_per_page')))->fetchAll(PDO::FETCH_ASSOC);
$threads = [];
if(count($last_threads) > 0) {
if(isset($last_threads[0])) {
echo '<table width="100%">
<tr bgcolor="'.$config['vdarkborder'].'" align="center">
<td class="white">
<span style="font-size: 10px"><b>Thread</b></span></td>
<td><span style="font-size: 10px"><b>Thread Starter</b></span></td>
<td><span style="font-size: 10px"><b>Replies</b></span></td>
<td><span style="font-size: 10px"><b>Views</b></span></td>
<td><span style="font-size: 10px"><b>Last Post</b></span></td>
</tr>';
$player = new OTS_Player();
foreach($last_threads as $thread) {
echo '<tr bgcolor="' . getStyle($number_of_rows++) . '"><td>';
if(Forum::isModerator()) {
echo '<a href="' . getLink('forum') . '?action=move_thread&id=' . $thread['id'] . '" title="Move Thread"><img src="images/icons/arrow_right.gif"/></a>';
$twig->display('forum.remove_post.html.twig', ['post' => $thread]);
}
$player->load($thread['player_id']);
if(!$player->isLoaded()) {
throw new RuntimeException('Forum error: Player not loaded.');
@@ -56,29 +79,28 @@ if(count($last_threads) > 0) {
$player_account = $player->getAccount();
$canEditForum = $player_account->hasFlag(FLAG_CONTENT_FORUM) || $player_account->isAdmin();
$thread['link'] = getForumThreadLink($thread['id']);
$thread['post_shortened'] = ($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50)));
$thread['player'] = $player;
$thread['player_link'] = getPlayerLink($thread['name']);
echo '<a href="' . getForumThreadLink($thread['id']) . '">'.htmlspecialchars($thread['post_topic']). '</a><br /><small>'.($canEditForum ? substr(strip_tags($thread['post_text']), 0, 50) : htmlspecialchars(substr($thread['post_text'], 0, 50))).'...</small></td><td>' . getPlayerLink($thread['name']) . '</td><td>'.(int) $thread['replies'].'</td><td>'.(int) $thread['views'].'</td><td>';
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();
$last_post['player_link'] = getPlayerLink($last_post['name']);
$thread['latest_post'] = $last_post;
if(isset($last_post['name'])) {
echo date('d.m.y H:i:s', $last_post['post_date']) . '<br />by ' . getPlayerLink($last_post['name']);
}
else {
echo 'No posts.';
}
}
else {
echo date('d.m.y H:i:s', $thread['post_date']) . '<br />by ' . getPlayerLink($thread['name']);
}
echo '</td></tr>';
}
$threads[] = $thread;
echo '</table>';
if($logged && (!$sections[$section_id]['closed'] || Forum::isModerator())) {
echo '<br /><a href="' . getLink('forum') . '?action=new_thread&section_id=' . $section_id . '"><img src="images/forum/topic.gif" border="0" /></a>';
}
}
$twig->display('forum.show_board.html.twig', [
'threads' => $threads,
'section_id' => $section_id,
'section_name' => $sections[$section_id]['name'],
'links_to_pages' => $links_to_pages,
'is_moderator' => Forum::isModerator(),
'closed' => $sections[$section_id]['closed'],
]);
else {
echo '<h3>No threads in this board.</h3>';
}

View File

@@ -21,9 +21,6 @@ if(!$logged) {
$errors[] = 'You are not logged in. You can\'t create guild.';
}
$configLuaFreePremium = configLua('freePremium');
$freePremium = (isset($configLuaFreePremium) && getBoolean($configLuaFreePremium));
$array_of_player_nig = array();
if(empty($errors))
{
@@ -34,7 +31,7 @@ if(empty($errors))
if(!$player_rank->isLoaded())
{
if($player->getLevel() >= setting('core.guild_need_level')) {
if(!setting('core.guild_need_premium') || $account_logged->isPremium() || $freePremium) {
if(!setting('core.guild_need_premium') || $account_logged->isPremium()) {
$array_of_player_nig[] = $player->getName();
}
}
@@ -98,7 +95,7 @@ if($todo == 'save')
if($player->getLevel() < setting('core.guild_need_level')) {
$errors[] = 'Character <b>'.$name.'</b> has too low level. To create guild you need character with level <b>' . setting('core.guild_need_level') . '</b>.';
}
if(setting('core.guild_need_premium') && !$account_logged->isPremium() && !$freePremium) {
if(setting('core.guild_need_premium') && !$account_logged->isPremium()) {
$errors[] = 'Character <b>'.$name.'</b> is on FREE account. To create guild you need PREMIUM account.';
}
}

View File

@@ -91,18 +91,13 @@ $guild_owner = $guild->getOwner();
if($guild_owner->isLoaded())
$guild_owner_name = $guild_owner->getName();
$deletedColumn = 'deleted';
if ($db->hasColumn('players', 'deletion')) {
$deletedColumn = 'deletion';
}
$guild_members = array();
foreach($rank_list as $rank)
{
if($db->hasTable(GUILD_MEMBERS_TABLE))
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `' . GUILD_MEMBERS_TABLE . '`.`rank_id` as `rank_id` FROM `players`, `' . GUILD_MEMBERS_TABLE . '` WHERE `' . GUILD_MEMBERS_TABLE . '`.`rank_id` = ' . $rank->getId() . ' AND `players`.`id` = `' . GUILD_MEMBERS_TABLE . '`.`player_id` AND `' . $deletedColumn . '` = 0 ORDER BY `name`;');
$players_with_rank = $db->query('SELECT `players`.`id` as `id`, `' . GUILD_MEMBERS_TABLE . '`.`rank_id` as `rank_id` FROM `players`, `' . GUILD_MEMBERS_TABLE . '` WHERE `' . GUILD_MEMBERS_TABLE . '`.`rank_id` = ' . $rank->getId() . ' AND `players`.`id` = `' . GUILD_MEMBERS_TABLE . '`.`player_id` ORDER BY `name`;');
else if($db->hasColumn('players', 'rank_id'))
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank->getId() . ' AND `' . $deletedColumn . '` = 0;');
$players_with_rank = $db->query('SELECT `id`, `rank_id` FROM `players` WHERE `rank_id` = ' . $rank->getId() . ' AND `deleted` = 0;');
$players_with_rank_number = $players_with_rank->rowCount();
if($players_with_rank_number > 0)

View File

@@ -13,7 +13,6 @@ use MyAAC\Cache\Cache;
use MyAAC\Models\Player;
use MyAAC\Models\PlayerDeath;
use MyAAC\Models\PlayerKillers;
use MyAAC\Server\XML\Vocations;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Highscores';
@@ -36,20 +35,24 @@ if(!is_numeric($page) || $page < 1 || $page > PHP_INT_MAX) {
$query = Player::query();
$configVocations = config('vocations');
$configVocationsAmount = config('vocations_amount');
$vocationId = null;
if($vocation !== 'all') {
foreach($configVocations as $id => $name) {
if(strtolower($name) == $vocation) {
$vocationId = $id;
$filterVocations = [$id];
$add_vocs = [$id];
while($tmpVoc = Vocations::getPromoted($id)) {
$id = $tmpVoc;
$filterVocations[] = $tmpVoc;
if ($id !== 0) {
$i = $id + $configVocationsAmount;
while (isset($configVocations[$i])) {
$add_vocs[] = $i;
$i += $configVocationsAmount;
}
}
$query->whereIn('players.vocation', $filterVocations);
$query->whereIn('players.vocation', $add_vocs);
break;
}
}
@@ -173,9 +176,7 @@ if (empty($highscores)) {
POT::SKILL_FISH => 'skill_fishing',
);
$query
->addSelect($skill_ids[$skill] . ' as value')
->orderByDesc($skill_ids[$skill] . '_tries');
$query->addSelect($skill_ids[$skill] . ' as value');
} else {
$query
->join('player_skills', 'player_skills.player_id', '=', 'players.id')
@@ -197,11 +198,11 @@ if (empty($highscores)) {
if ($skill == POT::SKILL__MAGLEVEL) {
$query
->addSelect('players.maglevel as value', 'players.maglevel')
->orderByDesc('manaspent');
->orderBy('manaspent');
} else { // level
$query
->addSelect('players.level as value', 'players.experience')
->orderByDesc('experience');
->orderBy('experience');
$list = 'experience';
}
}
@@ -246,7 +247,7 @@ foreach($highscores as $id => &$player)
$player['link'] = getPlayerLink($player['name'], false);
$player['flag'] = getFlagImage($player['country']);
$player['outfit'] = '<img style="position:absolute;margin-top:-50px;margin-left:-30px" src="' . $player['outfit_url'] . '" alt="" />';
$player['outfit'] = '<img style="position:absolute;margin-top:' . (in_array($player['looktype'], setting('core.outfit_images_wrong_looktypes')) ? '-15px;margin-left:5px' : '-45px;margin-left:-25px') . ';" src="' . $player['outfit_url'] . '" alt="" />';
if ($skill != POT::SKILL__LEVEL) {
if (isset($lastValue) && $lastValue == $player['value']) {
@@ -322,5 +323,4 @@ $twig->display('highscores.html.twig', [
'page' => $page,
'baseLink' => $baseLink,
'updatedAt' => $updatedAt,
'baseVocations' => Vocations::getBase(true),
]);

View File

@@ -122,7 +122,7 @@ if(!$news_cached)
);
}
$tickers_db = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'news` WHERE `type` = ' . TICKER . ' AND `hide` != 1 ORDER BY `date` DESC LIMIT ' . setting('core.news_ticker_limit'));
$tickers_db = $db->query('SELECT * FROM `' . TABLE_PREFIX . 'news` WHERE `type` = ' . TICKER .($canEdit ? '' : ' AND `hide` != 1') .' ORDER BY `date` DESC LIMIT ' . setting('core.news_ticker_limit'));
$tickers_content = '';
if($tickers_db->rowCount() > 0)
{
@@ -142,8 +142,7 @@ if(!$news_cached)
if($cache->enabled() && !$canEdit)
$cache->set('news_' . $template_name . '_' . TICKER, $tickers_content, 60 * 60);
$featured_article_db =$db->query('SELECT `id`, `title`, `article_text`, `article_image`, `hide` FROM `' . TABLE_PREFIX . 'news` WHERE `type` = ' . ARTICLE . ' AND `hide` != 1 ORDER BY `date` DESC LIMIT 1');
$featured_article_db =$db->query('SELECT `id`, `title`, `article_text`, `article_image`, `hide` FROM `' . TABLE_PREFIX . 'news` WHERE `type` = ' . ARTICLE . ($canEdit ? '' : ' AND `hide` != 1') .' ORDER BY `date` DESC LIMIT 1');
$article = '';
if($featured_article_db->rowCount() > 0) {
$article = $featured_article_db->fetch();
@@ -176,7 +175,7 @@ else {
if(!$news_cached)
{
ob_start();
$newses = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'news') . ' WHERE type = ' . NEWS . ' AND hide != 1 ORDER BY date' . ' DESC LIMIT ' . setting('core.news_limit'));
$newses = $db->query('SELECT * FROM ' . $db->tableName(TABLE_PREFIX . 'news') . ' WHERE type = ' . NEWS . ($canEdit ? '' : ' AND hide != 1') . ' ORDER BY date' . ' DESC LIMIT ' . setting('core.news_limit'));
if($newses->rowCount() > 0)
{
foreach($newses as $news)

View File

@@ -12,7 +12,6 @@
use MyAAC\Cache\Cache;
use MyAAC\Models\ServerConfig;
use MyAAC\Models\ServerRecord;
use MyAAC\Server\XML\Vocations;
defined('MYAAC') or die('Direct access not allowed!');
$title = 'Who is online?';
@@ -57,14 +56,15 @@ $cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60
$vocations = array_map(function ($name) {
return 0;
}, config('vocations'));
}, 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 ' . $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);
$configVocations = config('vocations');
$settingVocations = setting('core.vocations');
$settingVocationsAmount = setting('core.vocations_amount');
$players = [];
foreach($playersOnline as $player) {
@@ -81,19 +81,22 @@ $cached = Cache::remember("online_$order", setting('core.online_cache_ttl') * 60
}
}
$player['vocation'] = OTS_Toolbox::getVocationFromPromotion($player['vocation'], $player['promotion'] ?? 0);
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' => $configVocations[$player['vocation']],
'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[Vocations::getOriginal($player['vocation'])]++;
$vocations[($player['vocation'] > $settingVocationsAmount ? $player['vocation'] - $settingVocationsAmount : $player['vocation'])]++;
}
$record = '';
@@ -139,7 +142,6 @@ $twig->display('online.html.twig', array(
'vocations' => $cached['vocations'],
'vocs' => $cached['vocations'], // deprecated, to be removed
'order' => $order,
'baseVocations' => Vocations::getBase(false),
));
// search bar

View File

@@ -8,7 +8,6 @@
* @link https://my-aac.org
*/
use MyAAC\Models\Menu;
use MyAAC\Models\Pages;
use MyAAC\Plugins;
@@ -89,10 +88,8 @@ if($logged && $account_logged && $account_logged->isLoaded()) {
/**
* Routes loading
*/
$routesFinal = [];
$dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r) {
global $cache, $routesFinal;
$routesFinal = [];
foreach(getDatabasePages() as $page) {
$routesFinal[] = ['*', $page, '__database__/' . $page, 100];
}
@@ -168,7 +165,7 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
echo '</pre>';
die;
*/
foreach ($routesFinal as &$route) {
foreach ($routesFinal as $route) {
if ($route[0] === '*') {
$route[0] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD'];
}
@@ -201,10 +198,6 @@ $dispatcher = FastRoute\cachedDispatcher(function (FastRoute\RouteCollector $r)
log_append('router.log', $warning);
}
}
if ($cache->enabled()) {
$cache->set('routes_final', serialize($routesFinal), 10 * 365 * 24 * 60 * 60); // 10 years / infinite
}
},
[
'cacheFile' => CACHE . 'route.cache',
@@ -219,7 +212,7 @@ $found = true;
// old support for pages like /?subtopic=accountmanagement
$page = $_REQUEST['p'] ?? ($_REQUEST['subtopic'] ?? '');
if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) {
if(!empty($page) && preg_match('/^[A-z0-9\-]+$/', $page)) {
if (isset($_REQUEST['p'])) { // some plugins may require this
$_REQUEST['subtopic'] = $_REQUEST['p'];
}
@@ -228,26 +221,9 @@ if(!empty($page) && preg_match('/^[A-z0-9\/\-]+$/', $page)) {
require SYSTEM . 'compat/pages.php';
}
$foundRoute = false;
$tmp = null;
if ($cache->enabled() && $cache->fetch('routes_final', $tmp)) {
$routesFinal = unserialize($tmp);
}
foreach ($routesFinal as $route) {
if ($page === $route[1]) {
$file = $route[2];
$foundRoute = true;
break;
}
}
if (!$foundRoute) {
$file = loadPageFromFileSystem($page, $found);
if(!$found) {
$file = false;
}
$file = loadPageFromFileSystem($page, $found);
if(!$found) {
$file = false;
}
}
else {
@@ -332,20 +308,7 @@ else {
}
}
$tmpPageOriginal = $page;
$pagesWithDynamicPart = ['characters', 'forum', 'highscores', 'monsters'];
foreach ($pagesWithDynamicPart as $_page) {
if (str_contains($page, $_page)) {
$tmpPageOriginal = $_page;
}
}
$themeMenu = Menu::select(['name'])
->where('template', $template_name)
->where('link', $tmpPageOriginal)
->where('access', '>', $logged_access);
if (!$found || $themeMenu->count() >= 1) {
if (!$found) {
$page = '404';
$file = SYSTEM . 'pages/404.php';
}

View File

@@ -219,14 +219,7 @@ return [
'cache_engine' => [
'name' => 'Cache Engine',
'type' => 'options',
'options' => [
'auto' => 'Auto',
'file' => 'Files',
'apc' => 'APC',
'apcu' => 'APCu',
'php' => 'PHP',
'disable' => 'Disable',
],
'options' => ['auto' => 'Auto', 'file' => 'Files', 'apc' => 'APC', 'apcu' => 'APCu', 'disable' => 'Disable'],
'desc' => 'Auto is most reasonable. It will detect the best cache engine',
'default' => 'auto',
'is_config' => true,
@@ -319,6 +312,23 @@ return [
},
],
],
'vocations_amount' => [
'name' => 'Vocations Amount',
'type' => 'number',
'desc' => 'How much basic vocations your server got (without promotion)',
'default' => 4,
],
'vocations' => [
'name' => 'Vocation Names',
'type' => 'textarea',
'desc' => 'Separated by comma. Must be in the same order as in vocations.xml, starting with id: 0.',
'default' => 'None, Sorcerer, Druid, Paladin, Knight, Master Sorcerer, Elder Druid,Royal Paladin, Elite Knight',
'callbacks' => [
'get' => function ($value) {
return array_map('trim', explode(',', $value));
},
],
],
[
'type' => 'category',
'title' => 'Database',
@@ -727,18 +737,6 @@ Sent by MyAAC,<br/>
'desc' => 'should country of user be automatically recognized by his IP? This makes an external API call to http://ipinfo.io',
'default' => true,
],
'account_countries_most_popular' => [
'name' => 'Account Countries Most Popular',
'type' => 'text',
'desc' => 'Those countries will be display at the top of the list on the create account page. The short codes of countries can be found in file <i>system/countries.conf.php</i>',
'default' => 'pl,se,br,us,gb',
'callbacks' => [
'get' => function ($value) {
$tmp = array_map('trim', explode(',', $value));
return array_filter($tmp, function ($v) {return !empty($v); });
},
],
],
'characters_per_account' => [
'name' => 'Characters per Account',
'type' => 'number',
@@ -1472,6 +1470,17 @@ Sent by MyAAC,<br/>
'desc' => 'Set to animoutfit.php for animated outfit',
'default' => 'https://outfit-images.ots.me/latest/outfit.php',
],
'outfit_images_wrong_looktypes' => [
'name' => 'Outfit Images Wrong Looktypes',
'type' => 'text',
'desc' => 'This looktypes needs to have different margin-top and margin-left because they are wrong positioned',
'default' => '75, 126, 127, 266, 302',
'callbacks' => [
'get' => function ($value) {
return array_map('trim', explode(',', $value));
},
],
],
[
'type' => 'section',
'title' => 'Monster Images'

View File

@@ -13,8 +13,8 @@ namespace MyAAC\Cache;
class APC
{
private string $prefix;
private bool $enabled;
private $prefix;
private $enabled;
public function __construct($prefix = '')
{
@@ -22,14 +22,14 @@ class APC
$this->enabled = function_exists('apc_fetch');
}
public function set($key, $var, $ttl = 0): void
public function set($key, $var, $ttl = 0)
{
$key = $this->prefix . $key;
apc_delete($key);
apc_store($key, $var, $ttl);
}
public function get($key): string
public function get($key)
{
$tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) {
@@ -39,15 +39,18 @@ class APC
return '';
}
public function fetch($key, &$var): bool {
public function fetch($key, &$var)
{
return ($var = apc_fetch($this->prefix . $key)) !== false;
}
public function delete($key): void {
public function delete($key)
{
apc_delete($this->prefix . $key);
}
public function enabled(): bool {
public function enabled()
{
return $this->enabled;
}
}

View File

@@ -13,8 +13,8 @@ namespace MyAAC\Cache;
class APCu
{
private string $prefix;
private bool $enabled;
private $prefix;
private $enabled;
public function __construct($prefix = '')
{
@@ -22,14 +22,14 @@ class APCu
$this->enabled = function_exists('apcu_fetch');
}
public function set($key, $var, $ttl = 0): void
public function set($key, $var, $ttl = 0)
{
$key = $this->prefix . $key;
apcu_delete($key);
apcu_store($key, $var, $ttl);
}
public function get($key): string
public function get($key)
{
$tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) {
@@ -39,15 +39,18 @@ class APCu
return '';
}
public function fetch($key, &$var): bool {
public function fetch($key, &$var)
{
return ($var = apcu_fetch($this->prefix . $key)) !== false;
}
public function delete($key): void {
public function delete($key)
{
apcu_delete($this->prefix . $key);
}
public function enabled(): bool {
public function enabled()
{
return $this->enabled;
}
}

View File

@@ -47,15 +47,35 @@ class Cache
return self::$instance;
}
self::$instance = match (strtolower($engine)) {
'apc' => new APC($prefix),
'apcu' => new APCu($prefix),
'xcache' => new XCache($prefix),
'file' => new File($prefix, CACHE),
'php' => new PHP($prefix, CACHE),
'auto' => self::generateInstance(self::detect(), $prefix),
default => new self(),
};
switch (strtolower($engine)) {
case 'apc':
self::$instance = new APC($prefix);
break;
case 'apcu':
self::$instance = new APCu($prefix);
break;
case 'xcache':
self::$instance = new XCache($prefix);
break;
case 'file':
self::$instance = new File($prefix, CACHE);
break;
case 'php':
self::$instance = new PHP($prefix, CACHE);
break;
case 'auto':
self::$instance = self::generateInstance(self::detect(), $prefix);
break;
default:
self::$instance = new self();
break;
}
return self::$instance;
}
@@ -63,7 +83,7 @@ class Cache
/**
* @return string
*/
public static function detect(): string
public static function detect()
{
if (function_exists('apc_fetch'))
return 'apc';
@@ -78,7 +98,8 @@ class Cache
/**
* @return bool
*/
public function enabled(): bool {
public function enabled()
{
return false;
}
@@ -94,11 +115,6 @@ class Cache
return unserialize($value);
}
// -1 for infinite cache
if ($ttl == -1) {
$ttl = 10 * 365 * 24 * 60 * 60; // 10 years should be enough
}
$value = $callback();
$cache->set($key, serialize($value), $ttl);
return $value;

View File

@@ -12,22 +12,18 @@ namespace MyAAC\Cache;
class File
{
private string $prefix;
private string $dir;
private bool $enabled;
private $prefix;
private $dir;
private $enabled;
public function __construct($prefix = '', $dir = '')
{
$this->prefix = $prefix;
$this->dir = $dir;
ensureFolderExists($this->dir);
ensureIndexExists($this->dir);
$this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir));
}
public function set($key, $var, $ttl = 0): void
public function set($key, $var, $ttl = 0)
{
$file = $this->_name($key);
file_put_contents($file, $var);
@@ -39,7 +35,7 @@ class File
touch($file, time() + $ttl);
}
public function get($key): string
public function get($key)
{
$tmp = '';
if ($this->fetch($key, $tmp)) {
@@ -49,7 +45,7 @@ class File
return '';
}
public function fetch($key, &$var): bool
public function fetch($key, &$var)
{
$file = $this->_name($key);
if (!file_exists($file) || filemtime($file) < time()) {
@@ -60,7 +56,7 @@ class File
return true;
}
public function delete($key): void
public function delete($key)
{
$file = $this->_name($key);
if (file_exists($file)) {
@@ -68,11 +64,13 @@ class File
}
}
public function enabled(): bool {
public function enabled()
{
return $this->enabled;
}
private function _name($key): string {
private function _name($key)
{
return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key));
}
}

View File

@@ -12,40 +12,36 @@ namespace MyAAC\Cache;
class PHP
{
private string $prefix;
private string $dir;
private bool $enabled;
private $prefix;
private $dir;
private $enabled;
public function __construct($prefix = '', $dir = '')
{
$this->prefix = $prefix;
$this->dir = $dir;
ensureFolderExists($this->dir);
ensureIndexExists($this->dir);
$this->enabled = (file_exists($this->dir) && is_dir($this->dir) && is_writable($this->dir));
}
public function set($key, $var, $ttl = 0): void
public function set($key, $var, $ttl = 0)
{
$var = var_export($var, true);
// Write to temp file first to ensure atomicity
$tmp = $this->dir . "tmp_$key." . uniqid('', true) . '.tmp';
file_put_contents($tmp, '<?php $var = ' . $var . ';', LOCK_EX);
$file = $this->_name($key);
rename($tmp, $file);
if ($ttl === 0) {
$ttl = 365 * 24 * 60 * 60; // 365 days
}
$expires = time() + $ttl;
// Write to temp file first to ensure atomicity
$tmp = $this->dir . "tmp_$key." . uniqid('', true) . '.tmp';
file_put_contents($tmp, "<?php return ['expires' => $expires, 'var' => $var];", LOCK_EX);
$file = $this->_name($key);
rename($tmp, $file);
touch($file, time() + $ttl);
}
public function get($key): string
public function get($key)
{
$tmp = '';
if ($this->fetch($key, $tmp)) {
@@ -55,23 +51,19 @@ class PHP
return '';
}
public function fetch($key, &$var): bool
public function fetch($key, &$var)
{
$file = $this->_name($key);
if (!file_exists($file)) {
if (!file_exists($file) || filemtime($file) < time()) {
return false;
}
$content = include $file;
if (!isset($content) || $content['expires'] < time()) {
return false;
}
$var = $content['var'];
@include $file;
$var = isset($var) ? $var : null;
return true;
}
public function delete($key): void
public function delete($key)
{
$file = $this->_name($key);
if (file_exists($file)) {
@@ -79,11 +71,13 @@ class PHP
}
}
public function enabled(): bool {
public function enabled()
{
return $this->enabled;
}
private function _name($key): string {
private function _name($key)
{
return sprintf('%s%s%s', $this->dir, $this->prefix, sha1($key) . '.php');
}
}

View File

@@ -13,8 +13,8 @@ namespace MyAAC\Cache;
class XCache
{
private string $prefix;
private bool $enabled;
private $prefix;
private $enabled;
public function __construct($prefix = '')
{
@@ -22,14 +22,14 @@ class XCache
$this->enabled = function_exists('xcache_get') && ini_get('xcache.var_size');
}
public function set($key, $var, $ttl = 0): void
public function set($key, $var, $ttl = 0)
{
$key = $this->prefix . $key;
xcache_unset($key);
xcache_set($key, $var, $ttl);
}
public function get($key): string
public function get($key)
{
$tmp = '';
if ($this->fetch($this->prefix . $key, $tmp)) {
@@ -39,7 +39,7 @@ class XCache
return '';
}
public function fetch($key, &$var): bool
public function fetch($key, &$var)
{
$key = $this->prefix . $key;
if (!xcache_isset($key)) {
@@ -50,11 +50,13 @@ class XCache
return true;
}
public function delete($key): void {
public function delete($key)
{
xcache_unset($this->prefix . $key);
}
public function enabled(): bool {
public function enabled()
{
return $this->enabled;
}
}

View File

@@ -1,33 +0,0 @@
<?php
namespace MyAAC\Commands;
use POT;
trait Env
{
protected function init(): void
{
global $config;
if (!isset($config['installed']) || !$config['installed']) {
throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
}
if(empty($config['server_path'])) {
throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.');
}
// take care of trailing slash at the end
if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/';
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua');
// POT
require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance();
$eloquentConnection = null;
require_once SYSTEM . 'database.php';
}
}

View File

@@ -9,8 +9,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateCommand extends Command
{
use Env;
protected function configure(): void
{
$this->setName('migrate')
@@ -19,19 +17,9 @@ class MigrateCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
$this->init();
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output);
$tmp = '';
if(fetchDatabaseConfig('database_version', $tmp)) { // we got version
$tmp = (int)$tmp;
if ($tmp >= DATABASE_VERSION) {
$io->success('Already on latest version.');
return Command::SUCCESS;
}
}
require SYSTEM . 'migrate.php';
$io->success('Migrated to latest version (' . DATABASE_VERSION . ')');

View File

@@ -10,8 +10,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateRunCommand extends Command
{
use Env;
protected function configure(): void
{
$this->setName('migrate:run')
@@ -25,12 +23,12 @@ class MigrateRunCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
require SYSTEM . 'init.php';
$io = new SymfonyStyle($input, $output);
$ids = $input->getArgument('id');
$this->init();
// pre-check
// in case one of the migrations doesn't exist - we won't execute any of them
foreach ($ids as $id) {

View File

@@ -11,8 +11,6 @@ use Symfony\Component\Console\Style\SymfonyStyle;
class MigrateToCommand extends Command
{
use Env;
protected function configure(): void
{
$this->setName('migrate:to')
@@ -34,7 +32,7 @@ class MigrateToCommand extends Command
return Command::FAILURE;
}
$this->init();
$this->initEnv();
$currentVersion = Config::where('name', 'database_version')->first()->value;
if ($currentVersion > $versionDest) {
@@ -82,4 +80,29 @@ class MigrateToCommand extends Command
updateDatabaseConfig('database_version', ($_up ? $id : $id - 1));
}
private function initEnv()
{
global $config;
if (!isset($config['installed']) || !$config['installed']) {
throw new \RuntimeException('MyAAC has not been installed yet or there was error during installation. Please install again.');
}
if(empty($config['server_path'])) {
throw new \RuntimeException('Server Path has been not set. Go to config.php and set it.');
}
// take care of trailing slash at the end
if($config['server_path'][strlen($config['server_path']) - 1] !== '/')
$config['server_path'] .= '/';
$config['lua'] = load_config_lua($config['server_path'] . 'config.lua');
// POT
require_once SYSTEM . 'libs/pot/OTS.php';
$ots = POT::getInstance();
$eloquentConnection = null;
require_once SYSTEM . 'database.php';
}
}

View File

@@ -13,7 +13,6 @@ class PluginDisableCommand extends Command
protected function configure(): void
{
$this->setName('plugin:disable')
->setAliases(['plugin:deactivate'])
->setDescription('This command disables plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to disable');
}

View File

@@ -13,7 +13,6 @@ class PluginEnableCommand extends Command
protected function configure(): void
{
$this->setName('plugin:enable')
->setAliases(['plugin:activate'])
->setDescription('This command enables plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to enable');
}

View File

@@ -13,7 +13,6 @@ class PluginUninstallCommand extends Command
protected function configure(): void
{
$this->setName('plugin:uninstall')
->setAliases(['plugin:remove', 'plugin:delete'])
->setDescription('This command uninstalls plugin')
->addArgument('plugin-name', InputArgument::REQUIRED, 'Plugin that you want to uninstall');
}

View File

@@ -149,10 +149,7 @@ class CreateCharacter
if($db->hasColumn('players', 'direction'))
$player->setDirection($playerSample->getDirection());
if($db->hasColumn('players', 'conditions')) {
$player->setConditions($playerSample->getConditions());
}
$player->setConditions($playerSample->getConditions());
$rank = $playerSample->getRank();
if($rank->isLoaded()) {
$player->setRank($playerSample->getRank());
@@ -186,11 +183,7 @@ class CreateCharacter
$player->setLookHead($playerSample->getLookHead());
$player->setLookLegs($playerSample->getLookLegs());
$player->setLookType($playerSample->getLookType());
if($db->hasColumn('players', 'cap')) {
$player->setCap($playerSample->getCap());
}
$player->setCap($playerSample->getCap());
$player->setBalance(0);
$player->setPosX(0);
$player->setPosY(0);

View File

@@ -231,7 +231,6 @@ class Forum
if(!is_int($rows / 2)) { $bgcolor = 'ABED25'; } else { $bgcolor = '23ED25'; } $rows++;
$text = str_ireplace('[code]'.$code.'[/code]', '<i>Code:</i><br /><table cellpadding="0" style="background-color: #'.$bgcolor.'; width: 480px; border-style: dotted; border-color: #CCCCCC; border-width: 2px"><tr><td>'.$code.'</td></tr></table>', $text);
}
$rows = 0;
while(stripos($text, '[quote]') !== false && stripos($text, '[/quote]') !== false )
{
@@ -239,31 +238,11 @@ class Forum
if(!is_int($rows / 2)) { $bgcolor = 'AAAAAA'; } else { $bgcolor = 'CCCCCC'; } $rows++;
$text = str_ireplace('[quote]'.$quote.'[/quote]', '<table cellpadding="0" style="background-color: #'.$bgcolor.'; width: 480px; border-style: dotted; border-color: #007900; border-width: 2px"><tr><td>'.$quote.'</td></tr></table>', $text);
}
$tagsToParse = [
'url' => function ($str) {
return '<a href="'.$str.'" target="_blank">'.$str.'</a>';
},
'player' => function ($str) {
return generateLink(getPlayerLink($str, false), $str, true);
},
'guild' => function ($str) {
return generateLink(getGuildLink($str, false), $str, true);
},
'house' => function ($str) {
return generateLink(getHouseLink($str, false), $str, true);
}
];
foreach ($tagsToParse as $tag => $callback) {
while(stripos($text, "[$tag]") !== false && stripos($text, "[/$tag]") !== false
&& stripos($text, "[$tag]") < stripos($text, "[/$tag]"))
{
$length = strlen("[$tag]");
$substr = substr($text, stripos($text, "[$tag]") + $length, stripos($text, "[/$tag]") - stripos($text, "[$tag]") - $length);
$text = str_ireplace('[' . $tag . ']' . $substr . '[/' . $tag . ']', $callback($substr), $text);
}
$rows = 0;
while(stripos($text, '[url]') !== false && stripos($text, '[/url]') !== false )
{
$url = substr($text, stripos($text, '[url]')+5, stripos($text, '[/url]') - stripos($text, '[url]') - 5);
$text = str_ireplace('[url]'.$url.'[/url]', '<a href="'.$url.'" target="_blank">'.$url.'</a>', $text);
}
$xhtml = false;
@@ -273,6 +252,9 @@ class Forum
'#\[u\](.*?)\[/u\]#si' => ($xhtml ? '<span style="text-decoration: underline;">\\1</span>' : '<u>\\1</u>'),
'#\[s\](.*?)\[/s\]#si' => ($xhtml ? '<strike>\\1</strike>' : '<s>\\1</s>'),
'#\[guild\](.*?)\[/guild\]#si' => urldecode(generateLink(getGuildLink('$1', false), '$1', true)),
'#\[house\](.*?)\[/house\]#si' => urldecode(generateLink(getHouseLink('$1', false), '$1', true)),
'#\[player\](.*?)\[/player\]#si' => urldecode(generateLink(getPlayerLink('$1', false), '$1', true)),
// TODO: [poll] tag
'#\[color=(.*?)\](.*?)\[/color\]#si' => ($xhtml ? '<span style="color: \\1;">\\2</span>' : '<span style="color: \\1">\\2</span>'),

View File

@@ -76,11 +76,10 @@ class Items
public static function get($id) {
self::load();
return self::$items[$id] ?? [];
return isset(self::$items[$id]) ? self::$items[$id] : [];
}
public static function getDescription($id, $count = 1): string
{
public static function getDescription($id, $count = 1) {
$item = self::get($id);
$attr = $item['attributes'];
@@ -113,15 +112,15 @@ class Items
$s .= 'an item of type ' . $item['id'];
if(isset($attr['type']) && strtolower($attr['type']) == 'rune') {
$spell = Spell::where('item_id', $id)->first();
if($spell) {
if($spell->level > 0 && $spell->maglevel > 0) {
$s .= '. ' . ($count > 1 ? 'They' : 'It') . ' can only be used by ';
$item = Spell::where('item_id', $id)->first();
if($item) {
if($item->level > 0 && $item->maglevel > 0) {
$s .= '. ' . ($count > 1 ? "They" : "It") . ' can only be used by ';
}
$configVocations = config('vocations');
if(!empty(trim($spell->vocations))) {
$vocations = json_decode($spell->vocations);
if(!empty(trim($item->vocations))) {
$vocations = json_decode($item->vocations);
if(count($vocations) > 0) {
foreach($vocations as $voc => $show) {
$vocations[$configVocations[$voc]] = $show;
@@ -134,39 +133,8 @@ class Items
$s .= ' with';
if ($spell->level > 0) {
$s .= ' level ' . $spell->level;
}
if ($spell->maglevel > 0) {
if ($spell->level > 0) {
$s .= ' and';
}
$s .= ' magic level ' . $spell->maglevel;
}
$s .= ' or higher';
}
}
if (!empty($item['weaponType'])) {
if ($item['weaponType'] == 'distance' && isset($item['ammoType'])) {
$s .= ' (Range:' . $item['range'];
}
if (isset($item['attack']) && $item['attack'] != 0) {
$s .= ', Atk ' . ($item['attack'] > 0 ? '+' . $item['attack'] : '-' . $item['attack']);
}
if (isset($item['hitChance']) && $item['hitChance'] != -1) {
$s .= ', Hit% ' . ($item['hitChance'] > 0 ? '+' . $item['hitChance'] : '-' . $item['hitChance']);
}
elseif ($item['weaponType'] != 'ammo') {
}
}
return $s;
}
}

View File

@@ -5,15 +5,11 @@ namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
/**
* @property integer $premium_ends_at
* @property integer $premend
* @property integer $lastday
* @property integer $premdays
*/
class Account extends Model {
const GRATIS_PREMIUM_DAYS = 65535;
protected $table = 'accounts';
public $timestamps = false;
@@ -37,35 +33,32 @@ class Account extends Model {
public function getPremiumDaysAttribute()
{
if(isset($this->premium_ends_at) || isset($this->premend) ||
(isCanary() && isset($this->lastday))) {
$col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend'));
$ret = ceil(($this->{$col} - time()) / (24 * 60 * 60));
return max($ret, 0);
if(isset($this->premium_ends_at) || isset($this->premend)) {
$col = isset($this->premium_ends_at) ? 'premium_ends_at' : 'premend';
$ret = ceil(($this->{$col}- time()) / (24 * 60 * 60));
return $ret > 0 ? $ret : 0;
}
if($this->premdays == 0) {
return 0;
}
if($this->premdays == self::GRATIS_PREMIUM_DAYS){
return self::GRATIS_PREMIUM_DAYS;
if($this->premdays == 65535){
return 65535;
}
$ret = ceil($this->premdays - ((int)date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday)));
return max($ret, 0);
}
public function getIsPremiumAttribute(): bool
public function getIsPremiumAttribute()
{
if(isset($this->premium_ends_at) || isset($this->premend) ||
(isCanary() && isset($this->lastday))) {
$col = (isset($this->premium_ends_at) ? 'premium_ends_at' : (isset($this->lastday) ? 'lastday' : 'premend'));
return $this->{$col} > time();
if(isset($this->premium_ends_at)) {
return $this->premium_ends_at > time();
}
if($this->premdays == self::GRATIS_PREMIUM_DAYS){
return true;
if(isset($this->premend)) {
return $this->premend > time();
}
return ($this->premdays - (date("z", time()) + (365 * (date("Y", time()) - date("Y", $this->lastday))) - date("z", $this->lastday)) > 0);

View File

@@ -9,6 +9,6 @@ class AccountAction extends Model {
public $timestamps = false;
protected $fillable = ['account_id', 'ip', 'date', 'action'];
protected $fillable = ['account_id', 'ip', 'ipv6', 'date', 'action'];
}

View File

@@ -0,0 +1,14 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class AccountEMailCode extends Model {
protected $table = TABLE_PREFIX . 'account_email_codes';
public $timestamps = false;
protected $fillable = ['account_id', 'code', 'created_at'];
}

View File

@@ -1,15 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class AccountEmailVerify extends Model
{
protected $table = TABLE_PREFIX . 'account_emails_verify';
public $timestamps = false;
protected $fillable = ['account_id', 'hash', 'sent_at'];
}

View File

@@ -18,16 +18,7 @@ class Changelog extends Model {
public $timestamps = false;
protected $fillable = [
'body', 'type', 'where',
'date', 'player_id', 'hide',
];
public function scopeIsPublic($query) {
$query->where('hide', '!=', 1);
}
public function player() {
return $this->belongsTo(Player::class);
}
}

View File

@@ -1,16 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class ForumBoard extends Model {
protected $table = TABLE_PREFIX . 'forum_boards';
public $timestamps = false;
protected $fillable = [
'name', 'description', 'ordering',
'guild', 'access', 'closed', 'hide',
];
}

View File

@@ -10,9 +10,4 @@ class Gallery extends Model {
public $timestamps = false;
protected $fillable = [
'comment', 'image', 'thumb',
'author', 'ordering', 'hide',
];
}

View File

@@ -9,6 +9,6 @@ class Menu extends Model {
public $timestamps = false;
protected $fillable = ['template', 'name', 'link', 'access', 'blank', 'color', 'category', 'ordering', 'enabled'];
protected $fillable = ['template', 'name', 'link', 'blank', 'color', 'category', 'ordering', 'enabled'];
}

View File

@@ -1,15 +0,0 @@
<?php
namespace MyAAC\Models;
use Illuminate\Database\Eloquent\Model;
class NewsCategory extends Model {
protected $table = TABLE_PREFIX . 'news_categories';
public $timestamps = false;
protected $fillable = [
'name', 'description', 'icon_id', 'hide'
];
}

View File

@@ -23,8 +23,6 @@ class Player extends Model {
public $timestamps = false;
protected $guarded = [];
protected $casts = [
'worldid' => 'integer',
'sex' => 'integer',
@@ -48,8 +46,14 @@ class Player extends Model {
});
}
public function getVocationNameAttribute() {
return \OTS_Toolbox::getVocationName($this->vocation, $this->promotion ?? 0);
public function getVocationNameAttribute()
{
$vocation = $this->vocation;
if (isset($this->promotion) && $this->promotion > 0) {
$vocation += ($this->promotion * setting('core.vocations_amount'));
}
return config('vocations')[$vocation] ?? 'Unknown';
}
public function getIsDeletedAttribute()

Some files were not shown because too many files have changed in this diff Show More