feat(city): add player marketplace, mission journal, character customization and presence

- Player-to-player marketplace with listings, buying and selling
- Mission system with progress tracking and money rewards
- Character appearance customization (skin, hair, face, beard, accessory)
- Multiplayer presence feed showing nearby citizens in near-real-time
- Admin world dashboard with live platform metrics
- Bus and train transportation with temporary ride state
- Mobile joystick controls and minimap HUD
- Education bonus applied to work salary
This commit is contained in:
2026-10-17 22:51:20 -03:00
parent 18778b3d26
commit a620f83dd8
30 changed files with 1822 additions and 10 deletions
@@ -0,0 +1,81 @@
<?php
namespace App\Http\Controllers\Web\Admin;
use App\Http\Controllers\Controller;
use App\Models\Building;
use App\Models\Character;
use App\Models\CharacterMessage;
use App\Models\City;
use App\Models\Job;
use App\Models\MarketListing;
use App\Models\Mission;
use App\Models\Store;
use App\Models\Transaction;
use App\Models\User;
use App\Models\UserConsent;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\View\View;
/**
* Administrator world dashboard and metrics.
*
* Aggregates live city health: citizens, economy, constructions, missions
* and marketplace activity so operators can steer the persistent world.
*/
class AdminWorldController extends Controller
{
/**
* HTML dashboard for the admin area.
*/
public function index(Request $request): View
{
abort_unless($request->user()?->isAdmin(), 403);
return view('admin.world.index', [
'metrics' => $this->metrics(),
]);
}
/**
* JSON metrics (also used by the report command).
*/
public function metrics(): array
{
return [
'users' => [
'total' => User::query()->count(),
'pending' => User::query()->where('status', User::STATUS_PENDING)->count(),
'active' => User::query()->where('status', User::STATUS_ACTIVE)->count(),
'banned' => User::query()->where('status', User::STATUS_BANNED)->count(),
'consents' => UserConsent::query()->count(),
],
'cities' => City::query()->count(),
'characters' => [
'total' => Character::query()->count(),
'online' => Character::query()->where('is_online', true)->count(),
'hospitalized' => Character::query()->where('state', Character::STATE_HOSPITAL)->count(),
'avg_health' => (int) round(Character::query()->avg('health') ?? 0),
'avg_education' => (int) round(Character::query()->avg('education') ?? 0),
'total_money' => round((float) Character::query()->sum('money'), 2),
],
'world' => [
'stores' => Store::query()->count(),
'buildings' => Building::query()->count(),
'houses_complete' => Building::query()->where('type', 'house')->where('is_complete', true)->count(),
'jobs' => Job::query()->count(),
'messages' => CharacterMessage::query()->count(),
'transactions' => Transaction::query()->count(),
'transaction_volume' => round((float) Transaction::query()->sum('amount'), 2),
],
'market' => [
'listings' => MarketListing::query()->where('is_active', true)->count(),
],
'missions' => [
'active' => Mission::query()->where('is_active', true)->count(),
'completed' => DB::table('character_missions')->where('is_completed', true)->count(),
],
];
}
}