Files
mc/main.go
T

191 lines
4.7 KiB
Go
Raw Normal View History

2026-07-09 08:33:57 +08:00
package main
import (
"fmt"
"log/slog"
2026-07-12 04:04:55 +07:00
"math"
"math/rand/v2"
2026-07-09 08:33:57 +08:00
"os"
2026-07-12 04:04:55 +07:00
"runtime"
"runtime/debug"
"time"
2026-07-09 08:33:57 +08:00
"github.com/df-mc/dragonfly/server"
2026-07-12 04:04:55 +07:00
"github.com/df-mc/dragonfly/server/entity"
"github.com/df-mc/dragonfly/server/player"
2026-07-09 08:33:57 +08:00
"github.com/df-mc/dragonfly/server/player/chat"
"github.com/df-mc/dragonfly/server/world"
2026-07-12 04:04:55 +07:00
"github.com/go-gl/mathgl/mgl64"
2026-07-09 08:33:57 +08:00
"github.com/pelletier/go-toml"
)
func main() {
slog.SetLogLoggerLevel(slog.LevelDebug)
chat.Global.Subscribe(chat.StdoutSubscriber{})
conf, err := readConfig(slog.Default())
if err != nil {
panic(err)
}
srv := conf.New()
srv.CloseOnProgramEnd()
srv.Listen()
2026-07-12 04:04:55 +07:00
// 1. Periodic mob spawner loop
go func() {
for {
time.Sleep(20 * time.Second)
srv.World().Exec(func(tx *world.Tx) {
mobsCount := 0
for e := range tx.Entities() {
if _, ok := e.H().Type().(entity.MobType); ok {
mobsCount++
}
}
// Only spawn if count is below 25 to optimize performance
if mobsCount < 25 {
for plEntity := range tx.Players() {
pl, ok := plEntity.(*player.Player)
if !ok {
continue
}
// 50% chance to spawn a mob around this player
if rand.IntN(2) == 0 {
dx := float64(rand.IntN(30) - 15)
dz := float64(rand.IntN(30) - 15)
if math.Abs(dx) > 5 || math.Abs(dz) > 5 {
pos := pl.Position().Add(mgl64.Vec3{dx, 0, dz})
y := float64(tx.HighestBlock(int(pos.X()), int(pos.Z()))) + 1.0
if y > float64(tx.Range()[0]) {
spawnPos := mgl64.Vec3{pos.X(), y, pos.Z()}
types := []world.EntityType{
entity.PigType,
entity.CowType,
entity.SheepType,
entity.ZombieType,
entity.SkeletonType,
}
t := types[rand.IntN(len(types))]
opts := world.EntitySpawnOpts{Position: spawnPos}
h := opts.New(t, entity.PassiveBehaviourConfig{
Gravity: 0.08,
Drag: 0.02,
})
tx.AddEntity(h)
}
}
}
}
}
})
}
}()
// 2. Periodic item clearing and auto-optimization loop
go func() {
for {
// Sleep 10 minutes, then notify
time.Sleep(10 * time.Minute)
srv.World().Exec(func(tx *world.Tx) {
for plEntity := range tx.Players() {
if pl, ok := plEntity.(*player.Player); ok {
pl.Message("§e[Pemberitahuan] Semua item di tanah akan dibersihkan dalam 5 menit!§r")
}
}
})
// Sleep 5 minutes, then clear and optimize
time.Sleep(5 * time.Minute)
srv.World().Exec(func(tx *world.Tx) {
count := 0
for e := range tx.Entities() {
if e.H().Type().EncodeEntity() == "minecraft:item" {
_ = e.Close()
count++
}
}
for plEntity := range tx.Players() {
if pl, ok := plEntity.(*player.Player); ok {
pl.Message(fmt.Sprintf("§a[Pemberitahuan] Berhasil membersihkan %d item di tanah!§r", count))
}
}
})
// Trigger automatic optimization/GC
runtime.GC()
debug.FreeOSMemory()
}
}()
2026-07-09 08:33:57 +08:00
for p := range srv.Accept() {
2026-07-12 04:04:55 +07:00
p.SetGameMode(world.GameModeSurvival)
p.Message("§aSelamat datang! Bermainlah dalam Survival Mode.§r")
// Teleport player randomly near an existing player, or spawn
go func(pl *player.Player) {
time.Sleep(100 * time.Millisecond)
pl.H().ExecWorld(func(tx *world.Tx, e world.Entity) {
p := e.(*player.Player)
var players []world.Entity
for other := range tx.Players() {
if other.H().UUID() != p.H().UUID() {
players = append(players, other)
}
}
var basePos mgl64.Vec3
if len(players) > 0 {
target := players[rand.IntN(len(players))]
basePos = target.Position()
} else {
basePos = tx.World().Spawn().Vec3()
}
// Spawn randomly within 40 blocks of base position
dx := float64(rand.IntN(80) - 40)
dz := float64(rand.IntN(80) - 40)
spawnX := basePos.X() + dx
spawnZ := basePos.Z() + dz
spawnY := float64(tx.HighestBlock(int(spawnX), int(spawnZ))) + 1.0
spawnPos := mgl64.Vec3{spawnX, spawnY, spawnZ}
p.Teleport(spawnPos)
})
}(p)
2026-07-09 08:33:57 +08:00
}
}
func readConfig(log *slog.Logger) (server.Config, error) {
c := server.DefaultConfig()
var zero server.Config
if _, err := os.Stat("config.toml"); os.IsNotExist(err) {
data, err := toml.Marshal(c)
if err != nil {
return zero, fmt.Errorf("encode default config: %v", err)
}
if err := os.WriteFile("config.toml", data, 0644); err != nil {
return zero, fmt.Errorf("create default config: %v", err)
}
return c.Config(log)
}
data, err := os.ReadFile("config.toml")
if err != nil {
return zero, fmt.Errorf("read config: %v", err)
}
if err := toml.Unmarshal(data, &c); err != nil {
return zero, fmt.Errorf("decode config: %v", err)
}
return c.Config(log)
}