alchemyst/cmd/game/main.go
2019-10-31 15:08:09 +03:00

162 lines
3.8 KiB
Go

package main
import (
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap"
"lab.zaar.be/thefish/alchemyst-go/engine/gamemap/mapgens"
"lab.zaar.be/thefish/alchemyst-go/ui"
"lab.zaar.be/thefish/alchemyst-go/ui/mainwindow"
"lab.zaar.be/thefish/alchemyst-go/util"
blt "lab.zaar.be/thefish/bearlibterminal"
"os"
"runtime"
"time"
)
var modifiers = []int{blt.TK_SHIFT, blt.TK_ALT, blt.TK_CONTROL}
// Рецепт чтобы убежать от [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
rawInput chan int
}
// do runs f on the main thread.
func (*GameState) Do(f func()) {
done := make(chan struct{}, 1)
State.mainfunc <- func() {
f()
done <- struct{}{}
}
<-done
}
//we can run logic in separate goroutines
//
// go doSometing(State,...)
//
//and there we go like this:
// func doSomething(State main.GameState, args...) {
// ...
// State.Do(func() {
// ...do stuff in main thread
// })
// ...
// }
var State = GameState{
mainfunc: make(chan func()),
exit: make(chan struct{}, 1),
input: make(chan string, 1),
rawInput: make(chan int, 1),
}
func main() {
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])
mainCtx := util.NewClientContext(config, &logger)
mw := mainwindow.Init(mainCtx)
defer mw.Close()
setupLayers(mw)
level := gamemap.NewLevel(mainCtx, "test", 1)
level = mapgens.DefaultGen(level)
vp := mainwindow.NewViewPort(40, 0, 60, 47, level, mw.GetLayer("base"))
vp.Render()
go decodeInput(mainCtx, mw.GetLayer("base"))
//but every call to bearlibterminal must be wrapped to closure and passed to mainfunc
var exit = false
for !exit {
select {
case State.rawInput <- ui.ReadKeyCode():
break
case pressed := <-State.input:
mw.GetLayer("base").ClearArea(0, 3, 40, 1)
mw.GetLayer("base").Print(1, 3, "Key: "+pressed)
mw.GetLayer("base").Print(1, 6, "█")
break
//case f := <-State.mainfunc:
// f()
// break
case <-State.exit:
mainCtx.Logger().Warn().Msg("quitting NOW")
exit = true
break
// не оставляйте default в бесконесчном select {} - сожрет всё CPU
default:
vp.Render()
blt.Refresh()
}
}
mainCtx.Logger().Info().Msg("pre-shutdown sequence")
}
func setupLayers(mainwindow *mainwindow.MainWindow) {
mainwindow.AddLayer("base", 0, "white")
mainwindow.AddLayer("overlay", 1, "white")
mainwindow.AddLayer("menu", 2, "white")
}
func decodeInput(ctx util.ClientCtx, baseLayer *mainwindow.Layer) {
var exit = false
for !exit{
select {
case keycode := <-State.rawInput:
if keycode == blt.TK_NONE {
continue
}
var pressed= ""
var isModifier, _= util.InArray(keycode, modifiers)
if !isModifier {
pressed = ui.Scancodemap[keycode]
if blt.Check(blt.TK_SHIFT) != 0 {
pressed = "Shift+" + pressed
}
if blt.Check(blt.TK_ALT) != 0 {
pressed = "Alt+" + pressed
}
if blt.Check(blt.TK_CONTROL) != 0 {
pressed = "Ctrl+" + pressed
}
//global hotkeys
switch pressed {
case "F10":
State.Do(func() {
blt.Set("window: size=100x47; font: ./resources/fonts-ttf/UbuntuMono-R.ttf, size=11;")
})
case "Ctrl+q":
fallthrough
case "Escape":
ctx.Logger().Info().Msg("exiting on quit command...")
State.exit <- struct{}{}
ctx.Logger().Info().Msg("...done")
exit = true
return
default:
State.input <- pressed
}
}
}
}
}