non-main thread call fixed

This commit is contained in:
thefish 2019-10-25 02:26:17 +03:00
parent 8126e68141
commit 4ce0fa74c1
3 changed files with 111 additions and 54 deletions

View File

@ -4,5 +4,6 @@
"sizeX": 100, "sizeX": 100,
"sizeY": 47, "sizeY": 47,
"fpsLimit" : 60, "fpsLimit" : 60,
"font": "./resources/fonts-ttf/LiberationMono-Bold.ttf" "font": "./resources/fonts-ttf/LiberationMono-Bold.ttf",
"verbosity": "debug"
} }

103
main.go
View File

@ -1,7 +1,6 @@
package main package main
import ( import (
"github.com/jcerise/gogue/screens"
"github.com/rs/zerolog" "github.com/rs/zerolog"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"lab.zaar.be/thefish/alchemyst-go/ui" "lab.zaar.be/thefish/alchemyst-go/ui"
@ -9,33 +8,78 @@ import (
"lab.zaar.be/thefish/alchemyst-go/util" "lab.zaar.be/thefish/alchemyst-go/util"
blt "lab.zaar.be/thefish/bearlibterminal" blt "lab.zaar.be/thefish/bearlibterminal"
"os" "os"
"runtime"
"time" "time"
) )
// Рецепт чтобы убежать от [fatal] 'refresh' was not called from the main thread
// https://github.com/golang/go/wiki/LockOSThread
func init() {
runtime.LockOSThread()
}
type GameState struct {
mainfunc chan func()
exit chan struct{}
input chan string
}
var State = GameState{
mainfunc: make(chan func()),
exit: make(chan struct{}, 1),
input: make(chan string, 1),
}
func main() { func main() {
config := util.LoadConfig() config := util.LoadConfig()
var logLevels = map[string]zerolog.Level{"debug": zerolog.DebugLevel, "info": zerolog.InfoLevel, "warn": zerolog.WarnLevel}
var logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}).Level(logLevels[config.Verbosity])
//var logLevels = map[string]zerolog.Level{"debug": zerolog.DebugLevel, "info": zerolog.InfoLevel, "warn": zerolog.WarnLevel}
//var logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}).Level(logLevels[opts.Verbosity])
var logger = log.Output(zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339})
mainCtx := util.NewClientContext(config, &logger) mainCtx := util.NewClientContext(config, &logger)
mw := mainwindow.Init(mainCtx) mw := mainwindow.Init(mainCtx)
defer mw.Close() defer mw.Close()
//we can run logic in separate goroutines
go mainLoop(mainCtx)
mainLoop(mainCtx) //but every call to bearlibterminal must be wrapped to closure and passed to mainfunc
var exit = false
for !exit {
select {
case f := <-State.mainfunc:
f()
case <-State.exit:
mainCtx.Logger().Warn().Msg("quitting NOW")
exit = true
break
}
}
mainCtx.Logger().Info().Msg("pre-shutdown sequence")
}
// do runs f on the main thread.
func (*GameState) Do(f func()) {
done := make(chan struct{}, 1)
State.mainfunc <- func() {
f()
done <- struct{}{}
}
<-done
} }
func mainLoop(ctx util.ClientCtx) { func mainLoop(ctx util.ClientCtx) {
var exit = false
baseLayer := mainwindow.AddLayer(0, "white") baseLayer := mainwindow.AddLayer(0, "white")
bgLayer := mainwindow.AddLayer(1, "white") bgLayer := mainwindow.AddLayer(1, "white")
menuLayer := mainwindow.AddLayer(2, "white") menuLayer := mainwindow.AddLayer(2, "white")
initRender := func() {
baseLayer.WithColor("white").NewRect(3, 0, 17, 6).Fill() baseLayer.WithColor("white").NewRect(3, 0, 17, 6).Fill()
baseLayer.WithColor("grey").NewRect(22, 0, 38, 6).Splash() baseLayer.WithColor("grey").NewRect(22, 0, 38, 6).Splash()
baseLayer.WithColor("blue").NewRect(3, 8, 57, 6).Fill() baseLayer.WithColor("blue").NewRect(3, 8, 57, 6).Fill()
@ -61,20 +105,21 @@ Cursus in hac habitasse platea. Aliquet risus feugiat in ante metus dictum. Maec
Sed euismod nisi porta lorem mollis aliquam ut porttitor leo. Ut tellus elementum sagittis vitae et leo duis ut diam. Elementum curabitur vitae nunc sed velit dignissim. Auctor elit sed vulputate mi sit. Consectetur adipiscing elit ut aliquam purus. Feugiat vivamus at augue eget arcu. Duis ut diam quam nulla porttitor massa id neque. Pharetra magna ac placerat vestibulum lectus mauris ultrices. Non sodales neque sodales ut etiam. Massa ultricies mi quis hendrerit dolor. Est sit amet facilisis magna etiam. Ornare suspendisse sed nisi lacus sed viverra tellus in. Sed euismod nisi porta lorem mollis aliquam ut porttitor leo. Ut tellus elementum sagittis vitae et leo duis ut diam. Elementum curabitur vitae nunc sed velit dignissim. Auctor elit sed vulputate mi sit. Consectetur adipiscing elit ut aliquam purus. Feugiat vivamus at augue eget arcu. Duis ut diam quam nulla porttitor massa id neque. Pharetra magna ac placerat vestibulum lectus mauris ultrices. Non sodales neque sodales ut etiam. Massa ultricies mi quis hendrerit dolor. Est sit amet facilisis magna etiam. Ornare suspendisse sed nisi lacus sed viverra tellus in.
`) `)
baseLayer.Print(1, 1, "Hello, [font=bold]world[/font]!") baseLayer.Print(1, 1, "Hello, [font=bold]world[/font]!")
baseLayer.Print(1, 4, "Testing line-[color=orange]spacing[/color]") baseLayer.Print(1, 4, "Testing line-[color=orange]spacing[/color]")
blt.Refresh() blt.Refresh()
}
mgr := screens.NewScreenManager() State.Do(initRender)
for {
_ = mgr //fresh inputs to chan
State.Do(func() {
for !exit {
var key, keycode = ui.ReadKey(ctx) var key, keycode = ui.ReadKey(ctx)
if key != "" { if keycode == blt.TK_CLOSE {
blt.ClearArea(0, 3, 80, 1) ctx.Logger().Warn().Msg("exiting on window close...")
State.exit <- struct{}{}
ctx.Logger().Warn().Msg("...done")
return
} }
switch key { switch key {
case "F10": case "F10":
@ -84,19 +129,29 @@ Sed euismod nisi porta lorem mollis aliquam ut porttitor leo. Ut tellus elementu
case "Ctrl+q": case "Ctrl+q":
fallthrough fallthrough
case "Escape": case "Escape":
exit = true ctx.Logger().Info().Msg("exiting on quit command...")
State.exit <- struct{}{}
ctx.Logger().Info().Msg("...done")
return
default: default:
//blt.Print(1, 3, "Key: "+key) //blt.Print(1, 3, "Key: "+key)
menuLayer.Print(1, 3, "Key: "+key) State.input <- key
baseLayer.Print(1,5, key)
//baseLayer.Print(1, 4, "█") //baseLayer.Print(1, 4, "█")
} }
})
if keycode == blt.TK_CLOSE { //read inputs, write to screen
exit = true State.Do(func() {
key := <-State.input
if key != "" {
blt.ClearArea(0, 3, 80, 1)
menuLayer.Print(1, 3, "Key: "+key)
baseLayer.Print(1, 5, key)
} }
})
//update screen
State.Do(func(){
blt.Refresh() blt.Refresh()
})
} }
ctx.Logger().Warn().Msg("and it continues")
} }

View File

@ -14,6 +14,7 @@ type Config struct {
MainWindowSizeX int `json:"sizeX"` MainWindowSizeX int `json:"sizeX"`
MainWindowSizeY int `json:"sizeY"` MainWindowSizeY int `json:"sizeY"`
Font string `json:"font"` Font string `json:"font"`
Verbosity string `json:"verbosity"`
} }
func LoadConfig() *Config { func LoadConfig() *Config {