Adds a new port district on the north-east coast with walkable quay, container yard, terminal, gantry cranes, and berths. Includes AI-driven port master (Capitão do Porto) and dock workers for ship dispatch, plus full frontend rendering of ships, boats, and trucks.
176 lines
8.9 KiB
PHP
Executable File
176 lines
8.9 KiB
PHP
Executable File
<?php
|
|
|
|
use App\Http\Controllers\Web\AccountController;
|
|
use App\Http\Controllers\Web\Admin\AdminWorldController;
|
|
use App\Http\Controllers\Web\Admin\CitizenAdminController;
|
|
use App\Http\Controllers\Web\Admin\CityAdminController;
|
|
use App\Http\Controllers\Web\Admin\StoreAdminController;
|
|
use App\Http\Controllers\Web\AuthController;
|
|
use App\Http\Controllers\Web\CharacterChatController;
|
|
use App\Http\Controllers\Web\CharacterCustomizeController;
|
|
use App\Http\Controllers\Web\ChatController;
|
|
use App\Http\Controllers\Web\CityActionController;
|
|
use App\Http\Controllers\Web\CityMarketController;
|
|
use App\Http\Controllers\Web\CityPresenceController;
|
|
use App\Http\Controllers\Web\CitySocialController;
|
|
use App\Http\Controllers\Web\CityViewerController;
|
|
use App\Http\Controllers\Web\DashboardController;
|
|
use App\Http\Controllers\Web\LanguageController;
|
|
use App\Http\Controllers\Web\LegalController;
|
|
use App\Http\Controllers\Web\PersonTalkController;
|
|
use App\Http\Middleware\EnsureTermsAccepted;
|
|
use App\Http\Middleware\EnsureUserIsAdmin;
|
|
use Illuminate\Support\Facades\Route;
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| City10 Web Routes
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Public pages (welcome, legal documents, language switch) are open to
|
|
| guests. The dashboard and consent screen require an authenticated web
|
|
| session and are blocked until the current legal documents are accepted.
|
|
|
|
|
*/
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Public pages
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Route::get('/', function () {
|
|
return view('welcome');
|
|
})->name('welcome');
|
|
|
|
Route::get('/lang', [LanguageController::class, 'switch'])->name('lang.switch');
|
|
|
|
// Legal documents (public, readable without an account).
|
|
Route::get('/legal/{type}', [LegalController::class, 'show'])
|
|
->whereIn('type', ['terms', 'privacy', 'cookies'])
|
|
->name('legal.show');
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Guest authentication
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Route::middleware('guest')->group(function (): void {
|
|
Route::get('/login', [AuthController::class, 'showLogin'])->name('login');
|
|
Route::post('/login', [AuthController::class, 'login'])->middleware('throttle:10,1');
|
|
Route::get('/register', [AuthController::class, 'showRegister'])->name('register');
|
|
Route::post('/register', [AuthController::class, 'register'])->middleware('throttle:10,1');
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Authenticated area
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Route::middleware('auth')->group(function (): void {
|
|
Route::post('/logout', [AuthController::class, 'logout'])->name('logout');
|
|
|
|
// Pending registration wait screen (reachable before full approval).
|
|
Route::get('/account/pending', [AccountController::class, 'pending'])->name('account.pending');
|
|
|
|
// Consent screen is reachable even before terms are accepted (by design).
|
|
Route::get('/terms/accept', [LegalController::class, 'acceptForm'])->name('terms.accept');
|
|
Route::post('/terms/accept', [LegalController::class, 'accept'])->name('terms.accept.store');
|
|
Route::get('/terms/history', [LegalController::class, 'history'])->name('terms.history');
|
|
|
|
// Main platform features (blocked until terms are accepted).
|
|
Route::middleware(EnsureTermsAccepted::class)->group(function (): void {
|
|
Route::get('/dashboard', DashboardController::class)->name('dashboard');
|
|
|
|
// 3D city viewer (Phase 3).
|
|
Route::get('/city', CityViewerController::class)->name('city.viewer');
|
|
Route::get('/city/data', [CityViewerController::class, 'data'])->name('city.data');
|
|
|
|
// Citizen lifecycle actions inside the world.
|
|
Route::post('/city/actions/position', [CityActionController::class, 'position'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.actions.position');
|
|
Route::post('/city/actions/{action}', [CityActionController::class, 'handle'])
|
|
->middleware('throttle:90,1')
|
|
->name('city.actions.handle');
|
|
|
|
// Character social graph and chat.
|
|
Route::post('/city/social/{verb}', [CitySocialController::class, 'handle'])
|
|
->middleware('throttle:30,1')
|
|
->name('city.social.handle');
|
|
Route::get('/city/social/inbox', [CitySocialController::class, 'inbox'])->name('city.social.inbox');
|
|
Route::post('/city/messages/{character}', [CharacterChatController::class, 'send'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.messages.send');
|
|
Route::get('/city/messages/{character}', [CharacterChatController::class, 'index'])->name('city.messages.index');
|
|
|
|
// Multiplayer presence + marketplace + journal + cosmetics.
|
|
Route::get('/city/presence', CityPresenceController::class)
|
|
->middleware('throttle:60,1')
|
|
->name('city.presence');
|
|
Route::get('/city/market', [CityMarketController::class, 'index'])->name('city.market.index');
|
|
Route::post('/city/market/sell', [CityMarketController::class, 'sell'])
|
|
->middleware('throttle:30,1')
|
|
->name('city.market.sell');
|
|
Route::post('/city/market/buy', [CityMarketController::class, 'buy'])
|
|
->middleware('throttle:30,1')
|
|
->name('city.market.buy');
|
|
Route::get('/city/customize', [CharacterCustomizeController::class, 'show'])->name('city.customize.show');
|
|
Route::put('/city/customize', [CharacterCustomizeController::class, 'update'])
|
|
->middleware('throttle:20,1')
|
|
->name('city.customize.update');
|
|
|
|
// NPC chat (SSE stream + message POST).
|
|
Route::post('/city/chat/{agent}', [ChatController::class, 'send'])
|
|
->middleware('throttle:30,1')
|
|
->name('city.chat.send');
|
|
Route::get('/city/chat/{agent}/stream', [ChatController::class, 'stream'])->name('city.chat.stream');
|
|
|
|
// Daily street conversations (bump-to-talk) with persistent context.
|
|
Route::get('/talk/person', [PersonTalkController::class, 'index'])
|
|
->middleware('throttle:120,1')
|
|
->name('talk.person.index');
|
|
Route::post('/talk/person', [PersonTalkController::class, 'send'])
|
|
->middleware('throttle:30,1')
|
|
->name('talk.person.send');
|
|
|
|
// Airport ops: site info + ATC clearances (AI_ATC_MODEL).
|
|
Route::get('/city/airport', [CityViewerController::class, 'airport'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.airport');
|
|
Route::post('/city/airport/dispatch', [CityViewerController::class, 'dispatch'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.airport.dispatch');
|
|
|
|
// Port ops: geometry, Capitania clearances (AI-driven maneuvers).
|
|
Route::get('/city/port', [CityViewerController::class, 'port'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.port');
|
|
Route::post('/city/port/dispatch', [CityViewerController::class, 'dispatchPort'])
|
|
->middleware('throttle:60,1')
|
|
->name('city.port.dispatch');
|
|
});
|
|
});
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Admin area (administrator role required, on top of auth + terms)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
Route::middleware(['auth', EnsureTermsAccepted::class, EnsureUserIsAdmin::class])
|
|
->prefix('admin')
|
|
->name('admin.')
|
|
->group(function (): void {
|
|
Route::get('/stores', [StoreAdminController::class, 'index'])->name('stores.index');
|
|
Route::get('/stores/create', [StoreAdminController::class, 'create'])->name('stores.create');
|
|
Route::post('/stores', [StoreAdminController::class, 'store'])->name('stores.store');
|
|
Route::get('/stores/{store}/edit', [StoreAdminController::class, 'edit'])->name('stores.edit');
|
|
Route::put('/stores/{store}', [StoreAdminController::class, 'update'])->name('stores.update');
|
|
Route::delete('/stores/{store}', [StoreAdminController::class, 'destroy'])->name('stores.destroy');
|
|
|
|
Route::get('/citizens', [CitizenAdminController::class, 'index'])->name('citizens.index');
|
|
Route::post('/citizens/{user}/approve', [CitizenAdminController::class, 'approve'])->name('citizens.approve');
|
|
Route::post('/citizens/{user}/ban', [CitizenAdminController::class, 'ban'])->name('citizens.ban');
|
|
|
|
Route::get('/cities', [CityAdminController::class, 'index'])->name('cities.index');
|
|
Route::post('/cities', [CityAdminController::class, 'store'])->name('cities.store');
|
|
Route::post('/cities/{city}/expand', [CityAdminController::class, 'expand'])->name('cities.expand');
|
|
|
|
Route::get('/world', [AdminWorldController::class, 'index'])->name('world.index');
|
|
});
|