server

package
v0.0.0-...-6723bfa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: GPL-3.0 Imports: 54 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// DevLoginParam is the query parameter the middleware inspects when the
	// gate is on. Visiting any URL with this param sets the session subject
	// to the param's value, with no password or OAuth round-trip.
	DevLoginParam = "dev_user"

	// DevLoginEnvVar is the env var that gates the middleware. Anything
	// other than "true" disables fake login entirely — the middleware
	// short-circuits on the env check and passes the request through
	// unchanged. Default state is OFF; production deploys must keep it
	// that way.
	DevLoginEnvVar = "ENABLE_DEV_FAKE_LOGIN"
)
View Source
const DIST_FOLDER = "./web/dist"

You may have a builder/bundler creating an output folder. Set that path here. It can be absolute or relative to where the executable will be running from

View Source
const STATIC_FOLDER = "./web/static"
View Source
const ServeGzippedResources = true
View Source
const TEMPLATES_FOLDER = "./web/templates"

Variables

View Source
var AllowedUnitIDs = []int32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 37, 38, 39, 40, 41, 44}

Functions

func DevLoginEnabled

func DevLoginEnabled() bool

DevLoginEnabled reports whether the gate env var is currently set to "true". Read at request time, not at startup, so changing the env in dev (e.g. via `make devloop ENABLE_DEV_FAKE_LOGIN=true`) takes effect on the next request without restarting tests.

func GenerateRandomNickname

func GenerateRandomNickname() string

GenerateRandomNickname creates a fun random nickname like "HappyPanda" or "SwiftFalcon"

func GenerateRandomNicknameWithSpace

func GenerateRandomNicknameWithSpace() string

GenerateRandomNicknameWithSpace creates a nickname with space like "Happy Panda"

func GrpcAuthContext

func GrpcAuthContext(userID string) context.Context

GrpcAuthContext creates a gRPC context with user authentication metadata. Use this when calling gRPC services from page handlers to pass the user ID.

func HandleGRPCError

func HandleGRPCError(err error, w http.ResponseWriter, r *http.Request, app *goal.App[*LilBattleApp]) (error, bool)

HandleGRPCError checks if err is a gRPC error and handles it appropriately. For Unauthenticated errors, it redirects to /login with a callback URL. For NotFound errors, it renders the 404 page. For PermissionDenied errors, it renders the 403 page. Returns (error, finished) - if finished is true, the response has been written.

func IsValidNickname

func IsValidNickname(nickname string) bool

IsValidNickname checks if a nickname is valid (not empty, reasonable length)

func ThemeFromRequest

func ThemeFromRequest(req *http.Request) string

func WrapDevLogin

func WrapDevLogin(oneauth *httpauth.OneAuth) func(http.Handler) http.Handler

WrapDevLogin returns a middleware that intercepts ?dev_user=<handle> on any path and calls oneauth.SetLoggedInSubject with that handle. The handle becomes the session subject, the loggedInSubject cookie value, and the JWT cookie's `sub` claim — identical to what a real login would produce, just without the password / OAuth round-trip.

Callers decide whether to install this middleware based on DevLoginEnabled() at handler-build time, so production handlers never even hold a reference to it. Wire it via:

withDevLogin := routes
if server.DevLoginEnabled() { withDevLogin = WrapDevLogin(oneauth)(routes) }
Session.LoadAndSave(withDevLogin)

The middleware MUST run inside Session.LoadAndSave so the session writes performed by SetLoggedInSubject reach the SCS store.

Every fake-login event emits an slog.Warn line so a production deploy that somehow installed this middleware cannot go unnoticed during log review.

Types

type ApiHandler

type ApiHandler struct {
	AuthMiddleware *httpauth.Middleware
	ClientMgr      *services.ClientMgr

	// Here we can have to ways of accessing the services - either via clients or by actual service instead if you are not
	// running the services on a dedicated port
	DisableIndexer       bool
	DisableGamesService  bool
	DisableWorldsService bool
	// contains filtered or unexported fields
}

func (*ApiHandler) Handler

func (n *ApiHandler) Handler() http.Handler

func (*ApiHandler) Init

func (a *ApiHandler) Init() error

