Initial implementation of server-side bots that: - Spawn as real Player entities with full equipment - Move and broadcast position updates (10 tick/sec) - Take damage and die with backpack drops - Respawn after death - Combat system with accuracy model (adjustment vs recoil) Includes project documentation in bot-docs/ and Claude agent helpers. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
11 KiB
PlanetSide Bots - Handoff Document
Read this first if you're a new Claude instance or agent picking up this project.
What Is This Project?
We're adding bot players to PlanetSide 1 via the PSForever server emulator. The goal is to make the game world feel alive even with low real player population.
The Vision
- Hundreds of bots per server (scaling down as real players join)
- Bots that feel like real players, not mechanical turrets
- V-menu chatter, teamwork, attitude/personality systems
- Infantry first, vehicles later
Key Stakeholder
The user is a veteran PlanetSide player (decade+ experience) and serves as the expert on "game feel". They have detailed notes on how bots should behave. Always defer to them on gameplay questions.
Project Structure
PSF-LoginServer/
├── bot-docs/ ← Bot project documentation
│ ├── HANDOFF.md ← YOU ARE HERE - Start here
│ ├── PROJECT.md ← Overview, goals, status
│ ├── GAME_FEEL.md ← Behavioral spec (vision, movement, V-menu, classes, etc.)
│ ├── ARCHITECTURE.md ← Technical design decisions
│ ├── CODEBASE_MAP.md ← Key files with line numbers (CRITICAL REFERENCE)
│ ├── POC_PLAN.md ← Phased implementation milestones
│ ├── DEV_SETUP.md ← Development environment setup
│ └── SKETCHES/ ← Conceptual code (not production)
│ ├── BotActor_v1.scala
│ └── BotSpawner_v1.scala
├── src/main/scala/net/psforever/
│ └── actors/bot/ ← Bot implementation code
│ ├── BotManager.scala
│ └── BotAvatarActor.scala
└── ... ← Rest of PSForever server codebase
Read Order for New Instance
- HANDOFF.md (this file) - Context and decisions
- CODEBASE_MAP.md - Where things are in the code
- GAME_FEEL.md - How bots should behave
- SKETCHES/ - Conceptual code to understand approach
Key Technical Decisions Made
1. BotActor Approach (NOT SessionActor)
We decided to create a new BotActor rather than emulating SessionActor because:
- SessionActor's main job is handling network packets from clients
- Bots have no client, so no incoming packets
- BotActor can be optimized specifically for AI needs
- Less overhead, better scalability
2. Server-Side Native Bots
Bots are first-class server entities, not fake clients connecting from outside.
- Bots use existing
PlayerandPlayerControlcode - No network overhead
- Actions broadcast through same services as real players
3. Bot Identity
Bot characters use:
- High positive IDs (900000+) to avoid collision with real DB players
- No special characters in names - use
xxBOTxxNameformat (not[BOT]Name) - Predefined loadouts per class
4. Tick Rate
- 10-20 FPS for bot AI decisions (not 60)
- Can reduce further for bots far from real players
- Server load monitoring will inform final values
Bot Architecture Summary
BotManager (per zone)
├── Monitors real player population
├── Spawns/despawns bots to maintain target count
└── Manages one Ace per faction (last to logout)
BotActor (per bot)
├── 10 FPS tick loop
├── Vision cone detection (60-90 degrees)
├── Decision making (attack, retreat, objective, help)
├── Movement execution
├── State broadcasting
└── Controls a Player entity
BotAvatarActor (stub)
└── Minimal - just accepts messages PlayerControl sends
Player + PlayerControl (existing code)
├── Player entity with Vitality, inventory, etc.
└── PlayerControl handles damage/death (already exists)
Spawn Flow (Critical Path)
// 1. Create avatar (HIGH POSITIVE ID - 900000+)
val avatar = Avatar(900000 + botNum, BasicCharacterData(name, faction, sex, head, voice))
// 2. Create player entity
val player = new Player(avatar)
player.Position = spawnPosition
player.Spawn()
// 3. Create typed stub avatar actor (MUST be typed ActorRef)
val typedSystem = context.system.toTyped
val botAvatarActor: ActorRef[AvatarActor.Command] =
typedSystem.systemActorOf(BotAvatarActor(), s"bot-avatar-$botId")
// 4. Register GUIDs (ASYNC - use registerAvatar, NOT registerPlayer!)
TaskWorkflow.execute(GUIDTask.registerAvatar(zone.GUID, player)).onComplete {
case Success(_) =>
// 5. Join zone population
zone.Population ! Zone.Population.Join(avatar)
// 6. Spawn player (creates PlayerControl actor)
zone.Population ! Zone.Population.Spawn(avatar, player, botAvatarActor)
// 7. Broadcast to clients
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.LoadPlayer(...))
case Failure(ex) =>
log.error(s"Failed: ${ex.getMessage}")
}
Broadcasting (How Bots Appear to Real Players)
Bots broadcast their state via the same channels real players use:
// Position updates (10-20 times per second)
zone.AvatarEvents ! AvatarServiceMessage(
zone.id,
AvatarAction.PlayerState(guid, pos, vel, facing, crouch, jump, ...)
)
// Weapon fire
zone.AvatarEvents ! AvatarServiceMessage(
zone.id,
AvatarAction.ChangeFireState_Start(playerGuid, weaponGuid)
)
// V-menu voice commands
// (Need to investigate ChatMsg format)
Bot Classes (From User's Notes)
| Class | Role | Behavior |
|---|---|---|
| Driver | Vehicle operation | Low priority for gunning, wants to drive |
| Support | Heal & Repair | LOVES gunning (can heal vehicle), prioritizes healing |
| Hacker | Infiltration | Door unlocking, base capture |
| AV | Anti-Vehicle | Tank hunters |
| MAX | Heavy Exosuit | AI/AV/AA variants, switches based on intel |
| Vet | Versatile | Jack of all trades, ADAD movement, vengeance system |
| Ace | Empire Leader | ONE per empire, last to logout, uses Command Chat |
Implementation Status
COMPLETED (POC Working!)
- BotAvatarActor stub (typed actor, absorbs messages)
- BotManager (spawns bots, handles async GUID flow)
!botchat command for testing- Bot spawns visible to players
- Bot takes damage from players (PlayerControl works!)
- Bot movement (10 tick/sec, random wandering, PlayerState broadcasts)
- Multiple bots work independently
KNOWN ISSUES (Expected for POC)
- No backpack on death (likely because bot has no items/loadout)
- Walks through walls (no collision detection)
- No Z-height adjustment (melts into stairs, terrain)
- Walk speed slightly fast for animation (4 units/sec, try 3)
NOT YET IMPLEMENTED
- Bot loadout/equipment
- Bot shooting (weapon fire broadcasts)
- Bot death/respawn cycle
- Terrain following (Z height from map data)
- Collision avoidance
- Pathfinding
- V-menu voice command sending
- Celebration coordination system
- Vengeance/attitude system
- Population scaling (spawn/despawn based on real players)
Resolved Questions (Through Trial & Error)
- Avatar IDs: Must be POSITIVE. Negative IDs break packet encoding (32-bit unsigned). Use 900000+.
- PlayerControl + stub AvatarActor: WORKS! BotAvatarActor just absorbs messages, PlayerControl functions normally.
- GUID Registration: Must use
registerAvatar()notregisterPlayer()- locker needs GUID for PlayerControl init.
Open Questions for PSForever Devs
- Bot identification: Should we add
isBot: Booleanto Player? - Spawn point access: Best way to find valid faction spawn locations?
Spawn Location Logic (For Future Implementation)
When a player dies, they choose from up to 3 spawn options (all must be friendly-owned):
- Nearest Tower - Guard towers scattered across continents
- Nearest AMS - Advanced Mobile Station (deployable spawn vehicle)
- Nearest Base/Facility - The main base spawn tubes
Special Cases:
- Sanctuary (home2, home1, home3): Only one spawn option (the sanctuary itself)
- Warpgates: Can spawn at warpgates your faction owns
For Bots:
- Currently: Respawn at original spawn position (simple)
- Future: Query zone for valid faction spawn points, pick nearest or random
- Need to find:
SpawnPointinstances, check faction ownership, calculate distance
Code References to Investigate:
SpawnPoint.scala- Spawn point trait and calculationsZone.spawnGroups- Map of building -> spawn pointsBuilding.Faction- Check ownership for spawn eligibility
Important Behavioral Notes
From GAME_FEEL.md (Key Points)
- Vision: 60-90 degree FOV, distance-based spotting time
- Movement: Newbies run straight, Vets do ADAD + crouch spam
- Retreat: Vets retreat at low HP, Drivers save vehicles, everyone retreats when out of ammo
- V-menu: "Needs" always fire, celebrations are coordinated (1-6 responders, staggered timing)
- Vengeance: Vets remember who killed them, may seek revenge, taunt on success
- Panic: Non-combat bots (repairing) panic when shot, run to cover while swapping weapons
- Chaos: The goal is authentic battlefield chaos - spam bullets, grenades, voice commands
What NOT to Do
- No bunny hopping (almost no one jumps except MAX dodging AV)
- No laser accuracy (bots should miss)
- No instant reactions (bots need reaction time)
- No perfect coordination (spread out, don't stand on same pixel)
- No mechanical behavior (turrets are terrible, we want human-like chaos)
Development Environment
# Server codebase
cd PSF-LoginServer
sbt compile # Compile
sbt server/run # Run server
# Requirements
- Java 8 JDK
- sbt (Scala Build Tool)
- PostgreSQL 10+
- PlanetSide client (version 3.15.84.0)
Context for Future Agents
If you're a coding agent tasked with implementation:
- Read
CODEBASE_MAP.mdfor file locations - Read
SKETCHES/for conceptual starting points - Start with Milestone 1: spawn a static bot that appears in-game
- Test empirically - compile, run, connect with client, observe
If you're a research agent investigating something:
- The PSF-LoginServer codebase is in
./PSF-LoginServer/ - All server code is under
src/main/scala/net/psforever/ - Tests are under
src/test/scala/ - Use grep/glob to find patterns
If the user says "update the docs":
- Update the relevant .md files
- Keep
CODEBASE_MAP.mdcurrent with any new discoveries - Add line numbers when referencing code
Last Session Summary
Date: 2024 (context creation date)
Accomplished:
- Analyzed PSF-LoginServer codebase architecture
- Mapped spawn/broadcast/GUID flows
- Created behavioral spec from user's notes
- Sketched BotActor and BotSpawner concepts
- Documented key files with line numbers
Next Steps:
- Set up dev environment
- Start Phase 1: spawn a static bot
- OR wait for dev team answers on open questions