look at the code if you want to know what i did

This commit is contained in:
adman
2026-03-22 00:35:07 +01:00
parent a6102b7ec9
commit ea024fe808
21 changed files with 294 additions and 78 deletions
+2
View File
@@ -3,6 +3,7 @@ package client
import (
"net"
"github.com/admin-else/strom/event"
"github.com/admin-else/strom/proto"
"github.com/admin-else/strom/proto_base"
)
@@ -30,6 +31,7 @@ func ConnectVersionLess(addr string) (ret *proto.Conn, err error) {
ret.SetState(proto_base.Handshaking)
ret.SetCompressionThreshold(-1)
ret.Actor = proto_base.Client
ret.Loop = event.NewLoop()
ret.Conn, err = net.Dial("tcp", addr)
if err != nil {
return
+6 -3
View File
@@ -19,8 +19,11 @@ func (c *ConfigIgnorer) OnStart() (err error) {
return
}
func (c *ConfigIgnorer) Default(event event.Anything) (err error) {
slog.Debug("Config ignorer", "packet", fmt.Sprintf("%#v", event))
func (c *ConfigIgnorer) Default(e event.Anything) (err error) {
if e.Val == (event.Tick{}) {
return
}
slog.Debug("Config ignorer", "packet", fmt.Sprintf("%#v", e))
return
}
@@ -56,7 +59,7 @@ func IgnoreConfig(c *proto.Conn) (err error) {
ci.RegisterUntilLatest(ci.OnPing)
ci.RegisterUntilLatest(ci.OnKeepAlive)
err = ci.Start()
err = ci.StartConn()
if err != nil {
err = errors.Join(err, errors.New("failed to ignore config"))
}
+1 -1
View File
@@ -106,7 +106,7 @@ func DoDnsSimple(in string) (out string, err error) {
if err != nil {
return
}
out = in
out = host + ":" + strconv.Itoa(int(portN))
if portN != 25565 {
return
}
+1 -4
View File
@@ -152,7 +152,7 @@ func Login(c *proto.Conn, account *api.Account) (err error) {
lc.SetState(proto_base.Login)
err = lc.Send(&v1_21_8.LoginToServerPacketLoginStart{Username: lc.Account.Name, PlayerUUID: lc.Account.Uuid})
err = lc.Start()
err = lc.StartConn()
if err != nil {
err = errors.Join(FailedToLoginErr, err)
}
@@ -165,8 +165,5 @@ func ConnectAndLogin(connectTo string, account *api.Account) (c *proto.Conn, err
return
}
err = Login(c, account)
if err != nil {
err = errors.Join(FailedToLoginErr, err)
}
return
}
+2 -7
View File
@@ -19,10 +19,6 @@ type StatusClient struct {
DoPingRoundTripTime bool
}
func (s *StatusClient) OnStart() (err error) {
return
}
func (s *StatusClient) OnStatus(p *v1_21_8.StatusToClientPacketServerInfo) (err error) {
s.Status = p.Response
s.PingSendTime = time.Now()
@@ -55,9 +51,8 @@ func StatusRaw(addr string) (s *StatusClient, err error) {
s = &StatusClient{
Conn: c,
}
s.Loop = event.NewLoop()
s.RegisterUntilLatest(s.OnStatus)
s.RegisterUntilLatest(s.OnPong)
s.RegisterCriticalUntilLatest(s.OnStatus)
s.RegisterCriticalUntilLatest(s.OnPong)
p, err := MakeHandshakePacketAddr(s.Conn, proto_base.Status, addr)
if err != nil {
+32 -26
View File
@@ -2,6 +2,7 @@ package data
import (
"errors"
"strconv"
)
// {
@@ -75,9 +76,9 @@ func LookupBlockByStateId(version string, stateId int32) (block *Block, ok bool)
return
}
func LookupBlockByName(version string, stateId int32) (block *Block, ok bool) {
func LookupBlockByName(version string, name string) (block *Block, ok bool) {
for _, b := range BlocksForVersion(version) {
if b.MinStateId <= stateId && stateId <= b.MaxStateId {
if b.Name == name {
block = b
ok = true
}
@@ -85,6 +86,16 @@ func LookupBlockByName(version string, stateId int32) (block *Block, ok bool) {
return
}
func StateIdFromBlocKAndStateMap(version string, name string, stateMap map[string]string) (stateId int32, err error) {
b, ok := LookupBlockByName(version, name)
if !ok {
err = BlockNotFoundErr
return
}
stateId, err = b.IdFromStateMap(stateMap)
return
}
var BlockStateOutOfRangeErr = errors.New("stateId out of range")
var BlockNotFoundErr = errors.New("block not found")
var InvalidBoolValueErr = errors.New("invalid bool value")
@@ -92,7 +103,7 @@ var BadBlockStateTypeErr = errors.New("bad block state type")
var BadEnumErr = errors.New("bad enum")
var SupplyAllStatesErr = errors.New("supply all states")
func FromBlockState(version string, stateId int32) (b *Block, stateData map[string]any, err error) {
func FromBlockState(version string, stateId int32) (b *Block, stateData map[string]string, err error) {
b, ok := LookupBlockByStateId(version, stateId)
if !ok {
err = BlockNotFoundErr
@@ -101,19 +112,17 @@ func FromBlockState(version string, stateId int32) (b *Block, stateData map[stri
return
}
// TODO: mc stores these as strings so we will do the same
func mcDataBlockStateTypeParse(n int32, s *BlockState) (v any, err error) {
func mcDataBlockStateTypeParse(n int32, s *BlockState) (v string, err error) {
switch s.Type {
case "int":
v = n
v = strconv.Itoa(int(n))
case "enum":
v = s.Values[n]
case "bool":
if n == 0 { // MOJANK: 0 is true, 1 is false
v = true
v = "true"
} else if n == 1 {
v = false
v = "false"
} else {
err = InvalidBoolValueErr
}
@@ -123,35 +132,32 @@ func mcDataBlockStateTypeParse(n int32, s *BlockState) (v any, err error) {
return
}
func mcDataBlockStateTypeSerialize(v any, s *BlockState) (n int32, err error) {
switch t := v.(type) {
case int32:
n = t
case bool:
if t {
n = 0
} else {
n = 1
func mcDataBlockStateTypeSerialize(v string, s *BlockState) (n int32, err error) {
if v == "true" {
return 0, nil
}
if v == "false" {
return 1, nil
}
n1, errMabye := strconv.Atoi(v)
if errMabye == nil {
return int32(n1), nil
}
case string:
for i, enumValue := range s.Values {
if enumValue == t {
if enumValue == v {
return int32(i), nil
}
}
err = BadEnumErr
default:
err = BadBlockStateTypeErr
}
return
}
func (b *Block) StateMapFromId(stateId int32) (ret map[string]any, err error) {
func (b *Block) StateMapFromId(stateId int32) (ret map[string]string, err error) {
if stateId < b.MinStateId || stateId > b.MaxStateId {
err = BlockStateOutOfRangeErr
return
}
ret = make(map[string]any)
ret = make(map[string]string)
stateId -= b.MinStateId
a := int32(1)
@@ -166,7 +172,7 @@ func (b *Block) StateMapFromId(stateId int32) (ret map[string]any, err error) {
return
}
func (b *Block) IdFromStateMap(m map[string]any) (ret int32, err error) {
func (b *Block) IdFromStateMap(m map[string]string) (ret int32, err error) {
a := int32(1)
for i := range len(b.States) {
s := b.States[len(b.States)-1-i]
+11 -1
View File
@@ -12,7 +12,7 @@ package data
type VersionInfo struct {
MinecraftVersion string
Version int32
DataVersion int
DataVersion int32
UsesNetty bool
MajorVersion string
ReleaseType string
@@ -42,6 +42,16 @@ func LookUpVersionByProtocolVersion(version int32) (ret VersionInfo, err error)
return
}
func LookUpVersionByDataVersion(version int32) (ret VersionInfo, err error) {
for _, v := range ProtocolVersions {
if v.DataVersion == version {
ret = v
}
}
err = UnknownMinecraftVersionError
return
}
func init() {
must(LoadJson("minecraft-data/data/pc/common/protocolVersions.json", &ProtocolVersions))
}
+12 -5
View File
@@ -53,10 +53,13 @@ func (e HandlerDoneErr) Unwrap() error {
return e.Return
}
// ErrDontForward will stop the event from being forwarded to other handlers, including anything handlers.
var ErrDontForward = errors.New("dont forward")
// DontForwardErr will stop the event from being forwarded to other handlers, including anything handlers.
var DontForwardErr = errors.New("dont forward")
var WhileClosingErr = errors.New("error while closing")
// CloseNonCriticalErr will close even when the event is non-critical
var CloseNonCriticalErr = errors.New("close non-critical")
func ValidateHandler(h any) (eventType reflect.Type, hv reflect.Value) {
hv = reflect.ValueOf(h)
if hv.Kind() != reflect.Func {
@@ -86,7 +89,11 @@ func (l *Loop) RegisterCustomType(eventType reflect.Type, hv reflect.Value) {
handleFunc := func(packet any) error {
v := hv.Call([]reflect.Value{reflect.ValueOf(packet)})[0]
if !v.IsNil() {
slog.Error("handler failed", "err", v.Interface().(error))
err := v.Interface().(error)
if errors.Is(err, CloseNonCriticalErr) {
return err
}
slog.Error("handler failed", "err", err)
}
return nil
}
@@ -124,7 +131,7 @@ func (l *Loop) FireFound(event any) (found bool, err error) {
func (l *Loop) Fire(event any) (err error) {
found, err := l.FireFound(event)
if err != nil {
if errors.Is(err, ErrDontForward) {
if errors.Is(err, DontForwardErr) {
err = nil
}
return
@@ -159,7 +166,7 @@ func (l *Loop) startLoop() (err error) {
return
}
func (l *Loop) Start() (err error) {
func (l *Loop) StartLoop() (err error) {
go func() {
l.ErrChan <- l.startLoop()
}()
+71
View File
@@ -0,0 +1,71 @@
package main
import (
"github.com/admin-else/strom/data"
"github.com/go-viper/mapstructure/v2"
)
type Position struct {
X, Y, Z int32
}
type MetaData struct {
Author string
Description string
Name string
TimeCreated int64
TimeModified int64
TotalBlocks int32
TotalVolume int32
RegionCount int32
EnclosingSize Position
}
type BlockState struct {
Name string
Properties map[string]string
}
type Region struct {
Position Position
Size Position
BlockStatePalette []BlockState
BlockStates []int64
}
type File struct {
Version int32
SubVersion int32
MinecraftDataVersion int32
Metadata MetaData
Regions map[string]Region
}
type Structure struct {
File
BlockStatePalletRealized map[string][]int32
}
func Load(v any) (s *Structure, err error) {
s = &Structure{}
err = mapstructure.Decode(v, &s.File)
if err != nil {
return
}
ret, err := data.LookUpVersionByDataVersion(s.MinecraftDataVersion)
if err != nil {
return
}
for k, r := range s.Regions {
s.BlockStatePalletRealized[k] = make([]int32, len(r.BlockStatePalette))
for i, b := range r.BlockStatePalette {
var stateId int32
stateId, err = data.StateIdFromBlocKAndStateMap(ret.MinecraftVersion, b.Name, b.Properties)
if err != nil {
return
}
s.BlockStatePalletRealized[k][i] = stateId
}
}
return
}
@@ -1,11 +1,11 @@
package level
package structure
import (
"github.com/admin-else/strom/nbt"
"github.com/go-viper/mapstructure/v2"
)
func LoadStructure(fileName string) (s *Structure, err error) {
func Load(fileName string) (s *Structure, err error) {
n, err := nbt.ReadFilePath(fileName)
if err != nil {
return
+3 -1
View File
@@ -291,6 +291,8 @@ func readPayload(id int8, r io.Reader) (ret any, err error) {
return
}
var UnknownTagTypeErr = errors.New("unknown nbt type")
func writePayload(v any, w io.Writer) (err error) {
switch v := v.(type) {
case struct{}:
@@ -361,7 +363,7 @@ func writePayload(v any, w io.Writer) (err error) {
}
err = binary.Write(w, Order, End)
default:
err = errors.New("unknown nbt type")
err = UnknownTagTypeErr
}
return
}
+91
View File
@@ -0,0 +1,91 @@
package nbt
import (
"fmt"
"io"
)
// PrintSNBTAny documented at https://minecraft.wiki/w/NBT_format#SNBT_format
func PrintSNBTAny(t any, w io.Writer) (err error) {
switch t := t.(type) {
case int8:
_, err = fmt.Fprintf(w, "%vB", t)
case bool:
_, err = fmt.Fprintf(w, "%v", t)
case int16:
_, err = fmt.Fprintf(w, "%vS", t)
case int32:
_, err = fmt.Fprintf(w, "%vI", t)
case int64:
_, err = fmt.Fprintf(w, "%vL", t)
case float32:
_, err = fmt.Fprintf(w, "%vF", t)
case float64:
_, err = fmt.Fprintf(w, "%vD", t)
case string:
_, err = fmt.Fprintf(w, "%q", t)
case []any:
_, err = fmt.Fprintf(w, "[")
for _, v := range t {
err = PrintSNBTAny(v, w)
if err != nil {
return
}
_, err = fmt.Fprintf(w, ",")
}
_, err = fmt.Fprintf(w, "]")
case map[string]any:
_, err = fmt.Fprintf(w, "{")
for k, v := range t {
_, err = fmt.Fprintf(w, "%q:,", k)
err = PrintSNBTAny(v, w)
if err != nil {
return
}
_, err = fmt.Fprintf(w, ",")
}
_, err = fmt.Fprintf(w, "}")
case []int8:
_, err = fmt.Fprintf(w, "[B;")
if err != nil {
return
}
for _, v := range t {
err = PrintSNBTAny(v, w)
if err != nil {
return
}
_, err = fmt.Fprintf(w, ",")
}
_, err = fmt.Fprintf(w, "]")
case []int32:
_, err = fmt.Fprintf(w, "[I;")
if err != nil {
return
}
for _, v := range t {
err = PrintSNBTAny(v, w)
if err != nil {
return
}
_, err = fmt.Fprintf(w, ",")
}
_, err = fmt.Fprintf(w, "]")
case []int64:
_, err = fmt.Fprintf(w, "[L;")
if err != nil {
return
}
for _, v := range t {
err = PrintSNBTAny(v, w)
if err != nil {
return
}
_, err = fmt.Fprintf(w, ",")
}
_, err = fmt.Fprintf(w, "]")
default:
err = UnknownTagTypeErr
}
return
}
+23
View File
@@ -0,0 +1,23 @@
package nbt
import (
"bytes"
_ "embed"
"testing"
)
//go:embed testdata/top_0_20.nbt
var topSNBT []byte
func TestPrintSNBTAny(t *testing.T) {
n, err := ReadFile(bytes.NewReader(topSNBT))
if err != nil {
panic(err)
}
bb := bytes.NewBuffer(nil)
err = PrintSNBTAny(n.Value, bb)
if err != nil {
panic(err)
}
t.Log(bb.String())
}
BIN
View File
Binary file not shown.
+8 -9
View File
@@ -60,13 +60,19 @@ type Conn struct {
func (c *Conn) StartConn() (err error) {
c.RegisterCritical(c.OnTick)
return c.Loop.Start()
if c.state == proto_base.Play {
c.ActivateReceiveRoutine()
}
err = c.Loop.StartLoop()
c.Loop = event.NewLoop()
return
}
func (c *Conn) ReceiveJob() {
ctx := c.Ctx
for {
select {
case <-c.Ctx.Done():
case <-ctx.Done():
return
default:
packet, err := c.Receive()
@@ -233,10 +239,3 @@ func (c *Conn) OnTick(_ event.Tick) (err error) {
}
return
}
func (c *Conn) Start() (err error) {
if c.Loop == nil {
c.Loop = &event.Loop{}
}
return c.Loop.Start()
}
+1 -1
View File
@@ -65,7 +65,7 @@ func ServeConfig(c *proto.Conn) (err error) {
}
err = c.Send(&v1_21_8.ConfigurationToClientPacketFinishConfiguration{})
cs := &ConfigServer{c}
return cs.Start()
return cs.StartLoop()
}
func (c *ConfigServer) OnFinishConfiguration(_ *v1_21_8.ConfigurationToServerPacketFinishConfiguration) (err error) {
+1 -1
View File
@@ -168,6 +168,6 @@ func ServeLogin(c *proto.Conn, settings ...LoginServerSetting) (ret *LoginServer
s(ret)
}
ret.CompressionThreshold = 256
err = ret.Start()
err = ret.StartLoop()
return
}
+1 -1
View File
@@ -67,6 +67,6 @@ func ServeStatus(c *proto.Conn, s StatusResponse) (err error) {
}
server.RegisterUntilLatest(server.OnStatusRequest)
server.RegisterUntilLatest(server.OnStatusPing)
err = server.Start()
err = server.StartLoop()
return
}
+14 -1
View File
@@ -1,6 +1,7 @@
package print_nbt
import (
"bytes"
"encoding/json"
"flag"
"os"
@@ -11,6 +12,7 @@ import (
var (
cmd = flag.NewFlagSet("print-nbt", flag.ContinueOnError)
FileFlag = cmd.String("file", "", "The NBT file to print")
HashFormatFlag = cmd.Bool("snbt", false, "will print with go %#v")
)
func Run(args []string) (err error) {
@@ -27,7 +29,18 @@ func Run(args []string) (err error) {
if err != nil {
return
}
b, err := json.MarshalIndent(n, "", " ")
var b []byte
if *HashFormatFlag {
bb := bytes.NewBuffer(nil)
err = nbt.PrintSNBTAny(n.Value, bb)
if err != nil {
return
}
b = bb.Bytes()
//b = []byte(strings.ReplaceAll(string(b), ",", ",\n"))
} else {
b, err = json.MarshalIndent(n, "", " ")
}
if err != nil {
return
}
+3 -6
View File
@@ -116,10 +116,7 @@ func handleClient(c *proto.Conn) (err error) {
return
}
defer sockPuppet.Close()
err = sockPuppet.Start(&client.LoginClient{
Conn: sockPuppet,
Account: acc,
})
err = sockPuppet.StartLoop()
if err != nil {
return
}
@@ -127,10 +124,10 @@ func handleClient(c *proto.Conn) (err error) {
p := &Proxy{Client: sockPuppet, Servee: c}
p.Data.Value = map[string]any{"Registries": []any{}}
go func() {
errChan <- p.Client.Start(p)
errChan <- p.Client.StartLoop()
}()
go func() {
errChan <- p.Servee.Start(p)
errChan <- p.Servee.StartLoop()
}()
err = <-errChan
f, err := os.Create("data/registry/" + SaveAs + ".nbt")
+2 -2
View File
@@ -154,10 +154,10 @@ func main() {
errChan := make(chan error)
defer pc.Close()
go func() {
errChan <- pc.Start(pc)
errChan <- pc.StartConn()
}()
go func() {
errChan <- p.Start(p)
errChan <- p.StartConn()
}()
err = <-errChan
return