bedrocktool/subcommands/world/world.go

628 lines
16 KiB
Go
Raw Normal View History

2022-09-04 14:26:32 +00:00
package world
import (
"context"
"encoding/json"
2022-02-27 10:08:19 +00:00
"flag"
"fmt"
"image"
2022-09-09 12:58:02 +00:00
"image/png"
2023-01-24 21:41:37 +00:00
"math/rand"
2022-08-13 16:09:31 +00:00
"os"
"path"
"strconv"
"strings"
2023-02-08 11:00:36 +00:00
"time"
"github.com/bedrock-tool/bedrocktool/locale"
2023-03-18 11:12:54 +00:00
"github.com/bedrock-tool/bedrocktool/ui/messages"
2022-09-04 14:53:21 +00:00
"github.com/bedrock-tool/bedrocktool/utils"
2023-01-23 18:18:01 +00:00
"github.com/bedrock-tool/bedrocktool/utils/behaviourpack"
2022-09-04 14:26:32 +00:00
"github.com/df-mc/dragonfly/server/block/cube"
2022-03-05 12:10:17 +00:00
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/chunk"
"github.com/df-mc/dragonfly/server/world/mcdb"
2022-04-16 11:02:32 +00:00
"github.com/df-mc/goleveldb/leveldb/opt"
2022-08-12 02:53:43 +00:00
"github.com/go-gl/mathgl/mgl32"
2023-04-01 22:22:50 +00:00
"github.com/repeale/fp-go"
2023-03-25 21:19:14 +00:00
"github.com/sandertv/gophertunnel/minecraft"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
2022-09-02 16:25:07 +00:00
"github.com/sirupsen/logrus"
)
2022-08-12 02:53:43 +00:00
type TPlayerPos struct {
Position mgl32.Vec3
Pitch float32
Yaw float32
HeadYaw float32
}
2022-02-27 10:08:19 +00:00
// the state used for drawing and saving
2022-08-12 16:54:29 +00:00
2023-03-30 11:48:03 +00:00
type worldSettings struct {
// settings
voidGen bool
withPacks bool
saveImage bool
blockUpdates bool
}
type worldState struct {
Dim world.Dimension
chunks map[protocol.ChunkPos]*chunk.Chunk
blockNBT map[protocol.SubChunkPos][]map[string]any
entities map[uint64]*entityState
openItemContainers map[byte]*itemContainer
Name string
}
type serverState struct {
ChunkRadius int
ispre118 bool
worldCounter int
playerInventory []protocol.ItemInstance
PlayerPos TPlayerPos
Name string
}
type worldsServer struct {
2023-01-29 21:20:13 +00:00
ctx context.Context
proxy *utils.ProxyContext
mapUI *MapUI
gui utils.UI
2023-01-29 21:20:13 +00:00
bp *behaviourpack.BehaviourPack
2023-03-30 11:48:03 +00:00
worldState worldState
serverState serverState
settings worldSettings
}
2023-03-30 11:48:03 +00:00
func NewWorldsServer(ctx context.Context, proxy *utils.ProxyContext, ServerName string, ui utils.UI) *worldsServer {
w := &worldsServer{
ctx: ctx,
proxy: proxy,
mapUI: nil,
gui: ui,
bp: behaviourpack.New(ServerName),
2023-02-12 21:22:44 +00:00
2023-03-30 11:48:03 +00:00
serverState: serverState{
ispre118: false,
worldCounter: 0,
ChunkRadius: 0,
playerInventory: nil,
PlayerPos: TPlayerPos{},
Name: ServerName,
},
settings: worldSettings{},
2022-08-12 16:54:29 +00:00
}
w.mapUI = NewMapUI(w)
2023-03-30 11:48:03 +00:00
w.Reset(w.CurrentName())
2023-03-08 11:46:16 +00:00
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.Init{
Handler: nil,
2023-03-08 11:46:16 +00:00
})
2022-09-04 11:13:45 +00:00
return w
}
2023-01-29 21:20:13 +00:00
var dimensionIDMap = map[uint8]world.Dimension{
2022-09-04 00:24:58 +00:00
0: world.Overworld,
1: world.Nether,
2: world.End,
// < 1.18
10: world.Overworld_legacy,
11: world.Nether,
12: world.End,
}
var (
2023-03-25 21:19:14 +00:00
black16x16 = image.NewRGBA(image.Rect(0, 0, 16, 16))
)
2022-03-18 18:22:31 +00:00
2022-02-27 10:08:19 +00:00
func init() {
2023-01-29 21:20:13 +00:00
for i := 3; i < len(black16x16.Pix); i += 4 {
black16x16.Pix[i] = 255
}
2022-09-04 14:26:32 +00:00
utils.RegisterCommand(&WorldCMD{})
2022-08-14 13:18:04 +00:00
}
type WorldCMD struct {
2023-03-30 11:48:03 +00:00
ServerAddress string
Packs bool
EnableVoid bool
SaveImage bool
2022-02-27 10:08:19 +00:00
}
func (*WorldCMD) Name() string { return "worlds" }
func (*WorldCMD) Synopsis() string { return locale.Loc("world_synopsis", nil) }
2022-07-29 16:12:06 +00:00
2023-01-29 21:20:13 +00:00
func (c *WorldCMD) SetFlags(f *flag.FlagSet) {
2023-03-06 01:03:31 +00:00
f.StringVar(&c.ServerAddress, "address", "", locale.Loc("remote_address", nil))
f.BoolVar(&c.Packs, "packs", false, locale.Loc("save_packs_with_world", nil))
f.BoolVar(&c.EnableVoid, "void", true, locale.Loc("enable_void", nil))
f.BoolVar(&c.SaveImage, "image", false, locale.Loc("save_image", nil))
2023-03-05 21:50:58 +00:00
}
func (c *WorldCMD) Execute(ctx context.Context, ui utils.UI) error {
serverAddress, hostname, err := ui.ServerInput(ctx, c.ServerAddress)
2022-03-05 12:10:17 +00:00
if err != nil {
return err
2022-03-05 12:10:17 +00:00
}
2023-03-06 01:03:31 +00:00
proxy, err := utils.NewProxy()
2023-02-12 21:22:44 +00:00
if err != nil {
return err
2023-02-12 21:22:44 +00:00
}
2023-03-30 11:48:03 +00:00
w := NewWorldsServer(ctx, proxy, hostname, ui)
w.settings = worldSettings{
voidGen: c.EnableVoid,
withPacks: c.Packs,
saveImage: c.SaveImage,
}
2022-09-03 17:32:30 +00:00
2023-01-24 11:50:27 +00:00
proxy.AlwaysGetPacks = true
2023-03-25 21:19:14 +00:00
proxy.GameDataModifier = func(gd *minecraft.GameData) {
gd.ClientSideGeneration = false
}
2022-09-04 14:26:32 +00:00
proxy.ConnectCB = w.OnConnect
2023-03-23 19:39:47 +00:00
proxy.OnClientConnect = func(hasClient bool) {
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetUIState(messages.UIStateConnecting))
2023-03-14 01:07:39 +00:00
}
2023-03-23 19:39:47 +00:00
proxy.PacketCB = func(pk packet.Packet, toServer bool, _ time.Time) (packet.Packet, error) {
2023-01-29 21:20:13 +00:00
forward := true
2022-09-03 17:32:30 +00:00
if toServer {
// from client
pk = w.processItemPacketsClient(pk, &forward)
pk = w.processMapPacketsClient(pk, &forward)
2022-09-03 17:32:30 +00:00
} else {
// from server
2023-03-18 21:30:44 +00:00
switch pk := pk.(type) {
case *packet.ChunkRadiusUpdated:
2023-03-30 11:48:03 +00:00
w.serverState.ChunkRadius = int(pk.ChunkRadius)
2023-03-18 21:30:44 +00:00
pk.ChunkRadius = 80
}
pk = w.processItemPacketsServer(pk)
pk = w.ProcessChunkPackets(pk)
pk = w.ProcessEntityPackets(pk)
2022-09-05 15:40:03 +00:00
}
2022-09-05 15:40:03 +00:00
if !forward {
return nil, nil
2022-09-03 17:32:30 +00:00
}
return pk, nil
2022-09-04 13:24:55 +00:00
}
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetUIState(messages.UIStateConnect))
2023-02-12 21:22:44 +00:00
err = w.proxy.Run(ctx, serverAddress)
if err != nil {
return err
}
w.SaveAndReset()
2023-04-01 22:22:50 +00:00
ui.Message(messages.SetUIState(messages.UIStateFinished))
return nil
2022-02-27 10:08:19 +00:00
}
2023-03-30 11:48:03 +00:00
func (w *worldsServer) SetPlayerPos(Position mgl32.Vec3, Pitch, Yaw, HeadYaw float32) {
last := w.serverState.PlayerPos
current := TPlayerPos{
2022-08-12 02:53:43 +00:00
Position: Position,
Pitch: Pitch,
Yaw: Yaw,
HeadYaw: HeadYaw,
}
2023-03-30 11:48:03 +00:00
w.serverState.PlayerPos = current
2022-08-18 13:08:44 +00:00
2023-03-30 11:48:03 +00:00
if int(last.Position.X()) != int(current.Position.X()) || int(last.Position.Z()) != int(current.Position.Z()) {
w.mapUI.SchedRedraw()
2022-08-18 13:08:44 +00:00
}
2022-03-18 18:36:44 +00:00
}
2023-03-30 11:48:03 +00:00
func (w *worldsServer) setVoidGen(val bool, fromUI bool) bool {
w.settings.voidGen = val
2023-04-01 22:22:50 +00:00
var s = locale.Loc("void_generator_false", nil)
2023-03-30 11:48:03 +00:00
if w.settings.voidGen {
2023-03-08 11:46:16 +00:00
s = locale.Loc("void_generator_true", nil)
}
w.proxy.SendMessage(s)
if !fromUI {
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetVoidGen{
2023-03-30 11:48:03 +00:00
Value: w.settings.voidGen,
2023-03-08 11:46:16 +00:00
})
}
return true
}
2023-03-30 11:48:03 +00:00
func (w *worldsServer) setWorldName(val string, fromUI bool) bool {
w.worldState.Name = val
w.proxy.SendMessage(locale.Loc("worldname_set", locale.Strmap{"Name": w.worldState.Name}))
2023-03-08 11:46:16 +00:00
if !fromUI {
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetWorldName{
2023-03-30 11:48:03 +00:00
WorldName: w.worldState.Name,
2023-03-08 11:46:16 +00:00
})
}
return true
}
2023-03-30 11:48:03 +00:00
func (w *worldsServer) CurrentName() string {
worldName := "world"
if w.serverState.worldCounter > 1 {
worldName = fmt.Sprintf("world-%d", w.serverState.worldCounter)
}
return worldName
}
func (w *worldsServer) Reset(newName string) {
w.worldState = worldState{
Dim: nil,
chunks: make(map[protocol.ChunkPos]*chunk.Chunk),
blockNBT: make(map[protocol.SubChunkPos][]map[string]any),
entities: make(map[uint64]*entityState),
openItemContainers: make(map[byte]*itemContainer),
Name: newName,
}
w.mapUI.Reset()
2022-08-14 13:18:04 +00:00
}
2023-01-29 21:20:13 +00:00
// SaveAndReset writes the world to a folder, resets all the chunks
2023-03-30 11:48:03 +00:00
func (w *worldsServer) SaveAndReset() {
2023-03-23 19:39:47 +00:00
// cull empty chunks
2023-03-30 11:48:03 +00:00
keys := make([]protocol.ChunkPos, 0, len(w.worldState.chunks))
for cp := range w.worldState.chunks {
2023-03-14 01:07:39 +00:00
keys = append(keys, cp)
}
2023-04-01 22:22:50 +00:00
for _, cp := range fp.Filter(func(cp protocol.ChunkPos) bool {
return fp.Some(func(sc *chunk.SubChunk) bool {
return !sc.Empty()
})(w.worldState.chunks[cp].Sub())
})(keys) {
delete(w.worldState.chunks, cp)
2023-03-14 01:07:39 +00:00
}
2023-04-01 22:22:50 +00:00
2023-03-30 11:48:03 +00:00
if len(w.worldState.chunks) == 0 {
w.Reset(w.CurrentName())
2023-01-24 21:41:37 +00:00
return
}
2023-03-11 15:05:26 +00:00
2023-03-30 11:48:03 +00:00
logrus.Infof(locale.Loc("saving_world", locale.Strmap{"Name": w.worldState.Name, "Count": len(w.worldState.chunks)}))
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SavingWorld{
2023-03-30 11:48:03 +00:00
Name: w.worldState.Name,
Chunks: len(w.worldState.chunks),
2023-03-28 13:22:11 +00:00
})
2022-08-16 15:34:55 +00:00
// open world
2023-03-30 11:48:03 +00:00
folder := path.Join("worlds", fmt.Sprintf("%s/%s", w.serverState.Name, w.worldState.Name))
os.RemoveAll(folder)
os.MkdirAll(folder, 0o777)
2022-09-04 00:24:58 +00:00
provider, err := mcdb.New(logrus.StandardLogger(), folder, opt.DefaultCompression)
if err != nil {
2022-09-04 23:40:55 +00:00
logrus.Fatal(err)
}
2022-08-16 15:34:55 +00:00
// save chunk data
2023-03-30 11:48:03 +00:00
for cp, c := range w.worldState.chunks {
provider.SaveChunk((world.ChunkPos)(cp), c, w.worldState.Dim)
}
2022-08-16 15:34:55 +00:00
// save block nbt data
blockNBT := make(map[world.ChunkPos][]map[string]any)
2023-03-30 11:48:03 +00:00
for scp, v := range w.worldState.blockNBT { // 3d to 2d
cp := world.ChunkPos{scp.X(), scp.Z()}
blockNBT[cp] = append(blockNBT[cp], v...)
}
for cp, v := range blockNBT {
2023-03-30 11:48:03 +00:00
err = provider.SaveBlockNBT(cp, v, w.worldState.Dim)
if err != nil {
logrus.Error(err)
}
}
2023-03-23 19:39:47 +00:00
// save entities
chunkEntities := make(map[world.ChunkPos][]world.Entity)
2023-03-30 11:48:03 +00:00
for _, es := range w.worldState.entities {
cp := world.ChunkPos{int32(es.Position.X()) >> 4, int32(es.Position.Z()) >> 4}
2023-01-29 21:20:13 +00:00
chunkEntities[cp] = append(chunkEntities[cp], es.ToServerEntity())
}
for cp, v := range chunkEntities {
2023-03-30 11:48:03 +00:00
err = provider.SaveEntities(cp, v, w.worldState.Dim)
if err != nil {
2022-09-04 23:40:55 +00:00
logrus.Error(err)
}
}
2023-03-28 13:22:11 +00:00
err = provider.SaveLocalPlayerData(w.playerData())
if err != nil {
logrus.Error(err)
}
2023-03-25 21:19:14 +00:00
2023-03-30 11:48:03 +00:00
playerPos := w.proxy.Server.GameData().PlayerPosition
spawnPos := cube.Pos{int(playerPos.X()), int(playerPos.Y()), int(playerPos.Z())}
2022-08-16 15:34:55 +00:00
// write metadata
s := provider.Settings()
2023-03-28 13:22:11 +00:00
s.Spawn = spawnPos
2023-03-30 11:48:03 +00:00
s.Name = w.worldState.Name
2022-08-16 15:34:55 +00:00
// set gamerules
2022-08-13 16:09:31 +00:00
ld := provider.LevelDat()
2022-09-04 14:26:32 +00:00
gd := w.proxy.Server.GameData()
for _, gr := range gd.GameRules {
2022-08-13 14:30:46 +00:00
switch gr.Name {
2022-08-13 16:09:31 +00:00
case "commandblockoutput":
ld.CommandBlockOutput = gr.Value.(bool)
case "maxcommandchainlength":
ld.MaxCommandChainLength = int32(gr.Value.(uint32))
case "commandblocksenabled":
ld.CommandsEnabled = gr.Value.(bool)
case "dodaylightcycle":
ld.DoDayLightCycle = gr.Value.(bool)
case "doentitydrops":
ld.DoEntityDrops = gr.Value.(bool)
case "dofiretick":
ld.DoFireTick = gr.Value.(bool)
case "domobloot":
ld.DoMobLoot = gr.Value.(bool)
case "domobspawning":
ld.DoMobSpawning = gr.Value.(bool)
case "dotiledrops":
ld.DoTileDrops = gr.Value.(bool)
case "doweathercycle":
ld.DoWeatherCycle = gr.Value.(bool)
case "drowningdamage":
ld.DrowningDamage = gr.Value.(bool)
case "doinsomnia":
ld.DoInsomnia = gr.Value.(bool)
case "falldamage":
ld.FallDamage = gr.Value.(bool)
case "firedamage":
ld.FireDamage = gr.Value.(bool)
case "keepinventory":
ld.KeepInventory = gr.Value.(bool)
case "mobgriefing":
ld.MobGriefing = gr.Value.(bool)
case "pvp":
ld.PVP = gr.Value.(bool)
case "showcoordinates":
ld.ShowCoordinates = gr.Value.(bool)
case "naturalregeneration":
ld.NaturalRegeneration = gr.Value.(bool)
case "tntexplodes":
ld.TNTExplodes = gr.Value.(bool)
case "sendcommandfeedback":
ld.SendCommandFeedback = gr.Value.(bool)
case "randomtickspeed":
ld.RandomTickSpeed = int32(gr.Value.(uint32))
case "doimmediaterespawn":
ld.DoImmediateRespawn = gr.Value.(bool)
case "showdeathmessages":
ld.ShowDeathMessages = gr.Value.(bool)
case "functioncommandlimit":
ld.FunctionCommandLimit = int32(gr.Value.(uint32))
case "spawnradius":
ld.SpawnRadius = int32(gr.Value.(uint32))
case "showtags":
ld.ShowTags = gr.Value.(bool)
case "freezedamage":
ld.FreezeDamage = gr.Value.(bool)
case "respawnblocksexplode":
ld.RespawnBlocksExplode = gr.Value.(bool)
case "showbordereffect":
ld.ShowBorderEffect = gr.Value.(bool)
2022-08-13 14:30:46 +00:00
// todo
2022-08-13 16:09:31 +00:00
default:
logrus.Warnf(locale.Loc("unknown_gamerule", locale.Strmap{"Name": gr.Name}))
2022-08-13 14:30:46 +00:00
}
}
ld.RandomSeed = int64(gd.WorldSeed)
2022-08-16 15:34:55 +00:00
// void world
2023-03-30 11:48:03 +00:00
if w.settings.voidGen {
ld.FlatWorldLayers = `{"biome_id":1,"block_layers":[{"block_data":0,"block_id":0,"count":1},{"block_data":0,"block_id":0,"count":2},{"block_data":0,"block_id":0,"count":1}],"encoding_version":3,"structure_options":null}`
ld.Generator = 2
}
if w.bp.HasContent() {
if ld.Experiments == nil {
ld.Experiments = map[string]any{}
}
ld.Experiments["data_driven_items"] = true
ld.Experiments["experiments_ever_used"] = true
ld.Experiments["saved_with_toggled_experiments"] = true
}
provider.SaveSettings(s)
2023-03-14 01:07:39 +00:00
if err = provider.Close(); err != nil {
logrus.Error(err)
}
2023-03-30 11:48:03 +00:00
w.serverState.worldCounter += 1
2022-08-13 16:09:31 +00:00
2023-01-24 11:50:27 +00:00
type dep struct {
2023-01-29 21:20:13 +00:00
PackID string `json:"pack_id"`
2023-01-24 11:50:27 +00:00
Version [3]int `json:"version"`
}
2023-01-29 21:20:13 +00:00
addPacksJSON := func(name string, deps []dep) {
2023-01-24 11:50:27 +00:00
f, err := os.Create(path.Join(folder, name))
if err != nil {
logrus.Error(err)
return
}
defer f.Close()
if err := json.NewEncoder(f).Encode(deps); err != nil {
logrus.Error(err)
return
}
}
// save behaviourpack
if w.bp.HasContent() {
2023-03-30 11:48:03 +00:00
name := strings.ReplaceAll(w.serverState.Name, "./", "")
2023-03-18 11:12:54 +00:00
name = strings.ReplaceAll(name, "/", "-")
2023-01-29 21:20:13 +00:00
packFolder := path.Join(folder, "behavior_packs", name)
os.MkdirAll(packFolder, 0o755)
2023-01-24 11:50:27 +00:00
for _, p := range w.proxy.Server.ResourcePacks() {
p := utils.PackFromBase(p)
w.bp.CheckAddLink(p)
}
2023-01-24 11:50:27 +00:00
2023-01-29 21:20:13 +00:00
w.bp.Save(packFolder)
addPacksJSON("world_behavior_packs.json", []dep{{
PackID: w.bp.Manifest.Header.UUID,
2023-01-24 11:50:27 +00:00
Version: w.bp.Manifest.Header.Version,
}})
// force resource packs for worlds with custom blocks
2023-03-30 11:48:03 +00:00
w.settings.withPacks = true
}
// add resource packs
2023-03-30 11:48:03 +00:00
if w.settings.withPacks {
packs, err := utils.GetPacks(w.proxy.Server)
if err != nil {
logrus.Error(err)
} else {
2023-03-30 11:48:03 +00:00
var rdeps []dep
for k, p := range packs {
2023-03-24 19:45:53 +00:00
if p.Encrypted() && !p.CanDecrypt() {
logrus.Warnf("Cant add %s, it is encrypted", p.Name())
continue
}
logrus.Infof(locale.Loc("adding_pack", locale.Strmap{"Name": k}))
2023-01-29 21:20:13 +00:00
packFolder := path.Join(folder, "resource_packs", p.Name())
os.MkdirAll(packFolder, 0o755)
2023-03-30 11:48:03 +00:00
utils.UnpackZip(p, int64(p.Len()), packFolder)
rdeps = append(rdeps, dep{
PackID: p.Manifest().Header.UUID,
Version: p.Manifest().Header.Version,
})
2023-02-05 16:41:06 +00:00
}
2023-03-30 11:48:03 +00:00
_ = rdeps
2023-03-25 21:19:14 +00:00
/*
if len(rdeps) > 0 {
addPacksJSON("world_resource_packs.json", rdeps)
}
*/
}
2023-01-23 18:18:01 +00:00
}
2023-03-30 11:48:03 +00:00
if w.settings.saveImage {
2022-09-09 12:58:02 +00:00
f, _ := os.Create(folder + ".png")
png.Encode(f, w.mapUI.ToImage())
2022-09-09 13:23:45 +00:00
f.Close()
2022-09-09 12:58:02 +00:00
}
2022-08-16 15:34:55 +00:00
// zip it
2022-08-13 16:09:31 +00:00
filename := folder + ".mcworld"
2022-09-04 14:26:32 +00:00
if err := utils.ZipFolder(filename, folder); err != nil {
2023-03-30 11:48:03 +00:00
logrus.Error(err)
2022-08-13 16:09:31 +00:00
}
logrus.Info(locale.Loc("saved", locale.Strmap{"Name": filename}))
2023-03-14 01:07:39 +00:00
//os.RemoveAll(folder)
2023-03-30 11:48:03 +00:00
w.Reset(w.CurrentName())
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetUIState(messages.UIStateMain))
}
2023-03-30 11:48:03 +00:00
func (w *worldsServer) OnConnect(err error) bool {
2023-04-01 22:22:50 +00:00
w.gui.Message(messages.SetUIState(messages.UIStateMain))
2023-03-14 01:07:39 +00:00
2023-02-22 15:48:24 +00:00
if err != nil {
return false
}
2022-09-05 15:40:03 +00:00
gd := w.proxy.Server.GameData()
2023-03-30 11:48:03 +00:00
w.serverState.ChunkRadius = int(gd.ChunkRadius)
w.proxy.ClientWritePacket(&packet.ChunkRadiusUpdated{
ChunkRadius: 80,
})
2022-09-05 15:40:03 +00:00
2023-01-24 21:41:37 +00:00
world.InsertCustomItems(gd.Items)
for _, ie := range gd.Items {
w.bp.AddItem(ie)
}
2023-01-29 21:20:13 +00:00
mapItemID, _ := world.ItemRidByName("minecraft:filled_map")
MapItemPacket.Content[0].Stack.ItemType.NetworkID = mapItemID
2023-01-24 21:41:37 +00:00
if gd.ServerAuthoritativeInventory {
2023-01-29 21:20:13 +00:00
MapItemPacket.Content[0].StackNetworkID = 0xffff + rand.Int31n(0xfff)
2023-01-24 21:41:37 +00:00
}
2022-10-20 23:46:18 +00:00
if len(gd.CustomBlocks) > 0 {
logrus.Info(locale.Loc("using_customblocks", nil))
2023-01-23 18:18:01 +00:00
for _, be := range gd.CustomBlocks {
w.bp.AddBlock(be)
}
// telling the chunk code what custom blocks there are so it can generate offsets
world.InsertCustomBlocks(gd.CustomBlocks)
2022-10-20 23:46:18 +00:00
}
2022-08-17 18:04:13 +00:00
{ // check game version
2022-08-17 13:11:22 +00:00
gv := strings.Split(gd.BaseGameVersion, ".")
2022-09-03 17:32:30 +00:00
var err error
2022-08-17 13:11:22 +00:00
if len(gv) > 1 {
var ver int
ver, err = strconv.Atoi(gv[1])
2023-03-30 11:48:03 +00:00
w.serverState.ispre118 = ver < 18
2022-08-17 13:11:22 +00:00
}
if err != nil || len(gv) <= 1 {
logrus.Info(locale.Loc("guessing_version", nil))
2022-08-17 13:11:22 +00:00
}
2022-09-03 17:32:30 +00:00
2023-01-29 21:20:13 +00:00
dimensionID := gd.Dimension
2023-03-30 11:48:03 +00:00
if w.serverState.ispre118 {
logrus.Info(locale.Loc("using_under_118", nil))
2023-01-29 21:20:13 +00:00
dimensionID += 10
2022-09-03 17:32:30 +00:00
}
2023-03-30 11:48:03 +00:00
w.worldState.Dim = dimensionIDMap[uint8(dimensionID)]
}
w.proxy.SendMessage(locale.Loc("use_setname", nil))
2023-03-23 19:39:47 +00:00
w.proxy.AddCommand(utils.IngameCommand{
Exec: func(cmdline []string) bool {
2023-03-08 11:46:16 +00:00
return w.setWorldName(strings.Join(cmdline, " "), false)
},
2022-09-04 14:26:32 +00:00
Cmd: protocol.Command{
2022-09-04 00:24:58 +00:00
Name: "setname",
Description: locale.Loc("setname_desc", nil),
2023-03-27 12:11:40 +00:00
Overloads: []protocol.CommandOverload{{
Parameters: []protocol.CommandParameter{{
Name: "name",
Type: protocol.CommandArgTypeString,
Optional: false,
}},
}},
2022-09-04 00:24:58 +00:00
},
})
2023-03-23 19:39:47 +00:00
w.proxy.AddCommand(utils.IngameCommand{
Exec: func(cmdline []string) bool {
2023-03-30 11:48:03 +00:00
return w.setVoidGen(!w.settings.voidGen, false)
},
2022-09-04 14:26:32 +00:00
Cmd: protocol.Command{
2022-09-04 00:24:58 +00:00
Name: "void",
Description: locale.Loc("void_desc", nil),
2022-09-04 00:24:58 +00:00
},
})
2023-02-22 15:48:24 +00:00
2023-03-23 19:39:47 +00:00
w.mapUI.Start()
2023-02-22 15:48:24 +00:00
return true
2022-09-03 17:32:30 +00:00
}