type AttackSimulatorPage

type AttackSimulatorPage struct {
	BasePage
	Header Header

	// URL parameters for pre-populating form
	AttackerUnit    string
	AttackerTerrain string
	AttackerHealth  string
	DefenderUnit    string
	DefenderTerrain string
	DefenderHealth  string
	WoundBonus      string
	NumSimulations  string

	// Terrain and unit data for dropdowns
	AllTerrains []TerrainType
	AllUnits    []UnitType
	Theme       string
}

func (*AttackSimulatorPage) Load

func (p *AttackSimulatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type BasePage

type BasePage struct {
	goal.BasePage
}

func (*BasePage) SetCanonicalFromRequest

func (p *BasePage) SetCanonicalFromRequest(app *goal.App[*LilBattleApp], r *http.Request)

SetCanonicalFromRequest sets the canonical URL from the app's BaseUrl and request path. Call this in page Load() methods to enable SEO canonical tags.

type ConnectGameSyncServiceAdapter

type ConnectGameSyncServiceAdapter struct {
	// contains filtered or unexported fields
}

ConnectGameSyncServiceAdapter adapts the gRPC GameSyncService to Connect's interface This enables multiplayer sync via HTTP/Connect for frontend clients

func NewConnectGameSyncServiceAdapter

func NewConnectGameSyncServiceAdapter(client v1s.GameSyncServiceClient) *ConnectGameSyncServiceAdapter

func (*ConnectGameSyncServiceAdapter) Broadcast

func (*ConnectGameSyncServiceAdapter) Subscribe

type ConnectGamesServiceAdapter

type ConnectGamesServiceAdapter struct {
	// contains filtered or unexported fields
}

ConnectGamesServiceAdapter adapts the gRPC GamesService to Connect's interface

func NewConnectGamesServiceAdapter

func NewConnectGamesServiceAdapter(client v1s.GamesServiceClient) *ConnectGamesServiceAdapter

func (*ConnectGamesServiceAdapter) CreateGame

func (*ConnectGamesServiceAdapter) DeleteGame

func (*ConnectGamesServiceAdapter) GetGame

func (*ConnectGamesServiceAdapter) GetGameState

func (*ConnectGamesServiceAdapter) GetGames

func (*ConnectGamesServiceAdapter) GetOptionsAt

func (*ConnectGamesServiceAdapter) JoinGame

func (*ConnectGamesServiceAdapter) ListGames

func (*ConnectGamesServiceAdapter) ListMoves

func (*ConnectGamesServiceAdapter) ProcessMoves

func (*ConnectGamesServiceAdapter) SimulateAttack

func (*ConnectGamesServiceAdapter) SimulateFix

func (*ConnectGamesServiceAdapter) UpdateGame

type ConnectIndexerServiceAdapter

type ConnectIndexerServiceAdapter struct {
	// contains filtered or unexported fields
}

ConnectIndexerServiceAdapter adapts the gRPC IndexerService to Connect's interface

func NewConnectIndexerServiceAdapter

func NewConnectIndexerServiceAdapter(client v1s.IndexerServiceClient) *ConnectIndexerServiceAdapter

type ConnectWorldsServiceAdapter

type ConnectWorldsServiceAdapter struct {
	// contains filtered or unexported fields
}

ConnectWorldsServiceAdapter adapts the gRPC WorldsService to Connect's interface

func NewConnectWorldsServiceAdapter

func NewConnectWorldsServiceAdapter(client v1s.WorldsServiceClient) *ConnectWorldsServiceAdapter

func (*ConnectWorldsServiceAdapter) CreateWorld

func (*ConnectWorldsServiceAdapter) DeleteWorld

func (*ConnectWorldsServiceAdapter) GetWorld

func (*ConnectWorldsServiceAdapter) GetWorlds

func (*ConnectWorldsServiceAdapter) ListWorlds

func (*ConnectWorldsServiceAdapter) UpdateWorld

type CrossingType

type CrossingType struct {
	ID          string `json:"id"`   // "road" or "bridge"
	Name        string `json:"name"` // Display name
	IconDataURL string `json:"iconDataURL"`
}

CrossingType represents a road or bridge crossing

type FixSimulatorPage

type FixSimulatorPage struct {
	BasePage
	Header Header

	// URL parameters for pre-populating form
	FixingUnit       string
	FixingUnitHealth string
	InjuredUnit      string
	NumSimulations   string

	// Units data for dropdowns
	// FixingUnits only includes units with fix_value > 0
	FixingUnits []UnitType
	// AllUnits includes all units (for injured unit dropdown)
	AllUnits []UnitType
	Theme    string
}

func (*FixSimulatorPage) Load

func (p *FixSimulatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type ForbiddenPage

type ForbiddenPage struct {
	BasePage
	Header  Header
	Message string
}

ForbiddenPage is the view data for 403 pages

func (*ForbiddenPage) Load

type ForgotPasswordPage

type ForgotPasswordPage struct {
	BasePage
	CustomHeader bool
	Sent         bool
}

ForgotPasswordPage renders the forgot password form.

func (*ForgotPasswordPage) Load

func (p *ForgotPasswordPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type GameCreatorPage

type GameCreatorPage struct {
	BasePage
	Header        Header
	Game          *protos.Game
	Errors        map[string]string
	AllowCustomId bool
}

func (*GameCreatorPage) Load

func (v *GameCreatorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

func (*GameCreatorPage) SetupDefaults

func (v *GameCreatorPage) SetupDefaults()

type GameDetailPage

type GameDetailPage struct {
	BasePage
	Header Header
	Game   *protos.Game
	GameId string
}

func (*GameDetailPage) Load

func (p *GameDetailPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type GameListView

type GameListView struct {
	goal.WithPagination
	goal.WithFiltering

	Games []*protos.Game
}

func (*GameListView) Load

func (p *GameListView) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type GameListingPage

type GameListingPage struct {
	BasePage
	Header Header

	GameListView GameListView
	ListingData  *goal.EntityListingData[*protos.Game]
}

func (*GameListingPage) Load

func (m *GameListingPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type GameViewerPage

type GameViewerPage struct {
	BasePage
	Header      Header
	GameId      string
	WorldId     string
	Game        *protos.Game
	GameState   *protos.GameState
	GameHistory *protos.GameMoveHistory

	// Game creation parameters from URL
	PlayerCount      int
	MaxTurns         int
	UnitRestrictions map[string]string // unitId -> restriction level

	WasmExecJsPath string
	WasmBundlePath string

	// Viewer context for Join functionality
	ViewerUserId string
}

func (*GameViewerPage) GetTerrainDataJSON

func (p *GameViewerPage) GetTerrainDataJSON() string

GetTerrainDataJSON returns terrain data from rules engine as JSON string

func (*GameViewerPage) GetTerrainUnitPropertiesJSON

func (p *GameViewerPage) GetTerrainUnitPropertiesJSON() string

GetTerrainUnitPropertiesJSON returns terrain-unit interaction properties as JSON string

func (*GameViewerPage) GetUnitDataJSON

func (p *GameViewerPage) GetUnitDataJSON() string

GetUnitDataJSON returns unit data from rules engine as JSON string

func (*GameViewerPage) GetUnitUnitPropertiesJSON

func (p *GameViewerPage) GetUnitUnitPropertiesJSON() string

GetUnitUnitPropertiesJSON returns unit-vs-unit combat properties as JSON string

func (*GameViewerPage) Load

func (p *GameViewerPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type GamesGroup

type GamesGroup struct {
	// contains filtered or unexported fields
}

GamesGroup implements goal.PageGroup for /games routes.

func (*GamesGroup) RegisterRoutes

func (g *GamesGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux

RegisterRoutes registers all game-related routes using goal.Register.

type GenericPage

type GenericPage struct {
	BasePage
	Header Header
}

func (*GenericPage) Load

func (v *GenericPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)
type Header struct {
	AppName             string
	PageData            any
	LogoTitle           string
	Styles              map[string]any
	Width               string
	HeaderStyleLink     string
	MenuStyleLink       string
	FixedHeader         bool
	ShowHomeButton      bool
	ShowComposeButton   bool
	ShowLoginButton     bool
	ShowLogoutButton    bool
	HomeButtonImage     string
	CenterMenuItems     []HeaderMenuItem
	SpecialMenuItems    []HeaderMenuItem
	RightMenuItems      []HeaderMenuItem
	HideCenterMenuItems bool
	IsLoggedIn          bool
	LoggedInUserId      string
	Username            string
	DisplayName         string // Shown in header: Nickname -> Name -> UserID
}

func (*Header) Load

func (v *Header) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

func (*Header) SetupDefaults

func (h *Header) SetupDefaults()

type HeaderMenuItem

type HeaderMenuItem struct {
	Id            string
	Title         string
	Link          string
	Class         string
	LowWidthClass string
	Raw           string
	OnClick       string
	Attributes    map[string]string
}

type HomePage

type HomePage struct {
	BasePage
	Header Header

	// Dashboard data
	RecentGames  []*v1.Game
	RecentWorlds []*v1.World
	TotalGames   int32
	TotalWorlds  int32
}

func (*HomePage) Load

func (p *HomePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type IndexerAppServer

type IndexerAppServer struct {
	goal.WebAppServer
}

type LilBattleApp

type LilBattleApp struct {
	// Auth
	Auth           *httpauth.OneAuth
	AuthMiddleware *httpauth.Middleware
	AuthService    *goalservices.AuthService
	UsernameStore  accounts.UsernameStore // Username → UserID mapping for login alias
	Session        *scs.SessionManager

	// Services
	Api       *ApiHandler
	ClientMgr *services.ClientMgr

	// Views (thin wrapper for page routing)
	ViewsRoot *RootViewsHandler

	// App config
	HideGames  bool
	HideWorlds bool

	// Ad config - all default to enabled, can be disabled per-placement
	AdsEnabled        bool   // Master switch: LILBATTLE_ADS_ENABLED (default: true)
	AdsFooterEnabled  bool   // Footer banner: LILBATTLE_ADS_FOOTER (default: true)
	AdsHomeEnabled    bool   // Homepage mid-section: LILBATTLE_ADS_HOME (default: true)
	AdsListingEnabled bool   // Listing pages: LILBATTLE_ADS_LISTING (default: true)
	AdNetworkId       string // Google AdSense publisher ID: LILBATTLE_AD_NETWORK_ID
	AdSlotId          string // Google AdSense ad unit slot ID: LILBATTLE_AD_SLOT_ID

	BaseUrl string
	// contains filtered or unexported fields
}

LilBattleApp is the pure application context. It holds all app-specific state without knowing about goapplib. Views access this via app.Context in goal.App[*LilBattleApp].

func NewLilBattleApp

func NewLilBattleApp(clientMgr *services.ClientMgr) (lilbattleApp *LilBattleApp, goalApp *goal.App[*LilBattleApp], err error)

NewLilBattleApp creates a new LilBattleApp and its associated goal.App. Returns the LilBattleApp and the goal.App wrapper.

func (*LilBattleApp) EnsureAuthUser

func (n *LilBattleApp) EnsureAuthUser(authtype string, provider string, token *oauth2.Token, userInfo map[string]any) (accounts.User, error)

func (*LilBattleApp) GetUserByID

func (n *LilBattleApp) GetUserByID(userId string) (accounts.User, error)

func (*LilBattleApp) Handler

func (a *LilBattleApp) Handler() http.Handler

Handler returns a configured HTTP handler with all routes.

func (*LilBattleApp) ValidateUsernamePassword

func (n *LilBattleApp) ValidateUsernamePassword(username string, password string) (accounts.User, error)

type LoginPage

type LoginPage struct {
	goal.SampleLoginPage[*LilBattleApp]
	Header             Header
	EnableTwitterLogin bool
}

LoginPage extends goapplib.SampleLoginPage with app-specific features.

func (*LoginPage) Load

func (p *LoginPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type NotFoundPage

type NotFoundPage struct {
	BasePage
	Header Header
	Path   string
}

NotFoundPage is the view data for 404 pages

func (*NotFoundPage) Load

type PrivacyPolicy

type PrivacyPolicy struct {
	BasePage
	Header Header
}

func (*PrivacyPolicy) Load

func (p *PrivacyPolicy) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type ProfilePage

type ProfilePage struct {
	goal.SampleProfilePage[*LilBattleApp]
	Header Header

	// App-specific user information
	User accounts.User

	// Username fields - for login alias (stored in UsernameStore)
	UsernameNeeded bool // True if user hasn't set a username yet

	// Nickname fields (Nickname is in SampleProfilePage base)
	NicknameNeeded    bool   // True if user needs to set their nickname
	SuggestedNickname string // Random suggestion for nickname

	// Password availability
	HasLocalAuth bool // True if user has an email identity (can potentially have password)
	HasPassword  bool // True if user has a local channel with password set
}

ProfilePage extends goapplib.SampleProfilePage with app-specific features.

func (*ProfilePage) Load

func (p *ProfilePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type RegisterPage

type RegisterPage struct {
	goal.SampleRegisterPage[*LilBattleApp]
	Header Header
}

RegisterPage extends goapplib.SampleRegisterPage with app-specific features.

func (*RegisterPage) Load

func (p *RegisterPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type ResendEmailSender

type ResendEmailSender struct {
	// contains filtered or unexported fields
}

ResendEmailSender sends emails via the Resend API

func NewResendEmailSender

func NewResendEmailSender(apiKey, fromAddr string) *ResendEmailSender

func (*ResendEmailSender) SendPasswordResetEmail

func (r *ResendEmailSender) SendPasswordResetEmail(to string, resetLink string) error

func (*ResendEmailSender) SendVerificationEmail

func (r *ResendEmailSender) SendVerificationEmail(to string, verificationLink string) error

type ResetPasswordPage

type ResetPasswordPage struct {
	BasePage
	CustomHeader bool
	Token        string
	InvalidToken bool
	Success      bool
	Error        string
}

ResetPasswordPage renders the password reset form.

func (*ResetPasswordPage) Load

func (p *ResetPasswordPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type RootViewsHandler

type RootViewsHandler struct {
	LilBattleApp *LilBattleApp            // Pure app context
	GoalApp      *goal.App[*LilBattleApp] // goal.App wrapper for templates/rendering
	// contains filtered or unexported fields
}

RootViewsHandler is a thin wrapper for page routing. It references both the LilBattleApp (pure context) and goal.App (templates/rendering).

func NewRootViewsHandler

func NewRootViewsHandler(lilbattleApp *LilBattleApp, goalApp *goal.App[*LilBattleApp]) *RootViewsHandler

NewRootViewsHandler creates a new RootViewsHandler.

func (*RootViewsHandler) HandleError

func (b *RootViewsHandler) HandleError(err error, w io.Writer)

func (*RootViewsHandler) Handler

func (n *RootViewsHandler) Handler() http.Handler

func (*RootViewsHandler) RegisterSEORoutes

func (n *RootViewsHandler) RegisterSEORoutes()

RegisterSEORoutes registers robots.txt and sitemap handlers

type RulesGroup

type RulesGroup struct{}

RulesGroup implements goal.PageGroup for /rules routes.

func (*RulesGroup) RegisterRoutes

func (g *RulesGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux

RegisterRoutes registers all rules-related routes using goal.Register.

type SecurityHeadersMiddleware

type SecurityHeadersMiddleware struct {
	// IsDevelopment disables some strict policies for local development
	IsDevelopment bool
}

SecurityHeadersMiddleware adds security headers to all responses. These headers help protect against common web vulnerabilities.

func NewSecurityHeadersMiddleware

func NewSecurityHeadersMiddleware() *SecurityHeadersMiddleware

NewSecurityHeadersMiddleware creates a new security headers middleware. Set isDevelopment=true to relax some policies for local development.

func (*SecurityHeadersMiddleware) Wrap

Wrap wraps an http.Handler with security headers.

type SelectWorldPage

type SelectWorldPage struct {
	BasePage
	Header        Header
	WorldListView WorldListView
}

func (*SelectWorldPage) Load

func (m *SelectWorldPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type SitemapIndex

type SitemapIndex struct {
	XMLName  xml.Name            `xml:"sitemapindex"`
	XMLNS    string              `xml:"xmlns,attr"`
	Sitemaps []SitemapIndexEntry `xml:"sitemap"`
}

type SitemapIndexEntry

type SitemapIndexEntry struct {
	Loc     string `xml:"loc"`
	LastMod string `xml:"lastmod,omitempty"`
}

type SitemapURL

type SitemapURL struct {
	Loc        string `xml:"loc"`
	LastMod    string `xml:"lastmod,omitempty"`
	ChangeFreq string `xml:"changefreq,omitempty"`
	Priority   string `xml:"priority,omitempty"`
}

type StartGamePage

type StartGamePage struct {
	BasePage
	Header            Header
	World             *protos.World
	WorldData         *protos.WorldData
	WorldId           string
	UnitTypes         []UnitType
	GameConfiguration *protos.GameConfiguration

	// Form fields (can be pre-filled or from error retry)
	GameId       string
	GameName     string
	ErrorMessage string // Error message for ID conflicts etc.
}

func (*StartGamePage) Load

func (p *StartGamePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type TBButton

type TBButton struct {
	ButtonId  string
	IconImage string
	Label     string
	Command   string
}

Toolbar buttons on the editor page

type TermsOfService

type TermsOfService struct {
	BasePage
	Header Header
}

func (*TermsOfService) Load

func (t *TermsOfService) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type TerrainData

type TerrainData struct {
	ID           int32        // `json:"id"`
	Name         string       // `json:"name"`
	BaseMoveCost float64      // `json:"baseMoveCost"` // Base movement cost for this terrain
	DefenseBonus float64      // `json:"defenseBonus"`
	Type         TerrainType2 // `json:"type"` // Nature or Player terrain
	Properties   []string     // `json:"properties,omitempty"`

}

TerrainData represents terrain type information

type TerrainType

type TerrainType struct {
	TerrainData
	IconDataURL     string `json:"iconDataURL"`
	HasPlayerColors bool   `json:"hasPlayerColors"`
}

type TerrainType2

type TerrainType2 int32

TerrainType represents whether terrain is nature or player-controllable

const (
	TerrainNature TerrainType2 = iota // Natural terrain (grass, mountains, water, etc.)
	TerrainPlayer                     // Player-controllable structures (bases, cities, etc.)
)

type ThemeManager

type ThemeManager struct {
	// contains filtered or unexported fields
}

ThemeManager handles theme asset resolution and caching

func GetThemeManager

func GetThemeManager() *ThemeManager

GetThemeManager returns the singleton theme manager

func (*ThemeManager) ClearCache

func (tm *ThemeManager) ClearCache()

ClearCache clears the theme mapping cache

func (*ThemeManager) GetTerrainIconURL

func (tm *ThemeManager) GetTerrainIconURL(terrainID int32, useTheme bool, themeName string) string

GetTerrainIconURL returns the icon URL for a terrain ID

func (*ThemeManager) GetTerrainName

func (tm *ThemeManager) GetTerrainName(terrainID int32, defaultName string, useTheme bool, themeName string) string

GetTerrainName returns the themed name for a terrain, or the default name if not themed

func (*ThemeManager) GetUnitIconURL

func (tm *ThemeManager) GetUnitIconURL(unitID int32, useTheme bool, themeName string) string

GetUnitIconURL returns the icon URL for a unit ID

func (*ThemeManager) GetUnitName

func (tm *ThemeManager) GetUnitName(unitID int32, defaultName string, useTheme bool, themeName string) string

GetUnitName returns the themed name for a unit, or the default name if not themed

func (*ThemeManager) LoadThemeMapping

func (tm *ThemeManager) LoadThemeMapping(themeName string) (*ThemeMapping, error)

LoadThemeMapping loads and caches a theme's mapping.json

type ThemeMapping

type ThemeMapping struct {
	Units    map[string]ThemeMappingEntry `json:"units"`
	Terrains map[string]ThemeMappingEntry `json:"terrains"`
}

ThemeMapping represents the mapping.json structure

type ThemeMappingEntry

type ThemeMappingEntry struct {
	Old   string `json:"old"`
	Name  string `json:"name"`
	Image string `json:"image"`
}

type TwitterOAuth2

type TwitterOAuth2 struct {
	ClientId       string
	ClientSecret   string
	CallbackURL    string
	HandleUser     accounts.HandleUserFunc
	AuthFailureUrl string
	// contains filtered or unexported fields
}

TwitterOAuth2 implements OAuth 2.0 with PKCE for Twitter/X authentication.

func NewTwitterOAuth2

func NewTwitterOAuth2(clientId, clientSecret, callbackUrl string, handleUser accounts.HandleUserFunc) *TwitterOAuth2

NewTwitterOAuth2 creates a new Twitter OAuth2 handler. Empty parameters will be read from environment variables.

func (*TwitterOAuth2) Handler

func (t *TwitterOAuth2) Handler() http.Handler

type TwitterUserResponse

type TwitterUserResponse struct {
	Data struct {
		ID              string `json:"id"`
		Name            string `json:"name"`
		Username        string `json:"username"`
		ProfileImageURL string `json:"profile_image_url"`
	} `json:"data"`
}

TwitterUserResponse represents the Twitter API v2 user response.

type URLSet

type URLSet struct {
	XMLName xml.Name     `xml:"urlset"`
	XMLNS   string       `xml:"xmlns,attr"`
	URLs    []SitemapURL `xml:"url"`
}

type UnitType

type UnitType struct {
	*protos.UnitDefinition
	IconDataURL string `json:"iconDataURL"`
}

type UsersHandler

type UsersHandler struct {
	App *LilBattleApp
}

UsersHandler handles user showcase pages

func NewUsersHandler

func NewUsersHandler(app *LilBattleApp) *UsersHandler

NewUsersHandler creates a new users handler

func (*UsersHandler) Handler

func (h *UsersHandler) Handler() http.Handler

Handler returns an HTTP handler for users routes

type WebAppServer

type WebAppServer struct {
	goal.WebAppServer
}

func (*WebAppServer) Start

func (s *WebAppServer) Start(ctx context.Context, srvErr chan error, stopChan chan bool) error

type WorldCreatePage

type WorldCreatePage struct {
	BasePage
	Header Header

	// Form fields (pre-filled on conflict retry)
	SuggestedId  string
	ErrorMessage string
	WorldName    string
}

func (*WorldCreatePage) Load

func (p *WorldCreatePage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type WorldEditorPage

type WorldEditorPage struct {
	BasePage
	Header         Header
	IsOwner        bool
	WorldId        string
	World          *protos.World
	WorldData      *protos.WorldData
	Errors         map[string]string
	TBButtons      []*TBButton
	AllowCustomId  bool
	NatureTerrains []TerrainType
	CityTerrains   []TerrainType
	UnitTypes      []UnitType
	Crossings      []CrossingType // Road and Bridge crossings
	PlayerCount    int
	Theme          string // Theme name from query parameter (default, fantasy, modern)
}

func (*WorldEditorPage) Load

func (v *WorldEditorPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

func (*WorldEditorPage) SetupDefaults

func (v *WorldEditorPage) SetupDefaults()

type WorldListView

type WorldListView struct {
	goal.WithPagination
	goal.WithFiltering

	Worlds     []*protos.World
	ActionMode string // "manage" or "select"
}

func (*WorldListView) Load

func (p *WorldListView) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type WorldListingPage

type WorldListingPage struct {
	BasePage
	Header Header

	WorldListView WorldListView
	ListingData   *goal.EntityListingData[*protos.World]
}

func (*WorldListingPage) Load

func (m *WorldListingPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type WorldViewerPage

type WorldViewerPage struct {
	BasePage
	Header    Header
	World     *protos.World
	WorldData *protos.WorldData
	WorldId   string
}

func (*WorldViewerPage) Load

func (p *WorldViewerPage) Load(r *http.Request, w http.ResponseWriter, app *goal.App[*LilBattleApp]) (err error, finished bool)

type WorldsGroup

type WorldsGroup struct {
	// contains filtered or unexported fields
}

WorldsGroup implements goal.PageGroup for /worlds routes.

func (*WorldsGroup) RegisterRoutes

func (g *WorldsGroup) RegisterRoutes(app *goal.App[*LilBattleApp]) *http.ServeMux

RegisterRoutes registers all world-related routes using goal.Register.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL