Player Counter: Added Palworld Support#125
Player Counter: Added Palworld Support#125makepeacej wants to merge 3 commits intopelican-dev:mainfrom
Conversation
…ings for admin password.
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 42 minutes and 18 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR introduces support for Palworld servers by adding a new REST-based query schema that authenticates with the server's admin password and retrieves player and server metrics from the Palworld API. It extends the query architecture with a Changes
Sequence DiagramsequenceDiagram
participant Client as Client
participant GameQuery as GameQuery
participant Schema as PalworldQueryTypeSchema
participant API as Palworld API
participant DB as Server Model
Client->>GameQuery: runQuery(Server)
GameQuery->>Schema: Determine schema type
alt ServerAwareQueryTypeSchemaInterface
GameQuery->>DB: Retrieve server config
GameQuery->>Schema: processWithServer(Server, IP, Port)
Schema->>DB: Extract ADMIN_PASSWORD
Schema->>API: GET /v1/api/players (with auth)
API-->>Schema: Players data
Schema->>API: GET /v1/api/metrics (with auth)
API-->>Schema: Server metrics
Schema->>Schema: Transform & normalize response
Schema-->>GameQuery: Normalized snapshot
else Standard QueryTypeSchemaInterface
GameQuery->>Schema: process(IP, Port)
Schema-->>GameQuery: Result
end
GameQuery-->>Client: Query result
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php (1)
60-62: Hardcoded map name and player cap fallback.
'Palpagos Islands'is Palworld's vanilla world name and32is the default server cap; both can differ for modded/custom servers. If a suitable field is returned by/v1/api/metrics(or another endpoint), prefer dynamic values; otherwise, consider translating the map label or making it configurable. Non-blocking.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php` around lines 60 - 62, The code currently hardcodes the map name and fallback max player cap ('Palpagos Islands' and 32) in the array built in PalworldQueryTypeSchema; replace those literals with dynamic values by checking $metrics (e.g. use $metrics['map'] or $metrics['world_name'] if present) and prefer a configurable fallback from a config/service (or translate/label the map name) and use $metrics['maxplayers'] ?? config('palworld.default_max_players') instead of the literal 32; update the array keys 'map' and 'max_players' to pull from these sources while leaving 'current_players' => count($players) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php`:
- Around line 47-64: The array and return key/value pairs use vertical alignment
around the => operator; update the mappings in the array_map callback (the
$players mapping using 'id' => and 'name' =>) and the returned associative array
keys ('hostname' =>, 'map' =>, 'current_players' =>, 'max_players' =>, 'players'
=>) to remove extra spaces so each => has a single space on both sides (collapse
multiple spaces to one) to conform with Pint's default preset.
- Around line 53-64: The code reads wrong metric keys and skips status checks:
before calling ->json() on the metrics response, check ->ok() (like the players
call) and handle non-OK responses; then read the actual API fields from the
decoded $metrics array—use 'currentplayernum' for current players and
'maxplayernum' for max players (fall back to count($players) and 32 respectively
if absent), and do not attempt to read a non-existent 'servername' (use
$server->name as the hostname fallback). Locate the metrics HTTP call and the
return array in PalworldQueryTypeSchema (the $metrics variable and the returned
'hostname','current_players','max_players' entries) and apply these changes.
---
Nitpick comments:
In `@player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php`:
- Around line 60-62: The code currently hardcodes the map name and fallback max
player cap ('Palpagos Islands' and 32) in the array built in
PalworldQueryTypeSchema; replace those literals with dynamic values by checking
$metrics (e.g. use $metrics['map'] or $metrics['world_name'] if present) and
prefer a configurable fallback from a config/service (or translate/label the map
name) and use $metrics['maxplayers'] ?? config('palworld.default_max_players')
instead of the literal 32; update the array keys 'map' and 'max_players' to pull
from these sources while leaving 'current_players' => count($players) unchanged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 85bff950-3d20-413b-84be-549eb638dbad
📒 Files selected for processing (4)
player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.phpplayer-counter/src/Extensions/Query/ServerAwareQueryTypeSchemaInterface.phpplayer-counter/src/Models/GameQuery.phpplayer-counter/src/Providers/PlayerCounterPluginProvider.php
📜 Review details
🧰 Additional context used
🪛 GitHub Actions: Lint
player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php
[error] 1-1: Laravel Pint style check failed: 1 style issue found in 210 files. Failed at PalworldQueryTypeSchema.php.
🪛 PHPMD (2.15.0)
player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php
[warning] 22-22: Avoid unused parameters such as '$ip'. (undefined)
(UnusedFormalParameter)
[warning] 22-22: Avoid unused parameters such as '$port'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (4)
player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php (1)
22-25: Intentional null-return fallback — PHPMD warnings are false positives.The PHPMD
UnusedFormalParameterwarnings on$ip/$portcan be safely ignored here: the method signature is fixed byQueryTypeSchemaInterface::process(), and returningnullfrom the non-server-aware path is the documented fallback for when auth context is unavailable.player-counter/src/Extensions/Query/ServerAwareQueryTypeSchemaInterface.php (1)
1-11: LGTM!Clean interface design. Extending
QueryTypeSchemaInterfacepreserves backward compatibility (implementors must still provideprocess()), and the return-type contract onprocessWithServer()matches the parent'sprocess()signature so both code paths inGameQuery::runQuery()yield the same shape.player-counter/src/Providers/PlayerCounterPluginProvider.php (1)
14-14: LGTM!Registration follows the same pattern as the other default schemas;
QueryTypeService::register()accepts anyQueryTypeSchemaInterface, soServerAwareQueryTypeSchemaInterfaceimplementors are fine here.Also applies to: 39-39
player-counter/src/Models/GameQuery.php (1)
63-68: LGTM — branching preserves null-safety.Since
QueryTypeService::get()can returnnull, theinstanceofcheck cleanly falls through to the existing$schema?->process($ip, $port)null-safe call. Behavior for all previously registered (non-server-aware) schemas is unchanged.
| $metrics = Http::timeout(5) | ||
| ->withBasicAuth('admin', $adminPassword) | ||
| ->get("http://{$ip}:{$port}/v1/api/metrics") | ||
| ->json(); | ||
|
|
||
| return [ | ||
| 'hostname' => $metrics['servername'] ?? $server->name, | ||
| 'map' => 'Palpagos Islands', | ||
| 'current_players' => count($players), | ||
| 'max_players' => $metrics['maxplayers'] ?? 32, | ||
| 'players' => $players, | ||
| ]; |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
Palworld dedicated server REST API endpoints /v1/api/players /v1/api/metrics response fields
💡 Result:
Palworld dedicated server provides a REST API at base URL http://localhost:8212/v1/api (configurable port). Enable with RESTAPIEnabled=True in PalWorldSettings.ini and uses HTTP Basic Auth (username: admin, password: AdminPassword). /v1/api/players (GET): Returns list of online players. Response schema (array of objects): - name: string (player name) - accountName: string (platform account name) - playerId: string - userId: string - ip: string (IP address) - ping: number - location_x: number - location_y: number - level: integer (game level) - building_count: integer (buildings owned) Confirmed in official docs (result 9) and hosting guide (result 10). /v1/api/metrics (GET): Returns server performance metrics. Response schema: - serverfps: integer (server FPS) - currentplayernum: integer (current players) - serverframetime: number (frame time ms) - maxplayernum: integer (max players) - uptime: integer (uptime seconds) - basecampnum: integer (base camps) - days: integer (in-game days) Confirmed in official docs (result 11) and multiple references (results 4,10,14). API not for public internet exposure; use LAN or proxy. Other endpoints include /info, /settings, /kick, /ban, etc.
Citations:
- 1: https://docs.palworldgame.com/api/rest-api/players/
- 2: https://xgamingserver.com/docs/palworld/rest-api
- 3: https://docs.palworldgame.com/api/rest-api/metrics/
- 4: https://docs.palworldgame.com/category/rest-api/
- 5: https://docs.palworldgame.com/api/rest-api/settings/
Fix incorrect Palworld metrics API field names—the code will silently fail.
The metrics response contains two critical issues:
-
Field names are incorrect and don't exist in the actual API response:
- Code accesses
$metrics['servername']—the/v1/api/metricsendpoint does not return aservernamefield - Code accesses
$metrics['maxplayers']—the field is actuallymaxplayernumin the API response - Full actual response schema:
serverfps,currentplayernum,serverframetime,maxplayernum,uptime,basecampnum,days - This causes the code to always fall back to defaults (
$server->nameand32), never retrieving actual server metrics
- Code accesses
-
Missing
.ok()check (like the players call at line 42): If the endpoint returns 4xx/5xx,->json()may decode an error body and yield unexpected values. Add a response status check before decoding.
Suggested fix
- $metrics = Http::timeout(5)
- ->withBasicAuth('admin', $adminPassword)
- ->get("http://{$ip}:{$port}/v1/api/metrics")
- ->json();
-
+ $metricsResponse = Http::timeout(5)
+ ->withBasicAuth('admin', $adminPassword)
+ ->get("http://{$ip}:{$port}/v1/api/metrics");
+ $metrics = $metricsResponse->ok() ? (array) $metricsResponse->json() : [];
+
return [
- 'hostname' => $metrics['servername'] ?? $server->name,
+ 'hostname' => $server->name,
'map' => 'Palpagos Islands',
'current_players' => count($players),
- 'max_players' => $metrics['maxplayers'] ?? 32,
+ 'max_players' => $metrics['maxplayernum'] ?? 32,
'players' => $players,
];Note: The API does not provide a servername field, only server performance metrics.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@player-counter/src/Extensions/Query/Schemas/PalworldQueryTypeSchema.php`
around lines 53 - 64, The code reads wrong metric keys and skips status checks:
before calling ->json() on the metrics response, check ->ok() (like the players
call) and handle non-OK responses; then read the actual API fields from the
decoded $metrics array—use 'currentplayernum' for current players and
'maxplayernum' for max players (fall back to count($players) and 32 respectively
if absent), and do not attempt to read a non-existent 'servername' (use
$server->name as the hostname fallback). Locate the metrics HTTP call and the
return array in PalworldQueryTypeSchema (the $metrics variable and the returned
'hostname','current_players','max_players' entries) and apply these changes.
- hostname now uses $server->name directly (metrics has no servername field) - max_players now reads maxplayernum from metrics (not maxplayers) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This pull request introduces support for Palworld dedicated servers in the Player Counter plugin. Palworld does not
implement the Steam A2S query protocol despite binding the query port, so this adds a new interface and schema to
support REST API-based querying with server credential context.
*Assisted by Claude to match existing patterns
Relates to #124
Summary by CodeRabbit