Compare commits

...

5 Commits

52 changed files with 1931 additions and 370 deletions

4
.gitignore vendored
View File

@ -17,3 +17,7 @@ yarn-error.log
/.fleet
/.idea
/.vscode
**/caddy
frankenphp
frankenphp-worker.php

View File

@ -35,8 +35,9 @@ class RegisterController extends Controller
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @param array $data
* @return Account
* @throws \Throwable
*/
protected function create(array $data): Account
{
@ -50,6 +51,35 @@ class RegisterController extends Controller
return $account;
}
/**
* Executes the registration logic on a validator input
*
* @param \Illuminate\Validation\Validator $validator
* @return RedirectResponse
* @throws ValidationException
* @throws \Throwable
*/
protected function runRegistrationLogic(\Illuminate\Validation\Validator $validator): RedirectResponse
{
// Validate the input
if ($validator->fails()) {
return redirect('user/register')
->withErrors($validator)
->withInput($validator->getData());
}
// Retrieve the validated input
$validated = $validator->validated();
// Attempt to create the account and emit the event
event(new Registered($user = $this->create($validated)));
// Authenticate the user
Auth::guard()->login($user);
return redirect('user/verification/notice');
}
/**
* Show the application registration form.
*
@ -65,16 +95,31 @@ class RegisterController extends Controller
*
* @param Request $request
* @return RedirectResponse
* @throws ValidationException
* @throws \Throwable
*/
public function register(Request $request)
public function register(Request $request): RedirectResponse
{
$this->validator($request->all())->validate();
$validator = $this->validator($request->all());
return $this->runRegistrationLogic($validator);
}
event(new Registered($user = $this->create($request->all())));
/**
* Handle a registration request for the application.
*
* @param Request $request
* @return RedirectResponse
* @throws \Throwable
*/
public function registerFromHeader(Request $request): RedirectResponse
{
$requestData = $request->all();
$validator = $this->validator([
'login' => $requestData['header-form-login'] ?? null,
'email' => $requestData['header-form-email'] ?? null,
'password' => $requestData['header-form-password'] ?? null,
'tac' => $requestData['header-form-tac'] ?? null,
]);
Auth::guard()->login($user);
return redirect('user/verification/notice');
return $this->runRegistrationLogic($validator);
}
}

View File

@ -0,0 +1,86 @@
<?php
namespace App\Http\Controllers\Highscore;
use App\Http\Controllers\Controller;
use App\Models\Enums\EmpireEnum;
use App\Models\Game\Highscore\GuildHighscoreCache;
use Illuminate\Http\Request;
use Illuminate\View\View;
class GuildHighscoreController extends Controller
{
private const RESULTS_PER_PAGE = 10;
public function show(Request $request, ?int $empireChoice = null, ?int $page = null): View
{
$where = [];
// If "empireChoice" is a valid empire, add it to the query; otherwise set empireChoice to -1
if (in_array($empireChoice, array_column(EmpireEnum::cases(), 'value'), true))
$where[] = ['empire', $empireChoice];
else
$empireChoice = -1;
// Check whether "guildChoice" or "guildLeaderChoice" were requested
$validated = $request->validate([
'guild-choice' => 'nullable',
'guild-leader-choice' => 'nullable',
]);
$guildChoice = $validated['guild-choice'] ?? null;
$guildLeaderChoice = $validated['guild-leader-choice'] ?? null;
// If "guild-choice" was specified, find the guild with that name
if (!empty($guildChoice))
$where[] = ['name', $guildChoice];
// If "guild-leader-choice" was specified, find the guild master with that name
if (!empty($guildLeaderChoice))
$where[] = ['master', $guildLeaderChoice];
$highscore = GuildHighscoreCache::where($where)->paginate(self::RESULTS_PER_PAGE, page: $page);
return view('main/guildhighscore', [
'highscore' => $highscore,
'empireChoice' => $empireChoice,
'guildChoice' => $guildChoice,
'guildLeaderChoice' => $guildLeaderChoice,
]);
}
public function search(Request $request): View
{
$where = [];
$validated = $request->validate([
'empire-choice' => 'required|int',
'guild-choice' => 'nullable',
'guild-leader-choice' => 'nullable',
]);
$empireChoice = (int) $validated['empire-choice'];
$guildChoice = $validated['guild-choice'];
$guildLeaderChoice = $validated['guild-leader-choice'];
// If "empire-choice" is a valid empire, add it to the query
if (in_array($empireChoice, array_column(EmpireEnum::cases(), 'value'), true))
$where[] = ['empire', $empireChoice];
// If "guild-choice" was specified, find the guild with that name
if (!empty($guildChoice))
$where[] = ['name', $guildChoice];
// If "guild-leader-choice" was specified, find the guild master with that name
if (!empty($guildLeaderChoice))
$where[] = ['master', $guildLeaderChoice];
$highscore = GuildHighscoreCache::where($where)->paginate(self::RESULTS_PER_PAGE);
return view('main/guildhighscore', [
'highscore' => $highscore,
'empireChoice' => $empireChoice,
'guildChoice' => $guildChoice,
'guildLeaderChoice' => $guildLeaderChoice,
]);
}
}

View File

