Skip to content

Copyover (Hot-reload) for GoMud #405

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<ansi fg="yellow-bold">
================================================================================
SERVER COPYOVER SCHEDULED
================================================================================</ansi>

<ansi fg="cyan">A server hot reload has been scheduled to apply updates.</ansi>

{{if .Minutes}}<ansi fg="yellow">Time until copyover: {{.Minutes}} minute{{if ne .Minutes 1}}s{{end}}</ansi>{{end}}
{{if .Seconds}}<ansi fg="yellow">Time until copyover: {{.Seconds}} second{{if ne .Seconds 1}}s{{end}}</ansi>{{end}}

<ansi fg="white">The game will continue normally until the copyover begins.
You will NOT be disconnected during this process.</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="green-bold">=== BUILD COMPLETE - PREPARING FOR RESTART ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<ansi fg="red-bold">=== BUILD FAILED - COPYOVER CANCELLED ===</ansi>

<ansi fg="white">The build process encountered an error. The copyover has been cancelled.
The game will continue running on the current version.</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="cyan-bold">=== BUILDING NEW SERVER EXECUTABLE... ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>
<ansi fg="red-bold"> COPYOVER CANCELLED</ansi>
<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>

The scheduled copyover has been <ansi fg="yellow">cancelled</ansi>.

{{if .Reason}}Reason: <ansi fg="cyan">{{.Reason}}</ansi>{{end}}

Normal operations will continue uninterrupted.

<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="yellow-bold">=== COPYOVER IN {{.Seconds}} SECONDS ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<ansi fg="green-bold">
================================================================================
COPYOVER COMPLETE - BUILD {{.BuildNumber}}
================================================================================</ansi>

<ansi fg="cyan">Welcome back! The server has been successfully reloaded.</ansi>

<ansi fg="green">✓ All systems operational
✓ Your session has been restored
✓ You may continue playing</ansi>

