Compare commits

..

16 Commits

Author SHA1 Message Date
slawkens
8d76e4e670 Merge branch 'develop' into feature/docker 2024-12-20 23:03:39 +01:00
slawkens
5e14521f08 Fix docker build 2024-12-20 22:27:57 +01:00
slawkens
335a0d1cff Merge branch 'develop' into feature/docker 2024-12-20 21:20:48 +01:00
slawkens
5735d487d9 Merge branch 'develop' into feature/docker 2024-07-14 06:01:27 +02:00
slawkens
d7e1ca747e Merge branch 'develop' into feature/docker 2024-02-29 16:12:28 +01:00
slawkens
5a9490138b Merge branch 'develop' into feature/docker 2024-02-18 12:12:32 +01:00
slawkens
42e40e5d77 Twig_SimpleFilter is deprecated 2023-09-22 16:18:05 +02:00
slawkens
80a3a72b36 Update .gitignore 2023-09-20 15:55:06 +02:00
slawkens
a4b1631f6d Add missing file 2023-09-20 15:54:44 +02:00
slawkens
49af260c2e Some features for docker users
Disable IP Check on install
automatically fill out server_path
2023-09-17 14:39:02 +02:00
slawkens
72d7ee8bf2 Speed up 20x? By removing volume 2023-09-16 21:49:11 +02:00
slawkens
c503f5e0a5 enable apcu & opcache 2023-09-16 19:10:56 +02:00
slawkens
03b2d71572 [wip] docker setup
It's working now
2023-09-16 18:20:08 +02:00
slawkens
86b94ea5e8 Merge branch 'develop' into feature/docker 2023-09-16 14:41:28 +02:00
slawkens
e9b5617748 Create Dockerfile 2023-09-16 14:40:58 +02:00
slawkens
fee9d60da4 Create docker-compose.yml 2023-09-16 14:40:55 +02:00
73 changed files with 2861 additions and 2734 deletions

65
.dockerignore Normal file
View File

