Initial commit: Shattered Void MMO foundation
- Complete PostgreSQL database schema with 21+ tables - Express.js server with dual authentication (player/admin) - WebSocket support for real-time features - Comprehensive middleware (auth, validation, logging, security) - Game systems: colonies, resources, fleets, research, factions - Plugin-based combat architecture - Admin panel foundation - Production-ready logging and error handling - Docker support and CI/CD ready - Complete project structure following CLAUDE.md patterns 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
commit
1a60cf55a3
69 changed files with 24471 additions and 0 deletions
307
src/controllers/api/player.controller.js
Normal file
307
src/controllers/api/player.controller.js
Normal file
|
|
@ -0,0 +1,307 @@
|
|||
/**
|
||||
* Player Management Controller
|
||||
* Handles player-specific operations and game-related endpoints
|
||||
*/
|
||||
|
||||
const PlayerService = require('../../services/user/PlayerService');
|
||||
const { asyncHandler } = require('../../middleware/error.middleware');
|
||||
const logger = require('../../utils/logger');
|
||||
|
||||
const playerService = new PlayerService();
|
||||
|
||||
/**
|
||||
* Get player dashboard data
|
||||
* GET /api/player/dashboard
|
||||
*/
|
||||
const getDashboard = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player dashboard request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
// Get player profile with resources and stats
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
// TODO: Add additional dashboard data such as:
|
||||
// - Recent activities
|
||||
// - Colony summaries
|
||||
// - Fleet statuses
|
||||
// - Research progress
|
||||
// - Messages/notifications
|
||||
|
||||
const dashboardData = {
|
||||
player: profile,
|
||||
summary: {
|
||||
totalColonies: profile.stats.coloniesCount,
|
||||
totalFleets: profile.stats.fleetsCount,
|
||||
totalBattles: profile.stats.totalBattles,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0
|
||||
},
|
||||
// Placeholder for future dashboard sections
|
||||
recentActivity: [],
|
||||
notifications: [],
|
||||
gameStatus: {
|
||||
online: true,
|
||||
lastTick: new Date().toISOString()
|
||||
}
|
||||
};
|
||||
|
||||
logger.info('Player dashboard data retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
username: profile.username
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Dashboard data retrieved successfully',
|
||||
data: dashboardData,
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get player resources
|
||||
* GET /api/player/resources
|
||||
*/
|
||||
const getResources = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player resources request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
logger.info('Player resources retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
scrap: profile.resources.scrap,
|
||||
energy: profile.resources.energy
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Resources retrieved successfully',
|
||||
data: {
|
||||
resources: profile.resources,
|
||||
lastUpdated: new Date().toISOString()
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get player statistics
|
||||
* GET /api/player/stats
|
||||
*/
|
||||
const getStats = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
|
||||
logger.info('Player statistics request received', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
const profile = await playerService.getPlayerProfile(playerId, correlationId);
|
||||
|
||||
const detailedStats = {
|
||||
...profile.stats,
|
||||
winRate: profile.stats.totalBattles > 0
|
||||
? Math.round((profile.stats.battlesWon / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
lossRate: profile.stats.totalBattles > 0
|
||||
? Math.round(((profile.stats.totalBattles - profile.stats.battlesWon) / profile.stats.totalBattles) * 100)
|
||||
: 0,
|
||||
accountAge: Math.floor((Date.now() - new Date(profile.createdAt).getTime()) / (1000 * 60 * 60 * 24)) // days
|
||||
};
|
||||
|
||||
logger.info('Player statistics retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
totalBattles: detailedStats.totalBattles,
|
||||
winRate: detailedStats.winRate
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Statistics retrieved successfully',
|
||||
data: {
|
||||
stats: detailedStats,
|
||||
lastUpdated: new Date().toISOString()
|
||||
},
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Update player settings
|
||||
* PUT /api/player/settings
|
||||
*/
|
||||
const updateSettings = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const settings = req.body;
|
||||
|
||||
logger.info('Player settings update request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
settingsKeys: Object.keys(settings)
|
||||
});
|
||||
|
||||
// TODO: Implement player settings update
|
||||
// This would involve:
|
||||
// 1. Validate settings data
|
||||
// 2. Update player_settings table
|
||||
// 3. Return updated settings
|
||||
|
||||
logger.warn('Player settings update requested but not implemented', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Player settings update feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get player activity log
|
||||
* GET /api/player/activity
|
||||
*/
|
||||
const getActivity = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { page = 1, limit = 20 } = req.query;
|
||||
|
||||
logger.info('Player activity log request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
page,
|
||||
limit
|
||||
});
|
||||
|
||||
// TODO: Implement player activity log retrieval
|
||||
// This would show recent actions like:
|
||||
// - Colony creations/updates
|
||||
// - Fleet movements
|
||||
// - Research completions
|
||||
// - Battle results
|
||||
// - Resource transactions
|
||||
|
||||
const mockActivity = {
|
||||
activities: [],
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total: 0,
|
||||
totalPages: 0,
|
||||
hasNext: false,
|
||||
hasPrev: false
|
||||
}
|
||||
};
|
||||
|
||||
logger.info('Player activity log retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
activitiesCount: mockActivity.activities.length
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Activity log retrieved successfully',
|
||||
data: mockActivity,
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Get player notifications
|
||||
* GET /api/player/notifications
|
||||
*/
|
||||
const getNotifications = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { unreadOnly = false } = req.query;
|
||||
|
||||
logger.info('Player notifications request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadOnly
|
||||
});
|
||||
|
||||
// TODO: Implement player notifications retrieval
|
||||
// This would show:
|
||||
// - System messages
|
||||
// - Battle results
|
||||
// - Research completions
|
||||
// - Fleet arrival notifications
|
||||
// - Player messages
|
||||
|
||||
const mockNotifications = {
|
||||
notifications: [],
|
||||
unreadCount: 0,
|
||||
totalCount: 0
|
||||
};
|
||||
|
||||
logger.info('Player notifications retrieved', {
|
||||
correlationId,
|
||||
playerId,
|
||||
unreadCount: mockNotifications.unreadCount
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
message: 'Notifications retrieved successfully',
|
||||
data: mockNotifications,
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Mark notifications as read
|
||||
* PUT /api/player/notifications/read
|
||||
*/
|
||||
const markNotificationsRead = asyncHandler(async (req, res) => {
|
||||
const correlationId = req.correlationId;
|
||||
const playerId = req.user.playerId;
|
||||
const { notificationIds } = req.body;
|
||||
|
||||
logger.info('Mark notifications read request received', {
|
||||
correlationId,
|
||||
playerId,
|
||||
notificationCount: notificationIds?.length || 0
|
||||
});
|
||||
|
||||
// TODO: Implement notification marking as read
|
||||
logger.warn('Mark notifications read requested but not implemented', {
|
||||
correlationId,
|
||||
playerId
|
||||
});
|
||||
|
||||
res.status(501).json({
|
||||
success: false,
|
||||
message: 'Mark notifications read feature not yet implemented',
|
||||
correlationId
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
getDashboard,
|
||||
getResources,
|
||||
getStats,
|
||||
updateSettings,
|
||||
getActivity,
|
||||
getNotifications,
|
||||
markNotificationsRead
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue