diff --git a/core/db/players.go b/core/db/players.go index 6d88a24..0e799b1 100644 --- a/core/db/players.go +++ b/core/db/players.go @@ -122,7 +122,7 @@ const ( ) func (db *DBHandler) readPlayer(rows *sql.Rows) (*entity.Player, error) { - plr := entity.Player{ActiveNanoSlotNum: -1} + plr := entity.Player{ActiveNanoSlotNum: 0} if err := rows.Scan( &plr.PlayerID, &plr.AccountID, &plr.Slot, &plr.PCStyle.SzFirstName, &plr.PCStyle.SzLastName, diff --git a/core/entity/chunk.go b/core/entity/chunk.go index 5549494..d33eead 100644 --- a/core/entity/chunk.go +++ b/core/entity/chunk.go @@ -28,11 +28,16 @@ func (c *Chunk) RemoveEntity(entity Entity) { // send packet to all peers in this chunk and kill each peer if error func (c *Chunk) SendPacket(typeID uint32, pkt ...interface{}) { + c.SendPacketExclude(nil, typeID, pkt...) +} + +func (c *Chunk) SendPacketExclude(exclude Entity, typeID uint32, pkt ...interface{}) { c.lock.Lock() defer c.lock.Unlock() for entity := range c.Entities { - if entity.GetKind() != ENTITY_KIND_PLAYER { + // only send to players, and exclude the player that sent the packet + if entity.GetKind() != ENTITY_KIND_PLAYER || entity == exclude { continue } diff --git a/core/entity/player.go b/core/entity/player.go index 95bfbc7..c610ebb 100644 --- a/core/entity/player.go +++ b/core/entity/player.go @@ -122,6 +122,6 @@ func (plr *Player) GetAppearanceData() protocol.SPCAppearanceData { PCStyle: plr.PCStyle, IPCState: plr.IPCState, ItemEquip: plr.Equip, - Nano: protocol.SNano{}, //plr.Nanos[plr.ActiveNanoSlotNum], + Nano: plr.Nanos[plr.ActiveNanoSlotNum], } } diff --git a/shard/chunks.go b/shard/chunks.go index dfa0efb..f3b1aa6 100644 --- a/shard/chunks.go +++ b/shard/chunks.go @@ -23,9 +23,11 @@ func (server *ShardServer) getViewableChunks(pos entity.ChunkPosition) []*entity return chunks } -func (server *ShardServer) sendPacketToViewableChunks(plr *entity.Player, typeID uint32, pkt ...interface{}) error { - for _, chunk := range server.getViewableChunks(plr.Chunk) { - chunk.SendPacket(typeID, pkt...) +// sends a packet to all peers in the given chunks, excluding the given peer +func (server *ShardServer) sendOthersPacket(plr *entity.Player, typeID uint32, pkt ...interface{}) error { + chunks := server.getViewableChunks(plr.Chunk) + for _, chunk := range chunks { + chunk.SendPacketExclude(plr, typeID, pkt...) } return nil @@ -34,11 +36,17 @@ func (server *ShardServer) sendPacketToViewableChunks(plr *entity.Player, typeID func (server *ShardServer) removeEntityFromChunks(chunks []*entity.Chunk, this entity.Entity) { for _, chunk := range chunks { for e, _ := range chunk.Entities { + if e == this { + continue + } + + // notify other players we're leaving if e.GetKind() == entity.ENTITY_KIND_PLAYER { otherPlr := e.(*entity.Player) this.DisappearFromViewOf(otherPlr.Peer) } + // notify us they're leaving if this.GetKind() == entity.ENTITY_KIND_PLAYER { thisPlr := this.(*entity.Player) e.DisappearFromViewOf(thisPlr.Peer) @@ -50,11 +58,17 @@ func (server *ShardServer) removeEntityFromChunks(chunks []*entity.Chunk, this e func (server *ShardServer) addEntityToChunks(chunks []*entity.Chunk, this entity.Entity) { for _, chunk := range chunks { for e, _ := range chunk.Entities { + if e == this { + continue + } + + // notify other players we're entering if e.GetKind() == entity.ENTITY_KIND_PLAYER { otherPlr := e.(*entity.Player) this.EnterIntoViewOf(otherPlr.Peer) } + // notify us they're entering if this.GetKind() == entity.ENTITY_KIND_PLAYER { thisPlr := this.(*entity.Player) e.EnterIntoViewOf(thisPlr.Peer) @@ -64,6 +78,11 @@ func (server *ShardServer) addEntityToChunks(chunks []*entity.Chunk, this entity } func (server *ShardServer) updateEntityChunk(e entity.Entity, from entity.ChunkPosition, to entity.ChunkPosition) { + // no change needed + if from == to { + return + } + oldViewables := server.getViewableChunks(from) newViewables := server.getViewableChunks(to) diff --git a/shard/join.go b/shard/join.go index 85254ca..4faca25 100644 --- a/shard/join.go +++ b/shard/join.go @@ -59,7 +59,7 @@ func (server *ShardServer) RequestEnter(peer *protocol.CNPeer, pkt protocol.Pack log.Printf("Player %d (AccountID %d) entered\n", resp.IID, loginData.AccountID) - server.updatePlayerPosition(peer, int(plr.X), int(plr.Y), int(plr.Z), int(plr.Angle)) + server.updatePlayerPosition(plr, int(plr.X), int(plr.Y), int(plr.Z), int(plr.Angle)) return peer.Send(protocol.P_FE2CL_REP_PC_ENTER_SUCC, resp) } diff --git a/shard/movement.go b/shard/movement.go index 6ea302c..260e249 100644 --- a/shard/movement.go +++ b/shard/movement.go @@ -1,25 +1,18 @@ package shard import ( + "time" + "github.com/CPunch/gopenfusion/core/entity" "github.com/CPunch/gopenfusion/core/protocol" ) -func (server *ShardServer) updatePlayerPosition(peer *protocol.CNPeer, X, Y, Z, Angle int) error { - plr, err := server.getPlayer(peer) - if err != nil { - return err - } - newPos := entity.MakeChunkPosition(X, Y) - oldPos := plr.Chunk - +func (server *ShardServer) updatePlayerPosition(plr *entity.Player, X, Y, Z, Angle int) error { plr.X = X plr.Y = Y plr.Z = Z plr.Angle = Angle - if newPos != oldPos { - server.updateEntityChunk(plr, oldPos, newPos) - } + server.updateEntityChunk(plr, plr.GetChunk(), entity.MakeChunkPosition(X, Y)) return nil } @@ -27,5 +20,85 @@ func (server *ShardServer) playerMove(peer *protocol.CNPeer, pkt protocol.Packet var move protocol.SP_CL2FE_REQ_PC_MOVE pkt.Decode(&move) - return server.updatePlayerPosition(peer, int(move.IX), int(move.IY), int(move.IZ), int(move.IAngle)) + // sanity check + plr, err := server.getPlayer(peer) + if err != nil { + return err + } + + // update chunking + if err := server.updatePlayerPosition(plr, int(move.IX), int(move.IY), int(move.IZ), int(move.IAngle)); err != nil { + return err + } + + return server.sendOthersPacket(plr, protocol.P_FE2CL_PC_MOVE, protocol.SP_FE2CL_PC_MOVE{ + ICliTime: uint64(time.Now().Unix()), + IX: move.IX, + IY: move.IY, + IZ: move.IZ, + FVX: move.FVX, + FVY: move.FVY, + FVZ: move.FVZ, + IAngle: move.IAngle, + CKeyValue: move.CKeyValue, + ISpeed: move.ISpeed, + IID: int32(plr.PlayerID), + ISvrTime: uint64(time.Now().Unix()), + }) +} + +func (server *ShardServer) playerStop(peer *protocol.CNPeer, pkt protocol.Packet) error { + var stop protocol.SP_CL2FE_REQ_PC_STOP + pkt.Decode(&stop) + + // sanity check + plr, err := server.getPlayer(peer) + if err != nil { + return err + } + + // update chunking + if err := server.updatePlayerPosition(plr, int(stop.IX), int(stop.IY), int(stop.IZ), plr.Angle); err != nil { + return err + } + + return server.sendOthersPacket(plr, protocol.P_FE2CL_PC_STOP, protocol.SP_FE2CL_PC_STOP{ + ICliTime: uint64(time.Now().Unix()), + IX: stop.IX, + IY: stop.IY, + IZ: stop.IZ, + IID: int32(plr.PlayerID), + ISvrTime: uint64(time.Now().Unix()), + }) +} + +func (server *ShardServer) playerJump(peer *protocol.CNPeer, pkt protocol.Packet) error { + var jump protocol.SP_CL2FE_REQ_PC_JUMP + pkt.Decode(&jump) + + // sanity check + plr, err := server.getPlayer(peer) + if err != nil { + return err + } + + // update chunking + if err := server.updatePlayerPosition(plr, int(jump.IX), int(jump.IY), int(jump.IZ), plr.Angle); err != nil { + return err + } + + return server.sendOthersPacket(plr, protocol.P_FE2CL_PC_JUMP, protocol.SP_FE2CL_PC_JUMP{ + ICliTime: uint64(time.Now().Unix()), + IX: jump.IX, + IY: jump.IY, + IZ: jump.IZ, + IVX: jump.IVX, + IVY: jump.IVY, + IVZ: jump.IVZ, + IAngle: jump.IAngle, + CKeyValue: jump.CKeyValue, + ISpeed: jump.ISpeed, + IID: int32(plr.PlayerID), + ISvrTime: uint64(time.Now().Unix()), + }) } diff --git a/shard/shardServer.go b/shard/shardServer.go index db30c03..76c40db 100644 --- a/shard/shardServer.go +++ b/shard/shardServer.go @@ -50,6 +50,9 @@ func NewShardServer(dbHndlr *db.DBHandler, redisHndlr *redis.RedisHandler, port server.packetHandlers = map[uint32]PacketHandler{ protocol.P_CL2FE_REQ_PC_ENTER: server.RequestEnter, protocol.P_CL2FE_REQ_PC_LOADING_COMPLETE: server.LoadingComplete, + protocol.P_CL2FE_REQ_PC_MOVE: server.playerMove, + protocol.P_CL2FE_REQ_PC_STOP: server.playerStop, + protocol.P_CL2FE_REQ_PC_JUMP: server.playerJump, } redisHndlr.RegisterShard(redis.ShardMetadata{