2024-08-29 00:05:28 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/veandco/go-sdl2/sdl"
|
|
|
|
"image/color"
|
|
|
|
"math/rand"
|
2024-08-30 19:07:56 +02:00
|
|
|
"net"
|
|
|
|
"sync"
|
2024-08-29 00:05:28 +02:00
|
|
|
)
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
var playerUpdateMutex sync.Mutex
|
2024-08-30 19:07:56 +02:00
|
|
|
var lastPlayerID = uint32(0)
|
2024-08-31 15:35:19 +02:00
|
|
|
var playersMutex sync.RWMutex
|
2024-08-30 19:07:56 +02:00
|
|
|
|
2024-08-29 00:05:28 +02:00
|
|
|
type Player struct {
|
2024-09-01 20:13:53 +02:00
|
|
|
local bool
|
|
|
|
connection *net.TCPConn
|
|
|
|
playerColors PlayerColors
|
|
|
|
playerColorID uint32
|
|
|
|
keyMap KeyMap
|
|
|
|
joyMap JoyMap
|
|
|
|
joyStick *sdl.Joystick
|
|
|
|
camera *sdl.Rect
|
|
|
|
energy uint32
|
|
|
|
ammunition uint32
|
|
|
|
shields uint32
|
2024-08-30 19:07:56 +02:00
|
|
|
|
|
|
|
digCooldown uint32
|
|
|
|
shootCooldown uint32
|
|
|
|
repairCooldown uint32
|
|
|
|
rechargeCooldown uint32
|
|
|
|
movementCooldown uint32
|
|
|
|
reloadCooldown uint32
|
2024-08-31 15:35:19 +02:00
|
|
|
reloadWait uint32
|
2024-08-30 19:07:56 +02:00
|
|
|
|
|
|
|
gameObject *GameObject
|
|
|
|
playerID uint32
|
|
|
|
|
|
|
|
knownGameMap *GameMap
|
|
|
|
knownBullets map[uint32]*Bullet
|
|
|
|
knownBulletParticles map[uint32]*BulletParticle
|
|
|
|
knownBases map[uint32]*Base
|
|
|
|
knownPlayers map[uint32]*Player
|
2024-09-01 20:13:53 +02:00
|
|
|
|
|
|
|
previousEnergy uint32
|
|
|
|
previousAmmunition uint32
|
|
|
|
previousShields uint32
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
window *sdl.Window
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
logicalSurface *sdl.Surface
|
|
|
|
playSurface *sdl.Surface
|
|
|
|
HUDSurface *sdl.Surface
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
playSurfaceRect *sdl.Rect
|
|
|
|
HUDSurfaceRect *sdl.Rect
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
playSurfaceTargetRect *sdl.Rect
|
|
|
|
HUDSurfaceTargetRect *sdl.Rect
|
2024-08-29 21:12:18 +02:00
|
|
|
|
|
|
|
totalHandleEventsTime uint64
|
|
|
|
totalRenderTime uint64
|
|
|
|
totalFrameTime uint64
|
|
|
|
totalScalingTime uint64
|
|
|
|
frameCount uint64
|
2024-09-01 20:13:53 +02:00
|
|
|
initialized bool
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
func (player *Player) track(camera *sdl.Rect) {
|
|
|
|
camera.X = player.gameObject.baseRect.X - 37
|
|
|
|
camera.Y = player.gameObject.baseRect.Y - 38
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) render(camera *sdl.Rect, surface *sdl.Surface, players map[uint32]*Player) {
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
if player.shields > 0 &&
|
|
|
|
player.shields <= serverConfig.MaxShields &&
|
|
|
|
player.gameObject.baseRect.X >= 0 &&
|
|
|
|
player.gameObject.baseRect.Y >= 0 {
|
2024-08-29 18:48:27 +02:00
|
|
|
player.gameObject.render(camera, surface)
|
2024-08-30 19:07:56 +02:00
|
|
|
if !player.gameObject.inView && !config.Server {
|
|
|
|
delete(players, player.playerID)
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) tick(bullets map[uint32]*Bullet) {
|
2024-08-29 00:05:28 +02:00
|
|
|
if player.digCooldown > 0 {
|
|
|
|
player.digCooldown--
|
|
|
|
}
|
|
|
|
if player.shootCooldown > 0 {
|
|
|
|
player.shootCooldown--
|
|
|
|
}
|
|
|
|
if player.repairCooldown > 0 {
|
|
|
|
player.repairCooldown--
|
|
|
|
}
|
|
|
|
if player.rechargeCooldown > 0 {
|
|
|
|
player.rechargeCooldown--
|
|
|
|
}
|
|
|
|
if player.movementCooldown > 0 {
|
|
|
|
player.movementCooldown--
|
|
|
|
}
|
2024-08-29 18:48:27 +02:00
|
|
|
if player.reloadCooldown > 0 {
|
|
|
|
player.reloadCooldown--
|
2024-08-31 15:35:19 +02:00
|
|
|
} else if player.ammunition < serverConfig.MaxAmmunition && player.shootCooldown == 0 && player.reloadWait == 0 && player.energy > serverConfig.ReloadCost {
|
2024-08-29 18:48:27 +02:00
|
|
|
player.ammunition++
|
2024-08-30 19:07:56 +02:00
|
|
|
player.reloadCooldown = serverConfig.ReloadCooldown
|
|
|
|
player.energy -= serverConfig.ReloadCost
|
2024-08-29 18:48:27 +02:00
|
|
|
}
|
|
|
|
if player.shields <= 0 {
|
2024-08-30 19:07:56 +02:00
|
|
|
player.shields = serverConfig.MaxShields + 1
|
2024-08-29 18:48:27 +02:00
|
|
|
player.explode(bullets)
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
if player.reloadWait > 0 {
|
|
|
|
player.reloadWait--
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:13:53 +02:00
|
|
|
func (player *Player) digBlock(posX, posY uint32, gameMap *GameMap, isShooting bool) uint8 {
|
|
|
|
collisionAtDigSite := gameMap.checkCollision(int32(posX), int32(posY))
|
2024-08-31 15:35:19 +02:00
|
|
|
if collisionAtDigSite == 0 {
|
|
|
|
return 0
|
|
|
|
} else if collisionAtDigSite == 1 && (player.digCooldown == 0 || isShooting) {
|
|
|
|
if player.energy > serverConfig.DiggingCost {
|
|
|
|
if isShooting && player.energy > serverConfig.ShootDiggingCostBonus {
|
|
|
|
player.energy -= serverConfig.ShootDiggingCostBonus
|
|
|
|
}
|
|
|
|
player.digCooldown = serverConfig.DiggingCooldown
|
|
|
|
} else {
|
|
|
|
player.digCooldown = serverConfig.DiggingCooldownNoEnergy
|
|
|
|
}
|
|
|
|
if isShooting && player.ammunition < serverConfig.MaxAmmunition && rand.Intn(2) == 0 {
|
|
|
|
player.ammunition++
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Client {
|
2024-09-01 20:13:53 +02:00
|
|
|
player.sendDigToServer(posX, posY, isShooting)
|
2024-08-31 15:35:19 +02:00
|
|
|
}
|
|
|
|
gameMap.tiles[posX][posY] = 0
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
return 2
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) tryMove(gameMap *GameMap, isShooting bool, players map[uint32]*Player) (moved bool) {
|
2024-09-01 20:13:53 +02:00
|
|
|
if config.Client {
|
|
|
|
defer player.sendPositionToServer()
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
player.gameObject.adjustBaseRect()
|
2024-08-29 00:05:28 +02:00
|
|
|
if player.movementCooldown > 0 {
|
|
|
|
return false
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
ranOutOfEnergy := (isShooting && player.energy <= serverConfig.DiggingCost+serverConfig.ShootDiggingCostBonus) || player.energy <= serverConfig.DiggingCost
|
2024-08-29 00:05:28 +02:00
|
|
|
if ranOutOfEnergy {
|
|
|
|
isShooting = false
|
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
// Define movement deltas based on orientation
|
|
|
|
movementDeltas := []struct {
|
|
|
|
dx, dy int32
|
|
|
|
}{
|
|
|
|
{0, -1}, {1, 0}, {0, 1}, {-1, 0}, // Up, Right, Down, Left
|
|
|
|
{1, -1}, {-1, -1}, {1, 1}, {-1, 1}, // Up-Right, Up-Left, Down-Right, Down-Left
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
dx, dy := movementDeltas[player.gameObject.orientation].dx, movementDeltas[player.gameObject.orientation].dy
|
|
|
|
// Set collision rectangle
|
|
|
|
player.gameObject.collisionRect = &sdl.Rect{
|
|
|
|
X: player.gameObject.baseRect.X + oNeg(dx),
|
|
|
|
Y: player.gameObject.baseRect.Y + oNeg(dy),
|
|
|
|
W: player.gameObject.baseRect.W + abs(dx),
|
|
|
|
H: player.gameObject.baseRect.H + abs(dy),
|
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
// Check for player collision
|
|
|
|
playersMutex.RLock()
|
|
|
|
for _, opponent := range players {
|
|
|
|
if opponent != player && opponent.gameObject.baseRect.HasIntersection(player.gameObject.collisionRect) {
|
|
|
|
playersMutex.RUnlock()
|
|
|
|
return false
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
}
|
|
|
|
playersMutex.RUnlock()
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
// Initialize flags for movement and digging status
|
|
|
|
stopped := false
|
2024-08-29 00:05:28 +02:00
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
// Check collision and dig at the target position
|
|
|
|
for x := player.gameObject.baseRect.X + oNeg(dx); x < player.gameObject.baseRect.X+dx+player.gameObject.baseRect.W; x++ {
|
|
|
|
for y := player.gameObject.baseRect.Y + oNeg(dy); y < player.gameObject.baseRect.Y+dy+player.gameObject.baseRect.H; y++ {
|
2024-09-01 20:13:53 +02:00
|
|
|
digResult := player.digBlock(uint32(x), uint32(y), gameMap, isShooting)
|
2024-08-31 15:35:19 +02:00
|
|
|
if digResult == 1 { // Successfully dug a block
|
|
|
|
if !isShooting {
|
|
|
|
stopped = true // Stop movement if not shooting
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
} else if digResult == 2 { // Block could not be dug (e.g., solid block)
|
|
|
|
stopped = true
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
if stopped || !(digResult == 0 || (digResult == 1 && isShooting)) {
|
|
|
|
stopped = true
|
|
|
|
break
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
if stopped {
|
|
|
|
break
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
// Move player if there was no obstruction
|
|
|
|
if !stopped {
|
|
|
|
var dxT, dyT int32
|
|
|
|
if dx > 1 {
|
|
|
|
dxT = 1
|
|
|
|
} else if dx < -1 {
|
|
|
|
dxT = -1
|
|
|
|
} else {
|
|
|
|
dxT = dx
|
2024-08-29 18:48:27 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
if dy > 1 {
|
|
|
|
dyT = 1
|
|
|
|
} else if dy < -1 {
|
|
|
|
dyT = -1
|
|
|
|
} else {
|
|
|
|
dyT = dy
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
player.gameObject.baseRect.X += dxT
|
|
|
|
player.gameObject.baseRect.Y += dyT
|
|
|
|
moved = true
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
|
|
|
|
// Send the updated position to the server
|
|
|
|
// Apply movement cooldown
|
2024-08-29 00:05:28 +02:00
|
|
|
if moved {
|
|
|
|
if ranOutOfEnergy {
|
2024-08-30 19:07:56 +02:00
|
|
|
player.movementCooldown = serverConfig.MovementCooldownNoEnergy
|
2024-08-29 00:05:28 +02:00
|
|
|
} else {
|
2024-08-30 19:07:56 +02:00
|
|
|
player.movementCooldown = serverConfig.MovementCooldown
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
|
2024-08-29 00:05:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
func abs(dx int32) int32 {
|
|
|
|
if dx < 0 {
|
|
|
|
return -dx
|
|
|
|
} else {
|
|
|
|
return dx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func oNeg(dx int32) int32 {
|
|
|
|
if dx < 0 {
|
|
|
|
return dx
|
|
|
|
} else {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-29 18:48:27 +02:00
|
|
|
func (player *Player) getRGBAColor(colorIndex uint8, format *sdl.PixelFormat) uint32 {
|
|
|
|
var selectedColor color.Color
|
|
|
|
switch colorIndex {
|
|
|
|
case 0:
|
|
|
|
selectedColor = player.playerColors.tracks
|
|
|
|
case 1:
|
|
|
|
selectedColor = player.playerColors.body
|
|
|
|
case 2:
|
|
|
|
selectedColor = player.playerColors.cannon
|
|
|
|
}
|
|
|
|
var r, g, b, a uint8
|
|
|
|
if selectedColor != nil {
|
|
|
|
rt, gt, bt, at := selectedColor.RGBA()
|
|
|
|
r, g, b, a = uint8(rt), uint8(gt), uint8(bt), uint8(at)
|
|
|
|
}
|
|
|
|
return sdl.MapRGBA(format, r, g, b, a)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2024-09-01 09:12:17 +02:00
|
|
|
type Point struct {
|
|
|
|
X int32
|
|
|
|
Y int32
|
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) shoot(super bool, bullets map[uint32]*Bullet) {
|
|
|
|
if (super && (player.energy <= serverConfig.SuperShotCost || player.ammunition < serverConfig.MaxAmmunition)) || (!super && (player.energy <= serverConfig.NormalShotCost || player.ammunition < 1)) {
|
2024-08-29 00:05:28 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
if player.shootCooldown == 0 {
|
|
|
|
var shootX, shootY int32
|
|
|
|
|
2024-09-01 09:12:17 +02:00
|
|
|
offsets := []Point{
|
|
|
|
{X: 2, Y: 0}, // 0: Up
|
|
|
|
{X: 6, Y: 2}, // 1: Right
|
|
|
|
{X: 2, Y: 6}, // 2: Down
|
|
|
|
{X: 0, Y: 2}, // 3: Left
|
|
|
|
{X: 6, Y: 0}, // 4: Up-Right
|
|
|
|
{X: 0, Y: 0}, // 5: Up-Left
|
|
|
|
{X: 5, Y: 5}, // 6: Down-Right
|
|
|
|
{X: 0, Y: 6}, // 7: Down-Left
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 09:12:17 +02:00
|
|
|
// Access the offset based on the player's orientation
|
|
|
|
shootX = player.gameObject.baseRect.X + offsets[player.gameObject.orientation].X
|
|
|
|
shootY = player.gameObject.baseRect.Y + offsets[player.gameObject.orientation].Y
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
player.shootCooldown = serverConfig.ShootCooldown
|
2024-08-29 00:05:28 +02:00
|
|
|
// Set cooldown and decrease energy
|
|
|
|
if super {
|
2024-08-30 19:07:56 +02:00
|
|
|
player.energy -= serverConfig.SuperShotCost
|
2024-08-29 18:48:27 +02:00
|
|
|
player.ammunition = 0
|
2024-08-29 00:05:28 +02:00
|
|
|
} else {
|
2024-08-30 19:07:56 +02:00
|
|
|
player.energy -= serverConfig.NormalShotCost
|
2024-08-29 18:48:27 +02:00
|
|
|
player.ammunition--
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
player.reloadWait = serverConfig.ReloadWait
|
2024-08-30 19:07:56 +02:00
|
|
|
if config.Client {
|
|
|
|
player.sendShootToServer(super)
|
|
|
|
} else {
|
|
|
|
// Set bullet color
|
|
|
|
bulletColor := player.playerColors.body
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.Lock()
|
2024-08-30 19:07:56 +02:00
|
|
|
// Create and add the bullet
|
|
|
|
bullets[bulletLastID] = &Bullet{
|
|
|
|
posX: shootX,
|
|
|
|
posY: shootY,
|
|
|
|
direction: player.gameObject.orientation,
|
|
|
|
color: bulletColor,
|
|
|
|
super: super,
|
|
|
|
id: bulletLastID,
|
2024-08-31 15:35:19 +02:00
|
|
|
ownerID: player.playerID,
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.Unlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
bulletLastID++
|
|
|
|
}
|
2024-08-29 18:48:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) explode(bullets map[uint32]*Bullet) {
|
2024-08-29 18:48:27 +02:00
|
|
|
// Set bullet color
|
|
|
|
bulletColor := player.playerColors.body
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
for x := player.gameObject.baseRect.X - int32(serverConfig.BlastRadius); x < int32(serverConfig.BlastRadius)*2+1; x++ {
|
|
|
|
for y := player.gameObject.baseRect.Y - int32(serverConfig.BlastRadius); y < int32(serverConfig.BlastRadius)*2+1; y++ {
|
2024-08-29 18:48:27 +02:00
|
|
|
// Create and add the bullet
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.Lock()
|
2024-08-30 19:07:56 +02:00
|
|
|
bullets[bulletLastID] = &Bullet{
|
2024-08-29 18:48:27 +02:00
|
|
|
posX: x,
|
|
|
|
posY: y,
|
|
|
|
direction: uint8(rand.Intn(8)),
|
|
|
|
color: bulletColor,
|
|
|
|
super: true,
|
2024-08-30 19:07:56 +02:00
|
|
|
id: bulletLastID,
|
2024-08-31 15:35:19 +02:00
|
|
|
ownerID: player.playerID,
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.Unlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
bulletLastID++
|
2024-08-29 18:48:27 +02:00
|
|
|
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
func (player *Player) updateRemotePlayerMap(wgX *sync.WaitGroup) {
|
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
fromX := player.gameObject.baseRect.X - (config.CameraW / 2) - 1
|
|
|
|
fromY := player.gameObject.baseRect.Y - (config.CameraH / 2) - 1
|
|
|
|
toX := player.gameObject.baseRect.X + (config.CameraW / 2) + 2
|
|
|
|
toY := player.gameObject.baseRect.Y + (config.CameraH / 2) + 1
|
|
|
|
if uint32(toX) > serverConfig.MapWidth {
|
|
|
|
toX = int32(serverConfig.MapWidth)
|
|
|
|
}
|
|
|
|
if uint32(toY) > serverConfig.MapHeight {
|
|
|
|
toY = int32(serverConfig.MapHeight)
|
|
|
|
}
|
|
|
|
if fromX < 0 {
|
|
|
|
fromX = 0
|
|
|
|
}
|
|
|
|
if fromY < 0 {
|
|
|
|
fromY = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a WaitGroup to wait for all goroutines to finish
|
|
|
|
var wg sync.WaitGroup
|
|
|
|
var lck sync.Mutex
|
|
|
|
|
|
|
|
// Process columns instead of individual pixels
|
|
|
|
for x := fromX; x < toX; x++ {
|
|
|
|
// Increment the WaitGroup counter
|
|
|
|
wg.Add(1)
|
|
|
|
|
|
|
|
// Launch a goroutine for each column
|
|
|
|
go func(x int32) {
|
|
|
|
defer wg.Done() // Decrement the counter when the goroutine completes
|
|
|
|
|
|
|
|
for y := fromY; y < toY; y++ {
|
|
|
|
if player.knownGameMap.tiles[x][y] != gameMap.tiles[x][y] {
|
|
|
|
lck.Lock()
|
2024-09-01 20:13:53 +02:00
|
|
|
kind := gameMap.tiles[x][y]
|
|
|
|
err := sendTileUpdate(
|
|
|
|
uint32(x),
|
|
|
|
uint32(y),
|
|
|
|
kind,
|
|
|
|
player.connection)
|
|
|
|
if err == nil {
|
|
|
|
player.knownGameMap.tiles[x][y] = gameMap.tiles[x][y]
|
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
lck.Unlock()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}(x)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for all goroutines to finish
|
|
|
|
wg.Wait()
|
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
func (player *Player) updateRemotePlayerPlayers(players map[uint32]*Player, wgX *sync.WaitGroup) {
|
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
player.knownPlayers = make(map[uint32]*Player)
|
2024-08-31 15:35:19 +02:00
|
|
|
playersMutex.RLock()
|
2024-08-30 19:07:56 +02:00
|
|
|
for _, playerLoop := range players {
|
|
|
|
player.camera = &sdl.Rect{
|
|
|
|
X: player.gameObject.baseRect.X - (config.CameraW / 2),
|
|
|
|
Y: player.gameObject.baseRect.Y - (config.CameraH / 2),
|
|
|
|
W: config.CameraW,
|
|
|
|
H: config.CameraH,
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, playerLoopRect := range playerLoop.gameObject.getCurrentRects() {
|
|
|
|
if player.camera.HasIntersection(playerLoop.gameObject.adjustRectWorld(playerLoopRect.rect)) && playerLoop.shields <= serverConfig.MaxShields {
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.knownPlayers[playerLoop.playerID] == nil {
|
|
|
|
_ = sendOtherPlayer(
|
|
|
|
playerLoop.playerID,
|
|
|
|
uint32(player.gameObject.baseRect.X),
|
|
|
|
uint32(player.gameObject.baseRect.Y),
|
|
|
|
player.gameObject.orientation,
|
|
|
|
player.connection)
|
|
|
|
player.knownPlayers[playerLoop.playerID] = playerLoop
|
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
playersMutex.RUnlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
func (player *Player) updateRemotePlayerBullets(bullets map[uint32]*Bullet, wgX *sync.WaitGroup) {
|
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
player.knownBullets = make(map[uint32]*Bullet)
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.RLock()
|
2024-08-30 19:07:56 +02:00
|
|
|
for _, bullet := range bullets {
|
|
|
|
bulletRect := &sdl.Rect{
|
|
|
|
X: bullet.posX,
|
|
|
|
Y: bullet.posY,
|
|
|
|
W: 1,
|
|
|
|
H: 1,
|
|
|
|
}
|
|
|
|
player.camera = &sdl.Rect{
|
|
|
|
X: player.gameObject.baseRect.X - (config.CameraW / 2),
|
|
|
|
Y: player.gameObject.baseRect.Y - (config.CameraH / 2),
|
|
|
|
W: config.CameraW,
|
|
|
|
H: config.CameraH,
|
|
|
|
}
|
|
|
|
if player.camera.HasIntersection(bulletRect) {
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.knownBullets[bullet.id] == nil {
|
|
|
|
r, g, b, a := bullet.color.RGBA()
|
|
|
|
_ = sendBullet(
|
|
|
|
uint32(bullet.posX),
|
|
|
|
uint32(bullet.posY),
|
|
|
|
bullet.direction,
|
|
|
|
uint8(r),
|
|
|
|
uint8(g),
|
|
|
|
uint8(b),
|
|
|
|
uint8(a),
|
|
|
|
bullet.id,
|
|
|
|
bullet.super,
|
|
|
|
bullet.ownerID,
|
|
|
|
player.connection)
|
|
|
|
player.knownBullets[bullet.id] = bullet
|
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletMutex.RUnlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
|
2024-08-31 15:35:19 +02:00
|
|
|
func (player *Player) updateRemotePlayerBulletParticles(bulletParticles map[uint32]*BulletParticle, wgX *sync.WaitGroup) {
|
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
player.knownBulletParticles = make(map[uint32]*BulletParticle)
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletParticleMutex.RLock()
|
2024-08-30 19:07:56 +02:00
|
|
|
for _, bulletParticle := range bulletParticles {
|
|
|
|
bulletRect := &sdl.Rect{
|
|
|
|
X: bulletParticle.posX,
|
|
|
|
Y: bulletParticle.posY,
|
|
|
|
W: 1,
|
|
|
|
H: 1,
|
|
|
|
}
|
|
|
|
player.camera = &sdl.Rect{
|
|
|
|
X: player.gameObject.baseRect.X - (config.CameraW / 2),
|
|
|
|
Y: player.gameObject.baseRect.Y - (config.CameraH / 2),
|
|
|
|
W: config.CameraW,
|
|
|
|
H: config.CameraH,
|
|
|
|
}
|
|
|
|
if player.camera.HasIntersection(bulletRect) {
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.knownBullets[bulletParticle.id] == nil {
|
|
|
|
r, g, b, a := bulletParticle.color.RGBA()
|
|
|
|
_ = sendBulletParticle(
|
|
|
|
uint32(bulletParticle.posX),
|
|
|
|
uint32(bulletParticle.posY),
|
|
|
|
bulletParticle.expirationTimer,
|
|
|
|
uint8(r),
|
|
|
|
uint8(g),
|
|
|
|
uint8(b),
|
|
|
|
uint8(a),
|
|
|
|
bulletParticle.id,
|
|
|
|
player.connection)
|
|
|
|
player.knownBulletParticles[bulletParticle.id] = bulletParticle
|
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
bulletParticleMutex.RUnlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:13:53 +02:00
|
|
|
func (player *Player) updateRemotePlayerBases(bases map[uint32]*Base, players map[uint32]*Player, wgX *sync.WaitGroup) {
|
2024-08-31 15:35:19 +02:00
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
player.knownBases = make(map[uint32]*Base)
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.connection == nil || !config.Server {
|
|
|
|
return
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
baseMutex.RLock()
|
2024-08-30 19:07:56 +02:00
|
|
|
for _, base := range bases {
|
|
|
|
player.camera = &sdl.Rect{
|
|
|
|
X: player.gameObject.baseRect.X - (config.CameraW / 2),
|
|
|
|
Y: player.gameObject.baseRect.Y - (config.CameraH / 2),
|
|
|
|
W: config.CameraW,
|
|
|
|
H: config.CameraH,
|
|
|
|
}
|
|
|
|
for _, baseRect := range base.gameObject.getCurrentRects() {
|
|
|
|
if player.camera.HasIntersection(base.gameObject.adjustRectWorld(baseRect.rect)) {
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.knownPlayers[base.ownerID] == nil {
|
|
|
|
_ = sendBaseLocation(
|
|
|
|
uint32(base.gameObject.baseRect.X),
|
|
|
|
uint32(base.gameObject.baseRect.Y),
|
|
|
|
base.ownerID,
|
|
|
|
players[base.ownerID].playerColorID,
|
|
|
|
player.connection)
|
|
|
|
player.knownBases[base.ownerID] = base
|
|
|
|
}
|
2024-08-30 19:07:56 +02:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-08-31 15:35:19 +02:00
|
|
|
baseMutex.RUnlock()
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:13:53 +02:00
|
|
|
func (player *Player) sendPlayerUpdate(wgX *sync.WaitGroup) bool {
|
2024-08-31 15:35:19 +02:00
|
|
|
defer wgX.Done()
|
2024-08-30 19:07:56 +02:00
|
|
|
if player.connection != nil && config.Server {
|
2024-09-01 20:13:53 +02:00
|
|
|
if player.previousEnergy != player.energy ||
|
|
|
|
player.previousShields != player.shields ||
|
|
|
|
player.previousAmmunition != player.ammunition {
|
|
|
|
err := sendPlayerUpdate(player.energy, player.ammunition, player.shields, player.connection)
|
|
|
|
player.previousEnergy = player.energy
|
|
|
|
player.previousShields = player.shields
|
|
|
|
player.previousAmmunition = player.ammunition
|
|
|
|
return err == nil
|
|
|
|
} else {
|
|
|
|
return true
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:13:53 +02:00
|
|
|
func (player *Player) sendServerInfoToPlayer() bool {
|
2024-08-31 15:35:19 +02:00
|
|
|
if player.connection != nil && config.Server {
|
2024-09-01 20:13:53 +02:00
|
|
|
err := sendServerInfo(
|
|
|
|
player.playerID,
|
|
|
|
player.playerColorID,
|
|
|
|
serverConfig.MaxEnergy,
|
|
|
|
serverConfig.MaxAmmunition,
|
|
|
|
serverConfig.MaxShields,
|
|
|
|
serverConfig.MapWidth,
|
|
|
|
serverConfig.MapHeight,
|
|
|
|
serverConfig.NormalShotCost,
|
|
|
|
serverConfig.SuperShotCost,
|
|
|
|
serverConfig.ReloadCost,
|
|
|
|
serverConfig.MovementCost,
|
|
|
|
serverConfig.DiggingCost,
|
|
|
|
serverConfig.ShootDiggingCostBonus,
|
|
|
|
serverConfig.ShootCooldown,
|
|
|
|
serverConfig.RechargeCooldownOwn,
|
|
|
|
serverConfig.RechargeCooldownOpponent,
|
|
|
|
serverConfig.RepairCooldown,
|
|
|
|
serverConfig.DiggingCooldown,
|
|
|
|
serverConfig.MovementCooldown,
|
|
|
|
serverConfig.MovementCooldownNoEnergy,
|
|
|
|
serverConfig.DiggingCooldownNoEnergy,
|
|
|
|
serverConfig.ReloadCooldown,
|
|
|
|
serverConfig.BlastRadius,
|
|
|
|
serverConfig.ReloadWait,
|
|
|
|
player.connection)
|
|
|
|
return err == nil
|
2024-08-31 15:35:19 +02:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (player *Player) sendVersionBackToPlayer() bool {
|
|
|
|
if player.connection != nil && config.Server {
|
2024-09-01 20:13:53 +02:00
|
|
|
|
|
|
|
versionArray := getCurrentVersion()
|
|
|
|
err := sendPlayerStartResponse(
|
|
|
|
versionArray[0],
|
|
|
|
versionArray[1],
|
|
|
|
versionArray[2],
|
|
|
|
player.connection)
|
|
|
|
return err == nil
|
2024-08-31 15:35:19 +02:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func (player *Player) sendLocationToPlayer() bool {
|
|
|
|
if player.connection != nil && config.Server {
|
2024-09-01 20:13:53 +02:00
|
|
|
err := sendPositionUpdate(
|
|
|
|
uint32(player.gameObject.baseRect.X),
|
|
|
|
uint32(player.gameObject.baseRect.Y),
|
|
|
|
player.gameObject.orientation,
|
|
|
|
player.connection)
|
|
|
|
return err == nil
|
2024-08-31 15:35:19 +02:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-08-30 19:07:56 +02:00
|
|
|
func (player *Player) sendPositionToServer() bool {
|
|
|
|
if player.connection != nil && config.Client {
|
2024-09-01 20:13:53 +02:00
|
|
|
err := sendPlayerLocation(
|
|
|
|
uint32(player.gameObject.baseRect.X),
|
|
|
|
uint32(player.gameObject.baseRect.Y),
|
|
|
|
player.gameObject.orientation,
|
|
|
|
player.connection)
|
|
|
|
return err == nil
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2024-08-30 21:20:41 +02:00
|
|
|
func sendVersionToServer(connection *net.TCPConn) {
|
2024-08-30 19:07:56 +02:00
|
|
|
if connection != nil && config.Client {
|
2024-09-01 20:13:53 +02:00
|
|
|
versionArray := getCurrentVersion()
|
|
|
|
_ = sendPlayerStartRequest(
|
|
|
|
versionArray[0],
|
|
|
|
versionArray[1],
|
|
|
|
versionArray[2],
|
|
|
|
connection)
|
|
|
|
|
|
|
|
return
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (player *Player) sendDigToServer(posX, posY uint32, isShooting bool) {
|
|
|
|
if player.connection != nil && config.Client {
|
2024-09-01 20:13:53 +02:00
|
|
|
_ = sendDigBlock(
|
|
|
|
posX,
|
|
|
|
posY,
|
|
|
|
isShooting,
|
|
|
|
player.connection)
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (player *Player) sendShootToServer(isSuper bool) {
|
|
|
|
if player.connection != nil && config.Client {
|
2024-09-01 20:13:53 +02:00
|
|
|
_ = sendShoot(
|
|
|
|
isSuper,
|
|
|
|
player.connection)
|
2024-08-30 19:07:56 +02:00
|
|
|
}
|
2024-08-29 00:05:28 +02:00
|
|
|
}
|