Implement multiplayer persistence and vanilla lighting
This commit is contained in:
parent
8f7cacf9d9
commit
cae06eb97e
47 changed files with 3784 additions and 465 deletions
|
|
@ -1,6 +1,7 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
|
@ -10,92 +11,102 @@ import (
|
|||
)
|
||||
|
||||
// StartSpawning begins the entity tick and spawn loops.
|
||||
func (s *Server) StartSpawning() {
|
||||
go s.entityTickLoop()
|
||||
go s.mobSpawnLoop()
|
||||
func (s *Server) StartSpawning(ctx context.Context) {
|
||||
go s.entityTickLoop(ctx)
|
||||
go s.mobSpawnLoop(ctx)
|
||||
}
|
||||
|
||||
func (s *Server) entityTickLoop() {
|
||||
func (s *Server) entityTickLoop(ctx context.Context) {
|
||||
ticker := time.NewTicker(50 * time.Millisecond) // 20 TPS
|
||||
defer ticker.Stop()
|
||||
for range ticker.C {
|
||||
all := s.entities.All()
|
||||
for _, e := range all {
|
||||
// Apply gravity
|
||||
yBelow := int(e.Y - 0.1) // slightly below the entity
|
||||
blockBelow := s.chunks.GetBlock(int(e.X), yBelow, int(e.Z))
|
||||
|
||||
if blockBelow == world.StateAir || blockBelow == world.StateWater { // Air or Water
|
||||
e.VelocityY -= 80 // gravity acceleration
|
||||
if e.VelocityY < -3000 {
|
||||
e.VelocityY = -3000 // terminal velocity
|
||||
}
|
||||
} else {
|
||||
e.VelocityY = 0
|
||||
e.Y = float64(yBelow + 1)
|
||||
|
||||
// Basic random wandering or player tracking when on ground
|
||||
pos, ok := s.NearestPlayer(e.X, e.Y, e.Z)
|
||||
|
||||
if ok && e.TypeName == "minecraft:zombie" {
|
||||
// Zombies move towards the player
|
||||
dx := pos[0] - e.X
|
||||
dz := pos[2] - e.Z
|
||||
dist := math.Sqrt(dx*dx + dz*dz)
|
||||
if dist > 1.0 && dist < 32.0 {
|
||||
e.X += (dx / dist) * 0.15
|
||||
e.Z += (dz / dist) * 0.15
|
||||
// Simple yaw calculation
|
||||
e.Yaw = float32(math.Atan2(-dx, dz) * (180 / math.Pi))
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
all := s.entities.All()
|
||||
for i := range all {
|
||||
snapshot := all[i]
|
||||
yBelow := int(math.Floor(snapshot.Y - 0.1))
|
||||
blockBelow := s.chunks.GetBlock(int(math.Floor(snapshot.X)), yBelow, int(math.Floor(snapshot.Z)))
|
||||
nearest, hasPlayer := s.NearestPlayer(snapshot.X, snapshot.Y, snapshot.Z)
|
||||
s.entities.Update(all[i].ID, func(e *world.Entity) {
|
||||
// Apply gravity
|
||||
if blockBelow == world.StateAir || blockBelow == world.StateWater { // Air or Water
|
||||
e.VelocityY -= 80 // gravity acceleration
|
||||
if e.VelocityY < -3000 {
|
||||
e.VelocityY = -3000 // terminal velocity
|
||||
}
|
||||
} else {
|
||||
e.VelocityY = 0
|
||||
e.Y = float64(yBelow + 1)
|
||||
|
||||
// Basic random wandering or player tracking when on ground
|
||||
if hasPlayer && e.TypeName == "minecraft:zombie" {
|
||||
// Zombies move towards the player
|
||||
dx := nearest[0] - e.X
|
||||
dz := nearest[2] - e.Z
|
||||
dist := math.Sqrt(dx*dx + dz*dz)
|
||||
if dist > 1.0 && dist < 32.0 {
|
||||
e.X += (dx / dist) * 0.15
|
||||
e.Z += (dz / dist) * 0.15
|
||||
// Simple yaw calculation
|
||||
e.Yaw = float32(math.Atan2(-dx, dz) * (180 / math.Pi))
|
||||
}
|
||||
} else {
|
||||
// Random wander
|
||||
e.X += (rand.Float64() - 0.5) * 0.2
|
||||
e.Z += (rand.Float64() - 0.5) * 0.2
|
||||
e.Yaw += float32((rand.Float64() - 0.5) * 10.0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Random wander
|
||||
e.X += (rand.Float64() - 0.5) * 0.2
|
||||
e.Z += (rand.Float64() - 0.5) * 0.2
|
||||
e.Yaw += float32((rand.Float64() - 0.5) * 10.0)
|
||||
}
|
||||
}
|
||||
|
||||
if e.VelocityY != 0 {
|
||||
e.Y += float64(e.VelocityY) / 8000.0
|
||||
|
||||
if e.VelocityY != 0 {
|
||||
e.Y += float64(e.VelocityY) / 8000.0
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) mobSpawnLoop() {
|
||||
func (s *Server) mobSpawnLoop(ctx context.Context) {
|
||||
ticker := time.NewTicker(2 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
pigType := registry.Index("minecraft:entity_type", "minecraft:pig")
|
||||
zombieType := registry.Index("minecraft:entity_type", "minecraft:zombie")
|
||||
pigType := registry.EntityTypeIndex("minecraft:pig")
|
||||
zombieType := registry.EntityTypeIndex("minecraft:zombie")
|
||||
if pigType < 0 || zombieType < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for range ticker.C {
|
||||
all := s.entities.All()
|
||||
if len(all) > 50 {
|
||||
continue // limit to 50 entities
|
||||
}
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
if s.PlayerCount() == 0 || s.entities.Count() >= 50 {
|
||||
continue // limit to 50 entities
|
||||
}
|
||||
|
||||
// Spawn near the spawn point (8.5, 200, 8.5)
|
||||
x := (rand.Float64() - 0.5) * 30.0
|
||||
z := (rand.Float64() - 0.5) * 30.0
|
||||
|
||||
t := pigType
|
||||
name := "minecraft:pig"
|
||||
if rand.Float32() < 0.5 {
|
||||
t = zombieType
|
||||
name = "minecraft:zombie"
|
||||
}
|
||||
// Spawn near the spawn point (8.5, 200, 8.5)
|
||||
x := (rand.Float64() - 0.5) * 30.0
|
||||
z := (rand.Float64() - 0.5) * 30.0
|
||||
|
||||
s.entities.Add(&world.Entity{
|
||||
TypeID: t,
|
||||
TypeName: name,
|
||||
X: x + 8.5,
|
||||
Y: 200.0, // They float for now since there's no gravity
|
||||
Z: z + 8.5,
|
||||
})
|
||||
t := pigType
|
||||
name := "minecraft:pig"
|
||||
if rand.Float32() < 0.5 {
|
||||
t = zombieType
|
||||
name = "minecraft:zombie"
|
||||
}
|
||||
|
||||
s.entities.Add(&world.Entity{
|
||||
TypeID: t,
|
||||
TypeName: name,
|
||||
X: x + 8.5,
|
||||
Y: 200.0,
|
||||
Z: z + 8.5,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue