Noah Petherbridge
82884c79ae
Add the ability for the free version of the game to allow loading levels that use embedded custom doodads if those levels are signed. * Uses the same signing keys as the JWT token for license registrations. * Levels and Levelpacks can both be signed. So individual levels with embedded doodads can work in free versions of the game. * Levelpacks now support embedded doodads properly: the individual levels in the pack don't need to embed a custom doodad, but if the doodad exists in the levelpack's doodads/ folder it will load from there instead - for full versions of the game OR when the levelpack is signed. Signatures are computed by getting a listing of embedded assets inside the zipfile (the assets/ folder in levels, and the doodads/ + levels/ folders in levelpacks). Thus for individual signed levels, the level geometry and metadata may be changed without breaking the signature but if custom doodads are changed the signature will break. The doodle-admin command adds subcommands to `sign-level` and `verify-level` to manage signatures on levels and levelpacks. When using the `doodad levelpack create` command, any custom doodads the levels mention that are found in your profile directory get embedded into the zipfile by default (with --doodads custom).
99 lines
2.5 KiB
Go
99 lines
2.5 KiB
Go
package doodle
|
|
|
|
import (
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/levelpack"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/shmem"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/usercfg"
|
|
"git.kirsle.net/SketchyMaze/doodle/pkg/windows"
|
|
"git.kirsle.net/go/render"
|
|
"git.kirsle.net/go/ui"
|
|
)
|
|
|
|
// Set up the menu bar for Play Scene.
|
|
func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar {
|
|
menu := ui.NewMenuBar("Main Menu")
|
|
|
|
////////
|
|
// Game menu
|
|
gameMenu := menu.AddMenu("Game")
|
|
gameMenu.AddItem("Story Mode", func() {
|
|
// TODO: de-duplicate code from MainScene
|
|
if u.winLevelPacks == nil {
|
|
u.winLevelPacks = windows.NewLevelPackWindow(windows.LevelPack{
|
|
Supervisor: u.Supervisor,
|
|
Engine: d.Engine,
|
|
|
|
OnPlayLevel: func(lp *levelpack.LevelPack, which levelpack.Level) {
|
|
if err := d.PlayFromLevelpack(lp, which); err != nil {
|
|
shmem.FlashError(err.Error())
|
|
}
|
|
},
|
|
OnCloseWindow: func() {
|
|
u.winLevelPacks.Hide()
|
|
},
|
|
})
|
|
}
|
|
u.winLevelPacks.MoveTo(render.Point{
|
|
X: (d.width / 2) - (u.winLevelPacks.Size().W / 2),
|
|
Y: (d.height / 2) - (u.winLevelPacks.Size().H / 2),
|
|
})
|
|
u.winLevelPacks.Show()
|
|
})
|
|
gameMenu.AddItemAccel("New drawing", "Ctrl-N", d.GotoNewMenu)
|
|
gameMenu.AddItemAccel("Open drawing", "Ctrl-O", d.GotoLoadMenu)
|
|
|
|
gameMenu.AddSeparator()
|
|
gameMenu.AddItem("Quit to menu", func() {
|
|
d.Goto(&MainScene{})
|
|
})
|
|
gameMenu.AddItemAccel("Quit", "Escape", func() {
|
|
d.ConfirmExit()
|
|
})
|
|
|
|
////////
|
|
// Level menu
|
|
levelMenu := menu.AddMenu("Level")
|
|
levelMenu.AddItem("Restart level", u.RestartLevel)
|
|
levelMenu.AddItem("Retry from checkpoint", func() {
|
|
u.SetImperfect()
|
|
u.RetryCheckpoint()
|
|
})
|
|
levelMenu.AddSeparator()
|
|
levelMenu.AddItemAccel("Edit level", "E", u.EditLevel)
|
|
|
|
// Hilariously broken, someday!
|
|
if usercfg.Current.EnableFeatures {
|
|
levelMenu.AddSeparator()
|
|
levelMenu.AddItemAccel("New viewport", "v", func() {
|
|
pip := windows.MakePiPWindow(d.width, d.height, windows.PiP{
|
|
Supervisor: u.Supervisor,
|
|
Engine: u.d.Engine,
|
|
Level: u.Level,
|
|
Event: u.d.event,
|
|
})
|
|
|
|
pip.Show()
|
|
})
|
|
}
|
|
|
|
helpMenu := d.MakeHelpMenu(menu, u.Supervisor)
|
|
if usercfg.Current.EnableCheatsMenu {
|
|
helpMenu.AddSeparator()
|
|
helpMenu.AddItem("Cheats Menu", func() {
|
|
if u.cheatsWindow != nil {
|
|
u.cheatsWindow.Hide()
|
|
u.cheatsWindow.Destroy()
|
|
u.cheatsWindow = nil
|
|
}
|
|
|
|
u.cheatsWindow = u.d.MakeCheatsWindow(u.Supervisor)
|
|
u.cheatsWindow.Show()
|
|
})
|
|
}
|
|
|
|
menu.Supervise(u.Supervisor)
|
|
menu.Compute(d.Engine)
|
|
|
|
return menu
|
|
}
|