Add server-authoritative PvP main_test.go
This commit is contained in:
parent
689562aadd
commit
7cf6103544
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTicketSingleUse(t *testing.T) {
|
func TestTicketSingleUse(t *testing.T) {
|
||||||
@ -20,21 +21,18 @@ func TestTicketSingleUse(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestTransformSanitizers(t *testing.T) {
|
func TestTransformSanitizers(t *testing.T) {
|
||||||
if got := clampFloat(-5, 0, 3600); got != 0 {
|
if got := clampFloat(-5, 0, worldSize); got != 0 {
|
||||||
t.Fatalf("clamp low=%v", got)
|
t.Fatalf("clamp low=%v", got)
|
||||||
}
|
}
|
||||||
if got := clampFloat(4000, 0, 3600); got != 3600 {
|
if got := clampFloat(4000, 0, worldSize); got != worldSize {
|
||||||
t.Fatalf("clamp high=%v", got)
|
t.Fatalf("clamp high=%v", got)
|
||||||
}
|
}
|
||||||
if got := clampFloat(math.NaN(), 0, 3600); got != 0 {
|
if got := clampFloat(math.NaN(), 0, worldSize); got != 0 {
|
||||||
t.Fatalf("nan=%v", got)
|
t.Fatalf("nan=%v", got)
|
||||||
}
|
}
|
||||||
if got := normalizeAngle(-90); got != 270 {
|
if got := normalizeAngle(-90); got != 270 {
|
||||||
t.Fatalf("angle=%v", got)
|
t.Fatalf("angle=%v", got)
|
||||||
}
|
}
|
||||||
if got := clampInt(900, 0, 500); got != 500 {
|
|
||||||
t.Fatalf("hull=%v", got)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAudienceMatch(t *testing.T) {
|
func TestAudienceMatch(t *testing.T) {
|
||||||
@ -48,3 +46,99 @@ func TestAudienceMatch(t *testing.T) {
|
|||||||
t.Fatal("wrong client must not match")
|
t.Fatal("wrong client must not match")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServerMovementUsesInputNotClientTransform(t *testing.T) {
|
||||||
|
state := newPlayerState("player-1", "Dave", 0, 0)
|
||||||
|
startX, startY := state.X, state.Y
|
||||||
|
input := inputState{Throttle: 1, Steer: 0.4, Seq: 7}
|
||||||
|
now := time.Unix(100, 0)
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
stepPlayer(&state, input, now.Add(time.Duration(i)*simTick), simTick.Seconds())
|
||||||
|
}
|
||||||
|
if state.InputSeq != 7 {
|
||||||
|
t.Fatalf("input seq=%d", state.InputSeq)
|
||||||
|
}
|
||||||
|
if state.Speed <= 0 || state.Speed > playerMaxSpeed {
|
||||||
|
t.Fatalf("speed=%v", state.Speed)
|
||||||
|
}
|
||||||
|
if state.X == startX && state.Y == startY {
|
||||||
|
t.Fatal("authoritative simulation did not move player")
|
||||||
|
}
|
||||||
|
if state.Angle == 0 {
|
||||||
|
t.Fatal("steer input did not change angle")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDockedInputFreezesAuthoritativeShip(t *testing.T) {
|
||||||
|
state := newPlayerState("player-1", "Dave", 0, 0)
|
||||||
|
state.Speed = 150
|
||||||
|
x, y := state.X, state.Y
|
||||||
|
stepPlayer(&state, inputState{Docked: true, Seq: 1}, time.Now(), simTick.Seconds())
|
||||||
|
if state.Speed != 0 || state.X != x || state.Y != y {
|
||||||
|
t.Fatalf("docked ship moved: speed=%v x=%v y=%v", state.Speed, state.X, state.Y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBroadsideSpawnsThreeServerProjectilesAndEnforcesReload(t *testing.T) {
|
||||||
|
h := newHub("TEST")
|
||||||
|
c := &client{state: newPlayerState("one", "One", 0, 0), lastFire: map[string]time.Time{}}
|
||||||
|
h.clients[c.state.ID] = c
|
||||||
|
now := time.Unix(100, 0)
|
||||||
|
if !h.fire("one", "port", now) {
|
||||||
|
t.Fatal("first fire should succeed")
|
||||||
|
}
|
||||||
|
if len(h.projectiles) != 3 {
|
||||||
|
t.Fatalf("projectiles=%d", len(h.projectiles))
|
||||||
|
}
|
||||||
|
if h.fire("one", "port", now.Add(100*time.Millisecond)) {
|
||||||
|
t.Fatal("reload should reject early second broadside")
|
||||||
|
}
|
||||||
|
if !h.fire("one", "port", now.Add(broadsideReload)) {
|
||||||
|
t.Fatal("broadside should fire after reload")
|
||||||
|
}
|
||||||
|
if len(h.projectiles) != 6 {
|
||||||
|
t.Fatalf("projectiles after reload=%d", len(h.projectiles))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerProjectileAppliesDamageDeathAndKill(t *testing.T) {
|
||||||
|
h := newHub("TEST")
|
||||||
|
shooter := &client{state: newPlayerState("one", "One", 0, 0), lastFire: map[string]time.Time{}}
|
||||||
|
target := &client{state: newPlayerState("two", "Two", 0, 0), lastFire: map[string]time.Time{}}
|
||||||
|
shooter.state.X, shooter.state.Y = 1000, 1000
|
||||||
|
target.state.X, target.state.Y = 1050, 1000
|
||||||
|
target.state.Hull = shotDamage
|
||||||
|
h.clients[shooter.state.ID] = shooter
|
||||||
|
h.clients[target.state.ID] = target
|
||||||
|
now := time.Unix(100, 0)
|
||||||
|
h.projectiles["shot"] = projectileState{
|
||||||
|
ID: "shot", OwnerID: shooter.state.ID, X: target.state.X, Y: target.state.Y,
|
||||||
|
Damage: shotDamage, bornAt: now,
|
||||||
|
}
|
||||||
|
h.step(now.Add(simTick), simTick.Seconds())
|
||||||
|
if target.state.Alive {
|
||||||
|
t.Fatal("target should be dead")
|
||||||
|
}
|
||||||
|
if target.state.Deaths != 1 || shooter.state.Kills != 1 {
|
||||||
|
t.Fatalf("kills/deaths=%d/%d", shooter.state.Kills, target.state.Deaths)
|
||||||
|
}
|
||||||
|
if target.state.LastKiller != "One" {
|
||||||
|
t.Fatalf("killer=%q", target.state.LastKiller)
|
||||||
|
}
|
||||||
|
if _, ok := h.projectiles["shot"]; ok {
|
||||||
|
t.Fatal("hit projectile should be removed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestServerRespawnsDestroyedPlayer(t *testing.T) {
|
||||||
|
state := newPlayerState("player-1", "Dave", 0, 1)
|
||||||
|
now := time.Unix(100, 0)
|
||||||
|
state.Alive = false
|
||||||
|
state.Hull = 0
|
||||||
|
state.Speed = 120
|
||||||
|
state.RespawnAt = now.Add(respawnDelay).UnixMilli()
|
||||||
|
stepPlayer(&state, inputState{}, now.Add(respawnDelay+time.Millisecond), simTick.Seconds())
|
||||||
|
if !state.Alive || state.Hull != playerMaxHull || state.Speed != 0 {
|
||||||
|
t.Fatalf("bad respawn: %+v", state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user