move tools to strom cli
This commit is contained in:
+18
-10
@@ -12,11 +12,15 @@ import (
|
||||
"github.com/admin-else/strom/cmd/strom/api"
|
||||
"github.com/admin-else/strom/cmd/strom/data"
|
||||
"github.com/admin-else/strom/cmd/strom/extract_mca"
|
||||
"github.com/admin-else/strom/cmd/strom/mca_to_tmcpr"
|
||||
"github.com/admin-else/strom/cmd/strom/offline_uuid"
|
||||
"github.com/admin-else/strom/cmd/strom/packet_info"
|
||||
"github.com/admin-else/strom/cmd/strom/packet_inspector"
|
||||
"github.com/admin-else/strom/cmd/strom/print_nbt"
|
||||
"github.com/admin-else/strom/cmd/strom/print_replay"
|
||||
"github.com/admin-else/strom/cmd/strom/registry_data_hunter"
|
||||
"github.com/admin-else/strom/cmd/strom/serve_tmcpr"
|
||||
"github.com/admin-else/strom/cmd/strom/serve_world"
|
||||
"github.com/admin-else/strom/cmd/strom/status"
|
||||
)
|
||||
|
||||
@@ -45,16 +49,20 @@ func Version(args []string) error {
|
||||
}
|
||||
|
||||
var subcommands = map[string]func(args []string) error{
|
||||
"offline-uuid": offline_uuid.Run,
|
||||
"packet-info": packet_info.Run,
|
||||
"print-nbt": print_nbt.Run,
|
||||
"status": status.Run,
|
||||
"packet-spy": packet_inspector.Run,
|
||||
"api": api.Run,
|
||||
"version": Version,
|
||||
"extract-mca": extract_mca.Run,
|
||||
"data": data.Run,
|
||||
"print-replay": print_replay.Run,
|
||||
"offline-uuid": offline_uuid.Run,
|
||||
"packet-info": packet_info.Run,
|
||||
"print-nbt": print_nbt.Run,
|
||||
"status": status.Run,
|
||||
"packet-spy": packet_inspector.Run,
|
||||
"api": api.Run,
|
||||
"version": Version,
|
||||
"extract-mca": extract_mca.Run,
|
||||
"data": data.Run,
|
||||
"print-replay": print_replay.Run,
|
||||
"registry-data-hunter": registry_data_hunter.Run,
|
||||
"serve-world": serve_world.Run,
|
||||
"mca-to-tmcpr": mca_to_tmcpr.Run,
|
||||
"serve-tmcpr": serve_tmcpr.Run,
|
||||
}
|
||||
|
||||
func Help(args []string) (err error) {
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
package mca_to_tmcpr
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/admin-else/strom/level"
|
||||
"github.com/admin-else/strom/level/anvil"
|
||||
"github.com/admin-else/strom/nbt"
|
||||
"github.com/admin-else/strom/proto/replay"
|
||||
"github.com/admin-else/strom/proto_generated/v1_21_11"
|
||||
"github.com/admin-else/strom/util"
|
||||
)
|
||||
|
||||
var (
|
||||
cmd = flag.NewFlagSet("mca-to-tmcpr", flag.ContinueOnError)
|
||||
worldPath = cmd.String("world", "", "Path to world directory")
|
||||
output = cmd.String("output", "", "Output .tmcpr file path")
|
||||
radius = cmd.Int("radius", 14, "Chunk radius around spawn")
|
||||
spawnX = cmd.Float64("spawn-x", 0.5, "Spawn X coordinate")
|
||||
spawnY = cmd.Float64("spawn-y", 100, "Spawn Y coordinate")
|
||||
spawnZ = cmd.Float64("spawn-z", 0.5, "Spawn Z coordinate")
|
||||
)
|
||||
|
||||
var FullLight [][]uint8
|
||||
|
||||
func init() {
|
||||
light := make([]uint8, 2048)
|
||||
for i := range light {
|
||||
light[i] = 0xFF
|
||||
}
|
||||
sectionsPerChunk := 384 / 16
|
||||
FullLight = make([][]uint8, sectionsPerChunk)
|
||||
for i := range sectionsPerChunk {
|
||||
FullLight[i] = light
|
||||
}
|
||||
}
|
||||
|
||||
func GetChunkFromMca(x, z int32, version string) (b []byte, err error) {
|
||||
xmca := util.FloorDiv(x, anvil.ChunksWidthRegionFile)
|
||||
zmca := util.FloorDiv(z, anvil.ChunksWidthRegionFile)
|
||||
x = x % anvil.ChunksWidthRegionFile
|
||||
if x < 0 {
|
||||
x += anvil.ChunksWidthRegionFile
|
||||
}
|
||||
z = z % anvil.ChunksWidthRegionFile
|
||||
if z < 0 {
|
||||
z += anvil.ChunksWidthRegionFile
|
||||
}
|
||||
|
||||
f, err := os.Open(fmt.Sprintf("./level/anvil/testdata/securechattestworld/region/r.%v.%v.mca", xmca, zmca))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
mca, err := anvil.ReadChunkHeader(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var n *nbt.Tag
|
||||
n, err = mca.ChunkAt(f, x, z)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var chunk anvil.Chunk
|
||||
err = nbt.Format.Decode(n.Value, &chunk)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var packetChunk *level.Chunk
|
||||
packetChunk, err = chunk.ToStorage(version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
err = packetChunk.WriteChunkData(buffer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b = buffer.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
func Run(args []string) error {
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
|
||||
err := cmd.Parse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *worldPath == "" {
|
||||
slog.Error("no world path specified")
|
||||
return nil
|
||||
}
|
||||
if *output == "" {
|
||||
slog.Error("no output path specified")
|
||||
return nil
|
||||
}
|
||||
|
||||
outFile, err := os.Create(*output)
|
||||
if err != nil {
|
||||
slog.Error("failed to create output file", "error", err)
|
||||
return err
|
||||
}
|
||||
defer outFile.Close()
|
||||
|
||||
w := replay.NewWriter(outFile)
|
||||
|
||||
err = w.WritePacket(&v1_21_11.PlayToClientPacketLogin{
|
||||
EntityId: 73,
|
||||
IsHardcore: false,
|
||||
WorldNames: []string{"minecraft:overworld", "minecraft:the_end", "minecraft:the_nether"},
|
||||
MaxPlayers: 100,
|
||||
ViewDistance: 10,
|
||||
SimulationDistance: 10,
|
||||
ReducedDebugInfo: false,
|
||||
EnableRespawnScreen: true,
|
||||
DoLimitedCrafting: false,
|
||||
WorldState: v1_21_11.PlayToClientSpawnInfo{
|
||||
Dimension: 0,
|
||||
Name: "minecraft:overworld",
|
||||
HashedSeed: -8365436745629239539,
|
||||
Gamemode: "survival",
|
||||
PreviousGamemode: 0xff,
|
||||
IsDebug: false,
|
||||
IsFlat: false,
|
||||
Death: nil,
|
||||
PortalCooldown: 0,
|
||||
SeaLevel: 63,
|
||||
},
|
||||
EnforcesSecureChat: false,
|
||||
}, 0)
|
||||
if err != nil {
|
||||
slog.Error("failed to write login packet", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.WritePacket(&v1_21_11.PlayToClientPacketPosition{
|
||||
TeleportId: 0,
|
||||
X: *spawnX,
|
||||
Y: *spawnY,
|
||||
Z: *spawnZ,
|
||||
Dx: 0,
|
||||
Dy: 0,
|
||||
Dz: 0,
|
||||
Yaw: 0,
|
||||
Pitch: 0,
|
||||
Flags: v1_21_11.PlayToClientPositionUpdateRelatives{},
|
||||
}, 0)
|
||||
if err != nil {
|
||||
slog.Error("failed to write position packet", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
chunkX := int32(*spawnX) >> 4
|
||||
chunkZ := int32(*spawnZ) >> 4
|
||||
|
||||
err = w.WritePacket(&v1_21_11.PlayToClientPacketUpdateViewPosition{
|
||||
ChunkX: chunkX,
|
||||
ChunkZ: chunkZ,
|
||||
}, 0)
|
||||
if err != nil {
|
||||
slog.Error("failed to write view position packet", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = w.WritePacket(&v1_21_11.PlayToClientPacketGameStateChange{
|
||||
Reason: "level_chunks_load_start",
|
||||
}, 0)
|
||||
if err != nil {
|
||||
slog.Error("failed to write game state packet", "error", err)
|
||||
return err
|
||||
}
|
||||
|
||||
radius32 := int32(*radius)
|
||||
|
||||
for x := -radius32; x < radius32; x++ {
|
||||
for z := -radius32; z < radius32; z++ {
|
||||
var chunkData []byte
|
||||
chunkData, err = GetChunkFromMca(x, z, "1.21.11")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if chunkData == nil {
|
||||
continue
|
||||
}
|
||||
OLDpacket := &v1_21_11.PlayToClientPacketMapChunk{}
|
||||
OLDpacket.X = x
|
||||
OLDpacket.Z = z
|
||||
OLDpacket.ChunkData = v1_21_11.ByteArray{Val: chunkData}
|
||||
OLDpacket.BlockLight = FullLight
|
||||
OLDpacket.BlockLightMask = []int64{(1 << 24) - 1}
|
||||
err = w.WritePacket(OLDpacket, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
slog.Info("conversion complete", "output", *output)
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
package registry_data_hunter
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"github.com/admin-else/strom/api"
|
||||
"github.com/admin-else/strom/client"
|
||||
"github.com/admin-else/strom/data"
|
||||
"github.com/admin-else/strom/event"
|
||||
"github.com/admin-else/strom/nbt"
|
||||
"github.com/admin-else/strom/proto"
|
||||
"github.com/admin-else/strom/proto_base"
|
||||
"github.com/admin-else/strom/proto_generated/v1_21_8"
|
||||
"github.com/admin-else/strom/server"
|
||||
"github.com/admin-else/strom/text"
|
||||
)
|
||||
|
||||
func wontFail[T any](v T, err error) T {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
var (
|
||||
Version = "1.21.11"
|
||||
SaveAs = "data/registry/" + Version + ".nbt"
|
||||
|
||||
CompatibleProtocolVersion = wontFail(data.LookUpVersionByName(Version)).Version
|
||||
FinishedConfigErr = errors.New("finished configuration")
|
||||
)
|
||||
|
||||
var Status = wontFail(json.Marshal(server.StatusResponse{
|
||||
Version: server.StatusResponseVersion{
|
||||
Name: nil,
|
||||
Protocol: CompatibleProtocolVersion,
|
||||
},
|
||||
Description: text.Pretty("Registry data hunter"),
|
||||
}))
|
||||
|
||||
type Proxy struct {
|
||||
Client, Servee *proto.Conn
|
||||
Data *nbt.Tag
|
||||
}
|
||||
|
||||
func (p *Proxy) OnAnything(e event.Anything) (err error) {
|
||||
packet, ok := e.Val.(proto_base.EncodeDecodeAble)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
packetInfo, ok := proto.LookupPacketInfoByType(packet)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
switch packetInfo.Direction {
|
||||
case proto_base.ToServer:
|
||||
err = p.Client.Send(packet)
|
||||
case proto_base.ToClient:
|
||||
err = p.Servee.Send(packet)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Proxy) OnFinishConfiguration(_ *v1_21_8.ConfigurationToClientPacketFinishConfiguration) (err error) {
|
||||
err = FinishedConfigErr
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Proxy) OnSelectKnownPacks(data *v1_21_8.ConfigurationToClientPacketCommonSelectKnownPacks) (err error) {
|
||||
var entries []any
|
||||
for _, entry := range data.Packs {
|
||||
e := map[string]any{"Namespace": entry.Namespace, "Id": entry.Id, "Version": entry.Version}
|
||||
entries = append(entries, e)
|
||||
}
|
||||
p.Data.Value.(map[string]any)["KnownPacks"] = entries
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Proxy) OnData(data *v1_21_8.ConfigurationToClientPacketRegistryData) (err error) {
|
||||
d := p.Data.Value.(map[string]any)["Registries"].([]any)
|
||||
var entries []any
|
||||
for _, entry := range data.Entries {
|
||||
if entry.Value != nil {
|
||||
entries = append(entries, map[string]any{"TagType": entry.Key, "Value": entry.Value.Value})
|
||||
} else {
|
||||
entries = append(entries, map[string]any{"TagType": entry.Key})
|
||||
}
|
||||
}
|
||||
d = append(d, map[string]any{"Id": data.Id, "Entries": entries})
|
||||
p.Data.Value.(map[string]any)["Registries"] = d
|
||||
return
|
||||
}
|
||||
|
||||
func (p *Proxy) OnTags(data *v1_21_8.ConfigurationToClientPacketTags) (err error) {
|
||||
var tags []any
|
||||
for _, tag := range data.Tags {
|
||||
var entries []any
|
||||
for _, entry := range tag.Tags.Val {
|
||||
entries = append(entries, map[string]any{"TagName": entry.TagName, "Entries": entry.Entries})
|
||||
}
|
||||
tags = append(tags, map[string]any{"TagType": tag.TagType, "Entries": entries})
|
||||
}
|
||||
p.Data.Value.(map[string]any)["Tags"] = tags
|
||||
return
|
||||
}
|
||||
|
||||
func handleClient(c *proto.Conn) (err error) {
|
||||
acc := api.NewOfflineAccount("RegistryHunter")
|
||||
|
||||
_, err = server.ServeLogin(c, server.WithOtherAccount(acc), server.WithCompatibleVersions(CompatibleProtocolVersion), server.WithRawStatus(Status))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
sockPuppet, err := client.Login(":25565", acc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer sockPuppet.Close()
|
||||
errChan := make(chan error)
|
||||
p := &Proxy{Client: sockPuppet, Servee: c}
|
||||
p.Data.Value = map[string]any{"Registries": []any{}}
|
||||
p.Client.RegisterCritical(p.OnAnything)
|
||||
p.Servee.RegisterCritical(p.OnAnything)
|
||||
p.Client.RegisterCriticalUntilLatest(p.OnData)
|
||||
p.Client.RegisterCriticalUntilLatest(p.OnTags)
|
||||
p.Client.RegisterCriticalUntilLatest(p.OnSelectKnownPacks)
|
||||
p.Client.RegisterCriticalUntilLatest(p.OnFinishConfiguration)
|
||||
|
||||
go func() {
|
||||
errChan <- p.Client.StartConn()
|
||||
}()
|
||||
go func() {
|
||||
errChan <- p.Servee.StartConn()
|
||||
}()
|
||||
err = <-errChan
|
||||
f, err := os.Create(SaveAs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
err = nbt.WriteUnstructuredFile(f, p.Data)
|
||||
slog.Info("saved", "file", SaveAs)
|
||||
return
|
||||
}
|
||||
|
||||
func Run(args []string) error {
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
return server.StartServerWithOnConn(":25566", handleClient)
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package serve_tmcpr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"flag"
|
||||
"io"
|
||||
"log/slog"
|
||||
"math/rand/v2"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/admin-else/strom/event"
|
||||
"github.com/admin-else/strom/proto"
|
||||
"github.com/admin-else/strom/proto/replay"
|
||||
"github.com/admin-else/strom/proto_generated/v1_21_8"
|
||||
"github.com/admin-else/strom/server"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
*proto.Conn
|
||||
*event.Timer
|
||||
}
|
||||
|
||||
var (
|
||||
cmd = flag.NewFlagSet("serve-tmcpr", flag.ContinueOnError)
|
||||
tmcprFile = cmd.String("file", "/tmp/world.tmcpr", "Path to .tmcpr replay file")
|
||||
bindAddr = cmd.String("bind", ":25566", "Address to listen on")
|
||||
)
|
||||
|
||||
func Limbo(c *proto.Conn, tmcprPath string) (err error) {
|
||||
s := &Server{Conn: c}
|
||||
|
||||
_, err = server.ServeLogin(s.Conn, server.WithoutOnlineMode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = server.ServeConfig(s.Conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
f, err := os.Open(tmcprPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
r := replay.NewReader(f)
|
||||
r.Version = c.ProtocolVersion
|
||||
|
||||
start := time.Now()
|
||||
|
||||
for {
|
||||
var packetData []byte
|
||||
var timestamp uint32
|
||||
packetData, timestamp, _, err = r.ReadRaw()
|
||||
if err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
return err
|
||||
}
|
||||
time.Sleep(time.Duration(timestamp)*time.Millisecond - time.Since(start))
|
||||
err = s.SendRaw(packetData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
s.Timer = &event.Timer{}
|
||||
s.Timer.Every(time.Second*15, s.SendKeepAlive)
|
||||
s.Timer.Start(c.Loop)
|
||||
|
||||
return s.StartConn()
|
||||
}
|
||||
|
||||
func (s *Server) SendKeepAlive() error {
|
||||
return s.Send(&v1_21_8.PlayToClientPacketKeepAlive{KeepAliveId: rand.Int64()})
|
||||
}
|
||||
|
||||
func Run(args []string) error {
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
|
||||
err := cmd.Parse(args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if *tmcprFile == "" {
|
||||
slog.Error("no file specified")
|
||||
return nil
|
||||
}
|
||||
|
||||
return server.StartServerWithOnConn(*bindAddr, func(c *proto.Conn) error {
|
||||
return Limbo(c, *tmcprFile)
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package serve_world
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"math/rand/v2"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/admin-else/strom/event"
|
||||
"github.com/admin-else/strom/level"
|
||||
"github.com/admin-else/strom/level/anvil"
|
||||
"github.com/admin-else/strom/nbt"
|
||||
"github.com/admin-else/strom/proto"
|
||||
"github.com/admin-else/strom/proto_generated/v1_21_8"
|
||||
"github.com/admin-else/strom/server"
|
||||
"github.com/admin-else/strom/util"
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
*proto.Conn
|
||||
*event.Timer
|
||||
|
||||
reconnectCalled bool
|
||||
}
|
||||
|
||||
var FullLight [][]uint8
|
||||
|
||||
func init() {
|
||||
light := make([]uint8, 2048)
|
||||
for i := range light {
|
||||
light[i] = 0xFF
|
||||
}
|
||||
|
||||
sectionsPerChunk := 384 / 16
|
||||
FullLight = make([][]uint8, sectionsPerChunk)
|
||||
for i := range sectionsPerChunk {
|
||||
FullLight[i] = light
|
||||
}
|
||||
}
|
||||
|
||||
func GetChunkFromMca(x, z int32, version string) (b []byte, err error) {
|
||||
xmca := util.FloorDiv(x, anvil.ChunksWidthRegionFile)
|
||||
zmca := util.FloorDiv(z, anvil.ChunksWidthRegionFile)
|
||||
x = x % anvil.ChunksWidthRegionFile
|
||||
if x < 0 {
|
||||
x += anvil.ChunksWidthRegionFile
|
||||
}
|
||||
z = z % anvil.ChunksWidthRegionFile
|
||||
if z < 0 {
|
||||
z += anvil.ChunksWidthRegionFile
|
||||
}
|
||||
|
||||
f, err := os.Open(fmt.Sprintf("./level/anvil/testdata/securechattestworld/region/r.%v.%v.mca", xmca, zmca))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer f.Close()
|
||||
mca, err := anvil.ReadChunkHeader(f)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var n *nbt.Tag
|
||||
n, err = mca.ChunkAt(f, x, z)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if n == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var chunk anvil.Chunk
|
||||
err = nbt.Format.Decode(n.Value, &chunk)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var packetChunk *level.Chunk
|
||||
packetChunk, err = chunk.ToStorage(version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
err = packetChunk.WriteChunkData(buffer)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
b = buffer.Bytes()
|
||||
return
|
||||
}
|
||||
|
||||
func Limbo(c *proto.Conn) (err error) {
|
||||
s := &Server{
|
||||
Conn: c,
|
||||
}
|
||||
_, err = server.ServeLogin(s.Conn, server.WithoutOnlineMode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = server.ServeConfig(s.Conn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
login := &v1_21_8.PlayToClientPacketLogin{EntityId: 73, IsHardcore: false, WorldNames: []string{"minecraft:overworld", "minecraft:the_end", "minecraft:the_nether"}, MaxPlayers: 100, ViewDistance: 10, SimulationDistance: 10, ReducedDebugInfo: false, EnableRespawnScreen: true, DoLimitedCrafting: false, WorldState: v1_21_8.PlayToClientSpawnInfo{Dimension: 0, Name: "minecraft:overworld", HashedSeed: -8365436745629239539, Gamemode: "survival", PreviousGamemode: 0xff, IsDebug: false, IsFlat: false, Death: nil, PortalCooldown: 0, SeaLevel: 63}, EnforcesSecureChat: false}
|
||||
err = s.Send(login)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = s.Send(&v1_21_8.PlayToClientPacketPosition{
|
||||
TeleportId: 0,
|
||||
X: 0.5,
|
||||
Y: 100,
|
||||
Z: 0.5,
|
||||
Dx: 0,
|
||||
Dy: 0,
|
||||
Dz: 0,
|
||||
Yaw: 0,
|
||||
Pitch: 0,
|
||||
Flags: v1_21_8.PlayToClientPositionUpdateRelatives{},
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = s.Send(&v1_21_8.PlayToClientPacketUpdateViewPosition{
|
||||
ChunkX: 0,
|
||||
ChunkZ: 0,
|
||||
})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = s.Send(&v1_21_8.PlayToClientPacketGameStateChange{
|
||||
Reason: "level_chunks_load_start",
|
||||
})
|
||||
|
||||
radius := int32(10)
|
||||
|
||||
for x := -radius; x < radius; x++ {
|
||||
for z := -radius; z < radius; z++ {
|
||||
var chunkData []byte
|
||||
chunkData, err = GetChunkFromMca(x, z, c.Version)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if chunkData == nil {
|
||||
continue
|
||||
}
|
||||
OLDpacket := &v1_21_8.PlayToClientPacketMapChunk{}
|
||||
OLDpacket.X = x
|
||||
OLDpacket.Z = z
|
||||
OLDpacket.ChunkData = v1_21_8.ByteArray{Val: chunkData}
|
||||
OLDpacket.BlockLight = FullLight
|
||||
OLDpacket.BlockLightMask = []int64{(1 << 24) - 1}
|
||||
err = s.Send(OLDpacket)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s.Timer = &event.Timer{}
|
||||
s.Timer.Every(time.Second*15, s.SendKeepAlive)
|
||||
s.Timer.Start(c.Loop)
|
||||
|
||||
return s.StartConn()
|
||||
}
|
||||
func (s *Server) SendKeepAlive() (err error) {
|
||||
err = s.Send(&v1_21_8.PlayToClientPacketKeepAlive{KeepAliveId: rand.Int64()})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func Run(args []string) error {
|
||||
slog.SetLogLoggerLevel(slog.LevelDebug)
|
||||
return server.StartServerWithOnConn(":25566", Limbo)
|
||||
}
|
||||
Reference in New Issue
Block a user