Skip to main content

Submit Leaderboard Score

The submit leaderboard score method allows players to submit their scores to specific leaderboards. This is used for ongoing competitions and ranking systems outside of tournaments.

Overview

The submitScore method:

  • Submits player scores to specific leaderboards
  • Updates leaderboard rankings in real-time
  • Validates player participation and score validity
  • Returns status code indicating success or failure

Method Signature

public function submitScore(string $gameID, string $leaderboardID, int $score): int

Parameters

Required Parameters

  • gameID (String) - The Game ID for the leaderboard
  • leaderboardID (String) - The Leaderboard ID to submit score to
  • score (int) - The player's score to submit

Return Value

Returns an integer status code:

  • Positive value - Score submitted successfully
  • Zero or negative - Submission failed

Basic Usage

Simple Score Submission

use Veniso\Moitribe\Sdk\modules\classes\MoitribeApi;

$moitribe = new MoitribeApi([
'gameid' => 'your-game-id',
'channelid' => 'your-channel-id',
'playerid' => 'player-123'
]);

try {
$result = $moitribe->leaderboardRequestsHandler->submitScore(
'your-game-id',
'leaderboard-123',
2500
);

if ($result > 0) {
echo "Score submitted successfully!\n";
echo "Submission ID: " . $result . "\n";
} else {
echo "Failed to submit score\n";
echo "Error code: " . $result . "\n";
}

} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}

Score Submission with Validation

function submitLeaderboardScore($gameId, $leaderboardId, $score, $gameSessionData) {
global $moitribe;

try {
// Validate score
if ($score < 0) {
return ['success' => false, 'message' => 'Score cannot be negative'];
}

// Check if leaderboard exists and is active
$leaderboards = $moitribe->leaderboardRequestsHandler->getLeaderboards($gameId);
$targetLeaderboard = null;

foreach ($leaderboards as $leaderboard) {
if ($leaderboard->getId() === $leaderboardId) {
$targetLeaderboard = $leaderboard;
break;
}
}

if (!$targetLeaderboard) {
return ['success' => false, 'message' => 'Leaderboard not found'];
}

if ($targetLeaderboard->getStatus() !== 'active') {
return ['success' => false, 'message' => 'Leaderboard is not active'];
}

// Submit score
$result = $moitribe->leaderboardRequestsHandler->submitScore(
$gameId,
$leaderboardId,
$score
);

if ($result > 0) {
// Log submission
$this->logScoreSubmission($leaderboardId, $score, $gameSessionData, $result);

return [
'success' => true,
'message' => 'Score submitted successfully',
'submission_id' => $result,
'leaderboard_name' => $targetLeaderboard->getName()
];
} else {
return [
'success' => false,
'message' => 'Failed to submit score',
'error_code' => $result
];
}

} catch (Exception $e) {
error_log("Leaderboard score submission error: " . $e->getMessage());
return [
'success' => false,
'message' => 'Server error occurred'
];
}
}

// Usage
$gameSession = [
'level' => 12,
'time_played' => 900, // 15 minutes
'difficulty' => 'hard',
'character' => 'warrior'
];

$result = submitLeaderboardScore('your-game-id', 'leaderboard-456', 3200, $gameSession);

if ($result['success']) {
echo "Success: " . $result['message'] . "\n";
echo "Leaderboard: " . $result['leaderboard_name'] . "\n";
echo "Submission ID: " . $result['submission_id'] . "\n";
} else {
echo "Error: " . $result['message'] . "\n";
}

Integration Examples

Real-time Score Submission

