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