From 7eb7f6148cdf96011519509adbb8a39f42e9fc6c Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Thu, 18 Apr 2024 20:23:07 -0700 Subject: [PATCH] WIP Doodle++ --- Building.md | 123 ++++++++--- Makefile | 40 ++-- bootstrap.py | 8 + cmd/doodad/main.go | 13 +- cmd/doodle/main.go | 14 +- pkg/balance/flag_free.go | 7 - pkg/balance/flag_paid.go | 7 - pkg/balance/tag_dpp.go | 7 + pkg/balance/tag_foss.go | 7 + pkg/branding/builds/builds.go | 36 ++++ pkg/doodads/fmt_readwrite.go | 23 --- pkg/editor_ui.go | 8 +- pkg/editor_ui_doodad.go | 3 +- pkg/editor_ui_menubar.go | 23 ++- .../giant_screenshot/giant_screenshot.go | 4 +- .../giant_screenshot/regular_screenshot.go | 4 +- pkg/level/publishing/publishing.go | 5 +- pkg/license/admin.go | 100 --------- pkg/license/config.go | 25 --- pkg/license/levelsigning/level_signing.go | 193 ------------------ pkg/license/license.go | 108 ---------- pkg/main_scene.go | 9 +- pkg/native/username.go | 6 +- pkg/play_scene.go | 3 +- pkg/plus/dpp/plus_dpp.go | 24 +++ pkg/plus/foss/plus_foss.go | 22 ++ pkg/plus/initdpp/plus_dpp.go | 24 +++ pkg/plus/initdpp/plus_foss.go | 22 ++ pkg/plus/initdpp/plus_init.go | 1 + pkg/plus/plus.go | 23 +++ pkg/uix/canvas_actors.go | 6 +- pkg/windows/license_key.go | 3 +- pkg/windows/open_level_editor.go | 5 +- 33 files changed, 338 insertions(+), 568 deletions(-) delete mode 100644 pkg/balance/flag_free.go delete mode 100644 pkg/balance/flag_paid.go create mode 100644 pkg/balance/tag_dpp.go create mode 100644 pkg/balance/tag_foss.go create mode 100644 pkg/branding/builds/builds.go delete mode 100644 pkg/license/admin.go delete mode 100644 pkg/license/config.go delete mode 100644 pkg/license/levelsigning/level_signing.go delete mode 100644 pkg/license/license.go create mode 100644 pkg/plus/dpp/plus_dpp.go create mode 100644 pkg/plus/foss/plus_foss.go create mode 100644 pkg/plus/initdpp/plus_dpp.go create mode 100644 pkg/plus/initdpp/plus_foss.go create mode 100644 pkg/plus/initdpp/plus_init.go create mode 100644 pkg/plus/plus.go diff --git a/Building.md b/Building.md index c03d9d0..60512f0 100644 --- a/Building.md +++ b/Building.md @@ -1,12 +1,21 @@ # Building Doodle -* [Automated Release Scripts](#automated-release-scripts) -* [Quickstart with bootstrap.py](#quickstart-with-bootstrap-py) -* [Detailed Instructions](#detailed-instructions) -* [Linux](#linux) -* [Flatpak for Linux](#flatpak-for-linux) -* [Windows Cross-Compile from Linux](#windows-cross-compile-from-linux) -* [Old Docs](#old-docs) +- [Building Doodle](#building-doodle) +- [Dockerfile](#dockerfile) +- [Automated Release Scripts](#automated-release-scripts) +- [Go Environment](#go-environment) +- [Quickstart with bootstrap.py](#quickstart-with-bootstrappy) +- [Detailed Instructions](#detailed-instructions) + - [Fonts](#fonts) + - [Makefile](#makefile) +- [Dependencies](#dependencies) + - [Flatpak for Linux](#flatpak-for-linux) + - [Windows Cross-Compile from Linux](#windows-cross-compile-from-linux) + - [Windows DLLs](#windows-dlls) + - [Build on macOS from scratch](#build-on-macos-from-scratch) +- [WebAssembly](#webassembly) +- [Build Tags](#build-tags) + - [dpp](#dpp) # Dockerfile @@ -43,6 +52,21 @@ Other Dockerfiles and scripts used to release the game: The Docker container depends on all the git servers being up, but if you have the uber blob source code you can read the Dockerfile to see what it does. +# Go Environment + +Part of the build scripts involve building and running the `doodad` command +from this repo in order to generate the game's built-in doodads. For this to +work smoothly from your Linux or macOS build environment, you may need to +ensure that your `${GOPATH}/bin` directory is on your `$PATH` by, for example, +configuring this in your bash/zsh profile: + +```bash +export GOPATH="${HOME}/go" +export PATH="${PATH}:${GOPATH}/bin" +``` + +For a complete example, see the "Build on macOS from scratch" section below. + # Quickstart with bootstrap.py From any Unix-like system (Fedora, Ubuntu, macOS) the bootstrap.py script @@ -278,6 +302,47 @@ cp /usr/x86_64-w64-mingw32/bin/SDL*.dll bin/ SDL2_ttf requires libfreetype, you can get its DLL here: https://github.com/ubawurinna/freetype-windows-binaries +## Build on macOS from scratch + +Here are some detailed instructions how to build Sketchy Maze from a fresh +install of macOS Ventura that assumes no previous software or configuration +was applied to the system yet. + +Install homebrew: https://brew.sh pay attention to the instructions at the end +of the install to set up your zsh profile for homebrew to work correctly. + +Clone the doodle repository: + +```bash +git clone https://git.kirsle.net/SketchyMaze/doodle +cd doodle +``` + +Note: on a fresh install, invoking the `git` command may cause macOS to install +developer tools and Xcode. After installed, run the git clone again to finish +cloning the repository. + +Set your Go environment variables: edit your ~/.zprofile and ensure that $GOPATH +is configured and that your $PATH includes $GOPATH/bin. **Note:** restart your +terminal session or reload the config file (e.g. `. ~/.zprofile`) after making +this change. + +```bash +# in your .zprofile, .bash_profile, .zshrc or similar shell config +export GOPATH="${HOME}/go" +export PATH="${PATH}:${GOPATH}/bin" +``` + +Run the bootstrap script: + +```bash +python3 bootstrap.py +``` + +Answer N (default) when asked to clone dependency repos over ssh. The bootstrap +script will `brew install` any necessary dependencies (Go, SDL2, etc.) and clone +support repos for the game (doodads, levelpacks, assets). + # WebAssembly There is some **experimental** support for a WebAssembly build of Sketchy Maze @@ -304,33 +369,33 @@ Some tips to get a WASM build to work: * Run `make wasm` to build the WASM binary and `make wasm-serve` to run a simple Go web server to serve it from. -# Old Docs +# Build Tags -## Build Tags +Go build tags used by this game: -These aren't really used much anymore but documented here: +## dpp -### shareware +The dpp tag stands for Doodle++ and is used for official commercial builds of +the game. Doodle++ builds include additional code not found in the free & open +source release of the game engine. -> Files ending with `_free.go` are for the shareware release as opposed to -> `_paid.go` for the full version. +This build tag should be set automatically by the Makefile **if** the deps/ +folder has a git clone of the dpp project. The bootstrap.py script will clone +the dpp repo **if** you use SSH to clone dependencies: so you will need SSH +credentials to the upstream git server. It basically means that third-party +users who download the open source release will not have the dpp dependency, +and will not build dpp copies of the game. -Builds the game in the free shareware release mode. +If you _do_ have the dpp dependency, you can force build (and run) FOSS +versions of the game via the Makefile commands `make build-free`, +`make run-free` or `make dist-free` which are counterparts to the main make +commands but which deliberately do not set the dpp build tag. -Run `make build-free` to build the shareware binary. +In source code, files ending with `_dpp.go` and `_foss.go` are conditionally +compiled depending on this build tag. -Shareware releases of the game have the following changes compared to the default -(release) mode: +How to tell whether your build of Sketchy Maze is Doodle++ include: -* No access to the Doodad Editor scene in-game (soft toggle) - -### developer - -> Files ending with `_developer.go` are for the developer build as opposed to -> `_release.go` for the public version. - -Developer builds support extra features over the standard release version: - -* Ability to write the JSON file format for Levels and Doodads. - -Run `make build-debug` to build a developer version of the program. +* The version string on the title screen. + * FOSS builds (not dpp) will say "open source" in the version. + * DPP builds may say "shareware" if unregistered or just the version. diff --git a/Makefile b/Makefile index 6055340..349c89a 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,12 @@ CURDIR=$(shell curdir) LDFLAGS := -ldflags "-X main.Build=$(BUILD) -X main.BuildDate=$(BUILD_DATE)" LDFLAGS_W := -ldflags "-X main.Build=$(BUILD) -X main.BuildDate=$(BUILD_DATE) -H windowsgui" +# Doodle++ build tag for official builds of the game. +BUILD_TAGS := -tags="" +ifneq ("$(wildcard ./deps/dpp)", "") + BUILD_TAGS = -tags="dpp" +endif + # `make setup` to set up a new environment, pull dependencies, etc. .PHONY: setup setup: clean @@ -17,8 +23,8 @@ setup: clean # `make build` to build the binary. .PHONY: build build: - go build $(LDFLAGS) -o bin/sketchymaze cmd/doodle/main.go - go build $(LDFLAGS) -o bin/doodad cmd/doodad/main.go + go build $(LDFLAGS) $(BUILD_TAGS) -o bin/sketchymaze cmd/doodle/main.go + go build $(LDFLAGS) $(BUILD_TAGS) -o bin/doodad cmd/doodad/main.go # `make buildall` to run all build steps including doodads. .PHONY: buildall @@ -28,15 +34,8 @@ buildall: doodads build .PHONY: build-free build-free: gofmt -w . - go build $(LDFLAGS) -tags="shareware" -o bin/sketchymaze cmd/doodle/main.go - go build $(LDFLAGS) -tags="shareware" -o bin/doodad cmd/doodad/main.go - -# `make build-debug` to build the binary in developer mode. -.PHONY: build-debug -build-debug: - gofmt -w . - go build $(LDFLAGS) -tags="developer" -o bin/sketchymaze cmd/doodle/main.go - go build $(LDFLAGS) -tags="developer" -o bin/doodad cmd/doodad/main.go + go build $(LDFLAGS) -o bin/sketchymaze cmd/doodle/main.go + go build $(LDFLAGS) -o bin/doodad cmd/doodad/main.go # `make bindata` generates the embedded binary assets package. .PHONY: bindata @@ -74,30 +73,30 @@ doodads: mingw: env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS_W) -i -o bin/sketchymaze.exe cmd/doodle/main.go + go build $(LDFLAGS_W) $(BUILD_TAGS) -i -o bin/sketchymaze.exe cmd/doodle/main.go env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS) -i -o bin/doodad.exe cmd/doodad/main.go + go build $(LDFLAGS) $(BUILD_TAGS) -i -o bin/doodad.exe cmd/doodad/main.go # `make mingw32` to cross-compile a Windows binary with mingw (32-bit). .PHONY: mingw32 mingw32: env CGO_ENABLED="1" CC="/usr/bin/i686-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS_W) -i -o bin/sketchymaze.exe cmd/doodle/main.go + go build $(LDFLAGS_W) $(BUILD_TAGS) -i -o bin/sketchymaze.exe cmd/doodle/main.go env CGO_ENABLED="1" CC="/usr/bin/i686-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS) -i -o bin/doodad.exe cmd/doodad/main.go + go build $(LDFLAGS) $(BUILD_TAGS) -i -o bin/doodad.exe cmd/doodad/main.go # `make mingw-free` for Windows binary in free mode. .PHONY: mingw-free mingw-free: env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS_W) -tags="shareware" -i -o bin/sketchymaze.exe cmd/doodle/main.go + go build $(LDFLAGS_W) -i -o bin/sketchymaze.exe cmd/doodle/main.go env CGO_ENABLED="1" CC="/usr/bin/x86_64-w64-mingw32-gcc" \ GOOS="windows" CGO_LDFLAGS="-lmingw32 -lSDL2" CGO_CFLAGS="-D_REENTRANT" \ - go build $(LDFLAGS) -tags="shareware" -i -o bin/doodad.exe cmd/doodad/main.go + go build $(LDFLAGS) -i -o bin/doodad.exe cmd/doodad/main.go # `make release` runs the release.sh script, must be run # after `make dist` @@ -145,12 +144,17 @@ from-docker32: build mingw32 __dist-common # `make run` to run it from source. .PHONY: run run: + go run ${BUILD_TAGS} cmd/doodle/main.go + +# `make run-free` to run it from source with no build tags (foss version). +.PHONY: run-free +run-free: go run cmd/doodle/main.go # `make debug` to run it in -debug mode. .PHONY: debug debug: - go run cmd/doodle/main.go -debug + go run $(BUILD_TAGS) cmd/doodle/main.go -debug # `make guitest` to run it in guitest mode. .PHONY: guitest diff --git a/bootstrap.py b/bootstrap.py index 927c414..2e8d4d9 100755 --- a/bootstrap.py +++ b/bootstrap.py @@ -37,6 +37,10 @@ repos_github = { "git@github.com:kirsle/audio": "audio", # TODO: the rest } +repos_ssh = { + # SSH-only (private) repos. + "git@git.kirsle.net:SketchyMaze/dpp": "dpp", +} # Software dependencies. dep_fedora = ["make", "golang", "SDL2-devel", "SDL2_ttf-devel", "SDL2_mixer-devel", "zip", "rsync"] @@ -167,4 +171,8 @@ if __name__ == "__main__": https = k.replace("git@git.kirsle.net:", "https://git.kirsle.net/") repos[https] = repos[k] del repos[k] + else: + # mix in SSH-only repos + repos.update(repos_ssh) + main() diff --git a/cmd/doodad/main.go b/cmd/doodad/main.go index 1b4ba54..01f4754 100644 --- a/cmd/doodad/main.go +++ b/cmd/doodad/main.go @@ -8,8 +8,7 @@ import ( "time" "git.kirsle.net/SketchyMaze/doodle/cmd/doodad/commands" - "git.kirsle.net/SketchyMaze/doodle/pkg/branding" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "github.com/urfave/cli/v2" ) @@ -31,15 +30,9 @@ func main() { app.Name = "doodad" app.Usage = "command line interface for Doodle" - var freeLabel string - if !license.IsRegistered() { - freeLabel = " (shareware)" - } - - app.Version = fmt.Sprintf("%s build %s%s. Built on %s", - branding.Version, + app.Version = fmt.Sprintf("%s build %s. Built on %s", + builds.Version, Build, - freeLabel, BuildDate, ) diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index 180f820..b8e16ca 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -15,9 +15,9 @@ import ( doodle "git.kirsle.net/SketchyMaze/doodle/pkg" "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/chatbot" "git.kirsle.net/SketchyMaze/doodle/pkg/gamepad" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/native" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" @@ -55,11 +55,6 @@ func main() { app.Name = "doodle" app.Usage = fmt.Sprintf("%s - %s", branding.AppName, branding.Summary) - var freeLabel string - if !license.IsRegistered() { - freeLabel = " (shareware)" - } - // Load user settings from disk ASAP. if err := usercfg.Load(); err != nil { log.Error("Error loading user settings (defaults will be used): %s", err) @@ -73,10 +68,9 @@ func main() { // Set GameController style. gamepad.SetStyle(gamepad.Style(usercfg.Current.ControllerStyle)) - app.Version = fmt.Sprintf("%s build %s%s. Built on %s", - branding.Version, + app.Version = fmt.Sprintf("%s build %s. Built on %s", + builds.Version, Build, - freeLabel, BuildDate, ) @@ -119,6 +113,8 @@ func main() { } app.Action = func(c *cli.Context) error { + log.Info("Starting %s %s", app.Name, app.Version) + // --chdir into a different working directory? e.g. for Flatpak especially. if doodlePath := c.String("chdir"); doodlePath != "" { if err := os.Chdir(doodlePath); err != nil { diff --git a/pkg/balance/flag_free.go b/pkg/balance/flag_free.go deleted file mode 100644 index 725f5d3..0000000 --- a/pkg/balance/flag_free.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build shareware -// +build shareware - -package balance - -// FreeVersion is true in the free version of the game. -const FreeVersion = true diff --git a/pkg/balance/flag_paid.go b/pkg/balance/flag_paid.go deleted file mode 100644 index 25482ae..0000000 --- a/pkg/balance/flag_paid.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build !shareware -// +build !shareware - -package balance - -// FreeVersion is true in the free version of the game. -const FreeVersion = false diff --git a/pkg/balance/tag_dpp.go b/pkg/balance/tag_dpp.go new file mode 100644 index 0000000..9bcf6e5 --- /dev/null +++ b/pkg/balance/tag_dpp.go @@ -0,0 +1,7 @@ +//go:build dpp +// +build dpp + +package balance + +// Doodle++ tag compiled in. +const DPP = true diff --git a/pkg/balance/tag_foss.go b/pkg/balance/tag_foss.go new file mode 100644 index 0000000..8cd64f9 --- /dev/null +++ b/pkg/balance/tag_foss.go @@ -0,0 +1,7 @@ +//go:build !dpp +// +build !dpp + +package balance + +// Doodle++ tag compiled in. +const DPP = false diff --git a/pkg/branding/builds/builds.go b/pkg/branding/builds/builds.go new file mode 100644 index 0000000..cf2b3d8 --- /dev/null +++ b/pkg/branding/builds/builds.go @@ -0,0 +1,36 @@ +// Package builds handles build-specific branding strings. +package builds + +import ( + "fmt" + + "git.kirsle.net/SketchyMaze/doodle/pkg/balance" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding" + "git.kirsle.net/SketchyMaze/doodle/pkg/license" +) + +var ( + /* + Version string for user display. + + It may look like the following: + + - "v1.2.3 (open source)" for FOSS builds of the game. + - "v1.2.3 (shareware)" for unregistered Doodle++ builds. + - "v1.2.3" for registered Doodle++ builds. + */ + Version = branding.Version + VersionSuffix = " (unknown)" +) + +func init() { + if !balance.DPP { + VersionSuffix = " (open source)" + } else if !license.IsRegistered() { + VersionSuffix = " (shareware)" + } else { + VersionSuffix = "" + } + + Version = fmt.Sprintf("v%s%s", branding.Version, VersionSuffix) +} diff --git a/pkg/doodads/fmt_readwrite.go b/pkg/doodads/fmt_readwrite.go index 16f6472..a50ae80 100644 --- a/pkg/doodads/fmt_readwrite.go +++ b/pkg/doodads/fmt_readwrite.go @@ -9,11 +9,9 @@ import ( "strings" "git.kirsle.net/SketchyMaze/doodle/assets" - "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" "git.kirsle.net/SketchyMaze/doodle/pkg/enum" "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" "git.kirsle.net/SketchyMaze/doodle/pkg/wasm" @@ -114,27 +112,6 @@ func ListBuiltin() ([]string, error) { return result, nil } -/* -LoadFromEmbeddable reads a doodad file, checking a level's embeddable -file data in addition to the usual places. - -Use a true value for `force` to always return the file if available. By -default it will do a license check and free versions of the game won't -read the asset and get an error instead. A "Signed Level" is allowed to -use embedded assets in free versions and the caller uses force=true to -communicate the signature status. -*/ -func LoadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*Doodad, error) { - if bin, err := fs.GetFile(balance.EmbeddedDoodadsBasePath + filename); err == nil { - log.Debug("doodads.LoadFromEmbeddable: found %s", filename) - if !force && !license.IsRegistered() { - return nil, license.ErrRegisteredFeature - } - return Deserialize(filename, bin) - } - return LoadFile(filename) -} - // LoadFile reads a doodad file from disk, checking a few locations. // // It checks for embedded bindata, system-level doodads on the filesystem, diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 352d5f4..f44145b 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -6,11 +6,11 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/drawtool" "git.kirsle.net/SketchyMaze/doodle/pkg/enum" "git.kirsle.net/SketchyMaze/doodle/pkg/level" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" "git.kirsle.net/SketchyMaze/doodle/pkg/uix" @@ -595,12 +595,8 @@ func (u *EditorUI) SetupStatusBar(d *Doodle) *ui.Frame { } } - var shareware string - if !license.IsRegistered() { - shareware = " (shareware)" - } extraLabel := ui.NewLabel(ui.Label{ - Text: fmt.Sprintf("%s v%s%s", branding.AppName, branding.Version, shareware), + Text: fmt.Sprintf("%s %s", branding.AppName, builds.Version), Font: balance.StatusFont, }) extraLabel.Configure(ui.Config{ diff --git a/pkg/editor_ui_doodad.go b/pkg/editor_ui_doodad.go index 14303f6..f0f3436 100644 --- a/pkg/editor_ui_doodad.go +++ b/pkg/editor_ui_doodad.go @@ -9,6 +9,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/uix" "git.kirsle.net/go/render" ) @@ -34,7 +35,7 @@ func (u *EditorUI) startDragActor(doodad *doodads.Doodad, actor *level.Actor) { if doodad == nil { if actor != nil { - obj, err := doodads.LoadFromEmbeddable(actor.Filename, u.Scene.Level, false) + obj, err := plus.DoodadFromEmbeddable(actor.Filename, u.Scene.Level, false) if err != nil { log.Error("startDragExistingActor: actor doodad name %s not found: %s", actor.Filename, err) return diff --git a/pkg/editor_ui_menubar.go b/pkg/editor_ui_menubar.go index 8c3cbc3..fc3b961 100644 --- a/pkg/editor_ui_menubar.go +++ b/pkg/editor_ui_menubar.go @@ -276,17 +276,22 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { //////// // Help menu var ( - helpMenu = u.d.MakeHelpMenu(menu, u.Supervisor) - registerText = "Register" + helpMenu = u.d.MakeHelpMenu(menu, u.Supervisor) ) - helpMenu.AddSeparator() - if license.IsRegistered() { - registerText = "Registration" + + // Registration item for Doodle++ builds. + if balance.DPP { + var registerText = "Register" + if license.IsRegistered() { + registerText = "Registration" + } + + helpMenu.AddSeparator() + helpMenu.AddItem(registerText, func() { + u.licenseWindow.Show() + u.Supervisor.FocusWindow(u.licenseWindow) + }) } - helpMenu.AddItem(registerText, func() { - u.licenseWindow.Show() - u.Supervisor.FocusWindow(u.licenseWindow) - }) menu.Supervise(u.Supervisor) menu.Compute(d.Engine) diff --git a/pkg/level/giant_screenshot/giant_screenshot.go b/pkg/level/giant_screenshot/giant_screenshot.go index 5ae11ae..d9c3ed3 100644 --- a/pkg/level/giant_screenshot/giant_screenshot.go +++ b/pkg/level/giant_screenshot/giant_screenshot.go @@ -9,9 +9,9 @@ import ( "path/filepath" "time" - "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" "git.kirsle.net/SketchyMaze/doodle/pkg/wallpaper" @@ -95,7 +95,7 @@ func GiantScreenshot(lvl *level.Level) (image.Image, error) { // Render the doodads. log.Debug("GiantScreenshot: Render actors...") for _, actor := range lvl.Actors { - doodad, err := doodads.LoadFromEmbeddable(actor.Filename, lvl, false) + doodad, err := plus.DoodadFromEmbeddable(actor.Filename, lvl, false) if err != nil { log.Error("GiantScreenshot: Load doodad: %s", err) continue diff --git a/pkg/level/giant_screenshot/regular_screenshot.go b/pkg/level/giant_screenshot/regular_screenshot.go index b6e73c8..4ece9d7 100644 --- a/pkg/level/giant_screenshot/regular_screenshot.go +++ b/pkg/level/giant_screenshot/regular_screenshot.go @@ -12,9 +12,9 @@ import ( "time" "git.kirsle.net/SketchyMaze/doodle/pkg/balance" - "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" "git.kirsle.net/go/render" "golang.org/x/image/draw" @@ -78,7 +78,7 @@ func CroppedScreenshot(lvl *level.Level, viewport render.Rect) (image.Image, err // Render the doodads. log.Debug("CroppedScreenshot: Render actors...") for _, actor := range lvl.Actors { - doodad, err := doodads.LoadFromEmbeddable(actor.Filename, lvl, false) + doodad, err := plus.DoodadFromEmbeddable(actor.Filename, lvl, false) if err != nil { log.Error("CroppedScreenshot: Load doodad: %s", err) continue diff --git a/pkg/level/publishing/publishing.go b/pkg/level/publishing/publishing.go index 9a39bff..42e5eeb 100644 --- a/pkg/level/publishing/publishing.go +++ b/pkg/level/publishing/publishing.go @@ -19,6 +19,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" ) /* @@ -37,7 +38,7 @@ func Publish(lvl *level.Level) error { } // Registered games only. - if !license.IsRegistered() { + if !balance.DPP || !license.IsRegistered() { return errors.New("only registered versions of the game can attach doodads to levels") } @@ -52,7 +53,7 @@ func Publish(lvl *level.Level) error { log.Debug("Embed filename: %s", filename) names[filename] = nil - doodad, err := doodads.LoadFromEmbeddable(filename, lvl, false) + doodad, err := plus.DoodadFromEmbeddable(filename, lvl, false) if err != nil { return fmt.Errorf("couldn't load doodad %s: %s", filename, err) } diff --git a/pkg/license/admin.go b/pkg/license/admin.go deleted file mode 100644 index af0ed06..0000000 --- a/pkg/license/admin.go +++ /dev/null @@ -1,100 +0,0 @@ -package license - -import ( - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/x509" - "encoding/pem" - "io/ioutil" - "time" - - "github.com/dgrijalva/jwt-go" -) - -// AdminGenerateKeys generates the ECDSA public and private key pair for the admin -// side of creating signed license files. -func AdminGenerateKeys() (*ecdsa.PrivateKey, error) { - privateKey, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader) - return privateKey, err -} - -// AdminWriteKeys writes the admin signing key to .pem files on disk. -func AdminWriteKeys(key *ecdsa.PrivateKey, privateFile, publicFile string) error { - // Encode the private key to PEM format. - x509Encoded, err := x509.MarshalECPrivateKey(key) - if err != nil { - return err - } - pemEncoded := pem.EncodeToMemory(&pem.Block{ - Type: "PRIVATE KEY", - Bytes: x509Encoded, - }) - - // Encode the public key to PEM format. - x509EncodedPub, err := x509.MarshalPKIXPublicKey(key.Public()) - if err != nil { - return err - } - pemEncodedPub := pem.EncodeToMemory(&pem.Block{ - Type: "PUBLIC KEY", - Bytes: x509EncodedPub, - }) - - // Write the files. - if err := ioutil.WriteFile(privateFile, pemEncoded, 0600); err != nil { - return err - } - if err := ioutil.WriteFile(publicFile, pemEncodedPub, 0644); err != nil { - return err - } - - return nil -} - -// AdminLoadPrivateKey loads the private key from disk. -func AdminLoadPrivateKey(privateFile string) (*ecdsa.PrivateKey, error) { - // Read the private key file. - pemEncoded, err := ioutil.ReadFile(privateFile) - if err != nil { - return nil, err - } - - // Decode the private key. - block, _ := pem.Decode([]byte(pemEncoded)) - x509Encoded := block.Bytes - privateKey, _ := x509.ParseECPrivateKey(x509Encoded) - return privateKey, nil -} - -// AdminLoadPublicKey loads the private key from disk. -func AdminLoadPublicKey(publicFile string) (*ecdsa.PublicKey, error) { - pemEncodedPub, err := ioutil.ReadFile(publicFile) - if err != nil { - return nil, err - } - - // Decode the public key. - blockPub, _ := pem.Decode([]byte(pemEncodedPub)) - x509EncodedPub := blockPub.Bytes - genericPublicKey, _ := x509.ParsePKIXPublicKey(x509EncodedPub) - publicKey := genericPublicKey.(*ecdsa.PublicKey) - - return publicKey, nil -} - -// AdminSignRegistration signs the registration object. -func AdminSignRegistration(key *ecdsa.PrivateKey, reg Registration) (string, error) { - reg.StandardClaims = jwt.StandardClaims{ - Issuer: "Maze Admin", - IssuedAt: time.Now().Unix(), - NotBefore: time.Now().Unix(), - } - - token := jwt.NewWithClaims(jwt.SigningMethodES384, reg) - signed, err := token.SignedString(key) - if err != nil { - return "", err - } - return signed, nil -} diff --git a/pkg/license/config.go b/pkg/license/config.go deleted file mode 100644 index 3124b09..0000000 --- a/pkg/license/config.go +++ /dev/null @@ -1,25 +0,0 @@ -package license - -import ( - "crypto/ecdsa" - "fmt" -) - -// Run-time configuration variables provided by the application. -const pemSigningKey = `-----BEGIN PUBLIC KEY----- -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEMrqAMHjZ1dPlKwDOsiCSr5N3OSvnYKLM -efe2xD+5hJYrpvparRFnaMbMuqde4M6d6sCCKO8BHtfAzmyiQ/CD38zs9MiDsamy -FDYEEJu+Fqx482I7fIa5ZEE770+wWJ3k ------END PUBLIC KEY-----` - -var Signer *ecdsa.PublicKey - -func init() { - key, err := ParsePublicKeyPEM(pemSigningKey) - if err != nil { - fmt.Printf("license: failed to parse app keys: %s\n", err) - return - } - - Signer = key -} diff --git a/pkg/license/levelsigning/level_signing.go b/pkg/license/levelsigning/level_signing.go deleted file mode 100644 index 82584fe..0000000 --- a/pkg/license/levelsigning/level_signing.go +++ /dev/null @@ -1,193 +0,0 @@ -package levelsigning - -import ( - "crypto/ecdsa" - "crypto/rand" - "crypto/sha256" - "encoding/json" - "fmt" - "io/ioutil" - - "git.kirsle.net/SketchyMaze/doodle/pkg/level" - "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" - "git.kirsle.net/SketchyMaze/doodle/pkg/log" -) - -// IsLevelSigned returns a quick answer. -func IsLevelSigned(lvl *level.Level) bool { - return VerifyLevel(license.Signer, lvl) -} - -// IsLevelPackSigned returns a quick answer. -func IsLevelPackSigned(lp *levelpack.LevelPack) bool { - return VerifyLevelPack(license.Signer, lp) -} - -/* -SignLevel creates a signature on a level file which allows it to load its -embedded doodads even for free versions of the game. - -Free versions will verify a level's signature before bailing out with the -"can't play levels w/ embedded doodads" response. - -NOTE: this only supported Zipfile levels and will assume the level you -pass has a Zipfile to access embedded assets. -*/ -func SignLevel(key *ecdsa.PrivateKey, lvl *level.Level) ([]byte, error) { - // Encode the attached files data to deterministic JSON. - certificate, err := StringifyAssets(lvl) - if err != nil { - return nil, err - } - - log.Info("Sign file tree: %s", certificate) - digest := shasum(certificate) - - signature, err := ecdsa.SignASN1(rand.Reader, key, digest) - if err != nil { - return nil, err - } - log.Info("Digest: %x Signature: %x", digest, signature) - - return signature, nil -} - -// VerifyLevel verifies a level's signature and returns if it is OK. -func VerifyLevel(publicKey *ecdsa.PublicKey, lvl *level.Level) bool { - // No signature = not verified. - if lvl.Signature == nil || len(lvl.Signature) == 0 { - return false - } - - // Encode the attached files data to deterministic JSON. - certificate, err := StringifyAssets(lvl) - if err != nil { - log.Error("VerifyLevel: couldn't stringify assets: %s", err) - return false - } - - digest := shasum(certificate) - - // Verify the signature against our public key. - return ecdsa.VerifyASN1(publicKey, digest, lvl.Signature) -} - -/* -SignLevelpack applies a signature to a levelpack as a whole, to allow its -shared custom doodads to be loaded by its levels in free games. -*/ -func SignLevelPack(key *ecdsa.PrivateKey, lp *levelpack.LevelPack) ([]byte, error) { - // Encode the attached files data to deterministic JSON. - certificate, err := StringifyLevelpackAssets(lp) - if err != nil { - return nil, err - } - - log.Info("Sign file tree: %s", certificate) - digest := shasum(certificate) - - signature, err := ecdsa.SignASN1(rand.Reader, key, digest) - if err != nil { - return nil, err - } - log.Info("Digest: %x Signature: %x", digest, signature) - - return signature, nil -} - -// VerifyLevelPack verifies a levelpack's signature and returns if it is OK. -func VerifyLevelPack(publicKey *ecdsa.PublicKey, lp *levelpack.LevelPack) bool { - // No signature = not verified. - if lp.Signature == nil || len(lp.Signature) == 0 { - return false - } - - // Encode the attached files data to deterministic JSON. - certificate, err := StringifyLevelpackAssets(lp) - if err != nil { - log.Error("VerifyLevelPack: couldn't stringify assets: %s", err) - return false - } - - digest := shasum(certificate) - - // Verify the signature against our public key. - return ecdsa.VerifyASN1(publicKey, digest, lp.Signature) -} - -// StringifyAssets creates the signing checksum of a level's attached assets. -func StringifyAssets(lvl *level.Level) ([]byte, error) { - // Get a listing of all embedded files. Note: gives us a conveniently - // sorted array of files too. - files := lvl.Files.List() - - // Pair each filename with its SHA256 sum. - var checksum = map[string]string{} - for _, filename := range files { - if sum, err := lvl.Files.Checksum(filename); err != nil { - return nil, fmt.Errorf("when checksum %s got error: %s", filename, err) - } else { - checksum[filename] = sum - } - } - - // Encode the payload to deterministic JSON. - certificate, err := json.Marshal(checksum) - if err != nil { - return nil, err - } - - return certificate, nil -} - -// StringifyLevelpackAssets creates the signing checksum of a level's attached assets. -func StringifyLevelpackAssets(lp *levelpack.LevelPack) ([]byte, error) { - var ( - files = []string{} - seen = map[string]struct{}{} - ) - - // Enumerate the files in the zipfile assets/ folder. - for _, file := range lp.Zipfile.File { - if file.Name == "index.json" { - continue - } - - if _, ok := seen[file.Name]; !ok { - files = append(files, file.Name) - seen[file.Name] = struct{}{} - } - } - - // Pair each filename with its SHA256 sum. - var checksum = map[string]string{} - for _, filename := range files { - file, err := lp.Zipfile.Open(filename) - if err != nil { - return nil, err - } - - bin, err := ioutil.ReadAll(file) - if err != nil { - return nil, err - } - - checksum[filename] = fmt.Sprintf("%x", shasum(bin)) - } - - // Encode the payload to deterministic JSON. - certificate, err := json.Marshal(checksum) - if err != nil { - return nil, err - } - - return certificate, nil -} - -// Common function to SHA-256 checksum a thing. -func shasum(data []byte) []byte { - h := sha256.New() - h.Write(data) - return h.Sum(nil) -} diff --git a/pkg/license/license.go b/pkg/license/license.go deleted file mode 100644 index d47103f..0000000 --- a/pkg/license/license.go +++ /dev/null @@ -1,108 +0,0 @@ -// Package license holds functions related to paid product activation. -package license - -import ( - "crypto/ecdsa" - "crypto/x509" - "encoding/pem" - "errors" - "io/ioutil" - "path/filepath" - - "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" - "github.com/dgrijalva/jwt-go" -) - -// Errors -var ( - ErrRegisteredFeature = errors.New("feature not available") -) - -// Registration object encoded into a license key file. -type Registration struct { - Name string `json:"name"` - Email string `json:"email"` - jwt.StandardClaims -} - -// IsRegistered returns a boolean answer: is the product registered? -func IsRegistered() bool { - if _, err := GetRegistration(); err == nil { - return true - } - return false -} - -// GetRegistration returns the currently registered user, by checking -// for the license.key file in the profile folder. -func GetRegistration() (Registration, error) { - if Signer == nil { - return Registration{}, errors.New("signer not ready") - } - - filename := filepath.Join(userdir.ProfileDirectory, "license.key") - jwt, err := ioutil.ReadFile(filename) - if err != nil { - return Registration{}, err - } - - // Check if the JWT is valid. - reg, err := Validate(Signer, string(jwt)) - if err != nil { - return Registration{}, err - } - - return reg, err -} - -// UploadLicenseFile handles the user selecting the license key file, and it is -// validated and ingested. -func UploadLicenseFile(filename string) (Registration, error) { - if Signer == nil { - return Registration{}, errors.New("signer not ready") - } - - jwt, err := ioutil.ReadFile(filename) - if err != nil { - return Registration{}, err - } - - // Check if the JWT is valid. - reg, err := Validate(Signer, string(jwt)) - if err != nil { - return Registration{}, err - } - - // Upload the license to Doodle's profile directory. - outfile := filepath.Join(userdir.ProfileDirectory, "license.key") - if err := ioutil.WriteFile(outfile, jwt, 0644); err != nil { - return Registration{}, err - } - - return reg, nil -} - -// Validate the registration is signed by the appropriate public key. -func Validate(publicKey *ecdsa.PublicKey, tokenString string) (Registration, error) { - var reg Registration - token, err := jwt.ParseWithClaims(tokenString, ®, func(token *jwt.Token) (interface{}, error) { - return publicKey, nil - }) - if err != nil { - return reg, err - } - - if !token.Valid { - return reg, errors.New("token not valid") - } - return reg, nil -} - -// ParsePublicKeyPEM loads a public key from PEM format. -func ParsePublicKeyPEM(keytext string) (*ecdsa.PublicKey, error) { - blockPub, _ := pem.Decode([]byte(keytext)) - x509EncodedPub := blockPub.Bytes - genericPublicKey, _ := x509.ParsePKIXPublicKey(x509EncodedPub) - publicKey := genericPublicKey.(*ecdsa.PublicKey) - return publicKey, nil -} diff --git a/pkg/main_scene.go b/pkg/main_scene.go index ccc94d4..22cca58 100644 --- a/pkg/main_scene.go +++ b/pkg/main_scene.go @@ -6,6 +6,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" "git.kirsle.net/SketchyMaze/doodle/pkg/license" @@ -120,12 +121,8 @@ func (s *MainScene) Setup(d *Doodle) error { s.labelSubtitle.Compute(d.Engine) // Version label. - var shareware string - if !license.IsRegistered() { - shareware = " (shareware)" - } ver := ui.NewLabel(ui.Label{ - Text: fmt.Sprintf("v%s%s", branding.Version, shareware), + Text: builds.Version, Font: balance.TitleScreenVersionFont, }) ver.Compute(d.Engine) @@ -228,7 +225,7 @@ func (s *MainScene) Setup(d *Doodle) error { { Name: "Register", If: func() bool { - return !license.IsRegistered() + return balance.DPP && !license.IsRegistered() }, Func: func() { if s.winRegister == nil { diff --git a/pkg/native/username.go b/pkg/native/username.go index 85d9298..7d7d222 100644 --- a/pkg/native/username.go +++ b/pkg/native/username.go @@ -3,7 +3,7 @@ package native import ( "os" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" ) var USER string = os.Getenv("USER") @@ -18,8 +18,8 @@ Otherwise fall back to their native operating system user. */ func DefaultAuthor() string { // Are we registered? - if license.IsRegistered() { - if reg, err := license.GetRegistration(); err == nil { + if plus.IsRegistered() { + if reg, err := plus.GetRegistration(); err == nil { return reg.Name } } diff --git a/pkg/play_scene.go b/pkg/play_scene.go index b3a8a79..3625916 100644 --- a/pkg/play_scene.go +++ b/pkg/play_scene.go @@ -19,6 +19,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/modal" "git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen" "git.kirsle.net/SketchyMaze/doodle/pkg/physics" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/savegame" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" @@ -503,7 +504,7 @@ func (s *PlayScene) setupPlayer(playerCharacterFilename string) { // centerIn is optional, ignored if zero. func (s *PlayScene) installPlayerDoodad(filename string, spawn render.Point, centerIn render.Rect) { // Load in the player character. - player, err := doodads.LoadFromEmbeddable(filename, s.Level, false) + player, err := plus.DoodadFromEmbeddable(filename, s.Level, false) if err != nil { log.Error("PlayScene.Setup: failed to load player doodad: %s", err) player = doodads.NewDummy(32) diff --git a/pkg/plus/dpp/plus_dpp.go b/pkg/plus/dpp/plus_dpp.go new file mode 100644 index 0000000..31825ee --- /dev/null +++ b/pkg/plus/dpp/plus_dpp.go @@ -0,0 +1,24 @@ +//go:build dpp +// +build dpp + +package plus + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "git.kirsle.net/SketchyMaze/dpp/embedding" + "git.kirsle.net/SketchyMaze/dpp/license" +) + +func DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { + return embedding.LoadFromEmbeddable(filename, fs, force) +} + +func IsRegistered() bool { + return license.IsRegistered() +} + +func GetRegistration() (*Registration, error) { + reg, err := license.GetRegistration() + return reg.(*Registration), err +} diff --git a/pkg/plus/foss/plus_foss.go b/pkg/plus/foss/plus_foss.go new file mode 100644 index 0000000..c4c649e --- /dev/null +++ b/pkg/plus/foss/plus_foss.go @@ -0,0 +1,22 @@ +//go:build !dpp +// +build !dpp + +package plus + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" +) + +// DoodadFromEmbeddable may load a doodad from an embedding filesystem, such as a Level or LevelPack. +func DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { + return doodads.LoadFile(filename) +} + +func IsRegistered() bool { + return false +} + +func GetRegistration() (*Registration, error) { + return nil, ErrNotImplemented +} diff --git a/pkg/plus/initdpp/plus_dpp.go b/pkg/plus/initdpp/plus_dpp.go new file mode 100644 index 0000000..31825ee --- /dev/null +++ b/pkg/plus/initdpp/plus_dpp.go @@ -0,0 +1,24 @@ +//go:build dpp +// +build dpp + +package plus + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "git.kirsle.net/SketchyMaze/dpp/embedding" + "git.kirsle.net/SketchyMaze/dpp/license" +) + +func DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { + return embedding.LoadFromEmbeddable(filename, fs, force) +} + +func IsRegistered() bool { + return license.IsRegistered() +} + +func GetRegistration() (*Registration, error) { + reg, err := license.GetRegistration() + return reg.(*Registration), err +} diff --git a/pkg/plus/initdpp/plus_foss.go b/pkg/plus/initdpp/plus_foss.go new file mode 100644 index 0000000..c4c649e --- /dev/null +++ b/pkg/plus/initdpp/plus_foss.go @@ -0,0 +1,22 @@ +//go:build !dpp +// +build !dpp + +package plus + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" +) + +// DoodadFromEmbeddable may load a doodad from an embedding filesystem, such as a Level or LevelPack. +func DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { + return doodads.LoadFile(filename) +} + +func IsRegistered() bool { + return false +} + +func GetRegistration() (*Registration, error) { + return nil, ErrNotImplemented +} diff --git a/pkg/plus/initdpp/plus_init.go b/pkg/plus/initdpp/plus_init.go new file mode 100644 index 0000000..f5ca1e4 --- /dev/null +++ b/pkg/plus/initdpp/plus_init.go @@ -0,0 +1 @@ +package initdpp diff --git a/pkg/plus/plus.go b/pkg/plus/plus.go new file mode 100644 index 0000000..c7d9491 --- /dev/null +++ b/pkg/plus/plus.go @@ -0,0 +1,23 @@ +// Package plus connects the open source Doodle engine to the Doodle++ feature. +package plus + +import ( + "errors" + + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "github.com/dgrijalva/jwt-go" +) + +var ErrNotImplemented = errors.New("not implemented") + +type Bridge interface { + DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) +} + +// Registration object encoded into a license key file. +type Registration struct { + Name string `json:"name"` + Email string `json:"email"` + jwt.StandardClaims +} diff --git a/pkg/uix/canvas_actors.go b/pkg/uix/canvas_actors.go index 949ceab..965f269 100644 --- a/pkg/uix/canvas_actors.go +++ b/pkg/uix/canvas_actors.go @@ -6,10 +6,10 @@ import ( "sort" "strings" - "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/license/levelsigning" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting/exceptions" "git.kirsle.net/go/render" @@ -44,11 +44,11 @@ func (w *Canvas) InstallActors(actors level.ActorMap) error { var actor = actors[id] // Try loading the doodad from the level's own attached files. - doodad, err := doodads.LoadFromEmbeddable(actor.Filename, w.level, isSigned) + doodad, err := plus.DoodadFromEmbeddable(actor.Filename, w.level, isSigned) if err != nil { // If we have a signed levelpack, try loading from the levelpack. if w.IsSignedLevelPack != nil { - if found, err := doodads.LoadFromEmbeddable(actor.Filename, w.IsSignedLevelPack, true); err == nil { + if found, err := plus.DoodadFromEmbeddable(actor.Filename, w.IsSignedLevelPack, true); err == nil { doodad = found } } diff --git a/pkg/windows/license_key.go b/pkg/windows/license_key.go index 5e670ba..997dfff 100644 --- a/pkg/windows/license_key.go +++ b/pkg/windows/license_key.go @@ -6,6 +6,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" + "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/modal" @@ -51,7 +52,7 @@ func NewLicenseWindow(cfg License) *ui.Window { valueSize = render.NewRect(windowWidth-labelSize.W-4, labelSize.H) isRegistered bool registration license.Registration - summary = "Unregistered (shareware)" + summary = "Unregistered" + builds.VersionSuffix ) // Get our current registration status. diff --git a/pkg/windows/open_level_editor.go b/pkg/windows/open_level_editor.go index d833511..53fa333 100644 --- a/pkg/windows/open_level_editor.go +++ b/pkg/windows/open_level_editor.go @@ -171,9 +171,8 @@ func NewOpenLevelEditor(config OpenLevelEditor) *ui.Window { * Frame for selecting User Doodads ******************/ - // Doodads not shown if we're loading a map to play, nor are they - // available to the free version. - if !config.LoadForPlay && !balance.FreeVersion { + // Doodads not shown if we're loading a map to play. + if !config.LoadForPlay { label2 := ui.NewLabel(ui.Label{ Text: "Doodads", Font: balance.LabelFont,