NewClient function

NewClient creates a netcode client bound to the given component name.

Parameters:

  • name string
  • decode func(map[string]any) T
  • interp func(T, T, float64) T

Returns:

  • *Client[T]
Show/Hide Function Body
{
	return newClient(name, decode, interp, hostclient.Send, hostclient.RegisterHandler)
}

testState struct

Fields:

  • X (float64) - json:"x"

decodeState function

Parameters:

  • m map[string]any

Returns:

  • testState

References:

Show/Hide Function Body
{
	x, _ := m["x"].(float64)
	return testState{X: x}
}

lerp function

Parameters:

  • a testState
  • b testState
  • alpha float64

Returns:

  • testState

References:

Show/Hide Function Body
{
	return testState{X: a.X + (b.X-a.X)*alpha}
}

TestSync function

Simulates latency between client and server and verifies interpolation.

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	cmdCh := make(chan map[string]any, 1)
	snapCh := make(chan map[string]any, 1)

	send := func(_ string, payload any) {
		p := payload.(map[string]any)
		go func() {
			time.Sleep(25 * time.Millisecond)
			cmdCh <- p
		}()
	}
	register := func(_ string, h func(map[string]any)) {
		go func() {
			for p := range snapCh {
				h(p)
			}
		}()
	}

	c := newClient("Game", decodeState, lerp, send, register)
	srv := NewServer("Game", testState{}, func(s *testState, cmd any) {
		m := cmd.(map[string]any)
		if dx, ok := m["dx"].(float64); ok {
			s.X += dx
		}
	})

	go func() {
		for payload := range cmdCh {
			if cmds, ok := payload["commands"].([]any); ok {
				for _, cmd := range cmds {
					srv.apply(&srv.state, cmd)
				}
			}
			b, _ := json.Marshal(srv.Snapshot())
			var m map[string]any
			_ = json.Unmarshal(b, &m)
			snap := map[string]any{
				"tick":  payload["tick"],
				"state": m,
			}
			time.Sleep(25 * time.Millisecond)
			snapCh <- snap
		}
	}()

	c.Enqueue(map[string]any{"dx": 5.0})
	c.Flush(100)
	time.Sleep(100 * time.Millisecond)

	c.Enqueue(map[string]any{"dx": 5.0})
	c.Flush(200)
	time.Sleep(100 * time.Millisecond)

	mid := c.State(150)
	if math.Abs(mid.X-7.5) > 0.1 {
		t.Fatalf("expected ~7.5 got %v", mid.X)
	}
}

TestServerUpdate function

Parameters:

  • t *testing.T
Show/Hide Function Body
{
	srv := NewServer("Game", testState{}, func(s *testState, cmd any) {
		if dx, ok := cmd.(float64); ok {
			s.X += dx
		}
	})

	srv.Update(func(s *testState) {
		s.X = 5
	})
	if srv.Snapshot().X != 5 {
		t.Fatalf("expected update to set X to 5")
	}

	srv.Update(func(s *testState) {
		s.X *= 2
	})
	if srv.Snapshot().X != 10 {
		t.Fatalf("expected chained updates to run under lock")
	}

	srv.apply(&srv.state, 1.0)
	if srv.Snapshot().X != 11 {
		t.Fatalf("expected command application to still work, got %v", srv.Snapshot().X)
	}
}

Server struct

Server applies commands and broadcasts state snapshots.

Fields:

  • name (string)
  • state (T)
  • apply (func(*T, any))
  • mu (sync.Mutex)

NewServer function

NewServer creates a Server for the given component name and initial state.

Parameters:

  • name string
  • initial T
  • apply func(*T, any)

Returns:

  • *Server[T]
Show/Hide Function Body
{
	return &Server[T]{name: name, state: initial, apply: apply}
}

sendFunc type

Type Definition:

func(string, any)

registerFunc type

Type Definition:

func(string, func(map[string]any))

snapshot struct

Fields:

  • tick (int64)
  • state (T)

Client struct

Client maintains a command queue and interpolates server snapshots.

Fields:

  • name (string)
  • send (sendFunc)
  • decode (func(map[string]any) T)
  • interp (func(T, T, float64) T)
  • snaps ([]snapshot[T])
  • cmds ([]any)
  • mu (sync.Mutex)

newClient function

Parameters:

  • name string
  • decode func(map[string]any) T
  • interp func(T, T, float64) T
  • send sendFunc
  • register registerFunc

Returns:

  • *Client[T]

References:

Show/Hide Function Body
{
	c := &Client[T]{name: name, send: send, decode: decode, interp: interp}
	register(name, c.handle)
	return c
}

github.com/rfwlab/rfw/v1/hostclient import

Import example:

import "github.com/rfwlab/rfw/v1/hostclient"

Imported as:

hostclient

encoding/json import

Import example:

import "encoding/json"

math import

Import example:

import "math"

testing import

Import example:

import "testing"

time import

Import example:

import "time"

sync import

Import example:

import "sync"

github.com/rfwlab/rfw/v1/host import

Import example:

import "github.com/rfwlab/rfw/v1/host"

sync import

Import example:

import "sync"