class LeaderboardScoreManager {
private $moitribe;
private $gameId;
private $scoreQueue = [];

public function __construct($moitribe, $gameId) {
$this->moitribe = $moitribe;
$this->gameId = $gameId;
}

public function queueScoreSubmission($leaderboardId, $score, $metadata = []) {
$this->scoreQueue[] = [
'leaderboard_id' => $leaderboardId,
'score' => $score,
'timestamp' => time(),
'metadata' => $metadata,
'attempts' => 0
];

return count($this->scoreQueue);
}

public function processScoreQueue() {
$processed = 0;
$failed = 0;

foreach ($this->scoreQueue as $index => &$scoreSubmission) {
try {
$scoreSubmission['attempts']++;

$result = $this->moitribe->leaderboardRequestsHandler->submitScore(
$this->gameId,
$scoreSubmission['leaderboard_id'],
$scoreSubmission['score']
);

if ($result > 0) {
$this->logSuccessfulSubmission($scoreSubmission, $result);
unset($this->scoreQueue[$index]);
$processed++;
} else {
$this->logFailedSubmission($scoreSubmission, $result);
$failed++;

// Remove from queue after 3 attempts
if ($scoreSubmission['attempts'] >= 3) {
unset($this->scoreQueue[$index]);
}
}

} catch (Exception $e) {
error_log("Score processing error: " . $e->getMessage());
$failed++;

if ($scoreSubmission['attempts'] >= 3) {
unset($this->scoreQueue[$index]);
}
}

// Small delay to avoid overwhelming API
usleep(50000); // 0.05 seconds
}

return [
'processed' => $processed,
'failed' => $failed,
'remaining' => count($this->scoreQueue)
];
}

public function getQueueStatus() {
return [
'total_queued' => count($this->scoreQueue),
'queue' => $this->scoreQueue
];
}

private function logSuccessfulSubmission($submission, $submissionId) {
$logData = [
'submission_id' => $submissionId,
'leaderboard_id' => $submission['leaderboard_id'],
'score' => $submission['score'],
'timestamp' => $submission['timestamp'],
'metadata' => $submission['metadata'],
'status' => 'success',
'processed_at' => date('Y-m-d H:i:s')
];

error_log("Score submitted successfully: " . json_encode($logData));
}

private function logFailedSubmission($submission, $errorCode) {
$logData = [
'leaderboard_id' => $submission['leaderboard_id'],
'score' => $submission['score'],
'timestamp' => $submission['timestamp'],
'attempts' => $submission['attempts'],
'error_code' => $errorCode,
'status' => 'failed'
];

error_log("Score submission failed: " . json_encode($logData));
}
}

// Usage
$scoreManager = new LeaderboardScoreManager($moitribe, 'your-game-id');

// Queue multiple scores during gameplay
$scoreManager->queueScoreSubmission('daily-leaderboard', 1500, [
'level' => 10,
'character' => 'mage'
]);

$scoreManager->queueScoreSubmission('weekly-leaderboard', 2800, [
'level' => 10,
'character' => 'mage'
]);

// Process queue (could be called periodically)
$result = $scoreManager->processScoreQueue();

echo "Processed: {$result['processed']}, Failed: {$result['failed']}, Remaining: {$result['remaining']}\n";

Web Score Submission Handler

function handleLeaderboardScoreSubmission() {
global $moitribe;

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
echo json_encode(['error' => 'Method not allowed']);
return;
}

$input = json_decode(file_get_contents('php://input'), true);

$requiredFields = ['game_id', 'leaderboard_id', 'player_id', 'score'];
foreach ($requiredFields as $field) {
if (!isset($input[$field])) {
http_response_code(400);
echo json_encode(['error' => "Missing required field: $field"]);
return;
}
}

$gameId = $input['game_id'];
$leaderboardId = $input['leaderboard_id'];
$playerId = $input['player_id'];
$score = (int)$input['score'];
$metadata = $input['metadata'] ?? [];

try {
// Validate inputs
if (empty($gameId) || empty($leaderboardId) || empty($playerId)) {
throw new InvalidArgumentException('Game ID, Leaderboard ID, and Player ID are required');
}

if (!is_int($score) || $score < 0) {
throw new InvalidArgumentException('Score must be a non-negative integer');
}

// Submit score
$result = $moitribe->leaderboardRequestsHandler->submitScore(
$gameId,
$leaderboardId,
$score
);

if ($result > 0) {
// Log submission
$this->logWebScoreSubmission($gameId, $leaderboardId, $playerId, $score, $metadata, $result);

http_response_code(200);
echo json_encode([
'success' => true,
'message' => 'Score submitted successfully',
'submission_id' => $result
]);
} else {
http_response_code(400);
echo json_encode([
'success' => false,
'message' => 'Failed to submit score',
'error_code' => $result
]);
}

} catch (InvalidArgumentException $e) {
http_response_code(400);
echo json_encode(['success' => false, 'message' => $e->getMessage()]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['success' => false, 'message' => 'Server error occurred']);
error_log("Leaderboard score API error: " . $e->getMessage());
}
}

function logWebScoreSubmission($gameId, $leaderboardId, $playerId, $score, $metadata, $submissionId) {
$logData = [
'submission_id' => $submissionId,
'game_id' => $gameId,
'leaderboard_id' => $leaderboardId,
'player_id' => $playerId,
'score' => $score,
'metadata' => $metadata,
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
'timestamp' => date('Y-m-d H:i:s')
];

error_log("Web score submission: " . json_encode($logData));
}

// Route handler
if (strpos($_SERVER['REQUEST_URI'], '/api/leaderboard/submit-score') !== false) {
handleLeaderboardScoreSubmission();
}

Error Handling

Common Error Scenarios

  • Invalid leaderboard ID - Leaderboard doesn't exist
  • Leaderboard not active - Leaderboard is disabled or archived
  • Invalid score - Negative or unrealistic score values
  • Player not eligible - Player doesn't meet requirements
  • Duplicate submission - Same score submitted multiple times
  • Network issues - API communication problems

Error Handling Example

function safeSubmitLeaderboardScore($gameId, $leaderboardId, $score) {
global $moitribe;

try {
// Validate inputs
if (empty($gameId) || empty($leaderboardId)) {
throw new InvalidArgumentException("Game ID and Leaderboard ID are required");
}

if (!is_int($score) || $score < 0) {
throw new InvalidArgumentException("Score must be a non-negative integer");
}

$result = $moitribe->leaderboardRequestsHandler->submitScore(
$gameId,
$leaderboardId,
$score
);

if ($result > 0) {
return [
'success' => true,
'submission_id' => $result,
'message' => 'Score submitted successfully'
];
} else {
$errorMessage = $this->getScoreSubmissionErrorMessage($result);
return [
'success' => false,
'message' => $errorMessage,
'error_code' => $result
];
}

} catch (InvalidArgumentException $e) {
return [
'success' => false,
'message' => 'Invalid input: ' . $e->getMessage()
];
} catch (Exception $e) {
error_log("Leaderboard score submission error: " . $e->getMessage());
return [
'success' => false,
'message' => 'Failed to submit score'
];
}
}

function getScoreSubmissionErrorMessage($errorCode) {
switch ($errorCode) {
case 0:
return 'Score submission failed';
case -1:
return 'Leaderboard not found';
case -2:
return 'Leaderboard is not active';
case -3:
return 'Invalid score value';
case -4:
return 'Player not eligible for this leaderboard';
case -5:
return 'Duplicate score submission';
default:
return 'Unknown error occurred';
}
}

Best Practices

  1. Validate Score Values

    • Ensure scores are non-negative integers
    • Check for realistic score ranges
    • Validate against game rules
  2. Implement Rate Limiting

    • Avoid spamming score submissions
    • Implement cooldown periods between submissions
    • Queue submissions for batch processing
  3. Handle Network Issues

    • Implement retry mechanisms for failed submissions
    • Store failed submissions for later retry
    • Provide offline submission capabilities
  4. Log Submission Events

    • Track all score submissions for analytics
    • Monitor for unusual patterns or cheating
    • Maintain audit trails