@ -0,0 +1,85 @@
<?php
namespace App\Http\Controllers\Highscore;
use App\Http\Controllers\Controller;
use App\Models\Enums\CharacterClassEnum;
use App\Models\Enums\EmpireEnum;
use App\Models\Game\Highscore\HighscoreCache;
use Illuminate\Http\Request;
use Illuminate\View\View;
class HighscoreController extends Controller
{
private const RESULTS_PER_PAGE = 10;
public function show(Request $request, ?int $empireChoice = null, ?int $classChoice = null, ?int $page = null): View
{
$where = [];
// If "empireChoice" is a valid empire, add it to the query; otherwise set empireChoice to -1
if (in_array($empireChoice, array_column(EmpireEnum::cases(), 'value'), true))
$where[] = ['empire', $empireChoice];
else
$empireChoice = -1;
// If "classChoice" is a valid empire, add it to the query; otherwise set empireChoice to -1
if (in_array($classChoice, array_column(CharacterClassEnum::cases(), 'value'), true))
$where[] = ['job', $classChoice];
else
$classChoice = -1;
// Check whether "characterChoice" was requested
$validated = $request->validate(['character-choice' => 'nullable']);
$characterChoice = $validated['character-choice'] ?? null;
// If "character-choice" was specified, find the character with that name
if (!empty($characterChoice))
$where[] = ['name', $characterChoice];
$highscore = HighscoreCache::where($where)->paginate(self::RESULTS_PER_PAGE, page: $page);
return view('main/highscore', [
'highscore' => $highscore,
'empireChoice' => $empireChoice,
'classChoice' => $classChoice,
'characterChoice' => $characterChoice,
]);
}
public function search(Request $request): View
{
$where = [];
$validated = $request->validate([
'empire-choice' => 'required|int',
'class-choice' => 'required|int',
'character-choice' => 'nullable',
]);
$empireChoice = (int) $validated['empire-choice'];
$classChoice = (int) $validated['class-choice'];
$characterChoice = $validated['character-choice'];
// If "empire-choice" is a valid empire, add it to the query
if (in_array($empireChoice, array_column(EmpireEnum::cases(), 'value'), true))
$where[] = ['empire', $empireChoice];
// If "class-choice" is a valid character class, add it to the query
if (in_array($classChoice, array_column(CharacterClassEnum::cases(), 'value'), true))
$where[] = ['job', $classChoice];
// If "character-choice" was specified, find the character with that name
if (!empty($characterChoice))
$where[] = ['name', $characterChoice];
$highscore = HighscoreCache::where($where)->paginate(self::RESULTS_PER_PAGE);
return view('main/highscore', [
'highscore' => $highscore,
'empireChoice' => $empireChoice,
'classChoice' => $classChoice,
'characterChoice' => $characterChoice,
]);
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace App\Http\Controllers\User;
use App\Http\Controllers\Controller;
use App\Models\Game\Player\Player;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
class CharactersController extends Controller
{
public function show(): View
{
$characters = Player::where('account_id', Auth::user()->id)->get();
return view('user/characters', [
'characters' => $characters
]);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace App\Models\Enums;
enum CharacterClassEnum: int
{
case WARRIOR = 0;
case NINJA = 1;
case SURA = 2;
case SHAMAN = 3;
public function name(): string
{
return match($this) {
self::WARRIOR => __('app/names.classes.warrior'),
self::NINJA => __('app/names.classes.ninja'),
self::SURA => __('app/names.classes.sura'),
self::SHAMAN => __('app/names.classes.shaman'),
};
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace App\Models\Enums;
enum CharacterJobEnum: int
{
case WARRIOR_M = 0;
case NINJA_F = 1;
case SURA_M = 2;
case SHAMAN_F = 3;
case WARRIOR_F = 4;
case NINJA_M = 5;
case SURA_F = 6;
case SHAMAN_M = 7;
public function name(): string
{
return match($this) {
self::WARRIOR_M, self::WARRIOR_F => __('app/names.classes.warrior'),
self::NINJA_M, self::NINJA_F => __('app/names.classes.ninja'),
self::SURA_M, self::SURA_F => __('app/names.classes.sura'),
self::SHAMAN_M, self::SHAMAN_F => __('app/names.classes.shaman'),
};
}
}

View File

@ -0,0 +1,28 @@
<?php
namespace App\Models\Enums;
enum EmpireEnum: int
{
case SHINSOO = 1;
case CHUNJO = 2;
case JINNO = 3;
public function name(): string
{
return match($this) {
self::SHINSOO => __('app/names.empires.shinsoo'),
self::CHUNJO => __('app/names.empires.chunjo'),
self::JINNO => __('app/names.empires.jinno'),
};
}
public function longName(): string
{
return match($this) {
self::SHINSOO => __('app/names.empires.shinsoo.long'),
self::CHUNJO => __('app/names.empires.chunjo.long'),
self::JINNO => __('app/names.empires.jinno.long'),
};
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace App\Models\Game\Highscore;
use App\Models\Enums\EmpireEnum;
use Illuminate\Database\Eloquent\Model;
class GuildHighscoreCache extends Model
{
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'website';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'guild_highscore_cache';
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'empire' => EmpireEnum::class,
'date' => 'datetime'
];
}

View File

@ -0,0 +1,67 @@
<?php
namespace App\Models\Game\Highscore;
use App\Models\Enums\CharacterClassEnum;
use App\Models\Enums\EmpireEnum;
use Illuminate\Database\Eloquent\Model;
class HighscoreCache extends Model
{
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'website';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'highscore_cache';
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'job' => CharacterClassEnum::class,
'empire' => EmpireEnum::class,
'date' => 'datetime'
];
}

View File

@ -3,8 +3,11 @@
namespace App\Models\Game\Player;
use App\Models\Account;
use App\Models\Enums\CharacterJobEnum;
use App\Models\Game\Highscore\HighscoreCache;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasOne;
class Player extends Model
{
@ -60,7 +63,7 @@ class Player extends Model
* @var array<string, string>
*/
protected $casts = [
'job' => CharacterJobEnum::class,
];
/**
@ -70,4 +73,20 @@ class Player extends Model
{
return $this->belongsTo(Account::class, 'account_id', 'id');
}
/**
* Get the index of this player's account
*/
public function index(): BelongsTo
{
return $this->belongsTo(PlayerIndex::class, 'account_id', 'id');
}
/**
* Get this player's ranking
*/
public function highscore(): HasOne
{
return $this->hasOne(HighscoreCache::class, 'name', 'name');
}
}

View File

@ -0,0 +1,75 @@
<?php
namespace App\Models\Game\Player;
use App\Models\Account;
use App\Models\Enums\CharacterJobEnum;
use App\Models\Enums\EmpireEnum;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class PlayerIndex extends Model
{
/**
* Indicates if the model should be timestamped.
*
* @var bool
*/
public $timestamps = false;
/**
* The connection name for the model.
*
* @var string|null
*/
protected $connection = 'player';
/**
* The table associated with the model.
*
* @var string
*/
protected $table = 'player_index';
/**
* The primary key for the model.
*
* @var string
*/
protected $primaryKey = 'id';
/**
* The attributes that are mass assignable.
*
* @var array<int, string>
*/
protected $fillable = [
];
/**
* The attributes that should be hidden for serialization.
*
* @var array<int, string>
*/
protected $hidden = [
];
/**
* The attributes that should be cast.
*
* @var array<string, string>
*/
protected $casts = [
'empire' => EmpireEnum::class,
];
/**
* Get the account that owns the player index.
*/
public function account(): BelongsTo
{
return $this->belongsTo(Account::class, 'id', 'id');
}
}

View File

@ -2,7 +2,9 @@
namespace App\Providers;
use App\View\Composers\HighscoreComposer;
use App\View\Composers\MallComposer;
use App\View\Composers\ThemeComposer;
use Illuminate\Support\Facades;
use Illuminate\Support\ServiceProvider;
@ -21,6 +23,8 @@ class ViewServiceProvider extends ServiceProvider
*/
public function boot(): void
{
Facades\View::composer('layouts.app', ThemeComposer::class);
Facades\View::composer('layouts.mall', MallComposer::class);
Facades\View::composer('layouts.app', HighscoreComposer::class);
}
}

View File

@ -0,0 +1,24 @@
<?php
namespace App\View\Composers;
use App\Models\Game\Highscore\GuildHighscoreCache;
use App\Models\Game\Highscore\HighscoreCache;
use Illuminate\View\View;
class HighscoreComposer
{
/**
* Bind data to the view.
*/
public function compose(View $view): void
{
// Fetch the top highscore
$topHighscore = HighscoreCache::orderBy('id')->take(10)->get();
$view->with('topHighscore', $topHighscore);
// Fetch the top guild highscore
$topGuildHighscore = GuildHighscoreCache::orderBy('id')->take(10)->get();
$view->with('topGuildHighscore', $topGuildHighscore);
}
}

View File

@ -0,0 +1,17 @@
<?php
namespace App\View\Composers;
use Illuminate\View\View;
class ThemeComposer
{
/**
* Bind data to the view.
*/
public function compose(View $view): void
{
$view->with('theme', 'classic');
$view->with('subTheme', 'normal');
}
}

View File

@ -6,12 +6,13 @@
"license": "MIT",
"require": {
"php": "^8.2",
"ext-gd": "*",
"ext-simplexml": "*",
"guzzlehttp/guzzle": "^7.2",
"laravel/framework": "^11.31",
"laravel/octane": "^2.6",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^2.8",
"ext-gd": "*",
"ext-simplexml": "*"
"laravel/tinker": "^2.8"
},
"require-dev": {
"fakerphp/faker": "^1.9.1",

263
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "a560395d060e8def1be287fc4798d9b3",
"content-hash": "304103575d8c6cd1c07a2d3f5a226f77",
"packages": [
{
"name": "brick/math",
@ -1054,6 +1054,94 @@
],
"time": "2023-12-03T19:50:20+00:00"
},
{
"name": "laminas/laminas-diactoros",
"version": "3.5.0",
"source": {
"type": "git",
"url": "https://github.com/laminas/laminas-diactoros.git",
"reference": "143a16306602ce56b8b092a7914fef03c37f9ed2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/143a16306602ce56b8b092a7914fef03c37f9ed2",
"reference": "143a16306602ce56b8b092a7914fef03c37f9ed2",
"shasum": ""
},
"require": {
"php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"psr/http-factory": "^1.1",
"psr/http-message": "^1.1 || ^2.0"
},
"conflict": {
"amphp/amp": "<2.6.4"
},
"provide": {
"psr/http-factory-implementation": "^1.0",
"psr/http-message-implementation": "^1.1 || ^2.0"
},
"require-dev": {
"ext-curl": "*",
"ext-dom": "*",
"ext-gd": "*",
"ext-libxml": "*",
"http-interop/http-factory-tests": "^2.2.0",
"laminas/laminas-coding-standard": "~2.5.0",
"php-http/psr7-integration-tests": "^1.4.0",
"phpunit/phpunit": "^10.5.36",
"psalm/plugin-phpunit": "^0.19.0",
"vimeo/psalm": "^5.26.1"
},
"type": "library",
"extra": {
"laminas": {
"module": "Laminas\\Diactoros",
"config-provider": "Laminas\\Diactoros\\ConfigProvider"
}
},
"autoload": {
"files": [
"src/functions/create_uploaded_file.php",
"src/functions/marshal_headers_from_sapi.php",
"src/functions/marshal_method_from_sapi.php",
"src/functions/marshal_protocol_version_from_sapi.php",
"src/functions/normalize_server.php",
"src/functions/normalize_uploaded_files.php",
"src/functions/parse_cookie_header.php"
],
"psr-4": {
"Laminas\\Diactoros\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"description": "PSR HTTP Message implementations",
"homepage": "https://laminas.dev",
"keywords": [
"http",
"laminas",
"psr",
"psr-17",
"psr-7"
],
"support": {
"chat": "https://laminas.dev/chat",
"docs": "https://docs.laminas.dev/laminas-diactoros/",
"forum": "https://discourse.laminas.dev",
"issues": "https://github.com/laminas/laminas-diactoros/issues",
"rss": "https://github.com/laminas/laminas-diactoros/releases.atom",
"source": "https://github.com/laminas/laminas-diactoros"
},
"funding": [
{
"url": "https://funding.communitybridge.org/projects/laminas-project",
"type": "community_bridge"
}
],
"time": "2024-10-14T11:59:49+00:00"
},
{
"name": "laravel/framework",
"version": "v11.34.2",
@ -1267,6 +1355,96 @@
},
"time": "2024-11-27T15:43:57+00:00"
},
{
"name": "laravel/octane",
"version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/laravel/octane.git",
"reference": "b8b11ef25600baa835d364e724f2e948dc1eb88b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/laravel/octane/zipball/b8b11ef25600baa835d364e724f2e948dc1eb88b",
"reference": "b8b11ef25600baa835d364e724f2e948dc1eb88b",
"shasum": ""
},
"require": {
"laminas/laminas-diactoros": "^3.0",
"laravel/framework": "^10.10.1|^11.0",
"laravel/prompts": "^0.1.24|^0.2.0|^0.3.0",
"laravel/serializable-closure": "^1.3|^2.0",
"nesbot/carbon": "^2.66.0|^3.0",
"php": "^8.1.0",
"symfony/console": "^6.0|^7.0",
"symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0"
},
"conflict": {
"spiral/roadrunner": "<2023.1.0",
"spiral/roadrunner-cli": "<2.6.0",
"spiral/roadrunner-http": "<3.3.0"
},
"require-dev": {
"guzzlehttp/guzzle": "^7.6.1",
"inertiajs/inertia-laravel": "^0.6.9|^1.0",
"laravel/scout": "^10.2.1",
"laravel/socialite": "^5.6.1",
"livewire/livewire": "^2.12.3|^3.0",
"mockery/mockery": "^1.5.1",
"nunomaduro/collision": "^6.4.0|^7.5.2|^8.0",
"orchestra/testbench": "^8.21|^9.0",
"phpstan/phpstan": "^1.10.15",
"phpunit/phpunit": "^10.4",
"spiral/roadrunner-cli": "^2.6.0",
"spiral/roadrunner-http": "^3.3.0"
},
"bin": [
"bin/roadrunner-worker",
"bin/swoole-server"
],
"type": "library",
"extra": {
"laravel": {
"aliases": {
"Octane": "Laravel\\Octane\\Facades\\Octane"
},
"providers": [
"Laravel\\Octane\\OctaneServiceProvider"
]
},
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"autoload": {
"psr-4": {
"Laravel\\Octane\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylor@laravel.com"
}
],
"description": "Supercharge your Laravel application's performance.",
"keywords": [
"frankenphp",
"laravel",
"octane",
"roadrunner",
"swoole"
],
"support": {
"issues": "https://github.com/laravel/octane/issues",
"source": "https://github.com/laravel/octane"
},
"time": "2024-11-25T21:47:18+00:00"
},
{
"name": "laravel/prompts",
"version": "v0.3.2",
@ -4834,6 +5012,89 @@
],
"time": "2024-11-06T14:24:19+00:00"
},
{
"name": "symfony/psr-http-message-bridge",
"version": "v7.2.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/psr-http-message-bridge.git",
"reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
"reference": "03f2f72319e7acaf2a9f6fcbe30ef17eec51594f",
"shasum": ""
},
"require": {
"php": ">=8.2",
"psr/http-message": "^1.0|^2.0",
"symfony/http-foundation": "^6.4|^7.0"
},
"conflict": {
"php-http/discovery": "<1.15",
"symfony/http-kernel": "<6.4"
},
"require-dev": {
"nyholm/psr7": "^1.1",
"php-http/discovery": "^1.15",
"psr/log": "^1.1.4|^2|^3",
"symfony/browser-kit": "^6.4|^7.0",
"symfony/config": "^6.4|^7.0",
"symfony/event-dispatcher": "^6.4|^7.0",
"symfony/framework-bundle": "^6.4|^7.0",
"symfony/http-kernel": "^6.4|^7.0"
},
"type": "symfony-bridge",
"autoload": {
"psr-4": {
"Symfony\\Bridge\\PsrHttpMessage\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "PSR HTTP message bridge",
"homepage": "https://symfony.com",
"keywords": [
"http",
"http-message",
"psr-17",
"psr-7"
],
"support": {
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.2.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-26T08:57:56+00:00"
},
{
"name": "symfony/routing",
"version": "v7.2.0",

224
config/octane.php Normal file
View File

@ -0,0 +1,224 @@
<?php
use Laravel\Octane\Contracts\OperationTerminated;
use Laravel\Octane\Events\RequestHandled;
use Laravel\Octane\Events\RequestReceived;
use Laravel\Octane\Events\RequestTerminated;
use Laravel\Octane\Events\TaskReceived;
use Laravel\Octane\Events\TaskTerminated;
use Laravel\Octane\Events\TickReceived;
use Laravel\Octane\Events\TickTerminated;
use Laravel\Octane\Events\WorkerErrorOccurred;
use Laravel\Octane\Events\WorkerStarting;
use Laravel\Octane\Events\WorkerStopping;
use Laravel\Octane\Listeners\CloseMonologHandlers;
use Laravel\Octane\Listeners\CollectGarbage;
use Laravel\Octane\Listeners\DisconnectFromDatabases;
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
use Laravel\Octane\Listeners\FlushOnce;
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
use Laravel\Octane\Listeners\FlushUploadedFiles;
use Laravel\Octane\Listeners\ReportException;
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
use Laravel\Octane\Octane;
return [
/*
|--------------------------------------------------------------------------
| Octane Server
|--------------------------------------------------------------------------
|
| This value determines the default "server" that will be used by Octane
| when starting, restarting, or stopping your server via the CLI. You
| are free to change this to the supported server of your choosing.
|
| Supported: "roadrunner", "swoole", "frankenphp"
|
*/
'server' => env('OCTANE_SERVER', 'roadrunner'),
/*
|--------------------------------------------------------------------------
| Force HTTPS
|--------------------------------------------------------------------------
|
| When this configuration value is set to "true", Octane will inform the
| framework that all absolute links must be generated using the HTTPS
| protocol. Otherwise your links may be generated using plain HTTP.
|
*/
'https' => env('OCTANE_HTTPS', false),
/*
|--------------------------------------------------------------------------
| Octane Listeners
|--------------------------------------------------------------------------
|
| All of the event listeners for Octane's events are defined below. These
| listeners are responsible for resetting your application's state for
| the next request. You may even add your own listeners to the list.
|
*/
'listeners' => [
WorkerStarting::class => [
EnsureUploadedFilesAreValid::class,
EnsureUploadedFilesCanBeMoved::class,
],
RequestReceived::class => [
...Octane::prepareApplicationForNextOperation(),
...Octane::prepareApplicationForNextRequest(),
//
],
RequestHandled::class => [
//
],
RequestTerminated::class => [
// FlushUploadedFiles::class,
],
TaskReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
TaskTerminated::class => [
//
],
TickReceived::class => [
...Octane::prepareApplicationForNextOperation(),
//
],
TickTerminated::class => [
//
],
OperationTerminated::class => [
FlushOnce::class,
FlushTemporaryContainerInstances::class,
// DisconnectFromDatabases::class,
// CollectGarbage::class,
],
WorkerErrorOccurred::class => [
ReportException::class,
StopWorkerIfNecessary::class,
],
WorkerStopping::class => [
CloseMonologHandlers::class,
],
],
/*
|--------------------------------------------------------------------------
| Warm / Flush Bindings
|--------------------------------------------------------------------------
|
| The bindings listed below will either be pre-warmed when a worker boots
| or they will be flushed before every new request. Flushing a binding
| will force the container to resolve that binding again when asked.
|
*/
'warm' => [
...Octane::defaultServicesToWarm(),
],
'flush' => [
//
],
/*
|--------------------------------------------------------------------------
| Octane Swoole Tables
|--------------------------------------------------------------------------
|
| While using Swoole, you may define additional tables as required by the
| application. These tables can be used to store data that needs to be
| quickly accessed by other workers on the particular Swoole server.
|
*/
'tables' => [
'example:1000' => [
'name' => 'string:1000',
'votes' => 'int',
],
],
/*
|--------------------------------------------------------------------------
| Octane Swoole Cache Table
|--------------------------------------------------------------------------
|
| While using Swoole, you may leverage the Octane cache, which is powered
| by a Swoole table. You may set the maximum number of rows as well as
| the number of bytes per row using the configuration options below.
|
*/
'cache' => [
'rows' => 1000,
'bytes' => 10000,
],
/*
|--------------------------------------------------------------------------
| File Watching
|--------------------------------------------------------------------------
|
| The following list of files and directories will be watched when using
| the --watch option offered by Octane. If any of the directories and
| files are changed, Octane will automatically reload your workers.
|
*/
'watch' => [
'app',
'bootstrap',
'config/**/*.php',
'database/**/*.php',
'public/**/*.php',
'resources/**/*.php',
'routes',
'composer.lock',
'.env',
],
/*
|--------------------------------------------------------------------------
| Garbage Collection Threshold
|--------------------------------------------------------------------------
|
| When executing long-lived PHP scripts such as Octane, memory can build
| up before being cleared by PHP. You can force Octane to run garbage
| collection if your application consumes this amount of megabytes.
|
*/
'garbage' => 50,
/*
|--------------------------------------------------------------------------
| Maximum Execution Time
|--------------------------------------------------------------------------
|
| The following setting configures the maximum execution time for requests
| being handled by Octane. You may set this value to 0 to indicate that
| there isn't a specific time limit on Octane request execution time.
|
*/
'max_execution_time' => 30,
];

View File

@ -64,11 +64,11 @@ RUN composer install --no-ansi --no-interaction --no-plugins --no-progress --no-
RUN npm ci && npm run build
# Make the init script executable
RUN chmod +x /app/docker/init.sh
RUN chmod +x /app/docker/init-apache.sh
# Expose the API on port 80
EXPOSE 80
# Run supervisord for handling the container services
ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/app/docker/init.sh"]
CMD ["/app/docker/init-apache.sh"]

View File

@ -0,0 +1,36 @@
# syntax=docker/dockerfile:1
FROM dunglas/frankenphp:php8.2-alpine
#
# Install system packages & dependencies
#
RUN apk update && apk add wget npm
# Composer
RUN wget -O composer-setup.php https://getcomposer.org/installer \
&& php composer-setup.php --install-dir=/usr/local/bin --filename=composer \
&& rm ./composer-setup.php
#
# PHP extensions
#
RUN install-php-extensions pcntl gd zip intl exif mysqli pdo pdo_mysql
# Copy the source code
WORKDIR /app
COPY . /app
# Install the dependencies
RUN composer install --no-ansi --no-interaction --no-plugins --no-progress --no-scripts --optimize-autoloader
RUN npm ci && npm run build
# Make the init script executable
RUN chmod +x /app/docker/init-frankenphp.sh
# Expose the API on port 80
EXPOSE 80
# Run supervisord for handling the container services
ENTRYPOINT ["/bin/sh", "-c"]
CMD ["/app/docker/init-frankenphp.sh"]

50
docker/init-frankenphp.sh Normal file
View File

@ -0,0 +1,50 @@
#!/bin/sh
set -e
KERNEL_VERSION=$(uname -r)
KERNEL_ARCH=$(uname -m)
FRANKENPHP_VERSION=$(frankenphp -v | cut -d " " -f 2)
PHP_VERSION=$(php -r "echo PHP_VERSION;")
echo "The Old Metin2 Project - Web management system"
echo "Kernel ${KERNEL_VERSION}, architecture: ${KERNEL_ARCH}, FrankenPHP: ${FRANKENPHP_VERSION}, PHP: ${PHP_VERSION}"
# Create storage directories if they don't exist
if [ ! -d /app/storage/app/public/ ]; then
mkdir -p /app/storage/app/public/;
fi
if [ ! -d /app/storage/app/public/patch-data/ ]; then
mkdir -p /app/storage/app/public/patch-data/;
fi
if [ ! -d /app/storage/framework/cache/data/ ]; then
mkdir -p /app/storage/framework/cache/data/;
fi
if [ ! -d /app/storage/framework/sessions/ ]; then
mkdir -p /app/storage/framework/sessions/;
fi
if [ ! -d /app/storage/framework/testing/ ]; then
mkdir -p /app/storage/framework/sessions/;
fi
if [ ! -d /app/storage/framework/views/ ]; then
mkdir -p /app/storage/framework/views/;
fi
if [ ! -d /app/storage/logs/ ]; then
mkdir -p /app/storage/logs/;
fi
# Set folder permissions
chown -R www-data:www-data /app/storage
# Link filesystem paths
/usr/local/bin/php artisan storage:link
# Run database migrations
/usr/local/bin/php artisan migrate --force --no-interaction
# Run Laravel Octane with FrankenPHP
/usr/local/bin/php artisan octane:frankenphp --port=80

30
lang/en/app/highscore.php Normal file
View File

@ -0,0 +1,30 @@
<?php
return [
'title' => 'Metin2 - Ranking',
'search.select-empire' => 'Select empire:',
'search.all-empires' => '[All empires]',
'search.select-class' => 'Select class:',
'search.all-classes' => '[All classes]',
'search.find-character' => 'Find character:',
'search.find-guild' => 'Find guild:',
'search.find-guild-leader' => 'Find guild leader:',
'search' => 'Search',
'no-results' => 'The search returned no results.',
'pagination.prev' => 'previous :count ranks',
'pagination.next' => 'next :count ranks',
'header.rank' => 'Rank',
'header.character-name' => 'Character name',
'header.guild-name' => 'Guild name',
'header.guild-leader' => 'Guild leader',
'header.empire' => 'Empire',
'header.level' => 'Level',
'header.exp' => 'EXP',
'header.guild-points' => 'Points',
'update-time' => 'Updated at:'
];

17
lang/en/app/names.php Normal file
View File

@ -0,0 +1,17 @@
<?php
return [
// Empire names
'empires.shinsoo' => 'Shinsoo',
'empires.shinsoo.long' => 'Shinsoo Empire',
'empires.chunjo' => 'Chunjo',
'empires.chunjo.long' => 'Chunjo Empire',
'empires.jinno' => 'Jinno',
'empires.jinno.long' => 'Jinno Empire',
// Character class names
'classes.warrior' => "Warrior",
'classes.ninja' => "Ninja",
'classes.sura' => "Sura",
'classes.shaman' => "Shaman",
];

39
lang/en/app/register.php Normal file
View File

@ -0,0 +1,39 @@
<?php
return [
'title' => 'Register',
'subtitle' => 'Create an account',
'progress-texts.register' => 'Register',
'progress-texts.activate-download' => 'Activate and download',
'progress-texts.install-play' => 'Install and play',
'to-login' => 'or Login',
'form.username' => 'Username',
'form.email' => 'Email',
'form.password' => 'Password',
'form.password-requirements' => 'Requirements',
'form.terms-and-conditions' => 'I have read the [**Terms and Conditions**](:termsUrl) and the [**Privacy Policy**](:privacyUrl) and accept them.',
'form.password-info.header' => 'A safe password must contain',
'form.password-info.rule-1' => 'between 5 and 16 characters',
'form.password-info.rule-2' => 'or at least one lowercase letter',
'form.password-info.rule-3' => 'at least one uppercase letter',
'form.password-info.rule-4' => 'at least one digit',
'form.password-info.rule-5' => 'at least one special character',
'form.password-info.special-chars' => 'Allowed special characters',
'form.password-security' => "Your password's security level",
'form.required' => '* is required',
'form.register-btn' => 'Register',
'header-form.step-1' => 'Register',
'header-form.step-2' => 'Download',
'header-form.step-3' => 'Play for free',
'header-form.hint-username' => 'Only letters and numbers allowed.<br />Length between 5 and 16 characters.',
'header-form.hint-email' => 'The activation link will be sent to this address.',
'header-form.hint-password' => 'Only letters and numbers allowed.<br />Length between 5 and 16 characters.',
];

View File

@ -0,0 +1,12 @@
<?php
return [
'title' => 'Character list',
'rank' => 'Rank',
'class' => 'Class',
'time' => 'Playtime',
'level' => 'Level',
'exp' => 'Experience',
'empire' => 'Empire',
];

30
lang/ro/app/highscore.php Normal file
View File

@ -0,0 +1,30 @@
<?php
return [
'title' => 'Metin2 - Clasament',
'search.select-empire' => 'Alege regat:',
'search.all-empires' => '[Toate regatele]',
'search.select-class' => 'Alege categoria:',
'search.all-classes' => '[Toate categoriile]',
'search.find-character' => 'Caută caracter:',
'search.find-guild' => 'Caută breaslă:',
'search.find-guild-leader' => 'Caută lider breaslă:',
'search' => 'Caută',
'no-results' => 'Căutarea nu a întors niciun rezultat.',
'pagination.prev' => 'anterioarele :count ranguri',
'pagination.next' => 'următoarele :count ranguri',
'header.rank' => 'Rang',
'header.character-name' => 'Numele caracterului',
'header.guild-name' => 'Numele breslei',
'header.guild-leader' => 'Lider breaslă',
'header.empire' => 'Regat',
'header.level' => 'Nivel',
'header.exp' => 'EXP',
'header.guild-points' => 'Puncte',
'update-time' => 'Actualizat la:'
];

17
lang/ro/app/names.php Normal file
View File

@ -0,0 +1,17 @@
<?php
return [
// Empire names
'empires.shinsoo' => 'Shinsoo',
'empires.shinsoo.long' => 'Imperiul Shinsoo',
'empires.chunjo' => 'Chunjo',
'empires.chunjo.long' => 'Imperiul Chunjo',
'empires.jinno' => 'Jinno',
'empires.jinno.long' => 'Imperiul Jinno',
// Character class names
'classes.warrior' => "Războinic",
'classes.ninja' => "Ninja",
'classes.sura' => "Sura",
'classes.shaman' => "Șaman",
];

39
lang/ro/app/register.php Normal file
View File

@ -0,0 +1,39 @@
<?php
return [
'title' => 'Înregistrare',
'subtitle' => 'Creează un cont',
'progress-texts.register' => 'Înregistrare',
'progress-texts.activate-download' => 'Activează și descarcă',
'progress-texts.install-play' => 'Instalează și joacă-te',
'to-login' => 'sau Autentifică-te',
'form.username' => 'Nume de utilizator',
'form.email' => 'Email',
'form.password' => 'Parola',
'form.password-requirements' => 'Reguli parolă',
'form.terms-and-conditions' => 'Am citit [**Termenii și Condițiile**](:termsUrl) și [**Politica de Confidențialitate**](:privacyUrl), și le accept.',
'form.password-info.header' => 'O parolă sigură conține',
'form.password-info.rule-1' => 'între 5 și 16 caractere',
'form.password-info.rule-2' => 'sau cel puțin o literă mică',
'form.password-info.rule-3' => 'cel puțin o literă mare',
'form.password-info.rule-4' => 'cel puțin o cifră',
'form.password-info.rule-5' => 'cel puțin un caracter special',
'form.password-info.special-chars' => 'Caractere speciale permise',
'form.password-security' => 'Nivelul de securitate al parolei tale',
'form.required' => '* este necesar',
'form.register-btn' => 'Înregistrare',
'header-form.step-1' => 'Înregistrează-te',
'header-form.step-2' => 'Descarcă',
'header-form.step-3' => 'Joacă gratis',
'header-form.hint-username' => 'Sunt permise doar litere și cifre.<br />Lungime între 5 și 16 caractere.',
'header-form.hint-email' => 'Un link de activare va fi trimis la această adresă.',
'header-form.hint-password' => 'Sunt permise doar litere și cifre.<br />Lungime între 5 și 16 caractere.',
];

View File

@ -0,0 +1,12 @@
<?php
return [
'title' => 'Lista personajelor',
'rank' => 'Rang',
'class' => 'Clasă',
'time' => 'Timp de joc',
'level' => 'Nivel',
'exp' => 'Experiență',
'empire' => 'Regat',
];

View File

@ -0,0 +1,60 @@
.header-wrapper {
background: url(../img/header-bg-classic-btn.jpg) no-repeat 50% 0;
height: 230px;
}
.header-box {
margin: 160px 0 0 199px;
}
#userBox {
background: url(../img/user-box.jpg) no-repeat;
height:66px;
margin:125px 0 0 159px;
padding:10px 40px;
width:535px;
}
#regBtn {
background:url(../img/reg-btn-classic.jpg) no-repeat;
display:block;
color:#f2e69f;
font-size:18px;
font-weight:bold;
height:38px;
line-height:38px;
margin:0 auto;
text-align:center;
text-decoration:none;
text-shadow:2px 2px 5px #000000;
width:320px;
}
#regBtn:hover {background-position:0 -38px;}
.header-box-nav-container{
background: url(../img/header-box.png) no-repeat;
margin: 2px 0 0 6px;
}
.welcome-text-left, .welcome-text-right{
margin-top: 1px;
}
.container-wrapper {
background: url(../img/container-bg-top-classic-btn.jpg) no-repeat 50% 0;
}
.col-1, .col-3 {
margin: -42px 0 0 11px;
}
.col-3 {
margin: -42px 9px 0 0;
}
.boxes-top {
background: url(../img/box-top-1-classic-btn.jpg) no-repeat;
}
.col-3 .boxes-top {
background: url(../img/box-top-2-classic-btn.jpg) no-repeat;
}

View File

@ -0,0 +1,21 @@
.header-wrapper {
background: url(../img/header-bg-classic.jpg) no-repeat 50% 0;
height: 250px;
}
#header {
height: 250px;
}
.header-box {
margin: 130px 0 0 199px;
}
.header-box-nav-container{
background: url(../img/header-box.png) no-repeat;
margin: 7px 0 0 6px;
}
.container-wrapper {
background: url(../img/container-bg-top-classic.jpg) no-repeat 50% 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 82 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -1,8 +1,8 @@
<div id="progressTracker">
@php($progressTexts = [
1 => 'Înregistrare',
2 => 'Activează și descarcă',
3 => 'Instalează și joacă-te',
1 => __('app/register.progress-texts.register'),
2 => __('app/register.progress-texts.activate-download'),
3 => __('app/register.progress-texts.install-play'),
])
@for ($i = 1; $i <= 3; $i++)

View File

@ -10,6 +10,11 @@
<link rel="shortcut icon" href="{{ asset('favicon.ico') }}" type="image/x-icon" />
<link href="{{ asset('assets/main/css/reset.css') }}" rel="stylesheet" type="text/css" media="all"/>
<link href="{{ asset('assets/main/css/all.css') }}" rel="stylesheet" type="text/css" media="all"/>
@if ($subTheme == 'classic')
<link href="{{ asset('assets/main/css/header-classic.css') }}" rel="stylesheet" type="text/css" media="all"/>
@elseif ($subTheme == 'classic-btn')
<link href="{{ asset('assets/main/css/header-classic-btn.css') }}" rel="stylesheet" type="text/css" media="all"/>
@endif
<link href="{{ asset('assets/main/css/plugins.css') }}" rel="stylesheet" type="text/css" media="screen" />
<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="{{ asset('assets/main/css/ie6.css') }}" media="screen"/><![endif]-->
@ -108,31 +113,102 @@
</a>
@guest
<div class="header-box">
<div id="regBtn">
<a id="toReg" href="{{ url('user/register') }}" title="{{ __('app/main.header.register_alt') }}">
@if ($subTheme == 'classic')
<div class="header-box">
<ul class="top-nav">
<li><span>1</span><a href="{{ url('user/register') }}">{{ __('app/register.header-form.step-1') }}</a></li>
<li><span>2</span><a href="{{ url('main/download') }}">{{ __('app/register.header-form.step-2') }}</a></li>
<li><span>3</span><a href="{{ url('main/howto') }}">{{ __('app/register.header-form.step-3') }}</a></li>
</ul>
<div id="err-register" style="display: none;"></div>
<form action="{{ url('user/register-from-header') }}" method="post">
@csrf
<div class="form">
<fieldset>
<div class="box">
<label for="namefield">{{ __('app/register.form.username') }}</label>
<div class="input"><input type="text" id="namefield" name="header-form-login" maxlength="16" value="" onblur="registrationTooltip(this,'',1,false);" onfocus="registrationTooltip(this,'',1,true);"/></div>
</div>
<div class="box">
<label for="emailfield">{{ __('app/register.form.email') }}</label>
<div class="input input-2"><input type="text" id="emailfield" name="header-form-email" maxlength="64" value="" onblur="registrationTooltip(this,'',2,false);" onfocus="registrationTooltip(this,'',2,true);"/></div>
</div>
<div class="box">
<label for="pwdfield">{{ __('app/register.form.password') }}</label>
<div class="input input-3"><input type="password" id="pwdfield" name="header-form-password" maxlength="16" value="" onblur="registrationTooltip(this,'',3,false);" onfocus="registrationTooltip(this,'',3,true);"/></div>
</div>
<input type="submit" class="button" value="{{ __('app/register.form.register-btn') }}"/>
</fieldset>
<input class="form-agb-box" name="header-form-tac" type="checkbox" value="tac" />
<div class="agb-label">
{!! Str::inlineMarkdown(__('app/register.form.terms-and-conditions', ['termsUrl' => url('legal/terms'), 'privacyUrl' => url('legal/privacy')])) !!}
</div>
</div>
</form>
</div>
<script type="text/javascript">
function registrationTooltip(elem, text, hint, clear) {
if (clear) {
if (elem.value === text) {
elem.value = '';
}
switch (hint) {
case 1:
$("#err-register").html("{!! __('app/register.header-form.hint-username') !!}");
$("#err-register").css("display", "block");
break;
case 2:
$("#err-register").html("{!! __('app/register.header-form.hint-email') !!}");
$("#err-register").css("display", "block");
break;
case 3:
$("#err-register").html("{!! __('app/register.header-form.hint-password') !!}");
$("#err-register").css("display", "block");
break;
}
} else {
if ((elem.value === '') && (text != null)) {
elem.value = text;
}
$("#err-register").css("display", "none");
}
}
</script>
@elseif ($subTheme == 'classic-btn')
<div class="header-box">
<a id="regBtn" href="{{ url('user/register') }}" title="{{ __('app/main.header.register_alt') }}">
{{ __('app/main.header.register') }}
</a>
<div id="regSteps">
<a href="{{ url('user/register') }}" title="{{ __('app/main.header.register_alt') }}">
<span>{{ __('app/main.header.register_steps_1') }}</span> »
<span>{{ __('app/main.header.register_steps_2') }}</span> »
<span>{{ __('app/main.header.register_steps_3') }}</span>
</a>
</div>
</div>
@elseif ($subTheme == 'normal')
<div class="header-box">
<div id="regBtn">
<a id="toReg" href="{{ url('user/register') }}" title="{{ __('app/main.header.register_alt') }}">
{{ __('app/main.header.register') }}
</a>
<div id="regSteps">
<a href="{{ url('user/register') }}" title="{{ __('app/main.header.register_alt') }}">
<span>{{ __('app/main.header.register_steps_1') }}</span> »
<span>{{ __('app/main.header.register_steps_2') }}</span> »
<span>{{ __('app/main.header.register_steps_3') }}</span>
</a>
</div>
</div>
<script type="text/javascript">
$('#regBtn').hover(
function () {
$(this).addClass("reg-hover");
},
function () {
$(this).removeClass("reg-hover");
}
);
</script>
</div>
<script type="text/javascript">
$('#regBtn').hover(
function () {
$(this).addClass("reg-hover");
},
function () {
$(this).removeClass("reg-hover");
}
);
</script>
</div>
@endif
@else
<div id="userBox">
<div class="welcome-text welcome-text-left">{{ __('app/main.header.welcome', ['name' => Auth::user()->login]) }}</div>
@ -288,19 +364,49 @@
<h3 style="margin-top:0">{{ __('app/main.ranking.players') }}</h3>
<div class="form-score">
<div id="highscore-player">
<ul><li><div class="empire2"><strong class="offset">1</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore" class="first">picyu3</a></div></li><li class="light"><div class="empire1"><strong class="offset">2</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">XXXMEN77</a></div></li><li><div class="empire1"><strong class="offset">3</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">Spydy</a></div></li><li class="light"><div class="empire3"><strong class="offset">4</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">beLeSe</a></div></li><li><div class="empire2"><strong class="offset">5</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">alexdenis</a></div></li><li class="light"><div class="empire3"><strong class="offset">6</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">Pixie03</a></div></li><li><div class="empire3"><strong class="offset">7</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">KingARAGORN</a></div></li><li class="light"><div class="empire1"><strong class="offset">8</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">SCORPIO1</a></div></li><li><div class="empire2"><strong class="offset">9</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">Parazltu</a></div></li><li class="light"><div class="empire2"><strong>10</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/highscore">Sayana</a></div></li></ul> </div>
<ul>
@foreach ($topHighscore as $entry)
<li @class(['light' => $loop->even])>
<div
@class([
'empire1' => $entry->empire == \App\Models\Enums\EmpireEnum::SHINSOO,
'empire2' => $entry->empire == \App\Models\Enums\EmpireEnum::CHUNJO,
'empire3' => $entry->empire == \App\Models\Enums\EmpireEnum::JINNO
])
>
<strong @class(['offset' => $entry->id < 10])>{{ $entry->id }}</strong>&ndash;<a href="{{ url('main/highscore') }}" @class(['first' => $loop->first])>{{ $entry->name }}</a>
</div>
</li>
@endforeach
</ul>
</div>
<a href="{{ url('main/highscore') }}" class="btn" rel="nofollow">{{ __('app/main.ranking.btn_highscore') }}</a>
</div>
<h3 style="margin-top:0">{{ __('app/main.ranking.guilds') }}</h3>
<div class="form-score">
<div id="highscore-guild">
<ul><li><div class="empire2"><strong class="offset">1</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore" class="first">InStyle</a></div></li><li class="light"><div class="empire3"><strong class="offset">2</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">ISENGARD</a></div></li><li><div class="empire2"><strong class="offset">3</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">TheRulers</a></div></li><li class="light"><div class="empire2"><strong class="offset">4</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">A55A55INII</a></div></li><li><div class="empire3"><strong class="offset">5</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">TheElfs</a></div></li><li class="light"><div class="empire3"><strong class="offset">6</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">MAESTRIIpur</a></div></li><li><div class="empire2"><strong class="offset">7</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">NeBuNaTiCii</a></div></li><li class="light"><div class="empire1"><strong class="offset">8</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">TheGoDs</a></div></li><li><div class="empire2"><strong class="offset">9</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">7UP</a></div></li><li class="light"><div class="empire2"><strong>10</strong>&ndash;<a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore">ReVoLuTioN</a></div></li></ul> </div>
<ul>
@foreach ($topGuildHighscore as $entry)
<li @class(['light' => $loop->even])>
<div
@class([
'empire1' => $entry->empire == \App\Models\Enums\EmpireEnum::SHINSOO,
'empire2' => $entry->empire == \App\Models\Enums\EmpireEnum::CHUNJO,
'empire3' => $entry->empire == \App\Models\Enums\EmpireEnum::JINNO
])
>
<strong @class(['offset' => $entry->id < 10])>{{ $entry->id }}</strong>&ndash;<a href="{{ url('main/guildhighscore') }}" @class(['first' => $loop->first])>{{ $entry->name }}</a>
</div>
</li>
@endforeach
</ul>
</div>
<a href="{{ url('main/guildhighscore') }}" class="btn" rel="nofollow">{{ __('app/main.ranking.btn_highscore') }}</a>
</div>
</div>
</div>
</div>
<div class="boxes-bottom"> </div>
<div class="boxes-bottom"></div>
</div>
</div>
</div>

View File

@ -6,153 +6,131 @@
<div class="content content-last">
<div class="content-bg">
<div class="content-bg-bottom">
<h2>Metin2 - Listarea rangurilor</h2>
<h2>{{ __('app/highscore.title') }}</h2>
<div class="ranks-inner-content"><br/>
<div class="ranks-dropdowns-box">
<form action="{{ url('main/guildhighscore') }}" name="highscoreform" method="POST">
<form action="{{ url('main/guildhighscore') }}" name="highscore-form" method="POST">
@csrf
{{-- Temporarily disabled until multi-server support is implemented; added guild leader instead
<div class="ranks-select-box">
<label>Server:</label>
<select name="serverchoice">
<option value="1" selected="selected">Server name 1</option>
<option value="2">Server name 2</option>
<option value="3">Server name 3</option>
</select>
</div>
--}}
<div class="ranks-select-box">
<label>Server:</label>
<select name="serverchoice">
<option value="1" selected="selected">Leonis</option>
<option value="2">Virgo</option>
<option value="3">Pegasus</option>
<option value="4">Sagitta</option>
<option value="5">Corvus</option>
<option value="6">Taurus</option>
<option value="7">Hydra</option>
<option value="8">Aries</option>
<option value="9">Gemini</option>
<option value="10">Lupus</option>
<option value="11">Draco</option>
<option value="12">Volans</option>
<option value="13">Trianguli</option>
<label>{{ __('app/highscore.search.select-empire') }}</label>
<select name="empire-choice">
<option value="-1" selected>{{ __('app/highscore.search.all-empires') }}</option>
@foreach (\App\Models\Enums\EmpireEnum::cases() as $empire)
<option value="{{ $empire->value }}" @selected($empireChoice === $empire->value)>
{{ $empire->name() }}
</option>
@endforeach
</select>
</div>
<div class="ranks-select-box">
<label>Arată imperiu:</label>
<select name="empirechoice">
<option value="-1" selected>[toate imperiile]</option>
<option value="1">Imperiul Shinsoo</option>
<option value="2">Imperiul Chunjo</option>
<option value="3">Imperiul Jinno</option>
</select>
</div>
<div class="ranks-select-box">
<label>Caută breasla:</label>
<label>{{ __('app/highscore.search.find-guild') }}</label>
<div class="ranks-input">
<input type="text" value="" name="guildchoice"/>
<input type="text" value="{{ $guildChoice ?? '' }}" name="guild-choice"/>
</div>
</div>
<div class="ranks-select-box">
<label>{{ __('app/highscore.search.find-guild-leader') }}</label>
<div class="ranks-input">
<input type="text" value="{{ $guildLeaderChoice ?? '' }}" name="guild-leader-choice"/>
</div>
</div>
<div class="ranks-select-box-btn">
<a class="small-btn" href="#" onclick="document.forms['highscoreform'].submit();return false;">Căutare</a>
<a class="small-btn" href="#" onclick="document.forms['highscore-form'].submit();return false;">
{{ __('app/highscore.search') }}
</a>
</div>
<div class="clearfloat"></div>
</form>
</div>
<div class="ranks-nav prev prev-top"><a href="https://web.archive.org/web/20130715184054/http://www.metin2.ro/main/guildhighscore/1/-1/1/">&lt;&lt; anterioarele 10 ranguri</a></div>
<div class="ranks-nav next next-top"><a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore/1/-1/11/">urmatoarele 10 ranguri &gt;&gt;</a></div>
<br class="clearfloat"/>
<table border="0" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th class="guildrank-th-1">Rang</th>
<th class="guildrank-th-2">Breasla</th>
<th class="guildrank-th-3">Lider Breaslă</th>
<th class="guildrank-th-4">Regat</th>
<th class="guildrank-th-5">Nivel</th>
<th class="guildrank-th-6">Puncte</th>
</tr>
</thead>
<tbody>
<tr class="rankfirst">
<td class="guildrank-td-1-1">1</td>
<td class="guildrank-td-1-2">InStyle</td>
<td class="guildrank-td-1-3">divolitzaTa</td>
<td class="guildrank-td-1-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-1-5">20</td>
<td class="guildrank-td-1-6">119494</td>
</tr>
<tr>
<td class="guildrank-td-2-1">2</td>
<td class="guildrank-td-2-2">ISENGARD</td>
<td class="guildrank-td-2-3">Florin10</td>
<td class="guildrank-td-2-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34px" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="guildrank-td-2-5">20</td>
<td class="guildrank-td-2-6">113902</td>
</tr>
<tr>
<td class="guildrank-td-1-1">3</td>
<td class="guildrank-td-1-2">TheRulers</td>
<td class="guildrank-td-1-3">gabitza20</td>
<td class="guildrank-td-1-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-1-5">20</td>
<td class="guildrank-td-1-6">76941</td>
</tr>
<tr>
<td class="guildrank-td-2-1">4</td>
<td class="guildrank-td-2-2">A55A55INII</td>
<td class="guildrank-td-2-3">AnA3634</td>
<td class="guildrank-td-2-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-2-5">20</td>
<td class="guildrank-td-2-6">75729</td>
</tr>
<tr>
<td class="guildrank-td-1-1">5</td>
<td class="guildrank-td-1-2">TheElfs</td>
<td class="guildrank-td-1-3">SorrcerreR</td>
<td class="guildrank-td-1-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34px" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="guildrank-td-1-5">20</td>
<td class="guildrank-td-1-6">55547</td>
</tr>
<tr>
<td class="guildrank-td-2-1">6</td>
<td class="guildrank-td-2-2">MAESTRIIpur</td>
<td class="guildrank-td-2-3">MAESTRAiuby</td>
<td class="guildrank-td-2-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34px" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="guildrank-td-2-5">15</td>
<td class="guildrank-td-2-6">50908</td>
</tr>
<tr>
<td class="guildrank-td-1-1">7</td>
<td class="guildrank-td-1-2">NeBuNaTiCii</td>
<td class="guildrank-td-1-3">MANXL</td>
<td class="guildrank-td-1-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-1-5">20</td>
<td class="guildrank-td-1-6">50164</td>
</tr>
<tr>
<td class="guildrank-td-2-1">8</td>
<td class="guildrank-td-2-2">TheGoDs</td>
<td class="guildrank-td-2-3">PaCaToaSa</td>
<td class="guildrank-td-2-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf2.geo.gfsrv.net/cdn13/7211083d422c5dc6c70b198e850004.png" width="34px" alt="Imperiul Shinsoo" title="Imperiul Shinsoo"/></td>
<td class="guildrank-td-2-5">12</td>
<td class="guildrank-td-2-6">48107</td>
</tr>
<tr>
<td class="guildrank-td-1-1">9</td>
<td class="guildrank-td-1-2">7UP</td>
<td class="guildrank-td-1-3">KANNDY</td>
<td class="guildrank-td-1-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-1-5">20</td>
<td class="guildrank-td-1-6">45964</td>
</tr>
<tr>
<td class="guildrank-td-2-1">10</td>
<td class="guildrank-td-2-2">ReVoLuTioN</td>
<td class="guildrank-td-2-3">Tucson</td>
<td class="guildrank-td-2-4"><img src="https://web.archive.org/web/20130621071508im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34px" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="guildrank-td-2-5">20</td>
<td class="guildrank-td-2-6">42929</td>
</tr>
</tbody>
</table>
<div class="ranks-nav prev"><a href="https://web.archive.org/web/20130715184054/http://www.metin2.ro/main/guildhighscore/1/-1/1/">&lt;&lt; anterioarele 10 ranguri</a></div>
@if ($highscore->isEmpty())
<div class="error-mini error-mini-margin error-mini-maxwidth">{{ __("app/highscore.no-results") }}</div>
@else
@if ($highscore->lastPage() > 1)
<div class="ranks-nav prev prev-top">
@if ($highscore->currentPage() > 1)
<a href="{{ route('guild-highscore-page', ['empireChoice' => $empireChoice, 'page' => $highscore->currentPage() - 1, 'guild-choice' => $guildChoice ?? null, 'guild-leader-choice' => $guildChoice ?? null]) }}">&lt;&lt; {{ __("app/highscore.pagination.prev", ['count' => $highscore->perPage()]) }}</a>
@endif
</div>
<div class="ranks-nav next next-top">
@if ($highscore->hasMorePages())
<a href="{{ route('guild-highscore-page', ['empireChoice' => $empireChoice, 'page' => $highscore->currentPage() + 1, 'guild-choice' => $guildChoice ?? null, 'guild-leader-choice' => $guildChoice ?? null]) }}">{{ __("app/highscore.pagination.next", ['count' => $highscore->perPage()]) }} &gt;&gt;</a>
@endif
</div>
@endif
<div class="ranks-nav next"><a href="https://web.archive.org/web/20130621071508/http://www.metin2.ro/main/guildhighscore/1/-1/11/">urmatoarele 10 ranguri &gt;&gt;</a></div>
<br class="clearfloat"/>
<table border="0" cellpadding="0" cellspacing="0">
<thead>
<tr>
<th class="guildrank-th-1">{{ __("app/highscore.header.rank") }}</th>
<th class="guildrank-th-2">{{ __("app/highscore.header.guild-name") }}</th>
<th class="guildrank-th-3">{{ __("app/highscore.header.guild-leader") }}</th>
<th class="guildrank-th-4">{{ __("app/highscore.header.empire") }}</th>
<th class="guildrank-th-5">{{ __("app/highscore.header.level") }}</th>
<th class="guildrank-th-6">{{ __("app/highscore.header.guild-points") }}</th>
</tr>
</thead>
<tbody>
@foreach ($highscore as $entry)
<tr @class(["rankfirst" => $entry->id == 1, "zebra" => $loop->odd])>
<td @class(["guildrank-td-1-1" => $loop->odd, "guildrank-td-2-1" => $loop->even])>
{{ $entry->id }}
</td>
<td @class(["guildrank-td-1-2" => $loop->odd, "guildrank-td-2-2" => $loop->even])>
{{ $entry->name }}
</td>
<td @class(["guildrank-td-1-3" => $loop->odd, "guildrank-td-2-3" => $loop->even])>
{{ $entry->master }}
</td>
<td @class(["guildrank-td-1-4" => $loop->odd, "guildrank-td-2-4" => $loop->even])>
@if ($entry->empire == \App\Models\Enums\EmpireEnum::SHINSOO)
<img src="{{ asset("assets/main/img/empire1.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@elseif ($entry->empire == \App\Models\Enums\EmpireEnum::CHUNJO)
<img src="{{ asset("assets/main/img/empire2.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@elseif ($entry->empire == \App\Models\Enums\EmpireEnum::JINNO)
<img src="{{ asset("assets/main/img/empire3.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@endif
</td>
<td @class(["guildrank-td-1-5" => $loop->odd, "guildrank-td-2-5" => $loop->even])>
{{ $entry->level }}
</td>
<td @class(["guildrank-td-1-6" => $loop->odd, "guildrank-td-2-6" => $loop->even])>
{{ $entry->ladder_point }}
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="clearfloat"></div>
<div class="ranks-update-time">Update: 21.06.2013 05:27:36</div>
@if ($highscore->lastPage() > 1)
<div class="ranks-nav prev">
@if ($highscore->currentPage() > 1)
<a href="{{ route('guild-highscore-page', ['empireChoice' => $empireChoice, 'page' => $highscore->currentPage() - 1, 'guild-choice' => $guildChoice ?? null, 'guild-leader-choice' => $guildChoice ?? null]) }}">&lt;&lt; {{ __("app/highscore.pagination.prev", ['count' => $highscore->perPage()]) }}</a>
@endif
</div>
<div class="ranks-nav next">
@if ($highscore->hasMorePages())
<a href="{{ route('guild-highscore-page', ['empireChoice' => $empireChoice, 'page' => $highscore->currentPage() + 1, 'guild-choice' => $guildChoice ?? null, 'guild-leader-choice' => $guildChoice ?? null]) }}">{{ __("app/highscore.pagination.next", ['count' => $highscore->perPage()]) }} &gt;&gt;</a>
@endif
</div>
@endif
<div class="clearfloat"></div>
<div class="ranks-update-time">{{ __('app/highscore.update-time') }} {{ $highscore->max('date')->translatedFormat('d F Y H:i:s') }}</div>
@endif
<div class="box-foot"></div>
</div>
</div>
@ -160,9 +138,4 @@
</div>
<div class="shadow">&nbsp;</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#guildHighscore table tr:odd').addClass('zebra');
});
</script>
@endsection

View File

@ -6,143 +6,132 @@
<div class="content content-last">
<div class="content-bg">
<div class="content-bg-bottom">
<h2>Metin2 - Listarea rangurilor</h2>
<h2>{{ __('app/highscore.title') }}</h2>
<div class="ranks-inner-content"><br/>
<div class="ranks-dropdowns-box">
<form action="{{ url('main/highscore') }}" name="highscoreform" method="post">
<form action="{{ url('main/highscore') }}" name="highscore-form" method="post">
@csrf
{{-- Temporarily disabled until multi-server support is implemented; added empire choice instead
<div class="ranks-select-box">
<label>Server:</label>
<select name="serverchoice">
<option value="1" selected="selected">Server name 1</option>
<option value="2">Server name 2</option>
<option value="3">Server name 3</option>
</select>
</div>
--}}
<div class="ranks-select-box">
<label>Server:</label>
<select name="serverchoice">
<option value="1" selected="selected">Leonis</option>
<option value="2">Virgo</option>
<option value="3">Pegasus</option>
<option value="4">Sagitta</option>
<option value="5">Corvus</option>
<option value="6">Taurus</option>
<option value="7">Hydra</option>
<option value="8">Aries</option>
<option value="9">Gemini</option>
<option value="10">Lupus</option>
<option value="11">Draco</option>
<option value="12">Volans</option>
<option value="13">Trianguli</option>
<label>{{ __('app/highscore.search.select-empire') }}</label>
<select name="empire-choice">
<option value="-1">{{ __('app/highscore.search.all-empires') }}</option>
@foreach (\App\Models\Enums\EmpireEnum::cases() as $empire)
<option value="{{ $empire->value }}" @selected($empireChoice === $empire->value)>
{{ $empire->name() }}
</option>
@endforeach
</select>
</div>
<div class="ranks-select-box">
<label>Arata categoriile:</label>
<select name="classchoice">
<option value="-1" selected="selected">[all classes]</option>
<option value="0">Războinic</option>
<option value="1">Ninja</option>
<option value="2">Sura</option>
<option value="3">Şaman</option>
<label>{{ __('app/highscore.search.select-class') }}</label>
<select name="class-choice">
<option value="-1">{{ __('app/highscore.search.all-classes') }}</option>
@foreach (\App\Models\Enums\CharacterClassEnum::cases() as $class)
<option value="{{ $class->value }}" @selected($classChoice === $class->value)>
{{ $class->name() }}
</option>
@endforeach
</select>
</div>
<div class="ranks-select-box">
<label>Alege caracterul:</label>
<label>{{ __('app/highscore.search.find-character') }}</label>
<div class="ranks-input">
<input type="text" value="" name="characterchoice"/>
<input type="text" value="{{ $characterChoice ?? '' }}" name="character-choice"/>
</div>
</div>
<div class="ranks-select-box-btn">
<a class="small-btn" href="#" onclick="document.forms['highscoreform'].submit();return false;">Căutare</a>
<a class="small-btn" href="#" onclick="document.forms['highscore-form'].submit();return false;">
{{ __('app/highscore.search') }}
</a>
</div>
<div class="clearfloat"></div>
</form>
</div>
<div class="ranks-nav prev prev-top"><a href="https://web.archive.org/web/20130715184054/http://www.metin2.ro/main/guildhighscore/1/-1/1/">&lt;&lt; anterioarele 10 ranguri</a></div>
<div class="ranks-nav next next-top"><a href="https://web.archive.org/web/20130708165425/http://www.metin2.ro/main/highscore/1/-1/11/">urmatoarele 10 ranguri &gt;&gt;</a></div>
<br class="clearfloat"/>
<table border="0" style="table-layout:fixed">
<thead>
<tr>
<th class="rank-th-1">Rang</th>
<th class="rank-th-2">Numele Caracterului</th>
<th class="rank-th-3">Regat</th>
<th class="rank-th-4">Nivel</th>
<th class="rank-th-5">EXP</th>
</tr>
</thead>
<tbody>
<tr class="rankfirst">
<td class="rank-td-1-1">1</td>
<td class="rank-td-1-2">picyu3</td>
<td class="rank-td-1-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="rank-td-1-4">105</td>
<td class="rank-td-1-5">0</td>
</tr>
<tr>
<td class="rank-td-2-1">2</td>
<td class="rank-td-2-2">XXXMEN77</td>
<td class="rank-td-2-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn13/7211083d422c5dc6c70b198e850004.png" width="34" alt="Imperiul Shinsoo" title="Imperiul Shinsoo"/></td>
<td class="rank-td-2-4">105</td>
<td class="rank-td-2-5">0</td>
</tr>
<tr>
<td class="rank-td-1-1">3</td>
<td class="rank-td-1-2">Spydy</td>
<td class="rank-td-1-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn13/7211083d422c5dc6c70b198e850004.png" width="34" alt="Imperiul Shinsoo" title="Imperiul Shinsoo"/></td>
<td class="rank-td-1-4">105</td>
<td class="rank-td-1-5">0</td>
</tr>
<tr>
<td class="rank-td-2-1">4</td>
<td class="rank-td-2-2">beLeSe</td>
<td class="rank-td-2-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="rank-td-2-4">105</td>
<td class="rank-td-2-5">0</td>
</tr>
<tr>
<td class="rank-td-1-1">5</td>
<td class="rank-td-1-2">alexdenis</td>
<td class="rank-td-1-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="rank-td-1-4">105</td>
<td class="rank-td-1-5">0</td>
</tr>
<tr>
<td class="rank-td-2-1">6</td>
<td class="rank-td-2-2">addygryg</td>
<td class="rank-td-2-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="rank-td-2-4">105</td>
<td class="rank-td-2-5">0</td>
</tr>
<tr>
<td class="rank-td-1-1">7</td>
<td class="rank-td-1-2">Pixie03</td>
<td class="rank-td-1-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="rank-td-1-4">105</td>
<td class="rank-td-1-5">0</td>
</tr>
<tr>
<td class="rank-td-2-1">8</td>
<td class="rank-td-2-2">KingARAGORN</td>
<td class="rank-td-2-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn17/202178f2cf7a2e45f4be61bb360228.png" width="34" alt="Imperiul Jinno" title="Imperiul Jinno"/></td>
<td class="rank-td-2-4">105</td>
<td class="rank-td-2-5">0</td>
</tr>
<tr>
<td class="rank-td-1-1">9</td>
<td class="rank-td-1-2">pauldpv2001</td>
<td class="rank-td-1-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf3.geo.gfsrv.net/cdnbe/2bb161df7f13e26bd0545acc5967b2.png" width="34" alt="Imperiul Chunjo" title="Imperiul Chunjo"/></td>
<td class="rank-td-1-4">105</td>
<td class="rank-td-1-5">0</td>
</tr>
<tr>
<td class="rank-td-2-1">10</td>
<td class="rank-td-2-2">SCORPIO1</td>
<td class="rank-td-2-3"><img src="https://web.archive.org/web/20130708165425im_/http://gf2.geo.gfsrv.net/cdn13/7211083d422c5dc6c70b198e850004.png" width="34" alt="Imperiul Shinsoo" title="Imperiul Shinsoo"/></td>
<td class="rank-td-2-4">105</td>
<td class="rank-td-2-5">0</td>
</tr>
</tbody>
</table>
<div class="ranks-nav prev"><a href="https://web.archive.org/web/20130715184054/http://www.metin2.ro/main/guildhighscore/1/-1/1/">&lt;&lt; anterioarele 10 ranguri</a></div>
@if ($highscore->isEmpty())
<div class="error-mini error-mini-margin error-mini-maxwidth">{{ __("app/highscore.no-results") }}</div>
@else
@if ($highscore->lastPage() > 1)
<div class="ranks-nav prev prev-top">
@if ($highscore->currentPage() > 1)
<a href="{{ route('highscore-page', ['empireChoice' => $empireChoice, 'classChoice' => $classChoice, 'page' => $highscore->currentPage() - 1, 'character-choice' => $characterChoice ?? null]) }}">&lt;&lt; {{ __("app/highscore.pagination.prev", ['count' => $highscore->perPage()]) }}</a>
@endif
</div>
<div class="ranks-nav next next-top">
@if ($highscore->hasMorePages())
<a href="{{ route('highscore-page', ['empireChoice' => $empireChoice, 'classChoice' => $classChoice, 'page' => $highscore->currentPage() + 1, 'character-choice' => $characterChoice ?? null]) }}">{{ __("app/highscore.pagination.next", ['count' => $highscore->perPage()]) }} &gt;&gt;</a>
@endif
</div>
@endif
<div class="ranks-nav next"><a href="https://web.archive.org/web/20130708165425/http://www.metin2.ro/main/highscore/1/-1/11/">urmatoarele 10 ranguri &gt;&gt;</a></div>
<br class="clearfloat"/>
<table border="0" style="table-layout:fixed">
<thead>
<tr>
<th class="rank-th-1">{{ __("app/highscore.header.rank") }}</th>
<th class="rank-th-2">{{ __("app/highscore.header.character-name") }}</th>
<th class="rank-th-3">{{ __("app/highscore.header.empire") }}</th>
<th class="rank-th-4">{{ __("app/highscore.header.level") }}</th>
<th class="rank-th-5">{{ __("app/highscore.header.exp") }}</th>
</tr>
</thead>
<tbody>
@foreach ($highscore as $entry)
<tr @class(["rankfirst" => $entry->id == 1, "zebra" => $loop->odd])>
<td @class(["rank-td-1-1" => $loop->odd, "rank-td-2-1" => $loop->even])>
{{ $entry->id }}
</td>
<td @class(["rank-td-1-2" => $loop->odd, "rank-td-2-2" => $loop->even])>
{{ $entry->name }}
</td>
<td @class(["rank-td-1-3" => $loop->odd, "rank-td-2-3" => $loop->even])>
@if ($entry->empire == \App\Models\Enums\EmpireEnum::SHINSOO)
<img src="{{ asset("assets/main/img/empire1.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@elseif ($entry->empire == \App\Models\Enums\EmpireEnum::CHUNJO)
<img src="{{ asset("assets/main/img/empire2.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@elseif ($entry->empire == \App\Models\Enums\EmpireEnum::JINNO)
<img src="{{ asset("assets/main/img/empire3.png") }}" width="34" alt="{{ $entry->empire->longName() }}" title="{{ $entry->empire->longName() }}" />
@endif
</td>
<td @class(["rank-td-1-4" => $loop->odd, "rank-td-2-4" => $loop->even])>
{{ $entry->level }}
</td>
<td @class(["rank-td-1-5" => $loop->odd, "rank-td-2-5" => $loop->even])>
{{ $entry->exp }}
</td>
</tr>
@endforeach
</tbody>
</table>
<div class="clearfloat"></div>
<div class="ranks-update-time">Update: 08.07.2013 14:57:16</div>
@if ($highscore->lastPage() > 1)
<div class="ranks-nav prev">
@if ($highscore->currentPage() > 1)
<a href="{{ route('highscore-page', ['empireChoice' => $empireChoice, 'classChoice' => $classChoice, 'page' => $highscore->currentPage() - 1, 'character-choice' => $characterChoice ?? null]) }}">&lt;&lt; {{ __("app/highscore.pagination.prev", ['count' => $highscore->perPage()]) }}</a>
@endif
</div>
<div class="ranks-nav next">
@if ($highscore->hasMorePages())
<a href="{{ route('highscore-page', ['empireChoice' => $empireChoice, 'classChoice' => $classChoice, 'page' => $highscore->currentPage() + 1, 'character-choice' => $characterChoice ?? null]) }}">{{ __("app/highscore.pagination.next", ['count' => $highscore->perPage()]) }} &gt;&gt;</a>
@endif
</div>
@endif
<div class="clearfloat"></div>
<div class="ranks-update-time">{{ __('app/highscore.update-time') }} {{ $highscore->max('date')->translatedFormat('d F Y H:i:s') }}</div>
@endif
<div class="box-foot"></div>
</div>
</div>
@ -150,9 +139,4 @@
</div>
<div class="shadow">&nbsp;</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('#highscore table tr:odd').addClass('zebra');
});
</script>
@endsection

View File

@ -8,7 +8,7 @@
<div class="content-bg-bottom">
<!-- character list -->
<div class="char-list-content">
<h2>Lista caracterelor</h2>
<h2>{{ __('app/user/characters.title') }}</h2>
{{--
Pagination reverse-engineering (incomplete)
@ -30,51 +30,50 @@
</div>
--}}
<div class="charList">
<div class="charimg" rowspan="3">
<img src="{{ asset('assets/main/img/characters/0.png') }}" width="44" height="40" />
</div>
<div class="charuser">
<div class="charname">gigelfronescu</div>
<div class="charrank">
<span class="charlabel">Rang</span> <span class="chardata">#123</span>
@foreach ($characters as $character)
<div class="charList">
<div class="charimg" rowspan="3">
<img src="{{ asset("assets/main/img/characters/{$character->job->value}.png") }}" width="44" height="40" />
</div>
<div class="charuser">
<div class="charname">{{ $character->name }}</div>
<div class="charrank">
<span class="charlabel">{{ __('app/user/characters.rank') }}</span>
@if ($character->highscore)
<span class="chardata">#{{ $character->highscore->id }}</span>
@else
<span class="chardata">N/A</span>
@endif
</div>
</div>
<div class="charrow">
<div class="charclass">
<span class="charlabel">{{ __('app/user/characters.class') }}</span>
<span class="chardata">{{ $character->job->name() }}</span>
</div>
<div class="chartime">
<span class="charlabel">{{ __('app/user/characters.time') }}</span>
<span class="chardata">{{ (int) ($character->playtime / 60) }}h {{ $character->playtime % 60 }}m</span>
</div>
</div>
<div class="charrow">
<div class="charlevel">
<span class="charlabel">{{ __('app/user/characters.level') }}</span>
<span class="chardata">{{ $character->level }}</span>
</div>
<div class="charlevel">
<span class="charlabel">{{ __('app/user/characters.exp') }}</span>
<span class="chardata">{{ number_format($character->exp, 0, ',', '.') }}</span>
</div>
</div>
<div class="charrow charend">
<div class="charposition">
<span class="charlabel">{{ __('app/user/characters.empire') }}</span>
<span class="chardata">{{ $character->index->empire->name() }}</span>
</div>
</div>
</div>
<div class="charrow">
<div class="charclass"><span class="charlabel">Clasă</span> <span class="chardata">Sura</span></div>
<div class="chartime"><span class="charlabel">Timp de joc</span> <span class="chardata">3h 20m</span></div>
</div>
<div class="charrow">
<div class="charlevel"><span class="charlabel">Nivel</span><span class="chardata">69</span></div>
<div class="charlevel"><span class="charlabel">Experiență</span> <span class="chardata">1.351.561</span></div>
</div>
<div class="charrow charend">
<div class="charposition"><span class="charlabel">Regat</span> <span class="chardata">Shinsoo</span></div>
</div>
</div>
<div class="charList">
<div class="charimg" rowspan="3">
<img src="{{ asset('assets/main/img/characters/2.png') }}" width="44" height="40" />
</div>
<div class="charuser">
<div class="charname">gigelfronescu</div>
<div class="charrank">
<span class="charlabel">Rang</span> <span class="chardata">#123</span>
</div>
</div>
<div class="charrow">
<div class="charclass"><span class="charlabel">Clasă</span> <span class="chardata">Sura</span></div>
<div class="chartime"><span class="charlabel">Timp de joc</span> <span class="chardata">3h 20m</span></div>
</div>
<div class="charrow">
<div class="charlevel"><span class="charlabel">Nivel</span><span class="chardata">69</span></div>
<div class="charlevel"><span class="charlabel">Experiență</span> <span class="chardata">1.351.561</span></div>
</div>
<div class="charrow charend">
<div class="charposition"><span class="charlabel">Regat</span> <span class="chardata">Shinsoo</span></div>
</div>
</div>
@endforeach
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
@extends('layouts.app')
@section('content')
<!-- center column -->
<div class="col-2">
<div class="content content-last">
<div class="content-bg">
<div class="content-bg-bottom">
<h2>Your Account</h2>
<div class="register-inner-content">
<div class="input-data-box">
<div class="box-img"></div>
<h4>Change Password</h4>
<p>Change your password here.</p>
<div class="pass-lost-box-small" style="margin-top: 0;">
<form action="{{ url('user/passwordchangerequest') }}" method="POST" name="registerForm">
<div class="pass-lost-box-inner-content">
<label>Old Password</label>
<div class="input-data-input">
<input type="password" name="old-password" maxlength="16" value="" />
</div>
<label>New Password</label>
<div class="input-data-input">
<input type="password" name="new-password" maxlength="16" value="" />
</div>
<input class="button btn-login btn-center-input" type="submit" onclick="document.forms['registerForm'].submit();return false;" value="Send"/>
</div>
</form>
</div>
</div>
<br class="clearfloat">
<a class="btn back-btn" href="{{ url('user/administration') }}">Back</a>
</div>
</div>
</div>
</div>
<div class="shadow">&nbsp;</div>
</div>
@endsection

View File

@ -6,36 +6,42 @@
<div class="content content-last">
<div class="content-bg">
<div class="content-bg-bottom">
<h2>Înregistrarea</h2>
<h2>{{ __('app/register.title') }}</h2>
<x-registration.progress :step="1" />
<div class="inner-form-border">
<div class="inner-form-box">
<h3><a id="toLogin" href="{{ url('user/login') }}" title="sau la autentificare">sau la autentificare</a>Creează un cont</h3>
<h3>
<a id="toLogin" href="{{ url('user/login') }}" title="{{ __('app/register.to-login') }}">{{ __('app/register.to-login') }}</a>
{{ __('app/register.title') }}
</h3>
<div class="trenner"></div>
<form name="registerForm" id="registerForm" method="post" action="{{ url('user/register') }}">
@csrf
<div>
<label for="username">Nume de utilizator: *</label>
<input type="text" class="validate[required,custom[noSpecialCharacters],length[5,16]]" id="username" name="login" title="" value="" maxlength="16"/>
<label for="username">{{ __('app/register.form.username') }}: *</label>
<input type="text" class="validate[required,custom[noSpecialCharacters],length[5,16]]" id="username" name="login" title="" value="{{ old('login') }}" maxlength="16" />
</div>
<div>
<label for="email">Email: *</label>
<input type="text" class="validate[required,custom[email]]" id="email" name="email" maxlength="64" title="" value=""/>
<label for="email">{{ __('app/register.form.email') }}: *</label>
<input type="text" class="validate[required,custom[email]]" id="email" name="email" maxlength="64" title="" value="{{ old('email') }}" />
</div>
<div id="pwField">
<div id="pwInfo">
<h3><img src="{{ asset('assets/main/img/help.gif') }}" alt="Reguli parolă" title="Reguli parolă"/> O parolă sigură conţină:</h3>
<h3>
<img src="{{ asset('assets/main/img/help.gif') }}" alt="{{ __('app/register.form.password-requirements') }}" title="{{ __('app/register.form.password-requirements') }}"/>
{{ __('app/register.form.password-info.header') }}:
</h3>
<ul>
<li>între 5 și 16 caractere</li>
<li>sau cel puțin o literă mică</li>
<li>cel puțin o literă mare</li>
<li>cel puțin un număr</li>
<li>cel puțin un caracter special</li>
<li>{{ __('app/register.form.password-info.rule-1') }}</li>
<li>{{ __('app/register.form.password-info.rule-2') }}</li>
<li>{{ __('app/register.form.password-info.rule-3') }}</li>
<li>{{ __('app/register.form.password-info.rule-4') }}</li>
<li>{{ __('app/register.form.password-info.rule-5') }}</li>
</ul>
<p><strong>Caractere speciale permise</strong>:<br/>
<p><strong>{{ __('app/register.form.password-info.special-chars') }}</strong>:<br/>
@ ! # $ % &amp; ( ) { } * + ,<br/>
- . / : ; &lt; &gt; = ? [ ] ^ _ | ~
</p>
@ -53,13 +59,15 @@
});
</script>
</div>
<label for="password">Parola: *
<span id="toPwInfo" title="Reguli parolă">Reguli parolă <img src="{{ asset('assets/main/img/help.gif') }}" alt="Reguli parolă" title="Reguli parolă"/>
</span>
<label for="password">{{ __('app/register.form.password') }}: *
<span id="toPwInfo" title="{{ __('app/register.form.password-requirements') }}">
{{ __('app/register.form.password-requirements') }}
<img src="{{ asset('assets/main/img/help.gif') }}" alt="{{ __('app/register.form.password-requirements') }}" title="{{ __('app/register.form.password-requirements') }}" />
</span>
</label>
<input type="password" class="validate[required,custom[onlyValidPasswordCharacters],length[5,16]]" id="password" name="password" maxlength="16" value=""/>
<input type="password" class="validate[required,custom[onlyValidPasswordCharacters],length[5,16]]" id="password" name="password" maxlength="16" value="" />
<div id="securePwd">
<p>Nivelul de securitate al parolei voastre:</p>
<p>{{ __('app/register.form.password-security') }}:</p>
<div class="valid-icon invalid"></div>
<div class="securePwdBarBox">
<div id="securePwdBar"></div>
@ -69,9 +77,11 @@
</div>
<div id="checkerror">
<input type="checkbox" class="validate[required]" id="tac" name="tac" value="tac"/>
<span>Am citit <a href="{{ url('legal/terms') }}" target="_blank"><strong>Termenii și Condițiile</strong></a> și <a href="{{ url('legal/privacy') }}" target="_blank"><strong>Declarația privind protecția datelor</strong></a>. *</span>
<span>
{!! Str::inlineMarkdown(__('app/register.form.terms-and-conditions', ['termsUrl' => url('legal/terms'), 'privacyUrl' => url('legal/privacy')])) !!} *
</span>
</div>
<input id="submitBtn" type="submit" name="SubmitRegisterForm" value="Înregistrare" class="btn-big"/>
<input id="submitBtn" type="submit" value="{{ __('app/register.form.register-btn') }}" class="btn-big"/>
<script type="text/javascript">
@error('login')
@ -88,7 +98,7 @@
@enderror
</script>
</form>
<p id="regLegend">* este necesar</p>
<p id="regLegend">{{ __('app/register.form.required') }}</p>
</div>
</div>
</div>

View File

@ -3,12 +3,15 @@
use App\Http\Controllers\Auth\LoginController;
use App\Http\Controllers\Auth\RegisterController;
use App\Http\Controllers\Auth\VerificationController;
use App\Http\Controllers\Highscore\GuildHighscoreController;
use App\Http\Controllers\Highscore\HighscoreController;
use App\Http\Controllers\Mall\AuthController;
use App\Http\Controllers\Mall\CategoryController;
use App\Http\Controllers\Mall\HomeController;
use App\Http\Controllers\Mall\ItemController;
use App\Http\Controllers\Patch\PatchConfigController;
use App\Http\Controllers\Patch\PatchLandingController;
use App\Http\Controllers\User\CharactersController;
use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Route;
@ -31,8 +34,16 @@ Route::prefix('main')->group(function() {
Route::get('/media', fn () => view('main/media'));
Route::get('/news', fn () => view('main/news'));
Route::get('/download', fn () => view('main/download'));
Route::get('/highscore', fn () => view('main/highscore'));
Route::get('/guildhighscore', fn () => view('main/guildhighscore'));
# Highscore
Route::get('/highscore', [HighscoreController::class, 'show']);
Route::post('/highscore', [HighscoreController::class, 'search']);
Route::get('/highscore/{empireChoice}/{classChoice}/{page}', [HighscoreController::class, 'show'])->name('highscore-page');
# Guild highscore
Route::get('/guildhighscore', [GuildHighscoreController::class, 'show']);
Route::post('/guildhighscore', [GuildHighscoreController::class, 'search']);
Route::get('/guildhighscore/{empireChoice}/{page}', [GuildHighscoreController::class, 'show'])->name('guild-highscore-page');
# The game
Route::get('/thegame', fn () => view('main/thegame/thegame'));
@ -60,6 +71,7 @@ Route::prefix('user')->group(function() {
# Registration
Route::get('/register', [RegisterController::class, 'showRegistrationForm'])->middleware('guest');
Route::post('/register', [RegisterController::class, 'register'])->middleware('guest');
Route::post('/register-from-header', [RegisterController::class, 'registerFromHeader'])->middleware('guest');
Route::get('/verification/notice', [VerificationController::class, 'show'])->name('verification.notice');
Route::get('/verification/verify/{id}/{hash}', [VerificationController::class, 'verify'])->name('verification.verify');
Route::get('/verification/resend', [VerificationController::class, 'resend'])->name('verification.resend');
@ -71,14 +83,16 @@ Route::prefix('user')->group(function() {
});
Route::get('/logout', [LoginController::class, 'logout']);
Route::get('/passwordlostrequest', fn () => view('user/passwordlostrequest'));
Route::get('/passwordlost/{username}/{hash}', fn ($username, $hash) => view('user/passwordlost-expired'));
Route::get('/passwordlostrequest', fn () => view('user/password-lost/password-lost-request'));
Route::get('/passwordlost/{username}/{hash}', fn ($username, $hash) => view('user/password-lost/password-lost-expired'));
# User administration
Route::middleware(['auth', 'verified'])->group(function() {
Route::get('/administration', fn () => view('user/administration'));
Route::get('/characters', fn () => view('user/characters'));
Route::get('/characters', [CharactersController::class, 'show']);
Route::get('/passwordchangerequest', fn () => view('user/password-change/password-change-request'));
Route::get('/emailchangeaccept/{username}/{hash}', fn ($username, $hash) => view('user/emailchangeaccept'));
Route::get('/emailchangecancel/{username}/{hash}', fn ($username, $hash) => view('user/emailchangecancel'));
@ -87,7 +101,7 @@ Route::prefix('user')->group(function() {
Route::get('/generatecode/{userId}/{hash}', fn ($userId, $hash) => view('user/generatecode'));
Route::get('/lostpasswordcode/{userId}/{hash}', fn ($userId, $hash) => view('user/lostpasswordcode'));
Route::get('/lostpasswordcode/{userId}/{hash}', fn ($userId, $hash) => view('user/password-lost/password-lost-code'));
});
});