Fix a few network issues
This commit is contained in:
parent
d310509035
commit
0ba96ca478
62
base.go
62
base.go
@ -3,8 +3,12 @@ package main
|
||||
import (
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
"image/color"
|
||||
"strconv"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var baseMutex sync.RWMutex
|
||||
|
||||
type Base struct {
|
||||
ownerID uint32
|
||||
openingWidth int32
|
||||
@ -12,8 +16,9 @@ type Base struct {
|
||||
}
|
||||
|
||||
func (base *Base) tick(players map[uint32]*Player) {
|
||||
playersMutex.RLock()
|
||||
for playerID, player := range players {
|
||||
if player.gameObject.baseRect.HasIntersection(&base.gameObject.baseRect) {
|
||||
if player.gameObject.baseRect.HasIntersection(base.gameObject.baseRect) {
|
||||
if player.rechargeCooldown == 0 && player.energy < serverConfig.MaxEnergy {
|
||||
if serverConfig.MaxEnergy-player.energy < 4 {
|
||||
player.energy++
|
||||
@ -32,6 +37,7 @@ func (base *Base) tick(players map[uint32]*Player) {
|
||||
}
|
||||
}
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
}
|
||||
|
||||
func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface, bases map[uint32]*Base) {
|
||||
@ -42,14 +48,6 @@ func (base *Base) render(camera *sdl.Rect, surface *sdl.Surface, bases map[uint3
|
||||
}
|
||||
|
||||
func (base *Base) build(gameMap *GameMap) {
|
||||
borderWidth := base.gameObject.baseRect.W - base.openingWidth
|
||||
borderWidthA := borderWidth / 2
|
||||
if borderWidth < 0 {
|
||||
panic("Bad border width")
|
||||
}
|
||||
if base.gameObject.baseRect.H < 9 {
|
||||
panic("Bad border height")
|
||||
}
|
||||
if gameMap.width-uint32(base.gameObject.baseRect.X)-uint32(base.gameObject.baseRect.W) <= 0 {
|
||||
panic("Bad base x location")
|
||||
}
|
||||
@ -57,30 +55,32 @@ func (base *Base) build(gameMap *GameMap) {
|
||||
panic("Bad base y location")
|
||||
}
|
||||
if base.gameObject.baseRect.X < 0 || base.gameObject.baseRect.Y < 0 {
|
||||
panic("Bad base negative location")
|
||||
panic("Bad base negative location " + strconv.Itoa(int(base.gameObject.baseRect.X)) + " - " + strconv.Itoa(int(base.gameObject.baseRect.Y)))
|
||||
}
|
||||
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W+1; x++ {
|
||||
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H+1; y++ {
|
||||
base.gameObject.adjustBaseRect()
|
||||
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W; x++ {
|
||||
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H; y++ {
|
||||
gameMap.tiles[x][y] = 0
|
||||
}
|
||||
}
|
||||
for y := base.gameObject.baseRect.Y; y < base.gameObject.baseRect.Y+base.gameObject.baseRect.H; y++ {
|
||||
gameMap.tiles[base.gameObject.baseRect.X][y] = 4
|
||||
gameMap.tiles[base.gameObject.baseRect.X+base.gameObject.baseRect.W][y] = 4
|
||||
}
|
||||
for x := base.gameObject.baseRect.X; x < base.gameObject.baseRect.X+borderWidthA; x++ {
|
||||
gameMap.tiles[x][base.gameObject.baseRect.Y] = 4
|
||||
gameMap.tiles[x][base.gameObject.baseRect.Y+base.gameObject.baseRect.H] = 4
|
||||
}
|
||||
for x := base.gameObject.baseRect.X + borderWidthA + base.openingWidth; x < base.gameObject.baseRect.X+base.gameObject.baseRect.W+1; x++ {
|
||||
gameMap.tiles[x][base.gameObject.baseRect.Y] = 4
|
||||
gameMap.tiles[x][base.gameObject.baseRect.Y+base.gameObject.baseRect.H] = 4
|
||||
for _, rectT := range base.gameObject.getCurrentRects() {
|
||||
rect := sdl.Rect{
|
||||
X: rectT.rect.X + base.gameObject.baseRect.X,
|
||||
Y: rectT.rect.Y + base.gameObject.baseRect.Y,
|
||||
W: rectT.rect.W,
|
||||
H: rectT.rect.H,
|
||||
}
|
||||
for x := rect.X; x < rect.X+rect.W; x++ {
|
||||
for y := rect.Y; y < rect.Y+rect.H; y++ {
|
||||
gameMap.tiles[x][y] = 4
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createBase(gameMap *GameMap, baseColor color.Color, posX, posY, ownerID, openingWidth uint32) *Base {
|
||||
gameObject := &GameObject{}
|
||||
gameObject.baseRect = sdl.Rect{
|
||||
gameObject.baseRect = &sdl.Rect{
|
||||
X: int32(posX),
|
||||
Y: int32(posY),
|
||||
W: 35,
|
||||
@ -97,12 +97,12 @@ func createBase(gameMap *GameMap, baseColor color.Color, posX, posY, ownerID, op
|
||||
panic("Bad border width")
|
||||
}
|
||||
gameObject.addColor(baseColor)
|
||||
gameObject.addColoredRect(0, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(gameObject.baseRect.W, 0, 1, gameObject.baseRect.H, 0)
|
||||
gameObject.addColoredRect(0, 0, 1, gameObject.baseRect.H-1, 0)
|
||||
gameObject.addColoredRect(gameObject.baseRect.W, 0, 1, gameObject.baseRect.H-1, 0)
|
||||
gameObject.addColoredRect(0, 0, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+int32(openingWidth), 0, borderWidthB, 1, 0)
|
||||
gameObject.addColoredRect(0, gameObject.baseRect.H, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+int32(openingWidth), gameObject.baseRect.H, borderWidthB, 1, 0)
|
||||
gameObject.addColoredRect(0, gameObject.baseRect.H-1, borderWidthA, 1, 0)
|
||||
gameObject.addColoredRect(borderWidthA+int32(openingWidth), gameObject.baseRect.H-1, borderWidthB, 1, 0)
|
||||
base := &Base{
|
||||
gameObject: gameObject,
|
||||
ownerID: ownerID,
|
||||
@ -118,12 +118,16 @@ func (base *Base) delete(bases map[uint32]*Base) {
|
||||
gameMap.tiles[x][y] = 0
|
||||
}
|
||||
}
|
||||
baseMutex.Lock()
|
||||
delete(bases, base.ownerID)
|
||||
baseMutex.Unlock()
|
||||
}
|
||||
|
||||
func createBases(players map[uint32]*Player, gameMap *GameMap) map[uint32]*Base {
|
||||
bases := map[uint32]*Base{}
|
||||
playersMutex.RLock()
|
||||
for ownerID, player := range players {
|
||||
baseMutex.Lock()
|
||||
bases[ownerID] = createBase(gameMap,
|
||||
player.playerColors.body,
|
||||
uint32(player.gameObject.baseRect.X-14),
|
||||
@ -131,6 +135,8 @@ func createBases(players map[uint32]*Player, gameMap *GameMap) map[uint32]*Base
|
||||
ownerID,
|
||||
uint32(float64(player.gameObject.baseRect.W)*1.5),
|
||||
)
|
||||
baseMutex.Unlock()
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
return bases
|
||||
}
|
||||
|
@ -4,11 +4,15 @@ import (
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
"image/color"
|
||||
"math/rand"
|
||||
"sync"
|
||||
)
|
||||
|
||||
var bulletLastID = uint32(0)
|
||||
var bulletParticleLastID = uint32(0)
|
||||
|
||||
var bulletMutex sync.RWMutex
|
||||
var bulletParticleMutex sync.RWMutex
|
||||
|
||||
type Bullet struct {
|
||||
posX, posY int32
|
||||
direction uint8
|
||||
@ -159,6 +163,7 @@ func (bullet *Bullet) tick(gameMap *GameMap,
|
||||
H: 1,
|
||||
}
|
||||
hitPlayer := false
|
||||
playersMutex.RLock()
|
||||
for _, player := range players {
|
||||
if player.playerID == bullet.ownerID {
|
||||
continue
|
||||
@ -174,6 +179,7 @@ func (bullet *Bullet) tick(gameMap *GameMap,
|
||||
}
|
||||
}
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
if collisionResult != 0 || hitPlayer {
|
||||
bullet.explode(gameMap, bulletParticleMap)
|
||||
delete(bulletMap, bullet.id)
|
||||
|
@ -6,13 +6,14 @@ import (
|
||||
)
|
||||
|
||||
type GameObject struct {
|
||||
baseRect sdl.Rect
|
||||
prevBaseRect sdl.Rect
|
||||
borderRect sdl.Rect
|
||||
orientation uint8
|
||||
visualRects [][]*ColoredRect
|
||||
colors []color.Color
|
||||
inView bool
|
||||
baseRect *sdl.Rect
|
||||
prevBaseRect *sdl.Rect
|
||||
borderRect *sdl.Rect
|
||||
collisionRect *sdl.Rect
|
||||
orientation uint8
|
||||
visualRects [][]*ColoredRect
|
||||
colors []color.Color
|
||||
inView bool
|
||||
}
|
||||
|
||||
type ColoredRect struct {
|
||||
@ -38,6 +39,13 @@ func (gameObject *GameObject) adjustRectWorld(offset *sdl.Rect) *sdl.Rect {
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) adjustColoredRectWorld(offset *ColoredRect) *ColoredRect {
|
||||
return &ColoredRect{
|
||||
color: offset.color,
|
||||
rect: gameObject.adjustRectWorld(offset.rect),
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) adjustRectToCamera(offset *sdl.Rect, camera *sdl.Rect) *sdl.Rect {
|
||||
return &sdl.Rect{
|
||||
X: gameObject.baseRect.X + offset.X - camera.X,
|
||||
@ -47,20 +55,31 @@ func (gameObject *GameObject) adjustRectToCamera(offset *sdl.Rect, camera *sdl.R
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) adjustBaseRect() {
|
||||
first := true
|
||||
oldX, oldY := gameObject.baseRect.X, gameObject.baseRect.Y
|
||||
for _, rect := range gameObject.getCurrentRects() {
|
||||
if first {
|
||||
gameObject.baseRect = gameObject.adjustRectWorld(rect.rect)
|
||||
first = false
|
||||
} else {
|
||||
|
||||
}
|
||||
newRect := gameObject.baseRect.Union(gameObject.adjustRectWorld(rect.rect))
|
||||
gameObject.baseRect = &newRect
|
||||
gameObject.baseRect.X, gameObject.baseRect.Y = oldX, oldY
|
||||
}
|
||||
}
|
||||
|
||||
func (gameObject *GameObject) render(camera *sdl.Rect, surface *sdl.Surface) {
|
||||
if camera.HasIntersection(&gameObject.baseRect) {
|
||||
if camera.HasIntersection(gameObject.baseRect) {
|
||||
gameObject.inView = true
|
||||
if config.Debug {
|
||||
gameObject.borderRect = sdl.Rect{
|
||||
X: gameObject.baseRect.X - 1,
|
||||
Y: gameObject.baseRect.Y - 1,
|
||||
W: gameObject.baseRect.W + 2,
|
||||
H: gameObject.baseRect.H + 2,
|
||||
}
|
||||
borderRectFinal := adjustRectToCamera(&gameObject.borderRect, camera)
|
||||
baseRectFinal := adjustRectToCamera(&gameObject.baseRect, camera)
|
||||
surface.FillRect(borderRectFinal, sdl.MapRGBA(surface.Format, 20, 192, 128, 64))
|
||||
baseRectFinal := adjustRectToCamera(gameObject.baseRect, camera)
|
||||
surface.FillRect(baseRectFinal, sdl.MapRGBA(surface.Format, 255, 20, 10, 64))
|
||||
if !gameObject.collisionRect.Empty() {
|
||||
surface.FillRect(adjustRectToCamera(gameObject.collisionRect, camera), sdl.MapRGBA(surface.Format, 40, 192, 255, 64))
|
||||
}
|
||||
}
|
||||
if config.RenderGameObjects {
|
||||
for _, coloredRect := range gameObject.visualRects[gameObject.orientation] {
|
||||
|
258
main.go
258
main.go
@ -8,10 +8,13 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"runtime/pprof"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const GameVersion = "TunnEElineningnegbfbf Through the wiAldWest"
|
||||
|
||||
type ServerConfig struct {
|
||||
MapWidth uint32 `json:"map_width"`
|
||||
MapHeight uint32 `json:"map_height"`
|
||||
@ -37,44 +40,47 @@ type ServerConfig struct {
|
||||
MovementCooldownNoEnergy uint32 `json:"movement_cooldown_no_energy"`
|
||||
DiggingCooldownNoEnergy uint32 `json:"digging_cooldown_no_energy"`
|
||||
ReloadCooldown uint32 `json:"reload_cooldown"`
|
||||
ReloadWait uint32 `json:"reload_wait"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Debug bool `json:"debug"`
|
||||
MapWindow bool `json:"map_window"`
|
||||
RenderGameObjects bool `json:"render_game_objects"`
|
||||
ProfilerOn bool `json:"profiler_on"`
|
||||
ProfilerInterval uint64 `json:"profiler_interval"`
|
||||
Server bool `json:"server"`
|
||||
CameraW int32 `json:"camera_w"`
|
||||
CameraH int32 `json:"camera_h"`
|
||||
Version string `json:"version"`
|
||||
Client bool `json:"client"`
|
||||
Address string `json:"address"`
|
||||
JoyStickDeadZone int16 `json:"joystick_dead_zone"`
|
||||
DoAllKeymapsPlayers bool `json:"do_all_keymaps_players"`
|
||||
DoJoyStickPlayers bool `json:"do_joystick_players"`
|
||||
DoKeymapPlayer bool `json:"do_keymap_player"`
|
||||
ServerConfig ServerConfig `json:"server_config"`
|
||||
Debug bool `json:"debug"`
|
||||
MapWindow bool `json:"map_window"`
|
||||
MapUpdateInterval uint16 `json:"map_update_interval"`
|
||||
RenderGameObjects bool `json:"render_game_objects"`
|
||||
ProfilerOn bool `json:"profiler_on"`
|
||||
ProfilerInterval uint64 `json:"profiler_interval"`
|
||||
Server bool `json:"server"`
|
||||
CameraW int32 `json:"camera_w"`
|
||||
CameraH int32 `json:"camera_h"`
|
||||
Client bool `json:"client"`
|
||||
Address string `json:"address"`
|
||||
JoyStickDeadZone int16 `json:"joystick_dead_zone"`
|
||||
DoAllKeymapsPlayers bool `json:"do_all_keymaps_players"`
|
||||
DoJoyStickPlayers bool `json:"do_joystick_players"`
|
||||
DoKeymapPlayer bool `json:"do_keymap_player"`
|
||||
RecentlyDugBlocksClearInterval uint16 `json:"recently_dug_blocks_clear_interval"`
|
||||
ServerConfig ServerConfig `json:"server_config"`
|
||||
}
|
||||
|
||||
func loadOrCreateConfig(filename string) (*Config, error) {
|
||||
config := &Config{
|
||||
Debug: false,
|
||||
MapWindow: false,
|
||||
RenderGameObjects: true,
|
||||
ProfilerOn: false,
|
||||
ProfilerInterval: 100,
|
||||
Server: false,
|
||||
CameraW: 76,
|
||||
CameraH: 76,
|
||||
Version: "69420",
|
||||
Client: true,
|
||||
Address: "192.168.1.8:5074",
|
||||
JoyStickDeadZone: 8000,
|
||||
DoAllKeymapsPlayers: false,
|
||||
DoJoyStickPlayers: true,
|
||||
DoKeymapPlayer: true,
|
||||
Debug: false,
|
||||
MapWindow: false,
|
||||
MapUpdateInterval: 999,
|
||||
RenderGameObjects: true,
|
||||
ProfilerOn: false,
|
||||
ProfilerInterval: 100,
|
||||
Server: false,
|
||||
CameraW: 76,
|
||||
CameraH: 76,
|
||||
Client: true,
|
||||
Address: "192.168.1.8:5074",
|
||||
JoyStickDeadZone: 8000,
|
||||
DoAllKeymapsPlayers: false,
|
||||
DoJoyStickPlayers: true,
|
||||
DoKeymapPlayer: true,
|
||||
RecentlyDugBlocksClearInterval: 20,
|
||||
ServerConfig: ServerConfig{
|
||||
MapWidth: 1000,
|
||||
MapHeight: 1000,
|
||||
@ -100,6 +106,7 @@ func loadOrCreateConfig(filename string) (*Config, error) {
|
||||
MovementCooldownNoEnergy: 4,
|
||||
DiggingCooldownNoEnergy: 8,
|
||||
ReloadCooldown: 16,
|
||||
ReloadWait: 16,
|
||||
},
|
||||
}
|
||||
|
||||
@ -149,6 +156,8 @@ var clientInitialized = false
|
||||
|
||||
var worldLock sync.Mutex
|
||||
|
||||
var totalRenderTime, totalGameLogicCatchUp, totalNormalGameLogic, totalTicking, totalScalingTime, totalRemotePlayerUpdate, tickCount, totalFrameTime, frameCount uint64
|
||||
|
||||
func main() {
|
||||
initializeSDL()
|
||||
defer sdl.Quit()
|
||||
@ -158,6 +167,17 @@ func main() {
|
||||
}
|
||||
serverConfig = configX.ServerConfig
|
||||
config = configX
|
||||
if config.ProfilerOn {
|
||||
f, err := os.Create("cpuprofile")
|
||||
if err != nil {
|
||||
log.Fatal("could not create CPU profile: ", err)
|
||||
}
|
||||
defer f.Close() // error handling omitted for example
|
||||
if err := pprof.StartCPUProfile(f); err != nil {
|
||||
log.Fatal("could not start CPU profile: ", err)
|
||||
}
|
||||
defer pprof.StopCPUProfile()
|
||||
}
|
||||
mapRendererRect = &sdl.Rect{X: 0, Y: 0, W: int32(serverConfig.MapWidth), H: int32(serverConfig.MapHeight)}
|
||||
players := make(map[uint32]*Player)
|
||||
initPlayerColors()
|
||||
@ -171,7 +191,7 @@ func main() {
|
||||
|
||||
if !config.Client {
|
||||
gameMap.createGameMap(true)
|
||||
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players)
|
||||
createPlayers(getNeededPlayers(), playerColors, keyMaps, joyMaps, gameMap, players, bases)
|
||||
bases = createBases(players, gameMap)
|
||||
} else {
|
||||
// Create a connection to the server
|
||||
@ -195,9 +215,11 @@ func main() {
|
||||
|
||||
defer closeThings(players)
|
||||
|
||||
playersMutex.Lock()
|
||||
for playerIndex, player := range players {
|
||||
initPlayer(uint8(playerIndex), player)
|
||||
}
|
||||
playersMutex.Unlock()
|
||||
|
||||
if config.Server {
|
||||
// Create a connection to the server
|
||||
@ -216,7 +238,12 @@ func main() {
|
||||
for {
|
||||
conn, err := listen.AcceptTCP()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
if opErr, ok := err.(*net.OpError); ok && opErr.Err.Error() == "use of closed network connection" {
|
||||
log.Println("Listener closed, stopping server.")
|
||||
return
|
||||
}
|
||||
log.Println("Error accepting connection:", err)
|
||||
continue
|
||||
}
|
||||
go handleRequest(conn, players, bullets, bases)
|
||||
}
|
||||
@ -227,7 +254,6 @@ func main() {
|
||||
mapWindow, mapSurface = setupMapWindowAndSurface()
|
||||
}
|
||||
running := true
|
||||
var totalRenderTime, totalScalingTime, totalFrameTime, frameCount uint64
|
||||
|
||||
// Delta time management
|
||||
var prevTime = sdl.GetTicks64()
|
||||
@ -239,17 +265,21 @@ func main() {
|
||||
prevTime = currentTime
|
||||
worldLock.Lock()
|
||||
|
||||
// Catch up in case of a large delta time
|
||||
for deltaTime > maxDeltaTime {
|
||||
deltaTime -= maxDeltaTime
|
||||
totalGameLogicCatchUp += profileSection(func() {
|
||||
// Catch up in case of a large delta time
|
||||
for deltaTime > maxDeltaTime {
|
||||
deltaTime -= maxDeltaTime
|
||||
|
||||
// Run multiple logic ticks if deltaTime is too large
|
||||
// Run multiple logic ticks if deltaTime is too large
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
}
|
||||
})
|
||||
totalNormalGameLogic += profileSection(func() {
|
||||
// Run logic for the remaining delta time
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
}
|
||||
|
||||
// Run logic for the remaining delta time
|
||||
runGameLogic(players, gameMap, bases, bullets, bulletParticles)
|
||||
})
|
||||
|
||||
playersMutex.RLock()
|
||||
for playerIndex, player := range players {
|
||||
if player.local {
|
||||
running = doPlayerFrame(uint8(playerIndex), player, players, gameMap, bases, bullets, bulletParticles)
|
||||
@ -258,25 +288,34 @@ func main() {
|
||||
}
|
||||
}
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
|
||||
// Render logic
|
||||
if config.MapWindow {
|
||||
if config.MapWindow && frameCount%uint64(config.MapUpdateInterval) == 0 {
|
||||
// Profile rendering (aggregate all renderings)
|
||||
totalRenderTime += profileSection(func() {
|
||||
running = running && handleEvents(mapWindow, mapSurface)
|
||||
gameMap.render(mapRendererRect, mapSurface)
|
||||
bulletMutex.RLock()
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).render(mapRendererRect, mapSurface, bullets)
|
||||
}
|
||||
bulletMutex.RUnlock()
|
||||
baseMutex.RLock()
|
||||
for _, base := range bases {
|
||||
(*base).render(mapRendererRect, mapSurface, bases)
|
||||
}
|
||||
baseMutex.RUnlock()
|
||||
playersMutex.RLock()
|
||||
for _, playerLoop := range players {
|
||||
(*playerLoop).render(mapRendererRect, mapSurface, players)
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
bulletParticleMutex.RLock()
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.render(mapRendererRect, mapSurface, bulletParticles)
|
||||
}
|
||||
bulletParticleMutex.RUnlock()
|
||||
})
|
||||
totalScalingTime += profileSection(func() {
|
||||
adjustWindow(mapWindow, mapSurface)
|
||||
@ -289,8 +328,8 @@ func main() {
|
||||
|
||||
// Log profiling information every 1000 frames
|
||||
if frameCount%config.ProfilerInterval == 0 && config.ProfilerOn {
|
||||
logMapProfilingInfo(totalRenderTime, totalScalingTime, totalFrameTime, frameCount)
|
||||
resetMapProfilingCounters(&totalRenderTime, &totalScalingTime, &totalFrameTime, &frameCount)
|
||||
logMapProfilingInfo(totalRenderTime, totalScalingTime, totalFrameTime, totalGameLogicCatchUp, totalNormalGameLogic, totalTicking, totalRemotePlayerUpdate, frameCount, tickCount)
|
||||
resetMapProfilingCounters(&totalRenderTime, &totalScalingTime, &totalFrameTime, &totalGameLogicCatchUp, &totalNormalGameLogic, &totalTicking, &totalRemotePlayerUpdate, &frameCount, &tickCount)
|
||||
}
|
||||
worldLock.Unlock()
|
||||
enforceFrameRate(currentTime, 60)
|
||||
@ -303,51 +342,94 @@ func runGameLogic(players map[uint32]*Player, gameMap *GameMap, bases map[uint32
|
||||
|
||||
if config.Server {
|
||||
//update remote player maps
|
||||
totalRemotePlayerUpdate += profileSection(func() {
|
||||
var wgX sync.WaitGroup
|
||||
var wgX2 sync.WaitGroup
|
||||
playerUpdateMutex.Lock()
|
||||
playersMutex.RLock()
|
||||
for _, player := range players {
|
||||
if player.local {
|
||||
continue
|
||||
}
|
||||
wgX.Add(6)
|
||||
go player.updateRemotePlayerMap(&wgX)
|
||||
go player.updateRemotePlayerBases(bases, &wgX)
|
||||
go player.updateRemotePlayerBullets(bullets, &wgX)
|
||||
go player.updateRemotePlayerBulletParticles(bulletParticles, &wgX)
|
||||
go player.updateRemotePlayerPlayers(players, &wgX)
|
||||
playerX := player
|
||||
go func() {
|
||||
fail := playerX.sendInfoToPlayer(&wgX)
|
||||
if fail {
|
||||
if playerX.connection != nil {
|
||||
(*playerX.connection).Close()
|
||||
}
|
||||
baseMutex.Lock()
|
||||
if bases[playerX.playerID] != nil {
|
||||
bases[playerX.playerID].delete(bases)
|
||||
}
|
||||
baseMutex.Unlock()
|
||||
playersMutex.TryLock()
|
||||
delete(players, playerX.playerID)
|
||||
playersMutex.Unlock()
|
||||
}
|
||||
}()
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
wgX.Wait()
|
||||
|
||||
playersMutex.Lock()
|
||||
for _, player := range players {
|
||||
wgX2.Add(1)
|
||||
playerX := player
|
||||
go func() {
|
||||
fail := playerX.sendUpdatesToPlayer(players, &wgX2)
|
||||
if fail {
|
||||
if playerX.connection != nil {
|
||||
(*playerX.connection).Close()
|
||||
}
|
||||
baseMutex.Lock()
|
||||
if bases[playerX.playerID] != nil {
|
||||
bases[playerX.playerID].delete(bases)
|
||||
}
|
||||
baseMutex.Unlock()
|
||||
delete(players, playerX.playerID)
|
||||
}
|
||||
}()
|
||||
}
|
||||
playersMutex.Unlock()
|
||||
wgX2.Wait()
|
||||
playerUpdateMutex.Unlock()
|
||||
})
|
||||
}
|
||||
totalTicking += profileSection(func() {
|
||||
playerUpdateMutex.Lock()
|
||||
bulletMutex.RLock()
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).tick(gameMap, bulletParticles, bullets, players)
|
||||
}
|
||||
bulletMutex.RUnlock()
|
||||
playersMutex.RLock()
|
||||
for _, player := range players {
|
||||
if player.local {
|
||||
continue
|
||||
}
|
||||
go player.updateRemotePlayerMap()
|
||||
go player.updateRemotePlayerBases(bases)
|
||||
go player.updateRemotePlayerBullets(bullets)
|
||||
go player.updateRemotePlayerBulletParticles(bulletParticles)
|
||||
go player.updateRemotePlayerPlayers(players)
|
||||
fail := player.sendInfoToPlayer()
|
||||
if fail {
|
||||
if player.connection != nil {
|
||||
(*player.connection).Close()
|
||||
}
|
||||
delete(players, player.playerID)
|
||||
continue
|
||||
}
|
||||
fail = player.sendUpdatesToPlayer(players)
|
||||
if fail {
|
||||
if player.connection != nil {
|
||||
(*player.connection).Close()
|
||||
}
|
||||
delete(players, player.playerID)
|
||||
continue
|
||||
}
|
||||
(*player).tick(bullets)
|
||||
}
|
||||
}
|
||||
|
||||
playerUpdateMutex.Lock()
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).tick(gameMap, bulletParticles, bullets, players)
|
||||
}
|
||||
for _, player := range players {
|
||||
if player.local {
|
||||
continue
|
||||
playersMutex.RUnlock()
|
||||
baseMutex.RLock()
|
||||
for _, base := range bases {
|
||||
(*base).tick(players)
|
||||
}
|
||||
(*player).tick(bullets)
|
||||
}
|
||||
for _, base := range bases {
|
||||
(*base).tick(players)
|
||||
}
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.tick(bulletParticles)
|
||||
}
|
||||
playerUpdateMutex.Unlock()
|
||||
baseMutex.RUnlock()
|
||||
bulletParticleMutex.RLock()
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.tick(bulletParticles)
|
||||
}
|
||||
bulletParticleMutex.RUnlock()
|
||||
playerUpdateMutex.Unlock()
|
||||
})
|
||||
tickCount++
|
||||
}
|
||||
|
||||
func initPlayer(playerIndex uint8, player *Player) {
|
||||
@ -387,18 +469,26 @@ func doPlayerFrame(playerIndex uint8, player *Player, players map[uint32]*Player
|
||||
player.track(player.camera)
|
||||
gameMap.render(player.camera, player.playSurface)
|
||||
|
||||
bulletMutex.RLock()
|
||||
for _, bullet := range bullets {
|
||||
(*bullet).render(player.camera, player.playSurface, bullets)
|
||||
}
|
||||
bulletMutex.RUnlock()
|
||||
baseMutex.RLock()
|
||||
for _, base := range bases {
|
||||
(*base).render(player.camera, player.playSurface, bases)
|
||||
}
|
||||
baseMutex.RUnlock()
|
||||
playersMutex.RLock()
|
||||
for _, playerLoop := range players {
|
||||
(*playerLoop).render(player.camera, player.playSurface, players)
|
||||
}
|
||||
playersMutex.RUnlock()
|
||||
bulletParticleMutex.RLock()
|
||||
for _, bulletParticle := range bulletParticles {
|
||||
bulletParticle.render(player.camera, player.playSurface, bulletParticles)
|
||||
}
|
||||
bulletParticleMutex.RUnlock()
|
||||
|
||||
player.tick(bullets)
|
||||
player.gameObject.prevBaseRect = player.gameObject.baseRect
|
||||
|
15
profiler.go
15
profiler.go
@ -18,14 +18,20 @@ func logProfilingInfo(handleEventsTime, renderTime, scaleTime, frameTime, frameC
|
||||
fmt.Printf("Average render time: %f ms\n", float64(renderTime)/floatFrame)
|
||||
fmt.Printf("Average scaling time: %f ms\n", float64(scaleTime)/floatFrame)
|
||||
fmt.Printf("Average frame time: %f ms\n", float64(frameTime)/floatFrame)
|
||||
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
func logMapProfilingInfo(renderTime, scaleTime, frameTime, frameCount uint64) {
|
||||
func logMapProfilingInfo(renderTime, scaleTime, frameTime, totalGameLogicCatchUp, totalNormalGameLogic, totalTicking, totalRemotePlayerUpdate, tickCount, frameCount uint64) {
|
||||
floatFrame := float64(frameCount)
|
||||
floatTick := float64(tickCount)
|
||||
fmt.Printf("Average map render time: %f ms\n", float64(renderTime)/floatFrame)
|
||||
fmt.Printf("Average map scaling time: %f ms\n", float64(scaleTime)/floatFrame)
|
||||
fmt.Printf("Average full render time: %f ms\n", float64(frameTime)/floatFrame)
|
||||
fmt.Printf("Average total gamelogic catching up time: %f ms\n", float64(totalGameLogicCatchUp)/floatFrame)
|
||||
fmt.Printf("Average normal gamelogic time: %f ms\n", float64(totalNormalGameLogic)/floatFrame)
|
||||
fmt.Printf("Average ticking time: %f ms\n", float64(totalTicking)/floatTick)
|
||||
fmt.Printf("Average remote player update time: %f ms\n", float64(totalRemotePlayerUpdate)/floatTick)
|
||||
fmt.Print("\n")
|
||||
}
|
||||
|
||||
@ -37,11 +43,16 @@ func resetProfilingCounters(handleEventsTime, renderTime, scaleTime, frameTime *
|
||||
*frameCount = 0
|
||||
}
|
||||
|
||||
func resetMapProfilingCounters(renderTime, scaleTime, frameTime *uint64, frameCount *uint64) {
|
||||
func resetMapProfilingCounters(renderTime, scaleTime, frameTime, totalGameLogicCatchUp, totalNormalGameLogic, totalTicking, totalRemotePlayerUpdate *uint64, frameCount, tickCount *uint64) {
|
||||
*renderTime = 0
|
||||
*scaleTime = 0
|
||||
*frameTime = 0
|
||||
*frameCount = 0
|
||||
*totalGameLogicCatchUp = 0
|
||||
*totalNormalGameLogic = 0
|
||||
*totalTicking = 0
|
||||
*totalRemotePlayerUpdate = 0
|
||||
*tickCount = 0
|
||||
}
|
||||
|
||||
func enforceFrameRate(frameStart uint64, targetFPS int) {
|
||||
|
@ -23,6 +23,7 @@ message Bullet {
|
||||
Color color = 3;
|
||||
uint32 id = 4;
|
||||
bool super = 5;
|
||||
uint32 ownerID = 6;
|
||||
}
|
||||
|
||||
message Color {
|
||||
@ -63,6 +64,7 @@ message ServerInfo {
|
||||
uint32 blastRadius = 21;
|
||||
uint32 playerID = 22;
|
||||
uint32 playerColorID = 23;
|
||||
uint32 reloadWait = 24;
|
||||
}
|
||||
|
||||
message PlayerUpdate {
|
||||
|
Loading…
Reference in New Issue
Block a user