Archived
1
0
Fork 0

cgo wrapper file

This commit is contained in:
Sebastian Benjamin 2025-04-22 18:15:22 -07:00
parent c41604e35b
commit 234b1df8f3
4 changed files with 117 additions and 53 deletions

View file

@ -1,6 +1,6 @@
[gd_scene load_steps=5 format=3 uid="uid://dsiowq0rnacln"]
[ext_resource type="PackedScene" uid="uid://cd3tqt7hr5pqs" path="res://danmaku!/Player.tscn" id="1_22cjd"]
[ext_resource type="PackedScene" uid="uid://qvo806pvgbdn" path="res://danmaku!/Player.tscn" id="1_22cjd"]
[ext_resource type="Script" uid="uid://ggkxv1cb1bjk" path="res://danmaku!/scaling.gd" id="1_o1mqp"]
[ext_resource type="Script" uid="uid://cd67rrch5h4t7" path="res://danmaku!/network_manager.gd" id="2_b2dol"]
[ext_resource type="Script" uid="uid://ddc5iqgtyv2ns" path="res://danmaku!/BulletManager.gd" id="4_ubrrh"]

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://cd3tqt7hr5pqs"]
[gd_scene load_steps=7 format=3 uid="uid://qvo806pvgbdn"]
[ext_resource type="Script" uid="uid://bhwiun72wpk6e" path="res://danmaku!/player.gd" id="1_r7xhp"]
[ext_resource type="Texture2D" uid="uid://bs3fntlmlqpt2" path="res://icon.svg" id="2_04s0l"]

79
server/ffi.go Normal file
View file

@ -0,0 +1,79 @@
package main
/*
#cgo CFLAGS: -I ${SRCDIR}/lib
#cgo LDFLAGS: -L ${SRCDIR}/lib -l ffi_wrapper
#include "ffi-wrapper.h"
#include <stdlib.h>
*/
import "C"
// Circles
type Circle struct {
cptr *C.Circle
}
func NewCircle(x float64, y float64, rad float64) Circle {
return Circle{
cptr: C.new_circle(C.double(x), C.double(y), C.double(rad)),
}
}
func (c *Circle) UpdatePos(x float64, y float64) {
c.cptr.x = C.double(x)
c.cptr.y = C.double(y)
}
func DestroyCircle(circle Circle) {
if circle.cptr == nil {
return
}
C.destroy_circle(circle.cptr)
}
func (c *Circle) GetPos() (float64, float64) {
return float64(c.cptr.x), float64(c.cptr.y)
}
// Bullets
type Bullet struct {
cptr *C.Bullet
}
func NewLinearBullet(tick int64, spawnX float64, spawnY float64, radius float64, velX float64, velY float64) Bullet {
return Bullet{
cptr: C.new_bullet(
C.uint8_t(0),
C.int64_t(tick),
C.double(spawnX),
C.double(spawnY),
C.double(radius),
C.double(velX),
C.double(velY),
),
}
}
func DestroyBullet(bullet Bullet) {
if bullet.cptr == nil {
return
}
C.destroy_bullet(bullet.cptr)
}
func (b *Bullet) BeyondKillBoundary(tick int64) bool {
return bool(C.bullet_beyond_kill_boundary(b.cptr, C.int64_t(tick)))
}
func (b *Bullet) CollidesWith(circle Circle, tick int64) bool {
return bool(C.bullet_collides_with(b.cptr, C.int64_t(tick), circle.cptr))
}
func (b *Bullet) GetPos(tick int64) (float64, float64) {
var x, y C.double
C.bullet_get_current_pos(b.cptr, C.int64_t(tick), &x, &y)
return float64(x), float64(y)
}

View file

