2023-06-25 06:51:21 +00:00
|
|
|
package entity
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Chunk struct {
|
|
|
|
Position ChunkPosition
|
2023-11-21 07:49:57 +00:00
|
|
|
entities map[Entity]struct{}
|
2023-06-25 06:51:21 +00:00
|
|
|
lock sync.Mutex
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewChunk(position ChunkPosition) *Chunk {
|
|
|
|
return &Chunk{
|
|
|
|
Position: position,
|
2023-11-21 07:49:57 +00:00
|
|
|
entities: make(map[Entity]struct{}),
|
2023-06-25 06:51:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Chunk) AddEntity(entity Entity) {
|
2023-11-21 07:49:57 +00:00
|
|
|
c.lock.Lock()
|
|
|
|
defer c.lock.Unlock()
|
|
|
|
|
|
|
|
c.entities[entity] = struct{}{}
|
2023-06-25 06:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Chunk) RemoveEntity(entity Entity) {
|
2023-11-21 07:49:57 +00:00
|
|
|
c.lock.Lock()
|
|
|
|
defer c.lock.Unlock()
|
|
|
|
|
|
|
|
delete(c.entities, entity)
|
2023-06-25 06:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// send packet to all peers in this chunk and kill each peer if error
|
|
|
|
func (c *Chunk) SendPacket(typeID uint32, pkt ...interface{}) {
|
2023-06-25 09:27:42 +00:00
|
|
|
c.SendPacketExclude(nil, typeID, pkt...)
|
|
|
|
}
|
|
|
|
|
2023-11-21 07:49:57 +00:00
|
|
|
// calls f for each entity in this chunk, if f returns true, stop iterating
|
2023-11-28 03:23:28 +00:00
|
|
|
// f can safely add/remove entities from the chunk
|
2023-11-21 07:49:57 +00:00
|
|
|
func (c *Chunk) ForEachEntity(f func(entity Entity) bool) {
|
|
|
|
for entity := range c.entities {
|
|
|
|
if f(entity) {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Chunk) SendPacketExclude(exclude Entity, typeID uint32, pkt ...interface{}) {
|
|
|
|
c.ForEachEntity(func(entity Entity) bool {
|
2023-06-25 09:27:42 +00:00
|
|
|
// only send to players, and exclude the player that sent the packet
|
|
|
|
if entity.GetKind() != ENTITY_KIND_PLAYER || entity == exclude {
|
2023-11-21 07:49:57 +00:00
|
|
|
return false
|
2023-06-25 06:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
plr, ok := entity.(*Player)
|
|
|
|
if !ok {
|
|
|
|
log.Panic("Chunk.SendPacket: entity kind was player, but is not a *Player")
|
|
|
|
}
|
|
|
|
peer := plr.Peer
|
|
|
|
|
|
|
|
if err := peer.Send(typeID, pkt...); err != nil {
|
2023-06-25 08:33:17 +00:00
|
|
|
log.Printf("Error sending packet to peer %p: %v", peer, err)
|
2023-06-25 06:51:21 +00:00
|
|
|
peer.Kill()
|
|
|
|
}
|
2023-11-21 07:49:57 +00:00
|
|
|
|
|
|
|
return false
|
|
|
|
})
|
2023-06-25 06:51:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Chunk) GetAdjacentPositions() []ChunkPosition {
|
|
|
|
return []ChunkPosition{
|
|
|
|
{c.Position.X - 1, c.Position.Y - 1},
|
|
|
|
{c.Position.X - 1, c.Position.Y},
|
|
|
|
{c.Position.X - 1, c.Position.Y + 1},
|
|
|
|
{c.Position.X, c.Position.Y - 1},
|
|
|
|
{c.Position.X, c.Position.Y},
|
|
|
|
{c.Position.X, c.Position.Y + 1},
|
|
|
|
{c.Position.X + 1, c.Position.Y - 1},
|
|
|
|
{c.Position.X + 1, c.Position.Y},
|
|
|
|
{c.Position.X + 1, c.Position.Y + 1},
|
|
|
|
}
|
|
|
|
}
|
2023-06-25 08:33:17 +00:00
|
|
|
|
|
|
|
// https://stackoverflow.com/a/45428032 lol
|
|
|
|
func ChunkSliceDifference(a, b []*Chunk) []*Chunk {
|
|
|
|
m := make(map[*Chunk]struct{})
|
|
|
|
for _, item := range b {
|
|
|
|
m[item] = struct{}{}
|
|
|
|
}
|
|
|
|
|
|
|
|
var diff []*Chunk
|
|
|
|
for _, item := range a {
|
|
|
|
if _, ok := m[item]; !ok {
|
|
|
|
diff = append(diff, item)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return diff
|
|
|
|
}
|