@@ -0,0 +1,65 @@
Thumbs.db
.DS_Store
.idea
#
/.htaccess
# composer
composer.phar
vendor
# npm
node_modules
tools/ext
# cypress
cypress.env.json
cypress/e2e/2-advanced-examples
cypress/screenshots
# created by release.sh
releases
tmp
config.local.php
!docker/config.local.php
# all custom templates
templates/*
!templates/tibiacom
!templates/kathrine
# guild images
images/guilds/*
!images/guilds/default.gif
# editor images
images/editor/*
!images/editor/index.html
# gallery images
images/gallery/*
!images/gallery/index.html
!images/gallery/demon.jpg
!images/gallery/demon_thumb.gif
# cache
system/cache/*
!system/cache/index.html
!system/cache/twig/index.html
!system/cache/signatures/index.html
!system/cache/plugins/index.html
!system/cache/persistent/index.html
# logs
system/logs/*
!system/logs/index.html
# data
system/data/*
!system/data/index.html
# php sessions
system/php_sessions/*
!system/php_sessions/index.html

View File

@@ -1,9 +1,9 @@
name: Cypress name: Cypress
on: on:
pull_request: pull_request:
branches: [main] branches: [develop]
push: push:
branches: [main] branches: [develop]
jobs: jobs:
cypress: cypress:
@@ -35,7 +35,7 @@ jobs:
- name: Checkout MyAAC - name: Checkout MyAAC
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
ref: main ref: develop
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:

View File

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

View File

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

5
.gitignore vendored
View File

@@ -4,7 +4,6 @@ Thumbs.db
# #
/.htaccess /.htaccess
lua
# composer # composer
composer.phar composer.phar
@@ -24,6 +23,7 @@ releases
tmp tmp
config.local.php config.local.php
!docker/config.local.php
# all custom templates # all custom templates
templates/* templates/*
@@ -76,3 +76,6 @@ landing
# system # system
system/functions_custom.php system/functions_custom.php
# others/rest
system/pages/downloads.php

View File

@@ -1,92 +1,5 @@
# Changelog # Changelog
## [1.2 - 09.02.2025]
### Added
* Twig session(key) function + reworked session functions to accept multi-array like in Laravel (https://github.com/slawkens/myaac/commit/b46ddb43d03ef7e5fc34e555e92e856bdc905691)
* add template_name to twig variables (https://github.com/slawkens/myaac/commit/ae1161d77050bda181802b4496c9de920a7bb1bc)
* add HOOK_INIT, executed just after $hooks are loaded (https://github.com/slawkens/myaac/commit/19686725dc810f63a07f049f82c66cf336d90ca6)
### Changed
* settings: password input hide/show, enable Save button only if changes has been made, save settings in transaction (https://github.com/slawkens/myaac/commit/4fda4f643b60a151179e5dd4f04912fb2618d98f, https://github.com/slawkens/myaac/commit/28fef952f857b79d64bc7495ffa5e1999e68e192, https://github.com/slawkens/myaac/commit/4b6024dc451accadb6c469fa282a9a764c1c0a81)
* rework menus: Different categories can have different colors + Option to reset menus (https://github.com/slawkens/myaac/commit/73de93a561f6b13111e019075724357d8a617249, https://github.com/slawkens/myaac/commit/3da3e62c5b12390d75de9b3320729bcca6e0b458)
### Fixed
* highscores: Fix online status + vocation for TFS 0.x (https://github.com/slawkens/myaac/commit/ea51ad27c38be88d86514cb979bb394fcfbef1f0)
* clear cache button in admin bar needed to be clicked twice until it worked (https://github.com/slawkens/myaac/commit/ea51ad27c38be88d86514cb979bb394fcfbef1f0)
* HOOK_STARTUP location (https://github.com/slawkens/myaac/commit/a73fb1003ee3f812cf182d1834d65f08e6f60d1f)
* if vocation name has more words (https://github.com/slawkens/myaac/commit/9d7fc98e1e0a96b59ecc1a7c39800a64445db364)
### Updated
* Bump twig/twig from 3.18.0 to 3.19.0 (#284)
## [1.1 - 27.01.2025]
### Changed
* adjust mailer settings descriptions to latest gmail (https://github.com/slawkens/myaac/commit/c5d5bb80671db135e6b503f53684771c7272e05d)
* optimize $player->isOnline() function, thanks @gesior (https://github.com/slawkens/myaac/commit/10dd818b139d5e1bb1ca9ec81edfb083ba9316b4)
* make players.comment and guilds.description VARCHAR (https://github.com/slawkens/myaac/commit/a45ceab83a74bee2b89cdb72baceda75e577e3cf)
* add lua/ folder to .gitignore (https://github.com/slawkens/myaac/commit/07012f786b1114cb6ab2f064f82c645b136a375a)
### Fixed
* general fixes in the tibiacom template menus, better support for custom menus
* make functions_custom.php optional (https://github.com/slawkens/myaac/commit/dc2b5afd9980984e2b259c9fc99f2ade46f70a5a)
* error in CLI, where BASE_URL is not defined (https://github.com/slawkens/myaac/commit/4d749b881582f64b5a46196dbbb5ee8097127f03)
* hook ACCOUNT_LOGIN_BEFORE_ACCOUNT location (https://github.com/slawkens/myaac/commit/669c447fca8643ce56d9ef8c1374ec647c780998)
## [1.0.1 - 14.01.2025]
### Fixed
* tibiacom account & news menu links not auto expanding
### Updated (Thanks dependabot)
* twig from ^2.0 to ^3.11
* tinymce from ^6.8.3 to ^7.2.0
* cypress from ^12.12.0 to ^13.17.0
* nesbot/carbon from 2.72.5 to 2.72.6
## [1.0 - 12.01.2025]
First stable release in the v1.0 series.
Minimum PHP 8.1 is required.
Changes since RC.2:
### Added
* feature: migrations up/down. Allows to downgrade/upgrade database to specified version (https://github.com/slawkens/myaac/commit/3f6ff3a3326b0475d28d11ffd7fff51f362d799f)
* new hooks for news management (https://github.com/slawkens/myaac/commit/011a85d8ae34283ded6999882833f9d4797028ec, https://github.com/slawkens/myaac/commit/36bd3eb846e829b45313e10f7568dc4e95841143)
* None Vocation to highscores (can be changed to RookStayer in Admin Panel) (https://github.com/slawkens/myaac/commit/a4a248099521bb5b8b2aa5bd592138debd2f19d5)
* support for button_color (green, red, blue) (https://github.com/slawkens/myaac/commit/d8b6b749ee62e88b6af4a05d3d7557f90b94d94e)
* add $whoopsHandler as variable, can be used by plugins (https://github.com/slawkens/myaac/commit/b0c8cf2ecda23045d725aaf43cfb3852ed766a4b)
* PlayerModel->outfit_url attribute (https://github.com/slawkens/myaac/commit/3b5be1a8db5dceecaa388e2925a5536d13b38881)
* support for selecting plugin themes in Admin menus.php (https://github.com/slawkens/myaac/commit/77a2c1cec343ffe4be5c2c2503ee81bc32a14ca1)
### Changed
* schema: Change character set to utf8mb4 (support for Emojis in Menus/Pages/News/Forum etc.) (https://github.com/slawkens/myaac/commit/27c44f1bdfb6234cf0c9d5b4b491123bb205b08f)
* prefer get_browser_real_ip() over REMOTE_ADDR (https://github.com/slawkens/myaac/commit/941846605c00cee83168d2f916410b8ba8d4b7b9)
* automatically set selected current one on highscores filters (https://github.com/slawkens/myaac/commit/e96227fbe41ae281783b2d49edb169a603601813)
* rewrite towns loading code, removed OTBM loader (was too slow) (https://github.com/slawkens/myaac/commit/c980a0914632e7b27f718464f669a200707d217e)
* allow OTS_Player to be passed as object to getPlayerLink (https://github.com/slawkens/myaac/commit/84d37c5a8f2c4535a41c8aa8264752969d3f3a3d)
* do not clear menus by default on install (https://github.com/slawkens/myaac/commit/12d8faa3eda5e798f97b71e941c035187daad96e)
* display warning in admin panel - plugins - if zip extension is not installed (https://github.com/slawkens/myaac/commit/e3ffe5d9e11d78ab064a370d8541bac351c9bcd9)
* set default_socket_timeout for ipinfo.io checkup to 5 seconds (https://github.com/slawkens/myaac/commit/783d96fc6568a607d3198b832fed3a0dd06c4ebb)
* refactor getTopPlayers function (support for balance) (https://github.com/slawkens/myaac/commit/c769962e39fe8dfb72ecd5be1864e145696be794)
### Fixed
* XSS in forum (https://github.com/slawkens/myaac/commit/c2b7286d20d4b579171540f7a774e8a0995d5e8f, https://github.com/slawkens/myaac/commit/8fb643596f9586005976e7bdb484a541a9d8715e)
* price deducted when changing sex (https://github.com/slawkens/myaac/commit/16671ea40b72dcf74037c359ad572f9eb825edf9)
* move_thread by unauthorized user (https://github.com/slawkens/myaac/commit/d6c40c836a53cb1710f911f77f45f28b54ea1b54, thanks @anyeor)
* TFS 1.4.2 where conditions is NULL (https://github.com/slawkens/myaac/commit/b8396d4c8482e951da538b13f2296123732c4545)
* do not show forum new thread show button if not logged in (https://github.com/slawkens/myaac/commit/507402171ba3b6e7ee184bd7fa73e0d55e0cad7a, @anyeor)
* login if limiter is disabled (https://github.com/slawkens/myaac/commit/a0f1971583f0f790013e2145fb5ac573c59fbdef)
* fixes to installMenus function (https://github.com/slawkens/myaac/commit/a2fadc5945fe0a5e39f740827f6ffbda1bb501e2)
* many PHP exceptions in different places
* fixes to tibiacom menus ActiveSubmenuItem
### Removed
* bugtracker SQL table code as the page has been removed/moved to plugins (https://github.com/slawkens/myaac/commit/5782772b901b05fb814bc718d062f6e2cd71df8c)
## [1.0-RC.2 - 25.10.2024] ## [1.0-RC.2 - 25.10.2024]
Still waiting for your reports about bugs found in this release. We are very close to stable release. Still waiting for your reports about bugs found in this release. We are very close to stable release.
@@ -174,6 +87,7 @@ Minimum PHP version for this release is 8.1.
* support for login and create account only by email (configurable) * support for login and create account only by email (configurable)
* with no need for account name * with no need for account name
* Google ReCAPTCHA v3 support (available as plugin) * Google ReCAPTCHA v3 support (available as plugin)
* automatically load towns names from .OTBM file
* support for Account Number * support for Account Number
* suggest account number option * suggest account number option
* many new functions, hooks and configurables * many new functions, hooks and configurables
@@ -202,4 +116,4 @@ Minimum PHP version for this release is 8.1.
* change_password email to be more informal * change_password email to be more informal
### Fixed ### Fixed
* hundreds of bug fixes, mostly patched from 0.8, so it makes no sense writing them again here * hundrets of bug fixes, mostly patched from 0.8, so it makes no sense writing them again here

View File

@@ -1,3 +1,3 @@
* Gesior.pl (2007 - 2008) * Gesior.pl (2007 - 2008)
* Slawkens (2009 - 2025) * Slawkens (2009 - 2023)
* Contributors listed in CONTRIBUTORS.txt * Contributors listed in CONTRIBUTORS.txt

View File

@@ -10,12 +10,12 @@ Official website: https://my-aac.org
[![OpenTibia Discord](https://img.shields.io/discord/288399552581468162)](https://discord.gg/2J39Wus) [![OpenTibia Discord](https://img.shields.io/discord/288399552581468162)](https://discord.gg/2J39Wus)
[![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed) [![Closed Issues](https://img.shields.io/github/issues-closed-raw/slawkens/myaac)](https://github.com/slawkens/myaac/issues?q=is%3Aissue+is%3Aclosed)
| Version | Status | Branch | Requirements | | Version | Status | Branch | Requirements |
|:--------|:-----------------------|:-------|:---------------| |:--------|:-----------------------|:--------|:---------------|
| **1.x** | **Active development** | master | **PHP >= 8.1** | | **1.x** | **Active development** | develop | **PHP >= 8.1** |
| 0.9.x | Not developed anymore | 0.9 | PHP >= 7.2.5 | | 0.9.x | Not developed anymore | 0.9 | PHP >= 7.2.5 |
| 0.8.x | Active support | 0.8 | PHP >= 7.2.5 | | 0.8.x | Active support | master | PHP >= 7.2.5 |
| 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 | | 0.7.x | End Of Life | 0.7 | PHP >= 5.3.3 |
### Requirements ### Requirements

View File

@@ -10,7 +10,6 @@
use MyAAC\Cache\Cache; use MyAAC\Cache\Cache;
use MyAAC\Models\Menu; use MyAAC\Models\Menu;
use MyAAC\Plugins;
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$title = 'Menus'; $title = 'Menus';
@@ -22,8 +21,6 @@ if (!hasFlag(FLAG_CONTENT_MENUS) && !superAdmin()) {
return; return;
} }
$pluginThemes = Plugins::getThemes();
if (isset($_POST['template'])) { if (isset($_POST['template'])) {
$template = $_POST['template']; $template = $_POST['template'];
@@ -59,67 +56,54 @@ if (isset($_POST['template'])) {
} }
} }
onTemplateMenusChange(); $cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('template_menus');
}
success('Saved at ' . date('H:i')); success('Saved at ' . date('H:i'));
} }
$path = TEMPLATES . $template; $file = TEMPLATES . $template . '/config.php';
if (file_exists($file)) {
if (isset($pluginThemes[$template])) { require_once $file;
$path = BASE . $pluginThemes[$template];
}
$path .= '/config.php';
if (file_exists($path)) {
require_once $path;
} else { } else {
echo 'Cannot find template config.php file.'; echo 'Cannot find template config.php file.';
return; return;
} }
if (isset($_GET['reset_colors'])) {
if (isset($config['menu_default_color'])) {
Menu::where('template', $template)->update(['color' => str_replace('#', '', $config['menu_default_color'])]);
success('Colors has been reset.');
}
else {
warning('There is no default color defined, cannot reset colors.');
}
}
if (!isset($config['menu_categories'])) { if (!isset($config['menu_categories'])) {
echo "No menu categories set in template config.php.<br/>This template doesn't support dynamic menus."; echo "No menu categories set in template config.php.<br/>This template doesn't support dynamic menus.";
return; return;
} }
if (isset($_GET['reset_colors'])) {
foreach ($config['menu_categories'] as $id => $options) {
$color = $options['default_links_color'] ?? ($config['menu_default_links_color'] ?? ($config['menu_default_color'] ?? '#ffffff'));
Menu::where('template', $template)->where('category', $id)->update(['color' => str_replace('#', '', $color)]);
}
onTemplateMenusChange();
success('Colors has been reset at ' . date('H:i'));
}
if (isset($_GET['reset_menus'])) {
$configMenus = config('menus');
if (isset($configMenus)) {
Plugins::installMenus($template, config('menus'), true);
onTemplateMenusChange();
success('Menus has been reset at ' . date('H:i'));
}
else {
error("This template don't support reinstalling menus.");
}
}
$title = 'Menus - ' . $template; $title = 'Menus - ' . $template;
$canResetColors = isset($config['menu_default_color']) || isset($config['menu_default_links_color']);
foreach ($config['menu_categories'] as $id => $options) {
if (isset($options['default_links_color'])) {
$canResetColors = true;
}
}
$twig->display('admin.menus.header.html.twig', [
'template' => $template,
'canResetColors' => $canResetColors
]);
?> ?>
<div align="center" class="text-center">
<p class="note">You are editing: <?= $template ?><br/><br/>
Hint: You can drag menu items.<br/>
Hint: Add links to external sites using: <b>http://</b> or <b>https://</b> prefix.<br/>
Not all templates support blank and colorful links.
</p>
<?php if (isset($config['menu_default_color'])) {?>
<form method="post" action="?p=menus&reset_colors" onsubmit="return confirm('Do you really want to reset colors?');">
<?php csrf(); ?>
<input type="hidden" name="template" value="<?php echo $template ?>"/>
<button type="submit" class="btn btn-danger">Reset Colors to default</button>
</form>
<br/>
<?php } ?>
</div>
<?php <?php
$menus = Menu::query() $menus = Menu::query()
->select('name', 'link', 'blank', 'color', 'category', 'ordering') ->select('name', 'link', 'blank', 'color', 'category', 'ordering')
@@ -149,13 +133,12 @@ if (isset($_POST['template'])) {
if (isset($menus[$id])) { if (isset($menus[$id])) {
$i = 0; $i = 0;
foreach ($menus[$id] as $menu): 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>Name:</label> <input type="text" name="menu[<?php echo $id ?>][]" value="<?php echo escapeHtml($menu['name']); ?>"/> <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'] ?>"/> <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"/> <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> <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; ?>"/> <input class="color-picker" type="text" name="menu_color[<?php echo $id ?>][]" value="<?php echo (empty($menu['color']) ? ($config['menu_default_color'] ?? '#ffffff') : $menu['color']); ?>"/>
<a class="remove-button" id="remove-button-<?php echo $id ?>-<?php echo $i ?>"><i class="fas fa-trash"></a></i></li> <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; <?php $i++; $last_id[$id] = $i;
endforeach; endforeach;
@@ -179,19 +162,15 @@ if (isset($_POST['template'])) {
$twig->display('admin.menus.js.html.twig', array( $twig->display('admin.menus.js.html.twig', array(
'menus' => $menus, 'menus' => $menus,
'last_id' => $last_id, 'last_id' => $last_id,
'menu_default_color' => $config['menu_default_color'] ?? '#ffffff'
)); ));
?> ?>
<?php <?php
} else { } else {
$templates = Menu::select('template')->distinct()->get()->toArray(); $templates = Menu::select('template')->distinct()->get()->toArray();
foreach ($templates as $key => $value) { foreach ($templates as $key => $value) {
$path = TEMPLATES . $value['template']; $file = TEMPLATES . $value['template'] . '/config.php';
if (!file_exists($file)) {
if (isset($pluginThemes[$value['template']])) {
$path = BASE . $pluginThemes[$value['template']];
}
if (!file_exists($path . '/config.php')) {
unset($templates[$key]); unset($templates[$key]);
} }
} }
@@ -200,11 +179,3 @@ if (isset($_POST['template'])) {
'templates' => $templates 'templates' => $templates
)); ));
} }
function onTemplateMenusChange(): void
{
$cache = Cache::getInstance();
if ($cache->enabled()) {
$cache->delete('template_menus');
}
}

View File

@@ -26,8 +26,8 @@
if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.'); if (version_compare(phpversion(), '8.1', '<')) die('PHP version 8.1 or higher is required.');
const MYAAC = true; const MYAAC = true;
const MYAAC_VERSION = '1.2'; const MYAAC_VERSION = '1.0-RC.2';
const DATABASE_VERSION = 43; const DATABASE_VERSION = 41;
const TABLE_PREFIX = 'myaac_'; const TABLE_PREFIX = 'myaac_';
define('START_TIME', microtime(true)); define('START_TIME', microtime(true));
define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX')); define('MYAAC_OS', stripos(PHP_OS, 'WIN') === 0 ? 'WINDOWS' : (strtoupper(PHP_OS) === 'DARWIN' ? 'MAC' : 'LINUX'));

View File

@@ -8,7 +8,7 @@
"ext-dom": "*", "ext-dom": "*",
"phpmailer/phpmailer": "^6.1", "phpmailer/phpmailer": "^6.1",
"composer/semver": "^3.2", "composer/semver": "^3.2",
"twig/twig": "^3.11", "twig/twig": "^2.0",
"erusev/parsedown": "^1.7", "erusev/parsedown": "^1.7",
"nikic/fast-route": "^1.3", "nikic/fast-route": "^1.3",
"matomo/device-detector": "^6.0", "matomo/device-detector": "^6.0",

295
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "be4d1489a53a9cd8eec6bcaa7a096f30", "content-hash": "27c63d07ab6337cd8bb5b59f2b2e08d8",
"packages": [ "packages": [
{ {
"name": "brick/math", "name": "brick/math",
@@ -885,16 +885,16 @@
}, },
{ {
"name": "matomo/device-detector", "name": "matomo/device-detector",
"version": "6.4.2", "version": "6.4.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/matomo-org/device-detector.git", "url": "https://github.com/matomo-org/device-detector.git",
"reference": "806e52d214b05ddead1a1d4304c7592f61f95976" "reference": "0d364e0dd6c177da3c24cd4049178026324fd7ac"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/matomo-org/device-detector/zipball/806e52d214b05ddead1a1d4304c7592f61f95976", "url": "https://api.github.com/repos/matomo-org/device-detector/zipball/0d364e0dd6c177da3c24cd4049178026324fd7ac",
"reference": "806e52d214b05ddead1a1d4304c7592f61f95976", "reference": "0d364e0dd6c177da3c24cd4049178026324fd7ac",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -950,20 +950,20 @@
"source": "https://github.com/matomo-org/matomo", "source": "https://github.com/matomo-org/matomo",
"wiki": "https://dev.matomo.org/" "wiki": "https://dev.matomo.org/"
}, },
"time": "2024-12-16T16:38:01+00:00" "time": "2024-09-24T13:50:04+00:00"
}, },
{ {
"name": "maximebf/debugbar", "name": "maximebf/debugbar",
"version": "v1.23.5", "version": "v1.23.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/php-debugbar/php-debugbar.git", "url": "https://github.com/maximebf/php-debugbar.git",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25" "reference": "687400043d77943ef95e8417cb44e1673ee57844"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/php-debugbar/php-debugbar/zipball/eeabd61a1f19ba5dcd5ac4585a477130ee03ce25", "url": "https://api.github.com/repos/maximebf/php-debugbar/zipball/687400043d77943ef95e8417cb44e1673ee57844",
"reference": "eeabd61a1f19ba5dcd5ac4585a477130ee03ce25", "reference": "687400043d77943ef95e8417cb44e1673ee57844",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1015,10 +1015,10 @@
"debugbar" "debugbar"
], ],
"support": { "support": {
"issues": "https://github.com/php-debugbar/php-debugbar/issues", "issues": "https://github.com/maximebf/php-debugbar/issues",
"source": "https://github.com/php-debugbar/php-debugbar/tree/v1.23.5" "source": "https://github.com/maximebf/php-debugbar/tree/v1.23.3"
}, },
"time": "2024-12-15T19:20:42+00:00" "time": "2024-10-29T12:24:25+00:00"
}, },
{ {
"name": "mustangostang/spyc", "name": "mustangostang/spyc",
@@ -1076,16 +1076,16 @@
}, },
{ {
"name": "nesbot/carbon", "name": "nesbot/carbon",
"version": "2.72.6", "version": "2.72.5",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/CarbonPHP/carbon.git", "url": "https://github.com/briannesbitt/Carbon.git",
"reference": "1e9d50601e7035a4c61441a208cb5bed73e108c5" "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1e9d50601e7035a4c61441a208cb5bed73e108c5", "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/afd46589c216118ecd48ff2b95d77596af1e57ed",
"reference": "1e9d50601e7035a4c61441a208cb5bed73e108c5", "reference": "afd46589c216118ecd48ff2b95d77596af1e57ed",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1105,7 +1105,7 @@
"doctrine/orm": "^2.7 || ^3.0", "doctrine/orm": "^2.7 || ^3.0",
"friendsofphp/php-cs-fixer": "^3.0", "friendsofphp/php-cs-fixer": "^3.0",
"kylekatarnls/multi-tester": "^2.0", "kylekatarnls/multi-tester": "^2.0",
"ondrejmirtes/better-reflection": "<6", "ondrejmirtes/better-reflection": "*",
"phpmd/phpmd": "^2.9", "phpmd/phpmd": "^2.9",
"phpstan/extension-installer": "^1.0", "phpstan/extension-installer": "^1.0",
"phpstan/phpstan": "^0.12.99 || ^1.7.14", "phpstan/phpstan": "^0.12.99 || ^1.7.14",
@@ -1118,6 +1118,10 @@
], ],
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": {
"dev-master": "3.x-dev",
"dev-2.x": "2.x-dev"
},
"laravel": { "laravel": {
"providers": [ "providers": [
"Carbon\\Laravel\\ServiceProvider" "Carbon\\Laravel\\ServiceProvider"
@@ -1127,10 +1131,6 @@
"includes": [ "includes": [
"extension.neon" "extension.neon"
] ]
},
"branch-alias": {
"dev-2.x": "2.x-dev",
"dev-master": "3.x-dev"
} }
}, },
"autoload": { "autoload": {
@@ -1179,7 +1179,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-27T09:28:11+00:00" "time": "2024-06-03T19:18:41+00:00"
}, },
{ {
"name": "nikic/fast-route", "name": "nikic/fast-route",
@@ -1575,16 +1575,16 @@
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v6.4.17", "version": "v6.4.15",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "799445db3f15768ecc382ac5699e6da0520a0a04" "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/799445db3f15768ecc382ac5699e6da0520a0a04", "url": "https://api.github.com/repos/symfony/console/zipball/f1fc6f47283e27336e7cebb9e8946c8de7bff9bd",
"reference": "799445db3f15768ecc382ac5699e6da0520a0a04", "reference": "f1fc6f47283e27336e7cebb9e8946c8de7bff9bd",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -1649,7 +1649,7 @@
"terminal" "terminal"
], ],
"support": { "support": {
"source": "https://github.com/symfony/console/tree/v6.4.17" "source": "https://github.com/symfony/console/tree/v6.4.15"
}, },
"funding": [ "funding": [
{ {
@@ -1665,7 +1665,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-07T12:07:30+00:00" "time": "2024-11-06T14:19:14+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
@@ -1686,12 +1686,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {
@@ -1760,8 +1760,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": { "thanks": {
"url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill",
"name": "symfony/polyfill" "url": "https://github.com/symfony/polyfill"
} }
}, },
"autoload": { "autoload": {
@@ -1836,8 +1836,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": { "thanks": {
"url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill",
"name": "symfony/polyfill" "url": "https://github.com/symfony/polyfill"
} }
}, },
"autoload": { "autoload": {
@@ -1914,8 +1914,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": { "thanks": {
"url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill",
"name": "symfony/polyfill" "url": "https://github.com/symfony/polyfill"
} }
}, },
"autoload": { "autoload": {
@@ -1998,8 +1998,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": { "thanks": {
"url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill",
"name": "symfony/polyfill" "url": "https://github.com/symfony/polyfill"
} }
}, },
"autoload": { "autoload": {
@@ -2052,6 +2052,71 @@
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2024-09-09T11:45:10+00:00"
}, },
{
"name": "symfony/polyfill-php72",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php72.git",
"reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
"reference": "fa2ae56c44f03bed91a39bfc9822e31e7c5c38ce",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "metapackage",
"extra": {
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 7.2+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php72/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.31.0", "version": "v1.31.0",
@@ -2072,8 +2137,8 @@
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": { "thanks": {
"url": "https://github.com/symfony/polyfill", "name": "symfony/polyfill",
"name": "symfony/polyfill" "url": "https://github.com/symfony/polyfill"
} }
}, },
"autoload": { "autoload": {
@@ -2132,82 +2197,6 @@
], ],
"time": "2024-09-09T11:45:10+00:00" "time": "2024-09-09T11:45:10+00:00"
}, },
{
"name": "symfony/polyfill-php81",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-php81.git",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php81/zipball/4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"reference": "4a4cfc2d253c21a5ad0e53071df248ed48c6ce5c",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Php81\\": ""
},
"classmap": [
"Resources/stubs"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill backporting some PHP 8.1+ features to lower PHP versions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-php81/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
},
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v3.5.1", "version": "v3.5.1",
@@ -2232,12 +2221,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {
@@ -2491,12 +2480,12 @@
}, },
"type": "library", "type": "library",
"extra": { "extra": {
"thanks": {
"url": "https://github.com/symfony/contracts",
"name": "symfony/contracts"
},
"branch-alias": { "branch-alias": {
"dev-main": "3.5-dev" "dev-main": "3.5-dev"
},
"thanks": {
"name": "symfony/contracts",
"url": "https://github.com/symfony/contracts"
} }
}, },
"autoload": { "autoload": {
@@ -2637,38 +2626,38 @@
}, },
{ {
"name": "twig/twig", "name": "twig/twig",
"version": "v3.19.0", "version": "v2.16.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/twigphp/Twig.git", "url": "https://github.com/twigphp/Twig.git",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e" "reference": "19185947ec75d433a3ac650af32fc05649b95ee1"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/d4f8c2b86374f08efc859323dbcd95c590f7124e", "url": "https://api.github.com/repos/twigphp/Twig/zipball/19185947ec75d433a3ac650af32fc05649b95ee1",
"reference": "d4f8c2b86374f08efc859323dbcd95c590f7124e", "reference": "19185947ec75d433a3ac650af32fc05649b95ee1",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0.2", "php": ">=7.1.3",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/polyfill-ctype": "^1.8", "symfony/polyfill-ctype": "^1.8",
"symfony/polyfill-mbstring": "^1.3", "symfony/polyfill-mbstring": "^1.3",
"symfony/polyfill-php81": "^1.29" "symfony/polyfill-php72": "^1.8"
}, },
"require-dev": { "require-dev": {
"phpstan/phpstan": "^2.0", "psr/container": "^1.0",
"psr/container": "^1.0|^2.0", "symfony/phpunit-bridge": "^5.4.9|^6.3"
"symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0"
}, },
"type": "library", "type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.16-dev"
}
},
"autoload": { "autoload": {
"files": [ "psr-0": {
"src/Resources/core.php", "Twig_": "lib/"
"src/Resources/debug.php", },
"src/Resources/escaper.php",
"src/Resources/string_loader.php"
],
"psr-4": { "psr-4": {
"Twig\\": "src/" "Twig\\": "src/"
} }
@@ -2701,7 +2690,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/twigphp/Twig/issues", "issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.19.0" "source": "https://github.com/twigphp/Twig/tree/v2.16.1"
}, },
"funding": [ "funding": [
{ {
@@ -2713,7 +2702,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-01-29T07:06:14+00:00" "time": "2024-09-09T17:53:56+00:00"
}, },
{ {
"name": "voku/portable-ascii", "name": "voku/portable-ascii",
@@ -2851,16 +2840,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "phpstan/phpstan", "name": "phpstan/phpstan",
"version": "1.12.15", "version": "1.12.12",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/phpstan/phpstan.git", "url": "https://github.com/phpstan/phpstan.git",
"reference": "c91d4e8bc056f46cf653656e6f71004b254574d1" "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/c91d4e8bc056f46cf653656e6f71004b254574d1", "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
"reference": "c91d4e8bc056f46cf653656e6f71004b254574d1", "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@@ -2905,7 +2894,7 @@
"type": "github" "type": "github"
} }
], ],
"time": "2025-01-05T16:40:22+00:00" "time": "2024-11-28T22:13:23+00:00"
} }
], ],
"aliases": [], "aliases": [],
@@ -2922,5 +2911,5 @@
"ext-dom": "*" "ext-dom": "*"
}, },
"platform-dev": [], "platform-dev": [],
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

View File

@@ -116,9 +116,9 @@ describe('Check Public Pages', () => {
}) })
// library // library
it('Go to monsters page', () => { it('Go to creatures page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/monsters', url: Cypress.env('URL') + '/creatures',
method: 'GET', method: 'GET',
}) })
}) })

View File

@@ -4,7 +4,7 @@ const YOU_ARE_NOT_LOGGEDIN = 'You are not logged in.';
describe('Check Protected Pages', () => { describe('Check Protected Pages', () => {
// character actions // character actions
it('Go to account character creation page', () => { it('Go to accouht character creation page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/character/create', url: Cypress.env('URL') + '/account/character/create',
method: 'GET', method: 'GET',
@@ -12,7 +12,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account character deletion page', () => { it('Go to accouht character deletion page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/character/delete', url: Cypress.env('URL') + '/account/character/delete',
method: 'GET', method: 'GET',
@@ -21,7 +21,7 @@ describe('Check Protected Pages', () => {
}) })
// account actions // account actions
it('Go to account email change page', () => { it('Go to accouht email change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/email', url: Cypress.env('URL') + '/account/email',
method: 'GET', method: 'GET',
@@ -29,7 +29,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account password change page', () => { it('Go to accouht password change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/password', url: Cypress.env('URL') + '/account/password',
method: 'GET', method: 'GET',
@@ -37,7 +37,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account info change page', () => { it('Go to accouht info change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/info', url: Cypress.env('URL') + '/account/info',
method: 'GET', method: 'GET',
@@ -45,7 +45,7 @@ describe('Check Protected Pages', () => {
cy.contains(REQUIRED_LOGIN_MESSAGE) cy.contains(REQUIRED_LOGIN_MESSAGE)
}) })
it('Go to account logout change page', () => { it('Go to accouht logout change page', () => {
cy.visit({ cy.visit({
url: Cypress.env('URL') + '/account/logout', url: Cypress.env('URL') + '/account/logout',
method: 'GET', method: 'GET',

40
docker-compose.yml Normal file
View File

@@ -0,0 +1,40 @@
services:
web:
ports:
- 8001:80
build:
args:
user: www-data
uid: 33
context: ./
dockerfile: ./docker/Dockerfile
restart: unless-stopped
working_dir: /var/www/html
depends_on:
- db
#volumes:
# - ./:/var/www/html
db:
image: mysql:8.0
restart: unless-stopped # always?
environment:
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
MYSQL_DATABASE: myaac
#MYSQL_ROOT_PASSWORD: root
MYSQL_PASSWORD: myaac
MYSQL_USER: myaac
ports:
- 8003:3306
volumes:
- ./docker/tfs_schema.sql:/docker-entrypoint-initdb.d/tfs_schema.sql
- db:/var/lib/mysql
phpmyadmin:
image: phpmyadmin
restart: always
ports:
- 8002:80
volumes:
db:

56
docker/Dockerfile Normal file
View File

@@ -0,0 +1,56 @@
FROM php:8.2-apache
ARG APCU_VERSION=5.1.22
# Arguments defined in docker-compose.yml
ARG user
ARG uid
# Install system dependencies
RUN apt-get update && apt-get install -y \
git \
curl \
libpng-dev \
libonig-dev \
libxml2-dev \
libzip-dev \
zip \
unzip \
nano \
vim
RUN apt-get install -y nodejs npm
# Clear cache
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
# Install PHP extensions
RUN docker-php-ext-install pdo pdo_mysql gd zip opcache
RUN docker-php-ext-configure opcache --enable-opcache
RUN pecl install apcu-${APCU_VERSION} && docker-php-ext-enable apcu
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
# Create system user to run Composer Commands
#RUN useradd -G www-data,root -u $uid -d /home/$user $user
RUN mkdir -p /home/$user/.composer && \
chown -R $user:$user /home/$user
RUN chown -R www-data.www-data /var/www
USER $user
WORKDIR /home/$user
RUN git clone https://github.com/otland/forgottenserver.git
COPY --chown=www-data:www-data docker/config.lua /home/$user/forgottenserver
COPY --chown=www-data:www-data docker/config.local.php /var/www/html
#WORKDIR /home/$user/forgottenserver
WORKDIR /var/www/html
COPY --chown=www-data:www-data . .
RUN composer install
RUN npm install

4
docker/config.local.php Normal file
View File

@@ -0,0 +1,4 @@
<?php
$config['installed'] = false;
$config['server_path'] = '/home/www-data/forgottenserver';
$config['install_ignore_ip_check'] = true;

12
docker/config.lua Normal file
View File

@@ -0,0 +1,12 @@
serverName = "Forgotten"
mysqlHost = "db"
mysqlUser = "myaac"
mysqlPass = "myaac"
mysqlDatabase = "myaac"
mysqlPort = 3306
mysqlSock = ""
ip = "192.168.176.1"
statusPort = 7171
statusTimeout = 2000

384
docker/tfs_schema.sql Normal file
View File

@@ -0,0 +1,384 @@
CREATE TABLE IF NOT EXISTS `accounts` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(32) NOT NULL,
`password` char(40) NOT NULL,
`secret` char(16) DEFAULT NULL,
`type` int NOT NULL DEFAULT '1',
`premium_ends_at` int unsigned NOT NULL DEFAULT '0',
`email` varchar(255) NOT NULL DEFAULT '',
`creation` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `players` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`group_id` int NOT NULL DEFAULT '1',
`account_id` int NOT NULL DEFAULT '0',
`level` int NOT NULL DEFAULT '1',
`vocation` int NOT NULL DEFAULT '0',
`health` int NOT NULL DEFAULT '150',
`healthmax` int NOT NULL DEFAULT '150',
`experience` bigint unsigned NOT NULL DEFAULT '0',
`lookbody` int NOT NULL DEFAULT '0',
`lookfeet` int NOT NULL DEFAULT '0',
`lookhead` int NOT NULL DEFAULT '0',
`looklegs` int NOT NULL DEFAULT '0',
`looktype` int NOT NULL DEFAULT '136',
`lookaddons` int NOT NULL DEFAULT '0',
`lookmount` int NOT NULL DEFAULT '0',
`lookmounthead` int NOT NULL DEFAULT '0',
`lookmountbody` int NOT NULL DEFAULT '0',
`lookmountlegs` int NOT NULL DEFAULT '0',
`lookmountfeet` int NOT NULL DEFAULT '0',
`randomizemount` tinyint NOT NULL DEFAULT '0',
`direction` tinyint unsigned NOT NULL DEFAULT '2',
`maglevel` int NOT NULL DEFAULT '0',
`mana` int NOT NULL DEFAULT '0',
`manamax` int NOT NULL DEFAULT '0',
`manaspent` bigint unsigned NOT NULL DEFAULT '0',
`soul` int unsigned NOT NULL DEFAULT '0',
`town_id` int NOT NULL DEFAULT '1',
`posx` int NOT NULL DEFAULT '0',
`posy` int NOT NULL DEFAULT '0',
`posz` int NOT NULL DEFAULT '0',
`conditions` blob DEFAULT NULL,
`cap` int NOT NULL DEFAULT '400',
`sex` int NOT NULL DEFAULT '0',
`lastlogin` bigint unsigned NOT NULL DEFAULT '0',
`lastip` varbinary(16) NOT NULL DEFAULT '0',
`save` tinyint NOT NULL DEFAULT '1',
`skull` tinyint NOT NULL DEFAULT '0',
`skulltime` bigint NOT NULL DEFAULT '0',
`lastlogout` bigint unsigned NOT NULL DEFAULT '0',
`blessings` tinyint NOT NULL DEFAULT '0',
`onlinetime` bigint NOT NULL DEFAULT '0',
`deletion` bigint NOT NULL DEFAULT '0',
`balance` bigint unsigned NOT NULL DEFAULT '0',
`offlinetraining_time` smallint unsigned NOT NULL DEFAULT '43200',
`offlinetraining_skill` int NOT NULL DEFAULT '-1',
`stamina` smallint unsigned NOT NULL DEFAULT '2520',
`skill_fist` int unsigned NOT NULL DEFAULT 10,
`skill_fist_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_club` int unsigned NOT NULL DEFAULT 10,
`skill_club_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_sword` int unsigned NOT NULL DEFAULT 10,
`skill_sword_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_axe` int unsigned NOT NULL DEFAULT 10,
`skill_axe_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_dist` int unsigned NOT NULL DEFAULT 10,
`skill_dist_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_shielding` int unsigned NOT NULL DEFAULT 10,
`skill_shielding_tries` bigint unsigned NOT NULL DEFAULT 0,
`skill_fishing` int unsigned NOT NULL DEFAULT 10,
`skill_fishing_tries` bigint unsigned NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`),
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
KEY `vocation` (`vocation`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `account_bans` (
`account_id` int NOT NULL,
`reason` varchar(255) NOT NULL,
`banned_at` bigint NOT NULL,
`expires_at` bigint NOT NULL,
`banned_by` int NOT NULL,
PRIMARY KEY (`account_id`),
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `account_ban_history` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`account_id` int NOT NULL,
`reason` varchar(255) NOT NULL,
`banned_at` bigint NOT NULL,
`expired_at` bigint NOT NULL,
`banned_by` int NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `account_storage` (
`account_id` int NOT NULL,
`key` int unsigned NOT NULL,
`value` int NOT NULL,
PRIMARY KEY (`account_id`, `key`),
FOREIGN KEY (`account_id`) REFERENCES `accounts`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `ip_bans` (
`ip` varbinary(16) NOT NULL,
`reason` varchar(255) NOT NULL,
`banned_at` bigint NOT NULL,
`expires_at` bigint NOT NULL,
`banned_by` int NOT NULL,
PRIMARY KEY (`ip`),
FOREIGN KEY (`banned_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_namelocks` (
`player_id` int NOT NULL,
`reason` varchar(255) NOT NULL,
`namelocked_at` bigint NOT NULL,
`namelocked_by` int NOT NULL,
PRIMARY KEY (`player_id`),
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`namelocked_by`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `account_viplist` (
`account_id` int NOT NULL COMMENT 'id of account whose viplist entry it is',
`player_id` int NOT NULL COMMENT 'id of target player of viplist entry',
`description` varchar(128) NOT NULL DEFAULT '',
`icon` tinyint unsigned NOT NULL DEFAULT '0',
`notify` tinyint NOT NULL DEFAULT '0',
UNIQUE KEY `account_player_index` (`account_id`,`player_id`),
FOREIGN KEY (`account_id`) REFERENCES `accounts` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guilds` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`ownerid` int NOT NULL,
`creationdata` int NOT NULL,
`motd` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
UNIQUE KEY (`name`),
UNIQUE KEY (`ownerid`),
FOREIGN KEY (`ownerid`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guild_invites` (
`player_id` int NOT NULL DEFAULT '0',
`guild_id` int NOT NULL DEFAULT '0',
PRIMARY KEY (`player_id`,`guild_id`),
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guild_ranks` (
`id` int NOT NULL AUTO_INCREMENT,
`guild_id` int NOT NULL COMMENT 'guild',
`name` varchar(255) NOT NULL COMMENT 'rank name',
`level` int NOT NULL COMMENT 'rank level - leader, vice, member, maybe something else',
PRIMARY KEY (`id`),
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guild_membership` (
`player_id` int NOT NULL,
`guild_id` int NOT NULL,
`rank_id` int NOT NULL,
`nick` varchar(15) NOT NULL DEFAULT '',
PRIMARY KEY (`player_id`),
FOREIGN KEY (`player_id`) REFERENCES `players` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`guild_id`) REFERENCES `guilds` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (`rank_id`) REFERENCES `guild_ranks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guild_wars` (
`id` int NOT NULL AUTO_INCREMENT,
`guild1` int NOT NULL DEFAULT '0',
`guild2` int NOT NULL DEFAULT '0',
`name1` varchar(255) NOT NULL,
`name2` varchar(255) NOT NULL,
`status` tinyint NOT NULL DEFAULT '0',
`started` bigint NOT NULL DEFAULT '0',
`ended` bigint NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `guild1` (`guild1`),
KEY `guild2` (`guild2`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `guildwar_kills` (
`id` int NOT NULL AUTO_INCREMENT,
`killer` varchar(50) NOT NULL,
`target` varchar(50) NOT NULL,
`killerguild` int NOT NULL DEFAULT '0',
`targetguild` int NOT NULL DEFAULT '0',
`warid` int NOT NULL DEFAULT '0',
`time` bigint NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (`warid`) REFERENCES `guild_wars` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `houses` (
`id` int NOT NULL AUTO_INCREMENT,
`owner` int NOT NULL,
`paid` int unsigned NOT NULL DEFAULT '0',
`warnings` int NOT NULL DEFAULT '0',
`name` varchar(255) NOT NULL,
`rent` int NOT NULL DEFAULT '0',
`town_id` int NOT NULL DEFAULT '0',
`bid` int NOT NULL DEFAULT '0',
`bid_end` int NOT NULL DEFAULT '0',
`last_bid` int NOT NULL DEFAULT '0',
`highest_bidder` int NOT NULL DEFAULT '0',
`size` int NOT NULL DEFAULT '0',
`beds` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `owner` (`owner`),
KEY `town_id` (`town_id`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `house_lists` (
`house_id` int NOT NULL,
`listid` int NOT NULL,
`list` text NOT NULL,
FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `market_history` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`player_id` int NOT NULL,
`sale` tinyint NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL,
`amount` smallint unsigned NOT NULL,
`price` bigint unsigned NOT NULL DEFAULT '0',
`expires_at` bigint unsigned NOT NULL,
`inserted` bigint unsigned NOT NULL,
`state` tinyint unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `player_id` (`player_id`, `sale`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `market_offers` (
`id` int unsigned NOT NULL AUTO_INCREMENT,
`player_id` int NOT NULL,
`sale` tinyint NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL,
`amount` smallint unsigned NOT NULL,
`created` bigint unsigned NOT NULL,
`anonymous` tinyint NOT NULL DEFAULT '0',
`price` bigint unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `sale` (`sale`,`itemtype`),
KEY `created` (`created`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `players_online` (
`player_id` int NOT NULL,
PRIMARY KEY (`player_id`)
) ENGINE=MEMORY DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_deaths` (
`player_id` int NOT NULL,
`time` bigint unsigned NOT NULL DEFAULT '0',
`level` int NOT NULL DEFAULT '1',
`killed_by` varchar(255) NOT NULL,
`is_player` tinyint NOT NULL DEFAULT '1',
`mostdamage_by` varchar(100) NOT NULL,
`mostdamage_is_player` tinyint NOT NULL DEFAULT '0',
`unjustified` tinyint NOT NULL DEFAULT '0',
`mostdamage_unjustified` tinyint NOT NULL DEFAULT '0',
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
KEY `killed_by` (`killed_by`),
KEY `mostdamage_by` (`mostdamage_by`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_depotitems` (
`player_id` int NOT NULL,
`sid` int NOT NULL COMMENT 'any given range eg 0-100 will be reserved for depot lockers and all > 100 will be then normal items inside depots',
`pid` int NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL,
`count` smallint NOT NULL DEFAULT '0',
`attributes` blob NOT NULL,
UNIQUE KEY `player_id_2` (`player_id`, `sid`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_inboxitems` (
`player_id` int NOT NULL,
`sid` int NOT NULL,
`pid` int NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL,
`count` smallint NOT NULL DEFAULT '0',
`attributes` blob NOT NULL,
UNIQUE KEY `player_id_2` (`player_id`, `sid`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_storeinboxitems` (
`player_id` int NOT NULL,
`sid` int NOT NULL,
`pid` int NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL,
`count` smallint NOT NULL DEFAULT '0',
`attributes` blob NOT NULL,
UNIQUE KEY `player_id_2` (`player_id`, `sid`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_items` (
`player_id` int NOT NULL DEFAULT '0',
`pid` int NOT NULL DEFAULT '0',
`sid` int NOT NULL DEFAULT '0',
`itemtype` smallint unsigned NOT NULL DEFAULT '0',
`count` smallint NOT NULL DEFAULT '0',
`attributes` blob NOT NULL,
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE,
KEY `sid` (`sid`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_spells` (
`player_id` int NOT NULL,
`name` varchar(255) NOT NULL,
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `player_storage` (
`player_id` int NOT NULL DEFAULT '0',
`key` int unsigned NOT NULL DEFAULT '0',
`value` int NOT NULL DEFAULT '0',
PRIMARY KEY (`player_id`,`key`),
FOREIGN KEY (`player_id`) REFERENCES `players`(`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `server_config` (
`config` varchar(50) NOT NULL,
`value` varchar(256) NOT NULL DEFAULT '',
PRIMARY KEY `config` (`config`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `tile_store` (
`house_id` int NOT NULL,
`data` longblob NOT NULL,
FOREIGN KEY (`house_id`) REFERENCES `houses` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
CREATE TABLE IF NOT EXISTS `towns` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`posx` int NOT NULL DEFAULT '0',
`posy` int NOT NULL DEFAULT '0',
`posz` int NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARACTER SET=utf8;
INSERT INTO `server_config` (`config`, `value`) VALUES ('db_version', '35'), ('players_record', '0');
DROP TRIGGER IF EXISTS `ondelete_players`;
DROP TRIGGER IF EXISTS `oncreate_guilds`;
DELIMITER //
CREATE TRIGGER `ondelete_players` BEFORE DELETE ON `players`
FOR EACH ROW BEGIN
UPDATE `houses` SET `owner` = 0 WHERE `owner` = OLD.`id`;
END
//
CREATE TRIGGER `oncreate_guilds` AFTER INSERT ON `guilds`
FOR EACH ROW BEGIN
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('the Leader', 3, NEW.`id`);
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Vice-Leader', 2, NEW.`id`);
INSERT INTO `guild_ranks` (`name`, `level`, `guild_id`) VALUES ('a Member', 1, NEW.`id`);
END
//
DELIMITER ;

View File

@@ -76,8 +76,6 @@ require_once SYSTEM . 'status.php';
$twig->addGlobal('config', $config); $twig->addGlobal('config', $config);
$twig->addGlobal('status', $status); $twig->addGlobal('status', $status);
$hooks->trigger(HOOK_STARTUP);
// backward support for gesior // backward support for gesior
if(setting('core.backward_support')) { if(setting('core.backward_support')) {
define('INITIALIZED', true); define('INITIALIZED', true);
@@ -119,6 +117,8 @@ if(setting('core.backward_support')) {
require_once SYSTEM . 'router.php'; require_once SYSTEM . 'router.php';
$hooks->trigger(HOOK_STARTUP);
// anonymous usage statistics // anonymous usage statistics
// sent only when user agrees // sent only when user agrees
if(setting('core.anonymous_usage_statistics')) { if(setting('core.anonymous_usage_statistics')) {
@@ -134,7 +134,7 @@ if(setting('core.anonymous_usage_statistics')) {
if(fetchDatabaseConfig('last_usage_report', $value)) { if(fetchDatabaseConfig('last_usage_report', $value)) {
$should_report = time() > (int)$value + $report_time; $should_report = time() > (int)$value + $report_time;
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('last_usage_report', $value, 60 * 60); $cache->set('last_usage_report', $value);
} }
} }
else { else {
@@ -148,7 +148,7 @@ if(setting('core.anonymous_usage_statistics')) {
updateDatabaseConfig('last_usage_report', time()); updateDatabaseConfig('last_usage_report', time());
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('last_usage_report', time(), 60 * 60); $cache->set('last_usage_report', time());
} }
} }
} }

View File

@@ -1,4 +1,4 @@
SET @myaac_database_version = 43; SET @myaac_database_version = 41;
CREATE TABLE `myaac_account_actions` CREATE TABLE `myaac_account_actions`
( (
@@ -91,7 +91,7 @@ CREATE TABLE `myaac_forum`
`post_date` int(20) NOT NULL default '0', `post_date` int(20) NOT NULL default '0',
`last_edit_aid` int(20) NOT NULL default '0', `last_edit_aid` int(20) NOT NULL default '0',
`edit_date` int(20) NOT NULL default '0', `edit_date` int(20) NOT NULL default '0',
`post_ip` varchar(45) NOT NULL default '0.0.0.0', `post_ip` varchar(32) NOT NULL default '0.0.0.0',
`sticked` tinyint(1) NOT NULL DEFAULT '0', `sticked` tinyint(1) NOT NULL DEFAULT '0',
`closed` tinyint(1) NOT NULL DEFAULT '0', `closed` tinyint(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`), PRIMARY KEY (`id`),

View File

@@ -195,7 +195,7 @@ if(is_writable(CACHE) && (MYAAC_OS != 'WINDOWS' || win_is_writable(CACHE))) {
} }
} }
if(!$allow) if(!$allow && !config('install_ignore_ip_check'))
{ {
$content = warning('In file <b>install/ip.txt</b> must be your IP!<br/> $content = warning('In file <b>install/ip.txt</b> must be your IP!<br/>
In file is:<br /><b>' . nl2br($file_content) . '</b><br/> In file is:<br /><b>' . nl2br($file_content) . '</b><br/>

View File

@@ -11,6 +11,7 @@ foreach($config['clients'] as $client) {
} }
$twig->display('install.config.html.twig', array( $twig->display('install.config.html.twig', array(
'config' => $config,
'clients' => $clients, 'clients' => $clients,
'timezones' => DateTimeZone::listIdentifiers(), 'timezones' => DateTimeZone::listIdentifiers(),
'locale' => $locale, 'locale' => $locale,

View File

@@ -41,6 +41,9 @@ if(!$error) {
$configToSave['cache_engine'] = 'auto'; $configToSave['cache_engine'] = 'auto';
$configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true); $configToSave['cache_prefix'] = 'myaac_' . generateRandomString(8, true, false, true);
$configToSave['database_auto_migrate'] = true; $configToSave['database_auto_migrate'] = true;
if (isset($config['install_ignore_ip_check'])) {
$configToSave['install_ignore_ip_check'] = $config['install_ignore_ip_check'];
}
if(!$error) { if(!$error) {
$content = ''; $content = '';
@@ -77,7 +80,7 @@ if(!$error) {
$_SESSION['config_content'] = $content; $_SESSION['config_content'] = $content;
unset($_SESSION['saved']); unset($_SESSION['saved']);
$locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.php</b>', $locale['step_database_error_file']); $locale['step_database_error_file'] = str_replace('$FILE$', '<b>' . BASE . 'config.local.php</b>', $locale['step_database_error_file']);
error($locale['step_database_error_file'] . '<br/> error($locale['step_database_error_file'] . '<br/>
<textarea cols="70" rows="10">' . $content . '</textarea>'); <textarea cols="70" rows="10">' . $content . '</textarea>');
} }

View File

@@ -1,4 +1,3 @@
<?php defined('MYAAC') or die('Direct access not allowed!'); ?>
<!DOCTYPE html> <!DOCTYPE html>
<html dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>"> <html dir="<?php echo $locale['direction']; ?>" lang="<?php echo $locale['lang']; ?>" xml:lang="<?php echo $locale['lang']; ?>">
<head> <head>

View File

@@ -156,14 +156,9 @@ if ($db->hasTable('guilds')) {
} }
if (!$db->hasColumn('guilds', 'description')) { if (!$db->hasColumn('guilds', 'description')) {
if (query("ALTER TABLE `guilds` ADD `description` VARCHAR(5000) NOT NULL DEFAULT '';")) if (query("ALTER TABLE `guilds` ADD `description` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' guilds.description...'); success($locale['step_database_adding_field'] . ' guilds.description...');
} }
else {
if (query("ALTER TABLE `guilds` MODIFY `description` VARCHAR(5000) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' guilds.description...');
}
}
if ($db->hasColumn('guilds', 'logo_gfx_name')) { if ($db->hasColumn('guilds', 'logo_gfx_name')) {
if (query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) { if (query("ALTER TABLE `guilds` CHANGE `logo_gfx_name` `logo_name` VARCHAR( 255 ) NOT NULL DEFAULT 'default.gif';")) {
@@ -202,14 +197,9 @@ if ($db->hasTable('players')) {
} }
if (!$db->hasColumn('players', 'comment')) { if (!$db->hasColumn('players', 'comment')) {
if (query("ALTER TABLE `players` ADD `comment` VARCHAR(5000) NOT NULL DEFAULT '';")) if (query("ALTER TABLE `players` ADD `comment` TEXT NOT NULL;"))
success($locale['step_database_adding_field'] . ' players.comment...'); success($locale['step_database_adding_field'] . ' players.comment...');
} }
else {
if (query("ALTER TABLE `players` MODIFY `comment` VARCHAR(5000) NOT NULL DEFAULT '';")) {
success($locale['step_database_modifying_field'] . ' players.comment...');
}
}
if ($db->hasColumn('players', 'rank_id')) { if ($db->hasColumn('players', 'rank_id')) {
if (query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;")) if (query("ALTER TABLE players MODIFY `rank_id` INT(11) NOT NULL DEFAULT 0;"))

View File

@@ -12,6 +12,10 @@ server {
deny all; deny all;
} }
location /vendor {
deny all;
}
# block .htaccess, CHANGELOG.md, composer.json etc. # block .htaccess, CHANGELOG.md, composer.json etc.
# this is to prevent finding software versions # this is to prevent finding software versions
location ~\.(ht|md|json|dist)$ { location ~\.(ht|md|json|dist)$ {
@@ -24,7 +28,7 @@ server {
} }
location / { location / {
try_files $uri $uri/ /index.php?$query_string; try_files $uri $uri/ /index.php?$query_string;;
} }
location ~ \.php$ { location ~ \.php$ {

905
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
"postinstall": "node ./npm-post-install.js" "postinstall": "node ./npm-post-install.js"
}, },
"devDependencies": { "devDependencies": {
"cypress": "^13.17.0" "cypress": "^12.12.0"
}, },
"dependencies": { "dependencies": {
"@tinymce/tinymce-jquery": "^2.1.0", "@tinymce/tinymce-jquery": "^2.1.0",
@@ -12,6 +12,6 @@
"fs-extra": "^11.2.0", "fs-extra": "^11.2.0",
"jquery": "^3.7.1", "jquery": "^3.7.1",
"jquery-ui": "^1.13.2", "jquery-ui": "^1.13.2",
"tinymce": "^7.2.0" "tinymce": "^6.8.3"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "create-account-hint", "name": "create-account-hint",
"description": "This plugin display text 'To play on Forgotten you need an account. All you have to do to create your new account is to enter an account name, password, country and your email address. Also you have to agree to the terms presented below. If you have done so, your account name will be shown on the following page and your account password will be sent to your email address along with further instructions. If you do not receive the email with your password, please check your spam filter.' on the create account page.", "description": "This plugin display text 'To play on Forgotten you need an account. All you have to do to create your new account is to enter an account name, password, country and your email address. Also you have to agree to the terms presented below. If you have done so, your account name will be shown on the following page and your account password will be sent to your email address along with further instructions. If you do not receive the email with your password, please check your spam filter.' on the create account page. <strong>Be careful when uninstalling this!</strong>",
"version": "1.0", "version": "1.0",
"author": "slawkens", "author": "slawkens",
"contact": "slawkens@gmail.com", "contact": "slawkens@gmail.com",

View File

@@ -9,4 +9,7 @@
*/ */
defined('MYAAC') or die('Direct access not allowed!'); defined('MYAAC') or die('Direct access not allowed!');
$twig->display('account-create-hint/hint.html.twig'); global $twig_loader;
$twig_loader->prependPath(BASE . 'plugins/account-create-hint');
$twig->display('hint.html.twig');

View File

@@ -22,7 +22,7 @@ if [ $1 = "prepare" ]; then
mkdir -p tmp mkdir -p tmp
# get myaac from git archive # get myaac from git archive
git archive --format zip --output tmp/myaac.zip main git archive --format zip --output tmp/myaac.zip develop
cd tmp/ || exit cd tmp/ || exit

View File

@@ -9,16 +9,16 @@
*/ */
use MyAAC\Exceptions\SensitiveException; use MyAAC\Exceptions\SensitiveException;
use Whoops\Handler\PlainTextHandler;
use Whoops\Handler\PrettyPageHandler;
use Whoops\Run;
if (class_exists(Run::class)) { if (class_exists(\Whoops\Run::class)) {
$whoops = new Run; $whoops = new \Whoops\Run;
if(IS_CLI) {
$whoops->pushHandler(new \Whoops\Handler\PlainTextHandler);
}
else {
$whoops->pushHandler(new \Whoops\Handler\PrettyPageHandler);
}
$whoopsHandler = IS_CLI ? (new PlainTextHandler()) : (new PrettyPageHandler());
$whoops->pushHandler($whoopsHandler);
$whoops->register(); $whoops->register();
return; return;
} }

View File

@@ -49,7 +49,7 @@ function warning($message, $return = false) {
return message($message, 'warning', $return); return message($message, 'warning', $return);
} }
function note($message, $return = false) { function note($message, $return = false) {
return message($message, 'note', $return); return info($message, $return);
} }
function info($message, $return = false) { function info($message, $return = false) {
return message($message, 'info', $return); return message($message, 'info', $return);
@@ -589,12 +589,24 @@ function template_form()
{ {
global $template_name; global $template_name;
$templates = Cache::remember('templates', 5 * 60, function() { $cache = Cache::getInstance();
return get_templates(); if($cache->enabled())
}); {
$tmp = '';
if($cache->fetch('templates', $tmp)) {
$templates = unserialize($tmp);
}
else
{
$templates = get_templates();
$cache->set('templates', serialize($templates), 30);
}
}
else
$templates = get_templates();
$options = ''; $options = '';
foreach($templates as $value) foreach($templates as $key => $value)
$options .= '<option ' . ($template_name == $value ? 'SELECTED' : '') . '>' . $value . '</option>'; $options .= '<option ' . ($template_name == $value ? 'SELECTED' : '') . '>' . $value . '</option>';
global $twig; global $twig;
@@ -1057,36 +1069,17 @@ function get_browser_real_ip() {
return '0'; return '0';
} }
function setSession($key, $value = null): void { function setSession($key, $data) {
if (!is_array($key)) { $_SESSION[setting('core.session_prefix') . $key] = $data;
$key = [$key => $value];
}
foreach ($key as $arrayKey => $arrayValue) {
if (is_null($arrayValue)) {
unsetSession($arrayKey);
}
else {
$_SESSION[setting('core.session_prefix') . $arrayKey] = $arrayValue;
}
}
} }
function getSession($key) { function getSession($key) {
return $_SESSION[setting('core.session_prefix') . $key] ?? null; $key = setting('core.session_prefix') . $key;
return isset($_SESSION[$key]) ? $_SESSION[$key] : false;
} }
function unsetSession($key): void { function unsetSession($key) {
unset($_SESSION[setting('core.session_prefix') . $key]); unset($_SESSION[setting('core.session_prefix') . $key]);
} }
function session($key): mixed {
if (is_array($key)) {
setSession($key);
return null;
}
return getSession($key);
}
function csrf(bool $return = false): string { function csrf(bool $return = false): string {
return CsrfToken::create($return); return CsrfToken::create($return);
} }
@@ -1109,16 +1102,20 @@ function csrfProtect(): void
} }
} }
function getTopPlayers($limit = 5, $skill = 'level') { function getTopPlayers($limit = 5) {
global $db; global $db;
if ($skill === 'level') { $cache = Cache::getInstance();
$skill = 'experience'; if($cache->enabled()) {
$tmp = '';
if($cache->fetch('top_' . $limit . '_level', $tmp)) {
$players = unserialize($tmp);
}
} }
return Cache::remember("top_{$limit}_{$skill}", 2 * 60, function () use ($db, $limit, $skill) { if (!isset($players)) {
$columns = [ $columns = [
'id', 'name', 'level', 'vocation', 'experience', 'balance', 'id', 'name', 'level', 'vocation', 'experience',
'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet' 'looktype', 'lookhead', 'lookbody', 'looklegs', 'lookfeet'
]; ];
@@ -1126,27 +1123,36 @@ function getTopPlayers($limit = 5, $skill = 'level') {
$columns[] = 'lookaddons'; $columns[] = 'lookaddons';
} }
return Player::query() if ($db->hasColumn('players', 'online')) {
$columns[] = 'online';
}
$players = Player::query()
->select($columns) ->select($columns)
->withOnlineStatus() ->withOnlineStatus()
->notDeleted() ->notDeleted()
->where('group_id', '<', setting('core.highscores_groups_hidden')) ->where('group_id', '<', setting('core.highscores_groups_hidden'))
->whereNotIn('id', setting('core.highscores_ids_hidden')) ->whereNotIn('id', setting('core.highscores_ids_hidden'))
->where('account_id', '!=', 1) ->where('account_id', '!=', 1)
->orderByDesc($skill) ->orderByDesc('experience')
->limit($limit) ->limit($limit)
->get() ->get()
->map(function ($e, $i) { ->map(function ($e, $i) {
$row = $e->toArray(); $row = $e->toArray();
$row['online'] = $e->online_status; $row['online'] = $e->online_status;
$row['rank'] = $i + 1; $row['rank'] = $i + 1;
$row['outfit_url'] = $e->outfit_url;
unset($row['online_table']); unset($row['online_table']);
return $row; return $row;
})->toArray(); })->toArray();
});
if($cache->enabled()) {
$cache->set('top_' . $limit . '_level', serialize($players), 120);
}
}
return $players;
} }
function deleteDirectory($dir, $ignore = array(), $contentOnly = false) { function deleteDirectory($dir, $ignore = array(), $contentOnly = false) {
@@ -1694,7 +1700,4 @@ function getAccountIdentityColumn(): string
require_once SYSTEM . 'compat/base.php'; require_once SYSTEM . 'compat/base.php';
// custom functions // custom functions
$customFunctions = SYSTEM . 'functions_custom.php'; require SYSTEM . 'functions_custom.php';
if (is_file($customFunctions)) {
require $customFunctions;
}

View File

@@ -50,7 +50,6 @@ $cache = Cache::getInstance();
global $hooks; global $hooks;
$hooks = new Hooks(); $hooks = new Hooks();
$hooks->load(); $hooks->load();
$hooks->trigger(HOOK_INIT);
// twig // twig
require_once SYSTEM . 'twig.php'; require_once SYSTEM . 'twig.php';
@@ -97,8 +96,8 @@ if($config_lua_reload) {
// cache config // cache config
if($cache->enabled()) { if($cache->enabled()) {
$cache->set('config_lua', serialize($config['lua']), 2 * 60); $cache->set('config_lua', serialize($config['lua']), 120);
$cache->set('server_path', $config['server_path'], 10 * 60); $cache->set('server_path', $config['server_path']);
} }
} }
unset($tmp); unset($tmp);
@@ -140,7 +139,7 @@ require_once SYSTEM . 'database.php';
// verify myaac tables exists in database // verify myaac tables exists in database
if(!defined('MYAAC_INSTALL') && !$db->hasTable('myaac_account_actions')) { if(!defined('MYAAC_INSTALL') && !$db->hasTable('myaac_account_actions')) {
throw new RuntimeException('Seems that the table myaac_account_actions of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting ' . (IS_CLI ? 'http://your-ip.com/' : BASE_URL) . 'install'); throw new RuntimeException('Seems that the table myaac_account_actions of MyAAC doesn\'t exist in the database. This is a fatal error. You can try to reinstall MyAAC by visiting ' . BASE_URL . 'install');
} }
// execute migrations // execute migrations

File diff suppressed because it is too large Load Diff

View File

@@ -14,12 +14,12 @@ $account_logged = new OTS_Account();
// stay-logged with sessions // stay-logged with sessions
$current_session = getSession('account'); $current_session = getSession('account');
if($current_session) if($current_session !== false)
{ {
$account_logged->load($current_session); $account_logged->load($current_session);
if($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password') if($account_logged->isLoaded() && $account_logged->getPassword() == getSession('password')
//&& (!isset($_SESSION['admin']) || admin()) //&& (!isset($_SESSION['admin']) || admin())
&& (getSession('remember_me') || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used && (getSession('remember_me') !== false || getSession('last_visit') > time() - 15 * 60)) { // login for 15 minutes if "remember me" is not used
$logged = true; $logged = true;
} }
else { else {

View File

@@ -8,7 +8,7 @@
// the size of ipv6 can be maximal 45 chars // the size of ipv6 can be maximal 45 chars
$up = function () use ($db) { $up = function () use ($db) {
$db->modifyColumn(TABLE_PREFIX . 'visitors', 'ip', 'VARCHAR(45) NOT NULL'); $db->modifyColumn(TABLE_PREFIX . 'visitors', 'ip', 'VARCHAR(15) NOT NULL');
}; };
$down = function () { $down = function () {

View File

@@ -1,15 +0,0 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
// 2025-09-01
// resize forum.post_ip to support ipv6
$up = function () use ($db) {
$db->modifyColumn(TABLE_PREFIX . 'forum', 'post_ip', "varchar(45) NOT NULL default '0.0.0.0'");
};
$down = function () {
// there is no downgrade for this
};

View File

@@ -1,20 +0,0 @@
<?php
/**
* @var OTS_DB_MySQL $db
*/
// 2025-01-22
// change columns to VARCHAR
$up = function () use ($db) {
$db->query("UPDATE guilds set description = '' WHERE description is NULL;"); // prevent truncate error when column is NULL
$db->modifyColumn('guilds', 'description', "VARCHAR(5000) NOT NULL DEFAULT ''");
$db->query("UPDATE players set comment = '' WHERE comment is NULL;");
$db->modifyColumn('players', 'comment', "VARCHAR(5000) NOT NULL DEFAULT ''");
};
$down = function () use ($db) {
$db->modifyColumn('guilds', 'description', "TEXT NOT NULL");
$db->modifyColumn('players', 'comment', "TEXT NOT NULL");
};

View File

@@ -66,7 +66,7 @@ else
$new_sex_str = $config['genders'][$new_sex]; $new_sex_str = $config['genders'][$new_sex];
$player->save(); $player->save();
$account_logged->setCustomField(setting('core.donate_column'), $points - setting('core.account_change_character_sex_price')); $account_logged->setCustomField(setting('core.donate_column'), $points - setting('core.account_change_character_name_price'));
$account_logged->logAction('Changed sex on character <b>' . $player->getName() . '</b> from <b>' . $old_sex_str . '</b> to <b>' . $new_sex_str . '</b>.'); $account_logged->logAction('Changed sex on character <b>' . $player->getName() . '</b> from <b>' . $old_sex_str . '</b> to <b>' . $new_sex_str . '</b>.');
$twig->display('success.html.twig', array( $twig->display('success.html.twig', array(
'title' => 'Character Sex Changed', 'title' => 'Character Sex Changed',

View File

@@ -35,7 +35,7 @@ if(Forum::canPost($account_logged))
$thread = $db->query("SELECT `author_guid`, `author_aid`, `first_post`, `post_topic`, `post_date`, `post_text`, `post_smile`, `post_html`, `id`, `section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$post_id." LIMIT 1")->fetch(); $thread = $db->query("SELECT `author_guid`, `author_aid`, `first_post`, `post_topic`, `post_date`, `post_text`, `post_smile`, `post_html`, `id`, `section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `id` = ".$post_id." LIMIT 1")->fetch();
if(isset($thread['id'])) { if(isset($thread['id'])) {
$first_post = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread['first_post']." LIMIT 1")->fetch(); $first_post = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`author_guid`, `" . FORUM_TABLE_PREFIX . "forum`.`author_aid`, `" . FORUM_TABLE_PREFIX . "forum`.`first_post`, `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`post_text`, `" . FORUM_TABLE_PREFIX . "forum`.`post_smile`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread['first_post']." LIMIT 1")->fetch();
echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread['first_post']) . '">'.htmlspecialchars($first_post['post_topic']).'</a> >> <b>Edit post</b>'; echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread['first_post']) . '">'.$first_post['post_topic'].'</a> >> <b>Edit post</b>';
if(Forum::hasAccess($thread['section'] && ($account_logged->getId() == $thread['author_aid'] || Forum::isModerator()))) { if(Forum::hasAccess($thread['section'] && ($account_logged->getId() == $thread['author_aid'] || Forum::isModerator()))) {
$char_id = $post_topic = $text = $smile = $html = null; $char_id = $post_topic = $text = $smile = $html = null;

View File

@@ -25,7 +25,6 @@ if(!$logged) {
if(!Forum::isModerator()) { if(!Forum::isModerator()) {
echo 'You are not logged in or you are not moderator.'; echo 'You are not logged in or you are not moderator.';
return;
} }
$save = isset($_REQUEST['save']) && (int)$_REQUEST['save'] == 1; $save = isset($_REQUEST['save']) && (int)$_REQUEST['save'] == 1;

View File

@@ -40,7 +40,7 @@ if(Forum::canPost($account_logged)) {
$thread = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." LIMIT 1")->fetch(); $thread = $db->query("SELECT `" . FORUM_TABLE_PREFIX . "forum`.`post_topic`, `" . FORUM_TABLE_PREFIX . "forum`.`id`, `" . FORUM_TABLE_PREFIX . "forum`.`section` FROM `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`id` = ".(int) $thread_id." AND `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".$thread_id." LIMIT 1")->fetch();
if(isset($thread['id']) && Forum::hasAccess($thread['section'])) { if(isset($thread['id']) && Forum::hasAccess($thread['section'])) {
echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread_id) . '">'.htmlspecialchars($thread['post_topic']).'</a> >> <b>Post new reply</b><br /><h3>'.htmlspecialchars($thread['post_topic']).'</h3>'; echo '<a href="' . getLink('forum') . '">Boards</a> >> <a href="' . getForumBoardLink($thread['section']) . '">'.$sections[$thread['section']]['name'].'</a> >> <a href="' . getForumThreadLink($thread_id) . '">'.$thread['post_topic'].'</a> >> <b>Post new reply</b><br /><h3>'.$thread['post_topic'].'</h3>';
$quote = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : NULL; $quote = isset($_REQUEST['quote']) ? (int) $_REQUEST['quote'] : NULL;
$text = isset($_REQUEST['text']) ? stripslashes(trim($_REQUEST['text'])) : NULL; $text = isset($_REQUEST['text']) ? stripslashes(trim($_REQUEST['text'])) : NULL;

View File

@@ -95,23 +95,7 @@ if(Forum::canPost($account_logged)) {
if (count($errors) == 0) { if (count($errors) == 0) {
$saved = true; $saved = true;
$db->insert(FORUM_TABLE_PREFIX . 'forum', [ $db->query("INSERT INTO `" . FORUM_TABLE_PREFIX . "forum` (`first_post` ,`last_post` ,`section` ,`replies` ,`views` ,`author_aid` ,`author_guid` ,`post_text` ,`post_topic` ,`post_smile`, `post_html` ,`post_date` ,`last_edit_aid` ,`edit_date`, `post_ip`) VALUES ('0', '" . time() . "', '" . (int)$section_id . "', '0', '0', '" . $account_logged->getId() . "', '" . $char_id . "', " . $db->quote($text) . ", " . $db->quote($post_topic) . ", '" . $smile . "', '" . $html . "', '" . time() . "', '0', '0', '" . get_browser_real_ip() . "')");
'first_post' => 0,
'last_post' => time(),
'section' => $section_id,
'replies' => 0,
'views' => 0,
'author_aid' => $account_logged->getId(),
'author_guid' => $char_id,
'post_text' => $text,
'post_topic' => $post_topic,
'post_smile' => $smile,
'post_html' => $html,
'post_date' => time(),
'last_edit_aid' => 0,
'edit_date' => 0,
'post_ip' => get_browser_real_ip(),
]);
$thread_id = $db->lastInsertId(); $thread_id = $db->lastInsertId();

View File

@@ -68,7 +68,7 @@ if(isset($last_threads[0])) {
echo '<tr bgcolor="' . getStyle($number_of_rows++) . '"><td>'; echo '<tr bgcolor="' . getStyle($number_of_rows++) . '"><td>';
if(Forum::isModerator()) { if(Forum::isModerator()) {
echo '<a href="' . getLink('forum') . '?action=move_thread&id='.$thread['id'].'"\')"><span style="color:darkgreen">[MOVE]</span></a>'; echo '<a href="' . getLink('forum') . '?action=move_thread&id='.$thread['id'].'"\')"><span style="color:darkgreen">[MOVE]</span></a>';
echo '<a href="' . getLink('forum') . '?action=remove_post&id='.$thread['id'].'" onclick="return confirm(\'Are you sure you want remove thread > '.htmlspecialchars($thread['post_topic']).' <?\')"><span style="color: red">[REMOVE]</span></a> '; echo '<a href="' . getLink('forum') . '?action=remove_post&id='.$thread['id'].'" onclick="return confirm(\'Are you sure you want remove thread > '.$thread['post_topic'].' <?\')"><span style="color: red">[REMOVE]</span></a> ';
} }
$player->load($thread['player_id']); $player->load($thread['player_id']);
@@ -79,7 +79,7 @@ if(isset($last_threads[0])) {
$player_account = $player->getAccount(); $player_account = $player->getAccount();
$canEditForum = $player_account->hasFlag(FLAG_CONTENT_FORUM) || $player_account->isAdmin(); $canEditForum = $player_account->hasFlag(FLAG_CONTENT_FORUM) || $player_account->isAdmin();
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>'; echo '<a href="' . getForumThreadLink($thread['id']) . '">'.($canEditForum ? $thread['post_topic'] : 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) { 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 = $db->query("SELECT `players`.`name`, `" . FORUM_TABLE_PREFIX . "forum`.`post_date` FROM `players`, `" . FORUM_TABLE_PREFIX . "forum` WHERE `" . FORUM_TABLE_PREFIX . "forum`.`first_post` = ".(int) $thread['id']." AND `players`.`id` = `" . FORUM_TABLE_PREFIX . "forum`.`author_guid` ORDER BY `post_date` DESC LIMIT 1")->fetch();
if(isset($last_post['name'])) if(isset($last_post['name']))

View File

@@ -21,9 +21,9 @@ $settingHighscoresCountryBox = setting('core.highscores_country_box');
if(config('account_country') && $settingHighscoresCountryBox) if(config('account_country') && $settingHighscoresCountryBox)
require SYSTEM . 'countries.conf.php'; require SYSTEM . 'countries.conf.php';
$list = urldecode($_GET['list'] ?? 'experience'); $list = $_GET['list'] ?? 'experience';
$page = $_GET['page'] ?? 1; $page = $_GET['page'] ?? 1;
$vocation = urldecode($_GET['vocation'] ?? 'all'); $vocation = $_GET['vocation'] ?? 'all';
if(!is_numeric($page) || $page < 1 || $page > PHP_INT_MAX) { if(!is_numeric($page) || $page < 1 || $page > PHP_INT_MAX) {
$page = 1; $page = 1;
@@ -207,7 +207,6 @@ if (empty($highscores)) {
$tmp = $row->toArray(); $tmp = $row->toArray();
$tmp['online'] = $row->online_status; $tmp['online'] = $row->online_status;
$tmp['vocation'] = $row->vocation_name; $tmp['vocation'] = $row->vocation_name;
$tmp['outfit_url'] = $row->outfit_url; // @phpstan-ignore-line
unset($tmp['online_table']); unset($tmp['online_table']);
return $tmp; return $tmp;
@@ -234,10 +233,14 @@ foreach($highscores as $id => &$player)
$player['experience'] = number_format($player['experience']); $player['experience'] = number_format($player['experience']);
} }
if(!$settingHighscoresVocation) {
unset($player['vocation']);
}
$player['link'] = getPlayerLink($player['name'], false); $player['link'] = getPlayerLink($player['name'], false);
$player['flag'] = getFlagImage($player['country']); $player['flag'] = getFlagImage($player['country']);
if($settingHighscoresOutfit) { if($settingHighscoresOutfit) {
$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="" />'; $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="' . 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'] . '" alt="" />';
} }
$player['rank'] = $offset + $i; $player['rank'] = $offset + $i;
} }

View File

@@ -88,7 +88,7 @@ if(isset($_GET['archive']))
foreach($news_DB as $news) foreach($news_DB as $news)
{ {
$newses[] = array( $newses[] = array(
'link' => getLink('news/archive') . '/' . $news['id'], 'link' => getLink('news') . '/' . $news['id'],
'icon_id' => $categories[$news['category']]['icon_id'], 'icon_id' => $categories[$news['category']]['icon_id'],
'title' => stripslashes($news['title']), 'title' => stripslashes($news['title']),
'date' => $news['date'] 'date' => $news['date']

View File

@@ -39,10 +39,10 @@ return [
[['GET', 'POST'], 'guilds/{guild:string}', 'guilds/show.php'], [['GET', 'POST'], 'guilds/{guild:string}', 'guilds/show.php'],
['GET', 'highscores/{list:string}/{vocation:string}/{page:int}', 'highscores.php'], ['GET', 'highscores/{list:alphanum}/{vocation:alphanum}/{page:int}', 'highscores.php'],
['GET', 'highscores/{list:string}/{page:int}', 'highscores.php'], ['GET', 'highscores/{list:alphanum}/{page:int}', 'highscores.php'],
['GET', 'highscores/{list:string}/{vocation:string}', 'highscores.php'], ['GET', 'highscores/{list:alphanum}/{vocation:alphanum}', 'highscores.php'],
['GET', 'highscores/{list:string}', 'highscores.php'], ['GET', 'highscores/{list:alphanum}', 'highscores.php'],
/* /*
'/^polls\/[0-9]+\/?$/' => array('subtopic' => 'polls', 'id' => '$1'), '/^polls\/[0-9]+\/?$/' => array('subtopic' => 'polls', 'id' => '$1'),
'/^spells\/[A-Za-z0-9-_%]+\/[A-Za-z0-9-_]+\/?$/' => array('subtopic' => 'spells', 'vocation' => '$1', 'order' => '$2'), '/^spells\/[A-Za-z0-9-_%]+\/[A-Za-z0-9-_]+\/?$/' => array('subtopic' => 'spells', 'vocation' => '$1', 'order' => '$2'),

View File

@@ -11,14 +11,8 @@
* - for number: min, max, step * - for number: min, max, step
*/ */
use MyAAC\Cache;
use MyAAC\Settings; use MyAAC\Settings;
$templates = Cache::remember('templates', 5 * 60, function () {
return get_templates();
});
$defaultTemplate = in_array('kathrine', $templates) ? 'kathrine' : $templates[0];
return [ return [
'name' => 'MyAAC', 'name' => 'MyAAC',
'settings' => [ 'settings' => [
@@ -94,7 +88,7 @@ return [
'type' => 'options', 'type' => 'options',
'options' => '$templates', 'options' => '$templates',
'desc' => 'Name of the template used by website', 'desc' => 'Name of the template used by website',
'default' => $defaultTemplate, 'default' => 'kathrine',
], ],
'template_allow_change' => [ 'template_allow_change' => [
'name' => 'Template Allow Change', 'name' => 'Template Allow Change',
@@ -348,7 +342,7 @@ return [
], ],
'database_password' => [ 'database_password' => [
'name' => 'Database Password', 'name' => 'Database Password',
'type' => 'password', 'type' => 'text',
'default' => '', 'default' => '',
'show_if' => [ 'show_if' => [
'database_overwrite', '=', 'true' 'database_overwrite', '=', 'true'
@@ -509,7 +503,7 @@ Sent by MyAAC,<br/>
'smtp_port' => [ 'smtp_port' => [
'name' => 'SMTP Host', 'name' => 'SMTP Host',
'type' => 'number', 'type' => 'number',
'desc' => '25 (default) / 587 (tls - GMail, Microsoft Outlook)', 'desc' => '25 (default) / 465 (ssl, GMail) / 587 (tls, Microsoft Outlook)',
'default' => 25, 'default' => 25,
'show_if' => [ 'show_if' => [
'mail_enabled', '=', 'true' 'mail_enabled', '=', 'true'
@@ -536,8 +530,7 @@ Sent by MyAAC,<br/>
'smtp_pass' => [ 'smtp_pass' => [
'name' => 'SMTP Password', 'name' => 'SMTP Password',
'type' => 'password', 'type' => 'password',
'desc' => 'Here your email password to authenticate with SMTP.' . PHP_EOL 'desc' => 'Here your email password to authenticate with SMTP',
. 'For GMail use generated App password - https://myaccount.google.com/apppasswords.',
'default' => '', 'default' => '',
'show_if' => [ 'show_if' => [
'mail_enabled', '=', 'true' 'mail_enabled', '=', 'true'
@@ -547,8 +540,7 @@ Sent by MyAAC,<br/>
'name' => 'SMTP Security', 'name' => 'SMTP Security',
'type' => 'options', 'type' => 'options',
'options' => ['None', 'SSL', 'TLS'], 'options' => ['None', 'SSL', 'TLS'],
'desc' => 'What kind of encryption to use on the SMTP connection.' . PHP_EOL 'desc' => 'What kind of encryption to use on the SMTP connection',
. '(Gmail, Outlook - tls).',
'default' => 0, 'default' => 0,
'show_if' => [ 'show_if' => [
'mail_enabled', '=', 'true' 'mail_enabled', '=', 'true'

View File

@@ -105,6 +105,9 @@ class CreateCharacter
* @param array $errors * @param array $errors
* @return bool * @return bool
* @throws \E_OTS_NotLoaded * @throws \E_OTS_NotLoaded
* @throws \Twig_Error_Loader
* @throws \Twig_Error_Runtime
* @throws \Twig_Error_Syntax
*/ */
public function doCreate($name, $sex, $vocation, $town, $account, &$errors) public function doCreate($name, $sex, $vocation, $town, $account, &$errors)
{ {

View File

@@ -82,9 +82,7 @@ class DataLoader
self::$startTime = microtime(true); self::$startTime = microtime(true);
$cache = Cache::getInstance(); $cache = Cache::getInstance();
if ($cache->enabled()) { $cache->delete('towns'); // will be reloaded after next page load
$cache->delete('towns'); // will be reloaded after next page load
}
global $db; global $db;
if ($db->hasTable('towns') && Town::count() > 0) { if ($db->hasTable('towns') && Town::count() > 0) {

View File

@@ -8,13 +8,6 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
* @property int $level * @property int $level
* @property int $vocation * @property int $vocation
* @property int $online * @property int $online
* @property int $looktype
* @property int $lookhead
* @property int $lookbody
* @property int $looklegs
* @property int $lookfeet
* @property int $lookaddons
* @property string $outfit_url
* @property hasOne $onlineTable * @property hasOne $onlineTable
*/ */
class Player extends Model { class Player extends Model {
@@ -49,8 +42,8 @@ class Player extends Model {
public function getVocationNameAttribute() public function getVocationNameAttribute()
{ {
$vocation = $this->vocation; $vocation = $this->vocation;
if (isset($this->promotion) && $this->promotion > 0) { if (isset($this->promotion)) {
$vocation += ($this->promotion * setting('core.vocations_amount')); $vocation *= $this->promotion;
} }
return config('vocations')[$vocation] ?? 'Unknown'; return config('vocations')[$vocation] ?? 'Unknown';
@@ -80,21 +73,11 @@ class Player extends Model {
$query->where($column, 0); $query->where($column, 0);
} }
public function scopeWithOnlineStatus($query) public function scopeWithOnlineStatus($query) {
{
global $db; global $db;
if ($db->hasColumn('players', 'online')) { $query->when($db->hasTable('players_online'), function ($query) {
$query->addSelect('online'); $query->with('onlineTable');
} });
else {
$query->when($db->hasTable('players_online'), function ($query) {
$query->with('onlineTable');
});
}
}
public function getOutfitUrlAttribute() {
return setting('core.outfit_images_url') . '?id=' . $this->looktype . (!empty($this->lookaddons) ? '&addons=' . $this->lookaddons : '') . '&head=' . $this->lookhead . '&body=' . $this->lookbody . '&legs=' . $this->looklegs . '&feet=' . $this->lookfeet;
} }
public function getOnlineStatusAttribute() public function getOnlineStatusAttribute()

View File

@@ -72,32 +72,24 @@ class Settings implements \ArrayAccess
} }
} }
global $db; $this->errors = [];
ModelsSettings::where('name', $pluginName)->delete();
try { foreach ($values as $key => $value) {
$db->beginTransaction(); $errorMessage = '';
if (isset($settings['settings'][$key]['callbacks']['beforeSave']) && !$settings['settings'][$key]['callbacks']['beforeSave']($key, $value, $errorMessage)) {
$this->errors = []; $this->errors[] = $errorMessage;
ModelsSettings::where('name', $pluginName)->delete(); continue;
foreach ($values as $key => $value) { }
$errorMessage = '';
if (isset($settings['settings'][$key]['callbacks']['beforeSave']) && !$settings['settings'][$key]['callbacks']['beforeSave']($key, $value, $errorMessage)) {
$this->errors[] = $errorMessage;
continue;
}
try {
ModelsSettings::create([ ModelsSettings::create([
'name' => $pluginName, 'name' => $pluginName,
'key' => $key, 'key' => $key,
'value' => $value 'value' => $value
]); ]);
} catch (\PDOException $error) {
$this->errors[] = 'Error while saving setting (' . $pluginName . ' - ' . $key . '): ' . $error->getMessage();
} }
$db->commit();
} catch (\Exception $error) {
$db->rollBack();
$this->errors[] = 'Error while saving settings (' . $pluginName . ')<br/>' . $error->getMessage();
return false;
} }
$this->clearCache(); $this->clearCache();
@@ -255,15 +247,7 @@ class Settings implements \ArrayAccess
$min = $max = $step = ''; $min = $max = $step = '';
} }
if ($setting['type'] === 'password') {
echo '<div class="input-group" id="show-hide-' . $key . '">';
}
echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"' . $min . $max . $step . '/>'; echo '<input class="form-control" type="' . $setting['type'] . '" name="settings[' . $key . ']" value="' . ($settingsDb[$key] ?? ($setting['default'] ?? '')) . '" id="' . $key . '"' . $min . $max . $step . '/>';
if ($setting['type'] === 'password') {
echo '<div class="input-group-append input-group-text"><a href=""><i class="fas fa-eye-slash" ></i></a></div></div>';
}
} }
else if($setting['type'] === 'textarea') { else if($setting['type'] === 'textarea') {

View File

@@ -5,7 +5,6 @@ const SKILL_BALANCE = -2;
$i = 0; $i = 0;
define('HOOK_INIT', ++$i);
define('HOOK_STARTUP', ++$i); define('HOOK_STARTUP', ++$i);
define('HOOK_BEFORE_PAGE', ++$i); define('HOOK_BEFORE_PAGE', ++$i);
define('HOOK_AFTER_PAGE', ++$i); define('HOOK_AFTER_PAGE', ++$i);
@@ -97,7 +96,7 @@ define('HOOK_CACHE_CLEAR', ++$i);
define('HOOK_INSTALL_FINISH', ++$i); define('HOOK_INSTALL_FINISH', ++$i);
define('HOOK_INSTALL_FINISH_END', ++$i); define('HOOK_INSTALL_FINISH_END', ++$i);
const HOOK_FIRST = HOOK_INIT; const HOOK_FIRST = HOOK_STARTUP;
define('HOOK_LAST', $i); define('HOOK_LAST', $i);
function is_sub_dir($path = NULL, $parent_folder = BASE): bool|string function is_sub_dir($path = NULL, $parent_folder = BASE): bool|string

View File

@@ -41,7 +41,7 @@ if(setting('core.template_allow_change'))
} }
else { else {
$template_session = getSession('template'); $template_session = getSession('template');
if ($template_session) { if ($template_session !== false) {
if (!preg_match("/[^A-z0-9_\-]/", $template_session)) { if (!preg_match("/[^A-z0-9_\-]/", $template_session)) {
$template_name = $template_session; $template_name = $template_session;
} }
@@ -95,7 +95,7 @@ else {
unset($file); unset($file);
if ($cache->enabled()) { if ($cache->enabled()) {
$cache->set('template_ini_' . $template_name, serialize($template_ini), 10 * 60); $cache->set('template_ini_' . $template_name, serialize($template_ini));
} }
} }
} }
@@ -133,54 +133,46 @@ if($forumSetting != '')
$template['link_forum'] = "<a href='" . $forumSetting . "' target='_blank'>"; $template['link_forum'] = "<a href='" . $forumSetting . "' target='_blank'>";
} }
$twig->addGlobal('template_name', $template_name);
$twig->addGlobal('template_path', $template_path); $twig->addGlobal('template_path', $template_path);
if($twig_loader) { if($twig_loader) {
$twig_loader->prependPath(BASE . $template_path); $twig_loader->prependPath(BASE . $template_path);
} }
function get_template_menus(): array function get_template_menus() {
{
global $template_name; global $template_name;
$result = Cache::remember('template_menus', 10 * 60, function () use ($template_name) { $cache = Cache::getInstance();
if ($cache->enabled()) {
$tmp = '';
if ($cache->fetch('template_menus', $tmp)) {
$result = unserialize($tmp);
}
}
if (!isset($result)) {
$result = Menu::select(['name', 'link', 'blank', 'color', 'category']) $result = Menu::select(['name', 'link', 'blank', 'color', 'category'])
->where('template', $template_name) ->where('template', $template_name)
->orderBy('category') ->orderBy('category')
->orderBy('ordering') ->orderBy('ordering')
->get(); ->get();
return $result->toArray(); if ($cache->enabled()) {
}); $cache->set('template_menus', serialize($result->toArray()), 600);
$configMenuCategories = config('menu_categories');
$configMenuDefaultColor = config('menu_default_links_color') ?? config('menu_default_color');
$menus = [];
foreach($result as $menu) {
if (empty($menu['link'])) {
$menu['link'] = 'news';
} }
$link_full = (str_starts_with(trim($menu['link']), 'http') ? $menu['link'] : getLink($menu['link']));
$target_blank = ($menu['blank'] == 1 ? ' target="blank"' : '');
$color = (empty($menu['color']) ? ($configMenuCategories[$menu['category']]['default_links_color'] ?? ($configMenuDefaultColor ?? '')) : $menu['color']);
$color = str_replace('#', '', $color);
$style_color = (empty($color) ? '' : 'style="color: #' . $color . '"');
$menus[$menu['category']][] = [
'name' => $menu['name'],
'link' => $menu['link'], 'link_full' => $link_full,
'blank' => $menu['blank'] == 1, 'target_blank' => $target_blank,
'color' => $color, 'style_color' => $style_color,
];
} }
$new_menus = []; $menus = array();
foreach($result as $menu) {
$link_full = strpos(trim($menu['link']), 'http') === 0 ? $menu['link'] : getLink($menu['link']);
$menus[$menu['category']][] = array('name' => $menu['name'], 'link' => $menu['link'], 'link_full' => $link_full, 'blank' => $menu['blank'] == 1, 'target_blank' => ($menu['blank'] == 1 ? ' target="blank"' : ''), 'color' => $menu['color']);
}
$new_menus = array();
/** /**
* @var array $configMenuCategories * @var array $configMenuCategories
*/ */
$configMenuCategories = config('menu_categories');
if($configMenuCategories === null) { if($configMenuCategories === null) {
return []; return [];
} }

View File

@@ -24,28 +24,21 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="{{
<td> <td>
<div class="InnerTableContainer"> <div class="InnerTableContainer">
<table style="width:100%;" > <table style="width:100%;" >
{{ hook('HOOK_ACCOUNT_LOGIN_BEFORE_PASSWORD') }}
{{ hook('HOOK_ACCOUNT_LOGIN_BEFORE_ACCOUNT') }}
<tr> <tr>
<td class="LabelV" > <td class="LabelV" >
<span{% if error is not null %} class="red"{% endif %}>{{ account_login_by }}:</span> <span{% if error is not null %} class="red"{% endif %}>{{ account_login_by }}:</span>
</td> </td>
<td style="width:100%;" ><input type="text" name="account_login" size="30" maxlength="{{ setting('core.account_login_by_email') ? '255' : '30' }}" autofocus/></td> <td style="width:100%;" ><input type="text" name="account_login" size="30" maxlength="{{ setting('core.account_login_by_email') ? '255' : '30' }}" autofocus/></td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_ACCOUNT') }}
{{ hook('HOOK_ACCOUNT_LOGIN_BEFORE_PASSWORD') }}
<tr> <tr>
<td class="LabelV" > <td class="LabelV" >
<span{% if error is not null %} class="red"{% endif %}>Password:</span> <span{% if error is not null %} class="red"{% endif %}>Password:</span>
</td> </td>
<td><input type="password" name="password_login" size="30" maxlength="29" ></td> <td><input type="password" name="password_login" size="30" maxlength="29" ></td>
</tr> </tr>
{{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD') }} {{ hook('HOOK_ACCOUNT_LOGIN_AFTER_PASSWORD') }}
<tr> <tr>
<td class="LabelV" ></td> <td class="LabelV" ></td>
<td><input type="checkbox" id="remember_me" name="remember_me" value="true" /> <td><input type="checkbox" id="remember_me" name="remember_me" value="true" />

View File

@@ -110,7 +110,7 @@ html { margin-top: 32px !important; }
<form method="post" action="{{ constant('ADMIN_URL') }}?p=dashboard"> <form method="post" action="{{ constant('ADMIN_URL') }}?p=dashboard">
{{ csrf() }} {{ csrf() }}
<input type="hidden" name="clear_cache" value="1" /> <input type="hidden" name="clear_cache" value="1" />
<a class="ab-item" href="javascript:void(0);" onclick="confirm('Are you sure that you want to clear cache?') && $(this).closest('form').submit()" title="Clear Cache">Clear Cache</a> <a class="ab-item" href="#" onclick="confirm('Are you sure that you want to clear cache?') && $(this).closest('form').submit()" title="Clear Cache">Clear Cache</a>
</form> </form>
</li> </li>
</ul> </ul>

View File

@@ -1,31 +0,0 @@
<div align="center" class="text-center">
<p class="note">You are editing: {{ template }}<br/><br/>
Hint: You can drag menu items.<br/>
Hint: Add links to external sites using: <b>http://</b> or <b>https://</b> prefix.<br/>
Not all templates support blank and colorful links.
</p>
<div class="row text-center">
<div class="col-md-2 col-sm-1"></div>
<div class="col-md-8 col-sm-10">
<div class="row justify-content-center">
{% if config('menus') is not null %}
<form method="post" action="?p=menus&reset_menus" onsubmit="return confirm('Do you really want to reset menus?');">
{{ csrf() }}
<input type="hidden" name="template" value="{{ template }}"/>
<button type="submit" class="btn btn-danger">Reset Menus to default</button>
</form>
<br/>
{% endif %}
{% if canResetColors %}
<form method="post" action="?p=menus&reset_colors" onsubmit="return confirm('Do you really want to reset colors?');">
{{ csrf() }}
<input type="hidden" name="template" value="{{ template }}"/>
<button type="submit" class="btn btn-warning" style="margin-left: 20px">Reset Colors to default</button>
</form>
<br/>
{% endif %}
</div>
</div>
<div class="col-md-2 col-sm-1"></div>
</div>
</div>

View File

@@ -1,41 +1,31 @@
<link type="text/css" rel="stylesheet" href="{{ constant('BASE_URL') }}tools/ext/jquery-ui/themes/base/jquery-ui.min.css"> <link type="text/css" rel="stylesheet" href="{{ constant('BASE_URL') }}tools/ext/jquery-ui/themes/base/jquery-ui.min.css">
<script> <script>
let last_id = []; var last_id = [];
let colors = [];
{% for cat, menu in menus %} {% for cat, menu in menus %}
last_id[{{ cat }}] = {{ last_id[cat] }}; last_id[{{ cat }}] = {{ last_id[cat] }};
{% endfor %} {% endfor %}
{% set menuDefaultLinksColor = config('menu_default_links_color') %}
{% for cat, options in config('menu_categories') %}
colors[{{ cat }}] = '{{ options['default_links_color'] ?? (menuDefaultLinksColor ?? config('menu_default_color')) }}';
{% endfor %}
$(function () { $(function () {
const $sortable = $(".sortable"); $(".sortable").sortable();
$sortable.sortable(); $(".sortable").disableSelection();
$sortable.disableSelection();
$(".remove-button").on('click', function () { $(".remove-button").click(function () {
var id = $(this).attr("id"); var id = $(this).attr("id");
$('#list-' + id.replace('remove-button-', '')).remove(); $('#list-' + id.replace('remove-button-', '')).remove();
}); });
$(".add-button").on('click', function () { $(".add-button").click(function () {
var cat = $(this).attr("id").replace('add-button-', ''); var cat = $(this).attr("id").replace('add-button-', '');
var id = last_id[cat]; var id = last_id[cat];
last_id[cat]++; last_id[cat]++;
const color = colors[cat]; $('#sortable-' + cat).append('<li class="ui-state-default" id="list-' + cat + '-' + id + '"><label>Name:</label> <input type="text" name="menu[' + cat + '][]" value=""/> <label>Link:</label> <input type="text" name="menu_link[' + cat + '][]" value=""/><input type="hidden" name="menu_blank[' + cat + '][]" value="0" /> <label><input class="blank-checkbox" type="checkbox"/><span title="Open in New Window">New Window</span></label> <input class="color-picker" type="text" name="menu_color[' + cat + '][]" value="{{ menu_default_color }}" /><a class="remove-button" id="remove-button-' + cat + '-' + id + '"><i class="fas fa-trash"></i></a></li>'); //add input bo
$('#sortable-' + cat).append('<li class="ui-state-default" id="list-' + cat + '-' + id + '"><label>Name:</label> <input type="text" name="menu[' + cat + '][]" value=""/> <label>Link:</label> <input type="text" name="menu_link[' + cat + '][]" value=""/><input type="hidden" name="menu_blank[' + cat + '][]" value="0" /> <label><input class="blank-checkbox" type="checkbox"/><span title="Open in New Window">New Window</span></label> <input class="color-picker" type="text" name="menu_color[' + cat + '][]" value="#' + color + '" /> <a class="remove-button" id="remove-button-' + cat + '-' + id + '"><i class="fas fa-trash"></i></a></li>'); //add input bo $('#remove-button-' + cat + '-' + id).click(function () {
$('#remove-button-' + cat + '-' + id).on('click', function () {
$('#list-' + $(this).attr("id").replace('remove-button-', '')).remove(); $('#list-' + $(this).attr("id").replace('remove-button-', '')).remove();
}); });
initializeSpectrum(); initialiceSpectrum();
}); });
$("#menus-form").on('submit', function (e) { $("#menus-form").submit(function (e) {
$('.blank-checkbox:not(:checked)').each(function (i, obj) { $('.blank-checkbox:not(:checked)').each(function (i, obj) {
$(obj).parent().prev().val("off"); $(obj).parent().prev().val("off");
}); });
@@ -62,11 +52,11 @@
<script type="text/javascript" src="{{ constant('BASE_URL') }}tools/js/spectrum.js"></script> <script type="text/javascript" src="{{ constant('BASE_URL') }}tools/js/spectrum.js"></script>
<link type="text/css" rel="stylesheet" href="{{ constant('BASE_URL') }}tools/css/spectrum.css"/> <link type="text/css" rel="stylesheet" href="{{ constant('BASE_URL') }}tools/css/spectrum.css"/>
<script type="text/javascript"> <script type="text/javascript">
$(function () { $(document).ready(function () {
initializeSpectrum(); initialiceSpectrum();
}); });
function initializeSpectrum() { function initialiceSpectrum() {
$(".color-picker").spectrum({ $(".color-picker").spectrum({
preferredFormat: "hex", preferredFormat: "hex",
showInput: true, showInput: true,

View File

@@ -80,26 +80,7 @@
} }
}); });
const noChangesText = "No changes has been made"; $('#settings').submit(function(e) {
$('form')
.each(function(){
$(this).data('serialized', $(this).serialize())
})
.on('change input', function(){
const disable = $(this).serialize() === $(this).data('serialized');
$(this)
.find('input:submit, button:submit')
.prop('disabled', disable)
.prop('title', disable ? noChangesText : '')
;
})
.find('input:submit, button:submit')
.prop('disabled', true)
.prop('title', noChangesText)
;
$('#settings').on('submit', function(e) {
e.preventDefault(); e.preventDefault();
$.ajax({ $.ajax({
@@ -113,13 +94,6 @@
duration: 3000, duration: 3000,
escapeMarkup: false, escapeMarkup: false,
}).showToast(); }).showToast();
let $settings = $('#settings');
$settings.data('serialized', $settings.serialize());
$settings
.find('input:submit, button:submit')
.prop('disabled', true)
.prop('title', noChangesText);
}, },
error : function(response) { error : function(response) {
Toastify({ Toastify({
@@ -135,27 +109,3 @@
}); });
}); });
</script> </script>
<script>
{% for key, value in settings %}
{% if value.type == 'password' %}
$(function () {
$('#show-hide-{{ key}} a').on('click', function(event) {
event.preventDefault();
const $showHideIcon = $('#show-hide-{{ key}} i');
const $showHideInput = $('#show-hide-{{ key }} input');
if($showHideInput.attr('type') === 'text'){
$showHideInput.attr('type', 'password');
$showHideIcon.addClass('fa-eye-slash');
$showHideIcon.removeClass('fa-eye');
}else if($showHideInput.attr("type") === 'password'){
$showHideInput.attr('type', 'text');
$showHideIcon.removeClass('fa-eye-slash');
$showHideIcon.addClass('fa-eye');
}
});
});
{% endif %}
{% endfor %}
</script>

View File

@@ -50,7 +50,7 @@
<table width="100%"> <table width="100%">
<tr bgcolor="{{ config.vdarkborder }}"> <tr bgcolor="{{ config.vdarkborder }}">
<td colspan="2"> <td colspan="2">
<span style="color: white"><b>Last 5 posts from thread: {{ topic }}</b></span> <span style="color: white"><b>Last 5 posts from thread: {{ topic|raw }}</b></span>
</td> </td>
</tr> </tr>
{% set i = 0 %} {% set i = 0 %}

View File

@@ -79,59 +79,57 @@
</tr> </tr>
{% set showedRank, i = false, 0 %} {% set showedRank, i = false, 0 %}
{% for rank in guild_members %} {% for rank in guild_members if rank.members|length > 0 %}
{% if rank.members|length > 0 %} {% set rankStyle, i = getStyle(i), i + 1 %}
{% set rankStyle, i = getStyle(i), i + 1 %}
{% for player in rank.members %} {% for player in rank.members %}
<tr bgcolor="{{ rankStyle }}"> <tr bgcolor="{{ rankStyle }}">
<td> <td>
{% if not showedRank %}{{ rank.rank_name }}{% endif %} {% if not showedRank %}{{ rank.rank_name }}{% endif %}
{% set showedRank = true %} {% set showedRank = true %}
</td> </td>
<td> <td>
{% set playerName = player.getName() %} {% set playerName = player.getName() %}
<form action="{{ getLink('guilds') }}?action=change_nick&name={{ playerName }}&guild={{ guild_name }}" method="post"> <form action="{{ getLink('guilds') }}?action=change_nick&name={{ playerName }}&guild={{ guild_name }}" method="post">
{{ csrf() }} {{ csrf() }}
{{ getPlayerLink(playerName, true)|raw }} {{ getPlayerLink(playerName, true)|raw }}
{% set showGuildNick = false %} {% set showGuildNick = false %}
{% if player.getGuildNick() is not empty %} {% if player.getGuildNick() is not empty %}
{% set showGuildNick = true %} {% set showGuildNick = true %}
{% set guildNickRaw = player.getGuildNick()|raw %} {% set guildNickRaw = player.getGuildNick()|raw %}
{% endif %} {% endif %}
{% if logged %} {% if logged %}
{% if player.getId() in players_from_account_ids %} {% if player.getId() in players_from_account_ids %}
(<input type="text" name="nick" value="{{ guildNickRaw }}"><input type="submit" value="Change">) (<input type="text" name="nick" value="{{ guildNickRaw }}"><input type="submit" value="Change">)
{% else %}
{% if showGuildNick %} ({{ guildNickRaw }}){% endif %}
{% endif %}
{% if level_in_guild > rank.rank_level or isLeader %}
{% if guildOwnerName != playerName %}
<span style="font-size: 10px; float: right">
{<a href="{{ getLink('guilds') }}?action=kick_player&guild={{ guild_name|url_encode }}&name={{ playerName|url_encode }}">KICK</a>}
</span>
{% endif %}
{% endif %}
{% else %} {% else %}
{% if showGuildNick %} ({{ guildNickRaw }}){% endif %} {% if showGuildNick %} ({{ guildNickRaw }}){% endif %}
{% endif %} {% endif %}
</form>
</td>
<td>{{ player.getVocationName() }}</td> {% if level_in_guild > rank.rank_level or isLeader %}
<td>{{ player.getLevel() }}</td> {% if guildOwnerName != playerName %}
<td> <span style="font-size: 10px; float: right">
<span style="color: {% if player.isOnline() %} green;"><b>Online{% else %} red;"><b>Offline{% endif %}</b></span> {<a href="{{ getLink('guilds') }}?action=kick_player&guild={{ guild_name|url_encode }}&name={{ playerName|url_encode }}">KICK</a>}
</td> </span>
</tr> {% endif %}
{% endfor %} {% endif %}
{% else %}
{% if showGuildNick %} ({{ guildNickRaw }}){% endif %}
{% endif %}
</form>
</td>
{% set showedRank = false %} <td>{{ player.getVocationName() }}</td>
{% endif %} <td>{{ player.getLevel() }}</td>
<td>
<span style="color: {% if player.isOnline() %} green;"><b>Online{% else %} red;"><b>Offline{% endif %}</b></span>
</td>
</tr>
{% endfor %}
{% set showedRank = false %}
{% else %} {% else %}
<tr bgcolor="{{ getStyle(i) }}"> <tr bgcolor="{{ getStyle(i) }}">
<td colspan="5">No guild members found.</td> <td colspan="5">No guild members found.</td>
@@ -164,7 +162,7 @@
</tr> </tr>
{% set i = 0 %} {% set i = 0 %}
{% for invited_player in invited_list %} {% for invited_player in invited_list if invited_list|length > 0 %}
{% if invited_player.isLoaded() %} {% if invited_player.isLoaded() %}
<tr bgcolor="{{ getStyle(i) }}"> <tr bgcolor="{{ getStyle(i) }}">
{% set i = i + 1 %} {% set i = i + 1 %}

View File

@@ -9,17 +9,19 @@
<td> <td>
<label for="skillFilter">Choose a Skill</label> <label for="skillFilter">Choose a Skill</label>
<select onchange="location = this.value;" id="skillFilter"> <select onchange="location = this.value;" id="skillFilter">
{% set i = 0 %}
{% for link, name in types %} {% for link, name in types %}
<option value="{{ getLink('highscores') }}/{{ link|urlencode }}{% if vocation is not null %}/{{ vocation|lower|urlencode }}{% endif %}" class="size_xs" {% if list is not null and list == link %}selected{% endif %}>{{ name }}</option> <option value="{{ getLink('highscores') }}/{{ link }}{% if vocation is not null %}/{{ vocation }}{% endif %}" class="size_xs" {% if list is not null and list == link %}selected{% endif %}>{{ name }}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
<td> <td>
<label for="vocationFilter">Choose a vocation</label> <label for="vocationFilter">Choose a vocation</label>
<select onchange="location = this.value;" id="vocationFilter"> <select onchange="location = this.value;" id="vocationFilter">
<option value="{{ getLink('highscores') }}/{{ list|urlencode }}" class="size_xs">[ALL]</option> <option value="{{ getLink('highscores') }}/{{ list }}" class="size_xs">[ALL]</option>
{% set i = 0 %}
{% for i in 0..config.vocations_amount %} {% for i in 0..config.vocations_amount %}
<option value="{{ getLink('highscores') }}/{{ list|urlencode }}/{{ config.vocations[i]|lower|urlencode }}" class="size_xs" {% if vocationId is not null and vocationId == i %}selected{% endif %}>{{ config.vocations[i]}}</option> <option value="{{ getLink('highscores') }}/{{ list }}/{{ config.vocations[i]|lower }}" class="size_xs" {% if vocationId is not null and vocationId == i %}selected{% endif %}>{{ config.vocations[i]}}</option>
{% endfor %} {% endfor %}
</select> </select>
</td> </td>
@@ -103,7 +105,7 @@
<tr bgcolor="{{ config.lightborder }}"> <tr bgcolor="{{ config.lightborder }}">
<td> <td>
{% for link, name in types %} {% for link, name in types %}
<a href="{{ getLink('highscores') }}/{{ link|urlencode }}{% if vocation is not null %}/{{ vocation|urlencode }}{% endif %}" class="size_xs">{{ name }}</a><br/> <a href="{{ getLink('highscores') }}/{{ link }}{% if vocation is not null %}/{{ vocation }}{% endif %}" class="size_xs">{{ name }}</a><br/>
{% endfor %} {% endfor %}
</td> </td>
</tr> </tr>
@@ -116,9 +118,9 @@
</tr> </tr>
<tr bgcolor="{{ config.lightborder }}"> <tr bgcolor="{{ config.lightborder }}">
<td> <td>
<a href="{{ getLink('highscores') }}/{{ list|urlencode }}" class="size_xs">[ALL]</a><br/> <a href="{{ getLink('highscores') }}/{{ list }}" class="size_xs">[ALL]</a><br/>
{% for i in 0..config.vocations_amount %} {% for i in 0..config.vocations_amount %}
<a href="{{ getLink('highscores') }}/{{ list|urlencode }}/{{ config.vocations[i]|lower|urlencode }}" class="size_xs">{{ config.vocations[i]}}</a><br/> <a href="{{ getLink('highscores') }}/{{ list }}/{{ config.vocations[i]|lower }}" class="size_xs">{{ config.vocations[i]}}</a><br/>
{% endfor %} {% endfor %}
</td> </td>
</tr> </tr>

View File

@@ -85,19 +85,17 @@ the search criteria and start a new search.
<tr bgcolor="{{ config.darkborder }}"> <tr bgcolor="{{ config.darkborder }}">
<td valign="top" rowspan="2"> <td valign="top" rowspan="2">
{% set checked = false %} {% set checked = false %}
{% for id, name in config.towns %} {% for id, name in config.towns if id > 0 %}
{% if id > 0 %} {% if ((townId is empty and name is not empty) or id == townId) and not checked %}
{% if ((townId is empty and name is not empty) or id == townId) and not checked %} {% set variable = "checked" %}
{% set variable = "checked" %} {% set checked = true %}
{% set checked = true %} {% else %}
{% else %} {% set variable = "" %}
{% set variable = "" %}
{% endif %}
<input type="radio" name="town" id="town_{{ id }}" value="{{ id }}"{% if variable is defined %} {{ variable }}{% endif %}>
<label for="town_{{ id }}"> {{ name }}</label>
<br>
{% endif %} {% endif %}
<input type="radio" name="town" id="town_{{ id }}" value="{{ id }}"{% if variable is defined %} {{ variable }}{% endif %}>
<label for="town_{{ id }}"> {{ name }}</label>
<br>
{% endfor %} {% endfor %}
</td> </td>

View File

@@ -10,9 +10,13 @@
<input type="hidden" name="step" id="step" value="database" /> <input type="hidden" name="step" id="step" value="database" />
{% for value in ['server_path'] %} {% for value in ['server_path'] %}
{% if value == 'server_path' and config.server_path is not null %}
{% set server_path = { 'var_server_path': config.server_path } %}
{% set session = session | merge (server_path) %}
{% endif %}
<div class="form-group mb-2"> <div class="form-group mb-2">
<label for="vars_{{ value }}">{{ locale['step_config_' ~ value] }}</label> <label for="vars_{{ value }}">{{ locale['step_config_' ~ value] }}</label>
<input class="form-control" type="{% if value == 'mail_admin' %}email{% else %}text{% endif %}" name="vars[{{ value }}]" id="vars_{{ value }}"{% if session['var_' ~ value] is not null %} value="{{ session['var_' ~ value] }}"{% endif %}/> <input class="form-control" type="text" name="vars[{{ value }}]" id="vars_{{ value }}"{% if session['var_' ~ value] is not null %} value="{{ session['var_' ~ value] }}"{% endif %}/>
<small class="form-text text-muted">{{ locale['step_config_' ~ value ~ '_desc'] }}</small> <small class="form-text text-muted">{{ locale['step_config_' ~ value ~ '_desc'] }}</small>
</div> </div>
{% endfor %} {% endfor %}

View File

@@ -140,11 +140,6 @@ $function = new TwigFunction('csrfToken', function () {
}); });
$twig->addFunction($function); $twig->addFunction($function);
$function = new TwigFunction('session', function ($key) {
return session($key);
});
$twig->addFunction($function);
$filter = new TwigFilter('urlencode', function ($s) { $filter = new TwigFilter('urlencode', function ($s) {
return urlencode($s); return urlencode($s);
}); });

View File

@@ -1,5 +1,5 @@
<?php <?php
$config['menu_default_links_color'] = '#ffffff'; $config['menu_default_color'] = '#ffffff';
$config['menu_categories'] = array( $config['menu_categories'] = array(
MENU_CATEGORY_NEWS => array('id' => 'news', 'name' => 'Latest News'), MENU_CATEGORY_NEWS => array('id' => 'news', 'name' => 'Latest News'),
@@ -8,5 +8,3 @@ $config['menu_categories'] = array(
MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'), MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'),
MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop') MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop')
); );
$config['menus'] = require __DIR__ . '/menus.php';

View File

@@ -26,7 +26,7 @@ return [
'Team' => 'team', 'Team' => 'team',
], ],
MENU_CATEGORY_LIBRARY => [ MENU_CATEGORY_LIBRARY => [
'Monsters' => 'monsters', 'Monsters' => 'creatures',
'Spells' => 'spells', 'Spells' => 'spells',
'Server Info' => 'server-info', 'Server Info' => 'server-info',
'Commands' => 'commands', 'Commands' => 'commands',

View File

@@ -42,6 +42,8 @@ defined('MYAAC') or die('Direct access not allowed!');
<div id="mainsubmenu"> <div id="mainsubmenu">
<?php <?php
$default_menu_color = "ffffff";
foreach($menus as $category => $menu) { foreach($menus as $category => $menu) {
if(!isset($menus[$category])) { if(!isset($menus[$category])) {
continue; continue;
@@ -52,8 +54,8 @@ defined('MYAAC') or die('Direct access not allowed!');
$size = count($menus[$category]); $size = count($menus[$category]);
$i = 0; $i = 0;
foreach($menus[$category] as $link) { foreach($menus[$category] as $menu) {
echo '<a href="' . $link['link_full'] . '" ' . $link['target_blank'] . ' ' . $link['style_color'] . '>' . $link['name'] . '</a>'; echo '<a href="' . $menu['link_full'] . '"' . ($menu['blank'] ? ' target="_blank"' : '') . ' style="color: #' . (strlen($menu['color']) == 0 ? $default_menu_color : $menu['color']) . ';">' . $menu['name'] . '</a>';
if(++$i != $size) { if(++$i != $size) {
echo '<span class="separator"></span>'; echo '<span class="separator"></span>';

View File

@@ -1,5 +1,5 @@
<?php <?php
$config['menu_default_links_color'] = '#ffffff'; $config['menu_default_color'] = '#ffffff';
$config['menu_categories'] = array( $config['menu_categories'] = array(
MENU_CATEGORY_NEWS => array('id' => 'news', 'name' => 'Latest News'), MENU_CATEGORY_NEWS => array('id' => 'news', 'name' => 'Latest News'),
@@ -9,5 +9,3 @@ $config['menu_categories'] = array(
MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'), MENU_CATEGORY_LIBRARY => array('id' => 'library', 'name' => 'Library'),
MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop') MENU_CATEGORY_SHOP => array('id' => 'shops', 'name' => 'Shop')
); );
$config['menus'] = require __DIR__ . '/menus.php';

View File

@@ -35,17 +35,6 @@ if(isset($config['boxes']))
} }
else { else {
$tmp = str_replace('/', '_', PAGE); $tmp = str_replace('/', '_', PAGE);
$exp = explode('/', PAGE);
if(PAGE !== 'account/create' && PAGE !== 'account/lost' && isset($exp[1])) {
if ($exp[0] === 'account') {
$tmp = 'account_manage';
} else if ($exp[0] === 'news' && $exp[1] === 'archive') {
$tmp = 'news_archive';
}
else if (in_array($exp[0], ['characters', 'highscores', 'guilds', 'forum'])) {
$tmp = $exp[0];
}
}
} }
} }
else { else {
@@ -118,15 +107,6 @@ if(isset($config['boxes']))
menu[0] = {}; menu[0] = {};
var unloadhelper = false; var unloadhelper = false;
<?php
$menuInitStr = '';
foreach ($config['menu_categories'] as $item) {
if ($item['id'] !== 'shops' || setting('core.gifts_system')) {
$menuInitStr .= $item['id'] . '=' . ($item['id'] === 'news' ? '1' : '0') . '&';
}
}
?>
// load the menu and set the active submenu item by using the variable 'activeSubmenuItem' // load the menu and set the active submenu item by using the variable 'activeSubmenuItem'
function LoadMenu() function LoadMenu()
{ {
@@ -134,7 +114,7 @@ if(isset($config['boxes']))
document.getElementById("ActiveSubmenuItemIcon_"+activeSubmenuItem).style.visibility = "visible"; document.getElementById("ActiveSubmenuItemIcon_"+activeSubmenuItem).style.visibility = "visible";
menus = localStorage.getItem('menus'); menus = localStorage.getItem('menus');
if(menus == null || menus.lastIndexOf("&") === -1) { if(menus == null || menus.lastIndexOf("&") === -1) {
menus = "<?= $menuInitStr ?>"; menus = "news=1&account=0&community=0&library=0&forum=0<?php if (setting('core.gifts_system')) echo '&shops=0'; ?>&";
} }
FillMenuArray(); FillMenuArray();
InitializeMenu(); InitializeMenu();
@@ -338,22 +318,10 @@ if(isset($config['boxes']))
<?php <?php
$menus = get_template_menus(); $menus = get_template_menus();
$countElements = 0;
foreach($config['menu_categories'] as $id => $cat) {
if (!isset($menus[$id]) || ($id == MENU_CATEGORY_SHOP && !setting('core.gifts_system'))) {
continue;
}
$countElements++;
}
$i = 0;
foreach($config['menu_categories'] as $id => $cat) { foreach($config['menu_categories'] as $id => $cat) {
if(!isset($menus[$id]) || ($id == MENU_CATEGORY_SHOP && !setting('core.gifts_system'))) { if(!isset($menus[$id]) || ($id == MENU_CATEGORY_SHOP && !setting('core.gifts_system'))) {
continue; continue;
} }
$i++;
?> ?>
<div id='<?php echo $cat['id']; ?>' class='menuitem'> <div id='<?php echo $cat['id']; ?>' class='menuitem'>
<span onClick="MenuItemAction('<?php echo $cat['id']; ?>')"> <span onClick="MenuItemAction('<?php echo $cat['id']; ?>')">
@@ -372,13 +340,19 @@ foreach($config['menu_categories'] as $id => $cat) {
</span> </span>
<div id='<?php echo $cat['id']; ?>_Submenu' class='Submenu'> <div id='<?php echo $cat['id']; ?>_Submenu' class='Submenu'>
<?php <?php
$default_menu_color = "ffffff";
foreach($menus[$id] as $category => $menu) { foreach($menus[$id] as $category => $menu) {
if (empty($menu['link'])) {
$menu['link'] = 'news';
}
$link_color = '#' . (strlen($menu['color']) == 0 ? $default_menu_color : $menu['color']);
?> ?>
<a href='<?php echo $menu['link_full']; ?>'<?= $menu['target_blank']?>> <a href='<?php echo $menu['link_full']; ?>'<?php echo $menu['blank'] ? ' target="_blank"' : ''?>>
<div id='submenu_<?php echo str_replace('/', '_', $menu['link']); ?>' class='Submenuitem' onMouseOver='MouseOverSubmenuItem(this)' onMouseOut='MouseOutSubmenuItem(this)' > <div id='submenu_<?php echo str_replace('/', '_', $menu['link']); ?>' class='Submenuitem' onMouseOver='MouseOverSubmenuItem(this)' onMouseOut='MouseOutSubmenuItem(this)' style="color: <?php echo $link_color; ?>;">
<div class='LeftChain' style='background-image:url(<?php echo $template_path; ?>/images/general/chain.gif);'></div> <div class='LeftChain' style='background-image:url(<?php echo $template_path; ?>/images/general/chain.gif);'></div>
<div id='ActiveSubmenuItemIcon_<?php echo str_replace('/', '_', $menu['link']); ?>' class='ActiveSubmenuItemIcon' style='background-image:url(<?php echo $template_path; ?>/images/menu/icon-activesubmenu.gif);'></div> <div id='ActiveSubmenuItemIcon_<?php echo str_replace('/', '_', $menu['link']); ?>' class='ActiveSubmenuItemIcon' style='background-image:url(<?php echo $template_path; ?>/images/menu/icon-activesubmenu.gif);'></div>
<div class='SubmenuitemLabel' <?php echo $menu['style_color']; ?>><?php echo $menu['name']; ?></div> <div class='SubmenuitemLabel' style="color: <?php echo $link_color; ?>;"><?php echo $menu['name']; ?></div>
<div class='RightChain' style='background-image:url(<?php echo $template_path; ?>/images/general/chain.gif);'></div> <div class='RightChain' style='background-image:url(<?php echo $template_path; ?>/images/general/chain.gif);'></div>
</div> </div>
</a> </a>
@@ -387,7 +361,7 @@ foreach($config['menu_categories'] as $id => $cat) {
?> ?>
</div> </div>
<?php <?php
if($id == MENU_CATEGORY_SHOP || (!setting('core.gifts_system') && $i == $countElements)) { if($id == MENU_CATEGORY_SHOP || (!setting('core.gifts_system') && $id == MENU_CATEGORY_SHOP - 1)) {
?> ?>
<div id='MenuBottom' style='background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif);'></div> <div id='MenuBottom' style='background-image:url(<?php echo $template_path; ?>/images/general/box-bottom.gif);'></div>
<?php <?php

View File

@@ -28,7 +28,7 @@ return [
'Forum' => 'forum', 'Forum' => 'forum',
], ],
MENU_CATEGORY_LIBRARY => [ MENU_CATEGORY_LIBRARY => [
'Monsters' => 'monsters', 'Monsters' => 'creatures',
'Spells' => 'spells', 'Spells' => 'spells',
'Commands' => 'commands', 'Commands' => 'commands',
'Exp Stages' => 'exp-stages', 'Exp Stages' => 'exp-stages',