'HexaHost GameCloud', 'APIVersion' => '1.1', 'RequiresServer' => true, 'DefaultNonSSLPort' => '443', 'DefaultSSLPort' => '443', ]; } function hexagamecloud_ConfigOptions(): array { return [ 'plan_slug' => [ 'FriendlyName' => 'GameCloud Plan Slug', 'Type' => 'text', 'Size' => '32', 'Default' => 'free', 'Description' => 'Maps to a GameCloud plan slug', ], 'minecraft_version' => [ 'FriendlyName' => 'Minecraft Version', 'Type' => 'text', 'Size' => '16', 'Default' => '1.21.1', ], 'software_family' => [ 'FriendlyName' => 'Software Family', 'Type' => 'dropdown', 'Options' => 'VANILLA,PAPER,PURPUR,FABRIC,FORGE,NEOFORGE,QUILT', 'Default' => 'VANILLA', ], ]; } function hexagamecloud_CreateAccount(array $params): string { try { $client = new HexaGameCloudApiClient($params); $externalClientId = (string) $params['clientsdetails']['userid']; $externalServiceId = (string) $params['serviceid']; $client->upsertClient($externalClientId, [ 'email' => $params['clientsdetails']['email'], 'username' => $params['clientsdetails']['email'], 'displayName' => trim(($params['clientsdetails']['firstname'] ?? '') . ' ' . ($params['clientsdetails']['lastname'] ?? '')), ]); $response = $client->provisionService([ 'externalServiceId' => $externalServiceId, 'externalClientId' => $externalClientId, 'externalProductId' => (string) ($params['pid'] ?? ''), 'planSlug' => HexaGameCloudProductMapping::resolvePlanSlug($params), 'serverName' => $params['domain'] ?: ('server-' . $externalServiceId), 'minecraftVersion' => HexaGameCloudProductMapping::resolveMinecraftVersion($params), 'softwareFamily' => HexaGameCloudProductMapping::resolveSoftwareFamily($params), 'edition' => 'JAVA', 'eulaAccepted' => true, ]); return 'success'; } catch (Throwable $exception) { logModuleCall( 'hexagamecloud', __FUNCTION__, $params, $exception->getMessage(), $exception->getMessage(), ['password', 'secret', 'apiSecret'] ); return $exception->getMessage(); } } function hexagamecloud_SuspendAccount(array $params): string { return hexagamecloud_lifecycleAction($params, 'suspend', ['reason' => 'Suspended in WHMCS']); } function hexagamecloud_UnsuspendAccount(array $params): string { return hexagamecloud_lifecycleAction($params, 'unsuspend'); } function hexagamecloud_TerminateAccount(array $params): string { return hexagamecloud_lifecycleAction($params, 'terminate'); } function hexagamecloud_Renew(array $params): string { try { $client = new HexaGameCloudApiClient($params); $serviceId = (string) $params['serviceid']; $payload = array_filter([ 'invoiceId' => hexagamecloud_resolveRenewInvoiceId($params), 'periodEnd' => hexagamecloud_formatIso8601($params['nextduedate'] ?? null), ], static fn ($value) => $value !== null && $value !== ''); $client->renewService( $serviceId, $payload, HexaGameCloudIdempotency::renewKey($serviceId, $params) ); return 'success'; } catch (Throwable $exception) { logModuleCall( 'hexagamecloud', __FUNCTION__, $params, $exception->getMessage(), $exception->getMessage(), ['password', 'secret', 'apiSecret'] ); return $exception->getMessage(); } } function hexagamecloud_ChangePackage(array $params): string { try { $client = new HexaGameCloudApiClient($params); $client->changePackage((string) $params['serviceid'], [ 'planSlug' => HexaGameCloudProductMapping::resolvePlanSlug($params), ]); return 'success'; } catch (Throwable $exception) { logModuleCall('hexagamecloud', __FUNCTION__, $params, $exception->getMessage()); return $exception->getMessage(); } } function hexagamecloud_ServiceSingleSignOn(array $params) { return hexagamecloud_requestSso($params, 'service'); } function hexagamecloud_AdminSingleSignOn(array $params) { return hexagamecloud_requestSso($params, 'admin'); } function hexagamecloud_ClientArea(array $params): array { hexagamecloud_loadLanguage($params); $serviceId = (string) $params['serviceid']; $snapshot = hexagamecloud_fetchServiceSnapshot($params); $server = $snapshot['service']['server'] ?? []; $linkStatus = (string) ($snapshot['service']['status'] ?? 'PENDING'); return [ 'templatefile' => 'templates/clientarea', 'vars' => [ 'LANG' => hexagamecloud_langVars(), 'apiWarning' => $snapshot['warning'], 'notProvisioned' => $linkStatus === 'PENDING' && ($server['id'] ?? '') === '', 'serverName' => (string) ($server['name'] ?? ($params['domain'] ?? '')), 'technicalStatus' => (string) ($server['status'] ?? 'UNKNOWN'), 'joinAddress' => (string) ($server['joinHostname'] ?? '-'), 'edition' => (string) ($server['edition'] ?? 'JAVA'), 'softwareFamily' => (string) ($server['softwareFamily'] ?? HexaGameCloudProductMapping::resolveSoftwareFamily($params)), 'minecraftVersion' => (string) ($server['minecraftVersion'] ?? HexaGameCloudProductMapping::resolveMinecraftVersion($params)), 'planSlug' => HexaGameCloudProductMapping::resolvePlanSlug($params), 'ramMb' => (int) ($server['ramMb'] ?? 0), 'nextDueDate' => (string) ($params['nextduedate'] ?? '-'), 'billingStatus' => $linkStatus === 'SUSPENDED' ? hexagamecloud_lang('hexagamecloud_suspended_yes') : hexagamecloud_lang('hexagamecloud_suspended_no'), 'lastSync' => $snapshot['syncedAt'], ], ]; } function hexagamecloud_ClientAreaCustomButtonArray(): array { return [ hexagamecloud_lang('hexagamecloud_manage_panel') => 'ManagePanel', hexagamecloud_lang('hexagamecloud_action_start') => 'StartServer', hexagamecloud_lang('hexagamecloud_action_stop') => 'StopServer', hexagamecloud_lang('hexagamecloud_action_restart') => 'RestartServer', hexagamecloud_lang('hexagamecloud_action_backup') => 'BackupServer', ]; } function hexagamecloud_StartServer(array $params): string { return hexagamecloud_serviceAction($params, 'start'); } function hexagamecloud_StopServer(array $params): string { return hexagamecloud_serviceAction($params, 'stop'); } function hexagamecloud_RestartServer(array $params): string { return hexagamecloud_serviceAction($params, 'restart'); } function hexagamecloud_BackupServer(array $params): string { return hexagamecloud_serviceAction($params, 'backup'); } function hexagamecloud_serviceAction(array $params, string $action): string { try { $client = new HexaGameCloudApiClient($params); $serviceId = (string) $params['serviceid']; if ($action === 'start') { $client->startService($serviceId); } elseif ($action === 'stop') { $client->stopService($serviceId); } elseif ($action === 'restart') { $client->restartService($serviceId); } else { $client->backupService($serviceId); } return 'success'; } catch (Throwable $exception) { logModuleCall('hexagamecloud', $action, $params, $exception->getMessage()); return $exception->getMessage(); } } function hexagamecloud_ManagePanel(array $params): array { return hexagamecloud_requestSso($params, 'service'); } function hexagamecloud_AdminServicesTabFields(array $params): array { hexagamecloud_loadLanguage($params); $serviceId = (string) $params['serviceid']; $snapshot = hexagamecloud_fetchServiceSnapshot($params); $service = $snapshot['service']; $server = $service['server'] ?? []; $metadata = HexaGameCloudServiceMetadata::load($serviceId); $warning = $snapshot['warning'] !== null ? '
' . htmlspecialchars($snapshot['warning'], ENT_QUOTES, 'UTF-8') . '
' : ''; return [ hexagamecloud_lang('hexagamecloud_admin_server_id') => $warning . htmlspecialchars((string) ($server['id'] ?? '-'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_user_id') => htmlspecialchars((string) ($server['userId'] ?? '-'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_link_status') => htmlspecialchars((string) ($service['status'] ?? 'PENDING'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_technical_status') => htmlspecialchars((string) ($server['status'] ?? 'UNKNOWN'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_node') => htmlspecialchars((string) ($server['nodeId'] ?? '-'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_host_port') => htmlspecialchars((string) ($server['hostPort'] ?? '-'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_plan') => htmlspecialchars(HexaGameCloudProductMapping::resolvePlanSlug($params), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_ram') => htmlspecialchars((string) ((int) ($server['ramMb'] ?? 0)) . ' MiB', ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_last_sync') => htmlspecialchars((string) ($snapshot['syncedAt'] ?? '-'), ENT_QUOTES, 'UTF-8'), hexagamecloud_lang('hexagamecloud_admin_correlation_note') => '', ]; } function hexagamecloud_AdminServicesTabFieldsSave(array $params): void { $serviceId = (string) $params['serviceid']; $note = trim((string) ($params['hexagamecloud_correlation_note'] ?? '')); $existing = HexaGameCloudServiceMetadata::load($serviceId); HexaGameCloudServiceMetadata::save($serviceId, array_merge($existing, [ 'correlation_note' => $note, 'updated_at' => gmdate('c'), 'updated_by_admin_id' => (string) ($params['adminid'] ?? ''), ])); } function hexagamecloud_TestConnection(array $params): array { try { $client = new HexaGameCloudApiClient($params); $health = $client->health(); return [ 'success' => true, 'error' => 'Connected to ' . ($health['integrationId'] ?? 'GameCloud'), ]; } catch (Throwable $exception) { return ['success' => false, 'error' => $exception->getMessage()]; } } function hexagamecloud_ListAccounts(array $params): array { try { $client = new HexaGameCloudApiClient($params); $response = $client->listAccounts(); $accounts = []; foreach ($response['accounts'] ?? [] as $account) { $accounts[] = [ 'uuid' => $account['externalServiceId'] ?? '', 'domain' => $account['domain'] ?? '', 'username' => $account['username'] ?? '', 'status' => $account['status'] ?? 'Active', ]; } return $accounts; } catch (Throwable $exception) { logModuleCall('hexagamecloud', __FUNCTION__, $params, $exception->getMessage()); return []; } } function hexagamecloud_MetricProvider(array $params) { try { $client = new HexaGameCloudApiClient($params); $serviceId = (string) $params['serviceid']; $usage = $client->getServiceUsage($serviceId, hexagamecloud_resolveUsageQuery($params)); return [ 'metrics' => $usage['metrics'] ?? [], ]; } catch (Throwable $exception) { logModuleCall('hexagamecloud', __FUNCTION__, $params, $exception->getMessage()); return ['metrics' => []]; } } function hexagamecloud_UsageUpdate(array $params) { try { $client = new HexaGameCloudApiClient($params); $serviceId = (string) $params['serviceid']; $usage = $client->getServiceUsage($serviceId, hexagamecloud_resolveUsageQuery($params)); $usageUpdate = $usage['usageUpdate'] ?? []; return [ 'diskusage' => (float) ($usageUpdate['diskUsageGiB'] ?? 0), 'bandwidth' => (float) ($usageUpdate['bandwidthGiB'] ?? 0), ]; } catch (Throwable $exception) { logModuleCall('hexagamecloud', __FUNCTION__, $params, $exception->getMessage()); return [ 'diskusage' => 0, 'bandwidth' => 0, ]; } } function hexagamecloud_resolveUsageQuery(array $params): array { $query = []; if (!empty($params['usageperiodstart'])) { $query['periodStart'] = gmdate('c', strtotime((string) $params['usageperiodstart'])); } if (!empty($params['usageperiodend'])) { $query['periodEnd'] = gmdate('c', strtotime((string) $params['usageperiodend'])); } if (!empty($params['testmode']) || !empty($params['configoption4'])) { $query['testMode'] = true; } return $query; } function hexagamecloud_lifecycleAction(array $params, string $action, array $body = []): string { try { $client = new HexaGameCloudApiClient($params); $serviceId = (string) $params['serviceid']; if ($action === 'suspend') { $client->suspendService($serviceId, $body); } elseif ($action === 'unsuspend') { $client->unsuspendService($serviceId); } else { $client->terminateService($serviceId); } return 'success'; } catch (Throwable $exception) { logModuleCall('hexagamecloud', $action, $params, $exception->getMessage()); return $exception->getMessage(); } } function hexagamecloud_fetchServiceSnapshot(array $params): array { $serviceId = (string) $params['serviceid']; $cached = HexaGameCloudServiceMetadata::load($serviceId); $snapshot = [ 'service' => $cached['service'] ?? [ 'externalServiceId' => $serviceId, 'status' => 'PENDING', 'server' => [], ], 'warning' => null, 'syncedAt' => $cached['synced_at'] ?? null, ]; try { $client = new HexaGameCloudApiClient($params); $service = $client->getService($serviceId); $snapshot['service'] = $service; $snapshot['syncedAt'] = gmdate('c'); HexaGameCloudServiceMetadata::save($serviceId, [ 'service' => $service, 'synced_at' => $snapshot['syncedAt'], 'correlation_note' => $cached['correlation_note'] ?? '', 'updated_by_admin_id' => $cached['updated_by_admin_id'] ?? '', ]); } catch (Throwable $exception) { logModuleCall('hexagamecloud', 'fetchServiceSnapshot', $params, $exception->getMessage()); $snapshot['warning'] = hexagamecloud_lang('hexagamecloud_api_unavailable'); } return $snapshot; } function hexagamecloud_resolveRenewInvoiceId(array $params): ?string { $invoiceId = (string) ($params['invoiceid'] ?? ''); if ($invoiceId !== '') { return $invoiceId; } if (!empty($params['model']['invoiceid'])) { return (string) $params['model']['invoiceid']; } return null; } function hexagamecloud_formatIso8601(?string $value): ?string { if ($value === null || trim($value) === '') { return null; } $timestamp = strtotime($value); if ($timestamp === false) { return null; } return gmdate('c', $timestamp); } function hexagamecloud_loadLanguage(array $params): void { static $loaded = false; if ($loaded) { return; } $language = strtolower((string) ($params['clientsdetails']['language'] ?? $params['language'] ?? 'english')); if (!in_array($language, ['english', 'german'], true)) { $language = 'english'; } $langFile = __DIR__ . '/lang/' . $language . '.php'; if (!is_readable($langFile)) { $langFile = __DIR__ . '/lang/english.php'; } require $langFile; $loaded = true; } function hexagamecloud_lang(string $key): string { global $_LANG; return (string) ($_LANG[$key] ?? $key); } function hexagamecloud_langVars(): array { global $_LANG; return is_array($_LANG ?? null) ? $_LANG : []; } function hexagamecloud_requestSso(array $params, string $kind) { try { $client = new HexaGameCloudApiClient($params); $externalServiceId = (string) $params['serviceid']; $externalClientId = (string) ($params['clientsdetails']['userid'] ?? $params['userid'] ?? ''); $externalUserId = (string) ($params['clientsdetails']['userid'] ?? $params['adminid'] ?? $externalClientId); $response = $client->createServiceSso($externalServiceId, [ 'externalClientId' => $externalClientId, 'externalUserId' => $externalUserId, 'role' => $kind === 'admin' ? 'admin' : 'owner', 'kind' => $kind, ]); return [ 'success' => true, 'redirectTo' => $response['redirectUrl'], ]; } catch (Throwable $exception) { logModuleCall('hexagamecloud', 'sso:' . $kind, $params, $exception->getMessage()); return [ 'success' => false, 'error' => $exception->getMessage(), ]; } }