Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ Write idiomatic Zig 0.17, as OpenReliant's guide describes: name every number, g
`enum` and switch over it exhaustively, use tagged unions for variants and optionals for "none",
check invariants with `comptime`, and share code rather than copy it.

C and C++ come in through two shims and one header: the text editor's
([`src/ui/text_editor`](src/ui/text_editor)), Dear ImGui's internal calls
([`src/ui/imgui_extras`](src/ui/imgui_extras)), and [`src/platform/c.h`](src/platform/c.h), which
the build translates into the `c` module with SDL3 and Dear Bindings' C API for Dear ImGui.
C and C++ come in through three shims and one header: the text editor's
([`src/ui/text_editor`](src/ui/text_editor)), ImPlot's for the map ([`src/ui/plot`](src/ui/plot)),
Dear ImGui's internal calls ([`src/ui/imgui_extras`](src/ui/imgui_extras)), and
[`src/platform/c.h`](src/platform/c.h), which the build translates into the `c` module with SDL3
and Dear Bindings' C API for Dear ImGui.

Add `test` blocks next to the code in the same change, with inputs built by hand so that they run
without the game's files. `--check-missions` opens each of a game's own missions as source and
Expand Down
17 changes: 9 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ A mission editor, script debugger and mod editor for
StarLancer's engine. It links to the running game, so that a change to a mission or a mod shows in
the game as it's made.

**Status:** Mission mode's Script view works. It opens a mod's missions, a mission file or one of
the game's own missions as source, colours it with the game's commands, checks it as it's typed,
offers the game's commands and conditions as you type, explains them on hover and in the Reference
panel, builds the mission, and plays it in OpenReliant, from its start or from a part. The inspector
edits the records as forms, and the outline adds new ones ([Editing records](docs/editing.md)).
Linked to the game, it holds the mission's script at breakpoints, steps through it, and shows its
threads and values ([Debugging a mission](docs/debugging.md)). The rest of the [design](design/README.md) is in
place and greyed out, each part with the issue that plans it.
**Status:** Mission mode's Script and Scene views work. The Script view opens a mod's missions, a
mission file or one of the game's own missions as source, colours it with the game's commands,
checks it as it's typed, offers the game's commands and conditions as you type, explains them on
hover and in the Reference panel, builds the mission, and plays it in OpenReliant, from its start or
from a part. The inspector edits the records as forms, the outline adds new ones, and the Scene
view's map shows the ships and markers and moves them ([Editing records](docs/editing.md)). Linked
to the game, it holds the mission's script at breakpoints, steps through it, and shows its threads
and values ([Debugging a mission](docs/debugging.md)). The rest of the [design](design/README.md) is
in place and greyed out, each part with the issue that plans it.
The plan is OpenReliant's [#1126](https://github.com/OpenReliant/openreliant/issues/1126).

![The Script view of a mission, held at a breakpoint](design/images/mission-script.png)
Expand Down
13 changes: 10 additions & 3 deletions build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,14 @@ fn addWindowsResources(b: *std.Build, exe: *std.Build.Step.Compile, target: std.
}

/// Dear ImGui with its docking branch, Dear Bindings' C API over it, its SDL3 and SDL_GPU backends,
/// and the text editor with its C shim, as one static library. It is built optimized whatever the
/// editor's own mode, so that typing in a long mission stays smooth in a debug build too.
/// and the text editor and ImPlot with their C shims, as one static library. It is built optimized
/// whatever the editor's own mode, so that typing in a long mission stays smooth in a debug build
/// too.
fn interfaceLibrary(b: *std.Build, target: std.Build.ResolvedTarget, sdl_library: *std.Build.Step.Compile) *std.Build.Step.Compile {
const imgui = b.dependency("imgui", .{});
const bindings = b.dependency("dear_bindings", .{});
const text_editor = b.dependency("text_editor", .{});
const implot = b.dependency("implot", .{});
const library = b.addLibrary(.{
.name = "interface",
.linkage = .static,
Expand All @@ -190,17 +192,20 @@ fn interfaceLibrary(b: *std.Build, target: std.Build.ResolvedTarget, sdl_library
library.root_module.addCSourceFile(.{ .file = text_editor.path("TextEditor.cpp"), .flags = flags });
library.root_module.addCSourceFile(.{ .file = b.path("src/ui/text_editor/shim.cpp"), .flags = flags });
library.root_module.addCSourceFile(.{ .file = b.path("src/ui/imgui_extras/extras.cpp"), .flags = flags });
library.root_module.addCSourceFiles(.{ .root = implot.path("."), .files = &.{ "implot.cpp", "implot_items.cpp" }, .flags = flags });
library.root_module.addCSourceFile(.{ .file = b.path("src/ui/plot/plot_shim.cpp"), .flags = flags });
// The libraries' licences go with the program.
for ([_]struct { std.Build.LazyPath, []const u8 }{
.{ imgui.path("LICENSE.txt"), "LICENSE-imgui.txt" },
.{ bindings.path("LICENSE.txt"), "LICENSE-dear-bindings.txt" },
.{ text_editor.path("LICENSE"), "LICENSE-text-editor.txt" },
.{ implot.path("LICENSE"), "LICENSE-implot.txt" },
}) |notice| b.getInstallStep().dependOn(&b.addInstallFile(notice[0], notice[1]).step);
return library;
}

/// The folders the interface's headers are in.
fn interfaceIncludes(b: *std.Build) [7]std.Build.LazyPath {
fn interfaceIncludes(b: *std.Build) [9]std.Build.LazyPath {
const imgui = b.dependency("imgui", .{});
const bindings = b.dependency("dear_bindings", .{});
return .{
Expand All @@ -211,6 +216,8 @@ fn interfaceIncludes(b: *std.Build) [7]std.Build.LazyPath {
b.dependency("text_editor", .{}).path("."),
b.path("src/ui/text_editor"),
b.path("src/ui/imgui_extras"),
b.dependency("implot", .{}).path("."),
b.path("src/ui/plot"),
};
}

Expand Down
4 changes: 4 additions & 0 deletions build.zig.zon
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@
.url = "git+https://codeberg.org/ziglang/rc?ref=zig-0.17.x#a8a3b3cebbe6e414fa12d6ad028c56a3a349c75e",
.hash = "rc-0.0.0-rMftL71EAAAxhe4swpM5rrfcmC9k_j7ApwJJPRssBiDL",
},
.implot = .{
.url = "git+https://github.com/epezent/implot.git?ref=v1.0#524f9fcd48d76c13fdf94c5ffbba8787a1ff7e39",
.hash = "N-V-__8AAKSTCwA_ALBxWjOi20O0c9_WB3Y1COzRQxwZLpLy",
},
},
.paths = .{
"build.zig",
Expand Down
Binary file modified design/images/mission-scene.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions design/screens/mission-scene.html
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@
Ranges
</button>
<button class="chip chip-on" type="button" aria-pressed="true">
<svg class="i i14" viewBox="0 0 24 24" aria-hidden="true"><circle cx="6" cy="19" r="3"></circle><path d="M9 19h8.5a3.5 3.5 0 0 0 0-7h-11a3.5 3.5 0 0 1 0-7H15"></path><circle cx="18" cy="5" r="3"></circle></svg>
Routes
</button>
<button class="chip chip-on" type="button" aria-pressed="true">
<svg class="i i14" viewBox="0 0 24 24" aria-hidden="true"><path d="M4 18L18 6" style="stroke-dasharray: 3 3"></path><path d="M12 6h6v6"></path></svg>
Orders
</button>
Expand Down
37 changes: 34 additions & 3 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ own library, which `build.zig.zon` pins, so it reads every mission exactly as th
| [`panels.zig`](../src/panels.zig) | The dockable panels: the outline, problems, the inspector and the others |
| [`forms.zig`](../src/forms.zig) | The inspector's forms: a record's fields as controls that write the source |
| [`views/script.zig`](../src/views/script.zig) | The Script view: the source, its gutter, help and completion, and the listing |
| [`views/scene.zig`](../src/views/scene.zig) | The Scene view: the map of the mission's ships and markers, its ranges, curves and routes, and moving them |
| [`views/scene/drawing.zig`](../src/views/scene/drawing.zig) | How the map draws its parts: the grid, rings, legs, marks, names and notes |
| [`palette.zig`](../src/palette.zig) | The command palette, Play from part, and the game's missions |
| [`screens/`](../src/screens) | The start screen and the settings |
| [`toasts.zig`](../src/toasts.zig) | Short messages that fade out |
| [`ui/`](../src/ui) | The interface kit: colours, fonts, icons, widgets, the text editor |
| [`ui/`](../src/ui) | The interface kit: colours, fonts, icons, widgets, the text editor, and the map's plot (ImPlot, through a C shim) |
| [`platform/`](../src/platform) | The window, SDL_GPU, ImGui's backends, and the C header the build translates |

## The game profile
Expand All @@ -41,6 +43,8 @@ profile, a `game.Profile`:
parameters, the game's variables, and the names of its values;
- the records a mission's source declares, for the outline and the inspector, the fields each
record's table can give, and the changes that edit them or declare a new record;
- what the map shows of a mission: where its records start and which way its ships point, the
ranges its triggers watch, and its curves;
- building source into a mission file, with the map of its script's statements to the source's
lines, decompiling a mission file into source, and comparing two missions and their scripts;
- the game's messages on the editor link, and the script's flags for a set of offsets;
Expand Down Expand Up @@ -80,6 +84,34 @@ are each on one. While drawing, the interface only queues the change (`Document.
makes it once the frame is drawn, since making it checks the text again, which replaces the outline
the frame drew from.

## The map

The Scene view's map draws on ImPlot, which gives it equal axes, the pointer's pan and dragging; the
editor reaches it through a C shim (`ui/plot/plot_shim.h`), as it reaches the text editor. The
editor zooms the map itself, around the pointer, and switches ImPlot's zoom off, since ImPlot
doesn't zoom while the pointer is over a marker.

The profile says what the map shows (`Profile.scene`). StarLancer's places each ship and marker by
its `position`, and says which are scenery: the planets of the original's table
(`create.planets.original`) and the sun's and nebulae's markers. It points a ship as OpenReliant
turns it by its angles (`mission.recordOrientation`), rings each ShipReached trigger's nav point or
waypoint at the 4000 the game watches within, rings each ship the script's `SetFlybackMarker`
names at its range, and draws each curve as the director's camera runs it
(`executor.curves.point`). It reads the routes from the script's syntax tree, in the order the
source gives it: the orders that `SetAI` gives, found by the command catalogue's parameters and
sorted by OpenReliant's order table (`ai.orders.Order`) into flying, jumping and coming in, and the
patrol routes `SetPatrolRoute` sets. A branch that leaves a ship in different places stops its
route. The document keeps the scene until its text or its outline changes, since reading it parses
the whole script.

The map fits the mission without its scenery, which lies far off. Each frame it gathers the things
that would overlap on the screen into one mark, the most important first: the selection, the player,
the ships, the markers, the camera's points and the scenery. Names then go in the same order, each
on the first side of its mark where it covers no mark and no name, and crosses no route where a side
is free. The map draws its own grid, so that its scale is always a cell, and draws only the part of
a range's ring or a route's leg that shows. A dragged ship or marker is queued as an edit of its
place, as the forms' edits are, when it's let go.

## The debugger

The debugger links to the game over OpenReliant's editor link ([Debugging a mission](debugging.md)).
Expand All @@ -99,8 +131,7 @@ profile (`Profile.link`), so that it never names StarLancer's tags or opcodes.

Each shows in the interface, greyed out, with its issue:

- the Scene view ([#2](https://github.com/OpenReliant/openreliant-editor/issues/2)) and the Blocks
view ([#3](https://github.com/OpenReliant/openreliant-editor/issues/3));
- the Blocks view ([#3](https://github.com/OpenReliant/openreliant-editor/issues/3));
- Mod mode, with Reload scripts and Play with this mod only
([#4](https://github.com/OpenReliant/openreliant-editor/issues/4));
- the debugger's conditions, log points, Watch, values inline and Debugging screen
Expand Down
56 changes: 56 additions & 0 deletions docs/editing.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,59 @@ A name the source uses without declaring it shows in the Problems panel with **D
a record under that name: choose what kind it is.

Squads, formations and curves list other records, and are written in the source.

## The map

The Scene view (Ctrl+2, or Cmd+2 on macOS) shows the mission's map. **Top**, **Side** and
**Front** look at it from above, from the side and from the front; the note in the map's corner
says which way its axes point. Ships show as arrows that point the way they start, and nav points,
waypoints and points, such as where ships jump in, as diamonds, in their flight groups' colours.
Planets, the sun and nebulae show as faint discs. The scale in the corner is one cell of the grid.

A mission opens fitted to its ships and markers, leaving out the planets and the sun, which lie far
off. Many of the game's missions take place in several areas millions of units apart, so they open
as an overview: things that would overlap on the screen show as one round mark with how many it
holds, named after its most important thing.

- Drag the map to move it, and scroll to zoom in and out around the pointer. **Fit**, or a double
click on an empty part of the map, shows the whole mission again.
- Point at a numbered mark to list what it holds, and click it to zoom in to them. Where its
things lie on the same spot, the click lists them instead, to pick one.
- Names go where they have room, the selection's and the player's first, and keep off the routes
where they can. Point at a mark to see a name that has no room.
- Click a ship or a marker to select it: the inspector shows it, and the map marks it with its
place. Drag it to move where it starts: its `position` changes in the source when you let go, as
one step of Undo. Hold Shift to snap to 100. A click on an empty part of the map clears the
selection.
- **Ranges** rings each nav point or waypoint a ShipReached trigger watches, at the 4000 the game
watches within, and dots a ring where the script sets a flyback marker, at its range.
**Curves** shows the curves the director's camera flies, with their points.
- **Routes** shows where the script sends each ship and flight group (see below).
- **Follow** keeps a ship in the middle of the map.
- Where the map doesn't show the player's start, a note at its edge points to it.

**Live** and **Orders** show where the ships are and what they do in the running game, and come
with the live scene ([#21](https://github.com/OpenReliant/openreliant-editor/issues/21)).

### Routes

A route links the places the script sends a ship or a flight group to, in its group's colour. A
dotted leg is one the ship flies (Fly and Escort), and a dashed leg one it jumps (Jump Out and Warp
Out). An arrowhead shows where each leg goes, and a small ring where the route starts. In an
overview, the player's route shows the order the mission visits its areas in.

- A route starts where its ship starts, or a group's where its first ship starts. A ship the script
brings in by a jump or a warp waits far off until then, so its route starts where it comes in.
- When a ship reaches a marker that a ShipReached trigger watches, the trigger's orders continue
its route from there.
- A patrol route (`SetPatrolRoute`) goes round its flight group's waypoints in the order the mission
lists them, and back to the first.
- Where an `if` sends a ship to different places, the route stops there, since either could be
where it is next.
- A leg to or from a place off the map is a short stub that points the way.
- Select a ship, a group or a marker to make the routes it's on stand out, and click an empty part
of the map to show them all alike again.

Routes read the script in the order the source gives its orders. A trigger runs when its condition
holds, so in the game a ship may take a route's legs in another order. The live scene will show
where ships really go.
Loading
Loading