From 7eb7f6148cdf96011519509adbb8a39f42e9fc6c Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Thu, 18 Apr 2024 20:23:07 -0700 Subject: [PATCH 1/4] 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, From a06787411dc4ea6734ae6bbeb6ebb5d279dd0751 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Thu, 18 Apr 2024 22:12:56 -0700 Subject: [PATCH 2/4] Resolve circular import errors for Doodle++ plugin * pkg/plus/dpp is the main plugin bridge, and defines nothing but an interface that defines the Doodle++ surface area (referring to internal game types such as doodad.Doodad or level.Level), but not their implementations. * dpp.Driver (an interface) is the main API that other parts of the game will call, for example "dpp.Driver.IsLevelSigned()" * plus_dpp.go and plus_foss.go provide the dpp.Driver implementation for their build; with plus_dpp.go generally forwarding function calls directly to the proprietary dpp package and plus_foss.go generally returning false/errors. * The bootstrap package simply assigns the above stub function to dpp.Driver * pkg/plus/bootstrap is a package directly imported by main (in the doodle and doodad programs) and it works around circular dependency issues: this package simply assigns dpp.Driver to the DPP or FOSS version. Miscellaneous fixes: * File->Open in the editor and PlayScene will use the new Open Level window instead of loading the legacy GotoLoadMenu scene. * Deprecated legacy scenes: d.GotoLoadMenu() and d.GotoPlayMenu(). * The doodle-admin program depends on the private dpp package, so can not be compiled in FOSS mode. --- cmd/doodad/main.go | 3 ++ cmd/doodle-admin/command/key.go | 2 +- cmd/doodle-admin/command/sign.go | 2 +- cmd/doodle-admin/command/sign_level.go | 4 +- cmd/doodle-admin/command/verify.go | 2 +- cmd/doodle-admin/command/verify_level.go | 4 +- cmd/doodle/main.go | 3 ++ pkg/branding/builds/builds.go | 4 +- pkg/editor_scene.go | 9 ++-- pkg/editor_ui_doodad.go | 4 +- pkg/editor_ui_menubar.go | 24 +++++++-- pkg/editor_ui_popups.go | 4 +- .../giant_screenshot/giant_screenshot.go | 4 +- .../giant_screenshot/regular_screenshot.go | 4 +- pkg/level/publishing/publishing.go | 7 ++- pkg/main_scene.go | 4 +- pkg/menu_scene.go | 4 ++ pkg/native/username.go | 8 +-- pkg/play_scene.go | 10 ++-- pkg/play_scene_menubar.go | 21 +++++++- pkg/plus/bootstrap/bootstrap_dpp.go | 21 ++++++++ pkg/plus/bootstrap/bootstrap_foss.go | 14 +++++ pkg/plus/dpp/plugin.go | 21 ++++++++ pkg/plus/dpp/plus_dpp.go | 54 +++++++++++++++++-- pkg/plus/dpp/plus_foss.go | 46 ++++++++++++++++ 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 | 12 ++--- pkg/uix/canvas_actors.go | 9 ++-- pkg/windows/license_key.go | 9 ++-- 32 files changed, 253 insertions(+), 129 deletions(-) create mode 100644 pkg/plus/bootstrap/bootstrap_dpp.go create mode 100644 pkg/plus/bootstrap/bootstrap_foss.go create mode 100644 pkg/plus/dpp/plugin.go create mode 100644 pkg/plus/dpp/plus_foss.go delete mode 100644 pkg/plus/foss/plus_foss.go delete mode 100644 pkg/plus/initdpp/plus_dpp.go delete mode 100644 pkg/plus/initdpp/plus_foss.go delete mode 100644 pkg/plus/initdpp/plus_init.go diff --git a/cmd/doodad/main.go b/cmd/doodad/main.go index 01f4754..9d626d5 100644 --- a/cmd/doodad/main.go +++ b/cmd/doodad/main.go @@ -10,6 +10,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/cmd/doodad/commands" "git.kirsle.net/SketchyMaze/doodle/pkg/branding/builds" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/bootstrap" "github.com/urfave/cli/v2" ) @@ -26,6 +27,8 @@ func init() { } func main() { + bootstrap.InitPlugins() + app := cli.NewApp() app.Name = "doodad" app.Usage = "command line interface for Doodle" diff --git a/cmd/doodle-admin/command/key.go b/cmd/doodle-admin/command/key.go index 671728d..4d2382a 100644 --- a/cmd/doodle-admin/command/key.go +++ b/cmd/doodle-admin/command/key.go @@ -1,8 +1,8 @@ package command import ( - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/dpp/license" "github.com/urfave/cli/v2" ) diff --git a/cmd/doodle-admin/command/sign.go b/cmd/doodle-admin/command/sign.go index e14684b..aeb0ed5 100644 --- a/cmd/doodle-admin/command/sign.go +++ b/cmd/doodle-admin/command/sign.go @@ -4,8 +4,8 @@ import ( "fmt" "io/ioutil" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/dpp/license" "github.com/urfave/cli/v2" ) diff --git a/cmd/doodle-admin/command/sign_level.go b/cmd/doodle-admin/command/sign_level.go index c49d0bf..bd7c526 100644 --- a/cmd/doodle-admin/command/sign_level.go +++ b/cmd/doodle-admin/command/sign_level.go @@ -6,8 +6,8 @@ import ( "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/license/levelsigning" + "git.kirsle.net/SketchyMaze/dpp/license" + "git.kirsle.net/SketchyMaze/dpp/license/levelsigning" "github.com/urfave/cli/v2" ) diff --git a/cmd/doodle-admin/command/verify.go b/cmd/doodle-admin/command/verify.go index 8922c9d..ddb9a41 100644 --- a/cmd/doodle-admin/command/verify.go +++ b/cmd/doodle-admin/command/verify.go @@ -4,8 +4,8 @@ import ( "io/ioutil" "time" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/dpp/license" "github.com/urfave/cli/v2" ) diff --git a/cmd/doodle-admin/command/verify_level.go b/cmd/doodle-admin/command/verify_level.go index b7a695b..0a0d24e 100644 --- a/cmd/doodle-admin/command/verify_level.go +++ b/cmd/doodle-admin/command/verify_level.go @@ -5,9 +5,9 @@ import ( "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/license/levelsigning" "git.kirsle.net/SketchyMaze/doodle/pkg/log" + "git.kirsle.net/SketchyMaze/dpp/license" + "git.kirsle.net/SketchyMaze/dpp/license/levelsigning" "github.com/urfave/cli/v2" ) diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index b8e16ca..c1b36c2 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -20,6 +20,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/gamepad" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/native" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/bootstrap" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" "git.kirsle.net/SketchyMaze/doodle/pkg/sound" "git.kirsle.net/SketchyMaze/doodle/pkg/sprites" @@ -51,6 +52,8 @@ func init() { func main() { runtime.LockOSThread() + bootstrap.InitPlugins() + app := cli.NewApp() app.Name = "doodle" app.Usage = fmt.Sprintf("%s - %s", branding.AppName, branding.Summary) diff --git a/pkg/branding/builds/builds.go b/pkg/branding/builds/builds.go index cf2b3d8..d91cd26 100644 --- a/pkg/branding/builds/builds.go +++ b/pkg/branding/builds/builds.go @@ -6,7 +6,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "git.kirsle.net/SketchyMaze/doodle/pkg/branding" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" ) var ( @@ -26,7 +26,7 @@ var ( func init() { if !balance.DPP { VersionSuffix = " (open source)" - } else if !license.IsRegistered() { + } else if !dpp.Driver.IsRegistered() { VersionSuffix = " (shareware)" } else { VersionSuffix = "" diff --git a/pkg/editor_scene.go b/pkg/editor_scene.go index 07cc711..bdb10d7 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -15,16 +15,17 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/level/giant_screenshot" "git.kirsle.net/SketchyMaze/doodle/pkg/level/publishing" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/modal" "git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen" "git.kirsle.net/SketchyMaze/doodle/pkg/native" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/doodle/pkg/usercfg" "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" "git.kirsle.net/SketchyMaze/doodle/pkg/windows" "git.kirsle.net/go/render" "git.kirsle.net/go/render/event" + "git.kirsle.net/go/ui" ) // EditorScene manages the "Edit Level" game mode. @@ -55,6 +56,8 @@ type EditorScene struct { filename string lastAutosaveAt time.Time + + winOpenLevel *ui.Window } // Name of the scene. @@ -252,7 +255,7 @@ func (s *EditorScene) setupAsync(d *Doodle) error { func (s *EditorScene) installActors() error { if err := s.UI.Canvas.InstallActors(s.Level.Actors); err != nil { summary := "This level references some doodads that were not found:" - if strings.Contains(err.Error(), license.ErrRegisteredFeature.Error()) { + if strings.Contains(err.Error(), plus.ErrRegisteredFeature.Error()) { summary = "This level contains embedded doodads, but this is not\n" + "available in the free version of the game. The following\n" + "doodads could not be loaded:" @@ -507,7 +510,7 @@ func (s *EditorScene) LoadLevel(filename string) error { log.Info("Installing %d actors into the drawing", len(level.Actors)) if err := s.UI.Canvas.InstallActors(level.Actors); err != nil { summary := "This level references some doodads that were not found:" - if strings.Contains(err.Error(), license.ErrRegisteredFeature.Error()) { + if strings.Contains(err.Error(), plus.ErrRegisteredFeature.Error()) { summary = "This level contains embedded doodads, but this is not\n" + "available in the free version of the game. The following\n" + "doodads could not be loaded:" diff --git a/pkg/editor_ui_doodad.go b/pkg/editor_ui_doodad.go index f0f3436..7bd7bd6 100644 --- a/pkg/editor_ui_doodad.go +++ b/pkg/editor_ui_doodad.go @@ -9,7 +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/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/uix" "git.kirsle.net/go/render" ) @@ -35,7 +35,7 @@ func (u *EditorUI) startDragActor(doodad *doodads.Doodad, actor *level.Actor) { if doodad == nil { if actor != nil { - obj, err := plus.DoodadFromEmbeddable(actor.Filename, u.Scene.Level, false) + obj, err := dpp.Driver.LoadFromEmbeddable(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 fc3b961..d9f9fe0 100644 --- a/pkg/editor_ui_menubar.go +++ b/pkg/editor_ui_menubar.go @@ -9,10 +9,11 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/drawtool" "git.kirsle.net/SketchyMaze/doodle/pkg/enum" "git.kirsle.net/SketchyMaze/doodle/pkg/level/giant_screenshot" - "git.kirsle.net/SketchyMaze/doodle/pkg/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/modal" "git.kirsle.net/SketchyMaze/doodle/pkg/native" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" + "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" "git.kirsle.net/SketchyMaze/doodle/pkg/userdir" "git.kirsle.net/SketchyMaze/doodle/pkg/windows" "git.kirsle.net/go/render" @@ -282,7 +283,7 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { // Registration item for Doodle++ builds. if balance.DPP { var registerText = "Register" - if license.IsRegistered() { + if dpp.Driver.IsRegistered() { registerText = "Registration" } @@ -318,7 +319,24 @@ func (s *EditorScene) MenuNewDoodad() { // File->Open, or Ctrl-O func (s *EditorScene) MenuOpen() { s.ConfirmUnload(func() { - s.d.GotoLoadMenu() + if s.winOpenLevel == nil { + s.winOpenLevel = windows.NewOpenDrawingWindow(windows.OpenDrawing{ + Supervisor: s.UI.Supervisor, + Engine: shmem.CurrentRenderEngine, + OnOpenDrawing: func(filename string) { + s.d.EditFile(filename) + }, + OnCloseWindow: func() { + s.winOpenLevel.Destroy() + s.winOpenLevel = nil + }, + }) + } + s.winOpenLevel.MoveTo(render.Point{ + X: (s.d.width / 2) - (s.winOpenLevel.Size().W / 2), + Y: (s.d.height / 2) - (s.winOpenLevel.Size().H / 2), + }) + s.winOpenLevel.Show() }) } diff --git a/pkg/editor_ui_popups.go b/pkg/editor_ui_popups.go index ffbe44d..45feaae 100644 --- a/pkg/editor_ui_popups.go +++ b/pkg/editor_ui_popups.go @@ -9,9 +9,9 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/drawtool" "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/modal" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/windows" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" @@ -68,7 +68,7 @@ func (u *EditorUI) OpenPublishWindow() { OnPublish: func(includeBuiltins bool) { u.d.FlashError("OnPublish Called") // XXX: Paid Version Only. - if !license.IsRegistered() { + if !dpp.Driver.IsRegistered() { if u.licenseWindow != nil { u.licenseWindow.Show() u.Supervisor.FocusWindow(u.licenseWindow) diff --git a/pkg/level/giant_screenshot/giant_screenshot.go b/pkg/level/giant_screenshot/giant_screenshot.go index d9c3ed3..e76b439 100644 --- a/pkg/level/giant_screenshot/giant_screenshot.go +++ b/pkg/level/giant_screenshot/giant_screenshot.go @@ -11,7 +11,7 @@ import ( "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/plus/dpp" "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 := plus.DoodadFromEmbeddable(actor.Filename, lvl, false) + doodad, err := dpp.Driver.LoadFromEmbeddable(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 4ece9d7..9c7e994 100644 --- a/pkg/level/giant_screenshot/regular_screenshot.go +++ b/pkg/level/giant_screenshot/regular_screenshot.go @@ -14,7 +14,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/balance" "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/plus/dpp" "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 := plus.DoodadFromEmbeddable(actor.Filename, lvl, false) + doodad, err := dpp.Driver.LoadFromEmbeddable(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 42e5eeb..d31034b 100644 --- a/pkg/level/publishing/publishing.go +++ b/pkg/level/publishing/publishing.go @@ -17,9 +17,8 @@ import ( "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/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" - "git.kirsle.net/SketchyMaze/doodle/pkg/plus" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" ) /* @@ -38,7 +37,7 @@ func Publish(lvl *level.Level) error { } // Registered games only. - if !balance.DPP || !license.IsRegistered() { + if !balance.DPP || !dpp.Driver.IsRegistered() { return errors.New("only registered versions of the game can attach doodads to levels") } @@ -53,7 +52,7 @@ func Publish(lvl *level.Level) error { log.Debug("Embed filename: %s", filename) names[filename] = nil - doodad, err := plus.DoodadFromEmbeddable(filename, lvl, false) + doodad, err := dpp.Driver.LoadFromEmbeddable(filename, lvl, false) if err != nil { return fmt.Errorf("couldn't load doodad %s: %s", filename, err) } diff --git a/pkg/main_scene.go b/pkg/main_scene.go index 22cca58..8666a36 100644 --- a/pkg/main_scene.go +++ b/pkg/main_scene.go @@ -9,10 +9,10 @@ import ( "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" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/modal/loadscreen" "git.kirsle.net/SketchyMaze/doodle/pkg/native" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/savegame" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" @@ -225,7 +225,7 @@ func (s *MainScene) Setup(d *Doodle) error { { Name: "Register", If: func() bool { - return balance.DPP && !license.IsRegistered() + return balance.DPP && !dpp.Driver.IsRegistered() }, Func: func() { if s.winRegister == nil { diff --git a/pkg/menu_scene.go b/pkg/menu_scene.go index 42ba387..a87f924 100644 --- a/pkg/menu_scene.go +++ b/pkg/menu_scene.go @@ -73,6 +73,8 @@ func (d *Doodle) GotoNewDoodadMenu() { } // GotoLoadMenu loads the MenuScene and shows the "Load" window. +// +// DEPRECATED: loads the old menu, in dev console run `$ d.GotoLoadMenu()` to see. func (d *Doodle) GotoLoadMenu() { log.Info("Loading the MenuScene to the Load window for Edit Mode") scene := &MenuScene{ @@ -83,6 +85,8 @@ func (d *Doodle) GotoLoadMenu() { // GotoPlayMenu loads the MenuScene and shows the "Load" window for playing a // level, not editing it. +// +// DEPRECATED: loads the old menu, in dev console run `$ d.GotoPlayMenu()` to see. func (d *Doodle) GotoPlayMenu() { log.Info("Loading the MenuScene to the Load window for Play Mode") scene := &MenuScene{ diff --git a/pkg/native/username.go b/pkg/native/username.go index 7d7d222..2316f58 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/plus" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" ) var USER string = os.Getenv("USER") @@ -17,9 +17,9 @@ If they have registered the game, use the name from their license JWT token. Otherwise fall back to their native operating system user. */ func DefaultAuthor() string { - // Are we registered? - if plus.IsRegistered() { - if reg, err := plus.GetRegistration(); err == nil { + // Are we registered? TODO: get from registration + if dpp.Driver.IsRegistered() { + if reg, err := dpp.Driver.GetRegistration(); err == nil { return reg.Name } } diff --git a/pkg/play_scene.go b/pkg/play_scene.go index 3625916..0c41e9a 100644 --- a/pkg/play_scene.go +++ b/pkg/play_scene.go @@ -13,13 +13,12 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/keybind" "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/license/levelsigning" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "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/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/savegame" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" @@ -63,6 +62,7 @@ type PlayScene struct { menubar *ui.MenuBar editButton *ui.Button winLevelPacks *ui.Window + winOpenLevel *ui.Window // Custom debug labels. debPosition *string @@ -247,7 +247,7 @@ func (s *PlayScene) setupAsync(d *Doodle) error { s.drawing.OnResetTimer = s.ResetTimer // If this level game from a signed LevelPack, inform the canvas. - if s.LevelPack != nil && levelsigning.IsLevelPackSigned(s.LevelPack) { + if s.LevelPack != nil && dpp.Driver.IsLevelPackSigned(s.LevelPack) { s.drawing.IsSignedLevelPack = s.LevelPack } @@ -337,7 +337,7 @@ func (s *PlayScene) setupAsync(d *Doodle) error { func (s *PlayScene) installActors() error { if err := s.drawing.InstallActors(s.Level.Actors); err != nil { summary := "This level references some doodads that were not found:" - if strings.Contains(err.Error(), license.ErrRegisteredFeature.Error()) { + if strings.Contains(err.Error(), plus.ErrRegisteredFeature.Error()) { summary = "This level contains embedded doodads, but this is not\n" + "available in the free version of the game. The following\n" + "doodads could not be loaded:" @@ -504,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 := plus.DoodadFromEmbeddable(filename, s.Level, false) + player, err := dpp.Driver.LoadFromEmbeddable(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/play_scene_menubar.go b/pkg/play_scene_menubar.go index 8cf77f1..a07f85d 100644 --- a/pkg/play_scene_menubar.go +++ b/pkg/play_scene_menubar.go @@ -40,7 +40,26 @@ func (u *PlayScene) setupMenuBar(d *Doodle) *ui.MenuBar { u.winLevelPacks.Show() }) gameMenu.AddItemAccel("New drawing", "Ctrl-N", d.GotoNewMenu) - gameMenu.AddItemAccel("Open drawing", "Ctrl-O", d.GotoLoadMenu) + gameMenu.AddItemAccel("Open drawing", "Ctrl-O", func() { + if u.winOpenLevel == nil { + u.winOpenLevel = windows.NewOpenDrawingWindow(windows.OpenDrawing{ + Supervisor: u.Supervisor, + Engine: shmem.CurrentRenderEngine, + OnOpenDrawing: func(filename string) { + d.EditFile(filename) + }, + OnCloseWindow: func() { + u.winOpenLevel.Destroy() + u.winOpenLevel = nil + }, + }) + } + u.winOpenLevel.MoveTo(render.Point{ + X: (d.width / 2) - (u.winOpenLevel.Size().W / 2), + Y: (d.height / 2) - (u.winOpenLevel.Size().H / 2), + }) + u.winOpenLevel.Show() + }) gameMenu.AddSeparator() gameMenu.AddItem("Quit to menu", func() { diff --git a/pkg/plus/bootstrap/bootstrap_dpp.go b/pkg/plus/bootstrap/bootstrap_dpp.go new file mode 100644 index 0000000..5e6c566 --- /dev/null +++ b/pkg/plus/bootstrap/bootstrap_dpp.go @@ -0,0 +1,21 @@ +//go:build dpp +// +build dpp + +/* +Package bootstrap is a common import between the Doodle and Doodad programs. + +Its chief job is to work around circular dependency issues when dealing with +pluggable parts of the codebase, such as Doodle++ which adds features for the +official release which are missing from the FOSS version. +*/ +package bootstrap + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" +) + +var Driver dpp.Pluggable + +func InitPlugins() { + Driver = dpp.Plugin{} +} diff --git a/pkg/plus/bootstrap/bootstrap_foss.go b/pkg/plus/bootstrap/bootstrap_foss.go new file mode 100644 index 0000000..dd213f1 --- /dev/null +++ b/pkg/plus/bootstrap/bootstrap_foss.go @@ -0,0 +1,14 @@ +//go:build !dpp +// +build !dpp + +package bootstrap + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" +) + +var Driver dpp.Pluggable + +func InitPlugins() { + Driver = dpp.Plugin{} +} diff --git a/pkg/plus/dpp/plugin.go b/pkg/plus/dpp/plugin.go new file mode 100644 index 0000000..606d883 --- /dev/null +++ b/pkg/plus/dpp/plugin.go @@ -0,0 +1,21 @@ +package dpp + +import ( + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "git.kirsle.net/SketchyMaze/doodle/pkg/level" + "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" +) + +var Driver Pluggable + +// Plugin +type Pluggable interface { + LoadFromEmbeddable(string, filesystem.Embeddable, bool) (*doodads.Doodad, error) + IsRegistered() bool + GetRegistration() (plus.Registration, error) + UploadLicenseFile(string) (plus.Registration, error) + IsLevelSigned(*level.Level) bool + IsLevelPackSigned(*levelpack.LevelPack) bool +} diff --git a/pkg/plus/dpp/plus_dpp.go b/pkg/plus/dpp/plus_dpp.go index 31825ee..9a3a69b 100644 --- a/pkg/plus/dpp/plus_dpp.go +++ b/pkg/plus/dpp/plus_dpp.go @@ -1,24 +1,68 @@ //go:build dpp // +build dpp -package plus +package dpp import ( + "encoding/json" + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "git.kirsle.net/SketchyMaze/doodle/pkg/level" + "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/dpp/embedding" "git.kirsle.net/SketchyMaze/dpp/license" + "git.kirsle.net/SketchyMaze/dpp/license/levelsigning" ) -func DoodadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { +type Plugin struct{} + +func (Plugin) LoadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { return embedding.LoadFromEmbeddable(filename, fs, force) } -func IsRegistered() bool { +func (Plugin) IsRegistered() bool { return license.IsRegistered() } -func GetRegistration() (*Registration, error) { +func (Plugin) GetRegistration() (plus.Registration, error) { reg, err := license.GetRegistration() - return reg.(*Registration), err + if err != nil { + return plus.Registration{}, err + } + + return translateLicenseStruct(reg) +} + +func (Plugin) UploadLicenseFile(filename string) (plus.Registration, error) { + reg, err := license.UploadLicenseFile(filename) + if err != nil { + return plus.Registration{}, err + } + + return translateLicenseStruct(reg) +} + +// Hack: to translate JWT token types, easiest is to just encode/decode them (inner jwt.StandardClaims complexity). +func translateLicenseStruct(reg license.Registration) (plus.Registration, error) { + jsonStr, err := json.Marshal(reg) + if err != nil { + return plus.Registration{}, err + } + var result plus.Registration + err = json.Unmarshal(jsonStr, &result) + return result, err +} + +func (Plugin) IsLevelPackSigned(lp *levelpack.LevelPack) bool { + return levelsigning.IsLevelPackSigned(lp) +} + +func (Plugin) IsLevelSigned(lvl *level.Level) bool { + return levelsigning.IsLevelSigned(lvl) +} + +func init() { + Driver = Plugin{} } diff --git a/pkg/plus/dpp/plus_foss.go b/pkg/plus/dpp/plus_foss.go new file mode 100644 index 0000000..0a00b2d --- /dev/null +++ b/pkg/plus/dpp/plus_foss.go @@ -0,0 +1,46 @@ +//go:build !dpp +// +build !dpp + +package dpp + +import ( + "errors" + + "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" + "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" + "git.kirsle.net/SketchyMaze/doodle/pkg/level" + "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" +) + +var ErrNotImplemented = errors.New("not implemented") + +type Plugin struct{} + +func (Plugin) LoadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { + return doodads.LoadFile(filename) +} + +func (Plugin) IsRegistered() bool { + return false +} + +func (Plugin) GetRegistration() (plus.Registration, error) { + return plus.Registration{}, ErrNotImplemented +} + +func (Plugin) UploadLicenseFile(string) (plus.Registration, error) { + return plus.Registration{}, ErrNotImplemented +} + +func (Plugin) IsLevelPackSigned(*levelpack.LevelPack) bool { + return false +} + +func (Plugin) IsLevelSigned(*level.Level) bool { + return false +} + +func init() { + Driver = Plugin{} +} diff --git a/pkg/plus/foss/plus_foss.go b/pkg/plus/foss/plus_foss.go deleted file mode 100644 index c4c649e..0000000 --- a/pkg/plus/foss/plus_foss.go +++ /dev/null @@ -1,22 +0,0 @@ -//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 deleted file mode 100644 index 31825ee..0000000 --- a/pkg/plus/initdpp/plus_dpp.go +++ /dev/null @@ -1,24 +0,0 @@ -//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 deleted file mode 100644 index c4c649e..0000000 --- a/pkg/plus/initdpp/plus_foss.go +++ /dev/null @@ -1,22 +0,0 @@ -//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 deleted file mode 100644 index f5ca1e4..0000000 --- a/pkg/plus/initdpp/plus_init.go +++ /dev/null @@ -1 +0,0 @@ -package initdpp diff --git a/pkg/plus/plus.go b/pkg/plus/plus.go index c7d9491..05de27c 100644 --- a/pkg/plus/plus.go +++ b/pkg/plus/plus.go @@ -4,16 +4,14 @@ 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) -} +// Errors +var ( + ErrNotImplemented = errors.New("not implemented") + ErrRegisteredFeature = errors.New("feature not available") +) // Registration object encoded into a license key file. type Registration struct { diff --git a/pkg/uix/canvas_actors.go b/pkg/uix/canvas_actors.go index 965f269..c9c6ed1 100644 --- a/pkg/uix/canvas_actors.go +++ b/pkg/uix/canvas_actors.go @@ -7,9 +7,8 @@ import ( "strings" "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/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting" "git.kirsle.net/SketchyMaze/doodle/pkg/scripting/exceptions" "git.kirsle.net/go/render" @@ -37,18 +36,18 @@ func (w *Canvas) InstallActors(actors level.ActorMap) error { // Signed Levels: the free version normally won't load embedded assets from // a level and the call to LoadFromEmbeddable below returns the error. If the // level is signed it is allowed to use its embedded assets. - isSigned := w.IsSignedLevelPack != nil || levelsigning.IsLevelSigned(w.level) + isSigned := w.IsSignedLevelPack != nil || dpp.Driver.IsLevelSigned(w.level) w.actors = make([]*Actor, 0) for _, id := range actorIDs { var actor = actors[id] // Try loading the doodad from the level's own attached files. - doodad, err := plus.DoodadFromEmbeddable(actor.Filename, w.level, isSigned) + doodad, err := dpp.Driver.LoadFromEmbeddable(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 := plus.DoodadFromEmbeddable(actor.Filename, w.IsSignedLevelPack, true); err == nil { + if found, err := dpp.Driver.LoadFromEmbeddable(actor.Filename, w.IsSignedLevelPack, true); err == nil { doodad = found } } diff --git a/pkg/windows/license_key.go b/pkg/windows/license_key.go index 997dfff..9ff5c9a 100644 --- a/pkg/windows/license_key.go +++ b/pkg/windows/license_key.go @@ -7,10 +7,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/license" "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/modal" "git.kirsle.net/SketchyMaze/doodle/pkg/native" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" "git.kirsle.net/go/ui/style" @@ -51,12 +52,12 @@ func NewLicenseWindow(cfg License) *ui.Window { labelSize = render.NewRect(100, 16) valueSize = render.NewRect(windowWidth-labelSize.W-4, labelSize.H) isRegistered bool - registration license.Registration + registration plus.Registration summary = "Unregistered" + builds.VersionSuffix ) // Get our current registration status. - if reg, err := license.GetRegistration(); err == nil { + if reg, err := dpp.Driver.GetRegistration(); err == nil { isRegistered = true registration = reg windowHeight = 200 @@ -141,7 +142,7 @@ func NewLicenseWindow(cfg License) *ui.Window { } // Upload and validate the license key. - reg, err := license.UploadLicenseFile(filename) + reg, err := dpp.Driver.UploadLicenseFile(filename) if err != nil { modal.Alert("That license key didn't seem quite right.").WithTitle("License Error") return From a79601f983b85995506769a5bbbdefaf17831e1d Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Thu, 18 Apr 2024 22:31:11 -0700 Subject: [PATCH 3/4] D++ Default Author and Embedded Doodads Error * Update native.DefaultAuthor to get the name registered from the user's JWT license in a way that avoids cyclic dependency errors. * When plus_dpp.go#GetRegistration succeeds, it updates DefaultAuthor to the registered name. The main.go now gets and prints the registered owner to ensure this is populated on startup. * Return correct ErrRegisteredFeature error when the FOSS version fails to load embedded doodads. --- cmd/doodad/commands/convert.go | 4 ++-- cmd/doodle/main.go | 6 ++++++ pkg/editor_scene.go | 4 ++-- pkg/level/types.go | 2 +- pkg/native/username.go | 27 ++++----------------------- pkg/plus/dpp/plus_dpp.go | 13 +++++++++++-- pkg/plus/dpp/plus_foss.go | 6 +++++- 7 files changed, 31 insertions(+), 31 deletions(-) diff --git a/cmd/doodad/commands/convert.go b/cmd/doodad/commands/convert.go index b2ad7cf..75873c4 100644 --- a/cmd/doodad/commands/convert.go +++ b/cmd/doodad/commands/convert.go @@ -155,7 +155,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou if doodad.Title == "" { doodad.Title = "Converted Doodad" } - doodad.Author = native.DefaultAuthor() + doodad.Author = native.DefaultAuthor // Write the first layer and gather its palette. log.Info("Converting first layer to drawing and getting the palette") @@ -195,7 +195,7 @@ func imageToDrawing(c *cli.Context, chroma render.Color, inputFiles []string, ou if lvl.Title == "" { lvl.Title = "Converted Level" } - lvl.Author = native.DefaultAuthor() + lvl.Author = native.DefaultAuthor palette, chunker := imageToChunker(images[0], chroma, nil, lvl.Chunker.Size) lvl.Palette = palette lvl.Chunker = chunker diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index c1b36c2..9f4082d 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -21,6 +21,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/log" "git.kirsle.net/SketchyMaze/doodle/pkg/native" "git.kirsle.net/SketchyMaze/doodle/pkg/plus/bootstrap" + "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" "git.kirsle.net/SketchyMaze/doodle/pkg/shmem" "git.kirsle.net/SketchyMaze/doodle/pkg/sound" "git.kirsle.net/SketchyMaze/doodle/pkg/sprites" @@ -118,6 +119,11 @@ func main() { app.Action = func(c *cli.Context) error { log.Info("Starting %s %s", app.Name, app.Version) + // Print registration information, + also this sets the DefaultAuthor field. + if reg, err := dpp.Driver.GetRegistration(); err == nil { + log.Info("Registered to %s", reg.Name) + } + // --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/editor_scene.go b/pkg/editor_scene.go index bdb10d7..d69e82d 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -539,7 +539,7 @@ func (s *EditorScene) SaveLevel(filename string) error { m.Title = "Alpha" } if m.Author == "" { - m.Author = native.DefaultAuthor() + m.Author = native.DefaultAuthor } m.Palette = s.UI.Canvas.Palette @@ -641,7 +641,7 @@ func (s *EditorScene) SaveDoodad(filename string) error { d.Title = "Untitled Doodad" } if d.Author == "" { - d.Author = native.DefaultAuthor() + d.Author = native.DefaultAuthor } // TODO: is this copying necessary? diff --git a/pkg/level/types.go b/pkg/level/types.go index e32b536..efece3b 100644 --- a/pkg/level/types.go +++ b/pkg/level/types.go @@ -91,7 +91,7 @@ func New() *Level { Base: Base{ Version: 1, Title: "Untitled", - Author: native.DefaultAuthor(), + Author: native.DefaultAuthor, Files: NewFileSystem(), }, Chunker: NewChunker(balance.ChunkSize), diff --git a/pkg/native/username.go b/pkg/native/username.go index 2316f58..30150ca 100644 --- a/pkg/native/username.go +++ b/pkg/native/username.go @@ -2,28 +2,9 @@ package native import ( "os" - - "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" ) -var USER string = os.Getenv("USER") - -/* -DefaultAuthor will return the local user's name to be the default Author -for levels and doodads they create. - -If they have registered the game, use the name from their license JWT token. - -Otherwise fall back to their native operating system user. -*/ -func DefaultAuthor() string { - // Are we registered? TODO: get from registration - if dpp.Driver.IsRegistered() { - if reg, err := dpp.Driver.GetRegistration(); err == nil { - return reg.Name - } - } - - // Return OS username - return os.Getenv("USER") -} +var ( + USER string = os.Getenv("USER") + DefaultAuthor = USER +) diff --git a/pkg/plus/dpp/plus_dpp.go b/pkg/plus/dpp/plus_dpp.go index 9a3a69b..9bc4bc4 100644 --- a/pkg/plus/dpp/plus_dpp.go +++ b/pkg/plus/dpp/plus_dpp.go @@ -10,6 +10,7 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" "git.kirsle.net/SketchyMaze/doodle/pkg/level" "git.kirsle.net/SketchyMaze/doodle/pkg/levelpack" + "git.kirsle.net/SketchyMaze/doodle/pkg/native" "git.kirsle.net/SketchyMaze/doodle/pkg/plus" "git.kirsle.net/SketchyMaze/dpp/embedding" "git.kirsle.net/SketchyMaze/dpp/license" @@ -46,11 +47,19 @@ func (Plugin) UploadLicenseFile(filename string) (plus.Registration, error) { // Hack: to translate JWT token types, easiest is to just encode/decode them (inner jwt.StandardClaims complexity). func translateLicenseStruct(reg license.Registration) (plus.Registration, error) { - jsonStr, err := json.Marshal(reg) + // Set the DefaultAuthor to the registered user's name. + if reg.Name != "" { + native.DefaultAuthor = reg.Name + } + + // Marshal to JSON and back to cast the type. + var ( + result plus.Registration + jsonStr, err = json.Marshal(reg) + ) if err != nil { return plus.Registration{}, err } - var result plus.Registration err = json.Unmarshal(jsonStr, &result) return result, err } diff --git a/pkg/plus/dpp/plus_foss.go b/pkg/plus/dpp/plus_foss.go index 0a00b2d..f122399 100644 --- a/pkg/plus/dpp/plus_foss.go +++ b/pkg/plus/dpp/plus_foss.go @@ -18,7 +18,11 @@ var ErrNotImplemented = errors.New("not implemented") type Plugin struct{} func (Plugin) LoadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { - return doodads.LoadFile(filename) + if result, err := doodads.LoadFile(filename); err != nil { + return nil, plus.ErrRegisteredFeature + } else { + return result, nil + } } func (Plugin) IsRegistered() bool { From 33dc17bb19b071271cb9afec7a2b503478b6b792 Mon Sep 17 00:00:00 2001 From: Noah Petherbridge Date: Thu, 18 Apr 2024 22:49:12 -0700 Subject: [PATCH 4/4] Doodle++ Code Cleanup --- pkg/branding/builds/builds.go | 2 +- pkg/editor_ui_menubar.go | 8 +++++--- .../bootstrap/{bootstrap_dpp.go => bootstrap.go} | 3 --- pkg/plus/bootstrap/bootstrap_foss.go | 14 -------------- pkg/plus/dpp/plugin.go | 5 ++++- pkg/plus/dpp/plus_foss.go | 8 ++------ 6 files changed, 12 insertions(+), 28 deletions(-) rename pkg/plus/bootstrap/{bootstrap_dpp.go => bootstrap.go} (93%) delete mode 100644 pkg/plus/bootstrap/bootstrap_foss.go diff --git a/pkg/branding/builds/builds.go b/pkg/branding/builds/builds.go index d91cd26..d481df1 100644 --- a/pkg/branding/builds/builds.go +++ b/pkg/branding/builds/builds.go @@ -29,7 +29,7 @@ func init() { } else if !dpp.Driver.IsRegistered() { VersionSuffix = " (shareware)" } else { - VersionSuffix = "" + VersionSuffix = " (registered)" } Version = fmt.Sprintf("v%s%s", branding.Version, VersionSuffix) diff --git a/pkg/editor_ui_menubar.go b/pkg/editor_ui_menubar.go index d9f9fe0..9ddae37 100644 --- a/pkg/editor_ui_menubar.go +++ b/pkg/editor_ui_menubar.go @@ -112,9 +112,11 @@ func (u *EditorUI) SetupMenuBar(d *Doodle) *ui.MenuBar { levelMenu.AddItemAccel("Playtest", "P", func() { u.Scene.Playtest() }) - levelMenu.AddItem("Publish", func() { - u.OpenPublishWindow() - }) + if balance.DPP { + levelMenu.AddItem("Publish", func() { + u.OpenPublishWindow() + }) + } levelMenu.AddSeparator() levelMenu.AddItem("Screenshot", func() { diff --git a/pkg/plus/bootstrap/bootstrap_dpp.go b/pkg/plus/bootstrap/bootstrap.go similarity index 93% rename from pkg/plus/bootstrap/bootstrap_dpp.go rename to pkg/plus/bootstrap/bootstrap.go index 5e6c566..066a339 100644 --- a/pkg/plus/bootstrap/bootstrap_dpp.go +++ b/pkg/plus/bootstrap/bootstrap.go @@ -1,6 +1,3 @@ -//go:build dpp -// +build dpp - /* Package bootstrap is a common import between the Doodle and Doodad programs. diff --git a/pkg/plus/bootstrap/bootstrap_foss.go b/pkg/plus/bootstrap/bootstrap_foss.go deleted file mode 100644 index dd213f1..0000000 --- a/pkg/plus/bootstrap/bootstrap_foss.go +++ /dev/null @@ -1,14 +0,0 @@ -//go:build !dpp -// +build !dpp - -package bootstrap - -import ( - "git.kirsle.net/SketchyMaze/doodle/pkg/plus/dpp" -) - -var Driver dpp.Pluggable - -func InitPlugins() { - Driver = dpp.Plugin{} -} diff --git a/pkg/plus/dpp/plugin.go b/pkg/plus/dpp/plugin.go index 606d883..ebb2e14 100644 --- a/pkg/plus/dpp/plugin.go +++ b/pkg/plus/dpp/plugin.go @@ -8,9 +8,12 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/plus" ) +// Driver is the currently installed Doodle++ implementation (FOSS or DPP). var Driver Pluggable -// Plugin +// Pluggable defines the interface for Doodle++ functions, so that their implementations +// can avoid cyclic dependency errors. Documentation for these functions is only spelled +// out in the SketchyMaze/dpp package. type Pluggable interface { LoadFromEmbeddable(string, filesystem.Embeddable, bool) (*doodads.Doodad, error) IsRegistered() bool diff --git a/pkg/plus/dpp/plus_foss.go b/pkg/plus/dpp/plus_foss.go index f122399..87ddfa9 100644 --- a/pkg/plus/dpp/plus_foss.go +++ b/pkg/plus/dpp/plus_foss.go @@ -4,8 +4,6 @@ package dpp import ( - "errors" - "git.kirsle.net/SketchyMaze/doodle/pkg/doodads" "git.kirsle.net/SketchyMaze/doodle/pkg/filesystem" "git.kirsle.net/SketchyMaze/doodle/pkg/level" @@ -13,8 +11,6 @@ import ( "git.kirsle.net/SketchyMaze/doodle/pkg/plus" ) -var ErrNotImplemented = errors.New("not implemented") - type Plugin struct{} func (Plugin) LoadFromEmbeddable(filename string, fs filesystem.Embeddable, force bool) (*doodads.Doodad, error) { @@ -30,11 +26,11 @@ func (Plugin) IsRegistered() bool { } func (Plugin) GetRegistration() (plus.Registration, error) { - return plus.Registration{}, ErrNotImplemented + return plus.Registration{}, plus.ErrNotImplemented } func (Plugin) UploadLicenseFile(string) (plus.Registration, error) { - return plus.Registration{}, ErrNotImplemented + return plus.Registration{}, plus.ErrNotImplemented } func (Plugin) IsLevelPackSigned(*levelpack.LevelPack) bool {