summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorraven <citrons@mondecitronne.com>2026-03-21 17:25:01 -0500
committerraven <citrons@mondecitronne.com>2026-03-21 17:25:01 -0500
commit5b7c853952b1a358bf53053a6944bcbd30a200bd (patch)
tree295397227862ea669cbcdce247f396f33c85606a
parent0f0a8676f96d6fef56c4d4afba09cb4149899070 (diff)
/kick and /ban
-rw-r--r--server/commands.go59
-rw-r--r--server/player.go1
-rw-r--r--server/server.go34
3 files changed, 93 insertions, 1 deletions
diff --git a/server/commands.go b/server/commands.go
index 4e544ce..804be0d 100644
--- a/server/commands.go
+++ b/server/commands.go
@@ -1,6 +1,7 @@
package server
import (
+ "io"
"fmt"
"sort"
"strconv"
@@ -195,6 +196,50 @@ var commands = map[string]commandHandler {
}
return ""
},
+ "kick": func(ctx commandCtx) string {
+ name, ok := ctx.arg.nextArg()
+ if !ok {
+ return usage("kick")
+ }
+ arg, _ := io.ReadAll(ctx.arg.rd)
+ reason := strings.TrimSpace(string(arg))
+ if reason != "" {
+ reason = "Kicked: " + reason
+ }
+ if ctx.server.kick(name, string(reason)) {
+ ctx.sender.OnCommandOutput(ctx.server,
+ fmt.Sprintf("Kicked %s.", name),
+ )
+ } else {
+ return "Unknown player: " + name
+ }
+ return ""
+ },
+ "ban": func(ctx commandCtx) string {
+ name, ok := ctx.arg.nextArg()
+ if !ok {
+ return usage("ban")
+ }
+ arg, _ := io.ReadAll(ctx.arg.rd)
+ reason := strings.TrimSpace(string(arg))
+ if reason != "" {
+ reason = "Banned: " + reason
+ }
+ ctx.server.ban(name, string(reason))
+ ctx.sender.OnCommandOutput(ctx.server, fmt.Sprintf("Banned %s.", name))
+ return ""
+ },
+ "unban": func(ctx commandCtx) string {
+ name, ok := ctx.arg.nextArg()
+ if !ok {
+ return usage("unban")
+ }
+ ctx.server.unban(name)
+ ctx.sender.OnCommandOutput(ctx.server,
+ fmt.Sprintf("Unbanned %s.", name),
+ )
+ return ""
+ },
"op": func(ctx commandCtx) string {
name, ok := ctx.arg.nextArg()
if !ok {
@@ -267,6 +312,8 @@ var commands = map[string]commandHandler {
var commandAuth = map[string]authLevel {
"tp": cheatAuth,
+ "kick": moderateAuth,
+ "ban": moderateAuth,
"createLevel": opAuth,
"op": opAuth,
"deop": opAuth,
@@ -291,6 +338,18 @@ var help = map[string][]string {
"* --gen: Level generation type (flat, empty)",
"* --size: Level dimensions",
},
+ "kick": []string {
+ "/kick <player> [reason]",
+ "Disconnect a player from the server",
+ },
+ "ban": []string {
+ "/ban <player> [reason]",
+ "Ban a player from joining the server",
+ },
+ "unban": []string {
+ "/unban <player> [reason]",
+ "Unban a player from joining the server",
+ },
"op": []string {
"/op <player>",
"Grant operator status",
diff --git a/server/player.go b/server/player.go
index 6b03466..9904bbe 100644
--- a/server/player.go
+++ b/server/player.go
@@ -31,6 +31,7 @@ type playerState struct {
const (
defaultAuth = 0
cheatAuth = 100
+ moderateAuth = 150
opAuth = 200
ConsoleAuth = 900
)
diff --git a/server/server.go b/server/server.go
index c549122..b747b14 100644
--- a/server/server.go
+++ b/server/server.go
@@ -34,6 +34,7 @@ type worldState struct {
LastId levelId
SpawnLevel levelId
SpawnPos entityPos
+ Banned map[string]string
}
func NewServer(info ServerInfo) *Server {
@@ -66,6 +67,9 @@ func NewServer(info ServerInfo) *Server {
})
s.worldState = <-loaded
}
+ if s.worldState.Banned == nil {
+ s.worldState.Banned = make(map[string]string)
+ }
return s
}
@@ -179,11 +183,11 @@ func (s *Server) OnDisconnect(cl *client, username string, pl *player) {
}
if s.players[username] == pl {
delete(s.players, username)
+ s.Broadcast(nil, fmt.Sprintf("&e%s has left", username))
}
if username == "" {
return
}
- s.Broadcast(nil, fmt.Sprintf("&e%s has left", username))
})
}
@@ -250,9 +254,37 @@ func (s *Server) changePlayerAuth(
})
}
+func (s *Server) ban(playerName string, reason string) {
+ log.Printf("banning %s for '%s'", playerName, reason)
+ s.kick(playerName, reason)
+ s.worldState.Banned[playerName] = reason
+}
+
+func (s *Server) unban(playerName string) {
+ log.Printf("unbanning %s", playerName)
+ delete(s.worldState.Banned, playerName)
+}
+
+func (s *Server) kick(playerName string, reason string) bool {
+ pl := s.players[playerName]
+ if pl == nil {
+ return false
+ }
+ if reason == "" {
+ reason = "Bye!"
+ }
+ pl.Kick(s, reason)
+ return true
+}
+
func (s *Server) NewPlayer(
from phony.Actor, cl *client, name string, reply func(*player)) {
s.Act(from, func() {
+ banReason, ok := s.worldState.Banned[name]
+ if ok {
+ cl.Disconnect(s, banReason)
+ return
+ }
s.Broadcast(nil, fmt.Sprintf("&e%s has joined", name))
if s.players[name] != nil {
s.players[name].Act(s, func() {