diff --git a/.github/workflows/sonarcloud.yml b/.github/workflows/sonarcloud.yml index 35b8ea8..1d62c7d 100644 --- a/.github/workflows/sonarcloud.yml +++ b/.github/workflows/sonarcloud.yml @@ -14,6 +14,15 @@ jobs: - uses: actions/checkout@v6.0.2 with: fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis + - name: Set up PHP with Xdebug + uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + coverage: xdebug + - name: Install dependencies + run: composer install --prefer-dist --no-progress --no-interaction + - name: Run PHPUnit with coverage + run: php -d xdebug.mode=coverage vendor/bin/phpunit --coverage-clover=coverage.xml - name: SonarCloud Scan uses: SonarSource/sonarcloud-github-action@master env: diff --git a/.gitignore b/.gitignore index eff6085..bf0ecf3 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,6 @@ vendor/ # PHPUnit cache .phpunit.result.cache +# PHPUnit coverage output +coverage.xml + diff --git a/Handler/AllyListHandler.php b/Handler/AllyListHandler.php new file mode 100644 index 0000000..38d1c59 --- /dev/null +++ b/Handler/AllyListHandler.php @@ -0,0 +1,46 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + if (!isset($data['tag'], $data['allyList'])) { + throw new UnexpectedValueException('Allylist: Missing Value'); + } + + $tag = filter_var($data['tag']); + $members = []; + foreach ($data['allyList'] as $member) { + if (!isset($member['player'], $member['points'], $member['rank'], $member['coords'])) { + throw new UnexpectedValueException('Allylist: Missing Ally Detailed list'); + } + $members[] = [ + 'pseudo' => filter_var($member['player']), + 'points' => filter_var($member['points'], FILTER_SANITIZE_NUMBER_INT), + 'coords' => explode(':', $member['coords']), + 'rang' => filter_var($member['rank'], FILTER_SANITIZE_NUMBER_INT), + ]; + } + + $this->registerCallback('ally_list', ['list' => $members, 'tag' => $tag]); + $this->io->set(['type' => 'ally_list', 'tag' => $tag]); + $this->logAction('ally_list', ['tag' => $tag]); + } + + public function getType(): string + { + return 'ally_list'; + } + + public function getRequiredGrant(): string + { + return 'ranking'; + } +} diff --git a/Handler/BuildingsHandler.php b/Handler/BuildingsHandler.php new file mode 100644 index 0000000..309123e --- /dev/null +++ b/Handler/BuildingsHandler.php @@ -0,0 +1,70 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $coordinates = filter_var($data['planet']['coords']); + $planetName = filter_var($data['planet']['name']); + $planetType = filter_var($data['planet']['type']); + $planetId = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); + if (!isset($coordinates, $planetName, $planetType)) { + throw new UnexpectedValueException('Buildings- Missing data'); + } + + $buildings = $data['buildings']; + $coordinates = Check::coords($coordinates); + [$galaxy, $system, $position] = explode(':', $coordinates); + $planetType = $this->resolvePlanetType($planetType); + + $columns = ['id', 'galaxy', 'system', 'row', 'name']; + $values = [$planetId, $galaxy, $system, $position, $planetName]; + foreach ($this->database['buildings'] as $code) { + if (isset($buildings[$code])) { + $columns[] = $code; + $values[] = (int)$buildings[$code]; + } + } + + $updatePairs = ['name = VALUES(name)', 'galaxy = VALUES(galaxy)', 'system = VALUES(system)', 'row = VALUES(row)']; + foreach ($this->database['buildings'] as $code) { + if (isset($buildings[$code])) { + $updatePairs[] = "`$code` = VALUES(`$code`)"; + } + } + + $query = "INSERT INTO " . TABLE_USER_BUILDING . " (`" . implode('`, `', $columns) . "`) + VALUES (" . implode(', ', array_map(static function ($value) { + return is_numeric($value) ? $value : "'$value'"; + }, $values)) . ") + ON DUPLICATE KEY UPDATE " . implode(', ', $updatePairs); + $this->db->sql_query($query); + + $this->setPageUpdatedResponse('buildings', $coordinates); + $this->registerCallback('buildings', [ + 'coords' => explode(':', $coordinates), + 'planet_type' => $planetType, + 'planet_name' => $planetName, + 'buildings' => $buildings, + ]); + $this->logAction('buildings', ['coords' => $coordinates, 'planet_name' => $planetName]); + } + + public function getType(): string + { + return 'buildings'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/CombatReportHandler.php b/Handler/CombatReportHandler.php new file mode 100644 index 0000000..c12ed60 --- /dev/null +++ b/Handler/CombatReportHandler.php @@ -0,0 +1,218 @@ + 'PT', 203 => 'GT', 204 => 'CLE', 205 => 'CLO', 206 => 'CR', + 207 => 'VB', 208 => 'VC', 209 => 'REC', 210 => 'SE', 211 => 'BMD', + 212 => 'SAT', 213 => 'DST', 214 => 'EDLM', 215 => 'TRA', 217 => 'FOR', + 218 => 'FAU', 219 => 'ECL', + ]; + + private const DEFENSE_TECHNOLOGIES = [ + 401 => 'LM', 402 => 'LLE', 403 => 'LLO', 404 => 'CG', 405 => 'AI', + 406 => 'LP', 407 => 'PB', 408 => 'GB', 502 => 'MIC', 503 => 'MIP', + ]; + + public function handle(array $data): void + { + $reportType = $data['_xtense_request_type'] ?? 'rc'; + $rawPayload = $data['_xtense_raw_payload'] ?? json_encode($data); + unset($data['_xtense_request_type'], $data['_xtense_raw_payload']); + $api = filter_var($data['ogapilnk'] ?? '', FILTER_DEFAULT) ?: ''; + + if (!isset($data['timestamp'])) { + throw new UnexpectedValueException('Combat Report: Timestamp not sent'); + } + if (!$this->requireGrant($this->getRequiredGrant())) { + return; + } + + $this->registerCallback('rc', ['json' => $rawPayload, 'api' => $api]); + $timestamp = (int)$data['timestamp']; + $existing = $this->db->sql_fetch_row($this->db->sql_query( + "SELECT `id_rc` FROM " . TABLE_PARSEDRC . " WHERE `dateRC` = '{$timestamp}'" + )); + if (isset($existing[0])) { + $this->io->set(['type' => $reportType]); + $this->logAction($reportType); + return; + } + + $coordinates = $this->parseCoordinates($data['coordinates'])['coords']; + $rounds = $data['combatRounds'] ?? []; + $winner = match ($data['result']['winner'] ?? null) { + 'draw' => 'N', + 'attacker' => 'A', + 'defender' => 'D', + default => throw new UnexpectedValueException('Combat Report: Result not found'), + }; + + $loot = $this->resourceAmounts($data['result']['loot']['resources'] ?? []); + $debris = $this->resourceAmounts($data['result']['debris']['resources'] ?? []); + $losses = ['attacker' => 0, 'defender' => 0]; + foreach ($data['result']['totalValueOfUnitsLost'] ?? [] as $loss) { + if (isset($losses[$loss['side'] ?? ''])) { + $losses[$loss['side']] = (int)($loss['value'] ?? 0); + } + } + $moonChance = (int)($data['result']['moonCreation']['chance'] ?? 0); + + $defenderObject = $data['defenderSpaceObject'] ?? []; + $objectType = $this->db->sql_escape_string((string)($defenderObject['type'] ?? '')); + $parsedCoordinates = $this->parseCoordinates($coordinates); + $objectResult = $this->db->sql_query("SELECT id FROM " . TABLE_USER_BUILDING . " + WHERE galaxy = {$parsedCoordinates['galaxy']} AND system = {$parsedCoordinates['system']} + AND row = {$parsedCoordinates['row']} AND type = '{$objectType}' + ORDER BY last_update DESC LIMIT 1"); + $objectRow = $this->db->sql_fetch_row($objectResult); + $astroObjectId = isset($objectRow[0]) ? (int)$objectRow[0] : null; + if ($astroObjectId === null) { + throw new UnexpectedValueException("Combat Report: Astro object not found for coordinates {$coordinates} with type {$objectType}"); + } + + $this->db->sql_query("INSERT INTO " . TABLE_PARSEDRC . " ( + `dateRC`, `astro_object_id`, `nb_rounds`, `victoire`, `pertes_A`, `pertes_D`, + `gain_M`, `gain_C`, `gain_D`, `debris_M`, `debris_C`, `lune` + ) VALUES ( + {$timestamp}, {$astroObjectId}, " . count($rounds) . ", '{$winner}', {$losses['attacker']}, {$losses['defender']}, + {$loot['metal']}, {$loot['crystal']}, {$loot['deuterium']}, {$debris['metal']}, {$debris['crystal']}, {$moonChance} + )"); + $reportId = (int)$this->db->sql_insertid(); + + $combatants = $this->indexCombatants($data['fleets'] ?? []); + foreach ($rounds as $roundNumber => $round) { + $statistics = $this->roundStatistics($round['statistics'] ?? []); + $this->db->sql_query("INSERT INTO " . TABLE_PARSEDRCROUND . " ( + `id_rc`, `numround`, `attaque_tir`, `attaque_puissance`, `defense_bouclier`, + `attaque_bouclier`, `defense_tir`, `defense_puissance` + ) VALUES ( + {$reportId}, " . (int)$roundNumber . ", {$statistics['attacker']['hits']}, {$statistics['attacker']['strength']}, + {$statistics['defender']['absorbedDamage']}, {$statistics['attacker']['absorbedDamage']}, + {$statistics['defender']['hits']}, {$statistics['defender']['strength']} + )"); + $roundId = (int)$this->db->sql_insertid(); + if ($roundId === 0) { + throw new UnexpectedValueException("Combat Report: Failed to insert round {$roundNumber}"); + } + + foreach ($round['fleets'] ?? [] as $fleet) { + $this->insertRoundFleet($roundId, $astroObjectId, $fleet, $combatants); + } + } + + $this->io->set(['type' => $reportType]); + $this->logAction($reportType); + } + + private function resourceAmounts(array $resources): array + { + $amounts = ['metal' => 0, 'crystal' => 0, 'deuterium' => 0]; + foreach ($resources as $resource) { + $name = $resource['resource'] ?? ''; + if (array_key_exists($name, $amounts)) { + $amounts[$name] = (int)($resource['amount'] ?? 0); + } + } + return $amounts; + } + + private function indexCombatants(array $fleets): array + { + $combatants = ['attacker' => [], 'defender' => []]; + foreach ($fleets as $fleet) { + $side = $fleet['side'] ?? ''; + if (!isset($combatants[$side])) { + continue; + } + $research = ['armor' => 0, 'weapon' => 0, 'shield' => 0]; + foreach ($fleet['combatResearchPercentage'] ?? [] as $technology) { + $key = match ((int)($technology['id'] ?? 0)) { + 109 => 'armor', + 110 => 'weapon', + 111 => 'shield', + default => null, + }; + if ($key !== null) { + $research[$key] = (int)($technology['percentage'] ?? 0); + } + } + $player = $fleet['player'] ?? []; + $combatants[$side][(string)($player['name'] ?? '')] = $research; + } + return $combatants; + } + + private function roundStatistics(array $statistics): array + { + $result = [ + 'attacker' => ['hits' => 0, 'strength' => 0, 'absorbedDamage' => 0], + 'defender' => ['hits' => 0, 'strength' => 0, 'absorbedDamage' => 0], + ]; + foreach ($statistics as $stat) { + $side = $stat['side'] ?? ''; + if (!isset($result[$side])) { + continue; + } + foreach (['hits', 'strength', 'absorbedDamage'] as $field) { + $result[$side][$field] = (int)($stat[$field] ?? 0); + } + } + return $result; + } + + private function insertRoundFleet(int $roundId, int $astroObjectId, array $fleet, array $combatants): void + { + $side = $fleet['side'] ?? ''; + if (!in_array($side, ['attacker', 'defender'], true) || !isset($fleet['player'])) { + return; + } + + $player = $fleet['player']; + $playerName = $this->db->sql_escape_string((string)($player['name'] ?? 'Unknown')); + $playerId = (int)($player['id'] ?? -1); + $research = $combatants[$side][(string)($player['name'] ?? '')] ?? ['armor' => 0, 'weapon' => 0, 'shield' => 0]; + $units = $side === 'attacker' + ? $this->database['fleet'] + : array_values(array_unique(array_merge($this->database['fleet'], ['SAT', 'FOR'], $this->database['defense']))); + $mapping = self::FLEET_TECHNOLOGIES + ($side === 'defender' ? self::DEFENSE_TECHNOLOGIES : []); + $unitCounts = array_fill_keys($units, 0); + + foreach ($fleet['technologies'] ?? [] as $technology) { + $technologyId = (int)($technology['technologyId'] ?? 0); + $unitCode = $mapping[$technologyId] ?? null; + if ($unitCode !== null && array_key_exists($unitCode, $unitCounts)) { + $unitCounts[$unitCode] = (int)($technology['remaining'] ?? 0); + } + } + + $unitValues = []; + foreach ($units as $unit) { + $unitValues[] = in_array($unit, ['PB', 'GB'], true) + ? (int)($unitCounts[$unit] > 0) + : $unitCounts[$unit]; + } + $table = $side === 'attacker' ? TABLE_ROUND_ATTACK : TABLE_ROUND_DEFENSE; + $columns = $side === 'attacker' + ? '`id_rcround`, `player`, `astro_object_id`, `Armes`, `Bouclier`, `Protection`' + : '`id_rcround`, `player_id`, `astro_object_id`, `Armes`, `Bouclier`, `Protection`'; + $playerValue = $side === 'attacker' ? "'{$playerName}'" : (string)$playerId; + $unitColumns = '`' . implode('`, `', $units) . '`'; + $this->db->sql_query("INSERT INTO {$table} ({$columns}, {$unitColumns}) VALUES ( + {$roundId}, {$playerValue}, {$astroObjectId}, {$research['weapon']}, {$research['shield']}, {$research['armor']}, " . implode(', ', $unitValues) . ')'); + } + + public function getType(): string + { + return 'rc'; + } + + public function getRequiredGrant(): string + { + return 'messages'; + } +} diff --git a/Handler/DefenseHandler.php b/Handler/DefenseHandler.php new file mode 100644 index 0000000..2d198e3 --- /dev/null +++ b/Handler/DefenseHandler.php @@ -0,0 +1,75 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $coordinates = filter_var($data['planet']['coords']); + $planetName = filter_var($data['planet']['name']); + $planetId = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); + $planetType = filter_var($data['planet']['type']); + $defense = $data['defense'] ?? []; + if (!isset($coordinates, $planetName, $planetType)) { + throw new UnexpectedValueException('Defense: Missing Planet Details'); + } + + $parsed = $this->parseCoordinates($coordinates); + $planetType = $this->resolvePlanetType($planetType); + $planetTypeString = $this->planetTypeToString($planetType); + $escapedName = $this->db->sql_escape_string($planetName); + $playerId = (int)($this->userData['player_id'] ?? -1); + + $this->db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " + (id, type, galaxy, system, row, name, player_id) + VALUES ({$planetId}, '{$planetTypeString}', {$parsed['galaxy']}, {$parsed['system']}, {$parsed['row']}, '{$escapedName}', {$playerId}) + ON DUPLICATE KEY UPDATE name = '{$escapedName}'"); + + $fields = []; + $values = []; + $updates = []; + $callbackDefense = []; + foreach ($this->database['defense'] as $code) { + if (isset($defense[$code])) { + $level = (int)$defense[$code]; + $fields[] = "`$code`"; + $values[] = $level; + $updates[] = "`$code` = {$level}"; + $callbackDefense[$code] = $level; + } + } + + if ($fields !== []) { + $this->db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER_DEFENSE . " + (astro_object_id, " . implode(', ', $fields) . ") + VALUES ({$planetId}, " . implode(', ', $values) . ") + ON DUPLICATE KEY UPDATE " . implode(', ', $updates)); + } + + $this->setPageUpdatedResponse('defense', $parsed['coords']); + $this->registerCallback('defense', [ + 'coords' => explode(':', $parsed['coords']), + 'planet_type' => $planetType, + 'planet_name' => $planetName, + 'defense' => $callbackDefense, + ]); + $this->logAction('defense', ['coords' => $parsed['coords'], 'planet_name' => $planetName]); + } + + public function getType(): string + { + return 'defense'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/FleetHandler.php b/Handler/FleetHandler.php new file mode 100644 index 0000000..e2d86db --- /dev/null +++ b/Handler/FleetHandler.php @@ -0,0 +1,79 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $coordinates = filter_var($data['planet']['coords']); + $planetName = filter_var($data['planet']['name']); + $planetType = filter_var($data['planet']['type']); + $planetId = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); + $fleet = $data['fleet'] ?? []; + if (!isset($coordinates, $planetName, $planetType)) { + throw new UnexpectedValueException('Fleet: Missing Planet Details'); + } + + $parsed = $this->parseCoordinates($coordinates); + $planetType = $this->resolvePlanetType($planetType); + $planetTypeString = $this->planetTypeToString($planetType); + $escapedName = $this->db->sql_escape_string($planetName); + $playerId = (int)($this->userData['player_id'] ?? -1); + + $this->db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " + (id, type, galaxy, system, row, name, player_id) + VALUES ({$planetId}, '{$planetTypeString}', {$parsed['galaxy']}, {$parsed['system']}, {$parsed['row']}, '{$escapedName}', {$playerId}) + ON DUPLICATE KEY UPDATE name = '{$escapedName}'"); + + $this->upsertValues(TABLE_GAME_PLAYER_FLEET, 'astro_object_id', $planetId, $this->database['fleet'], $fleet); + $this->upsertValues(TABLE_USER_BUILDING, 'id', $planetId, $this->database['fleet_production'], $fleet); + + $this->setPageUpdatedResponse('fleet', $parsed['coords']); + $this->registerCallback('fleet', [ + 'coords' => explode(':', $parsed['coords']), + 'planet_type' => $planetType, + 'planet_name' => $planetName, + 'fleet' => $fleet, + ]); + $this->logAction('fleet', ['coords' => $parsed['coords'], 'planet_name' => $planetName]); + } + + private function upsertValues(string $table, string $keyColumn, int|false $key, array $codes, array $data): void + { + $fields = []; + $values = []; + $updates = []; + foreach ($codes as $code) { + if (isset($data[$code])) { + $level = (int)$data[$code]; + $fields[] = "`$code`"; + $values[] = $level; + $updates[] = "`$code` = {$level}"; + } + } + if ($fields === []) { + return; + } + + $this->db->sql_query("INSERT INTO {$table} ({$keyColumn}, " . implode(', ', $fields) . ") + VALUES ({$key}, " . implode(', ', $values) . ") + ON DUPLICATE KEY UPDATE " . implode(', ', $updates)); + } + + public function getType(): string + { + return 'fleet'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/MessageHandler.php b/Handler/MessageHandler.php new file mode 100644 index 0000000..7674e83 --- /dev/null +++ b/Handler/MessageHandler.php @@ -0,0 +1,285 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $lineType = $data['type'] ?? ''; + $returnAsSpy = ($data['_xtense_return_as'] ?? null) === 'spy'; + unset($data['_xtense_return_as'], $data['_xtense_raw_payload']); + switch ($lineType) { + case 'msg': + $this->handlePersonalMessage($data); + break; + case 'ally_msg': + $this->handleAllyMessage($data); + break; + case 'spy': + case 'spy_shared': + $this->handleSpyReport($data); + break; + case 'ennemy_spy': + $this->handleEnemySpy($data); + break; + case 'rc_cdr': + $this->handleRecyclerReport($data); + break; + case 'expedition': + case 'expedition_shared': + $this->handleExpedition($data); + break; + default: + throw new UnexpectedValueException('Message category not found ' . $lineType); + } + + $this->io->set(['type' => ($returnAsSpy ? 'spy' : 'messages')]); + $this->logAction('messages'); + } + + private function handlePersonalMessage(array $line): void + { + if (!isset($line['coords'], $line['from'], $line['subject'], $line['message'])) { + throw new UnexpectedValueException('Personal Message: Incomplete Metadata '); + } + $coordinates = Check::coords($line['coords']); + $this->registerCallback('msg', [ + 'coords' => explode(':', $coordinates), + 'from' => filter_var($line['from']), + 'subject' => filter_var($line['subject']), + 'message' => filter_var($line['message']), + 'time' => $line['date'] ?? null, + ]); + } + + private function handleAllyMessage(array $line): void + { + if (!isset($line['from'], $line['tag'], $line['message'])) { + throw new UnexpectedValueException('Alliance Message: Incomplete Metadata '); + } + $this->registerCallback('ally_msg', [ + 'from' => filter_var($line['from']), + 'tag' => filter_var($line['tag']), + 'message' => filter_var($line['message']), + 'time' => $line['date'] ?? null, + ]); + } + + private function handleSpyReport(array $line): void + { + if (!isset( + $line['player']['name'], + $line['planet']['name'], + $line['planet']['coordinates'], + $line['planet']['id'], + $line['resources'], + $line['proba'], + $line['activity'], + $line['date'] + )) { + throw new UnexpectedValueException('Spy: Incomplete Metadata '); + } + + global $databaseSpyId; + $coordinates = Check::coords($line['planet']['coordinates']); + $content = []; + foreach (['resources', 'buildings', 'lfBuildings', 'research', 'lfResearch', 'fleet', 'defense'] as $section) { + if (!isset($line[$section]) || !is_array($line[$section])) { + $line[$section] = []; + } + if ($line[$section] !== []) { + $content += $line[$section]; + } + } + + $spy = [ + 'proba' => min(100, (int)filter_var($line['proba'], FILTER_SANITIZE_NUMBER_INT)), + 'activite' => min(59, (int)filter_var($line['activity'], FILTER_SANITIZE_NUMBER_INT)), + 'coords' => $coordinates, + 'content' => $content, + 'time' => (int)filter_var($line['date'], FILTER_SANITIZE_NUMBER_INT), + 'player_name' => filter_var($line['player']['name']), + 'planet_name' => filter_var($line['planet']['name']), + 'planet_id' => (int)$line['planet']['id'], + ]; + $this->registerCallback($line['type'], $spy); + + $databaseSpyId = is_array($databaseSpyId ?? null) ? $databaseSpyId : []; + $spyDatabase = []; + foreach ($databaseSpyId as $mapping) { + $spyDatabase += $mapping; + } + $fields = ['`astro_object_id`', '`planet_name`', '`metal`', '`crystal`', '`deuterium`', '`sender_id`', '`proba`', '`activite`', '`dateRE`']; + $values = [ + $spy['planet_id'], + "'" . $this->db->sql_escape_string($spy['planet_name']) . "'", + (int)($content['metal'] ?? 0), + (int)($content['crystal'] ?? 0), + (int)($content['deuterium'] ?? 0), + (int)$this->userData['id'], + $spy['proba'], + $spy['activite'], + $spy['time'], + ]; + foreach ($spyDatabase as $code => $column) { + if (in_array($column, ['metal', 'crystal', 'deuterium'], true) || !isset($content[$code])) { + continue; + } + $fields[] = '`' . $column . '`'; + $values[] = (int)$content[$code]; + } + + $exists = $this->db->sql_numrows($this->db->sql_query( + "SELECT `id` FROM " . TABLE_PARSEDSPY . " WHERE `astro_object_id` = '{$spy['planet_id']}' AND `dateRE` = '{$spy['time']}'" + )); + if ($exists) { + return; + } + + $this->db->sql_query('INSERT INTO ' . TABLE_PARSEDSPY . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $values) . ')'); + $spiedPlayerId = -1; + $playerResult = $this->db->sql_query("SELECT `id` FROM " . TABLE_GAME_PLAYER . " WHERE `name` = '" . $this->db->sql_escape_string($spy['player_name']) . "'"); + if ($this->db->sql_numrows($playerResult) > 0) { + $playerRow = $this->db->sql_fetch_row($playerResult); + $spiedPlayerId = (int)$playerRow[0]; + } + + $parsed = $this->parseCoordinates($coordinates); + $planetType = (($line['planet']['type'] ?? null) === '3') ? 'moon' : 'planet'; + $insertFields = ['id', 'galaxy', 'system', 'row', 'type', 'name', 'last_update', 'last_update_user_id']; + $insertValues = [ + $spy['planet_id'], $parsed['galaxy'], $parsed['system'], $parsed['row'], + "'{$planetType}'", "'" . $this->db->sql_escape_string($spy['planet_name']) . "'", + $spy['time'], (int)$this->userData['id'], + ]; + $updates = ['name = VALUES(name)', 'last_update = VALUES(last_update)', 'last_update_user_id = VALUES(last_update_user_id)', 'type = VALUES(type)', 'galaxy = VALUES(galaxy)', 'system = VALUES(system)', 'row = VALUES(row)']; + if ($spiedPlayerId !== -1) { + $insertFields[] = 'player_id'; + $insertValues[] = $spiedPlayerId; + $updates[] = 'player_id = VALUES(player_id)'; + } + $this->appendMappedUpsertFields($line['buildings'] ?? [], $databaseSpyId['buildings'] ?? [], $insertFields, $insertValues, $updates); + $this->db->sql_query('INSERT INTO ' . TABLE_USER_BUILDING . ' (`' . implode('`, `', $insertFields) . '`) VALUES (' . implode(', ', $insertValues) . ') ON DUPLICATE KEY UPDATE ' . implode(', ', $updates)); + + $this->appendCategoryUpsert($spy['planet_id'], $line['defense'] ?? [], $databaseSpyId['defense'] ?? [], TABLE_GAME_PLAYER_DEFENSE); + $this->appendCategoryUpsert($spy['planet_id'], $line['fleet'] ?? [], $databaseSpyId['fleet'] ?? [], TABLE_GAME_PLAYER_FLEET); + if ($spiedPlayerId !== -1) { + $this->appendCategoryUpsert($spiedPlayerId, $line['research'] ?? [], $databaseSpyId['labo'] ?? [], TABLE_USER_TECHNOLOGY, 'player_id'); + } + + $this->db->sql_query('UPDATE ' . TABLE_USER . ' SET `spy_imports` = spy_imports + 1 WHERE `id` = ' . (int)$this->userData['id']); + update_statistic('spyimports', '1'); + $this->logAction('messages', ['added_spy' => $spy['planet_name'], 'added_spy_coords' => $spy['coords']]); + } + + private function appendMappedUpsertFields(array $data, array $mapping, array &$fields, array &$values, array &$updates): void + { + foreach ($mapping as $code => $column) { + if (isset($data[$code])) { + $fields[] = $column; + $values[] = (int)$data[$code]; + $updates[] = "`{$column}` = VALUES(`{$column}`)"; + } + } + } + + private function appendCategoryUpsert(int $objectId, array $data, array $mapping, string $table, string $keyColumn = 'astro_object_id'): void + { + $fields = []; + $values = []; + $updates = []; + foreach ($mapping as $code => $column) { + if (isset($data[$code])) { + $level = (int)$data[$code]; + $fields[] = "`{$column}`"; + $values[] = $level; + $updates[] = "`{$column}` = {$level}"; + } + } + if ($fields === []) { + return; + } + $this->db->sql_query("INSERT INTO {$table} ({$keyColumn}, " . implode(', ', $fields) . ') VALUES (' . $objectId . ', ' . implode(', ', $values) . ') ON DUPLICATE KEY UPDATE ' . implode(', ', $updates)); + } + + private function handleEnemySpy(array $line): void + { + if (!isset($line['from'], $line['to'], $line['proba'], $line['date'])) { + throw new UnexpectedValueException('Ennemy Spy: Incomplete Metadata '); + } + $probability = filter_var($line['proba'], FILTER_SANITIZE_NUMBER_INT); + $from = Check::coords($line['from']); + $to = Check::coords($line['to']); + $userId = (int)($this->userData['user_id'] ?? $this->userData['id']); + $query = "SELECT spy_id FROM " . TABLE_PARSEDSPYEN . " WHERE sender_id = '{$userId}' AND dateSpy = '{$line['date']}'"; + if ($this->db->sql_numrows($this->db->sql_query($query)) === 0) { + $this->db->sql_query("INSERT INTO " . TABLE_PARSEDSPYEN . " (`dateSpy`, `from`, `to`, `proba`, `sender_id`) VALUES ('{$line['date']}', '{$from}', '{$to}', '{$probability}', '{$userId}')"); + } + $this->registerCallback('ennemy_spy', [ + 'from' => explode(':', $from), + 'to' => explode(':', $to), + 'proba' => (int)$probability, + 'time' => $line['date'], + ]); + add_log('info', ['toolbar' => $this->toolbarInfo, 'message' => 'a été espionné avec une probabilité de ' . $probability]); + } + + private function handleRecyclerReport(array $line): void + { + $required = ['nombre', 'coords', 'M_recovered', 'C_recovered', 'M_total', 'C_total', 'date']; + foreach ($required as $field) { + if (!isset($line[$field])) { + throw new UnexpectedValueException('Harvesting Report: Incomplete Metadata '); + } + } + $values = []; + foreach (['nombre', 'M_recovered', 'C_recovered', 'M_total', 'C_total'] as $field) { + $values[$field] = filter_var($line[$field], FILTER_SANITIZE_NUMBER_INT); + } + $coordinates = Check::coords($line['coords']); + $userId = (int)($this->userData['user_id'] ?? $this->userData['id']); + $query = "SELECT `id_rec` FROM " . TABLE_PARSEDREC . " WHERE `sender_id` = '{$userId}' AND `dateRec` = '{$line['date']}'"; + if ($this->db->sql_numrows($this->db->sql_query($query)) === 0) { + $this->db->sql_query("INSERT INTO " . TABLE_PARSEDREC . " (`dateRec`, `coordinates`, `nbRec`, `M_total`, `C_total`, `M_recovered`, `C_recovered`, `sender_id`) VALUES ('{$line['date']}', '{$coordinates}', '{$values['nombre']}', '{$values['M_total']}', '{$values['C_total']}', '{$values['M_recovered']}', '{$values['C_recovered']}', '{$userId}')"); + } + $this->registerCallback('rc_cdr', [ + 'nombre' => (int)$values['nombre'], + 'coords' => explode(':', $coordinates), + 'M_reco' => (int)$values['M_recovered'], + 'C_reco' => (int)$values['C_recovered'], + 'M_total' => (int)$values['M_total'], + 'C_total' => (int)$values['C_total'], + 'time' => $line['date'], + ]); + } + + private function handleExpedition(array $line): void + { + if (!isset($line['coords'], $line['content'])) { + throw new UnexpectedValueException('Expedition Message: Incomplete Metadata '); + } + $coordinates = Check::coords(filter_var($line['coords']), 1); + $this->registerCallback($line['type'], [ + 'time' => $line['date'] ?? null, + 'coords' => explode(':', $coordinates), + 'content' => filter_var($line['content']), + ]); + } + + public function getType(): string + { + return 'messages'; + } + + public function getRequiredGrant(): string + { + return 'messages'; + } +} diff --git a/Handler/OverviewHandler.php b/Handler/OverviewHandler.php new file mode 100644 index 0000000..ca8d2df --- /dev/null +++ b/Handler/OverviewHandler.php @@ -0,0 +1,144 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $playerDetails = filter_var_array($data['playerdetails'], [ + 'player_name' => FILTER_DEFAULT, + 'player_id' => FILTER_DEFAULT, + 'playerclass_explorer' => FILTER_DEFAULT, + 'playerclass_miner' => FILTER_DEFAULT, + 'playerclass_warrior' => FILTER_VALIDATE_INT, + 'player_officer_commander' => FILTER_VALIDATE_INT, + 'player_officer_amiral' => FILTER_VALIDATE_INT, + 'player_officer_engineer' => FILTER_VALIDATE_INT, + 'player_officer_geologist' => FILTER_VALIDATE_INT, + 'player_officer_technocrate' => FILTER_VALIDATE_INT, + ]); + + $universeDetails = filter_var_array($data['unidetails'], [ + 'uni_version' => FILTER_DEFAULT, + 'uni_url' => FILTER_DEFAULT, + 'uni_lang' => FILTER_DEFAULT, + 'uni_name' => FILTER_DEFAULT, + 'uni_time' => FILTER_VALIDATE_INT, + 'uni_speed' => FILTER_VALIDATE_INT, + 'uni_speed_fleet_peaceful' => FILTER_VALIDATE_INT, + 'uni_speed_fleet_war' => FILTER_VALIDATE_INT, + 'uni_speed_fleet_holding' => FILTER_VALIDATE_INT, + 'uni_donut_g' => FILTER_VALIDATE_INT, + 'uni_donut_s' => FILTER_VALIDATE_INT, + ]); + + $planetName = filter_var($data['planet']['name'], FILTER_DEFAULT); + $planetId = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); + $resources = filter_var_array($data['ressources'], FILTER_VALIDATE_INT); + $temperatureMin = filter_var($data['temperature_min'], FILTER_VALIDATE_INT); + $temperatureMax = filter_var($data['temperature_max'], FILTER_VALIDATE_INT); + $fields = filter_var($data['fields'], FILTER_VALIDATE_INT); + $coordinates = $this->parseCoordinates($data['planet']['coords'])['coords']; + $planetType = $this->resolvePlanetType($data['planet']['type']); + $ogameTimestamp = $universeDetails['uni_time']; + + $playerClass = 'none'; + if ($playerDetails['playerclass_miner'] == 1) { + $playerClass = 'COL'; + } elseif ($playerDetails['playerclass_warrior'] == 1) { + $playerClass = 'GEN'; + } elseif ($playerDetails['playerclass_explorer'] == 1) { + $playerClass = 'EXP'; + } + + $gamePlayerId = (int)$playerDetails['player_id']; + $currentOgspyUserId = (int)$this->userData['id']; + if ($gamePlayerId > 0) { + $gamePlayerName = $this->db->sql_escape_string($playerDetails['player_name']); + $officerCommander = (int)$playerDetails['player_officer_commander']; + $officerAmiral = (int)$playerDetails['player_officer_amiral']; + $officerEngineer = (int)$playerDetails['player_officer_engineer']; + $officerGeologist = (int)$playerDetails['player_officer_geologist']; + $officerTechnocrate = (int)$playerDetails['player_officer_technocrate']; + + $query = " + INSERT INTO " . TABLE_GAME_PLAYER . " ( + `id`, `name`, `class`, + `off_commandant`, `off_amiral`, `off_ingenieur`, `off_geologue`, `off_technocrate`, + `datadate`, `status`, `ally_id` + ) VALUES ( + {$gamePlayerId}, '{$gamePlayerName}', '{$playerClass}', + {$officerCommander}, {$officerAmiral}, {$officerEngineer}, {$officerGeologist}, {$officerTechnocrate}, + {$ogameTimestamp}, '', -1 + ) + ON DUPLICATE KEY UPDATE + `name` = VALUES(`name`), + `class` = VALUES(`class`), + `off_commandant` = VALUES(`off_commandant`), + `off_amiral` = VALUES(`off_amiral`), + `off_ingenieur` = VALUES(`off_ingenieur`), + `off_geologue` = VALUES(`off_geologue`), + `off_technocrate` = VALUES(`off_technocrate`), + `datadate` = VALUES(`datadate`)"; + $this->db->sql_query($query); + } + + $this->db->sql_query("UPDATE " . TABLE_USER . " SET `player_id` = {$gamePlayerId} WHERE `id` = {$currentOgspyUserId}"); + $this->db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_uni', '{$universeDetails['uni_speed']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); + $this->db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_peaceful', '{$universeDetails['uni_speed_fleet_peaceful']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); + $this->db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_war', '{$universeDetails['uni_speed_fleet_war']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); + $this->db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_holding', '{$universeDetails['uni_speed_fleet_holding']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); + generate_config_cache(); + + if (isset($data['boosters'])) { + $boosters = booster_encode(update_boosters($data['boosters'], $ogameTimestamp)); + } else { + $boosters = booster_encodev(0, 0, 0, 0, 0, 0, 0, 0); + } + + [$galaxy, $system, $position] = explode(':', $coordinates); + $this->db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " + (`player_id`, `id`, `type`, `galaxy`, `system`, `row`, `name`, `fields`, `boosters`, `temperature_min`, `temperature_max`) + VALUES ({$gamePlayerId}, {$planetId}, '{$planetType}', {$galaxy}, {$system}, {$position}, '{$planetName}', {$fields}, '{$boosters}', {$temperatureMin}, {$temperatureMax}) + ON DUPLICATE KEY UPDATE + type = VALUES(type), + name = VALUES(name), + player_id = VALUES(player_id), + fields = VALUES(fields), + boosters = VALUES(boosters), + temperature_min = VALUES(temperature_min), + temperature_max = VALUES(temperature_max), + galaxy = VALUES(galaxy), + system = VALUES(system), + row = VALUES(row)"); + + $this->setPageUpdatedResponse('overview', $coordinates); + $this->registerCallback('overview', [ + 'coords' => explode(':', $coordinates), + 'planet_type' => $planetType, + 'planet_name' => $planetName, + 'fields' => $fields, + 'temperature_min' => $temperatureMin, + 'temperature_max' => $temperatureMax, + 'ressources' => $resources, + ]); + $this->logAction('overview', ['coords' => $coordinates, 'planet_name' => $planetName]); + } + + public function getType(): string + { + return 'overview'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/RankingHandler.php b/Handler/RankingHandler.php new file mode 100644 index 0000000..e243e3a --- /dev/null +++ b/Handler/RankingHandler.php @@ -0,0 +1,168 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + if (((int)$offset - 1) % 100 !== 0) { + throw new UnexpectedValueException('Ranking: Offset not found'); + } + if (!is_array($entries)) { + throw new UnexpectedValueException('Rankings: Incomplete Ranking'); + } + + $table = $this->getTargetTable($type1, $type2, $type3); + $timestamp = (int)($GLOBALS['timestamp'] ?? time()); + $senderId = (int)$this->userData['id']; + $processed = []; + $values = []; + $isPlayerMilitary = $type1 === 'player' && $table === TABLE_RANK_PLAYER_MILITARY; + + foreach ($entries as $entry) { + if (!is_array($entry)) { + continue; + } + if ($type1 === 'ally' && !isset($entry['ally_id'], $entry['points'], $entry['mean'], $entry['members'])) { + throw new UnexpectedValueException('Ranking Ally: Missing alliance data'); + } + $entry['rank'] = (int)($entry['rank'] ?? 0); + $entry['points'] = (int)($entry['points'] ?? 0); + + if ($type1 === 'player') { + $entry['player_name'] = filter_var($entry['player_name'] ?? '', FILTER_DEFAULT); + $entry['ally_tag'] = filter_var($entry['ally_tag'] ?? '', FILTER_DEFAULT); + $entry['ally_id'] = !empty($entry['ally_id']) ? (int)$entry['ally_id'] : -1; + $entry['player_id'] = !empty($entry['player_id']) ? (int)$entry['player_id'] : -1; + + if ($entry['player_id'] > 0 && $entry['player_name'] !== '') { + $playerName = $this->db->sql_escape_string($entry['player_name']); + $this->db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER . " (id, name, ally_id, datadate) + VALUES ({$entry['player_id']}, '{$playerName}', {$entry['ally_id']}, " . time() . ") + ON DUPLICATE KEY UPDATE name = VALUES(name), ally_id = VALUES(ally_id), datadate = VALUES(datadate)"); + } + if ($entry['ally_id'] > 0 && $entry['ally_tag'] !== '') { + $allyTag = $this->db->sql_escape_string($entry['ally_tag']); + $this->db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " (id, tag, datadate) + VALUES ({$entry['ally_id']}, '{$allyTag}', " . time() . ") + ON DUPLICATE KEY UPDATE tag = VALUES(tag), datadate = VALUES(datadate)"); + } + + $playerName = $this->db->sql_escape_string($entry['player_name']); + $allyTag = $this->db->sql_escape_string($entry['ally_tag']); + $rowValues = "({$timestamp}, {$entry['rank']}, '{$playerName}', {$entry['player_id']}, '{$allyTag}', {$entry['ally_id']}, {$entry['points']}, {$senderId}"; + if ($isPlayerMilitary) { + $rowValues .= ', ' . (int)($entry['nb_spacecraft'] ?? 0); + } + $values[] = $rowValues . ')'; + } else { + $entry['ally_tag'] = filter_var($entry['ally_tag'] ?? '', FILTER_DEFAULT); + $entry['ally_name'] = filter_var($entry['ally'] ?? '', FILTER_DEFAULT); + $allyTag = $this->db->sql_escape_string($entry['ally_tag']); + $allyName = $this->db->sql_escape_string($entry['ally_name']); + $allyId = (int)$entry['ally_id']; + $points = (int)$entry['points']; + $mean = (int)$entry['mean']; + $members = (int)$entry['members']; + + if ($allyId > 0 && $allyTag !== '' && $allyName !== '') { + $this->db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " (id, name, tag, datadate) + VALUES ({$allyId}, '{$allyName}', '{$allyTag}', " . time() . ") + ON DUPLICATE KEY UPDATE name = VALUES(name), tag = VALUES(tag), datadate = VALUES(datadate)"); + } + $values[] = "({$timestamp}, {$entry['rank']}, '{$allyTag}', {$allyId}, {$points}, {$senderId}, {$members}, {$mean})"; + } + + $processed[] = $entry; + } + + if ($values !== []) { + if ($type1 === 'player') { + $columns = '`datadate`, `rank`, `player`, `player_id`, `ally`, `ally_id`, `points`, `sender_id`'; + if ($isPlayerMilitary) { + $columns .= ', `nb_spacecraft`'; + } + $this->db->sql_query("REPLACE INTO {$table} ({$columns}) VALUES " . implode(',', $values)); + } else { + $this->db->sql_query("REPLACE INTO {$table} (datadate, rank, ally, ally_id, points, sender_id, number_member, points_per_member) VALUES " . implode(',', $values)); + $this->db->sql_query("UPDATE " . TABLE_USER . " SET rank_imports = rank_imports + " . count($values) . " WHERE id = {$senderId}"); + } + } + + $callbackType2 = $type2 === 'fleet' ? $type2 . $type3 : $type2; + $this->registerCallback('ranking_' . $type1 . '_' . $callbackType2, [ + 'data' => $processed, + 'offset' => (int)$offset, + 'time' => $timestamp, + ]); + $this->io->set(['type' => 'ranking', 'type1' => $type1, 'type2' => $callbackType2, 'offset' => (int)$offset]); + update_statistic('rankimports', 100); + $this->logAction('ranking', [ + 'type1' => $type1, + 'type2' => $callbackType2, + 'offset' => (int)$offset, + 'time' => $timestamp, + ]); + } + + private function getTargetTable(string $type1, string $type2, string $type3): string + { + if ($type1 === 'player') { + return match ($type2) { + 'points' => TABLE_RANK_PLAYER_POINTS, + 'economy' => TABLE_RANK_PLAYER_ECO, + 'research' => TABLE_RANK_PLAYER_TECHNOLOGY, + 'fleet' => match ($type3) { + '' => TABLE_RANK_PLAYER_MILITARY, + '5' => TABLE_RANK_PLAYER_MILITARY_BUILT, + '6' => TABLE_RANK_PLAYER_MILITARY_DESTRUCT, + '4' => TABLE_RANK_PLAYER_MILITARY_LOOSE, + '7' => TABLE_RANK_PLAYER_HONOR, + default => throw new OutOfRangeException('Ranking Player: Unexpected Ranking type for type3: ' . $type3), + }, + default => throw new UnexpectedValueException('Ranking Player: Unexpected Ranking type for type2: ' . $type2), + }; + } + + return match ($type2) { + 'points' => TABLE_RANK_ALLY_POINTS, + 'economy' => TABLE_RANK_ALLY_ECO, + 'research' => TABLE_RANK_ALLY_TECHNOLOGY, + 'fleet' => match ($type3) { + '' => TABLE_RANK_ALLY_MILITARY, + '5' => TABLE_RANK_ALLY_MILITARY_BUILT, + '6' => TABLE_RANK_ALLY_MILITARY_DESTRUCT, + '4' => TABLE_RANK_ALLY_MILITARY_LOOSE, + '7' => TABLE_RANK_ALLY_HONOR, + default => throw new OutOfRangeException('Ranking Ally: Unexpected Ranking type for type3: ' . $type3), + }, + default => throw new UnexpectedValueException('Ranking Ally: Unexpected Ranking type for type2: ' . $type2), + }; + } + + public function getType(): string + { + return 'ranking'; + } + + public function getRequiredGrant(): string + { + return 'ranking'; + } +} diff --git a/Handler/ResearchsHandler.php b/Handler/ResearchsHandler.php new file mode 100644 index 0000000..2843615 --- /dev/null +++ b/Handler/ResearchsHandler.php @@ -0,0 +1,62 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $coordinates = filter_var($data['planet']['coords']); + $planetName = filter_var($data['planet']['name']); + $planetType = filter_var($data['planet']['type']); + $researches = $data['researchs']; + if (!isset($coordinates, $planetName, $planetType)) { + throw new UnexpectedValueException('Researchs: Missing Planet Details'); + } + + $coordinates = Check::coords($coordinates); + $planetType = ((int)$planetType === TYPE_PLANET) ? TYPE_PLANET : TYPE_MOON; + if (!isset($this->userData['player_id']) || $this->userData['player_id'] <= 0) { + throw new UnexpectedValueException('Researchs: Player ID not available'); + } + + $playerId = (int)$this->userData['player_id']; + $fields = []; + $values = []; + $updates = []; + foreach ($this->database['labo'] as $code) { + if (isset($researches[$code])) { + $fields[] = "`$code`"; + $values[] = (int)$researches[$code]; + $updates[] = "`$code` = " . (int)$researches[$code]; + } + } + + if ($fields !== []) { + $this->db->sql_query("INSERT INTO " . TABLE_USER_TECHNOLOGY . " + (`player_id`, " . implode(', ', $fields) . ") + VALUES ({$playerId}, " . implode(', ', $values) . ") + ON DUPLICATE KEY UPDATE " . implode(', ', $updates)); + } + + $this->setPageUpdatedResponse('labo', $coordinates); + $this->registerCallback('research', ['research' => $researches]); + $this->logAction('research'); + } + + public function getType(): string + { + return 'researchs'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/ResourceSettingsHandler.php b/Handler/ResourceSettingsHandler.php new file mode 100644 index 0000000..4707ee9 --- /dev/null +++ b/Handler/ResourceSettingsHandler.php @@ -0,0 +1,95 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $coordinates = filter_var($data['planet']['coords']); + $planetName = filter_var($data['planet']['name']); + $planetType = filter_var($data['planet']['type'], FILTER_VALIDATE_INT); + $planetId = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); + $resourceSettings = isset($data['resourceSettings']) && is_array($data['resourceSettings']) + ? $data['resourceSettings'] + : null; + + if (!isset($coordinates, $planetName, $planetType) + || $planetId === false + || $planetType === false + || $resourceSettings === null + ) { + throw new UnexpectedValueException('ResourceSettings: Missing or invalid planet details or resourceSettings data'); + } + + $parsed = $this->parseCoordinates($coordinates); + $coordinates = $parsed['coords']; + $planetTypeConstant = $this->resolvePlanetType($planetType); + $planetTypeString = $this->planetTypeToString($planetTypeConstant); + + $settingsMap = [ + 'M_percentage' => 'M_percentage', + 'C_Percentage' => 'C_Percentage', + 'D_percentage' => 'D_percentage', + 'CES_percentage' => 'CES_percentage', + 'CEF_percentage' => 'CEF_percentage', + 'SAT_percentage' => 'Sat_percentage', + 'FOR_percentage' => 'FOR_percentage', + ]; + + $columns = ['id', 'galaxy', 'system', 'row', 'name', 'type']; + $values = [ + $planetId, + $parsed['galaxy'], + $parsed['system'], + $parsed['row'], + $this->db->sql_escape_string($planetName), + $this->db->sql_escape_string($planetTypeString), + ]; + foreach ($settingsMap as $jsonKey => $databaseColumn) { + $columns[] = $databaseColumn; + $values[] = isset($resourceSettings[$jsonKey]) ? (int)$resourceSettings[$jsonKey] : 100; + } + + $updatePairs = ['name', 'galaxy', 'system', 'row', 'type']; + $updatePairs = array_map(static function ($column) { + return "$column = VALUES($column)"; + }, $updatePairs); + foreach ($settingsMap as $databaseColumn) { + $updatePairs[] = "`$databaseColumn` = VALUES(`$databaseColumn`)"; + } + + $query = "INSERT INTO " . TABLE_USER_BUILDING . " (`" . implode('`, `', $columns) . "`) + VALUES (" . implode(', ', array_map(static function ($value) { + return is_numeric($value) ? $value : "'" . $value . "'"; + }, $values)) . ") + ON DUPLICATE KEY UPDATE " . implode(', ', $updatePairs); + $this->db->sql_query($query); + + // The existing Xtense protocol reports resource settings as a buildings page update. + $this->setPageUpdatedResponse('buildings', $coordinates); + $this->registerCallback('resourceSettings', [ + 'coords' => explode(':', $coordinates), + 'planet_type' => $planetTypeConstant, + 'planet_name' => $planetName, + 'resourceSettings' => $resourceSettings, + ]); + $this->logAction('resourceSettings', ['coords' => $coordinates, 'planet_name' => $planetName]); + } + + public function getType(): string + { + return 'resourceSettings'; + } + + public function getRequiredGrant(): string + { + return 'empire'; + } +} diff --git a/Handler/SystemHandler.php b/Handler/SystemHandler.php new file mode 100644 index 0000000..0fbd2fd --- /dev/null +++ b/Handler/SystemHandler.php @@ -0,0 +1,134 @@ +requireGrant($this->getRequiredGrant())) { + return; + } + + $galaxy = filter_var($data['galaxy'], FILTER_SANITIZE_NUMBER_INT); + $system = filter_var($data['system'], FILTER_SANITIZE_NUMBER_INT); + if (!isset($galaxy, $system)) { + throw new UnexpectedValueException('Galaxy: Missing Planet position'); + } + + $galaxy = (int)$galaxy; + $system = (int)$system; + if ($galaxy > $this->server_config['num_of_galaxies'] || $system > $this->server_config['num_of_systems']) { + $this->io->set(['type' => 'plugin univers', 'access' => 'system']); + $this->io->status(0); + return; + } + + $rows = $data['rows']; + $systemData = []; + for ($position = 1; $position < 16; $position++) { + if (isset($rows[$position])) { + $line = $rows[$position]; + $line['player_name'] = filter_var($line['player_name']); + $line['planet_name'] = filter_var($line['planet_name']); + $line['planet_id'] = filter_var($line['planet_id'], FILTER_VALIDATE_INT); + $line['ally_tag'] = filter_var($line['ally_tag']); + if (isset($line['debris'])) { + $line['debris'] = filter_var_array($line['debris'], [ + 'metal' => FILTER_SANITIZE_NUMBER_INT, + 'crystal' => FILTER_SANITIZE_NUMBER_INT, + 'deuterium' => FILTER_SANITIZE_NUMBER_INT, + ]); + } + if (isset($line['status'])) { + $line['status'] = filter_var($line['status']); + } + $systemData[$position] = $line; + continue; + } + + $systemData[$position] = [ + 'planet_id' => '', + 'planet_name' => '', + 'player_name' => '', + 'status' => '', + 'ally_tag' => '', + 'debris' => ['metal' => 0, 'cristal' => 0, 'deuterium' => 0], + 'moon' => 0, + 'activity' => '', + ]; + } + + foreach ($systemData as $position => $line) { + $status = Check::player_status_forbidden($line['status']) ? '' : $line['status']; + $playerId = isset($line['player_id']) ? (int)$line['player_id'] : -1; + $planetId = isset($line['planet_id']) ? (int)$line['planet_id'] : -1; + $moon = isset($line['moon']) ? (int)$line['moon'] : -1; + $moonId = isset($line['moon_id']) ? (int)$line['moon_id'] : -1; + $allyId = isset($line['ally_id']) ? (int)$line['ally_id'] : -1; + $allyTag = $line['ally_tag'] ?? ''; + $currentTime = time(); + + $this->db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " + (`id`, `galaxy`, `system`, `row`, `name`, `player_id`, `last_update`, `last_update_user_id`) + VALUES ({$planetId}, {$galaxy}, {$system}, {$position}, '{$line['planet_name']}', {$playerId}, {$currentTime}, " . (int)$this->userData['id'] . ") + ON DUPLICATE KEY UPDATE + `name` = '{$line['planet_name']}', + `player_id` = {$playerId}, + `last_update` = {$currentTime}, + `last_update_user_id` = " . (int)$this->userData['id']); + + if ($moonId !== -1 && $moon === 1) { + $this->db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " + (`id`, `type`, `galaxy`, `system`, `row`, `name`, `player_id`, `last_update_moon`, `last_update_user_id`) + VALUES ({$moonId}, 'moon', {$galaxy}, {$system}, {$position}, '{$line['planet_name']} - Moon', {$playerId}, {$currentTime}, " . (int)$this->userData['id'] . ") + ON DUPLICATE KEY UPDATE + `name` = '{$line['planet_name']} - Moon', + `player_id` = {$playerId}, + `last_update_moon` = {$currentTime}, + `last_update_user_id` = " . (int)$this->userData['id']); + } + + if ($playerId !== -1) { + $playerName = $this->db->sql_escape_string($line['player_name']); + $escapedStatus = $this->db->sql_escape_string($status); + $this->db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER . " + (`id`, `name`, `status`, `ally_id`, `datadate`) + VALUES ({$playerId}, '{$playerName}', '{$escapedStatus}', {$allyId}, {$currentTime}) + ON DUPLICATE KEY UPDATE + `name` = '{$playerName}', + `status` = '{$escapedStatus}', + `ally_id` = {$allyId}, + `datadate` = {$currentTime}"); + } + + if ($allyId > 0) { + $this->db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " (`id`, `tag`, `datadate`) + VALUES ({$allyId}, '{$allyTag}', {$currentTime}) + ON DUPLICATE KEY UPDATE `tag` = '{$allyTag}', `datadate` = {$currentTime}"); + } + } + + $this->db->sql_query("UPDATE " . TABLE_USER . " SET `planet_imports` = `planet_imports` + 15 WHERE `id` = " . (int)$this->userData['id']); + $this->registerCallback('system', [ + 'data' => $rows, + 'galaxy' => $galaxy, + 'system' => $system, + ]); + $this->io->set(['type' => 'system', 'galaxy' => $galaxy, 'system' => $system]); + update_statistic('planetimports', 15); + $this->logAction('system', ['coords' => $galaxy . ':' . $system]); + } + + public function getType(): string + { + return 'system'; + } + + public function getRequiredGrant(): string + { + return 'system'; + } +} diff --git a/phpunit.xml b/phpunit.xml index 3ce1727..3fd596e 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -10,4 +10,11 @@ ./tests/unit + + + ./Handler + ./includes + ./xtense.php + + diff --git a/sonar-project.properties b/sonar-project.properties index 91bad32..2287431 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,5 +1,6 @@ sonar.projectKey=OGSteam_mod-xtense sonar.organization=ogsteam +sonar.php.coverage.reportPaths=coverage.xml # This is the name and version displayed in the SonarCloud UI. #sonar.projectName=ogspy diff --git a/tests/bootstrap.php b/tests/bootstrap.php index f3366c7..3bf8433 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -56,6 +56,7 @@ 'TABLE_USER' => $p . 'user', 'TABLE_MOD' => $p . 'mod', 'TABLE_STATISTIC' => $p . 'statistics', + 'TABLE_PARSEDSPY' => $p . 'game_spy', 'TABLE_USER_BUILDING' => $p . 'game_astro_object', 'TABLE_GAME_PLAYER' => $p . 'game_player', 'TABLE_GAME_ALLY' => $p . 'game_ally', @@ -78,6 +79,10 @@ 'TABLE_RANK_ALLY_MILITARY_LOOSE' => $p . 'game_rank_ally_military_loose', 'TABLE_RANK_ALLY_MILITARY_DESTRUCT' => $p . 'game_rank_ally_military_destruct', 'TABLE_RANK_ALLY_HONOR' => $p . 'game_rank_ally_honor', + 'TABLE_PARSEDRC' => $p . 'game_rc', + 'TABLE_PARSEDRCROUND' => $p . 'game_rc_round', + 'TABLE_ROUND_ATTACK' => $p . 'game_rc_round_attack', + 'TABLE_ROUND_DEFENSE' => $p . 'game_rc_round_defense', ] as $constName => $constValue) { if (!defined($constName)) define($constName, $constValue); } @@ -92,6 +97,9 @@ function generate_config_cache(): void {} if (!function_exists('booster_encode')) { function booster_encode(array $boosters): string { return ''; } } +if (!function_exists('booster_decode')) { + function booster_decode(): array { return []; } +} if (!function_exists('booster_encodev')) { function booster_encodev(int ...$args): string { return ''; } } diff --git a/tests/unit/CombatReportHandlerTest.php b/tests/unit/CombatReportHandlerTest.php index 4c58462..7025fa7 100644 --- a/tests/unit/CombatReportHandlerTest.php +++ b/tests/unit/CombatReportHandlerTest.php @@ -121,6 +121,17 @@ public function testComplexFixtureDefenderHasDefenseAndFleetTechnologies(): void // Handler — main RC record (TABLE_PARSEDRC) // ------------------------------------------------------------------------- + private function getMainReportInsert(): string + { + foreach ($this->db->getQueriesContaining('game_rc') as $query) { + if (stripos($query, 'INSERT INTO ogspy_game_rc (') !== false) { + return $query; + } + } + + self::fail('Expected main combat-report INSERT'); + } + public function testHandleInsertsMainRcRecord(): void { $data = $this->getDecodedData('rc_complex'); @@ -141,8 +152,7 @@ public function testHandleRecordsWinnerAttacker(): void $handler = $this->createHandler('CombatReportHandler'); $handler->handle($data); - $inserts = $this->db->getQueriesContaining('game_rc'); - $sql = $inserts[0]; + $sql = $this->getMainReportInsert(); $this->assertStringContainsString("'A'", $sql, "Winner must be encoded as 'A'"); } @@ -152,7 +162,7 @@ public function testHandleRecordsLootValues(): void $handler = $this->createHandler('CombatReportHandler'); $handler->handle($data); - $sql = $this->db->getQueriesContaining('game_rc')[0]; + $sql = $this->getMainReportInsert(); $this->assertStringContainsString('200000', $sql, 'Loot metal missing'); $this->assertStringContainsString('150000', $sql, 'Loot crystal missing'); $this->assertStringContainsString('50000', $sql, 'Loot deuterium missing'); @@ -164,7 +174,7 @@ public function testHandleRecordsDebrisValues(): void $handler = $this->createHandler('CombatReportHandler'); $handler->handle($data); - $sql = $this->db->getQueriesContaining('game_rc')[0]; + $sql = $this->getMainReportInsert(); $this->assertStringContainsString('250000', $sql, 'Debris metal missing'); $this->assertStringContainsString('120000', $sql, 'Debris crystal missing'); } @@ -175,7 +185,7 @@ public function testHandleRecordsMoonCreationChance(): void $handler = $this->createHandler('CombatReportHandler'); $handler->handle($data); - $sql = $this->db->getQueriesContaining('game_rc')[0]; + $sql = $this->getMainReportInsert(); $this->assertStringContainsString('12', $sql, 'Moon chance (12) missing from RC insert'); } @@ -185,7 +195,7 @@ public function testHandleRecordsUnitLosses(): void $handler = $this->createHandler('CombatReportHandler'); $handler->handle($data); - $sql = $this->db->getQueriesContaining('game_rc')[0]; + $sql = $this->getMainReportInsert(); $this->assertStringContainsString('2500000', $sql, 'Attacker losses missing'); $this->assertStringContainsString('5000000', $sql, 'Defender losses missing'); } diff --git a/tests/unit/MessageHandlerTest.php b/tests/unit/MessageHandlerTest.php new file mode 100644 index 0000000..2d7c2ba --- /dev/null +++ b/tests/unit/MessageHandlerTest.php @@ -0,0 +1,45 @@ +createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'msg', + 'coords' => '4:246:12', + 'from' => 'Marshal Galileo', + 'subject' => 'Fleet movement', + 'message' => 'Fleet arrives soon', + 'date' => 1776500000, + ]); + + $this->assertTrue($this->callbackHandler->hasCallForType('msg')); + $params = $this->callbackHandler->getCallsForType('msg')[0]['params']; + $this->assertSame(['4', '246', '12'], $params['coords']); + $this->assertSame('Fleet arrives soon', $params['message']); + $this->assertSame('messages', $this->getIoResponse()['type']); + } + + public function testReturnAsSpyChangesResponseType(): void + { + $handler = $this->createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'msg', + 'coords' => '4:246:12', + 'from' => 'Marshal Galileo', + 'subject' => 'Fleet movement', + 'message' => 'Fleet arrives soon', + '_xtense_return_as' => 'spy', + ]); + + $this->assertSame('spy', $this->getIoResponse()['type']); + } + + public function testUnknownMessageTypeThrows(): void + { + $handler = $this->createHandler('MessageHandler'); + $this->expectException(UnexpectedValueException::class); + $handler->handle(['type' => 'unknown']); + } +} diff --git a/tests/unit/MessageSubtypeHandlerTest.php b/tests/unit/MessageSubtypeHandlerTest.php new file mode 100644 index 0000000..65beef1 --- /dev/null +++ b/tests/unit/MessageSubtypeHandlerTest.php @@ -0,0 +1,87 @@ +createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'ally_msg', + 'from' => 'Marshal Galileo', + 'tag' => 'SLD', + 'message' => 'Alliance message', + 'date' => 1776500000, + ]); + + $this->assertTrue($this->callbackHandler->hasCallForType('ally_msg')); + $this->assertSame('SLD', $this->callbackHandler->getCallsForType('ally_msg')[0]['params']['tag']); + } + + public function testSpyReportPersistsAndRegistersCallback(): void + { + $data = $this->getDecodedData('messages_spy'); + $data['buildings'] = false; + $data['lfBuildings'] = false; + $data['research'] = false; + $data['lfResearch'] = false; + $data['fleet'] = false; + $data['defense'] = false; + $handler = $this->createHandler('MessageHandler'); + $handler->handle($data); + + $this->assertTrue($this->callbackHandler->hasCallForType('spy')); + $this->assertNotEmpty($this->db->getQueriesContaining('INSERT INTO ogspy_game_spy')); + $this->assertNotEmpty($this->db->getQueriesContaining('INSERT INTO ogspy_game_astro_object')); + $this->assertSame('messages', $this->getIoResponse()['type']); + } + + public function testEnemySpyRegistersCallbackAndPersistsReport(): void + { + $handler = $this->createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'ennemy_spy', + 'from' => '4:246:12', + 'to' => '4:246:7', + 'proba' => '65', + 'date' => 1776500000, + ]); + + $this->assertTrue($this->callbackHandler->hasCallForType('ennemy_spy')); + $this->assertNotEmpty($this->db->getQueriesContaining('ogspy_parsedSpyEn')); + } + + public function testRecyclerReportRegistersNormalizedCallback(): void + { + $handler = $this->createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'rc_cdr', + 'nombre' => '5', + 'coords' => '4:246:12', + 'M_recovered' => '1200', + 'C_recovered' => '800', + 'M_total' => '2500', + 'C_total' => '1700', + 'date' => 1776500000, + ]); + + $this->assertTrue($this->callbackHandler->hasCallForType('rc_cdr')); + $params = $this->callbackHandler->getCallsForType('rc_cdr')[0]['params']; + $this->assertSame(1200, $params['M_reco']); + $this->assertNotEmpty($this->db->getQueriesContaining('ogspy_parsedRec')); + } + + public function testExpeditionRegistersExpeditionCallback(): void + { + $handler = $this->createHandler('MessageHandler'); + $handler->handle([ + 'type' => 'expedition_shared', + 'coords' => '4:246:16', + 'content' => 'Resources found', + 'date' => 1776500000, + ]); + + $this->assertTrue($this->callbackHandler->hasCallForType('expedition_shared')); + $params = $this->callbackHandler->getCallsForType('expedition_shared')[0]['params']; + $this->assertSame(['4', '246', '16'], $params['coords']); + } +} diff --git a/tests/unit/RankingHandlerTest.php b/tests/unit/RankingHandlerTest.php index 0e1fc6a..bebeb1b 100644 --- a/tests/unit/RankingHandlerTest.php +++ b/tests/unit/RankingHandlerTest.php @@ -122,6 +122,60 @@ public function testFleetMilitaryTableQueryIncludesNbSpacecraft(): void // Validation // ------------------------------------------------------------------------- + public function testAllianceRankingRejectsMissingPointsBeforeWrites(): void + { + $data = [ + 'type1' => 'ally', + 'type2' => 'points', + 'type3' => '', + 'offset' => '1', + 'time' => '1776500000', + 'n' => [[ + 'ally_id' => 500003, + 'rank' => 1, + 'ally' => 'Suivre Les Directives', + 'ally_tag' => 'SLD', + 'mean' => 100, + 'members' => 5, + ]], + ]; + $handler = $this->createHandler('RankingHandler'); + + try { + $handler->handle($data); + self::fail('Expected missing alliance points to be rejected'); + } catch (UnexpectedValueException $exception) { + $this->assertSame('Ranking Ally: Missing alliance data', $exception->getMessage()); + } + + $this->assertSame([], $this->db->getQueries()); + } + + public function testAllianceRankingCallbackPreservesAllyName(): void + { + $data = [ + 'type1' => 'ally', + 'type2' => 'points', + 'type3' => '', + 'offset' => '1', + 'time' => '1776500000', + 'n' => [[ + 'ally_id' => 500003, + 'rank' => 1, + 'ally' => 'Suivre Les Directives', + 'ally_tag' => 'SLD', + 'points' => 12345, + 'mean' => 2469, + 'members' => 5, + ]], + ]; + $handler = $this->createHandler('RankingHandler'); + $handler->handle($data); + + $calls = $this->callbackHandler->getCallsForType('ranking_ally_points'); + $this->assertSame('Suivre Les Directives', $calls[0]['params']['data'][0]['ally_name']); + } + public function testRankingThrowsOnInvalidOffset(): void { $data = $this->getDecodedData('ranking_player_points'); diff --git a/tests/unit/SimplePayloadHandlersTest.php b/tests/unit/SimplePayloadHandlersTest.php new file mode 100644 index 0000000..91af180 --- /dev/null +++ b/tests/unit/SimplePayloadHandlersTest.php @@ -0,0 +1,55 @@ +createHandler('DefenseHandler'); + $handler->handle([ + 'planet' => ['coords' => '4:246:12', 'name' => 'Home', 'id' => 33717002, 'type' => 0], + 'defense' => ['LM' => 15, 'PB' => 1], + ]); + + $queries = $this->db->getQueriesContaining('game_player_defense'); + $this->assertCount(1, $queries); + $this->assertStringContainsString('`LM`', $queries[0]); + $this->assertSame('defense', $this->getIoResponse()['page']); + $this->assertTrue($this->callbackHandler->hasCallForType('defense')); + } + + public function testFleetHandlerStoresFleetAndProductionValues(): void + { + $handler = $this->createHandler('FleetHandler'); + $handler->handle([ + 'planet' => ['coords' => '4:246:12', 'name' => 'Home', 'id' => 33717002, 'type' => 0], + 'fleet' => ['PT' => 5, 'SAT' => 2], + ]); + + $this->assertNotEmpty($this->db->getQueriesContaining('game_player_fleet')); + $productionQueries = $this->db->getQueriesContaining('game_astro_object'); + $this->assertNotEmpty($productionQueries); + $this->assertStringContainsString('`SAT`', end($productionQueries)); + $this->assertSame('fleet', $this->getIoResponse()['page']); + $this->assertTrue($this->callbackHandler->hasCallForType('fleet')); + } + + public function testAllyListHandlerBuildsCallbackAndResponse(): void + { + $handler = $this->createHandler('AllyListHandler'); + $handler->handle([ + 'tag' => 'SLD', + 'allyList' => [[ + 'player' => 'Marshal Galileo', + 'points' => '12345', + 'rank' => '42', + 'coords' => '4:246:12', + ]], + ]); + + $calls = $this->callbackHandler->getCallsForType('ally_list'); + $this->assertCount(1, $calls); + $this->assertSame('SLD', $calls[0]['params']['tag']); + $this->assertSame(['4', '246', '12'], $calls[0]['params']['list'][0]['coords']); + $this->assertSame('ally_list', $this->getIoResponse()['type']); + } +} diff --git a/tests/unit/SpyDatabase.php b/tests/unit/SpyDatabase.php index 8fdf140..6a8245e 100644 --- a/tests/unit/SpyDatabase.php +++ b/tests/unit/SpyDatabase.php @@ -26,8 +26,16 @@ public function sql_fetch_assoc($result): array return []; } + public function sql_numrows($result): int + { + return 0; + } + public function sql_fetch_row($result): array { + if (str_contains($this->getLastQuery() ?? '', 'SELECT id FROM ogspy_game_astro_object')) { + return [33717423]; + } return [null]; } diff --git a/xtense.php b/xtense.php index d763e9e..5728dfa 100755 --- a/xtense.php +++ b/xtense.php @@ -10,31 +10,35 @@ const IN_SPYOGAME = true; const IN_XTENSE = true; - date_default_timezone_set(@date_default_timezone_get()); -$currentFolder = getcwd(); if (str_contains(getcwd(), 'mod')) { chdir('../../'); } -$_SERVER['SCRIPT_FILENAME'] = str_replace(basename(__FILE__), 'index.php', preg_replace('#/mod/(.*)/#', '/', $_SERVER['SCRIPT_FILENAME'])); -include_once("common.php"); -list($root, $active) = $db->sql_fetch_row($db->sql_query("SELECT `root`, `active` FROM " . TABLE_MOD . " WHERE `action` = 'xtense'")); +$_SERVER['SCRIPT_FILENAME'] = str_replace( + basename(__FILE__), + 'index.php', + preg_replace('#/mod/(.*)/#', '/', $_SERVER['SCRIPT_FILENAME']) +); +include_once 'common.php'; +list($root, $active) = $db->sql_fetch_row($db->sql_query( + "SELECT `root`, `active` FROM " . TABLE_MOD . " WHERE `action` = 'xtense'" +)); -// CORS: allow extension and web origins; auth is in POST body, no cookies involved. -$request_method = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET'); +// Xtense authenticates in the POST body and does not use browser cookies. +$requestMethod = strtoupper($_SERVER['REQUEST_METHOD'] ?? 'GET'); header('Access-Control-Max-Age: 86400'); header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Headers: Content-Type, Authorization, X-Requested-With'); header('Access-Control-Allow-Methods: POST, OPTIONS'); header('X-Content-Type-Options: nosniff'); -if ($request_method === 'OPTIONS') { +if ($requestMethod === 'OPTIONS') { http_response_code(204); exit; } -if ($request_method !== 'POST') { +if ($requestMethod !== 'POST') { header('Allow: POST, OPTIONS'); header('Content-Type: text/plain; charset=utf-8'); http_response_code(405); @@ -42,15 +46,33 @@ exit; } -require_once("mod/$root/includes/config.php"); -require_once("mod/$root/includes/functions.php"); -require_once("mod/$root/includes/CallbackHandler.php"); -require_once("mod/$root/includes/Callback.php"); -require_once("mod/$root/includes/Io.php"); -require_once("mod/$root/includes/Check.php"); -require_once("mod/$root/includes/auth.php"); +require_once "mod/{$root}/includes/config.php"; +require_once "mod/{$root}/includes/functions.php"; +require_once "mod/{$root}/includes/CallbackHandler.php"; +require_once "mod/{$root}/includes/Callback.php"; +require_once "mod/{$root}/includes/Io.php"; +require_once "mod/{$root}/includes/Check.php"; +require_once "mod/{$root}/includes/auth.php"; +require_once "mod/{$root}/includes/AbstractHandler.php"; + +$handlerClasses = [ + 'OverviewHandler', + 'BuildingsHandler', + 'ResourceSettingsHandler', + 'DefenseHandler', + 'ResearchsHandler', + 'FleetHandler', + 'SystemHandler', + 'RankingHandler', + 'CombatReportHandler', + 'AllyListHandler', + 'MessageHandler', +]; +foreach ($handlerClasses as $handlerClass) { + require_once "mod/{$root}/Handler/{$handlerClass}.php"; +} -$start_time = microtime(true); +$startTime = microtime(true); $io = new Io(); $time = time() - 60 * 4; if ($time > mktime(0, 0, 0) && $time < mktime(8, 0, 0)) { @@ -64,1824 +86,90 @@ } $json = file_get_contents('php://input'); -$received_content = json_decode($json, true); -//print_r($received_content); - -if (!is_array($received_content)) { +$receivedContent = json_decode($json, true); +if (!is_array($receivedContent)) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo json_encode(['status' => 0, 'error' => 'Invalid JSON payload']); exit; } -$args = array( +$receivedGameData = filter_var_array($receivedContent, [ 'type' => FILTER_SANITIZE_SPECIAL_CHARS, 'toolbar_version' => FILTER_SANITIZE_SPECIAL_CHARS, 'toolbar_type' => FILTER_SANITIZE_SPECIAL_CHARS, 'mod_min_version' => FILTER_SANITIZE_SPECIAL_CHARS, 'univers' => FILTER_VALIDATE_URL, 'password' => FILTER_DEFAULT, - 'data' => FILTER_DEFAULT -); + 'data' => FILTER_DEFAULT, +]); -$received_game_data = filter_var_array($received_content, $args); -//print_r($received_game_data); - -if (!isset($received_game_data['type'])) { +if (!isset($receivedGameData['type'])) { header('Content-Type: application/json; charset=utf-8'); http_response_code(400); echo json_encode(['status' => 0, 'error' => 'Xtense data not provided']); exit; } -xtense_check_before_auth($received_game_data['toolbar_version'], $received_game_data['mod_min_version'], $active, $received_game_data['univers']); -$xtense_user_data = xtense_check_auth($received_game_data['password']); +xtense_check_before_auth( + $receivedGameData['toolbar_version'], + $receivedGameData['mod_min_version'], + $active, + $receivedGameData['univers'] +); +$xtense_user_data = xtense_check_auth($receivedGameData['password']); $xtense_user_data = xtense_check_user_rights($xtense_user_data); - $call = new CallbackHandler(); -// Xtense : Ajout de la version et du type de barre utilisée par l'utilisateur -$current_user_id = $xtense_user_data['id']; -$db->sql_query("UPDATE " . TABLE_USER . " SET `xtense_version` = '" . $received_game_data['toolbar_version'] . "', `xtense_type` = '" . $received_game_data['toolbar_type'] . "' WHERE `id` = $current_user_id"); -$toolbar_info = $received_game_data['toolbar_type'] . " V" . $received_game_data['toolbar_version']; - -// Récupération des données de jeu -$data = json_decode($received_game_data['data'], true); - -// Meilleur Endroit pour voir ce que l'on récupère de l'extension :-) -//print_r($data); +$currentUserId = $xtense_user_data['id']; +$db->sql_query("UPDATE " . TABLE_USER . " SET `xtense_version` = '" . $receivedGameData['toolbar_version'] . "', `xtense_type` = '" . $receivedGameData['toolbar_type'] . "' WHERE `id` = {$currentUserId}"); +$toolbarInfo = $receivedGameData['toolbar_type'] . ' V' . $receivedGameData['toolbar_version']; +$data = json_decode($receivedGameData['data'], true); try { - -switch ($received_game_data['type']) { - case 'overview': - { //PAGE OVERVIEW - if (!$xtense_user_data['grant']['empire']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'empire' - )); - $io->status(0); - } else { - - $player_details = filter_var_array($data['playerdetails'], [ - 'player_name' => FILTER_DEFAULT, - 'player_id' => FILTER_DEFAULT, - 'playerclass_explorer' => FILTER_DEFAULT, - 'playerclass_miner' => FILTER_DEFAULT, - 'playerclass_warrior' => FILTER_VALIDATE_INT, - 'player_officer_commander' => FILTER_VALIDATE_INT, - 'player_officer_amiral' => FILTER_VALIDATE_INT, - 'player_officer_engineer' => FILTER_VALIDATE_INT, - 'player_officer_geologist' => FILTER_VALIDATE_INT, - 'player_officer_technocrate' => FILTER_VALIDATE_INT - ]); - - $uni_details = filter_var_array( - $data['unidetails'], - [ - 'uni_version' => FILTER_DEFAULT, - 'uni_url' => FILTER_DEFAULT, - 'uni_lang' => FILTER_DEFAULT, - 'uni_name' => FILTER_DEFAULT, - 'uni_time' => FILTER_VALIDATE_INT, - 'uni_speed' => FILTER_VALIDATE_INT, // speed_uni - 'uni_speed_fleet_peaceful' => FILTER_VALIDATE_INT, - 'uni_speed_fleet_war' => FILTER_VALIDATE_INT, - 'uni_speed_fleet_holding' => FILTER_VALIDATE_INT, - 'uni_donut_g' => FILTER_VALIDATE_INT, - 'uni_donut_s' => FILTER_VALIDATE_INT - ] - ); - - $planet_name = filter_var($data['planet']['name'], FILTER_DEFAULT); - $planet_id = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); - $ressources = filter_var_array($data['ressources'], FILTER_VALIDATE_INT); - $temperature_min = filter_var($data['temperature_min'], FILTER_VALIDATE_INT); - $temperature_max = filter_var($data['temperature_max'], FILTER_VALIDATE_INT); - $fields = filter_var($data['fields'], FILTER_VALIDATE_INT); - - $coords = Check::coords($data['planet']['coords']); - $planet_type = ((int)$data['planet']['type'] == 0 ? TYPE_PLANET : TYPE_MOON); - $ogame_timestamp = $uni_details['uni_time']; - - $userclass = 'none'; - if ($player_details['playerclass_miner'] == 1) { - $userclass = 'COL'; - } elseif ($player_details['playerclass_warrior'] == 1) { - $userclass = 'GEN'; - } elseif ($player_details['playerclass_explorer'] == 1) { - $userclass = 'EXP'; - } - - // Met à jour les informations du joueur dans la table ogspy_game_player (TABLE_GAME_PLAYER) - // et lie l'ID du joueur de jeu à l'utilisateur OGSpy dans la table ogspy_user (TABLE_USER) - $gamePlayerId = (int)$player_details['player_id']; - if ($gamePlayerId > 0) { // S'assurer que player_id est valide - $gamePlayerName = $db->sql_escape_string($player_details['player_name']); - $officerCommander = (int)$player_details['player_officer_commander']; - $officerAmiral = (int)$player_details['player_officer_amiral']; - $officerEngineer = (int)$player_details['player_officer_engineer']; - $officerGeologist = (int)$player_details['player_officer_geologist']; - $officerTechnocrate = (int)$player_details['player_officer_technocrate']; - $ogameTimestamp = (int)$uni_details['uni_time']; - $currentOgspyUserId = (int)$xtense_user_data['id']; // ID de l'utilisateur OGSpy - - $queryGamePlayer = " - INSERT INTO " . TABLE_GAME_PLAYER . " ( - `id`, `name`, `class`, - `off_commandant`, `off_amiral`, `off_ingenieur`, `off_geologue`, `off_technocrate`, - `datadate`, - `status`, `ally_id` - ) VALUES ( - {$gamePlayerId}, - '{$gamePlayerName}', - '{$userclass}', - {$officerCommander}, - {$officerAmiral}, - {$officerEngineer}, - {$officerGeologist}, - {$officerTechnocrate}, - {$ogameTimestamp}, - '', - -1 - ) - ON DUPLICATE KEY UPDATE - `name` = VALUES(`name`), - `class` = VALUES(`class`), - `off_commandant` = VALUES(`off_commandant`), - `off_amiral` = VALUES(`off_amiral`), - `off_ingenieur` = VALUES(`off_ingenieur`), - `off_geologue` = VALUES(`off_geologue`), - `off_technocrate` = VALUES(`off_technocrate`), - `datadate` = VALUES(`datadate`)"; - $db->sql_query($queryGamePlayer); - } - - // Met à jour TABLE_USER pour stocker le player_id (ID du joueur dans le jeu) - $db->sql_query("UPDATE " . TABLE_USER . " SET `player_id` = {$gamePlayerId} WHERE `id` = {$currentOgspyUserId}"); - - //Uni Speed - $db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_uni', '{$uni_details['uni_speed']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); - //Uni Speed Peaceful - $db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_peaceful', '{$uni_details['uni_speed_fleet_peaceful']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); - //Uni Speed War - $db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_war', '{$uni_details['uni_speed_fleet_war']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); - //Uni Speed holding - $db->sql_query("INSERT INTO " . TABLE_CONFIG . " (name, value) VALUES ('speed_fleet_holding', '{$uni_details['uni_speed_fleet_holding']}') ON DUPLICATE KEY UPDATE value = VALUES(value)"); - //Update Config Cache - generate_config_cache(); - - //boosters - if (isset($data['boosters'])) { - $boosters = update_boosters($data['boosters'], $ogame_timestamp); /*Merge des différents boosters*/ - $boosters = booster_encode($boosters); /*Conversion de l'array boosters en string*/ - } else { - $boosters = booster_encodev(0, 0, 0, 0, 0, 0, 0, 0); /* si aucun booster détecté*/ - } - //Empire - list($g, $s, $r) = explode(':', $coords); - $db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " - (`player_id`, `id`, `type`, `galaxy`, `system`, `row`, `name`, `fields`, `boosters`, `temperature_min`, `temperature_max`) - VALUES - ({$gamePlayerId}, {$planet_id}, '{$planet_type}' , {$g}, {$s}, {$r},'{$planet_name}', {$fields}, '{$boosters}', {$temperature_min}, {$temperature_max}) - ON DUPLICATE KEY UPDATE - type = VALUES(type), - name = VALUES(name), - player_id = VALUES(player_id), - fields = VALUES(fields), - boosters = VALUES(boosters), - temperature_min = VALUES(temperature_min), - temperature_max = VALUES(temperature_max), - galaxy = VALUES(galaxy), - system = VALUES(system), - row = VALUES(row)"); - - $io->set(array( - 'type' => 'home updated', - 'page' => 'overview', - 'planet' => $coords - )); - - // Appel fonction de callback - $call->add('overview', array( - 'coords' => explode(':', $coords), - 'planet_type' => $planet_type, - 'planet_name' => $planet_name, - 'fields' => $fields, - 'temperature_min' => $temperature_min, - 'temperature_max' => $temperature_max, - 'ressources' => $ressources - )); - - add_log('overview', array('coords' => $coords, 'planet_name' => $planet_name, 'toolbar' => $toolbar_info)); - } - } - - - break; - - case 'buildings': //PAGE BATIMENTS - - if (!$xtense_user_data['grant']['empire']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'empire' - )); - $io->status(0); - } else { - $coords = filter_var($data['planet']['coords']); - $planet_name = filter_var($data['planet']['name']); - $planet_type = filter_var($data['planet']['type']); - $planet_id = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); - if (!isset($coords, $planet_name, $planet_type)) { - throw new UnexpectedValueException("Buildings- Missing data"); - } - $buildings = $data['buildings']; - - $coords = Check::coords($coords); - list($g, $s, $r) = explode(':', $coords); // ADDED: Parse coordinates - $planet_type = ((int)$planet_type == TYPE_PLANET ? TYPE_PLANET : TYPE_MOON); - - // Construction d'une requête UPSERT pour les bâtiments de la planète - $buildingColumns = []; - $buildingValues = []; - - // Préparation des colonnes de base - - $buildingColumns[] = 'id'; // ADDED - $buildingValues[] = $planet_id; // ADDED - $buildingColumns[] = 'galaxy'; // ADDED - $buildingValues[] = $g; // ADDED - $buildingColumns[] = 'system'; // ADDED - $buildingValues[] = $s; // ADDED - $buildingColumns[] = 'row'; // ADDED - $buildingValues[] = $r; // ADDED - - $buildingColumns[] = 'name'; // RENAMED from 'planet_name' - $buildingValues[] = $planet_name; - - // Ajout des bâtiments - foreach ($database['buildings'] as $code) { - if (isset($buildings[$code])) { - $buildingColumns[] = $code; - $buildingValues[] = (int)$buildings[$code]; - } - } - - // Préparation des champs pour la clause ON DUPLICATE KEY UPDATE - $updatePairs = []; - $updatePairs[] = "name = VALUES(name)"; // CHANGED and RENAMED - $updatePairs[] = "galaxy = VALUES(galaxy)"; // ADDED - $updatePairs[] = "system = VALUES(system)"; // ADDED - $updatePairs[] = "row = VALUES(row)"; // ADDED - - foreach ($database['buildings'] as $code) { - if (isset($buildings[$code])) { - $updatePairs[] = "`$code` = VALUES(`$code`)"; // CHANGED to use VALUES() - } - } - - // Construction de la requête complète - $query = "INSERT INTO " . TABLE_USER_BUILDING . " (`" . implode('`, `', $buildingColumns) . "`) - VALUES (" . implode(', ', array_map(function ($val) { - return is_numeric($val) ? $val : "'$val'"; - }, $buildingValues)) . ") - ON DUPLICATE KEY UPDATE " . implode(', ', $updatePairs); - - $db->sql_query($query); - - $io->set(array( - 'type' => 'home updated', - 'page' => 'buildings', - 'planet' => $coords - )); - } - - $call->add('buildings', array( - 'coords' => explode(':', $coords), - 'planet_type' => $planet_type, - 'planet_name' => $planet_name, - 'buildings' => $buildings - )); - - add_log('buildings', array('coords' => $coords, 'planet_name' => $planet_name, 'toolbar' => $toolbar_info)); - - break; - - case 'resourceSettings': - if (!$xtense_user_data['grant']['empire']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'empire' - )); - $io->status(0); - } else { - $coords_str = filter_var($data['planet']['coords']); - $planet_name = filter_var($data['planet']['name']); - $planet_type_int = filter_var($data['planet']['type'], FILTER_VALIDATE_INT); - $planet_id = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); - $resourceSettings_data = isset($data['resourceSettings']) && is_array($data['resourceSettings']) ? $data['resourceSettings'] : null; - - if (!isset($coords_str, $planet_name, $planet_type_int) || - $planet_id === false || $planet_type_int === false || $resourceSettings_data === null - ) { - throw new UnexpectedValueException("ResourceSettings: Missing or invalid planet details or resourceSettings data"); - } - - $coords = Check::coords($coords_str); - list($g, $s, $r) = explode(':', $coords); - - // Constante pour le callback (ex: TYPE_PLANET, TYPE_MOON) - $planet_type_const = ($planet_type_int == TYPE_PLANET ? TYPE_PLANET : TYPE_MOON); - // Chaîne pour la base de données ('planet', 'moon') - $astro_object_type_str = ($planet_type_int == TYPE_PLANET ? 'planet' : 'moon'); - - $columns = []; - $values = []; - - // Colonnes de base pour TABLE_USER_BUILDING (ogspy_game_astro_object) - $columns[] = 'id'; - $values[] = $planet_id; - $columns[] = 'galaxy'; - $values[] = (int)$g; - $columns[] = 'system'; - $values[] = (int)$s; - $columns[] = 'row'; - $values[] = (int)$r; - $columns[] = 'name'; - $values[] = $db->sql_escape_string($planet_name); - $columns[] = 'type'; - $values[] = $db->sql_escape_string($astro_object_type_str); - - // Colonnes pour les pourcentages de ressources - // Clé JSON => Colonne DB - $resource_settings_map = [ - 'M_percentage' => 'M_percentage', - 'C_Percentage' => 'C_Percentage', - 'D_percentage' => 'D_percentage', - 'CES_percentage' => 'CES_percentage', - 'CEF_percentage' => 'CEF_percentage', - 'SAT_percentage' => 'Sat_percentage', // Correction de casse pour la DB - 'FOR_percentage' => 'FOR_percentage' - ]; - - foreach ($resource_settings_map as $json_key => $db_col_name) { - $columns[] = $db_col_name; - // Si la clé n'est pas dans les données JSON, mettre 0 (comme pour 'buildings') - $values[] = isset($resourceSettings_data[$json_key]) ? (int)$resourceSettings_data[$json_key] : 100; - } - - // Préparation des champs pour la clause ON DUPLICATE KEY UPDATE - $updatePairs = []; - $updatePairs[] = "name = VALUES(name)"; - $updatePairs[] = "galaxy = VALUES(galaxy)"; - $updatePairs[] = "system = VALUES(system)"; - $updatePairs[] = "row = VALUES(row)"; - $updatePairs[] = "type = VALUES(type)"; - - foreach ($resource_settings_map as $json_key => $db_col_name) { - $updatePairs[] = "`$db_col_name` = VALUES(`$db_col_name`)"; - } - - // Construction de la requête complète - $query = "INSERT INTO " . TABLE_USER_BUILDING . " (`" . implode('`, `', $columns) . "`) - VALUES (" . implode(', ', array_map(function ($val) { - // Les valeurs numériques sont directes, les chaînes (déjà échappées) sont entourées d'apostrophes - return is_numeric($val) ? $val : "'" . $val . "'"; - }, $values)) . ") - ON DUPLICATE KEY UPDATE " . implode(', ', $updatePairs); - - $db->sql_query($query); - - $io->set(array( - 'type' => 'home updated', - 'page' => 'buildings', // Conformément au code existant pour resourceSettings et à la demande de reproduire 'buildings' - 'planet' => $coords - )); - - // Appel fonction de callback - $call->add('resourceSettings', array( // Nom de callback spécifique - 'coords' => explode(':', $coords), - 'planet_type' => $planet_type_const, // Utiliser la constante (ex: TYPE_PLANET) - 'planet_name' => $planet_name, - 'resourceSettings' => $resourceSettings_data // Renvoyer les données JSON originales - )); - - add_log('resourceSettings', array('coords' => $coords, 'planet_name' => $planet_name, 'toolbar' => $toolbar_info)); - } - - break; - - case 'defense': //PAGE DEFENSE - if (!$xtense_user_data['grant']['empire']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'empire' - )); - $io->status(0); - } else { - $coords = filter_var($data['planet']['coords']); - $planet_name = filter_var($data['planet']['name']); - $planet_id = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); - $planet_type = filter_var($data['planet']['type']); - - $defense = $data['defense']; - //Stop si donnée manquante - if (!isset($coords, $planet_name, $planet_type)) { - throw new UnexpectedValueException("Defense: Missing Planet Details"); - } - $coords = Check::coords($coords); - list($g, $s, $r) = explode(':', $coords); // Extraire les coordonnées - $planet_type = ((int)$planet_type == TYPE_PLANET ? TYPE_PLANET : TYPE_MOON); - $planet_type_str = ((int)$planet_type == TYPE_PLANET ? 'planet' : 'moon'); - - $db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " - (id, type, galaxy, system, row, name, player_id) - VALUES - ({$planet_id}, '{$planet_type_str}', {$g}, {$s}, {$r}, '{$planet_name}', {$xtense_user_data['player_id']}) - ON DUPLICATE KEY UPDATE - name = '{$planet_name}'"); - - // Préparer les champs pour la requête d'insertion/mise à jour des défenses - $defense_fields = []; - $defense_values = []; - $update_pairs = []; - - foreach ($database['defense'] as $code) { - if (isset($defense[$code])) { - $defense_fields[] = "`$code`"; - $defense_values[] = (int)$defense[$code]; - $update_pairs[] = "`$code` = " . (int)$defense[$code]; - } - } - - // Construction de la requête UPSERT pour les défenses - if (!empty($defense_fields)) { - $fields_str = implode(', ', $defense_fields); - $values_str = implode(', ', $defense_values); - - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER_DEFENSE . " - (astro_object_id, {$fields_str}) - VALUES - ({$planet_id}, {$values_str}) - ON DUPLICATE KEY UPDATE - " . implode(", ", $update_pairs)); - } - - $io->set(array( - 'type' => 'home updated', - 'page' => 'defense', - 'planet' => $coords - )); - - // Préparer les données pour le callback - $defenses = array(); - foreach ($database['defense'] as $code) { - if (isset($defense[$code])) { - $defenses[$code] = (int)$defense[$code]; - } - } - - $call->add('defense', [ - 'coords' => explode(':', $coords), - 'planet_type' => $planet_type, - 'planet_name' => $planet_name, - 'defense' => $defenses - ]); - - add_log('defense', array('coords' => $coords, 'planet_name' => $planet_name, 'toolbar' => $toolbar_info)); - } - break; - - case 'researchs': //PAGE RECHERCHE - - if (!$xtense_user_data['grant']['empire']) { - $io->set(['type' => 'plugin grant', 'access' => 'empire']); - $io->status(0); - } else { - $coords = filter_var($data['planet']['coords']); - $planet_name = filter_var($data['planet']['name']); - $planet_type = filter_var($data['planet']['type']); - $researchs = $data['researchs']; - - if (!isset($coords, $planet_name, $planet_type)) { - throw new UnexpectedValueException("Researchs: Missing Planet Details"); - } - $coords = Check::coords($coords); - $planet_type = ((int)$planet_type == TYPE_PLANET ? TYPE_PLANET : TYPE_MOON); - - // Vérifier que l'ID du joueur est disponible - if (!isset($xtense_user_data['player_id']) || $xtense_user_data['player_id'] <= 0) { - throw new UnexpectedValueException("Researchs: Player ID not available"); - } - - $player_id = (int)$xtense_user_data['player_id']; - - // Préparer les champs pour la requête d'insertion/mise à jour des technologies - $fields = []; - $values = []; - $update_parts = []; - - foreach ($database['labo'] as $code) { - if (isset($researchs[$code])) { - $fields[] = "`$code`"; - $values[] = (int)$researchs[$code]; - $update_parts[] = "`$code` = " . (int)$researchs[$code]; - } - } - - // Construction de la requête UPSERT pour les technologies - if (!empty($fields)) { - $fields_str = implode(', ', $fields); - $values_str = implode(', ', $values); - - $db->sql_query("INSERT INTO " . TABLE_USER_TECHNOLOGY . " - (`player_id`, {$fields_str}) - VALUES - ({$player_id}, {$values_str}) - ON DUPLICATE KEY UPDATE - " . implode(", ", $update_parts)); - } - - $io->set(array( - 'type' => 'home updated', - 'page' => 'labo', - 'planet' => $coords - )); - - $call->add('research', array( - 'research' => $researchs - )); - - add_log('research', array('toolbar' => $toolbar_info)); - } - break; - - case 'fleet': //PAGE FLOTTE - - if (!$xtense_user_data['grant']['empire']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'empire' - )); - $io->status(0); - } else { - $coords = filter_var($data['planet']['coords']); - $planet_name = filter_var($data['planet']['name']); - $planet_type = filter_var($data['planet']['type']); - $planet_id = filter_var($data['planet']['id'], FILTER_VALIDATE_INT); - $fleet = $data['fleet']; - - if (!isset($coords, $planet_name, $planet_type)) { - throw new UnexpectedValueException("Fleet: Missing Planet Details"); - } - $coords = Check::coords($coords); - list($g, $s, $r) = explode(':', $coords); // Extraire les coordonnées - $planet_type = ((int)$planet_type == TYPE_PLANET ? TYPE_PLANET : TYPE_MOON); - $planet_type_str = ((int)$planet_type == TYPE_PLANET ? 'planet' : 'moon'); - - $query = "INSERT INTO " . TABLE_USER_BUILDING . " (id, type, galaxy, system, row, name, player_id) - VALUES ({$planet_id}, '{$planet_type_str}', {$g}, {$s}, {$r}, '{$planet_name}', {$xtense_user_data['player_id']}) - ON DUPLICATE KEY - UPDATE name = '{$planet_name}'"; - - $db->sql_query($query); - - // Préparer les champs pour la requête d'insertion/mise à jour de la flotte - $fleet_fields = []; - $fleet_values = []; - $update_pairs = []; - - foreach ($database['fleet'] as $code) { - if (isset($fleet[$code])) { - $fleet_fields[] = "`$code`"; - $fleet_values[] = (int)$fleet[$code]; - $update_pairs[] = "`$code` = " . (int)$fleet[$code]; - } - } - - // Construction de la requête UPSERT pour la flotte - if (!empty($fleet_fields)) { - $fields_str = implode(', ', $fleet_fields); - $values_str = implode(', ', $fleet_values); - - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER_FLEET . " (astro_object_id, {$fields_str}) - VALUES - ({$planet_id}, {$values_str}) - ON DUPLICATE KEY UPDATE - " . implode(", ", $update_pairs)); - } - - // Mettre à jour les informations de la flotte de production - - foreach ($database['fleet_production'] as $code) { - if (isset($fleet[$code])) { - $fleet_production_fields[] = "`$code`"; - $fleet_production_values[] = (int)$fleet[$code]; - $update_prod_pairs[] = "`$code` = " . (int)$fleet[$code]; - } - } - - // Construction de la requête UPSERT pour la flotte - if (!empty($fleet_production_fields)) { - $fields_str = implode(', ', $fleet_production_fields); - $values_str = implode(', ', $fleet_production_values); - - $db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " - (id, {$fields_str}) - VALUES - ({$planet_id}, {$values_str}) - ON DUPLICATE KEY UPDATE - " . implode(", ", $update_prod_pairs)); - } - - - $io->set(array( - 'type' => 'home updated', - 'page' => 'fleet', - 'planet' => $coords - )); - - $call->add('fleet', array( - 'coords' => explode(':', $coords), - 'planet_type' => $planet_type, - 'planet_name' => $planet_name, - 'fleet' => $fleet - )); - - add_log('fleet', array('coords' => $coords, 'planet_name' => $planet_name, 'toolbar' => $toolbar_info)); - } - break; - - case 'system': //PAGE SYSTEME SOLAIRE - if (!$xtense_user_data['grant']['system']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'system' - )); - $io->status(0); - } else { - $galaxy = filter_var($data['galaxy'], FILTER_SANITIZE_NUMBER_INT); - $system = filter_var($data['system'], FILTER_SANITIZE_NUMBER_INT); - if (!isset($galaxy, $system)) { - throw new UnexpectedValueException("Galaxy: Missing Planet position"); - } - - if ($galaxy > $server_config['num_of_galaxies'] || $system > $server_config['num_of_systems']) { - $io->set(array( - 'type' => 'plugin univers', - 'access' => 'system' - )); - $io->status(0); - } - - $delete = []; - $update = []; - - $query = "SELECT `row` FROM " . TABLE_USER_BUILDING . " WHERE `galaxy` = {$galaxy} AND `system` = {$system}"; - $check = $db->sql_query($query); - while ($value = $db->sql_fetch_assoc($check)) { - $update[$value['row']] = true; - } - - $rows = $data['rows']; - // Recupération des données - for ($i = 1; $i < 16; $i++) { - if (isset($rows[$i])) { - $line = $rows[$i]; - - $line['player_name'] = filter_var($line['player_name']); - $line['planet_name'] = filter_var($line['planet_name']); - $line['planet_id'] = filter_var($line['planet_id'], FILTER_VALIDATE_INT); - $line['ally_tag'] = filter_var($line['ally_tag']); - - if (isset($line['debris'])) { - $line['debris'] = filter_var_array($line['debris'], [ - 'metal' => FILTER_SANITIZE_NUMBER_INT, - 'crystal' => FILTER_SANITIZE_NUMBER_INT, - 'deuterium' => FILTER_SANITIZE_NUMBER_INT, - ]); - } - if (isset($line['status'])) { - $line['status'] = filter_var($line['status']); - } - $system_data[$i] = $line; - } else { - $delete[] = $i; - $system_data[$i] = array( - 'planet_id' => '', - 'planet_name' => '', - 'player_name' => '', - 'status' => '', - 'ally_tag' => '', - 'debris' => array('metal' => 0, 'cristal' => 0, 'deuterium' => 0), - 'moon' => 0, - 'activity' => '' - ); - } - } - - foreach ($system_data as $row => $v) { - $statusTemp = (Check::player_status_forbidden($v['status']) ? "" : $v['status']); //On supprime les status qui sont subjectifs - - //default player_id/ally_id à -1 (cf shemas SQL) - $v['player_id'] = (isset($v['player_id']) ? (int)$v['player_id'] : -1); - $v['planet_id'] = (isset($v['planet_id']) ? (int)$v['planet_id'] : -1); - $v['moon'] = (isset($v['moon']) ? (int)$v['moon'] : -1); - $v['moon_id'] = (isset($v['moon_id']) ? (int)$v['moon_id'] : -1); - $v['ally_id'] = (isset($v['ally_id']) ? (int)$v['ally_id'] : -1); - $v['ally_tag'] = $v['ally_tag'] ?? ''; - - $db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " - (`id`, `galaxy`, `system`, `row`, `name`, `player_id`, `last_update`, `last_update_user_id`) - VALUES - ({$v['planet_id']},{$galaxy}, {$system}, {$row}, '{$v['planet_name']}', {$v['player_id']}, " . time() . ", {$xtense_user_data['id']} ) - ON DUPLICATE KEY UPDATE - `name` = '{$v['planet_name']}', - `player_id` = {$v['player_id']}, - `last_update` = " . time() . ", - `last_update_user_id` = {$xtense_user_data['id']}"); - - // Création des lignes pour les lunes - - if (isset($v['moon_id']) && $v['moon'] == 1) { - $db->sql_query("INSERT INTO " . TABLE_USER_BUILDING . " - (`id`, `type`, `galaxy`, `system`, `row`, `name`, `player_id`, `last_update_moon`, `last_update_user_id`) - VALUES - ({$v['moon_id']}, 'moon',{$galaxy}, {$system}, {$row}, '{$v['planet_name']} - Moon', {$v['player_id']}, " . time() . ", {$xtense_user_data['id']} ) - ON DUPLICATE KEY UPDATE - `name` = '{$v['planet_name']} - Moon', - `player_id` = {$v['player_id']}, - `last_update_moon` = " . time() . ", - `last_update_user_id` = {$xtense_user_data['id']}"); - } - - - // UPSERT pour la table game_player pour mettre à jour le statut - if ($v['player_id'] != -1) { - - $currentTime = time(); - $playerId = (int)$v['player_id']; - $playerName = $db->sql_escape_string($v['player_name']); - $status = $db->sql_escape_string($statusTemp); - $allyId = (int)$v['ally_id']; - - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER . " - (`id`, `name`, `status`, `ally_id`, `datadate`) - VALUES - ($playerId, '$playerName', '$status', $allyId, $currentTime) - ON DUPLICATE KEY UPDATE - `name` = '$playerName', - `status` = '$status', - `ally_id` = $allyId, - `datadate` = $currentTime"); - } - //La table game ally ne peut se mettre à jour, champs ally non alimenté (toutes les infos sont dans page rank) - // UPSERT pour la table game_player pour mettre à jour le statut - if ($v['ally_id'] > 0) { - - $currentTime = time(); - $allytag = $v['ally_tag']; - $allyId = $v['ally_id']; - - $db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " - (`id`, `tag`, `datadate`) - VALUES - ($allyId, '$allytag', $currentTime) - ON DUPLICATE KEY UPDATE - `tag` = '$allytag', - `datadate` = $currentTime"); - } - } - - if (!empty($delete)) { - $toDelete = array(); - foreach ($delete as $n) { - $toDelete[] = $galaxy . ':' . $system . ':' . $n; - } - } - - $db->sql_query("UPDATE " . TABLE_USER . " SET `planet_imports` = `planet_imports` + 15 WHERE `id` = " . $xtense_user_data['id']); - - $call->add('system', array( - 'data' => $data['rows'], - 'galaxy' => $galaxy, - 'system' => $system - )); - - $io->set(array( - 'type' => 'system', - 'galaxy' => $galaxy, - 'system' => $system - )); - - update_statistic('planetimports', 15); - add_log('system', array('coords' => $galaxy . ':' . $system, 'toolbar' => $toolbar_info)); - } - break; - - case 'ranking': //PAGE STATS - - $type1 = filter_var($data['type1']); - $type2 = filter_var($data['type2']); - $type3 = filter_var($data['type3']) ?? 0; - $offset = filter_var($data['offset'], FILTER_SANITIZE_NUMBER_INT); - $date = filter_var($data['time']); - - if (!isset($type1, $type2, $offset, $data['n'], $date)) { - throw new UnexpectedValueException("Rankings: Incomplete Ranking"); - } - - if (!$xtense_user_data['grant']['ranking']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'ranking' - )); - $io->status(0); - } else { - if ($type1 != ('player' || 'ally')) { - throw new UnexpectedValueException("Ranking: Unexpected Ranking type for type1"); - } - } - //Vérification Offset - if ((($offset - 1) % 100) != 0) { - throw new UnexpectedValueException("Ranking: Offset not found"); - } - - $n = $data['n']; - $total = 0; - $count = count($n); - - if ($type1 == 'player') { - $table = match ($type2) { - 'points' => TABLE_RANK_PLAYER_POINTS, - 'economy' => TABLE_RANK_PLAYER_ECO, - 'research' => TABLE_RANK_PLAYER_TECHNOLOGY, - 'fleet' => match ($type3) { - '' => TABLE_RANK_PLAYER_MILITARY, - '5' => TABLE_RANK_PLAYER_MILITARY_BUILT, - '6' => TABLE_RANK_PLAYER_MILITARY_DESTRUCT, - '4' => TABLE_RANK_PLAYER_MILITARY_LOOSE, - '7' => TABLE_RANK_PLAYER_HONOR, - default => throw new OutOfRangeException("Ranking Player: Unexpected Ranking type for type3: " . $type3), - }, - default => throw new UnexpectedValueException("Ranking Player: Unexpected Ranking type for type2: " . $type2), - }; - } else { - $table = match ($type2) { - 'points' => TABLE_RANK_ALLY_POINTS, - 'economy' => TABLE_RANK_ALLY_ECO, - 'research' => TABLE_RANK_ALLY_TECHNOLOGY, - 'fleet' => match ($type3) { - '' => TABLE_RANK_ALLY_MILITARY, - '5' => TABLE_RANK_ALLY_MILITARY_BUILT, - '6' => TABLE_RANK_ALLY_MILITARY_DESTRUCT, - '4' => TABLE_RANK_ALLY_MILITARY_LOOSE, - '7' => TABLE_RANK_ALLY_HONOR, - default => throw new OutOfRangeException("Ranking Ally: Unexpected Ranking type for type3: " . $type3), - }, - default => throw new UnexpectedValueException("Ranking Ally: Unexpected Ranking type for type2: " . $type2), - }; - } - - $query = array(); - - if ($type1 == 'player') { - foreach ($n as $data) { - - // Vérification des données essentielles - $data['player_name'] = filter_var($data['player_name']); - $data['ally_tag'] = filter_var($data['ally_tag']); - - if (!empty($data['points'])) { - $data['points'] = (int)$data['points']; - } - - $data['ally_id'] = !empty($data['ally_id']) ? (int)$data['ally_id'] : -1; - $data['player_id'] = !empty($data['player_id']) ? (int)$data['player_id'] : -1; - - //Compléter table GAME PLAYER pour les joueurs qui n'ont pas de compte - - if ($data['player_id'] > 0 && !empty($data['player_name'])) { - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER . " - (id, name, ally_id, datadate) - VALUES - ({$data['player_id']}, '{$data['player_name']}', {$data['ally_id']}, " . time() . ") - ON DUPLICATE KEY UPDATE - name = VALUES(name), - ally_id = VALUES(ally_id), - datadate = VALUES(datadate)"); - } - //Compléter table GAME ALLY pour les alliances qui n'ont pas de compte - // Insert or update alliance data in the GAME ALLY table - if ($data['ally_id'] > 0 && !empty($data['ally_tag'])) { - $db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " - (id, tag, datadate) - VALUES - ({$data['ally_id']}, '{$data['ally_tag']}', " . time() . ") - ON DUPLICATE KEY UPDATE - tag = VALUES(tag), - datadate = VALUES(datadate)"); - } - - - if ($table == TABLE_RANK_PLAYER_MILITARY) { - $query[] = "({$timestamp}, {$data['rank']}, '{$data['player_name']}' , {$data['player_id']}, '{$data['ally_tag']}', {$data['ally_id']}, {$data['points']}, {$xtense_user_data['id']}, {$data['nb_spacecraft']} )"; - } else { - $query[] = "({$timestamp}, {$data['rank']}, '{$data['player_name']}' , {$data['player_id']}, '{$data['ally_tag']}', {$data['ally_id']}, {$data['points']}, {$xtense_user_data['id']} )"; - } - $total++; - $datas[] = $data; - - if (!empty($query)) { - if ($table == TABLE_RANK_PLAYER_MILITARY) { - $db->sql_query("REPLACE INTO " . $table . " (`datadate`, `rank`, `player`, `player_id`, `ally`, `ally_id`, `points`, `sender_id`, `nb_spacecraft`) VALUES " . implode(',', $query)); - } else { - $db->sql_query("REPLACE INTO " . $table . " (`datadate`, `rank`, `player`, `player_id`, `ally`, `ally_id`, `points`, `sender_id`) VALUES " . implode(',', $query)); - } - } - } - } else { - $fields = 'datadate, rank, ally, ally_id, points, sender_id, number_member, points_per_member'; - foreach ($n as $data) { - $data['ally_tag'] = filter_var($data['ally_tag']); - $data['ally_name'] = filter_var($data['ally']); - $data['ally_id'] = filter_var($data['ally_id'] ?? throw new UnexpectedValueException("Ranking Ally: Alliance Id not found"), FILTER_SANITIZE_NUMBER_INT); - $data['points'] = filter_var($data['points'] ?? throw new UnexpectedValueException("Ranking Ally: No points sent"), FILTER_SANITIZE_NUMBER_INT); - $data['mean'] = filter_var($data['mean'] ?? throw new UnexpectedValueException("Ranking Ally: No mean found"), FILTER_SANITIZE_NUMBER_INT); - $data['members'] = filter_var($data['members'] ?? throw new UnexpectedValueException("Ranking Ally: Nb players not found"), FILTER_SANITIZE_NUMBER_INT); - - // Insert or update alliance data in the GAME ALLY table - if ($data['ally_id'] > 0 && !empty($data['ally_tag'] && !empty($data['ally_name']))) { - $db->sql_query("INSERT INTO " . TABLE_GAME_ALLY . " - (id, name, tag, datadate) - VALUES - ({$data['ally_id']}, '{$data['ally_name']}', '{$data['ally_tag']}', " . time() . ") - ON DUPLICATE KEY UPDATE - name = VALUES(name), - tag = VALUES(tag), - datadate = VALUES(datadate)"); - } - - - $query[] = "({$timestamp}, {$data['rank']} , '{$data['ally_tag']}' , {$data['ally_id']} , {$data['points']} , {$xtense_user_data['id']} , {$data['members']} ,{$data['mean']} )"; - $datas[] = $data; - $total++; - } - - if (!empty($query)) { - $db->sql_query("REPLACE INTO " . $table . " (" . $fields . ") VALUES " . implode(',', $query)); - } - - $db->sql_query("UPDATE " . TABLE_USER . " SET rank_imports = rank_imports + " . $total . " WHERE id = " . $xtense_user_data['id']); - } - - $type2 = (($type2 == 'fleet') ? $type2 . $type3 : $type2); - - $call->add('ranking_' . $type1 . '_' . $type2, array( - 'data' => $datas, - 'offset' => $offset, - 'time' => $timestamp - )); - - $io->set(array( - 'type' => 'ranking', - 'type1' => $type1, - 'type2' => $type2, - 'offset' => $offset - )); - - update_statistic('rankimports', 100); - add_log('ranking', array('type1' => $type1, 'type2' => $type2, 'offset' => $offset, 'time' => $timestamp, 'toolbar' => $toolbar_info)); - - break; - - case 'rc'://PAGE RC - case 'rc_shared': - $combatReport = $data; - $ogapilnk = filter_var($combatReport['ogapilnk']); - - if (!isset($json)) { - throw new UnexpectedValueException("Combat Report: JSON Report not sent"); - } - $ogapilnk = $ogapilnk ?? ''; - - if (!$xtense_user_data['grant']['messages']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'messages' - )); - $io->status(0); - } else { - $call->add('rc', array( - 'json' => $json, - 'api' => $ogapilnk - )); - - $exist = $db->sql_fetch_row($db->sql_query("SELECT `id_rc` FROM " . TABLE_PARSEDRC . " WHERE `dateRC` = '" . (int)$combatReport['timestamp'] . "'")); - - if (!isset($exist[0])) { -// Récupération des coordonnées - $coordinates = $combatReport['coordinates']; // "4:252:12" - -// Récupération du nombre de rounds - $nbRounds = count($combatReport['combatRounds']); - -// L'objet JSON n'existe plus dans cette structure, utilisez directement $combatReport -// Remplacez $jsonObj par $combatReport dans le code - -// Récupération du gagnant - $winner = match ($combatReport['result']['winner']) { - 'draw' => 'N', - 'attacker' => 'A', - 'defender' => 'D', - default => throw new UnexpectedValueException("Combat Report: Result not found"), - }; - -// Récupération des ressources du butin - $lootMetal = 0; - $lootCrystal = 0; - $lootDeuterium = 0; - - foreach ($combatReport['result']['loot']['resources'] as $resource) { - switch ($resource['resource']) { - case 'metal': - $lootMetal = $resource['amount']; - break; - case 'crystal': - $lootCrystal = $resource['amount']; - break; - case 'deuterium': - $lootDeuterium = $resource['amount']; - break; - } - } - -// Récupération des débris (si disponibles) - $debrisMetal = 0; - $debrisCrystal = 0; - - if (!empty($combatReport['result']['debris']['resources'])) { - foreach ($combatReport['result']['debris']['resources'] as $debris) { - switch ($debris['resource']) { - case 'metal': - $debrisMetal = $debris['amount']; - break; - case 'crystal': - $debrisCrystal = $debris['amount']; - break; - } - } - } - -// Récupération des pertes par camp - $lostUnitsAttacker = 0; - $lostUnitsDefender = 0; - - foreach ($combatReport['result']['totalValueOfUnitsLost'] as $loss) { - switch ($loss['side']) { - case 'attacker': - $lostUnitsAttacker = $loss['value']; - break; - case 'defender': - $lostUnitsDefender = $loss['value']; - break; - } - } - -// Chance de création de lune - $moon = 0; - if (isset($combatReport['result']['moonCreation']) && is_array($combatReport['result']['moonCreation'])) { - $moon = (int)($combatReport['result']['moonCreation']['chance'] ?? 0); - } - -// Récupération de l'astro_object_id depuis les coordonnées et le type d'objet - list($g, $s, $r) = explode(':', $coordinates); - -// Déterminer le type d'objet astro depuis les données du RC - $defenderSpaceObject = $combatReport['defenderSpaceObject']; - $astro_object_type = $defenderSpaceObject['type']; // 'planet' ou 'moon' - - $astro_object_result = $db->sql_query("SELECT id FROM " . TABLE_USER_BUILDING . " - WHERE galaxy = {$g} AND system = {$s} AND row = {$r} AND type = '{$astro_object_type}' - ORDER BY last_update DESC LIMIT 1"); - $astro_object_row = $db->sql_fetch_row($astro_object_result); - $astro_object_id = $astro_object_row[0] ?? null; - - if ($astro_object_id === null) { - throw new UnexpectedValueException("Combat Report: Astro object not found for coordinates {$coordinates} with type {$astro_object_type}"); - } - -// Mise à jour de la requête SQL - $db->sql_query( - "INSERT INTO " . TABLE_PARSEDRC . " ( - `dateRC`, `astro_object_id`, `nb_rounds`, `victoire`, `pertes_A`, `pertes_D`, `gain_M`, `gain_C`, `gain_D`, `debris_M`, `debris_C`, `lune` - ) VALUES ( - '{$combatReport['timestamp']}', - '{$astro_object_id}', - '{$nbRounds}', - '{$winner}', - '{$lostUnitsAttacker}', - '{$lostUnitsDefender}', - '{$lootMetal}', - '{$lootCrystal}', - '{$lootDeuterium}', - '{$debrisMetal}', - '{$debrisCrystal}', - '{$moon}' - )" - ); - $id_rc = $db->sql_insertid(); - - foreach ($combatReport['fleets'] as $fleet) { - if ($fleet['side'] === 'attacker') { - // Extraire les pourcentages de recherche de combat en utilisant les IDs - $armorPercent = 0; - $weaponPercent = 0; - $shieldPercent = 0; - - if (isset($fleet['combatResearchPercentage']) && is_array($fleet['combatResearchPercentage'])) { - foreach ($fleet['combatResearchPercentage'] as $research) { - switch ($research['id']) { - case 109: // Armor/Protection - $armorPercent = $research['percentage']; - break; - case 110: // Weapon/Armes - $weaponPercent = $research['percentage']; - break; - case 111: // Shield/Bouclier - $shieldPercent = $research['percentage']; - break; - } - } - } - - $attackers[$fleet['fleetId']] = array( - 'coords' => $fleet['spaceObject']['coordinates']['galaxy'] . ':' . - $fleet['spaceObject']['coordinates']['system'] . ':' . - $fleet['spaceObject']['coordinates']['position'], - 'planetType' => $fleet['spaceObject']['type'], - 'name' => $fleet['player']['name'], - 'armor' => $armorPercent, - 'weapon' => $weaponPercent, - 'shield' => $shieldPercent - ); - } else { - // Extraire les pourcentages de recherche de combat en utilisant les IDs pour les défenseurs - $armorPercent = 0; - $weaponPercent = 0; - $shieldPercent = 0; - - if (isset($fleet['combatResearchPercentage']) && is_array($fleet['combatResearchPercentage'])) { - foreach ($fleet['combatResearchPercentage'] as $research) { - switch ($research['id']) { - case 109: // Armor/Protection - $armorPercent = $research['percentage']; - break; - case 110: // Weapon/Armes - $weaponPercent = $research['percentage']; - break; - case 111: // Shield/Bouclier - $shieldPercent = $research['percentage']; - break; - } - } - } - - $defenders[] = array( - 'coords' => $fleet['spaceObject']['coordinates']['galaxy'] . ':' . - $fleet['spaceObject']['coordinates']['system'] . ':' . - $fleet['spaceObject']['coordinates']['position'], - 'planetType' => $fleet['spaceObject']['type'], - 'name' => $fleet['player']['name'], - 'armor' => $armorPercent, - 'weapon' => $weaponPercent, - 'shield' => $shieldPercent - ); - } - } - - for ($i = 0; $i < $nbRounds; $i++) { - $round = $combatReport['combatRounds'][$i]; - - // Initialisation des variables pour les statistiques - $a_nb = 0; - $d_nb = 0; - $a_shoot = 0; - $d_shoot = 0; - $a_bcl = 0; - $d_bcl = 0; - - // Parcourir les statistiques pour identifier attaquant et défenseur - foreach ($round['statistics'] as $stat) { - if ($stat['side'] === 'attacker') { - $a_nb = $stat['hits'] ?? 0; - $a_shoot = $stat['strength'] ?? 0; - $a_bcl = $stat['absorbedDamage'] ?? 0; - } elseif ($stat['side'] === 'defender') { - $d_nb = $stat['hits'] ?? 0; - $d_shoot = $stat['strength'] ?? 0; - $d_bcl = $stat['absorbedDamage'] ?? 0; - } - } - - $db->sql_query( - "INSERT INTO " . TABLE_PARSEDRCROUND . " ( - `id_rc`, `numround`, `attaque_tir`, `attaque_puissance`, `defense_bouclier`, `attaque_bouclier`, `defense_tir`, `defense_puissance` - ) VALUES ( - '{$id_rc}', '{$i}', '{$a_nb}', '{$a_shoot}', '{$d_bcl}', '{$a_bcl}', '{$d_nb}', '{$d_shoot}' - )" - ); - $id_rcround = $db->sql_insertid(); - - if (!$id_rcround) { - throw new UnexpectedValueException("Combat Report: Failed to insert round {$i}"); - } - - - - // Utilisation de la configuration existante pour le mapping ID -> code - $fleetMapping = $databaseSpyId['fleet']; - $defenseMapping = $databaseSpyId['defense']; - - // Colonnes pour attaquants (vaisseaux uniquement) - $attackerColumns = $database['fleet']; - - // Colonnes pour défenseurs (vaisseaux + défenses) - $defenderColumns = array_merge($database['fleet'], ['SAT', 'FOR'], $database['defense']); - - // Traitement des flottes par round - foreach ($round['fleets'] as $fleet) { - if (!isset($fleet['side'], $fleet['player'])) { - continue; - } - - $playerId = isset($fleet['player']['id']) ? (int)$fleet['player']['id'] : -1; - $playerName = isset($fleet['player']['name']) ? $db->sql_escape_string($fleet['player']['name']) : 'Unknown'; - - if ($fleet['side'] === 'attacker') { - // Traitement des attaquants - Trouver l'attaquant par nom au lieu de fleetId - $attacker = null; - if (isset($attackers) && is_array($attackers)) { - foreach ($attackers as $att) { - if (isset($att['name']) && $att['name'] === $fleet['player']['name']) { - $attacker = $att; - } - } - } - // Traitement des attaquants - Recherche directe par nom - - if (isset($attackers[$fleet['player']['name']])) { - $attacker = $attackers[$fleet['player']['name']]; - // Initialiser les compteurs à 0 - $fleetCounts = array_fill_keys($attackerColumns, 0); - } - - // Traiter les technologies du round (vaisseaux restants après combat) - if (isset($fleet['technologies']) && is_array($fleet['technologies'])) { - foreach ($fleet['technologies'] as $tech) { - if (!isset($tech['technologyId'])) continue; - - $techId = (int)$tech['technologyId']; - $remaining = isset($tech['remaining']) ? (int)$tech['remaining'] : 0; - - // Utiliser le mapping de la configuration - if (isset($fleetMapping[$techId]) && in_array($fleetMapping[$techId], $attackerColumns)) { - $shipCode = $fleetMapping[$techId]; - $fleetCounts[$shipCode] = $remaining; - } - } - } - - // Récupérer les stats de combat - $weapons = (isset($attacker) && is_array($attacker) && isset($attacker['weapon'])) ? (int)$attacker['weapon'] : 0; - $shields = (isset($attacker) && is_array($attacker) && isset($attacker['shield'])) ? (int)$attacker['shield'] : 0; - $armor = (isset($attacker) && is_array($attacker) && isset($attacker['armor'])) ? (int)$attacker['armor'] : 0; - - // Préparer les valeurs pour l'insertion - $values = []; - foreach ($attackerColumns as $column) { - $values[] = $fleetCounts[$column]; - } - - $query = "INSERT INTO " . TABLE_ROUND_ATTACK . " ( - `id_rcround`, `player`, `astro_object_id`, `Armes`, `Bouclier`, `Protection`, - `" . implode('`, `', $attackerColumns) . "` - ) VALUES ( - {$id_rcround}, '{$playerName}', {$astro_object_id}, {$weapons}, {$shields}, {$armor}, - " . implode(', ', $values) . " - )"; - - $db->sql_query($query); - - } elseif ($fleet['side'] === 'defender') { - // Traitement des défenseurs - - // Recherche du défenseur par nom - $defender = null; - if (isset($defenders) && is_array($defenders)) { - foreach ($defenders as $def) { - if (isset($def['name']) && $def['name'] === $fleet['player']['name']) { - $defender = $def; - break; - } - } - } - - // Initialiser les compteurs à 0 - $unitCounts = array_fill_keys($defenderColumns, 0); - - // Traiter les technologies du round (unités restantes après combat) - if (isset($fleet['technologies']) && is_array($fleet['technologies'])) { - foreach ($fleet['technologies'] as $tech) { - if (!isset($tech['technologyId'])) continue; - - $techId = (int)$tech['technologyId']; - $remaining = isset($tech['remaining']) ? (int)$tech['remaining'] : 0; - - $unitCode = null; - // Chercher dans les mappings de flotte et défense - if (isset($fleetMapping[$techId])) { - $unitCode = $fleetMapping[$techId]; - } elseif (isset($defenseMapping[$techId])) { - $unitCode = $defenseMapping[$techId]; - } - - if ($unitCode && in_array($unitCode, $defenderColumns)) { - $unitCounts[$unitCode] = $remaining; - } - } - } - - // Récupérer les stats de combat du défenseur - $weapons = (isset($defender) && is_array($defender) && isset($defender['weapon'])) ? (int)$defender['weapon'] : 0; - $shields = (isset($defender) && is_array($defender) && isset($defender['shield'])) ? (int)$defender['shield'] : 0; - $armor = (isset($defender) && is_array($defender) && isset($defender['armor'])) ? (int)$defender['armor'] : 0; - - // Préparer les valeurs pour l'insertion - $values = []; - foreach ($defenderColumns as $column) { - // Traitement spécial pour les boucliers (valeurs binaires) - if ($column === 'PB' || $column === 'GB') { - $values[] = ($unitCounts[$column] > 0) ? 1 : 0; - } else { - $values[] = $unitCounts[$column]; - } - } - - $query = "INSERT INTO " . TABLE_ROUND_DEFENSE . " ( - `id_rcround`, `player_id`, `astro_object_id`, `Armes`, `Bouclier`, `Protection`, - `" . implode('`, `', $defenderColumns) . "` - ) VALUES ( - {$id_rcround}, {$playerId}, {$astro_object_id}, {$weapons}, {$shields}, {$armor}, - " . implode(', ', $values) . " - )"; - - $db->sql_query($query); - } - } - - - } - } - $io->set(array( - 'type' => $received_game_data['type'], - )); - - add_log($received_game_data['type'], array('toolbar' => $toolbar_info)); - } - - break; - - case 'ally_list': //PAGE ALLIANCE - if (!$xtense_user_data['grant']['ranking']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'ranking' - )); - $io->status(0); - } else { - if (!isset($data['tag'], $data['allyList'])) { - throw new UnexpectedValueException("Allylist: Missing Value"); - } - - if (!isset($data['tag'])) { - break; - } //Pas d'alliance - $tag = filter_var($data['tag']); - $list = array(); - - foreach ($data['allyList'] as $data) { - - if (!isset($data['player'], $data['points'], $data['rank'], $data['coords'])) { - throw new UnexpectedValueException("Allylist: Missing Ally Detailed list"); - } - - $list[] = array( - 'pseudo' => filter_var($data['player']), - 'points' => filter_var($data['points'], FILTER_SANITIZE_NUMBER_INT), - 'coords' => explode(':', $data['coords']), - 'rang' => filter_var($data['rank'], FILTER_SANITIZE_NUMBER_INT) - ); - } - - $call->add('ally_list', array( - 'list' => $list, - 'tag' => $tag - )); - - $io->set(array( - 'type' => 'ally_list', - 'tag' => $tag - )); - - add_log('ally_list', array( - 'tag' => $tag, - 'toolbar' => $toolbar_info - )); - } - break; - - case 'messages': //PAGE MESSAGES - if (!$xtense_user_data['grant']['messages']) { - $io->set(array( - 'type' => 'plugin grant', - 'access' => 'messages' - )); - $io->status(0); - } else { - $line = $data; - switch ($line['type']) { - case 'msg': //MESSAGE PERSO - if (!isset($line['coords'], $line['from'], $line['subject'], $line['message'])) { - throw new UnexpectedValueException("Personal Message: Incomplete Metadata "); - } - $line['coords'] = Check::coords($line['coords']); - $line['from'] = filter_var($line['from']); - $line['message'] = filter_var($line['message']); - $line['subject'] = filter_var($line['subject']); - - $msg = array( - 'coords' => explode(':', $line['coords']), - 'from' => $line['from'], - 'subject' => $line['subject'], - 'message' => $line['message'], - 'time' => $line['date'] - ); - $call->add('msg', $msg); - break; - - case 'ally_msg': //MESSAGE ALLIANCE - if (!isset($line['from'], $line['tag'], $line['message'])) { - throw new UnexpectedValueException("Alliance Message: Incomplete Metadata "); - } - - $line['from'] = filter_var($line['from']); - $line['tag'] = filter_var($line['tag']); - $line['message'] = filter_var($line['message']); - - $ally_msg = array( - 'from' => $line['from'], - 'tag' => $line['tag'], - 'message' => $line['message'], - 'time' => $line['date'] - ); - $call->add('ally_msg', $ally_msg); - break; - - case 'spy': //RAPPORT ESPIONNAGE - case 'spy_shared': - if (!isset( - $line['player']['name'], - $line['planet']['name'], - $line['planet']['coordinates'], - $line['planet']['id'], - $line['resources'], - $line['proba'], - $line['activity'], - $line['date'] - )) { - throw new UnexpectedValueException("Spy: Incomplete Metadata "); - } - - $coords = Check::coords($line['planet']['coordinates']); - // Construction de $content à partir des nouvelles sections du JSON - $content = array(); - if (isset($line['resources']) && is_array($line['resources'])) { - $content = $content + $line['resources']; - } - if (isset($line['buildings']) && is_array($line['buildings'])) { - $content = $content + $line['buildings']; - } - if (isset($line['lfBuildings']) && is_array($line['lfBuildings'])) { - $content = $content + $line['lfBuildings']; - } - if (isset($line['research']) && is_array($line['research'])) { - $content = $content + $line['research']; - } - if (isset($line['lfResearch']) && is_array($line['lfResearch'])) { - $content = $content + $line['lfResearch']; - } - if (isset($line['fleet']) && is_array($line['fleet'])) { - $content = $content + $line['fleet']; - } - if (isset($line['defense']) && is_array($line['defense'])) { - $content = $content + $line['defense']; - } - - $playerName = filter_var($line['player']['name']); - $planetName = filter_var($line['planet']['name']); - $moon = ($line['planet']['type'] === "3"); - $proba = filter_var($line['proba'], FILTER_SANITIZE_NUMBER_INT); - $activite = filter_var($line['activity'], FILTER_SANITIZE_NUMBER_INT); - $date = filter_var($line['date'], FILTER_SANITIZE_NUMBER_INT); - - $proba = $proba > 100 ? 100 : $proba; - $activite = $activite > 59 ? 59 : $activite; - $spy = array( - 'proba' => $proba, - 'activite' => $activite, - 'coords' => $coords, - 'content' => $content, - 'time' => $date, - 'player_name' => $playerName, - 'planet_name' => $planetName, - 'planet_id' => $line['planet']['id'] - ); - $call->add($line['type'], $spy); - - $spyDB = []; - foreach ($databaseSpyId as $arr) { - $spyDB = $spyDB + $arr; - } - - // Initialisation des tableaux pour les champs et les valeurs - $query_fields = []; - $query_values = []; - - // Champs de base et valeurs correspondantes avec backticks pour les noms de champs - $query_fields = [ - '`astro_object_id`', '`planet_name`', '`metal`', '`crystal`', '`deuterium`', - '`sender_id`', '`proba`', '`activite`', '`dateRE`' - ]; - $query_values = [ - (int)$spy['planet_id'], - "'" . $db->sql_escape_string($spy['planet_name']) . "'", - (isset($spy['content']['metal']) ? (int)$spy['content']['metal'] : 0), - (isset($spy['content']['crystal']) ? (int)$spy['content']['crystal'] : 0), - (isset($spy['content']['deuterium']) ? (int)$spy['content']['deuterium'] : 0), - (int)$xtense_user_data['id'], - (int)$spy['proba'], - (int)$spy['activite'], - (int)$spy['time'] - ]; - - // On traite le contenu additionnel du rapport d'espionnage - foreach ($spyDB as $code => $name) { - if ($name === 'metal' || $name === 'crystal' || $name === 'deuterium') { - continue; - } - if (isset($spy['content'][$code])) { - $field = $name; - $query_fields[] = '`' . $field . '`'; - $query_values[] = (int)$spy['content'][$code]; - } - } - - // Construction des chaînes finales pour la requête SQL - $fields_for_db = implode(', ', $query_fields); - $values_for_db = implode(', ', $query_values); - - $spy_time = $spy['time']; - $test = $db->sql_numrows($db->sql_query("SELECT `id` FROM " . TABLE_PARSEDSPY . " WHERE `astro_object_id` = '{$spy['planet_id']}' AND `dateRE` = '$spy_time'")); - if (!$test) { - $db->sql_query("INSERT INTO " . TABLE_PARSEDSPY . " ( " . $fields_for_db . ") VALUES (" . $values_for_db . ")"); - - // On cherche l'ID du joueur espionné - $spied_player_id = -1; - $spied_player_id_result = $db->sql_query("SELECT `id` FROM " . TABLE_GAME_PLAYER . " WHERE `name` = '" . $db->sql_escape_string($spy['player_name']) . "'"); - if ($db->sql_numrows($spied_player_id_result) > 0) { - $spied_player_id = (int)$db->sql_fetch_row($spied_player_id_result)[0]; - } - - list($g, $s, $r) = explode(':', $spy['coords']); - $planet_type = $moon ? 'moon' : 'planet'; - - // Préparation de la mise à jour de TABLE_USER_BUILDING - $update_pairs = []; - $insert_fields = ['id', 'galaxy', 'system', 'row', 'type', 'name', 'last_update', 'last_update_user_id']; - $insert_values = [ - (int)$spy['planet_id'], - (int)$g, - (int)$s, - (int)$r, - "'" . $planet_type . "'", - "'" . $db->sql_escape_string($spy['planet_name']) . "'", - (int)$spy['time'], - (int)$xtense_user_data['id'] - ]; - - $update_pairs[] = 'name = VALUES(name)'; - $update_pairs[] = 'last_update = VALUES(last_update)'; - $update_pairs[] = 'last_update_user_id = VALUES(last_update_user_id)'; - $update_pairs[] = 'type = VALUES(type)'; - $update_pairs[] = 'galaxy = VALUES(galaxy)'; - $update_pairs[] = 'system = VALUES(system)'; - $update_pairs[] = 'row = VALUES(row)'; - - if ($spied_player_id !== -1) { - $insert_fields[] = 'player_id'; - $insert_values[] = (int)$spied_player_id; - $update_pairs[] = 'player_id = VALUES(player_id)'; - } - - // Bâtiments - if (isset($line['buildings']) && is_array($line['buildings'])) { - foreach ($databaseSpyId['buildings'] as $code => $name) { - if (isset($line['buildings'][$code])) { - $insert_fields[] = $name; - $insert_values[] = (int)$line['buildings'][$code]; - $update_pairs[] = "`" . $name . "` = VALUES(`" . $name . "`)"; - } - } - } - - $query = "INSERT INTO " . TABLE_USER_BUILDING . " (`" . implode('`, `', $insert_fields) . "`) - VALUES (" . implode(', ', $insert_values) . ") - ON DUPLICATE KEY UPDATE " . implode(', ', $update_pairs); - $db->sql_query($query); - - // Défenses - if (isset($line['defense']) && is_array($line['defense'])) { - $defense_fields = []; - $defense_values = []; - $defense_update_pairs = []; - - foreach ($databaseSpyId['defense'] as $code => $name) { - if (isset($line['defense'][$code])) { - $level = (int)$line['defense'][$code]; - $defense_fields[] = "`$name`"; - $defense_values[] = $level; - $defense_update_pairs[] = "`$name` = $level"; - } - } - - if (!empty($defense_fields)) { - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER_DEFENSE . " (astro_object_id, " . implode(', ', $defense_fields) . ") - VALUES (" . (int)$spy['planet_id'] . ", " . implode(', ', $defense_values) . ") - ON DUPLICATE KEY UPDATE " . implode(", ", $defense_update_pairs)); - } - } - - // Flotte - if (isset($line['fleet']) && is_array($line['fleet'])) { - $fleet_fields = []; - $fleet_values = []; - $fleet_update_pairs = []; - - foreach ($databaseSpyId['fleet'] as $code => $name) { - if (isset($line['fleet'][$code])) { - $level = (int)$line['fleet'][$code]; - $fleet_fields[] = "`$name`"; - $fleet_values[] = $level; - $fleet_update_pairs[] = "`$name` = $level"; - } - } - - if (!empty($fleet_fields)) { - $db->sql_query("INSERT INTO " . TABLE_GAME_PLAYER_FLEET . " (astro_object_id, " . implode(', ', $fleet_fields) . ") - VALUES (" . (int)$spy['planet_id'] . ", " . implode(', ', $fleet_values) . ") - ON DUPLICATE KEY UPDATE " . implode(", ", $fleet_update_pairs)); - } - } - - // Recherches - if ($spied_player_id !== -1 && isset($line['research']) && is_array($line['research'])) { - $research_fields = []; - $research_values = []; - $research_update_parts = []; - - foreach ($databaseSpyId['labo'] as $code => $name) { - if (isset($line['research'][$code])) { - $level = (int)$line['research'][$code]; - $research_fields[] = "`$name`"; - $research_values[] = $level; - $research_update_parts[] = "`$name` = $level"; - } - } - - if (!empty($research_fields)) { - $db->sql_query("INSERT INTO " . TABLE_USER_TECHNOLOGY . " (`player_id`, " . implode(', ', $research_fields) . ") - VALUES (" . (int)$spied_player_id . ", " . implode(', ', $research_values) . ") - ON DUPLICATE KEY UPDATE " . implode(", ", $research_update_parts)); - } - } - - // Mise à jour des statistiques - $db->sql_query('UPDATE ' . TABLE_USER . ' SET `spy_imports` = spy_imports + 1 WHERE `id` = ' . $xtense_user_data['id']); - update_statistic('spyimports', '1'); - add_log('messages', array('added_spy' => $spy['planet_name'], 'added_spy_coords' => $spy['coords'], 'toolbar' => $toolbar_info)); - } - break; - - case 'ennemy_spy': //RAPPORT ESPIONNAGE ENNEMIS - if (!isset($line['from'], $line['to'], $line['proba'], $line['date'])) { - throw new UnexpectedValueException("Ennemy Spy: Incomplete Metadata "); - } - - $line['proba'] = filter_var($line['proba'], FILTER_SANITIZE_NUMBER_INT); - $line['from'] = Check::coords($line['from']); - $line['to'] = Check::coords($line['to']); - - $query = "SELECT spy_id FROM " . TABLE_PARSEDSPYEN . " WHERE sender_id = '" . $xtense_user_data['user_id'] . "' AND dateSpy = '{$line['date']}'"; - if ($db->sql_numrows($db->sql_query($query)) == 0) { - $db->sql_query("INSERT INTO " . TABLE_PARSEDSPYEN . " (`dateSpy`, `from`, `to`, `proba`, `sender_id`) VALUES ('" . $line['date'] . "', '" . $line['from'] . "', '" . $line['to'] . "', '" . $line['proba'] . "', '" . $xtense_user_data['user_id'] . "')"); - } - $ennemy_spy = array( - 'from' => explode(':', $line['from']), - 'to' => explode(':', $line['to']), - 'proba' => (int)$line['proba'], - 'time' => $line['date'] - ); - $call->add('ennemy_spy', $ennemy_spy); - add_log('info', array('toolbar' => $toolbar_info, 'message' => "a été espionné avec une probabilité de " . $line['proba'])); - break; - - case 'rc_cdr': //RAPPORT RECYCLAGE - if (!isset($line['nombre'], - $line['coords'], - $line['M_recovered'], - $line['C_recovered'], - $line['M_total'], - $line['C_total'], - $line['date'])) { - throw new UnexpectedValueException("Harvesting Report: Incomplete Metadata "); - } - - $line['nombre'] = filter_var($line['nombre'], FILTER_SANITIZE_NUMBER_INT); - $line['coords'] = Check::coords($line['coords']); - $line['M_recovered'] = filter_var($line['M_recovered'], FILTER_SANITIZE_NUMBER_INT); - $line['C_recovered'] = filter_var($line['C_recovered'], FILTER_SANITIZE_NUMBER_INT); - $line['M_total'] = filter_var($line['M_total'], FILTER_SANITIZE_NUMBER_INT); - $line['C_total'] = filter_var($line['C_total'], FILTER_SANITIZE_NUMBER_INT); - - $query = "SELECT `id_rec` FROM " . TABLE_PARSEDREC . " WHERE `sender_id` = '" . $xtense_user_data['user_id'] . "' AND `dateRec` = '{$line['date']}'"; - if ($db->sql_numrows($db->sql_query($query)) == 0) { - $db->sql_query("INSERT INTO " . TABLE_PARSEDREC . " (`dateRec`, `coordinates`, `nbRec`, `M_total`, `C_total`, `M_recovered`, `C_recovered`, `sender_id`) VALUES ('" . $line['date'] . "', '" . $line['coords'] . "', '" . $line['nombre'] . "', '" . $line['M_total'] . "', '" . $line['C_total'] . "', '" . $line['M_recovered'] . "', '" . $line['C_recovered'] . "', '" . $xtense_user_data['user_id'] . "')"); - } - $rc_cdr = array( - 'nombre' => (int)$line['nombre'], - 'coords' => explode(':', $line['coords']), - 'M_reco' => (int)$line['M_recovered'], - 'C_reco' => (int)$line['C_recovered'], - 'M_total' => (int)$line['M_total'], - 'C_total' => (int)$line['C_total'], - 'time' => $line['date'] - ); - $call->add('rc_cdr', $rc_cdr); - break; - - case 'expedition': //RAPPORT EXPEDITION - case 'expedition_shared': - if (!isset($line['coords'], $line['content'])) { - throw new UnexpectedValueException("Expedition Message: Incomplete Metadata "); - } - - $line['content'] = filter_var($line['content']); - $line['coords'] = Check::coords($line['coords'], 1); - - $expedition = array( - 'time' => $line['date'], - 'coords' => explode(':', $line['coords']), - 'content' => $line['content'] - ); - $call->add($line['type'], $expedition); - break; - - default: - throw new UnexpectedValueException("Message category not found " . $line['type']); - } - $io->set(array( - 'type' => (isset($pub_returnAs) && $pub_returnAs == 'spy' ? 'spy' : 'messages') - )); - } - break; - - default: - throw new UnexpectedValueException("Game Data category not found " . $received_game_data['type']); -} - -$call->apply(); - + $handlerClass = match ($receivedGameData['type']) { + 'overview' => 'OverviewHandler', + 'buildings' => 'BuildingsHandler', + 'resourceSettings' => 'ResourceSettingsHandler', + 'defense' => 'DefenseHandler', + 'researchs' => 'ResearchsHandler', + 'fleet' => 'FleetHandler', + 'system' => 'SystemHandler', + 'ranking' => 'RankingHandler', + 'rc', 'rc_shared' => 'CombatReportHandler', + 'ally_list' => 'AllyListHandler', + 'messages' => 'MessageHandler', + default => throw new UnexpectedValueException('Game Data category not found ' . $receivedGameData['type']), + }; + + $handlerData = $data; + if ($handlerClass === 'CombatReportHandler') { + $handlerData['_xtense_request_type'] = $receivedGameData['type']; + $handlerData['_xtense_raw_payload'] = $json; + } elseif ($handlerClass === 'MessageHandler') { + $handlerData['_xtense_raw_payload'] = $json; + $handlerData['_xtense_return_as'] = $pub_returnAs ?? null; + } + + $handler = new $handlerClass( + $db, + $log, + $io, + $call, + $server_config, + $xtense_user_data, + $database, + $toolbarInfo + ); + $handler->handle($handlerData); + $call->apply(); } catch (\Throwable $e) { - $log->error("Xtense error: " . $e->getMessage(), ['exception' => $e]); + $log->error('Xtense error: ' . $e->getMessage(), ['exception' => $e]); $io->set('error', $e->getMessage()); $io->status(0); } -$io->set('execution', str_replace(',', '.', round((microtime(true) - $start_time) * 1000, 2))); +$io->set('execution', str_replace(',', '.', round((microtime(true) - $startTime) * 1000, 2))); $io->send(); $db->sql_close(); - -exit(); +exit; \ No newline at end of file