{{if .Duration}}<ansi fg="white">Copyover completed in {{.Duration}}</ansi>{{end}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<ansi fg="yellow-bold">
================================================================================
SERVER COPYOVER IMMINENT
================================================================================</ansi>

<ansi fg="cyan">The server is about to perform a hot reload. You will remain connected
during this process. The game will pause briefly while the new code loads.</ansi>

<ansi fg="green">✓ Your character data is being saved
✓ Your connection will be preserved
✓ You will be returned to your current location</ansi>

<ansi fg="yellow">Please wait...</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="yellow-bold">=== RESTARTING SERVER ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="cyan">=== Saving player data... ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<ansi fg="yellow-bold">
================================================================================
SERVER COPYOVER SCHEDULED
================================================================================</ansi>

<ansi fg="cyan">A server hot reload has been scheduled to apply updates.</ansi>

{{if .Minutes}}<ansi fg="yellow">Time until copyover: {{.Minutes}} minute{{if ne .Minutes 1}}s{{end}}</ansi>{{end}}
{{if .Seconds}}<ansi fg="yellow">Time until copyover: {{.Seconds}} second{{if ne .Seconds 1}}s{{end}}</ansi>{{end}}

<ansi fg="white">The game will continue normally until the copyover begins.
You will NOT be disconnected during this process.</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="green-bold">=== BUILD COMPLETE - PREPARING FOR RESTART ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<ansi fg="red-bold">=== BUILD FAILED - COPYOVER CANCELLED ===</ansi>

<ansi fg="white">The build process encountered an error. The copyover has been cancelled.
The game will continue running on the current version.</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="cyan-bold">=== BUILDING NEW SERVER EXECUTABLE... ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>
<ansi fg="red-bold"> COPYOVER CANCELLED</ansi>
<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>

The scheduled copyover has been <ansi fg="yellow">cancelled</ansi>.

{{if .Reason}}Reason: <ansi fg="cyan">{{.Reason}}</ansi>{{end}}

Normal operations will continue uninterrupted.

<ansi fg="red-bold">═══════════════════════════════════════════════════</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="yellow-bold">=== COPYOVER IN {{.Seconds}} SECONDS ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<ansi fg="green-bold">
================================================================================
COPYOVER COMPLETE - BUILD {{.BuildNumber}}
================================================================================</ansi>

<ansi fg="cyan">Welcome back! The server has been successfully reloaded.</ansi>

<ansi fg="green">✓ All systems operational
✓ Your session has been restored
✓ You may continue playing</ansi>

{{if .Duration}}<ansi fg="white">Copyover completed in {{.Duration}}</ansi>{{end}}
13 changes: 13 additions & 0 deletions _datafiles/world/empty/templates/copyover/copyover-pre.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<ansi fg="yellow-bold">
================================================================================
SERVER COPYOVER IMMINENT
================================================================================</ansi>

<ansi fg="cyan">The server is about to perform a hot reload. You will remain connected
during this process. The game will pause briefly while the new code loads.</ansi>

<ansi fg="green">✓ Your character data is being saved
✓ Your connection will be preserved
✓ You will be returned to your current location</ansi>

<ansi fg="yellow">Please wait...</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="yellow-bold">=== RESTARTING SERVER ===</ansi>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<ansi fg="cyan">=== Saving player data... ===</ansi>
148 changes: 148 additions & 0 deletions internal/combat/COPYOVER_COMBAT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Combat System Copyover Integration

This document describes how the combat system handles copyover (hot-reload) operations in GoMud.

## Overview

The combat system preserves all active combat states during copyover, allowing battles to continue seamlessly after the server restarts. This includes player vs mob, player vs player, and multi-target combat scenarios.

## Architecture

### State Preservation

The combat copyover system preserves the following state:

1. **Player Combat State** (`PlayerCombatState`)
- User ID and Room ID
- Active Aggro pointer (target and combat type)
- Damage tracking map (who dealt how much damage)
- Last damage timestamp

2. **Mob Combat State** (`MobCombatState`)
- Mob ID and Instance ID
- Room ID for mob location
- Active Aggro pointer
- Player damage tracking
- Charmed relationships

3. **Global State**
- Mob instance counter (ensures consistent IDs)

### File Structure

- `internal/combat/copyover.go` - Core combat state preservation
- `internal/copyover/integrations.go` - Centralized integration with copyover system
- `internal/copyover/manager.go` - Copyover state machine and coordination

## Implementation Details

### State Gathering

When copyover begins, the system:

1. The copyover manager calls the Combat system's Gather function
2. Iterates through all online players and active mobs
3. Captures combat-related state for entities in combat
4. Returns state for central copyover system to save

```go
func GatherCombatState() (*CombatCopyoverState, error) {
// Collect player combat states
// Collect mob combat states
// Save mob instance counter
}
```

### State Restoration

After copyover completes:

1. The copyover manager calls the Combat system's Restore function
2. Receives deserialized state from central system
3. Restores mob instance counter first
4. Re-establishes player combat states
5. Re-establishes mob combat states
6. Validates all aggro targets still exist

```go
func RestoreCombatState(state *CombatCopyoverState) error {
// Restore instance counter
// Restore player aggro
// Restore mob aggro
// Validate targets
}
```

## Combat Behavior During Copyover

### What Continues
- Active combat relationships (aggro)
- Damage tracking for attribution
- Mob instance IDs remain consistent
- Charmed mob relationships

### What Resets
- In-flight attack animations (resume next round)
- Spell casting with rounds waiting (cancelled)
- Combat messages in transit

### Round Processing
Combat rounds are atomic operations. Copyover occurs between rounds, so:
- No partial damage calculations
- No interrupted attack sequences
- Combat resumes at the next full round

## Integration Points

### Copyover System
The combat system is registered with the central copyover manager through:
```go
{
Name: "Combat",
Gather: func() (interface{}, error) {
return combat.GatherCombatState()
},
Restore: func(data interface{}) error {
if state, ok := data.(*combat.CombatCopyoverState); ok {
return combat.RestoreCombatState(state)
}
return fmt.Errorf("invalid combat state type")
},
}
```

### Dependencies
- `mobs.GetInstanceCounter()` / `SetInstanceCounter()`
- Character aggro pointers
- Room mob lists

## Error Handling

The system is resilient to:
- Missing aggro targets (clears invalid aggro)
- Changed room layouts (mobs stay in original rooms)
- Offline players (their combat state is preserved)

State save/load errors are logged but don't block copyover.

## Testing

See `combat_copyover_test.go` for unit tests covering:
- State serialization/deserialization
- Instance counter preservation
- Combat state validation

See `_datafiles/world/default/combat_copyover_test.md` for manual testing procedures.

## Limitations

1. **Spell Casting**: Spells with `RoundsWaiting > 0` are cancelled
2. **Ranged Combat**: Cross-room combat requires exit validation
3. **Temporary Effects**: Non-persistent buffs may need re-application

## Future Enhancements

1. Preserve spell casting state with round counters
2. Add combat pause flags for smoother transitions
3. Implement combat state compression for large battles
4. Add metrics for combat copyover performance
Loading
Loading