Skip to content

Latest commit

 

History

25 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dfhack

Go client for DFHack RPC server. Communication happens with DFHack's binary TCP protocol (handshake, fixed frames, bind/call/quit)

Contents

  • client/ the RPC client (Dial, Bind, Call, Close). Text delivered via OnText is automatically converted from DFHack's CP437 codepage to UTF-8, so non-ASCII names and glyphs render correctly.
  • gen/proto/ generated Go bindings for DFHack's core protobuf messages (CoreProtocol.proto, Basic.proto, BasicApi.proto), regenerated from upstream DFHack .proto files via make proto (see scripts/proto-entrypoint.sh).
  • cmd/ a minimal CLI example that runs a single DFHack console command.

Install

go get github.com/salimnassim/dfhack

Usage

Connect and run a DFHack console command (CoreRunCommandRequest/RunCommandID are always available, no Bind needed):

package main

import (
	"context"
	"fmt"
	"log/slog"

	"github.com/salimnassim/dfhack/client"
	pb "github.com/salimnassim/dfhack/gen/proto"
)

func main() {
	ctx := context.Background()

	c, err := client.Dial(ctx, client.DefaultAddr)
	if err != nil {
		slog.Error("dial failed", "error", err)
		return
	}
	defer c.Close()

	// Streamed text output (e.g. command output) arrives via OnText.
	c.OnText = func(n *pb.CoreTextNotification) {
		for _, fragment := range n.GetFragments() {
			fmt.Print(fragment.GetText())
		}
	}

	cmd := &pb.CoreRunCommandRequest{Command: new("ls")}
	if err := c.Call(ctx, client.RunCommandID, cmd, &pb.EmptyMessage{}); err != nil {
		slog.Error("command failed", "error", err)
	}
}

A runnable version of this is in cmd/command.go:

go run ./cmd -addr 127.0.0.1:5000 -command ls

Every Call and Bind takes a context.Context; cancelling it or passing its deadline aborts the in-flight request. After a transport or framing error (including a cancelled request) the connection's stream position is unknown, so all later calls on that Client fail with the same error — Dial a new one. A server-side failure (*client.RPCError) does not break the connection.

Text encoding

Dwarf Fortress encodes in-game text (item names, creature names, etc.) using the DOS CP437 codepage rather than UTF-8. The client transparently decodes CoreTextFragment text from CP437 to UTF-8 before it reaches OnText, so accented and special characters (e.g. é) print correctly instead of showing up as � or ?.

$ go run cmd/command.go --command instruments
shigós (handheld, WOODCRAFT/assemble)
  make shigós keyboard (GLASSMAKER: sand, sand bag)
  make shigós body (WOODCRAFT: wood)
  make shigós bellows (LEATHERWORK: leather)

zasgim (handheld, STONECRAFT/assemble)
  make zasgim yoke (BONECARVE: bone)
  make zasgim sound-chest (STONECRAFT: stone)
  make zasgim strings (WEAVING: silk thread)
  make zasgim bow (BONECARVE: bone)

eststek (handheld, STONECRAFT: stone)

gethust (handheld, POTTERY/assemble)
  make gethust blowpipe (WOODCRAFT: wood)
  make gethust wind chest (POTTERY: clay)
  make gethust pipe (POTTERY: clay)

ubur (handheld, GLASSMAKER: sand, sand bag)

kikës (building, METALCRAFT/assemble)
  forge kikës triangles (METALCRAFT: metal bars)
  make kikës stand (STONECRAFT: stone)

thortith (building, BONECARVE/assemble)
  make thortith bowls (BONECARVE: bone)
  forge thortith stand (METALCRAFT: metal bars)
  make thortith stick (WOODCRAFT: wood)

unib (building, POTTERY: clay)

dakas (building, CARPENTRY: wood)

Calling a plugin RPC method

Plugin-provided methods must be bound to an ID before use with Client.Bind, then invoked with Client.Call using that ID:

id, err := c.Bind(ctx, "SomeMethod", "someplugin", &pb.SomeMethodIn{}, &pb.SomeMethodOut{})
if err != nil {
	// handle error
}

out := &pb.SomeMethodOut{}
if err := c.Call(ctx, id, &pb.SomeMethodIn{ /* ... */ }, out); err != nil {
	// handle error
}

Regenerating protobuf bindings

Generated code under gen/proto/ is produced from upstream DFHack .proto files:

make proto DFHACK_VERSION=<tag>

See Makefile, buf.gen.yaml, and scripts/proto-entrypoint.sh for details.

About

Go client for DFHack RPC server.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages