feat(frontend): get login token from server

As of right now, we don't actually do anything with the token. But at
least we're actually able to get it. 😅

Caveats in implementation:
- UI now needs a pointer to player
- .env is now required for server auth (mentioned in README.md)
This commit is contained in:
Abdulmujeeb Raji 2023-08-04 14:55:53 +01:00
parent 4c536581e1
commit a1f6d8fe7f
9 changed files with 100 additions and 39 deletions

1
frontend/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
.env

6
frontend/README.md Normal file
View file

@ -0,0 +1,6 @@
# Frontend Usage
You must create a `.env` file in the same folder as your game executable, with
`BACKEND_URL` being a valid URL to a server running the [game server](../backend).
Note that this isn't necessary if you're playing in a browser or using a download
from itch.io

View file

@ -6,6 +6,7 @@ require (
github.com/devraza/ambition/frontend/player v0.0.0-00010101000000-000000000000 github.com/devraza/ambition/frontend/player v0.0.0-00010101000000-000000000000
github.com/devraza/ambition/frontend/ui v0.0.0-00010101000000-000000000000 github.com/devraza/ambition/frontend/ui v0.0.0-00010101000000-000000000000
github.com/hajimehoshi/ebiten/v2 v2.5.5 github.com/hajimehoshi/ebiten/v2 v2.5.5
github.com/joho/godotenv v1.5.1
) )
require ( require (

View file

@ -13,6 +13,8 @@ github.com/hajimehoshi/ebiten/v2 v2.5.5 h1:TJNoZsYJYUyFucwE56QRSgmZ+/cklUt1YrwpQ
github.com/hajimehoshi/ebiten/v2 v2.5.5/go.mod h1:mnHSOVysTr/nUZrN1lBTRqhK4NG+T9NR3JsJP2rCppk= github.com/hajimehoshi/ebiten/v2 v2.5.5/go.mod h1:mnHSOVysTr/nUZrN1lBTRqhK4NG+T9NR3JsJP2rCppk=
github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk= github.com/jezek/xgb v1.1.0 h1:wnpxJzP1+rkbGclEkmwpVFQWpuE2PUGNUzP8SbfFobk=
github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk= github.com/jezek/xgb v1.1.0/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ= github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=

View file

@ -11,12 +11,9 @@ import (
// Ebitengine // Ebitengine
"github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2"
// "github.com/hajimehoshi/ebiten/v2/ebitenutil" "github.com/hajimehoshi/ebiten/v2/ebitenutil"
) )
// Initialise the test player
var testPlayer = p.GetPlayer()
// Create the `Game` struct // Create the `Game` struct
type Game struct { type Game struct {
ui u.UI ui u.UI
@ -40,6 +37,7 @@ func (g *Game) Update() error {
func (g *Game) Draw(screen *ebiten.Image) { func (g *Game) Draw(screen *ebiten.Image) {
// Draw the UI onto the screen // Draw the UI onto the screen
g.ui.Base.Draw(screen) g.ui.Base.Draw(screen)
ebitenutil.DebugPrint(screen, g.activePlayer.JwtToken)
} }
// Layout implements Game // Layout implements Game
@ -64,11 +62,9 @@ func main() {
ebiten.SetWindowTitle(window_title) ebiten.SetWindowTitle(window_title)
// Initialise the game // Initialise the game
game := Game{ game := Game{}
// Initialise the UI game.activePlayer = p.NewPlayer()
activePlayer: testPlayer, game.ui = u.UiInit(window_width, window_height, &game.activePlayer)
ui: u.UiInit(window_width, window_height),
}
// Log and exit on error // Log and exit on error
if err := ebiten.RunGame(&game); err != nil { if err := ebiten.RunGame(&game); err != nil {

View file

@ -1,9 +1,13 @@
package player package player
import () import (
s "github.com/devraza/ambition/frontend/server"
"log"
)
// The player struct // The player struct
type Player struct { type Player struct {
JwtToken string
Health int Health int
MaxHealth int MaxHealth int
Defence int Defence int
@ -18,20 +22,40 @@ type Player struct {
var level_gates = make(map[int]float32) var level_gates = make(map[int]float32)
var level_ambition = make(map[int]float32) var level_ambition = make(map[int]float32)
// TODO(midnadimple): Move player initialization to server upon login func NewPlayer() Player {
func GetPlayer() Player {
return Player{ return Player{
Health: 100, JwtToken: "",
MaxHealth: 100, Health: 0,
Defence: 0, MaxHealth: 0,
Level: 1, Defence: 0,
Exp: 0.0, Level: 0,
NextExp: 0.0, Exp: 0.0,
Ambition: 0.0, // NOTE(midnadimple): In the future this will be affected by player activity NextExp: 0.0,
MaxAmbition: level_ambition[1], // NOTE(midnadimple): In the future this will be affected by player activity Ambition: 0.0,
MaxAmbition: 0.0,
} }
} }
func (p *Player) Init(name, password string) {
// JWT Get Token
jwt_token, err := s.GetUserJwtToken(name, password)
if err != nil {
log.Fatalln(err)
}
p.JwtToken = jwt_token
// TODO(midnadimple): Get player data from server.
p.Health = 100
p.MaxHealth = 100
p.Defence = 0
p.Level = 1
p.Exp = 0.0
p.NextExp = 0.0
p.Ambition = 0.0 // NOTE(midnadimple): In the future this will be affected by player activity
p.MaxAmbition = level_ambition[1] // NOTE(midnadimple): In the future this will be affected by player activity
}
// Formula for XP gain - extremely simple // Formula for XP gain - extremely simple
func gain(basexp float32, modifier float32) float32 { func gain(basexp float32, modifier float32) float32 {
gain := basexp * modifier gain := basexp * modifier

View file

@ -0,0 +1,40 @@
package server
import (
"os"
"errors"
"bytes"
"io/ioutil"
"encoding/json"
"net/http"
// Needed for server url
_ "github.com/joho/godotenv/autoload"
)
var server_address = os.Getenv("BACKEND_URL")
func GetUserJwtToken(name, password string) (string, error) {
if server_address == "" {
return "", errors.New("no server url provided")
}
post_body, _ := json.Marshal(map[string]string{
"name": name,
"password": password,
})
resp_body := bytes.NewBuffer(post_body)
resp, err := http.Post(server_address + "/user", "application/json", resp_body)
if err != nil {
return "", err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}

View file

@ -1,21 +1,18 @@
package ui package ui
import ( import (
// Misc.
"fmt"
// Image // Image
img "image" img "image"
// Ambition // Ambition
// p "github.com/devraza/ambition/frontend/player" p "github.com/devraza/ambition/frontend/player"
// EbitenUI // EbitenUI
"github.com/ebitenui/ebitenui/image" "github.com/ebitenui/ebitenui/image"
"github.com/ebitenui/ebitenui/widget" "github.com/ebitenui/ebitenui/widget"
) )
func makeLoginWindow(width, height int, root *widget.Container, shown *widget.Container) { func makeLoginWindow(width, height int, root *widget.Container, shown *widget.Container, player *p.Player) {
// Define the contents of the login window // Define the contents of the login window
loginContainer := widget.NewContainer( loginContainer := widget.NewContainer(
widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])), widget.ContainerOpts.BackgroundImage(image.NewNineSliceColor(ui.colors["gray"])),
@ -62,9 +59,6 @@ func makeLoginWindow(width, height int, root *widget.Container, shown *widget.Co
widget.CaretOpts.Size(defaultFace, 2), widget.CaretOpts.Size(defaultFace, 2),
), ),
widget.TextInputOpts.Placeholder("Username"), widget.TextInputOpts.Placeholder("Username"),
widget.TextInputOpts.SubmitHandler(func(args *widget.TextInputChangedEventArgs) {
fmt.Println("Text Submitted: ", args.InputText)
}),
) )
passwordInput := widget.NewTextInput( passwordInput := widget.NewTextInput(
widget.TextInputOpts.WidgetOpts( widget.TextInputOpts.WidgetOpts(
@ -91,9 +85,6 @@ func makeLoginWindow(width, height int, root *widget.Container, shown *widget.Co
widget.TextInputOpts.Secure(true), widget.TextInputOpts.Secure(true),
widget.TextInputOpts.Placeholder("Password"), widget.TextInputOpts.Placeholder("Password"),
widget.TextInputOpts.SubmitHandler(func(args *widget.TextInputChangedEventArgs) {
fmt.Println("Text Submitted: ", args.InputText)
}),
) )
// Add the text inputs to the login window // Add the text inputs to the login window
loginContainer.AddChild(usernameInput) loginContainer.AddChild(usernameInput)
@ -130,6 +121,7 @@ func makeLoginWindow(width, height int, root *widget.Container, shown *widget.Co
}), }),
// Button on-click handler // Button on-click handler
widget.ButtonOpts.ClickedHandler(func(args *widget.ButtonClickedEventArgs) { widget.ButtonOpts.ClickedHandler(func(args *widget.ButtonClickedEventArgs) {
player.Init(usernameInput.InputText, passwordInput.InputText)
removeContainer(root, loginContainer) removeContainer(root, loginContainer)
addContainer(root, shown) addContainer(root, shown)
}), }),

View file

@ -22,14 +22,12 @@ import (
// The UI struct // The UI struct
type UI struct { type UI struct {
Base ebitenui.UI Base ebitenui.UI
player *p.Player
colors map[string]color.RGBA colors map[string]color.RGBA
width, height int width, height int
textInput *widget.TextInput textInput *widget.TextInput
} }
// Get the player from the `player` package
var player = p.GetPlayer()
// The `hazakura` colorscheme (default) // The `hazakura` colorscheme (default)
var hazakura = map[string]color.RGBA{ var hazakura = map[string]color.RGBA{
// The monotone colors // The monotone colors
@ -62,9 +60,10 @@ var defaultFace, _ = makeFace(14, fonts.FiraRegular_ttf)
var buttonImage, _ = loadButtonImage() var buttonImage, _ = loadButtonImage()
// Function for UI initialization // Function for UI initialization
func UiInit(width, height int) UI { func UiInit(width, height int, player *p.Player) UI {
// Define the UI colors // Define the UI colors
ui.colors = hazakura ui.colors = hazakura
ui.player = player
// Get the window width/height // Get the window width/height
ui.width = width ui.width = width
@ -170,7 +169,7 @@ func UiInit(width, height int) UI {
addContainer(leftBar, chatContainer) addContainer(leftBar, chatContainer)
// Create the login window // Create the login window
makeLoginWindow(ui.width, ui.height, root, leftBar) makeLoginWindow(ui.width, ui.height, root, leftBar, player)
// Set the position and size of the left bar // Set the position and size of the left bar
leftBar.SetLocation(img.Rect(0, 0, int(float32(width)/3.5), height)) leftBar.SetLocation(img.Rect(0, 0, int(float32(width)/3.5), height))
@ -246,7 +245,7 @@ func makeStatsBars(parent *widget.TabBookTab, ui UI, face font.Face) {
}, },
), ),
// Set the min, max, and current values for each progressbar // Set the min, max, and current values for each progressbar
widget.ProgressBarOpts.Values(0, player.Health, player.MaxHealth), widget.ProgressBarOpts.Values(0, ui.player.Health, ui.player.MaxHealth),
) )
parent.AddChild(health) parent.AddChild(health)
parent.AddChild(health_progressbar) parent.AddChild(health_progressbar)
@ -281,7 +280,7 @@ func makeStatsBars(parent *widget.TabBookTab, ui UI, face font.Face) {
}, },
), ),
// Set the min, max, and current values for each progressbar // Set the min, max, and current values for each progressbar
widget.ProgressBarOpts.Values(0, int(player.Exp), int(player.NextExp)), widget.ProgressBarOpts.Values(0, int(ui.player.Exp), int(ui.player.NextExp)),
) )
parent.AddChild(level) parent.AddChild(level)
parent.AddChild(level_progressbar) parent.AddChild(level_progressbar)
@ -316,7 +315,7 @@ func makeStatsBars(parent *widget.TabBookTab, ui UI, face font.Face) {
}, },
), ),
// Set the min, max, and current values for each progressbar // Set the min, max, and current values for each progressbar
widget.ProgressBarOpts.Values(0, int(player.Ambition), int(player.MaxAmbition)), widget.ProgressBarOpts.Values(0, int(ui.player.Ambition), int(ui.player.MaxAmbition)),
) )
parent.AddChild(ambition) parent.AddChild(ambition)
parent.AddChild(ambition_progressbar) parent.AddChild(ambition_progressbar)