Skip to content

Commit b7ac2c0

Browse files
authored
Merge pull request #749 from JiepengTan/pr_update_spx_api
Update spx api
2 parents 04fad46 + 41a532a commit b7ac2c0

2 files changed

Lines changed: 69 additions & 16 deletions

File tree

internal/engine/coro.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ func GetGame() any {
1919
return pgame
2020
}
2121

22+
func IsSpxEnv() bool {
23+
return GetGame() != nil
24+
}
25+
2226
func SetCoroutines(co *coroutine.Coroutines) {
2327
gco = co
2428
profiler.SetGco(co)

pkg/api/coro.go renamed to pkg/spx/api.go

Lines changed: 65 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,46 @@
1-
package api
1+
package spx
22

33
import (
4+
"sync/atomic"
5+
"time"
6+
47
"github.com/goplus/spx/v2/internal/engine"
58
)
69

710
// HasInit checks if the SPX engine has been initialized.
8-
func HasInit() bool {
9-
return engine.GetGame() != nil
11+
func IsSpxEnv() bool {
12+
return engine.IsSpxEnv()
13+
}
14+
15+
// Executes the given function in a native Go goroutine from the current SPX coroutine context and waits for completion.
16+
// While waiting, it yields control via waitNextFrame to avoid blocking the SPX main thread.
17+
// Use this when you need to run potentially blocking Go operations (e.g., network requests, file I/O) from within SPX.
18+
func RunGoFromSpx(fn func()) {
19+
done := &atomic.Bool{}
20+
// Run the actual logic in a go routine to avoid blocking
21+
go func() {
22+
defer done.Store(true)
23+
fn()
24+
}()
25+
// Wait for completion while yielding control to SPX
26+
for !done.Load() {
27+
WaitNextFrame()
28+
}
29+
}
30+
31+
// Executes the given function in an SPX coroutine from the current Go goroutine context and waits for completion.
32+
// This function blocks until fn finishes execution.
33+
// Use this when you need to synchronously wait for the SPX coroutine to complete.
34+
func RunSpxFromGo(fn func()) {
35+
done := make(chan struct{}, 1)
36+
StartSpxCoro(func() {
37+
defer close(done)
38+
fn()
39+
})
40+
<-done
1041
}
1142

12-
// Go starts a new spx coroutine that executes the given function concurrently.
43+
// Starts a new spx coroutine that executes the given function concurrently.
1344
// This is useful for running multiple operations in parallel without blocking
1445
// the main execution flow.
1546
//
@@ -25,24 +56,28 @@ func HasInit() bool {
2556
//
2657
// done := false
2758
// // ... do something
28-
// api.Go(func() {
59+
// spx.GoAsync(func() {
2960
// // ... do something
3061
// for !done {
3162
// // Do some work here
32-
// api.WaitNextFrame() // CRITICAL: Yield control to prevent freezing
63+
// spx.WaitNextFrame() // CRITICAL: Yield control to prevent freezing
3364
// }
3465
// })
3566
//
3667
// Example of simple delayed execution:
3768
//
38-
// api.Go(func() {
39-
// api.Wait(2.0)
69+
// spx.GoAsync(func() {
70+
// spx.Wait(2.0)
4071
// fmt.Println("Hello after 2 seconds")
4172
// })
42-
func Go(fn func()) {
43-
engine.Go(engine.GetGame(), func() {
44-
fn()
45-
})
73+
func StartSpxCoro(fn func()) {
74+
if IsSpxEnv() {
75+
engine.Go(engine.GetGame(), func() {
76+
fn()
77+
})
78+
} else {
79+
go fn()
80+
}
4681
}
4782

4883
// Wait pauses the current coroutine for the specified number of seconds.
@@ -62,9 +97,16 @@ func Go(fn func()) {
6297
//
6398
// Example:
6499
//
65-
// actualTime := api.Wait(1.5) // Wait for 1.5 seconds
100+
// actualTime := spx.Wait(1.5) // Wait for 1.5 seconds
66101
func Wait(secs float64) float64 {
67-
return engine.Wait(secs)
102+
if IsSpxEnv() {
103+
return engine.Wait(secs)
104+
} else {
105+
// Fallback to a regular wait
106+
startTime := time.Now()
107+
time.Sleep(time.Duration(secs * float64(time.Second)))
108+
return time.Since(startTime).Seconds()
109+
}
68110
}
69111

70112
// WaitNextFrame pauses the current coroutine until the next frame is rendered.
@@ -83,9 +125,16 @@ func Wait(secs float64) float64 {
83125
// for i := 0; i < 1000; i++ {
84126
// // Do some expensive work
85127
// if i%100 == 0 {
86-
// api.WaitNextFrame() // Yield control every 100 iterations
128+
// spx.WaitNextFrame() // Yield control every 100 iterations
87129
// }
88130
// }
89131
func WaitNextFrame() float64 {
90-
return engine.WaitNextFrame()
132+
if IsSpxEnv() {
133+
return engine.WaitNextFrame()
134+
} else {
135+
// Fallback to a regular wait
136+
startTime := time.Now()
137+
time.Sleep(time.Millisecond * 16) // Approx 60 FPS
138+
return time.Since(startTime).Seconds()
139+
}
91140
}

0 commit comments

Comments
 (0)