Compare commits
3
Commits
0e509ad752
...
testing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
75eff6c5ad | ||
|
|
84d63ba4c1 | ||
|
|
49b84c8540 |
+16
-12
@@ -34,8 +34,8 @@ func loadModelAnimations(animPaths map[string]string) (types.AnimationSet, error
|
|||||||
|
|
||||||
func LoadModels() ([]types.ModelAsset, error) {
|
func LoadModels() ([]types.ModelAsset, error) {
|
||||||
// Goonion model and animations
|
// Goonion model and animations
|
||||||
goonerModel := rl.LoadModel("resources/models/biped/Animation_Unsteady_Walk_withSkin.glb")
|
goonerModel := rl.LoadModel("resources/models/gooner/walk_no_y_transform.glb")
|
||||||
goonerAnims, _ := loadModelAnimations(map[string]string{"idle": "resources/models/biped/Animation_Idle_withSkin.glb", "walk": "resources/models/biped/Animation_Unsteady_Walk_withSkin.glb"})
|
goonerAnims, _ := loadModelAnimations(map[string]string{"idle": "resources/models/gooner/idle_no_y_transform.glb", "walk": "resources/models/gooner/walk_no_y_transform.glb"})
|
||||||
|
|
||||||
// Apply transformations
|
// Apply transformations
|
||||||
transform := rl.MatrixIdentity()
|
transform := rl.MatrixIdentity()
|
||||||
@@ -45,15 +45,12 @@ func LoadModels() ([]types.ModelAsset, error) {
|
|||||||
goonerModel.Transform = transform
|
goonerModel.Transform = transform
|
||||||
|
|
||||||
// Coomer model (ready for animations)
|
// Coomer model (ready for animations)
|
||||||
coomerModel := rl.LoadModel("resources/models/coomer.obj")
|
coomerModel := rl.LoadModel("resources/models/coomer/idle_notransy.glb")
|
||||||
coomerTexture := rl.LoadTexture("resources/models/coomer.png")
|
// coomerTexture := rl.LoadTexture("resources/models/coomer.png")
|
||||||
rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture)
|
// rl.SetMaterialTexture(coomerModel.Materials, rl.MapDiffuse, coomerTexture)
|
||||||
// When you have animations, add them like:
|
// When you have animations, add them like:
|
||||||
// coomerAnims, _ := loadModelAnimations("resources/models/coomer.glb",
|
coomerAnims, _ := loadModelAnimations(map[string]string{"idle": "resources/models/coomer/idle_notransy.glb", "walk": "resources/models/coomer/unsteadywalk_notransy.glb"})
|
||||||
// map[string]string{
|
coomerModel.Transform = transform
|
||||||
// "idle": "resources/models/coomer_idle.glb",
|
|
||||||
// "walk": "resources/models/coomer_walk.glb",
|
|
||||||
// })
|
|
||||||
|
|
||||||
// Shreke model (ready for animations)
|
// Shreke model (ready for animations)
|
||||||
shrekeModel := rl.LoadModel("resources/models/shreke.obj")
|
shrekeModel := rl.LoadModel("resources/models/shreke.obj")
|
||||||
@@ -69,11 +66,18 @@ func LoadModels() ([]types.ModelAsset, error) {
|
|||||||
return []types.ModelAsset{
|
return []types.ModelAsset{
|
||||||
{
|
{
|
||||||
Model: goonerModel,
|
Model: goonerModel,
|
||||||
Animation: append(goonerAnims.Idle, goonerAnims.Walk...), // For compatibility
|
Animation: append(goonerAnims.Idle, goonerAnims.Walk...),
|
||||||
AnimFrames: int32(len(goonerAnims.Idle) + len(goonerAnims.Walk)),
|
AnimFrames: int32(len(goonerAnims.Idle) + len(goonerAnims.Walk)),
|
||||||
Animations: goonerAnims,
|
Animations: goonerAnims,
|
||||||
|
YOffset: 0.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Model: coomerModel,
|
||||||
|
Animation: append(coomerAnims.Idle, coomerAnims.Walk...),
|
||||||
|
AnimFrames: int32(len(coomerAnims.Idle) + len(coomerAnims.Walk)),
|
||||||
|
Animations: coomerAnims,
|
||||||
|
YOffset: -4.0,
|
||||||
},
|
},
|
||||||
{Model: coomerModel, Texture: coomerTexture},
|
|
||||||
{Model: shrekeModel, Texture: shrekeTexture},
|
{Model: shrekeModel, Texture: shrekeTexture},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
-2287
File diff suppressed because it is too large
Load Diff
+10
-8
@@ -25,12 +25,14 @@ type Chat struct {
|
|||||||
cursorPos int
|
cursorPos int
|
||||||
scrollOffset int
|
scrollOffset int
|
||||||
userData interface{}
|
userData interface{}
|
||||||
|
input InputHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewChat() *Chat {
|
func NewChat() *Chat {
|
||||||
return &Chat{
|
return &Chat{
|
||||||
messages: make([]types.ChatMessage, 0, maxMessages),
|
messages: make([]types.ChatMessage, 0, maxMessages),
|
||||||
inputBuffer: make([]rune, 0, runeLimit),
|
inputBuffer: make([]rune, 0, runeLimit),
|
||||||
|
input: &RaylibInput{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,23 +155,23 @@ func (c *Chat) Update() (string, bool) {
|
|||||||
c.scrollOffset = clamp(c.scrollOffset-int(wheelMove), 0, maxScroll)
|
c.scrollOffset = clamp(c.scrollOffset-int(wheelMove), 0, maxScroll)
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyT) {
|
if c.input.IsKeyPressed(rl.KeyT) {
|
||||||
c.isTyping = true
|
c.isTyping = true
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
key := rl.GetCharPressed()
|
key := c.input.GetCharPressed()
|
||||||
for key > 0 {
|
for key > 0 {
|
||||||
if len(c.inputBuffer) < runeLimit {
|
if len(c.inputBuffer) < runeLimit {
|
||||||
c.inputBuffer = append(c.inputBuffer[:c.cursorPos], append([]rune{key}, c.inputBuffer[c.cursorPos:]...)...)
|
c.inputBuffer = append(c.inputBuffer[:c.cursorPos], append([]rune{key}, c.inputBuffer[c.cursorPos:]...)...)
|
||||||
c.cursorPos++
|
c.cursorPos++
|
||||||
}
|
}
|
||||||
key = rl.GetCharPressed()
|
key = c.input.GetCharPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyEnter) || rl.IsKeyPressed(rl.KeyKpEnter) {
|
if c.input.IsKeyPressed(rl.KeyEnter) || c.input.IsKeyPressed(rl.KeyKpEnter) {
|
||||||
if len(c.inputBuffer) > 0 {
|
if len(c.inputBuffer) > 0 {
|
||||||
message := string(c.inputBuffer)
|
message := string(c.inputBuffer)
|
||||||
c.inputBuffer = c.inputBuffer[:0]
|
c.inputBuffer = c.inputBuffer[:0]
|
||||||
@@ -180,21 +182,21 @@ func (c *Chat) Update() (string, bool) {
|
|||||||
c.isTyping = false
|
c.isTyping = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyEscape) && c.isTyping {
|
if c.input.IsKeyPressed(rl.KeyEscape) && c.isTyping {
|
||||||
c.inputBuffer = c.inputBuffer[:0]
|
c.inputBuffer = c.inputBuffer[:0]
|
||||||
c.cursorPos = 0
|
c.cursorPos = 0
|
||||||
c.isTyping = false
|
c.isTyping = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyBackspace) && c.cursorPos > 0 {
|
if c.input.IsKeyPressed(rl.KeyBackspace) && c.cursorPos > 0 {
|
||||||
c.inputBuffer = append(c.inputBuffer[:c.cursorPos-1], c.inputBuffer[c.cursorPos:]...)
|
c.inputBuffer = append(c.inputBuffer[:c.cursorPos-1], c.inputBuffer[c.cursorPos:]...)
|
||||||
c.cursorPos--
|
c.cursorPos--
|
||||||
}
|
}
|
||||||
|
|
||||||
if rl.IsKeyPressed(rl.KeyLeft) && c.cursorPos > 0 {
|
if c.input.IsKeyPressed(rl.KeyLeft) && c.cursorPos > 0 {
|
||||||
c.cursorPos--
|
c.cursorPos--
|
||||||
}
|
}
|
||||||
if rl.IsKeyPressed(rl.KeyRight) && c.cursorPos < len(c.inputBuffer) {
|
if c.input.IsKeyPressed(rl.KeyRight) && c.cursorPos < len(c.inputBuffer) {
|
||||||
c.cursorPos++
|
c.cursorPos++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/testutils"
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/types"
|
||||||
|
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestChat_AddMessage(t *testing.T) {
|
||||||
|
chat := NewChat()
|
||||||
|
|
||||||
|
// Test adding single message
|
||||||
|
chat.AddMessage(1, "Hello")
|
||||||
|
assert.Equal(t, 1, len(chat.messages))
|
||||||
|
assert.Equal(t, int32(1), chat.messages[0].PlayerID)
|
||||||
|
assert.Equal(t, "Hello", chat.messages[0].Content)
|
||||||
|
|
||||||
|
// Test message limit
|
||||||
|
for i := 0; i < maxMessages+10; i++ {
|
||||||
|
chat.AddMessage(1, "spam")
|
||||||
|
}
|
||||||
|
assert.Equal(t, maxMessages, len(chat.messages))
|
||||||
|
assert.Equal(t, "spam", chat.messages[len(chat.messages)-1].Content)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChat_HandleServerMessages(t *testing.T) {
|
||||||
|
chat := NewChat()
|
||||||
|
mockGame := &Game{
|
||||||
|
Player: &types.Player{ID: 1},
|
||||||
|
OtherPlayers: map[int32]*types.Player{
|
||||||
|
2: {ID: 2},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
chat.userData = mockGame
|
||||||
|
|
||||||
|
messages := []*pb.ChatMessage{
|
||||||
|
{
|
||||||
|
PlayerId: 1,
|
||||||
|
Username: "player1",
|
||||||
|
Content: "test1",
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
PlayerId: 2,
|
||||||
|
Username: "player2",
|
||||||
|
Content: "test2",
|
||||||
|
Timestamp: time.Now().UnixNano(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
chat.HandleServerMessages(messages)
|
||||||
|
assert.Equal(t, 2, len(chat.messages))
|
||||||
|
assert.Equal(t, "test1", chat.messages[0].Content)
|
||||||
|
assert.Equal(t, "test2", chat.messages[1].Content)
|
||||||
|
|
||||||
|
// Test duplicate message prevention
|
||||||
|
chat.HandleServerMessages(messages)
|
||||||
|
assert.Equal(t, 2, len(chat.messages))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChat_Update(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
done := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
game, cleanup := setupTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
chat := game.Chat
|
||||||
|
|
||||||
|
// Test starting chat
|
||||||
|
testutils.SimulateKeyPress(rl.KeyT)
|
||||||
|
msg, sent := chat.Update()
|
||||||
|
assert.True(t, chat.isTyping)
|
||||||
|
assert.False(t, sent)
|
||||||
|
assert.Empty(t, msg)
|
||||||
|
|
||||||
|
// Test typing message
|
||||||
|
testutils.SimulateCharInput('h')
|
||||||
|
msg, sent = chat.Update()
|
||||||
|
testutils.SimulateCharInput('i')
|
||||||
|
msg, sent = chat.Update()
|
||||||
|
assert.Equal(t, 2, len(chat.inputBuffer))
|
||||||
|
assert.False(t, sent)
|
||||||
|
assert.Empty(t, msg)
|
||||||
|
|
||||||
|
// Test sending message
|
||||||
|
testutils.SimulateKeyPress(rl.KeyEnter)
|
||||||
|
msg, sent = chat.Update()
|
||||||
|
assert.True(t, sent)
|
||||||
|
assert.Equal(t, "hi", msg)
|
||||||
|
assert.False(t, chat.isTyping)
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
// Test completed successfully
|
||||||
|
case <-time.After(5 * time.Second):
|
||||||
|
t.Fatal("Test timed out")
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
-18
@@ -22,6 +22,7 @@ type Game struct {
|
|||||||
QuitChan chan struct{} // Channel to signal shutdown
|
QuitChan chan struct{} // Channel to signal shutdown
|
||||||
loginScreen *LoginScreen
|
loginScreen *LoginScreen
|
||||||
isLoggedIn bool
|
isLoggedIn bool
|
||||||
|
input InputHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
func New() *Game {
|
func New() *Game {
|
||||||
@@ -38,6 +39,7 @@ func New() *Game {
|
|||||||
Chat: NewChat(),
|
Chat: NewChat(),
|
||||||
QuitChan: make(chan struct{}),
|
QuitChan: make(chan struct{}),
|
||||||
loginScreen: NewLoginScreen(),
|
loginScreen: NewLoginScreen(),
|
||||||
|
input: &RaylibInput{},
|
||||||
}
|
}
|
||||||
game.Chat.userData = game
|
game.Chat.userData = game
|
||||||
return game
|
return game
|
||||||
@@ -86,7 +88,7 @@ func (g *Game) Update(deltaTime float32) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle ESC for menu
|
// Handle ESC for menu
|
||||||
if rl.IsKeyPressed(rl.KeyEscape) {
|
if g.input.IsKeyPressed(rl.KeyEscape) {
|
||||||
g.MenuOpen = !g.MenuOpen
|
g.MenuOpen = !g.MenuOpen
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -154,26 +156,26 @@ func (g *Game) DrawPlayer(player *types.Player, model rl.Model) {
|
|||||||
defer player.Unlock()
|
defer player.Unlock()
|
||||||
|
|
||||||
grid := GetMapGrid()
|
grid := GetMapGrid()
|
||||||
|
modelIndex := int(player.ID) % len(g.Models)
|
||||||
|
modelAsset := g.Models[modelIndex]
|
||||||
|
|
||||||
|
const defaultHeight = 8.0 // Default height above tile, fine tune per model in types.ModelAsset
|
||||||
playerPos := rl.Vector3{
|
playerPos := rl.Vector3{
|
||||||
X: player.PosActual.X,
|
X: player.PosActual.X,
|
||||||
Y: grid[player.PosTile.X][player.PosTile.Y].Height*types.TileHeight + 16.0,
|
Y: grid[player.PosTile.X][player.PosTile.Y].Height*types.TileHeight + defaultHeight + modelAsset.YOffset,
|
||||||
Z: player.PosActual.Z,
|
Z: player.PosActual.Z,
|
||||||
}
|
}
|
||||||
|
|
||||||
if player.ID%int32(len(g.Models)) == 0 {
|
// Check if model has animations
|
||||||
modelAsset := g.Models[0]
|
if modelAsset.Animations.Idle != nil || modelAsset.Animations.Walk != nil {
|
||||||
|
if player.IsMoving && len(modelAsset.Animations.Walk) > 0 {
|
||||||
// Check if model has animations
|
anim := modelAsset.Animations.Walk[0] // Use first walk animation
|
||||||
if modelAsset.Animations.Idle != nil || modelAsset.Animations.Walk != nil {
|
player.AnimationFrame = player.AnimationFrame % anim.FrameCount
|
||||||
if player.IsMoving && len(modelAsset.Animations.Walk) > 0 {
|
rl.UpdateModelAnimation(model, anim, player.AnimationFrame)
|
||||||
anim := modelAsset.Animations.Walk[0] // Use first walk animation
|
} else if len(modelAsset.Animations.Idle) > 0 {
|
||||||
player.AnimationFrame = player.AnimationFrame % anim.FrameCount
|
anim := modelAsset.Animations.Idle[0] // Use first idle animation
|
||||||
rl.UpdateModelAnimation(model, anim, player.AnimationFrame)
|
player.AnimationFrame = player.AnimationFrame % anim.FrameCount
|
||||||
} else if len(modelAsset.Animations.Idle) > 0 {
|
rl.UpdateModelAnimation(model, anim, player.AnimationFrame)
|
||||||
anim := modelAsset.Animations.Idle[0] // Use first idle animation
|
|
||||||
player.AnimationFrame = player.AnimationFrame % anim.FrameCount
|
|
||||||
rl.UpdateModelAnimation(model, anim, player.AnimationFrame)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,13 +327,13 @@ func (g *Game) DrawMenu() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check mouse hover
|
// Check mouse hover
|
||||||
mousePoint := rl.GetMousePosition()
|
mousePoint := g.input.GetMousePosition()
|
||||||
mouseHover := rl.CheckCollisionPointRec(mousePoint, buttonRect)
|
mouseHover := rl.CheckCollisionPointRec(mousePoint, buttonRect)
|
||||||
|
|
||||||
// Draw button
|
// Draw button
|
||||||
if mouseHover {
|
if mouseHover {
|
||||||
rl.DrawRectangleRec(buttonRect, rl.ColorAlpha(rl.White, 0.3))
|
rl.DrawRectangleRec(buttonRect, rl.ColorAlpha(rl.White, 0.3))
|
||||||
if rl.IsMouseButtonPressed(rl.MouseLeftButton) {
|
if g.input.IsMouseButtonPressed(toInt32(rl.MouseLeftButton)) {
|
||||||
switch item {
|
switch item {
|
||||||
case "Resume":
|
case "Resume":
|
||||||
g.MenuOpen = false
|
g.MenuOpen = false
|
||||||
|
|||||||
@@ -0,0 +1,106 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/testutils"
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/types"
|
||||||
|
pb "gitea.boner.be/bdnugget/goonserver/actions"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGame_HandleInput(t *testing.T) {
|
||||||
|
game := New()
|
||||||
|
game.Player = &types.Player{
|
||||||
|
ID: 1,
|
||||||
|
Speed: 50.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test valid click
|
||||||
|
simulateMouseRay(rl.Ray{
|
||||||
|
Position: rl.Vector3{X: 0, Y: 10, Z: 0},
|
||||||
|
Direction: rl.Vector3{X: 0, Y: -1, Z: 0},
|
||||||
|
})
|
||||||
|
simulateMouseButton(toInt32(rl.MouseLeftButton), true)
|
||||||
|
game.HandleInput()
|
||||||
|
assert.NotEmpty(t, game.Player.TargetPath)
|
||||||
|
|
||||||
|
// Test invalid click (outside map)
|
||||||
|
simulateMouseRay(rl.Ray{
|
||||||
|
Position: rl.Vector3{X: 1000, Y: 10, Z: 1000},
|
||||||
|
Direction: rl.Vector3{X: 0, Y: -1, Z: 0},
|
||||||
|
})
|
||||||
|
simulateMouseButton(toInt32(rl.MouseLeftButton), true)
|
||||||
|
game.HandleInput()
|
||||||
|
assert.Empty(t, game.Player.TargetPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGame_UpdateCamera(t *testing.T) {
|
||||||
|
game := New()
|
||||||
|
|
||||||
|
// Test zoom limits
|
||||||
|
testutils.SimulateMouseWheel(1.0) // Zoom in
|
||||||
|
testutils.SimulateMouseWheel(1.0)
|
||||||
|
assert.GreaterOrEqual(t, cameraDistance, float32(10.0))
|
||||||
|
|
||||||
|
testutils.SimulateMouseWheel(-1.0) // Zoom out
|
||||||
|
testutils.SimulateMouseWheel(-1.0)
|
||||||
|
assert.LessOrEqual(t, cameraDistance, float32(250.0))
|
||||||
|
|
||||||
|
// Test camera rotation
|
||||||
|
originalYaw := cameraYaw
|
||||||
|
testutils.SimulateKeyDown(rl.KeyRight, true)
|
||||||
|
game.Update(0.1)
|
||||||
|
assert.Greater(t, cameraYaw, originalYaw)
|
||||||
|
|
||||||
|
// Test pitch limits
|
||||||
|
simulateKeyDown(rl.KeyUp, true)
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
game.Update(0.1)
|
||||||
|
}
|
||||||
|
assert.GreaterOrEqual(t, cameraPitch, float32(20.0))
|
||||||
|
assert.LessOrEqual(t, cameraPitch, float32(85.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGame_ChatIntegration(t *testing.T) {
|
||||||
|
game := New()
|
||||||
|
game.Player = &types.Player{ID: 1}
|
||||||
|
|
||||||
|
// Test chat message to action queue
|
||||||
|
testutils.SimulateKeyPress(rl.KeyT)
|
||||||
|
game.Update(0.1)
|
||||||
|
assert.True(t, game.Chat.isTyping)
|
||||||
|
|
||||||
|
testutils.SimulateCharInput('h')
|
||||||
|
testutils.SimulateCharInput('i')
|
||||||
|
testutils.SimulateKeyPress(rl.KeyEnter)
|
||||||
|
game.Update(0.1)
|
||||||
|
|
||||||
|
assert.Equal(t, 1, len(game.Player.ActionQueue))
|
||||||
|
assert.Equal(t, pb.Action_CHAT, game.Player.ActionQueue[0].Type)
|
||||||
|
assert.Equal(t, "hi", game.Player.ActionQueue[0].ChatMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGame_MenuHandling(t *testing.T) {
|
||||||
|
game := New()
|
||||||
|
|
||||||
|
// Test menu toggle
|
||||||
|
assert.False(t, game.MenuOpen)
|
||||||
|
testutils.SimulateKeyPress(rl.KeyEscape)
|
||||||
|
game.Update(0.1)
|
||||||
|
assert.True(t, game.MenuOpen)
|
||||||
|
|
||||||
|
// Test input blocking when menu is open
|
||||||
|
game.Player = &types.Player{ID: 1}
|
||||||
|
testutils.SimulateMouseButton(testutils.ToInt32(rl.MouseLeftButton), true)
|
||||||
|
game.Update(0.1)
|
||||||
|
assert.Empty(t, game.Player.TargetPath)
|
||||||
|
|
||||||
|
// Test menu close
|
||||||
|
testutils.SimulateKeyPress(rl.KeyEscape)
|
||||||
|
game.Update(0.1)
|
||||||
|
assert.False(t, game.MenuOpen)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more test helpers as needed...
|
||||||
+82
-3
@@ -3,16 +3,95 @@ package game
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/mock"
|
||||||
"gitea.boner.be/bdnugget/goonscape/types"
|
"gitea.boner.be/bdnugget/goonscape/types"
|
||||||
rl "github.com/gen2brain/raylib-go/raylib"
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// InputHandler abstracts raylib input functions for testing
|
||||||
|
type InputHandler interface {
|
||||||
|
IsKeyPressed(key int32) bool
|
||||||
|
IsKeyDown(key int32) bool
|
||||||
|
IsMouseButtonPressed(button int32) bool
|
||||||
|
GetMousePosition() rl.Vector2
|
||||||
|
GetMouseRay(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray
|
||||||
|
GetMouseWheelMove() float32
|
||||||
|
GetCharPressed() rune
|
||||||
|
}
|
||||||
|
|
||||||
|
// RaylibInput implements InputHandler using actual raylib functions
|
||||||
|
type RaylibInput struct{}
|
||||||
|
|
||||||
|
func (r *RaylibInput) IsKeyPressed(key int32) bool { return rl.IsKeyPressed(key) }
|
||||||
|
func (r *RaylibInput) IsKeyDown(key int32) bool { return rl.IsKeyDown(key) }
|
||||||
|
func (r *RaylibInput) IsMouseButtonPressed(button int32) bool {
|
||||||
|
return rl.IsMouseButtonPressed(rl.MouseButton(button))
|
||||||
|
}
|
||||||
|
func (r *RaylibInput) GetMousePosition() rl.Vector2 { return rl.GetMousePosition() }
|
||||||
|
func (r *RaylibInput) GetMouseRay(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray {
|
||||||
|
return rl.GetMouseRay(mousePos, camera)
|
||||||
|
}
|
||||||
|
func (r *RaylibInput) GetMouseWheelMove() float32 { return rl.GetMouseWheelMove() }
|
||||||
|
func (r *RaylibInput) GetCharPressed() rune { return rl.GetCharPressed() }
|
||||||
|
|
||||||
|
// MockInput implements InputHandler using our mock functions
|
||||||
|
type MockInput struct{}
|
||||||
|
|
||||||
|
func (m *MockInput) IsKeyPressed(key int32) bool {
|
||||||
|
if mock.IsKeyPressed == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mock.IsKeyPressed(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) IsKeyDown(key int32) bool {
|
||||||
|
if mock.IsKeyDown == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mock.IsKeyDown(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) IsMouseButtonPressed(button int32) bool {
|
||||||
|
if mock.IsMouseButtonPressed == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mock.IsMouseButtonPressed(button)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) GetMousePosition() rl.Vector2 {
|
||||||
|
if mock.GetMousePosition == nil {
|
||||||
|
return rl.Vector2{}
|
||||||
|
}
|
||||||
|
return mock.GetMousePosition()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) GetMouseRay(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray {
|
||||||
|
if mock.GetMouseRay == nil {
|
||||||
|
return rl.Ray{}
|
||||||
|
}
|
||||||
|
return mock.GetMouseRay(mousePos, camera)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) GetMouseWheelMove() float32 {
|
||||||
|
if mock.GetMouseWheelMove == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return mock.GetMouseWheelMove()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *MockInput) GetCharPressed() rune {
|
||||||
|
if mock.GetCharPressed == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return mock.GetCharPressed()
|
||||||
|
}
|
||||||
|
|
||||||
func (g *Game) GetTileAtMouse() (types.Tile, bool) {
|
func (g *Game) GetTileAtMouse() (types.Tile, bool) {
|
||||||
if !rl.IsMouseButtonPressed(rl.MouseLeftButton) {
|
if !g.input.IsMouseButtonPressed(toInt32(rl.MouseLeftButton)) {
|
||||||
return types.Tile{}, false
|
return types.Tile{}, false
|
||||||
}
|
}
|
||||||
mouse := rl.GetMousePosition()
|
mouse := g.input.GetMousePosition()
|
||||||
ray := rl.GetMouseRay(mouse, g.Camera)
|
ray := g.input.GetMouseRay(mouse, g.Camera)
|
||||||
|
|
||||||
for x := 0; x < types.MapWidth; x++ {
|
for x := 0; x < types.MapWidth; x++ {
|
||||||
for y := 0; y < types.MapHeight; y++ {
|
for y := 0; y < types.MapHeight; y++ {
|
||||||
|
|||||||
@@ -0,0 +1,187 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/testutils"
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/types"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMouseInput_EdgeCases(t *testing.T) {
|
||||||
|
game, cleanup := setupTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
game.Player = &types.Player{ID: 1}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
ray rl.Ray
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Click outside map bounds",
|
||||||
|
ray: rl.Ray{
|
||||||
|
Position: rl.Vector3{X: 1000, Y: 10, Z: 1000},
|
||||||
|
Direction: rl.Vector3{X: 0, Y: -1, Z: 0},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Click at map edge",
|
||||||
|
ray: rl.Ray{
|
||||||
|
Position: rl.Vector3{X: float32(types.MapWidth * types.TileSize), Y: 10, Z: 0},
|
||||||
|
Direction: rl.Vector3{X: 0, Y: -1, Z: 0},
|
||||||
|
},
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Click on valid tile",
|
||||||
|
ray: rl.Ray{
|
||||||
|
Position: rl.Vector3{X: 32, Y: 10, Z: 32},
|
||||||
|
Direction: rl.Vector3{X: 0, Y: -1, Z: 0},
|
||||||
|
},
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
testutils.ResetMockInput()
|
||||||
|
testutils.SimulateMouseRay(tt.ray)
|
||||||
|
testutils.SimulateMouseButton(testutils.ToInt32(rl.MouseLeftButton), true)
|
||||||
|
tile, clicked := game.GetTileAtMouse()
|
||||||
|
assert.Equal(t, tt.expected, clicked)
|
||||||
|
if tt.expected {
|
||||||
|
assert.NotEmpty(t, tile)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChat_InputValidation(t *testing.T) {
|
||||||
|
game, cleanup := setupTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
game.Player = &types.Player{ID: 1}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
input []rune
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Empty message",
|
||||||
|
input: []rune{},
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Message with only spaces",
|
||||||
|
input: []rune(" "),
|
||||||
|
expected: "",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Very long message",
|
||||||
|
input: []rune(string(make([]rune, runeLimit))),
|
||||||
|
expected: string(make([]rune, runeLimit)),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Unicode characters",
|
||||||
|
input: []rune("Hello 世界"),
|
||||||
|
expected: "Hello 世界",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
testutils.ResetMockInput()
|
||||||
|
testutils.SimulateKeyPress(rl.KeyT)
|
||||||
|
game.Update(0.1)
|
||||||
|
|
||||||
|
for _, r := range tt.input {
|
||||||
|
testutils.SimulateCharInput(r)
|
||||||
|
game.Update(0.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
testutils.SimulateKeyPress(rl.KeyEnter)
|
||||||
|
game.Update(0.1)
|
||||||
|
|
||||||
|
if tt.expected != "" {
|
||||||
|
assert.Equal(t, 1, len(game.Player.ActionQueue))
|
||||||
|
assert.Equal(t, tt.expected, game.Player.ActionQueue[0].ChatMessage)
|
||||||
|
} else {
|
||||||
|
assert.Empty(t, game.Player.ActionQueue)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogin_InputValidation(t *testing.T) {
|
||||||
|
_, cleanup := setupTestEnvironment(t)
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
username string
|
||||||
|
password string
|
||||||
|
expectSuccess bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Valid credentials",
|
||||||
|
username: "validuser",
|
||||||
|
password: "validpass",
|
||||||
|
expectSuccess: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty username",
|
||||||
|
username: "",
|
||||||
|
password: "password",
|
||||||
|
expectSuccess: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty password",
|
||||||
|
username: "username",
|
||||||
|
password: "",
|
||||||
|
expectSuccess: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Username too long",
|
||||||
|
username: "verylongusername123",
|
||||||
|
password: "password",
|
||||||
|
expectSuccess: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Special characters in username",
|
||||||
|
username: "user@name",
|
||||||
|
password: "password",
|
||||||
|
expectSuccess: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
login := NewLoginScreen()
|
||||||
|
testutils.ResetMockInput()
|
||||||
|
|
||||||
|
// Simulate typing username
|
||||||
|
login.focusedField = 0
|
||||||
|
for _, r := range tt.username {
|
||||||
|
testutils.SimulateCharInput(r)
|
||||||
|
login.Update()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate typing password
|
||||||
|
login.focusedField = 1
|
||||||
|
for _, r := range tt.password {
|
||||||
|
testutils.SimulateCharInput(r)
|
||||||
|
login.Update()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Simulate clicking login button
|
||||||
|
testutils.SimulateMouseClick(400, 365)
|
||||||
|
_, _, _, submitted := login.Update()
|
||||||
|
assert.Equal(t, tt.expectSuccess, submitted)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/testutils"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestLoginScreen_Update(t *testing.T) {
|
||||||
|
login := NewLoginScreen()
|
||||||
|
|
||||||
|
// Test field focus switching
|
||||||
|
simulateMouseClick(400, 215) // Click username field
|
||||||
|
assert.Equal(t, 0, login.focusedField)
|
||||||
|
|
||||||
|
simulateMouseClick(400, 265) // Click password field
|
||||||
|
assert.Equal(t, 1, login.focusedField)
|
||||||
|
|
||||||
|
// Test input length limits
|
||||||
|
login.focusedField = 0
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
simulateCharInput('x')
|
||||||
|
}
|
||||||
|
assert.LessOrEqual(t, len(login.username), 12)
|
||||||
|
|
||||||
|
login.focusedField = 1
|
||||||
|
for i := 0; i < 30; i++ {
|
||||||
|
simulateCharInput('x')
|
||||||
|
}
|
||||||
|
assert.LessOrEqual(t, len(login.password), 20)
|
||||||
|
|
||||||
|
// Test mode switching
|
||||||
|
simulateMouseClick(600, 365) // Click switch mode button
|
||||||
|
assert.True(t, login.isRegistering)
|
||||||
|
simulateMouseClick(600, 365) // Click again
|
||||||
|
assert.False(t, login.isRegistering)
|
||||||
|
|
||||||
|
// Test submission
|
||||||
|
login.username = "test"
|
||||||
|
login.password = "password"
|
||||||
|
testutils.SimulateMousePosition(400, 365)
|
||||||
|
testutils.SimulateMouseButton(testutils.ToInt32(rl.MouseLeftButton), true)
|
||||||
|
username, password, isRegistering, submitted := login.Update()
|
||||||
|
assert.True(t, submitted)
|
||||||
|
assert.Equal(t, "test", username)
|
||||||
|
assert.Equal(t, "password", password)
|
||||||
|
assert.False(t, isRegistering)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoginScreen_ErrorHandling(t *testing.T) {
|
||||||
|
login := NewLoginScreen()
|
||||||
|
|
||||||
|
// Test empty fields
|
||||||
|
login.username = ""
|
||||||
|
login.password = "test"
|
||||||
|
testutils.SimulateMousePosition(400, 365)
|
||||||
|
testutils.SimulateMouseButton(testutils.ToInt32(rl.MouseLeftButton), true)
|
||||||
|
_, _, _, submitted := login.Update()
|
||||||
|
assert.False(t, submitted)
|
||||||
|
assert.Contains(t, login.errorMessage, "username")
|
||||||
|
|
||||||
|
// Test special characters
|
||||||
|
login.username = "test!@#"
|
||||||
|
login.password = "password"
|
||||||
|
testutils.SimulateMousePosition(400, 365)
|
||||||
|
testutils.SimulateMouseButton(testutils.ToInt32(rl.MouseLeftButton), true)
|
||||||
|
_, _, _, submitted = login.Update()
|
||||||
|
assert.False(t, submitted)
|
||||||
|
assert.Contains(t, login.errorMessage, "invalid characters")
|
||||||
|
|
||||||
|
// Test error message display
|
||||||
|
login.SetError("Test error")
|
||||||
|
assert.Equal(t, "Test error", login.errorMessage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateMouseClick(x, y float32) {
|
||||||
|
// Implementation would depend on how raylib is mocked
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package mock
|
||||||
|
|
||||||
|
import (
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
IsKeyPressed func(key int32) bool
|
||||||
|
IsKeyDown func(key int32) bool
|
||||||
|
IsMouseButtonPressed func(button int32) bool
|
||||||
|
GetMousePosition func() rl.Vector2
|
||||||
|
GetMouseRay func(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray
|
||||||
|
GetMouseWheelMove func() float32
|
||||||
|
GetCharPressed func() rune
|
||||||
|
)
|
||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/mock"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mockInput struct {
|
||||||
|
sync.Mutex
|
||||||
|
keyPressed map[int32]bool
|
||||||
|
keyDown map[int32]bool
|
||||||
|
mousePressed map[int32]bool
|
||||||
|
mousePosition rl.Vector2
|
||||||
|
mouseRay rl.Ray
|
||||||
|
mouseWheel float32
|
||||||
|
charPressed rune
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
resetMockInput()
|
||||||
|
setupMockFunctions()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupMockFunctions() {
|
||||||
|
mock.IsKeyPressed = mockIsKeyPressed
|
||||||
|
mock.IsKeyDown = mockIsKeyDown
|
||||||
|
mock.IsMouseButtonPressed = mockIsMouseButtonPressed
|
||||||
|
mock.GetMousePosition = mockGetMousePosition
|
||||||
|
mock.GetMouseRay = mockGetMouseRay
|
||||||
|
mock.GetMouseWheelMove = mockGetMouseWheelMove
|
||||||
|
mock.GetCharPressed = mockGetCharPressed
|
||||||
|
}
|
||||||
|
|
||||||
|
func resetMockInput() {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
mockInput.keyPressed = make(map[int32]bool)
|
||||||
|
mockInput.keyDown = make(map[int32]bool)
|
||||||
|
mockInput.mousePressed = make(map[int32]bool)
|
||||||
|
mockInput.mousePosition = rl.Vector2{}
|
||||||
|
mockInput.mouseRay = rl.Ray{}
|
||||||
|
mockInput.mouseWheel = 0
|
||||||
|
mockInput.charPressed = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock input simulation functions
|
||||||
|
func simulateKeyPress(key int32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.keyPressed[key] = true
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateKeyDown(key int32, isDown bool) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.keyDown[key] = isDown
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateMouseButton(button int32, isPressed bool) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mousePressed[button] = isPressed
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateMousePosition(x, y float32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mousePosition = rl.Vector2{X: x, Y: y}
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateMouseRay(ray rl.Ray) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mouseRay = ray
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateMouseWheel(move float32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mouseWheel = move
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func simulateCharInput(char rune) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.charPressed = char
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock raylib functions
|
||||||
|
func mockIsKeyPressed(key int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.keyPressed[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockIsKeyDown(key int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.keyDown[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockIsMouseButtonPressed(button int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mousePressed[button]
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetMousePosition() rl.Vector2 {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mousePosition
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetMouseRay(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mouseRay
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetMouseWheelMove() float32 {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mouseWheel
|
||||||
|
}
|
||||||
|
|
||||||
|
func mockGetCharPressed() rune {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.charPressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add more mock implementations...
|
||||||
|
|
||||||
|
// Add this helper function
|
||||||
|
func toInt32(button rl.MouseButton) int32 {
|
||||||
|
return int32(button)
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package game
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/mock"
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/testutils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupTestEnvironment(t *testing.T) (*Game, func()) {
|
||||||
|
testutils.ResetMockInput()
|
||||||
|
testutils.SetupMockFunctions()
|
||||||
|
|
||||||
|
game := New()
|
||||||
|
game.input = &MockInput{}
|
||||||
|
game.Chat.input = &MockInput{} // Also inject mock input into chat
|
||||||
|
|
||||||
|
// Verify mock setup
|
||||||
|
if mock.IsKeyPressed == nil || mock.GetCharPressed == nil {
|
||||||
|
t.Fatal("Mock functions not properly initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
return game, func() {
|
||||||
|
testutils.ResetMockInput()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
package testutils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"gitea.boner.be/bdnugget/goonscape/game/mock"
|
||||||
|
rl "github.com/gen2brain/raylib-go/raylib"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mockInput struct {
|
||||||
|
sync.Mutex
|
||||||
|
keyPressed map[int32]bool
|
||||||
|
keyDown map[int32]bool
|
||||||
|
mousePressed map[int32]bool
|
||||||
|
mousePosition rl.Vector2
|
||||||
|
mouseRay rl.Ray
|
||||||
|
mouseWheel float32
|
||||||
|
charPressed rune
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
ResetMockInput()
|
||||||
|
SetupMockFunctions()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetupMockFunctions initializes mock functions
|
||||||
|
func SetupMockFunctions() {
|
||||||
|
mock.IsKeyPressed = MockIsKeyPressed
|
||||||
|
mock.IsKeyDown = MockIsKeyDown
|
||||||
|
mock.IsMouseButtonPressed = MockIsMouseButtonPressed
|
||||||
|
mock.GetMousePosition = MockGetMousePosition
|
||||||
|
mock.GetMouseRay = MockGetMouseRay
|
||||||
|
mock.GetMouseWheelMove = MockGetMouseWheelMove
|
||||||
|
mock.GetCharPressed = MockGetCharPressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// ResetMockInput resets all mock input states
|
||||||
|
func ResetMockInput() {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
mockInput.keyPressed = make(map[int32]bool)
|
||||||
|
mockInput.keyDown = make(map[int32]bool)
|
||||||
|
mockInput.mousePressed = make(map[int32]bool)
|
||||||
|
mockInput.mousePosition = rl.Vector2{}
|
||||||
|
mockInput.mouseRay = rl.Ray{}
|
||||||
|
mockInput.mouseWheel = 0
|
||||||
|
mockInput.charPressed = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateKeyPress simulates a key press
|
||||||
|
func SimulateKeyPress(key int32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.keyPressed[key] = true
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateKeyDown simulates holding a key down
|
||||||
|
func SimulateKeyDown(key int32, isDown bool) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.keyDown[key] = isDown
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMouseButton simulates a mouse button press
|
||||||
|
func SimulateMouseButton(button int32, isPressed bool) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mousePressed[button] = isPressed
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMousePosition simulates mouse movement
|
||||||
|
func SimulateMousePosition(x, y float32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mousePosition = rl.Vector2{X: x, Y: y}
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMouseClick simulates a mouse click at the given position
|
||||||
|
func SimulateMouseClick(x, y float32) {
|
||||||
|
SimulateMousePosition(x, y)
|
||||||
|
SimulateMouseButton(ToInt32(rl.MouseLeftButton), true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMouseRay simulates a mouse ray
|
||||||
|
func SimulateMouseRay(ray rl.Ray) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mouseRay = ray
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateMouseWheel simulates mouse wheel movement
|
||||||
|
func SimulateMouseWheel(move float32) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.mouseWheel = move
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateCharInput simulates character input
|
||||||
|
func SimulateCharInput(char rune) {
|
||||||
|
mockInput.Lock()
|
||||||
|
mockInput.charPressed = char
|
||||||
|
mockInput.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mock raylib functions
|
||||||
|
func MockIsKeyPressed(key int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.keyPressed[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockIsKeyDown(key int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.keyDown[key]
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockIsMouseButtonPressed(button int32) bool {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mousePressed[button]
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockGetMousePosition() rl.Vector2 {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mousePosition
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockGetMouseRay(mousePos rl.Vector2, camera rl.Camera3D) rl.Ray {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mouseRay
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockGetMouseWheelMove() float32 {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.mouseWheel
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockGetCharPressed() rune {
|
||||||
|
mockInput.Lock()
|
||||||
|
defer mockInput.Unlock()
|
||||||
|
return mockInput.charPressed
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToInt32 converts MouseButton to int32
|
||||||
|
func ToInt32(button rl.MouseButton) int32 {
|
||||||
|
return int32(button)
|
||||||
|
}
|
||||||
@@ -8,8 +8,15 @@ require (
|
|||||||
google.golang.org/protobuf v1.36.3
|
google.golang.org/protobuf v1.36.3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/ebitengine/purego v0.8.2 // indirect
|
github.com/ebitengine/purego v0.8.2 // indirect
|
||||||
|
github.com/stretchr/testify v1.10.0
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect
|
||||||
golang.org/x/sys v0.29.0 // indirect
|
golang.org/x/sys v0.29.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
github.com/ebitengine/purego v0.8.2 h1:jPPGWs2sZ1UgOSgD2bClL0MJIqu58nOmIcBuXr62z1I=
|
||||||
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
github.com/ebitengine/purego v0.8.2/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b h1:JJfspevP3YOXcSKVABizYOv++yMpTJIdPUtoDzF/RWw=
|
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b h1:JJfspevP3YOXcSKVABizYOv++yMpTJIdPUtoDzF/RWw=
|
||||||
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q=
|
github.com/gen2brain/raylib-go/raylib v0.0.0-20250109172833-6dbba4f81a9b/go.mod h1:BaY76bZk7nw1/kVOSQObPY1v1iwVE1KHAGMfvI6oK1Q=
|
||||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA=
|
||||||
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
|
||||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
google.golang.org/protobuf v1.36.3 h1:82DV7MYdb8anAVi3qge1wSnMDrnKK7ebr+I0hHRN1BU=
|
||||||
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
google.golang.org/protobuf v1.36.3/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
-245
@@ -1,245 +0,0 @@
|
|||||||
INFO: Initializing raylib 5.5
|
|
||||||
INFO: Platform backend: DESKTOP (GLFW)
|
|
||||||
INFO: Supported raylib modules:
|
|
||||||
INFO: > rcore:..... loaded (mandatory)
|
|
||||||
INFO: > rlgl:...... loaded (mandatory)
|
|
||||||
INFO: > rshapes:... loaded (optional)
|
|
||||||
INFO: > rtextures:. loaded (optional)
|
|
||||||
INFO: > rtext:..... loaded (optional)
|
|
||||||
INFO: > rmodels:... loaded (optional)
|
|
||||||
INFO: > raudio:.... loaded (optional)
|
|
||||||
INFO: DISPLAY: Device initialized successfully
|
|
||||||
INFO: > Display size: 1920 x 1080
|
|
||||||
INFO: > Screen size: 1024 x 768
|
|
||||||
INFO: > Render size: 1024 x 768
|
|
||||||
INFO: > Viewport offsets: 0, 0
|
|
||||||
INFO: GLAD: OpenGL extensions loaded successfully
|
|
||||||
INFO: GL: Supported extensions count: 390
|
|
||||||
INFO: GL: OpenGL device information:
|
|
||||||
INFO: > Vendor: NVIDIA Corporation
|
|
||||||
INFO: > Renderer: NVIDIA GeForce GTX 1070/PCIe/SSE2
|
|
||||||
INFO: > Version: 3.3.0 NVIDIA 565.77
|
|
||||||
INFO: > GLSL: 3.30 NVIDIA via Cg compiler
|
|
||||||
INFO: GL: VAO extension detected, VAO functions loaded successfully
|
|
||||||
INFO: GL: NPOT textures extension detected, full NPOT textures supported
|
|
||||||
INFO: GL: DXT compressed textures supported
|
|
||||||
INFO: GL: ETC2/EAC compressed textures supported
|
|
||||||
INFO: PLATFORM: DESKTOP (GLFW - X11): Initialized successfully
|
|
||||||
INFO: TEXTURE: [ID 1] Texture loaded successfully (1x1 | R8G8B8A8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 1] Default texture loaded successfully
|
|
||||||
INFO: SHADER: [ID 1] Vertex shader compiled successfully
|
|
||||||
INFO: SHADER: [ID 2] Fragment shader compiled successfully
|
|
||||||
INFO: SHADER: [ID 3] Program shader loaded successfully
|
|
||||||
INFO: SHADER: [ID 3] Default shader loaded successfully
|
|
||||||
INFO: RLGL: Render batch vertex buffers loaded successfully in RAM (CPU)
|
|
||||||
INFO: RLGL: Render batch vertex buffers loaded successfully in VRAM (GPU)
|
|
||||||
INFO: RLGL: Default OpenGL state initialized successfully
|
|
||||||
INFO: TEXTURE: [ID 2] Texture loaded successfully (128x128 | GRAY_ALPHA | 1 mipmaps)
|
|
||||||
INFO: FONT: Default font loaded successfully (224 glyphs)
|
|
||||||
INFO: SYSTEM: Working Directory: /home/bd/Projects/go/goonscape
|
|
||||||
INFO: AUDIO: Device initialized successfully
|
|
||||||
INFO: > Backend: miniaudio | PulseAudio
|
|
||||||
INFO: > Format: 32-bit IEEE Floating Point -> 32-bit Signed Integer
|
|
||||||
INFO: > Channels: 2 -> 2
|
|
||||||
INFO: > Sample rate: 48000 -> 48000
|
|
||||||
INFO: > Periods size: 3600
|
|
||||||
INFO: TIMER: Target time per frame: 16.667 milliseconds
|
|
||||||
INFO: FILEIO: [resources/models/goonion.obj] Text file loaded successfully
|
|
||||||
INFO: FILEIO: [goonion.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 3] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: VAO: [ID 2] Mesh uploaded successfully to VRAM (GPU)
|
|
||||||
WARNING: VAO: [ID 2] Trying to re-load an already loaded mesh
|
|
||||||
INFO: FILEIO: [resources/models/goonion.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 4] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: FILEIO: [resources/models/biped/Animation_Unsteady_Walk_withSkin.glb] File loaded successfully
|
|
||||||
INFO: MODEL: [resources/models/biped/Animation_Unsteady_Walk_withSkin.glb] Loaded animation: Armature|Unsteady_Walk|baselayer (177 frames, 3.000000s)
|
|
||||||
INFO: FILEIO: [resources/models/coomer.obj] Text file loaded successfully
|
|
||||||
INFO: FILEIO: [coomer.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 5] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: VAO: [ID 3] Mesh uploaded successfully to VRAM (GPU)
|
|
||||||
WARNING: VAO: [ID 3] Trying to re-load an already loaded mesh
|
|
||||||
INFO: FILEIO: [resources/models/coomer.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 6] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: FILEIO: [resources/models/shreke.obj] Text file loaded successfully
|
|
||||||
INFO: FILEIO: [shreke.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 7] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: VAO: [ID 4] Mesh uploaded successfully to VRAM (GPU)
|
|
||||||
WARNING: VAO: [ID 4] Trying to re-load an already loaded mesh
|
|
||||||
INFO: FILEIO: [resources/models/shreke.png] File loaded successfully
|
|
||||||
INFO: IMAGE: Data loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: TEXTURE: [ID 8] Texture loaded successfully (2048x2048 | R8G8B8 | 1 mipmaps)
|
|
||||||
INFO: STREAM: Initialized successfully (48000 Hz, 32 bit, Stereo)
|
|
||||||
INFO: FILEIO: [resources/audio/GoonScape2.mp3] Music file loaded successfully
|
|
||||||
INFO: > Sample rate: 48000 Hz
|
|
||||||
INFO: > Sample size: 32 bits
|
|
||||||
INFO: > Channels: 2 (Stereo)
|
|
||||||
INFO: > Total frames: 3487104
|
|
||||||
2025/01/20 12:28:12 Connected to server. Authenticating...
|
|
||||||
2025/01/20 12:28:12 Successfully authenticated with player ID: 6
|
|
||||||
Clicked: 2, 1
|
|
||||||
Path found: [{5 1 1 true} {4 1 5 true} {3 1 4 true} {2 1 3 true}]
|
|
||||||
SIGSEGV: segmentation violation
|
|
||||||
PC=0x69da90 m=0 sigcode=1 addr=0x0
|
|
||||||
signal arrived during cgo execution
|
|
||||||
|
|
||||||
goroutine 1 gp=0xc0000061c0 m=0 mp=0x991ca0 [syscall, locked to thread]:
|
|
||||||
runtime.cgocall(0x5ef7f0, 0xc00002b858)
|
|
||||||
/usr/lib/go/src/runtime/cgocall.go:167 +0x4b fp=0xc00002b830 sp=0xc00002b7f8 pc=0x46a0ab
|
|
||||||
github.com/gen2brain/raylib-go/raylib._Cfunc_UpdateModelAnimation({{0x3f800000, 0x0, 0x0, 0x0, 0x0, 0x3f800000, 0x0, 0x0, 0x0, 0x0, ...}, ...}, ...)
|
|
||||||
_cgo_gotypes.go:7298 +0x45 fp=0xc00002b858 sp=0xc00002b830 pc=0x4db8c5
|
|
||||||
github.com/gen2brain/raylib-go/raylib.UpdateModelAnimation.func1(0x47731a?, 0x1000000?, 0x0)
|
|
||||||
/home/bd/.cache/go/mod/github.com/gen2brain/raylib-go/raylib@v0.0.0-20250109172833-6dbba4f81a9b/rmodels.go:613 +0x1a5 fp=0xc00002ba80 sp=0xc00002b858 pc=0x4dd265
|
|
||||||
github.com/gen2brain/raylib-go/raylib.UpdateModelAnimation({{0x3f800000, 0x0, 0x0, 0x0, 0x0, 0x3f800000, 0x0, 0x0, 0x0, 0x0, ...}, ...}, ...)
|
|
||||||
/home/bd/.cache/go/mod/github.com/gen2brain/raylib-go/raylib@v0.0.0-20250109172833-6dbba4f81a9b/rmodels.go:613 +0x25 fp=0xc00002baa8 sp=0xc00002ba80 pc=0x4dd085
|
|
||||||
gitea.boner.be/bdnugget/goonscape/game.(*Game).DrawPlayer(0xc0001a4000, 0xc0001de160, {{0x3f800000, 0x0, 0x0, 0x0, 0x0, 0x3f800000, 0x0, 0x0, ...}, ...})
|
|
||||||
/home/bd/Projects/go/goonscape/game/game.go:172 +0x2d5 fp=0xc00002bc58 sp=0xc00002baa8 pc=0x5c5c95
|
|
||||||
gitea.boner.be/bdnugget/goonscape/game.(*Game).Render(0xc0001a4000)
|
|
||||||
/home/bd/Projects/go/goonscape/game/game.go:221 +0x147 fp=0xc00002be00 sp=0xc00002bc58 pc=0x5c61e7
|
|
||||||
main.main()
|
|
||||||
/home/bd/Projects/go/goonscape/main.go:55 +0x4ac fp=0xc00002bf50 sp=0xc00002be00 pc=0x5c924c
|
|
||||||
runtime.main()
|
|
||||||
/usr/lib/go/src/runtime/proc.go:272 +0x28b fp=0xc00002bfe0 sp=0xc00002bf50 pc=0x43c42b
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc00002bfe8 sp=0xc00002bfe0 pc=0x4776c1
|
|
||||||
|
|
||||||
goroutine 2 gp=0xc000006c40 m=nil [force gc (idle)]:
|
|
||||||
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000054fa8 sp=0xc000054f88 pc=0x46ff0e
|
|
||||||
runtime.goparkunlock(...)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:430
|
|
||||||
runtime.forcegchelper()
|
|
||||||
/usr/lib/go/src/runtime/proc.go:337 +0xb3 fp=0xc000054fe0 sp=0xc000054fa8 pc=0x43c773
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000054fe8 sp=0xc000054fe0 pc=0x4776c1
|
|
||||||
created by runtime.init.7 in goroutine 1
|
|
||||||
/usr/lib/go/src/runtime/proc.go:325 +0x1a
|
|
||||||
|
|
||||||
goroutine 3 gp=0xc000007180 m=nil [GC sweep wait]:
|
|
||||||
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000055780 sp=0xc000055760 pc=0x46ff0e
|
|
||||||
runtime.goparkunlock(...)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:430
|
|
||||||
runtime.bgsweep(0xc00007e000)
|
|
||||||
/usr/lib/go/src/runtime/mgcsweep.go:277 +0x94 fp=0xc0000557c8 sp=0xc000055780 pc=0x427394
|
|
||||||
runtime.gcenable.gowrap1()
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:204 +0x25 fp=0xc0000557e0 sp=0xc0000557c8 pc=0x41baa5
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000557e8 sp=0xc0000557e0 pc=0x4776c1
|
|
||||||
created by runtime.gcenable in goroutine 1
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:204 +0x66
|
|
||||||
|
|
||||||
goroutine 4 gp=0xc000007340 m=nil [GC scavenge wait]:
|
|
||||||
runtime.gopark(0xc00007e000?, 0x7b0098?, 0x1?, 0x0?, 0xc000007340?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000055f78 sp=0xc000055f58 pc=0x46ff0e
|
|
||||||
runtime.goparkunlock(...)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:430
|
|
||||||
runtime.(*scavengerState).park(0x990ee0)
|
|
||||||
/usr/lib/go/src/runtime/mgcscavenge.go:425 +0x49 fp=0xc000055fa8 sp=0xc000055f78 pc=0x424dc9
|
|
||||||
runtime.bgscavenge(0xc00007e000)
|
|
||||||
/usr/lib/go/src/runtime/mgcscavenge.go:653 +0x3c fp=0xc000055fc8 sp=0xc000055fa8 pc=0x42533c
|
|
||||||
runtime.gcenable.gowrap2()
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:205 +0x25 fp=0xc000055fe0 sp=0xc000055fc8 pc=0x41ba45
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000055fe8 sp=0xc000055fe0 pc=0x4776c1
|
|
||||||
created by runtime.gcenable in goroutine 1
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:205 +0xa5
|
|
||||||
|
|
||||||
goroutine 5 gp=0xc000007c00 m=nil [finalizer wait]:
|
|
||||||
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000056620 sp=0xc000056600 pc=0x46ff0e
|
|
||||||
runtime.runfinq()
|
|
||||||
/usr/lib/go/src/runtime/mfinal.go:193 +0x107 fp=0xc0000567e0 sp=0xc000056620 pc=0x41ab27
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000567e8 sp=0xc0000567e0 pc=0x4776c1
|
|
||||||
created by runtime.createfing in goroutine 1
|
|
||||||
/usr/lib/go/src/runtime/mfinal.go:163 +0x3d
|
|
||||||
|
|
||||||
goroutine 6 gp=0xc000007dc0 m=nil [chan receive]:
|
|
||||||
runtime.gopark(0x6f63a0?, 0x0?, 0x48?, 0x69?, 0x986948?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000054718 sp=0xc0000546f8 pc=0x46ff0e
|
|
||||||
runtime.chanrecv(0xc00008a0e0, 0x0, 0x1)
|
|
||||||
/usr/lib/go/src/runtime/chan.go:639 +0x41c fp=0xc000054790 sp=0xc000054718 pc=0x40bb1c
|
|
||||||
runtime.chanrecv1(0x43c5c0?, 0xc000054776?)
|
|
||||||
/usr/lib/go/src/runtime/chan.go:489 +0x12 fp=0xc0000547b8 sp=0xc000054790 pc=0x40b6f2
|
|
||||||
runtime.unique_runtime_registerUniqueMapCleanup.func1(...)
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:1781
|
|
||||||
runtime.unique_runtime_registerUniqueMapCleanup.gowrap1()
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:1784 +0x2f fp=0xc0000547e0 sp=0xc0000547b8 pc=0x41eacf
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000547e8 sp=0xc0000547e0 pc=0x4776c1
|
|
||||||
created by unique.runtime_registerUniqueMapCleanup in goroutine 1
|
|
||||||
/usr/lib/go/src/runtime/mgc.go:1779 +0x96
|
|
||||||
|
|
||||||
goroutine 20 gp=0xc0001b8000 m=nil [IO wait]:
|
|
||||||
runtime.gopark(0xc0000bdad0?, 0x55fcb8?, 0x8?, 0xaa?, 0xb?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc0000bda68 sp=0xc0000bda48 pc=0x46ff0e
|
|
||||||
runtime.netpollblock(0x4b0778?, 0x408f46?, 0x0?)
|
|
||||||
/usr/lib/go/src/runtime/netpoll.go:575 +0xf7 fp=0xc0000bdaa0 sp=0xc0000bda68 pc=0x434fd7
|
|
||||||
internal/poll.runtime_pollWait(0x7094ad4a5680, 0x72)
|
|
||||||
/usr/lib/go/src/runtime/netpoll.go:351 +0x85 fp=0xc0000bdac0 sp=0xc0000bdaa0 pc=0x46f205
|
|
||||||
internal/poll.(*pollDesc).wait(0xc0001e2080?, 0xc0000d2000?, 0x0)
|
|
||||||
/usr/lib/go/src/internal/poll/fd_poll_runtime.go:84 +0x27 fp=0xc0000bdae8 sp=0xc0000bdac0 pc=0x4bf127
|
|
||||||
internal/poll.(*pollDesc).waitRead(...)
|
|
||||||
/usr/lib/go/src/internal/poll/fd_poll_runtime.go:89
|
|
||||||
internal/poll.(*FD).Read(0xc0001e2080, {0xc0000d2000, 0x1000, 0x1000})
|
|
||||||
/usr/lib/go/src/internal/poll/fd_unix.go:165 +0x27a fp=0xc0000bdb80 sp=0xc0000bdae8 pc=0x4bfa5a
|
|
||||||
net.(*netFD).Read(0xc0001e2080, {0xc0000d2000?, 0xc0000961e0?, 0x2710?})
|
|
||||||
/usr/lib/go/src/net/fd_posix.go:55 +0x25 fp=0xc0000bdbc8 sp=0xc0000bdb80 pc=0x5ae0c5
|
|
||||||
net.(*conn).Read(0xc0001b4030, {0xc0000d2000?, 0x10000000006?, 0xc0001a7b00?})
|
|
||||||
/usr/lib/go/src/net/net.go:189 +0x45 fp=0xc0000bdc10 sp=0xc0000bdbc8 pc=0x5b6345
|
|
||||||
net.(*TCPConn).Read(0x7094f4718a68?, {0xc0000d2000?, 0xedf202a1b?, 0x990e60?})
|
|
||||||
<autogenerated>:1 +0x25 fp=0xc0000bdc40 sp=0xc0000bdc10 pc=0x5c0c05
|
|
||||||
bufio.(*Reader).Read(0xc0000802a0, {0xc0001a7b0c, 0x4, 0x471809?})
|
|
||||||
/usr/lib/go/src/bufio/bufio.go:241 +0x197 fp=0xc0000bdc78 sp=0xc0000bdc40 pc=0x4d93b7
|
|
||||||
io.ReadAtLeast({0x7b2640, 0xc0000802a0}, {0xc0001a7b0c, 0x4, 0x4}, 0x4)
|
|
||||||
/usr/lib/go/src/io/io.go:335 +0x90 fp=0xc0000bdcc0 sp=0xc0000bdc78 pc=0x4aaa10
|
|
||||||
io.ReadFull(...)
|
|
||||||
/usr/lib/go/src/io/io.go:354
|
|
||||||
gitea.boner.be/bdnugget/goonscape/network.HandleServerCommunication({0x7b4bb8, 0xc0001b4030}, 0x6, 0xc0001de160, 0xc000194000, 0xc0001a0000)
|
|
||||||
/home/bd/Projects/go/goonscape/network/network.go:166 +0x412 fp=0xc0000bdfa0 sp=0xc0000bdcc0 pc=0x5c27b2
|
|
||||||
gitea.boner.be/bdnugget/goonscape/game.(*Game).Update.gowrap1()
|
|
||||||
/home/bd/Projects/go/goonscape/game/game.go:80 +0x33 fp=0xc0000bdfe0 sp=0xc0000bdfa0 pc=0x5c57d3
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000bdfe8 sp=0xc0000bdfe0 pc=0x4776c1
|
|
||||||
created by gitea.boner.be/bdnugget/goonscape/game.(*Game).Update in goroutine 1
|
|
||||||
/home/bd/Projects/go/goonscape/game/game.go:80 +0x45e
|
|
||||||
|
|
||||||
goroutine 7 gp=0xc0000c6380 m=nil [select]:
|
|
||||||
runtime.gopark(0xc000050f80?, 0x2?, 0x0?, 0x0?, 0xc000050f10?)
|
|
||||||
/usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000050db0 sp=0xc000050d90 pc=0x46ff0e
|
|
||||||
runtime.selectgo(0xc000050f80, 0xc000050f0c, 0x0?, 0x0, 0x0?, 0x1)
|
|
||||||
/usr/lib/go/src/runtime/select.go:335 +0x7a5 fp=0xc000050ed8 sp=0xc000050db0 pc=0x44e2a5
|
|
||||||
gitea.boner.be/bdnugget/goonscape/network.HandleServerCommunication.func1()
|
|
||||||
/home/bd/Projects/go/goonscape/network/network.go:108 +0xb2 fp=0xc000050fe0 sp=0xc000050ed8 pc=0x5c3492
|
|
||||||
runtime.goexit({})
|
|
||||||
/usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000050fe8 sp=0xc000050fe0 pc=0x4776c1
|
|
||||||
created by gitea.boner.be/bdnugget/goonscape/network.HandleServerCommunication in goroutine 20
|
|
||||||
/home/bd/Projects/go/goonscape/network/network.go:106 +0x3bd
|
|
||||||
|
|
||||||
rax 0x0
|
|
||||||
rbx 0x0
|
|
||||||
rcx 0x0
|
|
||||||
rdx 0x0
|
|
||||||
rdi 0x13ee9800
|
|
||||||
rsi 0xb1
|
|
||||||
rbp 0x13bd6580
|
|
||||||
rsp 0x7ffc9d661890
|
|
||||||
r8 0x140baba0
|
|
||||||
r9 0x0
|
|
||||||
r10 0x0
|
|
||||||
r11 0x0
|
|
||||||
r12 0x13bd1f20
|
|
||||||
r13 0x744e4
|
|
||||||
r14 0x4d898
|
|
||||||
r15 0x26c4c
|
|
||||||
rip 0x69da90
|
|
||||||
rflags 0x10246
|
|
||||||
cs 0x33
|
|
||||||
fs 0x0
|
|
||||||
gs 0x0
|
|
||||||
exit status 2
|
|
||||||
@@ -49,6 +49,7 @@ type ModelAsset struct {
|
|||||||
Animation []rl.ModelAnimation // Keep this for compatibility
|
Animation []rl.ModelAnimation // Keep this for compatibility
|
||||||
AnimFrames int32 // Keep this for compatibility
|
AnimFrames int32 // Keep this for compatibility
|
||||||
Animations AnimationSet // New field for organized animations
|
Animations AnimationSet // New field for organized animations
|
||||||
|
YOffset float32 // Additional height offset (added to default 8.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatMessage struct {
|
type ChatMessage struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user