Skip to content

Commit c8d3b8a

Browse files
PaulicStudiosReptudnJoe Rookyard4n4k1n
authored
[bots|wiki|go] 184 add go connection lib (#199)
* added golang-go package to the dockerfile for the go conn lib * simple go bot repo template * added go client lib into monorepo * removed deprecated package from go.mod * my core bot go docker image * added go.work that the go conn lib both works in prod and dev * devcontainer working now but not the go lib * works on my machine (not) * moved go client lib into the template temporarily * autocomplete now works inside the go devcontainer * [client_lib:go] fix spelling of 'schemas' * [client_lib:go] fix(socket): add newline to each socket message, feat: handle server side ticks, fix(Makefile): add clean rule * Fix paths go con lib and more improvements (#195) * [visualizer] removed force https when loading replay files (#191) * deleted dublicate go client lib, put go.mod into root, fix paths in dockerfile * [bots|go] refactor: renamed template to softcore * removed post create cmd as ./../../client_lib works both in the monorepo and in the devcontainer itself. removed cpp addons * reverted back changes that got lost from deleting the duplicate client_lib * [monorepo] added go language support to root makefile * [bots|go] fix basic connection so that client lib connects and ticks play out * updated library to correctly parse the server messages and improved parsing plus added untility functions * Change order of bot execution in Makefile Now the bot of the user runs in the foreground * Refactor game logic and connection handling in Go client library * Refactor Go client library: standardize field names and improve connection handling * Refactor main.go: streamline unit handling and improve method naming * feat: lots of new functions for go game library * [wiki|cleanup] added go wiki with multi group codeblocks, removed .idea folder and added it back to gitignore --------- Co-authored-by: Jonas Kauker <jonas.kauker2003@gmail.com> Co-authored-by: Joe Rookyard <jrookyar@1-B-12.42heilbronn.de> Co-authored-by: Anakin Pregitzer <anakin@pregitzer.de> Co-authored-by: Jonas <87537789+Reptudn@users.noreply.github.com>
1 parent e8bfe1f commit c8d3b8a

File tree

104 files changed

+8443
-1032
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

104 files changed

+8443
-1032
lines changed

.devcontainer/Dockerfile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,12 @@ RUN apt-get update && apt-get install -y \
2121
&& chmod +x /usr/local/bin/yq \
2222
&& rm -rf /var/lib/apt/lists/*
2323

24+
# Install Go 1.26.0
25+
ARG GO_VERSION=1.26.0
26+
RUN ARCH=$(dpkg --print-architecture) && \
27+
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" | tar -C /usr/local -xz
28+
ENV PATH="/usr/local/go/bin:/root/go/bin:${PATH}"
29+
ENV GOPATH="/root/go"
30+
2431
# Set default shell to zsh
2532
SHELL ["/bin/zsh", "-c"]

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"ms-vscode.cpptools",
2222
"ms-vscode.vscode-typescript-tslint-plugin",
2323
"GitHub.copilot",
24-
"twxs.cmake"
24+
"twxs.cmake",
25+
"golang.go"
2526
]
2627
}
2728
},

.github/workflows/my-core-bot-c-Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ COPY --from=connection /connection/core_lib.a /core/core_lib.a
3131
COPY --from=connection /connection/core_lib.a /core/con_lib.a
3232

3333
# Create .bashrc in /root/ directory by curling from URL
34-
# RUN curl -o /root/.bashrc https://raw.githubusercontent.com/42core-team/.shellrc/refs/heads/main/.bashrc
34+
RUN curl -o /root/.bashrc https://raw.githubusercontent.com/42core-team/.shellrc/refs/heads/main/.bashrc
3535

3636
# SHELL ["/bin/bash", "-c"]
3737
# ENV SHELL=/bin/bash
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
ARG TAG_NAME="dev"
2+
ARG SERVER_IMAGE="ghcr.io/42core-team/server"
3+
4+
FROM ${SERVER_IMAGE}:${TAG_NAME} AS game
5+
6+
FROM ubuntu:noble AS release
7+
ENV DEBIAN_FRONTEND=noninteractive
8+
9+
RUN apt update && \
10+
apt install -y git build-essential libcurl4 curl && \
11+
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') && \
12+
curl -fsSL "https://github.com/mikefarah/yq/releases/latest/download/yq_linux_${ARCH}" -o /usr/local/bin/yq && \
13+
chmod +x /usr/local/bin/yq && \
14+
rm -rf /var/lib/apt/lists/*
15+
16+
ARG GO_VERSION=1.26.0
17+
RUN ARCH=$(dpkg --print-architecture) && \
18+
curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-${ARCH}.tar.gz" | tar -C /usr/local -xz
19+
ENV PATH="/usr/local/go/bin:${PATH}"
20+
ENV GOPATH="/root/go"
21+
22+
COPY --from=game /core/server /core/server
23+
COPY --from=game /core/data /core/data
24+
COPY bots/go/client_lib/ /client_lib
25+
26+
# RUN curl -o /root/.zshrc https://raw.githubusercontent.com/42core-team/.shellrc/refs/heads/main/.zshrc
27+
28+
# SHELL ["/bin/zsh", "-c"]
29+
# ENV SHELL=/bin/zsh

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ require-vars:
66
@test -n "$(LANGUAGE)" || (echo "LANGUAGE is required (e.g. LANGUAGE=c)" && exit 2)
77
@test -n "$(STAGE)" || (echo "STAGE is required (dev|prod)" && exit 2)
88
@test -n "$(DIFFICULTY)" || (echo "DIFFICULTY is required (hardcore|softcore)" && exit 2)
9-
@echo "$(LANGUAGE)" | grep -Eq '^(c)$$' || (echo "LANGUAGE must be c (got $(LANGUAGE))" && exit 2)
9+
@echo "$(LANGUAGE)" | grep -Eq '^(c|go)$$' || (echo "LANGUAGE must be c or go (got $(LANGUAGE))" && exit 2)
1010
@echo "$(STAGE)" | grep -Eq '^(dev|prod)$$' || (echo "STAGE must be dev or prod (got $(STAGE))" && exit 2)
1111
@echo "$(DIFFICULTY)" | grep -Eq '^(hardcore|softcore)$$' || (echo "DIFFICULTY must be hardcore or softcore (got $(DIFFICULTY))" && exit 2)
1212

@@ -34,8 +34,8 @@ CONFIG_GAME_FILE := $(CONFIG_FOLDER)/game.config.json
3434

3535
.DEFAULT_GOAL := all
3636
all: setup-hooks require-vars stop
37-
# build client lib
38-
$(MAKE) -C $(CLIENT_LIB_DIR)
37+
# build client lib (only for c)
38+
$(if $(filter c,$(LANGUAGE)),$(MAKE) -C $(CLIENT_LIB_DIR))
3939

4040
# build clients
4141
$(MAKE) -C $(PLAYER_1_FOLDER) CLIENT_LIB_DIR=$(CLIENT_LIB_DIR)

bots/go/client_lib/.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# If you prefer the allow list template instead of the deny list, see community template:
2+
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
3+
#
4+
# Binaries for programs and plugins
5+
*.exe
6+
*.exe~
7+
*.dll
8+
*.so
9+
*.dylib
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Code coverage profiles and other test artifacts
15+
*.out
16+
coverage.*
17+
*.coverprofile
18+
profile.cov
19+
20+
# Dependency directories (remove the comment below to include it)
21+
# vendor/
22+
23+
# Go workspace file
24+
go.work
25+
go.work.sum
26+
27+
# env file
28+
.env
29+
30+
# Editor/IDE
31+
.idea/
32+
.vscode/

bots/go/client_lib/actions.go

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package coregame
2+
3+
import (
4+
"github.com/42core-team/go-client-lib/game"
5+
"github.com/42core-team/go-client-lib/internal"
6+
)
7+
8+
func (b *Bot) CreateUnit(unitType game.UnitType) {
9+
b.connection.ActionQueue().Add(internal.Action{
10+
Type: internal.ActionCreate,
11+
UnitType: unitType,
12+
})
13+
}
14+
15+
func (b *Bot) Move(unit *game.Object, pos game.Position) {
16+
if unit == nil {
17+
return
18+
}
19+
b.connection.ActionQueue().Add(internal.Action{
20+
Type: internal.ActionMove,
21+
UnitID: unit.ID,
22+
TargetPos: pos,
23+
})
24+
}
25+
26+
func (b *Bot) Attack(attacker, target *game.Object) {
27+
if attacker == nil || target == nil {
28+
return
29+
}
30+
b.connection.ActionQueue().Add(internal.Action{
31+
Type: internal.ActionAttack,
32+
UnitID: attacker.ID,
33+
TargetID: target.ID,
34+
})
35+
}
36+
37+
func (b *Bot) TransferGems(source *game.Object, targetPos game.Position, amount uint) {
38+
if source == nil {
39+
return
40+
}
41+
b.connection.ActionQueue().Add(internal.Action{
42+
Type: internal.ActionTransfer,
43+
UnitID: source.ID,
44+
TargetPos: targetPos,
45+
Amount: amount,
46+
})
47+
}
48+
49+
func (b *Bot) Build(builder *game.Object, pos game.Position) {
50+
if builder == nil {
51+
return
52+
}
53+
b.connection.ActionQueue().Add(internal.Action{
54+
Type: internal.ActionBuild,
55+
UnitID: builder.ID,
56+
TargetPos: pos,
57+
})
58+
}
59+
60+
func (b *Bot) SimplePathfind(unit *game.Object, targetPos game.Position) game.Position {
61+
if unit == nil || unit.Type != game.ObjectUnit {
62+
return game.Position{}
63+
}
64+
if unit.Pos.X == targetPos.X && unit.Pos.Y == targetPos.Y {
65+
return unit.Pos
66+
}
67+
68+
data := unit.GetUnitData()
69+
if data == nil || (data.ActionCooldown != nil && *data.ActionCooldown > 0) {
70+
return unit.Pos
71+
}
72+
73+
posOptionY := game.Position{X: unit.Pos.X, Y: unit.Pos.Y}
74+
if targetPos.Y != unit.Pos.Y {
75+
if targetPos.Y > unit.Pos.Y {
76+
posOptionY.Y = unit.Pos.Y + 1
77+
} else {
78+
posOptionY.Y = unit.Pos.Y - 1
79+
}
80+
}
81+
82+
posOptionX := game.Position{X: unit.Pos.X, Y: unit.Pos.Y}
83+
if targetPos.X != unit.Pos.X {
84+
if targetPos.X > unit.Pos.X {
85+
posOptionX.X = unit.Pos.X + 1
86+
} else {
87+
posOptionX.X = unit.Pos.X - 1
88+
}
89+
}
90+
91+
priorityX := 0
92+
priorityY := 0
93+
94+
if !b.game.IsPosValid(posOptionY) || posOptionY.Y == unit.Pos.Y {
95+
priorityY += 500
96+
}
97+
if !b.game.IsPosValid(posOptionX) || posOptionX.X == unit.Pos.X {
98+
priorityX += 500
99+
}
100+
101+
dx := abs(int(targetPos.X) - int(unit.Pos.X))
102+
dy := abs(int(targetPos.Y) - int(unit.Pos.Y))
103+
if dx > dy {
104+
priorityY++
105+
} else {
106+
priorityX++
107+
}
108+
109+
objAtX := b.game.ObjectAtPos(posOptionX)
110+
objAtY := b.game.ObjectAtPos(posOptionY)
111+
112+
if objAtX != nil {
113+
priorityX += 50
114+
}
115+
if objAtY != nil {
116+
priorityY += 50
117+
}
118+
119+
if objAtX != nil && objAtX.IsFriendly(b.game.MyTeamID) {
120+
priorityX += 100
121+
}
122+
if objAtY != nil && objAtY.IsFriendly(b.game.MyTeamID) {
123+
priorityY += 100
124+
}
125+
126+
if priorityX < 250 && priorityX < priorityY {
127+
if objAtX != nil && !objAtX.IsFriendly(b.game.MyTeamID) {
128+
b.Attack(unit, objAtX)
129+
} else if objAtX == nil {
130+
return posOptionX
131+
}
132+
}
133+
134+
if priorityY < 250 {
135+
if objAtY != nil && !objAtY.IsFriendly(b.game.MyTeamID) {
136+
b.Attack(unit, objAtY)
137+
} else if objAtY == nil {
138+
return posOptionY
139+
}
140+
}
141+
142+
return unit.Pos
143+
}
144+
145+
func abs(x int) int {
146+
if x < 0 {
147+
return -x
148+
}
149+
return x
150+
}

bots/go/client_lib/bot.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package coregame
2+
3+
import (
4+
"fmt"
5+
"os"
6+
7+
"github.com/42core-team/go-client-lib/game"
8+
"github.com/42core-team/go-client-lib/internal"
9+
)
10+
11+
type BotConfig struct {
12+
TeamID uint
13+
TeamName string
14+
ServerAddr string
15+
Debug bool
16+
}
17+
18+
type Bot struct {
19+
config BotConfig
20+
connection *internal.Connection
21+
game *game.Game
22+
}
23+
24+
func DefaultBotConfig(teamID int, teamName string) BotConfig {
25+
envIP := os.Getenv("SERVER_IP")
26+
envPort := os.Getenv("SERVER_PORT")
27+
port := "4444"
28+
if envPort != "" {
29+
port = envPort
30+
}
31+
32+
serverAddr := "127.0.0.1:" + port
33+
if envIP != "" {
34+
serverAddr = envIP + ":" + port
35+
}
36+
37+
return BotConfig{
38+
TeamID: uint(teamID),
39+
TeamName: teamName,
40+
ServerAddr: serverAddr,
41+
Debug: false,
42+
}
43+
}
44+
45+
func NewBot(config BotConfig) (*Bot, error) {
46+
conn, err := internal.NewConnection(config.ServerAddr, config.TeamID)
47+
if err != nil {
48+
return nil, fmt.Errorf("failed to create connection: %v", err)
49+
}
50+
51+
return &Bot{
52+
config: config,
53+
connection: conn,
54+
game: conn.Game(),
55+
}, nil
56+
}
57+
58+
func (b *Bot) Run(tick func(*game.Game, *Bot)) error {
59+
b.connection.SetTickCallback(func(g *game.Game) {
60+
tick(g, b)
61+
})
62+
return b.connection.Start(b.config.TeamID, b.config.TeamName)
63+
}
64+
65+
func (b *Bot) Close() error {
66+
return b.connection.Close()
67+
}
68+
69+
func (b *Bot) Game() *game.Game {
70+
return b.game
71+
}

bots/go/client_lib/debug.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package coregame
2+
3+
import (
4+
"github.com/42core-team/go-client-lib/game"
5+
)
6+
7+
func (b *Bot) AddObjectInfo(obj *game.Object, info string) {
8+
if obj == nil {
9+
return
10+
}
11+
b.connection.DebugData().AddObjectInfo(obj.ID, info)
12+
}
13+
14+
func (b *Bot) AddObjectPathStep(unit *game.Object, pos game.Position) {
15+
if unit == nil {
16+
return
17+
}
18+
b.connection.DebugData().AddObjectPathStep(unit.ID, pos)
19+
}

0 commit comments

Comments
 (0)