diff --git a/go.mod b/go.mod index e90fbec..d704cb6 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( require ( github.com/Shopify/go-lua v0.0.0-20221004153744-91867de107cf - github.com/aimjel/minecraft v0.0.0-20230927222750-0a432da348ec + github.com/aimjel/minecraft v0.0.0-20230928175911-f477127f6069 github.com/dop251/goja v0.0.0-20230919151941-fc55792775de ) diff --git a/go.sum b/go.sum index f0d8bd8..b4a57ab 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/aimjel/minecraft v0.0.0-20230927182639-1fa3dd7aeebc h1:irjh4/oH9vWvkO github.com/aimjel/minecraft v0.0.0-20230927182639-1fa3dd7aeebc/go.mod h1:/Y9/YBqxNOU7IFInEjDbsCVkdPNYJCPxC26jK+w3Phc= github.com/aimjel/minecraft v0.0.0-20230927222750-0a432da348ec h1:aFUC1sZUBSlOtIniOxDWN2orepj9/dSxSAdqVtdVNcE= github.com/aimjel/minecraft v0.0.0-20230927222750-0a432da348ec/go.mod h1:/Y9/YBqxNOU7IFInEjDbsCVkdPNYJCPxC26jK+w3Phc= +github.com/aimjel/minecraft v0.0.0-20230928175911-f477127f6069 h1:mDe3BVKwhXXuIXb/pzaZvXugDBGmJ9uUHp1jfDtI21E= +github.com/aimjel/minecraft v0.0.0-20230928175911-f477127f6069/go.mod h1:/Y9/YBqxNOU7IFInEjDbsCVkdPNYJCPxC26jK+w3Phc= github.com/chzyer/logex v1.2.0/go.mod h1:9+9sk7u7pGNWYMkh0hdiL++6OeibzJccyQU4p4MedaY= github.com/chzyer/readline v1.5.0/go.mod h1:x22KAscuvRqlLoK9CsoYsmxoXZMMFVyOl86cAH8qUic= github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= diff --git a/main.go b/main.go index 56fcea3..24f2f38 100644 --- a/main.go +++ b/main.go @@ -42,13 +42,13 @@ func start(cfg server.ServerConfig) { } func main() { - log.Info("Starting Dynamite Server") + log.Info("Starting Dynamite 1.20.1 Server") var cfg server.ServerConfig config.LoadConfig("config.toml", &cfg) log.Debug("Loaded config") if !cfg.Online && !util.HasArg("-no_offline_warn") { - log.Warn("Offline mode is insecure and you should not use it unless for a private server.") + log.Warn("Offline mode is insecure and you should not use it unless for a private server.\nRead https://github.com/DynamiteMC/Dynamite/wiki/Why-you-shouldn't-use-offline-mode") } if cfg.Web.Enable { diff --git a/server/broadcast.go b/server/broadcast.go index 4a2bc5a..e83b7c8 100644 --- a/server/broadcast.go +++ b/server/broadcast.go @@ -1,26 +1,75 @@ package server import ( + "fmt" + "math" + "github.com/aimjel/minecraft/packet" "github.com/aimjel/minecraft/player" + "github.com/dynamitemc/dynamite/server/commands" ) func (srv *Server) GlobalBroadcast(pk packet.Packet) { - srv.mu.RLock() - defer srv.mu.RUnlock() for _, p := range srv.Players { p.session.SendPacket(pk) } } +func (srv *Server) GlobalMessage(message string) { + srv.GlobalBroadcast(&packet.SystemChatMessage{ + Content: message, + }) + fmt.Println(commands.ParseChat(message)) +} + +func (p *PlayerController) BroadcastMovement(oldx, oldy, oldz float64) { + x1, y1, z1 := p.Position() + ong := p.OnGround() + for _, pl := range p.Server.Players { + if pl.UUID == p.UUID { + continue + } + x2, y2, z2 := pl.Position() + distance := math.Sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1) + (z2-z1)*(z2-z1)) + if pl.ClientSettings().ViewDistance*16 > int8(distance) { + continue + } + pl.session.SendPacket(&packet.EntityPosition{ + EntityID: p.player.EntityID, + X: (int16(x1)*32 - int16(oldx)*32) * 128, + Y: (int16(y1)*32 - int16(oldy)*32) * 128, + Z: (int16(z1)*32 - int16(oldz)*32) * 128, + OnGround: ong, + }) + } +} + +func (p *PlayerController) Spawn() { + x, y, z := p.Position() + yaw, pitch := p.Rotation() + for _, pl := range p.Server.Players { + if pl.UUID == p.UUID { + continue + } + fmt.Println(p.player.EntityID, pl.player.EntityID) + pl.session.SendPacket(&packet.SpawnPlayer{ + EntityID: p.player.EntityID, + PlayerUUID: p.session.Info().UUID, + X: x, + Y: y, + Z: z, + Yaw: byte(yaw), + Pitch: byte(pitch), + }) + } +} + func (srv *Server) PlayerlistUpdate() { var players []player.Info - srv.mu.RLock() for _, p := range srv.Players { p.session.Info().Listed = true players = append(players, *p.session.Info()) } - srv.mu.RUnlock() srv.GlobalBroadcast(&packet.PlayerInfoUpdate{ Actions: 0x01 | 0x08, Players: players, diff --git a/server/network/handlers/ChatCommand.go b/server/network/handlers/ChatCommand.go index fafa16c..e10cafe 100644 --- a/server/network/handlers/ChatCommand.go +++ b/server/network/handlers/ChatCommand.go @@ -10,6 +10,7 @@ import ( type controller interface { SystemChatMessage(s string) error HasPermissions(perms []string) bool + BroadcastMovement(oldx, oldy, oldz float64) } func ChatCommandPacket(controller controller, graph *commands.Graph, content string) { diff --git a/server/network/handlers/PlayerMovement.go b/server/network/handlers/PlayerMovement.go index 7f14a6d..0dfa47f 100644 --- a/server/network/handlers/PlayerMovement.go +++ b/server/network/handlers/PlayerMovement.go @@ -6,13 +6,16 @@ import ( ) func PlayerMovement( + controller controller, state *player.Player, pk packet.Packet, ) { switch pk := pk.(type) { case *packet.PlayerPosition: { - state.X, state.Y, state.Z, state.OnGround = pk.X, pk.FeetY, pk.Z, pk.OnGround + state.OnGround = pk.OnGround + controller.BroadcastMovement(state.X, state.Y, state.Z) + state.X, state.Y, state.Z = pk.X, pk.FeetY, pk.Z } case *packet.PlayerPositionRotation: { diff --git a/server/player_controller.go b/server/player_controller.go index 1d9f5c8..75b5502 100644 --- a/server/player_controller.go +++ b/server/player_controller.go @@ -1,6 +1,8 @@ package server import ( + "math/rand" + "github.com/aimjel/minecraft/packet" "github.com/dynamitemc/dynamite/server/commands" "github.com/dynamitemc/dynamite/server/player" @@ -34,7 +36,14 @@ func (p *PlayerController) JoinDimension(d *world.Dimension) error { }); err != nil { return err } + p.session.SendPacket(&packet.PluginMessage{ + Channel: "minecraft:brand", + Data: []byte("Dynamite 1.20.1"), + }) + p.Teleport(100, 100, 100, 0, 0) + p.SetGameMode(1) + p.Spawn() return p.session.SendPacket(&packet.SetDefaultSpawnPosition{}) } @@ -90,3 +99,8 @@ func (p *PlayerController) SendCommands(graph *commands.Graph) { } p.session.SendPacket(graph.Data()) } + +func (p *PlayerController) Keepalive() { + id := rand.Int63() * 100 + p.session.SendPacket(&packet.KeepAlive{PayloadID: id}) +} diff --git a/server/server.go b/server/server.go index 585fc36..30c1659 100644 --- a/server/server.go +++ b/server/server.go @@ -1,9 +1,12 @@ package server import ( + "crypto/md5" "errors" "os" + "strings" "sync" + "time" "github.com/google/uuid" @@ -53,6 +56,18 @@ func (srv *Server) Start() error { } } +func NameToUUID(name string) uuid.UUID { + version := 3 + h := md5.New() + h.Write([]byte("OfflinePlayer:")) + h.Write([]byte(name)) + var id uuid.UUID + h.Sum(id[:0]) + id[6] = (id[6] & 0x0f) | uint8((version&0xf)<<4) + id[8] = (id[8] & 0x3f) | 0x80 // RFC 4122 variant + return id +} + func (srv *Server) handleNewConn(conn *minecraft.Conn) { if srv.ValidateConn(conn) { return @@ -71,17 +86,24 @@ func (srv *Server) handleNewConn(conn *minecraft.Conn) { } } - cntrl.SendCommands(srv.CommandGraph) + //cntrl.SendCommands(srv.CommandGraph) + srv.addPlayer(cntrl) if err := cntrl.JoinDimension(srv.world.DefaultDimension()); err != nil { //TODO log error conn.Close(err) srv.Logger.Error("Failed to join player to dimension %s", err) } - srv.addPlayer(cntrl) + go func() { + ticker := time.NewTicker(10 * time.Second) + for range ticker.C { + cntrl.Keepalive() + } + }() if err := sesh.HandlePackets(cntrl); err != nil { srv.Logger.Info("[%s] Player %s (%s) has left the server", conn.RemoteAddr().String(), conn.Info.Name, cntrl.UUID) + srv.GlobalMessage(srv.Translate(srv.Config.Messages.PlayerLeave, map[string]string{"player": conn.Info.Name})) srv.PlayerlistRemove(conn.Info.UUID) delete(srv.Players, cntrl.UUID) //gui.RemovePlayer(cntrl.UUID) @@ -89,20 +111,28 @@ func (srv *Server) handleNewConn(conn *minecraft.Conn) { } func (srv *Server) addPlayer(p *PlayerController) { - srv.mu.Lock() + srv.mu.RLock() srv.Players[p.UUID] = p - srv.mu.Unlock() + srv.mu.RUnlock() srv.PlayerlistUpdate() //gui.AddPlayer(p.session.Info().Name, p.UUID) srv.Logger.Info("[%s] Player %s (%s) has joined the server", p.session.RemoteAddr().String(), p.session.Info().Name, p.UUID) + srv.GlobalMessage(srv.Translate(srv.Config.Messages.PlayerJoin, map[string]string{"player": p.Name()})) } func (srv *Server) GetCommandGraph() *commands.Graph { return srv.CommandGraph } +func (srv *Server) Translate(msg string, data map[string]string) string { + for k, v := range data { + msg = strings.ReplaceAll(msg, "%"+k+"%", v) + } + return msg +} + func (srv *Server) Reload() error { // load player data var files = []string{"whitelist.json", "banned_players.json", "ops.json", "banned_ips.json"} diff --git a/server/session.go b/server/session.go index e671287..2206696 100644 --- a/server/session.go +++ b/server/session.go @@ -38,7 +38,7 @@ func (s *Session) HandlePackets(controller *PlayerController) error { switch p.ID() { case 0x14, 0x15, 0x16, 0x17: { - handlers.PlayerMovement(s.state, p) + handlers.PlayerMovement(controller, s.state, p) } } }