first commit

This commit is contained in:
2026-03-11 22:04:36 +04:00
commit bae063a4fa
69 changed files with 12411 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
<?php
namespace App\Http\Controllers;
abstract class Controller
{
//
}
+112
View File
@@ -0,0 +1,112 @@
<?php
namespace App\Http\Controllers;
use App\Exceptions\DuplicateGameAccountException;
use App\Http\Requests\RegisterGameAccountRequest;
use App\Services\AzerothCoreAccountRegistrar;
use Illuminate\Http\RedirectResponse;
use Illuminate\View\View;
use Throwable;
class LandingController extends Controller
{
public function index(): View
{
$realm = config('moonwell.realm');
return view('landing', [
'realm' => $realm,
'highlights' => [
['value' => $realm['client_version'], 'label' => 'Клиент'],
['value' => '1+', 'label' => 'Игрок в инсте'],
['value' => 'Свой', 'label' => 'лаунчер'],
['value' => 'Быстрый', 'label' => 'сбор добычи'],
],
'pillars' => [
[
'title' => 'Персональная прогрессия',
'description' => 'Каждый персонаж проходит контент поэтапно: старые зоны, подземелья и рейды не теряют смысл после старта.',
],
[
'title' => 'Инсты под любой состав',
'description' => 'Автобаланс подстраивает сложность под количество игроков, поэтому данжи и рейды остаются проходимыми даже малой группой.',
],
[
'title' => 'Комфорт для малого состава',
'description' => 'Даже если вы играете соло или небольшой компанией, подземелья и другой PvE-контент остаются доступными и удобными для прохождения.',
],
[
'title' => 'Меньше рутины',
'description' => 'Базовые заклинания учатся автоматически, а лут с ближайших мобов собирается быстрее — меньше лишней беготни, больше игры.',
],
[
'title' => 'Собственный лаунчер',
'description' => 'Игрок получает удобную точку входа в проект: отдельный лаунчер помогает держать клиент и запуск под рукой.',
],
],
'featureRows' => [
[
'eyebrow' => 'Прогрессия персонажа',
'title' => 'Контент открывается по мере развития героя',
'description' => 'Система персональной прогрессии делает путь важнее спешки к эндгейму: каждый персонаж идёт по своему этапу и открывает контент постепенно.',
'points' => ['Старый контент остаётся актуальным', 'Разблокировки идут по мере продвижения', 'Групповая игра учитывает этап прогрессии'],
],
[
'eyebrow' => 'Комфортный PvE',
'title' => 'Подземелья и рейды не зависят от полного рейдового состава',
'description' => 'Сервер адаптирован для соло-игроков и небольших компаний, поэтому начинать и проходить PvE-контент заметно проще.',
'points' => ['Сложность масштабируется под размер группы', 'Комфортно играть соло и в малом составе', 'Прохождение не требует полного рейдового набора'],
],
],
'adventures' => [
[
'title' => 'Быстрый сбор добычи',
'description' => 'Добыча с ближайших противников собирается заметно быстрее — особенно удобно во время фарма и массовых боёв.',
],
[
'title' => 'Автообучение заклинаниям',
'description' => 'Классовые способности, ранги заклинаний и часть связанных навыков выдаются автоматически по мере развития персонажа.',
],
[
'title' => 'Кастомные игровые системы',
'description' => 'На сервере уже есть база для развития особых режимов, сезонных активностей и дополнительных игровых сервисов.',
],
[
'title' => 'Простая регистрация',
'description' => 'Игровой аккаунт создаётся сразу на сайте, без отдельной панели и ручных команд на сервере.',
],
],
'steps' => [
['title' => 'Создай аккаунт', 'description' => 'Заполни форму регистрации и получи логин для входа в игровой мир.'],
['title' => 'Скачай лаунчер', 'description' => 'Установи собственный лаунчер проекта и подготовь клиент к запуску.'],
['title' => 'Входи в игру', 'description' => sprintf('Запусти клиент, при необходимости используй realmlist %s и отправляйся в Азерот.', $realm['realmlist'])],
],
]);
}
public function register(RegisterGameAccountRequest $request, AzerothCoreAccountRegistrar $registrar): RedirectResponse
{
try {
$result = $registrar->register(
$request->string('username')->toString(),
$request->string('email')->toString(),
$request->string('password')->toString(),
);
} catch (DuplicateGameAccountException $exception) {
return back()
->withErrors([$exception->field => $exception->getMessage()])
->withInput($request->safe()->only(['username', 'email']));
} catch (Throwable $exception) {
report($exception);
return back()
->with('registration_error', 'Не удалось создать аккаунт. Проверь настройки сервера и попробуй снова.')
->withInput($request->safe()->only(['username', 'email']));
}
return redirect()
->route('landing.index')
->with('registration_success', sprintf('Игровой аккаунт %s успешно создан. Теперь можно входить в клиент WoW.', $result['username']));
}
}
@@ -0,0 +1,64 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class RegisterGameAccountRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
/**
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
*/
public function rules(): array
{
return [
'username' => ['required', 'string', 'min:3', 'max:32', 'regex:/^[A-Za-z0-9]+$/'],
'email' => ['required', 'string', 'email:rfc', 'max:255'],
'password' => ['required', 'string', 'min:8', 'max:32', 'confirmed', 'regex:/^(?=.*[A-Za-z])(?=.*\d).+$/'],
'terms' => ['accepted'],
];
}
/**
* @return array<string, string>
*/
public function messages(): array
{
return [
'username.required' => 'Укажи логин аккаунта.',
'username.string' => 'Логин должен быть строкой.',
'username.min' => 'Логин должен содержать минимум 3 символа.',
'username.max' => 'Логин не должен быть длиннее 32 символов.',
'username.regex' => 'Логин может содержать только латинские буквы и цифры.',
'email.required' => 'Укажи email для аккаунта.',
'email.string' => 'Email должен быть строкой.',
'email.email' => 'Укажи корректный email адрес.',
'email.max' => 'Email не должен быть длиннее 255 символов.',
'password.required' => 'Укажи пароль.',
'password.string' => 'Пароль должен быть строкой.',
'password.min' => 'Пароль должен содержать минимум 8 символов.',
'password.max' => 'Пароль не должен быть длиннее 32 символов.',
'password.confirmed' => 'Подтверждение пароля не совпадает.',
'password.regex' => 'Пароль должен содержать хотя бы одну букву и одну цифру.',
'terms.accepted' => 'Нужно принять правила сервера и пользовательское соглашение.',
];
}
/**
* @return array<string, string>
*/
public function attributes(): array
{
return [
'username' => 'логин аккаунта',
'email' => 'email',
'password' => 'пароль',
'terms' => 'правила',
];
}
}