Compare commits
21
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
208875264f | ||
|
|
8c21400bb1 | ||
|
|
e83521a34a | ||
|
|
3f5584d062 | ||
|
|
6ce72aa1ec | ||
|
|
9ee2b0b05c | ||
|
|
99dacd7a75 | ||
|
|
5447383f2b | ||
|
|
6745d027fb | ||
|
|
e7dd01371e | ||
|
|
68802195b6 | ||
|
|
7cba364aed | ||
|
|
35e9849cae | ||
|
|
f21d455d68 | ||
|
|
d1a16d8208 | ||
|
|
2a1826f876 | ||
|
|
3af2d5d977 | ||
|
|
b61a1656ad | ||
|
|
0fbf22a090 | ||
|
|
5e763aa73c | ||
|
|
6093ca9d8b |
@@ -5,4 +5,3 @@ site
|
||||
exports
|
||||
**/.aego
|
||||
*.test
|
||||
.claude
|
||||
|
||||
@@ -3,7 +3,6 @@ name: ci
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
tags: ["v*"]
|
||||
pull_request:
|
||||
|
||||
permissions:
|
||||
@@ -112,39 +111,4 @@ jobs:
|
||||
- name: example project
|
||||
run: |
|
||||
/tmp/aego check examples/native-rotator
|
||||
/tmp/aego run examples/native-rotator --headless --frames 60
|
||||
|
||||
release:
|
||||
needs: [checks, build]
|
||||
if: github.event_name == 'push'
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
contents: write
|
||||
env:
|
||||
CGO_ENABLED: "1"
|
||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITEA_API: ${{ github.server_url }}/api/v1/repos/${{ github.repository }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
- name: linux packages
|
||||
run: sudo apt-get update && sudo apt-get install -y $LINUX_PKGS
|
||||
- uses: actions/cache@v4
|
||||
continue-on-error: true
|
||||
with:
|
||||
path: .cache/native
|
||||
key: native-linux_amd64-${{ hashFiles('third_party/sdl/version.txt', 'tools/bootstrap-native.sh') }}
|
||||
- run: bash tools/bootstrap-native.sh
|
||||
- name: windows tools
|
||||
run: sudo apt-get install -y mingw-w64 nsis zip
|
||||
- name: publish
|
||||
env:
|
||||
REQUIRE_WINDOWS: "1"
|
||||
GITEA_RESOLVE: git.akarpov.ru:443:79.142.92.250
|
||||
run: |
|
||||
case "$GITHUB_REF" in
|
||||
refs/tags/v*) sh tools/release/release.sh "$GITHUB_REF_NAME" ;;
|
||||
refs/heads/master) sh tools/release/release.sh nightly ;;
|
||||
esac
|
||||
/tmp/aego run examples/native-rotator --headless --frames 60
|
||||
+4
-107
File diff suppressed because one or more lines are too long
@@ -38,7 +38,7 @@ BENCH_PHYSICS_PKGS :=
|
||||
.DEFAULT_GOAL := bootstrap
|
||||
-include modules/*/module.mk
|
||||
|
||||
.PHONY: bootstrap build test test-nonative test-editor test-runtime test-gl vet lint depcheck smoke run genfont genicons icons icons-doc res genpreviews golden golden-update site-headless bench bench-baseline bench-scripts bench-build bench-compare bench-profile bench-scripts-run bench-allocs playground playground-size site site-check cli example example-platformer check-all ci clean fuzz runtime export-smoke editor-app shaders test-wasm web-smoke web-smoke-update try-size shots shots-check
|
||||
.PHONY: bootstrap build test test-nonative test-editor test-runtime test-gl vet lint depcheck smoke run genfont genicons icons icons-doc res genpreviews golden golden-update site-headless bench bench-baseline bench-scripts bench-build bench-compare bench-profile bench-scripts-run bench-allocs playground playground-size site site-check cli example example-platformer check-all ci clean fuzz runtime export-smoke editor-app shaders test-wasm web-smoke web-smoke-update try-size
|
||||
|
||||
XVFB := $(shell command -v xvfb-run 2>/dev/null)
|
||||
GL_OVERRIDE = MESA_GL_VERSION_OVERRIDE=3.3 MESA_GLSL_VERSION_OVERRIDE=330
|
||||
@@ -98,7 +98,6 @@ vet: bootstrap
|
||||
|
||||
lint: bootstrap
|
||||
go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) $(LINT_PKGS)
|
||||
go run honnef.co/go/tools/cmd/staticcheck@$(STATICCHECK_VERSION) -tags aego_editor ./editor/... ./app/... ./tests/...
|
||||
|
||||
# All graph variants, the semantic pass and the negative rule tests.
|
||||
depcheck:
|
||||
@@ -212,7 +211,7 @@ site: cli
|
||||
@$(TRY_SIZE_CHECK)
|
||||
|
||||
playground:
|
||||
@if GOOS=js GOARCH=wasm go list -deps ./cmd/aego-playground | grep -E '^aego/(platform/sdl|gpu/gl33|asset/pipeline|asset/importers)'; then echo "playground graph pulls a native or pipeline package"; exit 1; fi
|
||||
@if GOOS=js GOARCH=wasm go list -deps ./cmd/aego-playground | grep -E '^aego/(platform/sdl|gpu/gl33|asset/pipeline|asset/importers|modules/render3d)'; then echo "playground graph pulls a native or pipeline package"; exit 1; fi
|
||||
$(MAKE) site
|
||||
|
||||
site-headless:
|
||||
@@ -282,29 +281,7 @@ fuzz:
|
||||
go test -run '^$$' -fuzz '^FuzzDecodeVerify$$' -fuzztime $(FUZZTIME) ./script/verify
|
||||
go test -run '^$$' -fuzz '^FuzzDecodeVerifyV3$$' -fuzztime $(FUZZTIME) ./script/verify
|
||||
|
||||
ci: build vet lint depcheck test test-nonative test-editor test-runtime test-wasm runtime smoke fuzz golden shots-check test-gl cli playground web-smoke site-check example example-platformer check-all export-smoke $(MODULE_CI) bench-allocs
|
||||
|
||||
|
||||
# Documentation screenshots of the real editor on the platformer example, under a clean user profile.
|
||||
SHOTS_TMP = $(CURDIR)/.cache/shots
|
||||
ifneq ($(XVFB),)
|
||||
SHOTS_ENV = $(XVFB) -a -s "-screen 0 1600x900x24" env SDL_VIDEODRIVER=x11 LIBGL_ALWAYS_SOFTWARE=1 GALLIUM_DRIVER=llvmpipe $(GL_OVERRIDE)
|
||||
else
|
||||
SHOTS_ENV = $(GL_ENV)
|
||||
endif
|
||||
SHOTS_RUN = rm -rf $(SHOTS_TMP)/project $(SHOTS_TMP)/home && mkdir -p $(SHOTS_TMP)/home && cp -R examples/platformer $(SHOTS_TMP)/project && \
|
||||
rm -rf $(SHOTS_TMP)/project/.aego $(SHOTS_TMP)/project/exports && \
|
||||
sed -i.bak 's|=> ../..|=> $(CURDIR)|' $(SHOTS_TMP)/project/go.mod && \
|
||||
XDG_CONFIG_HOME=$(SHOTS_TMP)/home XDG_DATA_HOME=$(SHOTS_TMP)/home $(SHOTS_ENV) env AEGO_SHOTS=$(1) .cache/bin/aego edit $(SHOTS_TMP)/project --hidden
|
||||
|
||||
shots: cli
|
||||
rm -rf docs/shots
|
||||
$(call SHOTS_RUN,$(CURDIR)/docs/shots)
|
||||
|
||||
shots-check: cli
|
||||
rm -rf $(SHOTS_TMP)/out
|
||||
$(call SHOTS_RUN,$(SHOTS_TMP)/out)
|
||||
go run ./tools/shotdiff -want docs/shots -got $(SHOTS_TMP)/out
|
||||
ci: build vet lint depcheck test test-nonative test-editor test-runtime test-wasm runtime smoke fuzz golden test-gl cli playground web-smoke site-check example example-platformer check-all export-smoke $(MODULE_CI) bench-allocs
|
||||
|
||||
runtime: bootstrap
|
||||
go build -tags aego_runtime -o .cache/bin/aego-runtime ./cmd/aego-runtime
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,85 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func mustFind(t *testing.T, name string) *Command {
|
||||
t.Helper()
|
||||
c, ok := Find(name)
|
||||
if !ok {
|
||||
t.Fatalf("no command %s", name)
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
func TestParseArgs(t *testing.T) {
|
||||
set := mustFind(t, "scene.set")
|
||||
a, f, err := parseArgs(set, []string{"s.aescene", "--json", "Player", "--dry-run", "Body2D.mass", "-3"})
|
||||
if err != nil || !f.json || a.Str("value") != "-3" || a.Str("node") != "Player" || !a.Bool("dry-run") {
|
||||
t.Fatalf("flags after positionals: %v %+v %v", a, f, err)
|
||||
}
|
||||
add := mustFind(t, "scene.add-node")
|
||||
for _, toks := range [][]string{{"s", "N", "--index=1"}, {"s", "N", "--index", "1"}} {
|
||||
a, _, err := parseArgs(add, toks)
|
||||
if n, _ := a.Int("index", -1); err != nil || n != 1 {
|
||||
t.Fatalf("%v: %v %v", toks, a, err)
|
||||
}
|
||||
}
|
||||
a, _, err = parseArgs(set, []string{"s", "--", "Player", "Body2D.mass", "--odd"})
|
||||
if err != nil || a.Str("value") != "--odd" {
|
||||
t.Fatalf("after --: %v %v", a, err)
|
||||
}
|
||||
if _, _, err := parseArgs(set, []string{"s", "--nope"}); err == nil {
|
||||
t.Fatal("an unknown flag was accepted")
|
||||
}
|
||||
if _, _, err := parseArgs(set, []string{"s", "a", "b", "c", "d"}); err == nil {
|
||||
t.Fatal("an extra positional was accepted")
|
||||
}
|
||||
var out, errw bytes.Buffer
|
||||
if code := Main(nil, []string{"scene", "set", "s", "--nope"}, &out, &errw, Options{}); code != 2 {
|
||||
t.Fatalf("unknown flag exit %d", code)
|
||||
}
|
||||
if code := Main(nil, []string{"scene", "set", "a", "b", "c", "d", "e"}, &out, &errw, Options{}); code != 2 {
|
||||
t.Fatalf("extra positional exit %d", code)
|
||||
}
|
||||
if code := Main(nil, []string{"scene", "help"}, &out, &errw, Options{}); code != 0 {
|
||||
t.Fatalf("help exit %d", code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSchemasAndToolNames(t *testing.T) {
|
||||
seen := map[string]bool{}
|
||||
for _, c := range Commands() {
|
||||
if seen[c.Tool()] {
|
||||
t.Fatalf("tool name %s is used twice", c.Tool())
|
||||
}
|
||||
seen[c.Tool()] = true
|
||||
b, err := json.Marshal(c.Schema())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var sch struct {
|
||||
Type string `json:"type"`
|
||||
Properties map[string]map[string]any `json:"properties"`
|
||||
Required []string `json:"required"`
|
||||
}
|
||||
if err := json.Unmarshal(b, &sch); err != nil || sch.Type != "object" {
|
||||
t.Fatalf("%s: %s", c.Name, b)
|
||||
}
|
||||
var want []string
|
||||
for _, x := range c.AllArgs() {
|
||||
if x.Required {
|
||||
want = append(want, x.Name)
|
||||
}
|
||||
if _, ok := sch.Properties[x.Name]; !ok {
|
||||
t.Fatalf("%s: no property %s", c.Name, x.Name)
|
||||
}
|
||||
}
|
||||
if len(want) != len(sch.Required) {
|
||||
t.Fatalf("%s: required %v, want %v", c.Name, sch.Required, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,66 +0,0 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"aego/asset"
|
||||
"aego/project/refs"
|
||||
"aego/scene/mutate"
|
||||
)
|
||||
|
||||
func projectCommands() []*Command {
|
||||
return []*Command{
|
||||
{Name: "project.validate", Doc: "missing assets and nodes, import errors, prefabs and scenes that do not load", Run: (*Session).projectValidate},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Session) projectValidate(Args) (*Output, error) {
|
||||
out := &Output{}
|
||||
add := func(err bool, node, msg string) {
|
||||
out.Problems = append(out.Problems, mutate.Problem{Error: err, Node: node, Message: msg})
|
||||
}
|
||||
for _, m := range refs.MissingAssets(s.Project, s.Pipeline) {
|
||||
add(true, "", "missing asset "+m.Label())
|
||||
}
|
||||
for _, m := range refs.MissingNodes(s.Pipeline) {
|
||||
add(true, m.Scene+" "+m.Path, m.Owner+"."+m.Field+" references a node that is not in the scene")
|
||||
}
|
||||
if s.scriptErr != nil {
|
||||
add(true, "", "script types: "+s.scriptErr.Error())
|
||||
}
|
||||
for _, e := range s.libErrs {
|
||||
add(true, "", e.Error())
|
||||
}
|
||||
for _, x := range s.Pipeline.Assets() {
|
||||
if x.Error != "" {
|
||||
add(true, x.Path, x.Error)
|
||||
continue
|
||||
}
|
||||
if x.Kind != asset.ArtScene && x.Kind != asset.ArtPrefab {
|
||||
continue
|
||||
}
|
||||
src, err := s.read(x.Path)
|
||||
if err != nil {
|
||||
add(true, x.Path, err.Error())
|
||||
continue
|
||||
}
|
||||
doc, err := mutate.Load(src, x.Path, s.env())
|
||||
if err != nil {
|
||||
add(true, x.Path, err.Error())
|
||||
continue
|
||||
}
|
||||
for _, p := range doc.Problems {
|
||||
add(p.Error, x.Path+" "+p.Node, p.Message)
|
||||
}
|
||||
}
|
||||
errs, warns := 0, 0
|
||||
for _, p := range out.Problems {
|
||||
if p.Error {
|
||||
errs++
|
||||
} else {
|
||||
warns++
|
||||
}
|
||||
}
|
||||
out.Notes = []string{"project: " + strconv.Itoa(errs) + " error(s), " + strconv.Itoa(warns) + " warning(s)"}
|
||||
return out, nil
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,6 @@ import (
|
||||
"aego/engine/module"
|
||||
"aego/modules/accessibility"
|
||||
"aego/modules/audio"
|
||||
"aego/modules/camera"
|
||||
"aego/modules/dataasset"
|
||||
"aego/modules/debug"
|
||||
"aego/modules/display"
|
||||
@@ -72,10 +71,6 @@ func tweenEntry() assembly.Entry {
|
||||
return assembly.Entry{ID: tween.ID, Requires: []string{scripting.ID}, New: func(assembly.Options) module.Module { return tween.New() }}
|
||||
}
|
||||
|
||||
func cameraEntry() assembly.Entry {
|
||||
return assembly.Entry{ID: camera.ID, Requires: []string{scripting.ID}, New: func(assembly.Options) module.Module { return camera.New() }}
|
||||
}
|
||||
|
||||
func dataEntry() assembly.Entry {
|
||||
return assembly.Entry{ID: dataasset.ID, New: func(assembly.Options) module.Module { return dataasset.New() }}
|
||||
}
|
||||
@@ -90,5 +85,5 @@ func savegameEntry() assembly.Entry {
|
||||
|
||||
func Default() assembly.Catalog {
|
||||
return assembly.Catalog{core(), dataEntry(), inputEntry(), render2dEntry(), render3dEntry(), scriptEntry(), physicsEntry(), debugEntry(),
|
||||
displayEntry(), audioEntry(), accessibilityEntry(), settingsEntry(), tweenEntry(), cameraEntry(), spawnEntry(), savegameEntry()}
|
||||
displayEntry(), audioEntry(), accessibilityEntry(), settingsEntry(), tweenEntry(), spawnEntry(), savegameEntry()}
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ package builtin
|
||||
import "aego/app/assembly"
|
||||
|
||||
func Headless() assembly.Catalog {
|
||||
return assembly.Catalog{core(), dataEntry(), inputEntry(), scriptEntry(), physicsEntry(), debugEntry(), displayEntry(), audioEntry(), accessibilityEntry(), settingsEntry(), tweenEntry(), cameraEntry(), spawnEntry(), savegameEntry()}
|
||||
return assembly.Catalog{core(), dataEntry(), inputEntry(), scriptEntry(), physicsEntry(), debugEntry(), displayEntry(), audioEntry(), accessibilityEntry(), settingsEntry(), tweenEntry(), spawnEntry(), savegameEntry()}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ package editors
|
||||
|
||||
import (
|
||||
"aego/app/assembly"
|
||||
"aego/modules/camera"
|
||||
cameraeditor "aego/modules/camera/editor"
|
||||
"aego/modules/debug"
|
||||
debugeditor "aego/modules/debug/editor"
|
||||
inputmod "aego/modules/input"
|
||||
@@ -22,6 +20,5 @@ func With(c assembly.Catalog) assembly.Catalog {
|
||||
With(render2d.ID, render2deditor.Hook).
|
||||
With(render3d.ID, render3deditor.Hook).
|
||||
With(physics.ID, physicseditor.Hook).
|
||||
With(camera.ID, cameraeditor.Hook).
|
||||
With(debug.ID, debugeditor.Hook)
|
||||
}
|
||||
|
||||
@@ -4,14 +4,11 @@ import (
|
||||
"aego/app/assembly"
|
||||
"aego/engine/base"
|
||||
"aego/engine/module"
|
||||
"aego/modules/camera"
|
||||
"aego/modules/debug"
|
||||
inputmod "aego/modules/input"
|
||||
"aego/modules/physics"
|
||||
"aego/modules/render2d"
|
||||
"aego/modules/render3d"
|
||||
"aego/modules/scripting"
|
||||
"aego/modules/tween"
|
||||
"aego/script/stdlib"
|
||||
"aego/script/vm"
|
||||
)
|
||||
@@ -26,9 +23,6 @@ func Catalog() assembly.Catalog {
|
||||
}},
|
||||
{ID: physics.ID, New: func(assembly.Options) module.Module { return physics.New() }},
|
||||
{ID: debug.ID, New: func(assembly.Options) module.Module { return debug.New() }},
|
||||
{ID: tween.ID, Requires: []string{scripting.ID}, New: func(assembly.Options) module.Module { return tween.New() }},
|
||||
{ID: camera.ID, Requires: []string{scripting.ID}, New: func(assembly.Options) module.Module { return camera.New() }},
|
||||
{ID: render3d.ID, New: func(assembly.Options) module.Module { return render3d.New() }},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package docstool
|
||||
|
||||
import (
|
||||
"aego/app/playground"
|
||||
"aego/engine/docs"
|
||||
"aego/script/diag"
|
||||
)
|
||||
|
||||
func diagnoser(pg *playground.Playground) func(string, *docs.DiagInfo) {
|
||||
return func(code string, d *docs.DiagInfo) {
|
||||
got, err := pg.Reproduce(code)
|
||||
if err != nil || got.Code == "" {
|
||||
return
|
||||
}
|
||||
d.Severity, d.At, d.Message = got.Severity, got.File, got.Message
|
||||
d.Line, d.Col, d.EndLine, d.EndCol = got.Line, got.Col, got.EndLine, got.EndCol
|
||||
}
|
||||
}
|
||||
|
||||
// DiagnosticProblems lists codes whose example is missing or no longer produces the code.
|
||||
func DiagnosticProblems() []docs.Problem {
|
||||
pg, err := playground.New()
|
||||
if err != nil {
|
||||
return []docs.Problem{{ID: docs.DiagnosticsID, Error: true, Message: "cannot start the docs runtime: " + err.Error()}}
|
||||
}
|
||||
var out []docs.Problem
|
||||
for _, c := range diag.Codes() {
|
||||
if _, err := pg.Reproduce(c); err != nil {
|
||||
out = append(out, docs.Problem{ID: c, Error: true, Message: err.Error()})
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func TestF1Refs(t *testing.T) {
|
||||
if err := os.WriteFile(path, []byte(probe), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
reg, ws, err := build(p, nil, nil)
|
||||
reg, ws, err := build(p, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -169,17 +169,3 @@ func TestF1Refs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiagnosticExamplesExported(t *testing.T) {
|
||||
if ps := DiagnosticProblems(); len(ps) > 0 {
|
||||
t.Fatalf("diagnostics examples: %v", ps)
|
||||
}
|
||||
reg, err := ExportRegistry(nil, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
e, ok := reg.Get("AES2001")
|
||||
if !ok || e.Diag == nil || e.Diag.Line == 0 || e.Diag.Severity != "error" || !strings.Contains(e.Diag.Message, "heigth") {
|
||||
t.Fatalf("AES2001 example was not diagnosed: %+v", e.Diag)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
"aego/app/assembly"
|
||||
"aego/app/assembly/builtin"
|
||||
"aego/app/playground"
|
||||
"aego/engine/docs"
|
||||
"aego/engine/module"
|
||||
scriptsystems "aego/modules/scripting/systems"
|
||||
@@ -21,7 +20,7 @@ import (
|
||||
"aego/script/workspace"
|
||||
)
|
||||
|
||||
func build(p *project.Project, mods []module.Module, diagnose func(string, *docs.DiagInfo)) (*docs.Registry, *workspace.Workspace, error) {
|
||||
func build(p *project.Project, mods []module.Module) (*docs.Registry, *workspace.Workspace, error) {
|
||||
types, err := assembly.NewTypes()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@@ -42,7 +41,6 @@ func build(p *project.Project, mods []module.Module, diagnose func(string, *docs
|
||||
return nil, nil, err
|
||||
}
|
||||
src := docs.SourcesOf(bm, types.Schema(), man)
|
||||
src.Diagnose = diagnose
|
||||
var ws *workspace.Workspace
|
||||
if p != nil {
|
||||
ws, err = workspace.Open(workspace.Config{Root: p.Root, Module: p.Module, Scripts: p.ScriptsDir(), Bindings: reg.Table(), Docs: bm})
|
||||
@@ -63,17 +61,7 @@ func build(p *project.Project, mods []module.Module, diagnose func(string, *docs
|
||||
}
|
||||
|
||||
func Registry(p *project.Project, mods []module.Module) (*docs.Registry, error) {
|
||||
r, _, err := build(p, mods, nil)
|
||||
return r, err
|
||||
}
|
||||
|
||||
// ExportRegistry is Registry with the diagnostics examples compiled for their messages and positions.
|
||||
func ExportRegistry(p *project.Project, mods []module.Module) (*docs.Registry, error) {
|
||||
pg, err := playground.New()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, _, err := build(p, mods, diagnoser(pg))
|
||||
r, _, err := build(p, mods)
|
||||
return r, err
|
||||
}
|
||||
|
||||
@@ -96,9 +84,9 @@ func WriteExport(reg *docs.Registry, title, path string, w io.Writer) error {
|
||||
return os.WriteFile(path, data, 0o644)
|
||||
}
|
||||
|
||||
func Check(reg *docs.Registry, strict bool, w io.Writer, extra ...docs.Problem) int {
|
||||
func Check(reg *docs.Registry, strict bool, w io.Writer) int {
|
||||
errs, warns := 0, 0
|
||||
for _, p := range append(reg.Check(strict), extra...) {
|
||||
for _, p := range reg.Check(strict) {
|
||||
level := "warn "
|
||||
if p.Error {
|
||||
level = "error"
|
||||
|
||||
+3
-15
@@ -16,7 +16,6 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"aego/app/assembly/builtin"
|
||||
"aego/engine"
|
||||
"aego/engine/module"
|
||||
"aego/project"
|
||||
@@ -41,7 +40,7 @@ func (e *Env) export(path string) error {
|
||||
}
|
||||
return e.Native(args...)
|
||||
}
|
||||
reg, err := ExportRegistry(e.Project, e.Modules)
|
||||
reg, err := Registry(e.Project, e.Modules)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -72,7 +71,7 @@ func (e *Env) Check(strict bool) int {
|
||||
fmt.Fprintln(e.Stderr, "aego:", err)
|
||||
return 1
|
||||
}
|
||||
code := Check(reg, strict, e.Stdout, DiagnosticProblems()...)
|
||||
code := Check(reg, strict, e.Stdout)
|
||||
if CheckTry(reg, e.Stdout) > 0 && code == 0 {
|
||||
code = 1
|
||||
}
|
||||
@@ -99,10 +98,7 @@ func (e *Env) git(args ...string) string {
|
||||
}
|
||||
|
||||
func (e *Env) commit() string {
|
||||
if c := e.git("rev-parse", "--short", "HEAD"); c != "" {
|
||||
return c
|
||||
}
|
||||
return os.Getenv("AEGO_COMMIT")
|
||||
return e.git("rev-parse", "--short", "HEAD")
|
||||
}
|
||||
|
||||
func (e *Env) branch() string {
|
||||
@@ -154,14 +150,6 @@ func (e *Env) Build(out string, play bool) error {
|
||||
if c := e.commit(); c != "" {
|
||||
args = append(args, "-commit", c)
|
||||
}
|
||||
var icons []string
|
||||
for _, d := range builtin.IconSources() {
|
||||
icons = append(icons, filepath.Join(e.Engine, filepath.FromSlash(d)))
|
||||
}
|
||||
args = append(args, "-icons", strings.Join(icons, ","))
|
||||
if shots := filepath.Join(e.Engine, "docs", "shots"); fileExists(filepath.Join(shots, "demo.png")) {
|
||||
args = append(args, "-poster", filepath.Join(shots, "demo.png"), "-shots", shots)
|
||||
}
|
||||
if hero := filepath.Join(e.Engine, "docs", "hero.png"); fileExists(hero) {
|
||||
args = append(args, "-hero", hero)
|
||||
}
|
||||
|
||||
@@ -21,11 +21,7 @@ func Tool(p *project.Project, args []string, stdout, stderr io.Writer, mods ...m
|
||||
if err := fs.Parse(args[1:]); err != nil {
|
||||
return 2
|
||||
}
|
||||
build := Registry
|
||||
if args[0] == "export" {
|
||||
build = ExportRegistry
|
||||
}
|
||||
reg, err := build(p, mods)
|
||||
reg, err := Registry(p, mods)
|
||||
if err != nil {
|
||||
fmt.Fprintln(stderr, "aego:", err)
|
||||
return 1
|
||||
@@ -38,7 +34,7 @@ func Tool(p *project.Project, args []string, stdout, stderr io.Writer, mods ...m
|
||||
}
|
||||
return 0
|
||||
case "check":
|
||||
return Check(reg, *strict, stdout, DiagnosticProblems()...)
|
||||
return Check(reg, *strict, stdout)
|
||||
}
|
||||
fmt.Fprintf(stderr, "unknown docs command %q\n", args[0])
|
||||
return 2
|
||||
|
||||
+4
-23
@@ -7,7 +7,6 @@ import (
|
||||
playmods "aego/app/assembly/playground"
|
||||
"aego/asset"
|
||||
"aego/asset/loader"
|
||||
"aego/contracts/debugdraw"
|
||||
"aego/core/log"
|
||||
"aego/core/mathx"
|
||||
edclip "aego/editor/core/clipboard"
|
||||
@@ -21,7 +20,6 @@ import (
|
||||
"aego/engine/base"
|
||||
"aego/engine/module"
|
||||
"aego/format/aetext"
|
||||
"aego/modules/physics"
|
||||
scriptsystems "aego/modules/scripting/systems"
|
||||
"aego/platform"
|
||||
"aego/render"
|
||||
@@ -43,11 +41,9 @@ const (
|
||||
maxSprites = 16384
|
||||
gameShare = 0.6
|
||||
stackBelow = 640
|
||||
// inspectorMin keeps field names and values readable in narrow embeds.
|
||||
inspectorMin = 400
|
||||
maxLines = 200
|
||||
defaultW = 960
|
||||
defaultH = 440
|
||||
maxLines = 200
|
||||
defaultW = 960
|
||||
defaultH = 440
|
||||
)
|
||||
|
||||
var coreBlocks = []string{"window", "defaults"}
|
||||
@@ -81,7 +77,6 @@ type App struct {
|
||||
log *log.Logger
|
||||
lines []Line
|
||||
textOn bool
|
||||
shown *engine.World
|
||||
closed bool
|
||||
}
|
||||
|
||||
@@ -275,7 +270,7 @@ func layout(body mathx.Rect, gap float32) (game, insp mathx.Rect) {
|
||||
return mathx.Rect{X: body.X, Y: body.Y, W: body.W, H: h},
|
||||
mathx.Rect{X: body.X, Y: body.Y + h + gap, W: body.W, H: max(0, body.H-h-gap)}
|
||||
}
|
||||
w := min(body.W*gameShare, body.W-inspectorMin)
|
||||
w := body.W * gameShare
|
||||
return mathx.Rect{X: body.X, Y: body.Y, W: w, H: body.H},
|
||||
mathx.Rect{X: body.X + w + gap, Y: body.Y, W: max(0, body.W-w-gap), H: body.H}
|
||||
}
|
||||
@@ -313,24 +308,10 @@ func (a *App) toolbar(r mathx.Rect) {
|
||||
}
|
||||
}
|
||||
|
||||
// showPhysics draws collider and joint outlines in the game view, since docs scenes have no art for them.
|
||||
func (a *App) showPhysics() {
|
||||
w := a.session.Controller().World()
|
||||
if w == nil || w == a.shown {
|
||||
return
|
||||
}
|
||||
if d, ok := engine.ServiceOf[debugdraw.Draw](w, debugdraw.ServiceID); ok {
|
||||
d.Hide(physics.ChannelShapes, false)
|
||||
d.Hide(physics.ChannelJoints, false)
|
||||
a.shown = w
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) Update(dt float64) {
|
||||
e := a.e
|
||||
now := e.Platform().Now()
|
||||
a.session.Tick(dt)
|
||||
a.showPhysics()
|
||||
ui := a.ui
|
||||
ui.Time = now
|
||||
m := e.Metrics()
|
||||
|
||||
@@ -27,7 +27,7 @@ func tries(t *testing.T) []docs.Entry {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out := p.TryScenes()
|
||||
if len(out) < 10 {
|
||||
if len(out) < 4 {
|
||||
t.Fatalf("only %d try scenes; does the module embed res/docs/try?", len(out))
|
||||
}
|
||||
return out
|
||||
|
||||
+5
-16
@@ -7,7 +7,6 @@ import (
|
||||
"strconv"
|
||||
|
||||
"aego/editor/core/docsession"
|
||||
"aego/scene/sceneio"
|
||||
)
|
||||
|
||||
type request struct {
|
||||
@@ -19,11 +18,10 @@ type request struct {
|
||||
}
|
||||
|
||||
type Reply struct {
|
||||
Text string `json:"text,omitempty"`
|
||||
Values map[string]string `json:"values,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
State *docsession.State `json:"state,omitempty"`
|
||||
Log []Line `json:"log,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
State *docsession.State `json:"state,omitempty"`
|
||||
Log []Line `json:"log,omitempty"`
|
||||
}
|
||||
|
||||
func (a *App) Call(method string, payload []byte) Reply {
|
||||
@@ -63,16 +61,7 @@ func (a *App) Call(method string, payload []byte) Reply {
|
||||
return Reply{Error: err.Error()}
|
||||
}
|
||||
st := s.State()
|
||||
return Reply{Text: string(s.Text()), Values: Values(s.Text()), State: &st}
|
||||
}
|
||||
|
||||
// Values flattens a scene file into the field keys the docs scene tree uses.
|
||||
func Values(text []byte) map[string]string {
|
||||
nodes, err := sceneio.Outline(text)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
return sceneio.OutlineValues(nodes)
|
||||
return Reply{Text: string(s.Text()), State: &st}
|
||||
}
|
||||
|
||||
func (a *App) Reply(method, payload string) string {
|
||||
|
||||
@@ -154,9 +154,6 @@ func Run(p *project.Project, cfg Config, mods ...sdk.Module) error {
|
||||
panic(rec)
|
||||
}
|
||||
}()
|
||||
if dir := os.Getenv(EnvShots); dir != "" {
|
||||
return s.shots(dir)
|
||||
}
|
||||
if err := s.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -116,8 +116,12 @@ func TestPlayLeavesEditSceneByteIdentical(t *testing.T) {
|
||||
t.Fatal("Spin is not registered")
|
||||
}
|
||||
speed, _ := td.Field("speed")
|
||||
add := commands.NewMutation("Add "+td.FullName, commands.EnvFor(es),
|
||||
commands.AddComp(es, spinner, td, []commands.FieldValue{{Field: speed.ID, Value: schema.Float32(3)}}))
|
||||
add := &commands.AddComponent{
|
||||
Node: spinner,
|
||||
Type: td.ID,
|
||||
Name: td.FullName,
|
||||
Values: []commands.FieldValue{{Field: speed.ID, Value: schema.Float32(3)}},
|
||||
}
|
||||
if err := d.History.Exec(add); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func TestColliderFitsSprite(t *testing.T) {
|
||||
}
|
||||
for _, name := range []string{"Crate", "Bare"} {
|
||||
id := es.ID(es.Find(es.Root(), name))
|
||||
if err := d.History.Exec(commands.NewMutation("Add "+td.FullName, commands.WithOnAdd(commands.EnvFor(es), ctx.OnAdd), commands.AddComp(es, id, td, nil))); err != nil {
|
||||
if err := d.History.Exec(&commands.AddComponent{Node: id, Type: td.ID, Name: td.FullName, OnAdd: ctx.OnAdd(td)}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,8 +51,12 @@ func openSpinner(t *testing.T) *spinFixture {
|
||||
}
|
||||
fd, _ := td.Field("speed")
|
||||
f.typ, f.speed = td.ID, fd.ID
|
||||
add := commands.NewMutation("Add "+td.FullName, commands.EnvFor(es),
|
||||
commands.AddComp(es, f.spinner, td, []commands.FieldValue{{Field: fd.ID, Value: schema.Float32(3)}}))
|
||||
add := &commands.AddComponent{
|
||||
Node: f.spinner,
|
||||
Type: td.ID,
|
||||
Name: td.FullName,
|
||||
Values: []commands.FieldValue{{Field: fd.ID, Value: schema.Float32(3)}},
|
||||
}
|
||||
if err := d.History.Exec(add); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,6 @@ canvas { display: block; width: 100%; height: 100%; outline: none; touch-action:
|
||||
#fullscreen { position: fixed; top: 10px; right: 10px; width: 36px; height: 36px; border: 0; border-radius: 6px; background: rgba(0, 0, 0, 0.45); color: #fff; font-size: 18px; cursor: pointer; opacity: 0.5; }
|
||||
#fullscreen:hover { opacity: 1; }
|
||||
</style>
|
||||
<link rel="preload" href="game.wasm?v={{.Build}}" as="fetch" type="application/wasm" crossorigin>
|
||||
</head>
|
||||
<body>
|
||||
<canvas id="game" data-aego tabindex="0" aria-label="{{.Title}}"></canvas>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
package playground
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"aego/app/assembly/builtin"
|
||||
)
|
||||
|
||||
func TestCheckSnippetsCompile(t *testing.T) {
|
||||
p, err := NewWith(builtin.Default())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
n := 0
|
||||
for _, e := range p.docs.All() {
|
||||
for _, s := range e.Snippets {
|
||||
if !s.Check || s.Lang != "aes" {
|
||||
continue
|
||||
}
|
||||
n++
|
||||
for _, d := range p.Compile(map[string]string{"main.aes": s.Code}) {
|
||||
if d.Severity == "error" {
|
||||
t.Errorf("%s (line %d of its page): %d:%d %s %s", e.ID, s.Line, d.Line, d.Col, d.Code, d.Message)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if n == 0 {
|
||||
t.Fatal("no aes check blocks in the documentation")
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package playground
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"aego/script/diag"
|
||||
)
|
||||
|
||||
const exampleFrames = 3
|
||||
|
||||
// Reproduce runs the diagnostics example of code and returns what its broken version reports.
|
||||
func (p *Playground) Reproduce(code string) (Diagnostic, error) {
|
||||
ex, ok := diag.Example(code)
|
||||
if !ok {
|
||||
return Diagnostic{}, errors.New("no example in script/diag/examples.go")
|
||||
}
|
||||
if ex.Why != "" {
|
||||
return Diagnostic{}, nil
|
||||
}
|
||||
if ex.Bad == "" || ex.Good == "" {
|
||||
return Diagnostic{}, errors.New("the example needs both a broken and a fixed version")
|
||||
}
|
||||
bad := reports(p.Run(ex.Sources(false), exampleFrames))
|
||||
var found *Diagnostic
|
||||
for i := range bad {
|
||||
if bad[i].Code == code {
|
||||
found = &bad[i]
|
||||
break
|
||||
}
|
||||
}
|
||||
if found == nil {
|
||||
return Diagnostic{}, fmt.Errorf("the broken example does not report %s, it reports %s", code, list(bad))
|
||||
}
|
||||
var wrong []Diagnostic
|
||||
for _, d := range reports(p.Run(ex.Sources(true), exampleFrames)) {
|
||||
if d.Code == code || d.Severity == "error" {
|
||||
wrong = append(wrong, d)
|
||||
}
|
||||
}
|
||||
if len(wrong) > 0 {
|
||||
return *found, fmt.Errorf("the fixed example still reports %s", list(wrong))
|
||||
}
|
||||
return *found, nil
|
||||
}
|
||||
|
||||
func reports(res Result) []Diagnostic {
|
||||
out := append([]Diagnostic(nil), res.Diagnostics...)
|
||||
for _, f := range res.Faults {
|
||||
out = append(out, Diagnostic{File: f.File, Line: f.Line, Code: f.Code, Severity: "error", Message: f.Message})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func list(ds []Diagnostic) string {
|
||||
if len(ds) == 0 {
|
||||
return "nothing"
|
||||
}
|
||||
parts := make([]string, len(ds))
|
||||
for i, d := range ds {
|
||||
parts[i] = strings.TrimSpace(d.Code + " " + d.Message)
|
||||
}
|
||||
return strings.Join(parts, "; ")
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package playground
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"aego/script/diag"
|
||||
)
|
||||
|
||||
func TestDiagnosticExamples(t *testing.T) {
|
||||
p := open(t)
|
||||
var skipped []string
|
||||
for _, code := range diag.Codes() {
|
||||
d, err := p.Reproduce(code)
|
||||
if err != nil {
|
||||
t.Errorf("%s: %v", code, err)
|
||||
continue
|
||||
}
|
||||
if d.Code == "" {
|
||||
skipped = append(skipped, code)
|
||||
continue
|
||||
}
|
||||
t.Logf("%s %s:%d:%d-%d:%d %s %s", code, d.File, d.Line, d.Col, d.EndLine, d.EndCol, d.Severity, d.Message)
|
||||
}
|
||||
if len(skipped) > 10 {
|
||||
t.Errorf("%d codes are not reproducible: %v", len(skipped), skipped)
|
||||
}
|
||||
}
|
||||
@@ -101,16 +101,9 @@ type Playground struct {
|
||||
proj *exampleProject
|
||||
gameCfg GameConfig
|
||||
game *Game
|
||||
|
||||
simEngine *engine.Engine
|
||||
}
|
||||
|
||||
func New() (*Playground, error) {
|
||||
return NewWith(playmods.Catalog())
|
||||
}
|
||||
|
||||
// NewWith builds a playground over another module catalog, for checks that need every module's types.
|
||||
func NewWith(cat assembly.Catalog) (*Playground, error) {
|
||||
proj, err := loadProject()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -120,7 +113,7 @@ func NewWith(cat assembly.Catalog) (*Playground, error) {
|
||||
return nil, err
|
||||
}
|
||||
reg := bind.New()
|
||||
man, err := cat.Load(types, reg, assembly.Options{Seed: 1, Testing: true})
|
||||
man, err := playmods.Catalog().Load(types, reg, assembly.Options{Seed: 1, Testing: true})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -212,23 +205,6 @@ func diagnostics(sm *source.Manager, ds []diag.Diagnostic) []Diagnostic {
|
||||
return out
|
||||
}
|
||||
|
||||
func blocked(failed map[string][]diag.Diagnostic) []Diagnostic {
|
||||
pkgs := make([]string, 0, len(failed))
|
||||
for pkg := range failed {
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
sort.Strings(pkgs)
|
||||
var out []Diagnostic
|
||||
for _, pkg := range pkgs {
|
||||
for _, d := range failed[pkg] {
|
||||
if d.Code == diag.CompileBlocked {
|
||||
out = append(out, Diagnostic{Code: d.Code, Message: d.Message, Severity: severity(d)})
|
||||
}
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func failed(err error) []Diagnostic {
|
||||
return []Diagnostic{{Severity: "error", Message: err.Error()}}
|
||||
}
|
||||
@@ -287,7 +263,6 @@ func (p *Playground) Run(files map[string]string, frames int) Result {
|
||||
gen, ds := p.ws.Build()
|
||||
res := Result{Diagnostics: diagnostics(gen.Sources, ds)}
|
||||
if len(gen.Failed) > 0 || diag.HasErrors(ds) {
|
||||
res.Diagnostics = append(res.Diagnostics, blocked(gen.Failed)...)
|
||||
return res
|
||||
}
|
||||
pkgs := make([]string, 0, len(gen.Modules))
|
||||
@@ -320,17 +295,16 @@ func (p *Playground) Run(files map[string]string, frames int) Result {
|
||||
}
|
||||
w := engine.NewWorld("playground")
|
||||
w.Input = &input.State{}
|
||||
w.SetService(scene.ServiceID, s)
|
||||
w.SetService(runtime.ServiceID, rt)
|
||||
e, detach, err := p.attach(w, s, lg)
|
||||
if err != nil {
|
||||
res.Diagnostics = append(res.Diagnostics, failed(err)...)
|
||||
return res
|
||||
}
|
||||
defer detach()
|
||||
ctx := engine.Context{World: w, Dt: 1.0 / 60}
|
||||
for i := 0; i < frames; i++ {
|
||||
frame = uint64(i + 1)
|
||||
e.TickWorld(w, engine.ScopePlay, 1.0/60)
|
||||
ctx.Frame++
|
||||
frame = ctx.Frame
|
||||
rt.RunDeferred()
|
||||
rt.FixedUpdate(&ctx)
|
||||
rt.Update(&ctx)
|
||||
rt.Coroutines(&ctx)
|
||||
s.Flush()
|
||||
s.UpdateTransforms()
|
||||
}
|
||||
res.Frames = frames
|
||||
for _, f := range rt.Faults() {
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package playground
|
||||
|
||||
import (
|
||||
"aego/core/log"
|
||||
"aego/engine"
|
||||
"aego/engine/module"
|
||||
"aego/scene"
|
||||
"aego/scene/frame"
|
||||
)
|
||||
|
||||
// sim is a windowless engine that steps the module systems of a console run, so tweens, timers and physics work there as in Play.
|
||||
func (p *Playground) sim() (*engine.Engine, error) {
|
||||
if p.simEngine != nil {
|
||||
return p.simEngine, nil
|
||||
}
|
||||
b := engine.NewBuilder(engine.Config{Headless: true, HeadlessFrameTime: 1.0 / 60, Seed: 1, AppID: "aego-playground-console"}).WithLogger(log.Nop())
|
||||
if err := frame.Register(b.Registry()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e, err := b.Use(p.man.Engine()).Build()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p.man.Init(&module.InitContext{Engine: e, Log: log.Nop(), Sections: p.sections}); err != nil {
|
||||
e.Close()
|
||||
return nil, err
|
||||
}
|
||||
p.simEngine = e
|
||||
return e, nil
|
||||
}
|
||||
|
||||
func (p *Playground) attach(w *engine.World, s *scene.Scene, lg *log.Logger) (*engine.Engine, func(), error) {
|
||||
e, err := p.sim()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
w.Time.Configure(e.TimeConfig())
|
||||
detach, err := p.man.Attach(&module.AttachContext{World: w, Scene: s, Log: lg, Play: true})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return e, detach, nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package run
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"aego/app/agent"
|
||||
"aego/core/log"
|
||||
"aego/core/rewind"
|
||||
"aego/project"
|
||||
"aego/sdk"
|
||||
)
|
||||
|
||||
const maxRunLog = 200
|
||||
|
||||
func AgentRunner(mods ...sdk.Module) agent.Runner {
|
||||
return func(p *project.Project, r agent.RunRequest) (agent.RunReport, error) {
|
||||
var buf bytes.Buffer
|
||||
lg := log.New(log.NewTextSink(&buf))
|
||||
lg.SetLevel(log.Warn)
|
||||
frames, seed := r.Frames, r.Seed
|
||||
if frames <= 0 {
|
||||
frames = 120
|
||||
}
|
||||
if seed == 0 {
|
||||
seed = 1
|
||||
}
|
||||
a, err := Open(p, Config{Headless: true, FrameTime: defaultDetStep, Seed: seed, ScenePath: r.Scene, Logger: lg, NoProfile: true}, mods...)
|
||||
if err != nil {
|
||||
return agent.RunReport{Log: logLines(buf.String())}, err
|
||||
}
|
||||
rep := agent.RunReport{}
|
||||
driver := a.Driver()
|
||||
for rep.Frames < frames {
|
||||
if !a.Engine.Step(driver) {
|
||||
rep.Error = "the game stopped at frame " + strconv.Itoa(rep.Frames+1)
|
||||
if err := a.Engine.Err(); err != nil {
|
||||
rep.Error += ": " + err.Error()
|
||||
}
|
||||
break
|
||||
}
|
||||
rep.Frames++
|
||||
}
|
||||
sum, _, _ := WorldHash(a.Engine.MainWorld(), rewind.NewHasher())
|
||||
rep.Hash = hex.EncodeToString(sum[:])
|
||||
a.Close()
|
||||
rep.Log = logLines(buf.String())
|
||||
return rep, nil
|
||||
}
|
||||
}
|
||||
|
||||
func logLines(s string) []string {
|
||||
var out []string
|
||||
for _, l := range strings.Split(strings.TrimSpace(s), "\n") {
|
||||
if l = strings.TrimSpace(l); l != "" {
|
||||
out = append(out, l)
|
||||
}
|
||||
}
|
||||
if len(out) > maxRunLog {
|
||||
out = append(out[:maxRunLog], "…")
|
||||
}
|
||||
return out
|
||||
}
|
||||
@@ -78,7 +78,7 @@ func WorldHash(w *engine.World, h *rewind.Hasher) (sum [32]byte, covered, skippe
|
||||
}
|
||||
|
||||
func determinismPass(p *project.Project, o DeterminismOptions, mods []sdk.Module) ([]checkpoint, []string, []string, error) {
|
||||
a, err := Open(p, Config{Headless: true, FrameTime: o.FrameTime, Seed: o.Seed, ScenePath: o.ScenePath, Logger: log.Nop(), NoProfile: true}, mods...)
|
||||
a, err := Open(p, Config{Headless: true, FrameTime: o.FrameTime, Seed: o.Seed, ScenePath: o.ScenePath, Logger: log.Nop()}, mods...)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ type Config struct {
|
||||
Profile string
|
||||
Logger *log.Logger
|
||||
Seed uint64
|
||||
NoProfile bool
|
||||
}
|
||||
|
||||
type App struct {
|
||||
@@ -139,7 +138,6 @@ func Open(p *project.Project, cfg Config, mods ...sdk.Module) (*App, error) {
|
||||
Debug: cfg.Debug,
|
||||
FailOnScriptErrors: true,
|
||||
Profile: cfg.Profile,
|
||||
NoProfile: cfg.NoProfile,
|
||||
}, sdk.AdaptAll(mods)...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package run
|
||||
|
||||
import (
|
||||
"aego/app/agent"
|
||||
"aego/app/agent/mcp"
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -42,10 +39,6 @@ func Tool(p *project.Project, args []string, stdout, stderr io.Writer, mods ...s
|
||||
return toolTest(p, args[1:], stdout, stderr, mods)
|
||||
case "docs":
|
||||
return docstool.Tool(p, args[1:], stdout, stderr, sdk.AdaptAll(mods)...)
|
||||
case "agent":
|
||||
return agent.Main(p, args[1:], stdout, stderr, agent.Options{Mods: mods, Run: AgentRunner(mods...)})
|
||||
case "mcp":
|
||||
return mcp.Main(p, args[1:], os.Stdin, stdout, stderr, agent.Options{Mods: mods, Run: AgentRunner(mods...)})
|
||||
}
|
||||
fmt.Fprintf(stderr, "unknown tool %q\n", args[0])
|
||||
return 2
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"syscall/js"
|
||||
|
||||
"aego/app/docsview"
|
||||
@@ -18,8 +17,7 @@ func main() {
|
||||
} else {
|
||||
app.OnChange = func(text string) {
|
||||
if f := g.Get("aegoDocsChanged"); f.Type() == js.TypeFunction {
|
||||
values, _ := json.Marshal(docsview.Values([]byte(text)))
|
||||
f.Invoke(text, string(values))
|
||||
f.Invoke(text)
|
||||
}
|
||||
}
|
||||
api.Set("call", js.FuncOf(func(_ js.Value, args []js.Value) any {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"aego/app/agent"
|
||||
"aego/app/agent/mcp"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"aego/app/bootstrap"
|
||||
@@ -53,8 +50,6 @@ func dispatch(args []string) int {
|
||||
return cmdCheck(args[1:])
|
||||
case "icons":
|
||||
return cmdIcons(args[1:])
|
||||
case "mcp":
|
||||
return cmdMcp(args[1:])
|
||||
case "docs":
|
||||
return cmdDocs(args[1:])
|
||||
case "test":
|
||||
@@ -65,9 +60,6 @@ func dispatch(args []string) int {
|
||||
usage()
|
||||
return 0
|
||||
}
|
||||
if slices.Contains(agent.Groups(), args[0]) {
|
||||
return cmdAgent(args)
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "unknown command %q\n", args[0])
|
||||
usage()
|
||||
return 2
|
||||
@@ -91,8 +83,6 @@ func usage() {
|
||||
run *_test.aes script tests headless, or run the game twice and compare state hashes
|
||||
dump script <pkg|Type> [--func name] disassemble a script package with source lines
|
||||
docs export|check|build|serve documentation registry, site and playground
|
||||
mcp [--project dir] [--watch] serve the project to an AI agent over MCP (stdio)
|
||||
scene|prefab|data|refs|asset|schema|project <verb> ... edit project files without the editor, see aego scene help
|
||||
`)
|
||||
}
|
||||
|
||||
@@ -107,40 +97,6 @@ func openProject(dir string) (*project.Project, error) {
|
||||
return project.Load(root)
|
||||
}
|
||||
|
||||
func projectFlag(args []string) string {
|
||||
for i, a := range args {
|
||||
switch {
|
||||
case a == "--project" && i+1 < len(args):
|
||||
return args[i+1]
|
||||
case strings.HasPrefix(a, "--project="):
|
||||
return strings.TrimPrefix(a, "--project=")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func cmdAgent(args []string) int {
|
||||
p, err := openProject(projectFlag(args))
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
if bootstrap.NeedsNative(p) {
|
||||
return scriptTool(p, append([]string{"agent"}, args...)...)
|
||||
}
|
||||
return agent.Main(p, args, os.Stdout, os.Stderr, agent.Options{Run: run.AgentRunner()})
|
||||
}
|
||||
|
||||
func cmdMcp(args []string) int {
|
||||
p, err := openProject(projectFlag(args))
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
if bootstrap.NeedsNative(p) {
|
||||
return scriptTool(p, append([]string{"mcp"}, args...)...)
|
||||
}
|
||||
return mcp.Main(p, args, os.Stdin, os.Stdout, os.Stderr, agent.Options{Run: run.AgentRunner()})
|
||||
}
|
||||
|
||||
func firstArg(args []string) (string, []string) {
|
||||
if len(args) > 0 && len(args[0]) > 0 && args[0][0] != '-' {
|
||||
return args[0], args[1:]
|
||||
|
||||
@@ -23,7 +23,6 @@ func scriptTool(p *project.Project, args ...string) int {
|
||||
}
|
||||
cmd := exec.Command(binary, append([]string{"--tool"}, args...)...)
|
||||
cmd.Dir = p.Root
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
return exitCode(cmd.Run())
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
package camera2d
|
||||
|
||||
import (
|
||||
"aego/render/view"
|
||||
"aego/scene"
|
||||
)
|
||||
|
||||
const (
|
||||
ServiceID = "camera2d.adjust"
|
||||
AccessibilityKind = "camera2d.accessibility"
|
||||
)
|
||||
|
||||
type Adjuster interface {
|
||||
Adjust(node scene.NodeHandle, v view.View) view.View
|
||||
}
|
||||
|
||||
type Accessibility struct {
|
||||
ScreenShake string
|
||||
ReducedMotion string
|
||||
}
|
||||
+1
-8
@@ -1,19 +1,12 @@
|
||||
FROM golang:1.27-alpine AS build
|
||||
RUN apk add --no-cache make gzip brotli
|
||||
RUN apk add --no-cache make gzip
|
||||
WORKDIR /src
|
||||
COPY go.mod go.sum ./
|
||||
COPY tools/gendocs/go.mod tools/gendocs/go.sum tools/gendocs/
|
||||
RUN go mod download && cd tools/gendocs && go mod download
|
||||
COPY . .
|
||||
ARG AEGO_COMMIT=""
|
||||
ENV AEGO_COMMIT=$AEGO_COMMIT
|
||||
RUN make site-headless
|
||||
RUN find site -type f \( -name '*.js' -o -name '*.css' -o -name '*.html' -o -name '*.json' -o -name '*.svg' \) -exec gzip -9 -k -f {} \;
|
||||
RUN find site -type f -name '*.wasm' | while read -r f; do [ -f "$f.gz" ] || gzip -9 -k -f "$f"; [ -f "$f.br" ] || brotli -q 11 -k -f "$f"; done
|
||||
COPY tools/release/install.sh tools/release/install.ps1 site/
|
||||
# the edge proxy serves the site from its own copy: everything but the wasm binaries, which it fetches separately
|
||||
RUN mkdir -p site/__edge && tar -czf site/__edge/site.tar.gz --exclude='./__edge' --exclude='*.wasm' --exclude='*.wasm.gz' --exclude='*.wasm.br' -C site . \
|
||||
&& sha256sum site/__edge/site.tar.gz | cut -c1-16 > site/__edge/version
|
||||
|
||||
FROM nginx:1.27-alpine
|
||||
COPY deploy/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
@@ -5,8 +5,6 @@ services:
|
||||
build:
|
||||
context: ..
|
||||
dockerfile: deploy/Dockerfile
|
||||
args:
|
||||
AEGO_COMMIT: ${AEGO_COMMIT:-}
|
||||
image: aego-site:latest
|
||||
container_name: aego-site
|
||||
restart: unless-stopped
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ else
|
||||
git checkout -q -f --detach "origin/$ref"
|
||||
fi
|
||||
sha=$(git rev-parse HEAD)
|
||||
AEGO_COMMIT=$(git rev-parse --short HEAD) docker compose -f deploy/compose.yml build
|
||||
docker compose -f deploy/compose.yml build
|
||||
docker compose -f deploy/compose.yml up -d --wait --remove-orphans
|
||||
docker image prune -f >/dev/null
|
||||
echo "$sha" >"$state/deployed"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user