@ -1,13 +1,5 @@
package main
/*
#cgo CFLAGS: -I ${SRCDIR}/lib
#cgo LDFLAGS: -L ${SRCDIR}/lib -l ffi_wrapper
#include "ffi-wrapper.h"
#include <stdlib.h>
*/
import "C"
import (
"context"
"database/sql"
@ -44,9 +36,9 @@ const (
type BattleRoyaleMatch struct{}
type PlayerStageState struct {
hitCol *C.Circle
grazeCol *C.Circle
bullets []*C.Bullet
hitCol Circle
grazeCol Circle
bullets []Bullet
updatePlayerPos bool
health int
graze int
@ -120,9 +112,9 @@ func (m *BattleRoyaleMatch) MatchJoin(ctx context.Context, logger runtime.Logger
lobbyState.presences[presences[i].GetSessionId()] = &PresenceState{
presence: presences[i],
stageState: PlayerStageState{
hitCol: C.new_circle(C.double(STAGE_WIDTH*0.5), C.double(STAGE_HEIGHT-STAGE_HEIGHT*0.1), C.double(STAGE_WIDTH*PLAYER_HIT_COL_RADIUS_MULTIPLIER)),
grazeCol: C.new_circle(C.double(STAGE_WIDTH*0.5), C.double(STAGE_HEIGHT-STAGE_HEIGHT*0.1), C.double(STAGE_WIDTH*PLAYER_GRAZE_COL_RADIUS_MULTIPLIER)),
bullets: []*C.Bullet{},
hitCol: NewCircle(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1, STAGE_WIDTH*PLAYER_HIT_COL_RADIUS_MULTIPLIER),
grazeCol: NewCircle(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1, STAGE_WIDTH*PLAYER_GRAZE_COL_RADIUS_MULTIPLIER),
bullets: []Bullet{},
updatePlayerPos: true,
health: 3,
deathTimer: -1,
@ -147,10 +139,10 @@ func (m *BattleRoyaleMatch) MatchLeave(ctx context.Context, logger runtime.Logge
playerState, exists := lobbyState.presences[sessionID]
if exists {
for _, bullet := range playerState.stageState.bullets {
C.destroy_bullet(bullet)
DestroyBullet(bullet)
}
C.destroy_circle(playerState.stageState.hitCol)
C.destroy_circle(playerState.stageState.grazeCol)
DestroyCircle(playerState.stageState.hitCol)
DestroyCircle(playerState.stageState.grazeCol)
delete(lobbyState.presences, sessionID)
}
}
@ -222,11 +214,8 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
update.X = math.Max(0, math.Min(update.X, STAGE_WIDTH))
update.Y = math.Max(0, math.Min(update.Y, STAGE_HEIGHT))
lobbyState.presences[msg.GetSessionId()].stageState.hitCol.x = C.double(update.X)
lobbyState.presences[msg.GetSessionId()].stageState.hitCol.y = C.double(update.Y)
lobbyState.presences[msg.GetSessionId()].stageState.grazeCol.x = C.double(update.X)
lobbyState.presences[msg.GetSessionId()].stageState.grazeCol.y = C.double(update.Y)
lobbyState.presences[msg.GetSessionId()].stageState.hitCol.UpdatePos(update.X, update.Y)
lobbyState.presences[msg.GetSessionId()].stageState.grazeCol.UpdatePos(update.X, update.Y)
if clampedX || clampedY {
lobbyState.presences[msg.GetSessionId()].stageState.updatePlayerPos = true
@ -236,9 +225,9 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
// Compute and broadcast per-presence state
for _, v := range lobbyState.presences {
// Clean up bullets when they pass off the board
v.stageState.bullets = slices.DeleteFunc(v.stageState.bullets, func(b *C.Bullet) bool {
if C.bullet_beyond_kill_boundary(b, C.int64_t(tick)) {
C.destroy_bullet(b)
v.stageState.bullets = slices.DeleteFunc(v.stageState.bullets, func(b Bullet) bool {
if b.BeyondKillBoundary(tick) {
DestroyBullet(b)
return true
}
return false
@ -250,20 +239,16 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
}
if v.stageState.deathTimer == 0 { // If the player's death timer has run out, reset them. 0 is a special deathTimer tick that indicates reset to the clients.
v.stageState.hitCol.x = C.double(STAGE_WIDTH * 0.5)
v.stageState.hitCol.y = C.double(STAGE_HEIGHT - STAGE_HEIGHT*0.1)
v.stageState.grazeCol.x = C.double(STAGE_WIDTH * 0.5)
v.stageState.grazeCol.y = C.double(STAGE_HEIGHT - STAGE_HEIGHT*0.1)
v.stageState.hitCol.UpdatePos(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1)
v.stageState.grazeCol.UpdatePos(STAGE_WIDTH*0.5, STAGE_HEIGHT-STAGE_HEIGHT*0.1)
v.stageState.updatePlayerPos = true
} else if v.stageState.deathTimer == -1 { // If the player is alive, check if the player collided with a bullet and kill them if so
if slices.ContainsFunc(v.stageState.bullets, func(b *C.Bullet) bool {
return bool(C.bullet_collides_with(b, C.int64_t(tick), v.stageState.hitCol))
if slices.ContainsFunc(v.stageState.bullets, func(b Bullet) bool {
return b.CollidesWith(v.stageState.hitCol, tick)
}) {
v.stageState.deathTimer = PLAYER_DEATH_TIMER_MAX
} else if slices.ContainsFunc(v.stageState.bullets, func(b *C.Bullet) bool { // Otherwise, check the graze col and increment the graze and score
return bool(C.bullet_collides_with(b, C.int64_t(tick), v.stageState.grazeCol))
} else if slices.ContainsFunc(v.stageState.bullets, func(b Bullet) bool { // Otherwise, check the graze col and increment the graze and score
return b.CollidesWith(v.stageState.grazeCol, tick)
}) {
v.stageState.graze += GRAZE_ADDITION_MULTIPLIER
}
@ -289,26 +274,24 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
velx := bulletSpeed * math.Cos(angleRad)
vely := bulletSpeed * math.Sin(angleRad)
bullet := C.new_bullet(
C.uint8_t(BULLET_LINEAR),
C.int64_t(tick),
C.double(spawnX), // Fixed X start position
C.double(spawnY), // Fixed Y start position
C.double(bulletRadiusMult*STAGE_WIDTH), // Fixed radius
C.double(velx),
C.double(vely),
bullet := NewLinearBullet(
tick,
spawnX,
spawnY,
bulletRadiusMult*STAGE_WIDTH,
velx,
vely,
)
v.stageState.bullets = append(v.stageState.bullets, bullet)
var x, y C.double
C.bullet_get_current_pos(bullet, C.int64_t(tick), &x, &y)
x, y := bullet.GetPos(tick)
bulletData := map[string]interface{}{
"class": BULLET_LINEAR,
"tick": tick,
"x": float64(x),
"y": float64(y),
"x": x,
"y": y,
"radius_multiplier": bulletRadiusMult,
"vel_x": velx,
"vel_y": vely,
@ -318,16 +301,18 @@ func (m *BattleRoyaleMatch) MatchLoop(ctx context.Context, logger runtime.Logger
}
}
hitPosX, hitPosY := v.stageState.hitCol.GetPos()
grazePosX, grazePosY := v.stageState.hitCol.GetPos()
var tickData = GameTickUpdate{
Tick: tick,
PlayerHitPos: map[string]interface{}{
"x": v.stageState.hitCol.x,
"y": v.stageState.hitCol.y,
"x": hitPosX,
"y": hitPosY,
"radius_multiplier": PLAYER_HIT_COL_RADIUS_MULTIPLIER,
},
PlayerGrazePos: map[string]interface{}{
"x": v.stageState.grazeCol.x,
"y": v.stageState.grazeCol.y,
"x": grazePosX,
"y": grazePosY,
"radius_multiplier": PLAYER_GRAZE_COL_RADIUS_MULTIPLIER,
},
NewBullets: newBulletsToBroadcast,