@scm-js/plugin-api 1.30.0 → 1.32.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.d.ts +382 -140
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -816,74 +816,6 @@ export type TerrainPick = {
816
816
  kind: "tile";
817
817
  id: number;
818
818
  };
819
- export interface Diamond {
820
- x: number;
821
- y: number;
822
- }
823
- export interface IsomCheck {
824
- /** Rects that have tiles under them. */
825
- rects: number;
826
- /** Rects whose tiles are not what their ISOM resolves to (doodad tiles are excused). */
827
- mismatched: number;
828
- }
829
- /**
830
- * `checkIsom` with what a rebuild would do about it — the verdict the palette, Check Map
831
- * and the Repair plugin draw from.
832
- *
833
- * The two numbers measure opposite directions and are not inverses: `mismatched` is the
834
- * lattice failing to reproduce the tiles, while a rebuild votes a lattice out of the
835
- * tiles. A rebuild converges in one pass and leaves `inherent` behind for good, because
836
- * hand-placed tiles, blends and another editor's ground are not terrain any lattice
837
- * describes. Reporting `mismatched` alone therefore recommended a repair that could not
838
- * move the number, on every map with terrain like that.
839
- */
840
- export interface IsomReport extends IsomCheck {
841
- /** Of `mismatched`, the rects a rebuild would leave: terrain no lattice describes. */
842
- inherent: number;
843
- /** A rebuild would bring more than `STALE_ISOM_SHARE` of the rects back in step. */
844
- stale: boolean;
845
- }
846
- export interface LocationStringChange {
847
- index: number;
848
- before: string | null;
849
- after: string | null;
850
- }
851
- export interface LocationChange {
852
- index: number;
853
- before: LocationRecord;
854
- after: LocationRecord;
855
- /** A string slot the edit adds (a name no existing string matched); removed again on undo. */
856
- string?: LocationStringChange;
857
- }
858
- export interface Bounds {
859
- left: number;
860
- top: number;
861
- right: number;
862
- bottom: number;
863
- }
864
- export interface LocationPatch {
865
- name?: string;
866
- left?: number;
867
- top?: number;
868
- right?: number;
869
- bottom?: number;
870
- elevationFlags?: number;
871
- }
872
- export type FogMode = "fog" | "clear";
873
- export interface SpriteChange {
874
- index: number;
875
- before: SpriteRecord | null;
876
- after: SpriteRecord | null;
877
- }
878
- export type SpriteKind = "pure" | "unit";
879
- /** Unit type catalogue: StarEdit names by units.dat id, and the palette's grouping of them. */
880
- export type RaceKey = "terran" | "zerg" | "protoss" | "neutral";
881
- export interface UnitGroup {
882
- race: RaceKey;
883
- label: string;
884
- /** units.dat ids, in palette order. */
885
- units: number[];
886
- }
887
819
  export interface UnitsDat {
888
820
  /** flingy.dat index. */
889
821
  flingy: Uint8Array;
@@ -975,6 +907,164 @@ export interface TechdataDat {
975
907
  /** The technology's name: a 1-based `stat_txt.tbl` index, 0 for none. */
976
908
  label: Uint16Array;
977
909
  }
910
+ /**
911
+ * Unit edits as invertible change lists, in the same spirit as terrain's `TileChange`.
912
+ * `before`/`after` are whole records: null `before` is an insertion at `index`, null
913
+ * `after` a removal, both set a replacement. Removals are listed highest index first so
914
+ * that applying them in order keeps the remaining indices valid; undo walks the list
915
+ * backwards and so re-inserts lowest first.
916
+ */
917
+ export interface UnitChange {
918
+ index: number;
919
+ before: UnitRecord | null;
920
+ after: UnitRecord | null;
921
+ }
922
+ export interface SpriteChange {
923
+ index: number;
924
+ before: SpriteRecord | null;
925
+ after: SpriteRecord | null;
926
+ }
927
+ export type SpriteKind = "pure" | "unit";
928
+ export interface DoodadChange {
929
+ index: number;
930
+ before: DoodadRecord | null;
931
+ after: DoodadRecord | null;
932
+ }
933
+ export interface DoodadPlacementOptions {
934
+ /** Skip StarEdit's ground check: any doodad goes on any terrain, even over another doodad. */
935
+ placeAnywhere: boolean;
936
+ /** Keep the left column on an even tile, as StarEdit always does. */
937
+ snapToGrid: boolean;
938
+ /** Place as plain terrain: the tiles (both sections) and any overlay sprite, no DD2 record — a placement and a conversion in one. */
939
+ asTerrain: boolean;
940
+ }
941
+ export interface DoodadVerdict {
942
+ ok: boolean;
943
+ /** The footprint leaves the map (never allowed). */
944
+ outOfBounds: boolean;
945
+ /** Cell indices (row-major) whose ground fails the check, for the ghost to mark red. */
946
+ bad: number[];
947
+ }
948
+ export interface LocationStringChange {
949
+ index: number;
950
+ before: string | null;
951
+ after: string | null;
952
+ }
953
+ export interface LocationChange {
954
+ index: number;
955
+ before: LocationRecord;
956
+ after: LocationRecord;
957
+ /** A string slot the edit adds (a name no existing string matched); removed again on undo. */
958
+ string?: LocationStringChange;
959
+ }
960
+ export interface Bounds {
961
+ left: number;
962
+ top: number;
963
+ right: number;
964
+ bottom: number;
965
+ }
966
+ export interface LocationPatch {
967
+ name?: string;
968
+ left?: number;
969
+ top?: number;
970
+ right?: number;
971
+ bottom?: number;
972
+ elevationFlags?: number;
973
+ }
974
+ /** The change lists of one edit; `HistoryEntry` adds the label. */
975
+ export interface HistoryEdit {
976
+ changes: TileChange[];
977
+ /** The isometric brush's changes to `scenario.isom`, undone together with the tiles. */
978
+ isom?: TileChange[];
979
+ /**
980
+ * Set when the edit gave a map an ISOM section it did not have (Rebuild ISOM). Undo
981
+ * removes the section again rather than leaving an all-zero one behind.
982
+ */
983
+ createdIsom?: Uint16Array;
984
+ /**
985
+ * Set when the edit rebuilt an existing lattice from the tiles, which is the one edit
986
+ * to `isom` the ISOM health is re-measured after: a brush stroke keeps the two in step
987
+ * by construction and is deliberately not measured (`useIsomStatus`), and measuring
988
+ * costs a second rebuild.
989
+ */
990
+ rebuiltIsom?: boolean;
991
+ /** Unit placements, moves and deletions (see editor/units.ts). */
992
+ units?: UnitChange[];
993
+ /**
994
+ * Doodad tiles stamped into or lifted off MTXM alone — TILE keeps the ground beneath
995
+ * (see editor/doodads.ts). Applied after `changes`, so a terrain stroke that removes
996
+ * the doodads it painted over restores their remaining cells on top of its own edit.
997
+ */
998
+ doodadTiles?: TileChange[];
999
+ /** DD2 record insertions, removals and replacements. */
1000
+ doodads?: DoodadChange[];
1001
+ /** THG2 record changes: the Sprites layer's edits, and a doodad's overlay sprite coming and going with it. */
1002
+ sprites?: SpriteChange[];
1003
+ /** MRGN slot replacements — create, move, resize, rename, delete (see editor/locations.ts); a rename may carry a string. */
1004
+ locations?: LocationChange[];
1005
+ /** Fog of war edits to `scenario.mask` (see editor/fog.ts); `at` indexes the MASK byte. */
1006
+ fog?: TileChange[];
1007
+ /**
1008
+ * Set when the edit gave a map a MASK section it did not have (the first fog stroke
1009
+ * on such a map). Undo removes the section again.
1010
+ */
1011
+ createdMask?: Uint8Array;
1012
+ }
1013
+ /**
1014
+ * Why the map changed: an edit recorded in the history, an undo or redo of one, a dialog
1015
+ * writing its tables (settings, triggers, strings — outside the history), a change to the
1016
+ * whole document (resize, tileset change, raw section edit), or other people's edits on a
1017
+ * shared map.
1018
+ */
1019
+ export type CommitReason = "edit" | "undo" | "redo" | "tables" | "whole" | "remote";
1020
+ /** Which parts of the map one commit touched. */
1021
+ export interface CommitParts {
1022
+ terrain: boolean;
1023
+ isom: boolean;
1024
+ units: boolean;
1025
+ doodads: boolean;
1026
+ sprites: boolean;
1027
+ locations: boolean;
1028
+ fog: boolean;
1029
+ settings: boolean;
1030
+ triggers: boolean;
1031
+ }
1032
+ export interface Diamond {
1033
+ x: number;
1034
+ y: number;
1035
+ }
1036
+ export interface IsomCheck {
1037
+ /** Rects that have tiles under them. */
1038
+ rects: number;
1039
+ /** Rects whose tiles are not what their ISOM resolves to (doodad tiles are excused). */
1040
+ mismatched: number;
1041
+ }
1042
+ /**
1043
+ * `checkIsom` with what a rebuild would do about it — the verdict the palette, Check Map
1044
+ * and the Repair plugin draw from.
1045
+ *
1046
+ * The two numbers measure opposite directions and are not inverses: `mismatched` is the
1047
+ * lattice failing to reproduce the tiles, while a rebuild votes a lattice out of the
1048
+ * tiles. A rebuild converges in one pass and leaves `inherent` behind for good, because
1049
+ * hand-placed tiles, blends and another editor's ground are not terrain any lattice
1050
+ * describes. Reporting `mismatched` alone therefore recommended a repair that could not
1051
+ * move the number, on every map with terrain like that.
1052
+ */
1053
+ export interface IsomReport extends IsomCheck {
1054
+ /** Of `mismatched`, the rects a rebuild would leave: terrain no lattice describes. */
1055
+ inherent: number;
1056
+ /** A rebuild would bring more than `STALE_ISOM_SHARE` of the rects back in step. */
1057
+ stale: boolean;
1058
+ }
1059
+ export type FogMode = "fog" | "clear";
1060
+ /** Unit type catalogue: StarEdit names by units.dat id, and the palette's grouping of them. */
1061
+ export type RaceKey = "terran" | "zerg" | "protoss" | "neutral";
1062
+ export interface UnitGroup {
1063
+ race: RaceKey;
1064
+ label: string;
1065
+ /** units.dat ids, in palette order. */
1066
+ units: number[];
1067
+ }
978
1068
  export interface SpriteGroup {
979
1069
  label: string;
980
1070
  ids: number[];
@@ -1349,18 +1439,6 @@ export interface StringUsage {
1349
1439
  ref: number;
1350
1440
  label: string;
1351
1441
  }
1352
- /**
1353
- * Unit edits as invertible change lists, in the same spirit as terrain's `TileChange`.
1354
- * `before`/`after` are whole records: null `before` is an insertion at `index`, null
1355
- * `after` a removal, both set a replacement. Removals are listed highest index first so
1356
- * that applying them in order keeps the remaining indices valid; undo walks the list
1357
- * backwards and so re-inserts lowest first.
1358
- */
1359
- export interface UnitChange {
1360
- index: number;
1361
- before: UnitRecord | null;
1362
- after: UnitRecord | null;
1363
- }
1364
1442
  export interface PlacementOptions {
1365
1443
  /** Refuse to put a unit on top of another (ground units and buildings only). */
1366
1444
  checkCollision: boolean;
@@ -1694,27 +1772,102 @@ export interface ChangeTilesetResult {
1694
1772
  spritesDropped: number;
1695
1773
  refilled: boolean;
1696
1774
  }
1697
- export type SymmetryMode = "none" | "h" | "v" | "hv" | "rot180" | "rot90" | "diag" | "adiag";
1698
- export interface DoodadChange {
1775
+ export interface WireListChange<T> {
1699
1776
  index: number;
1700
- before: DoodadRecord | null;
1701
- after: DoodadRecord | null;
1777
+ before: T | null;
1778
+ after: T | null;
1702
1779
  }
1703
- export interface DoodadPlacementOptions {
1704
- /** Skip StarEdit's ground check: any doodad goes on any terrain, even over another doodad. */
1705
- placeAnywhere: boolean;
1706
- /** Keep the left column on an even tile, as StarEdit always does. */
1707
- snapToGrid: boolean;
1708
- /** Place as plain terrain: the tiles (both sections) and any overlay sprite, no DD2 record — a placement and a conversion in one. */
1709
- asTerrain: boolean;
1780
+ export interface WireLocationChange {
1781
+ index: number;
1782
+ after: LocationRecord;
1783
+ /** The name as text (`after.nameIndex` is resolved again where it lands); null for none. */
1784
+ name: string | null;
1785
+ /** The slot was empty before: a new location, which moves to a free slot if someone else took this one. */
1786
+ created: boolean;
1710
1787
  }
1711
- export interface DoodadVerdict {
1712
- ok: boolean;
1713
- /** The footprint leaves the map (never allowed). */
1714
- outOfBounds: boolean;
1715
- /** Cell indices (row-major) whose ground fails the check, for the ghost to mark red. */
1716
- bad: number[];
1788
+ /**
1789
+ * One undo step's worth of terrain and objects. The grids are flat number lists: terrain
1790
+ * `[at, mtxm, tile, …]`, the others `[at, value, …]`. `reverse` marks the undo of an edit:
1791
+ * its parts go in the reverse of the usual order, as undo walks them.
1792
+ */
1793
+ export interface SyncEditOp {
1794
+ kind: "edit";
1795
+ label: string;
1796
+ /** The map size the cells index; a grid part is skipped on a map of another size. */
1797
+ width: number;
1798
+ height: number;
1799
+ reverse?: boolean;
1800
+ terrain?: number[];
1801
+ isom?: number[];
1802
+ doodadTiles?: number[];
1803
+ fog?: number[];
1804
+ /** The whole ISOM lattice (base64 of the u16 cells) the edit gave the map, or null for taking it away. */
1805
+ isomWhole?: string | null;
1806
+ maskWhole?: string | null;
1807
+ units?: WireListChange<UnitRecord>[];
1808
+ doodads?: WireListChange<DoodadRecord>[];
1809
+ sprites?: WireListChange<SpriteRecord>[];
1810
+ locations?: WireLocationChange[];
1811
+ }
1812
+ declare const SYNC_FIELDS: readonly [
1813
+ "type",
1814
+ "fileVersion",
1815
+ "nameIndex",
1816
+ "descriptionIndex",
1817
+ "playerTypes",
1818
+ "editorPlayerTypes",
1819
+ "playerRaces",
1820
+ "playerColors",
1821
+ "playerRgb",
1822
+ "forces",
1823
+ "unitSettings",
1824
+ "unitAvailability",
1825
+ "upgradeSettings",
1826
+ "upgradeRestrictions",
1827
+ "techSettings",
1828
+ "techRestrictions",
1829
+ "wavs",
1830
+ "cuwp",
1831
+ "cuwpUsed",
1832
+ "triggers",
1833
+ "briefing",
1834
+ "switchNames"
1835
+ ];
1836
+ export type SyncField = (typeof SYNC_FIELDS)[number];
1837
+ export interface SyncFieldsOp {
1838
+ kind: "fields";
1839
+ /** Each changed field's new value, packed (`pack`). */
1840
+ set: Partial<Record<SyncField, unknown>>;
1841
+ /** String slots that changed: `[index, before, after]`. */
1842
+ strings?: [
1843
+ number,
1844
+ string | null,
1845
+ string | null
1846
+ ][];
1847
+ /** The table's length afterwards (trailing blank slots are dropped). */
1848
+ stringsLength?: number;
1849
+ /** The table's width and text encoding, when they changed. */
1850
+ stringsFormat?: {
1851
+ extended: boolean;
1852
+ encoding: TextEncoding;
1853
+ };
1717
1854
  }
1855
+ export interface SyncExtrasOp {
1856
+ kind: "extras";
1857
+ /** `[member name, base64 bytes]`, or null bytes for a member taken out. */
1858
+ set: [
1859
+ string,
1860
+ string | null
1861
+ ][];
1862
+ }
1863
+ export interface SyncResetOp {
1864
+ kind: "reset";
1865
+ label: string;
1866
+ /** The whole scenario, base64. */
1867
+ chk: string;
1868
+ }
1869
+ export type SyncOp = SyncEditOp | SyncFieldsOp | SyncExtrasOp | SyncResetOp;
1870
+ export type SymmetryMode = "none" | "h" | "v" | "hv" | "rot180" | "rot90" | "diag" | "adiag";
1718
1871
  export type StartLayout = "ring" | "corners";
1719
1872
  export interface StartPlacementResult {
1720
1873
  changes: UnitChange[];
@@ -1741,45 +1894,6 @@ export interface BlendOptions {
1741
1894
  /** Optional filter over tile ids (the palette's group-kind dropdown). */
1742
1895
  include?: (id: number) => boolean;
1743
1896
  }
1744
- /** The change lists of one edit; `HistoryEntry` adds the label. */
1745
- export interface HistoryEdit {
1746
- changes: TileChange[];
1747
- /** The isometric brush's changes to `scenario.isom`, undone together with the tiles. */
1748
- isom?: TileChange[];
1749
- /**
1750
- * Set when the edit gave a map an ISOM section it did not have (Rebuild ISOM). Undo
1751
- * removes the section again rather than leaving an all-zero one behind.
1752
- */
1753
- createdIsom?: Uint16Array;
1754
- /**
1755
- * Set when the edit rebuilt an existing lattice from the tiles, which is the one edit
1756
- * to `isom` the ISOM health is re-measured after: a brush stroke keeps the two in step
1757
- * by construction and is deliberately not measured (`useIsomStatus`), and measuring
1758
- * costs a second rebuild.
1759
- */
1760
- rebuiltIsom?: boolean;
1761
- /** Unit placements, moves and deletions (see editor/units.ts). */
1762
- units?: UnitChange[];
1763
- /**
1764
- * Doodad tiles stamped into or lifted off MTXM alone — TILE keeps the ground beneath
1765
- * (see editor/doodads.ts). Applied after `changes`, so a terrain stroke that removes
1766
- * the doodads it painted over restores their remaining cells on top of its own edit.
1767
- */
1768
- doodadTiles?: TileChange[];
1769
- /** DD2 record insertions, removals and replacements. */
1770
- doodads?: DoodadChange[];
1771
- /** THG2 record changes: the Sprites layer's edits, and a doodad's overlay sprite coming and going with it. */
1772
- sprites?: SpriteChange[];
1773
- /** MRGN slot replacements — create, move, resize, rename, delete (see editor/locations.ts); a rename may carry a string. */
1774
- locations?: LocationChange[];
1775
- /** Fog of war edits to `scenario.mask` (see editor/fog.ts); `at` indexes the MASK byte. */
1776
- fog?: TileChange[];
1777
- /**
1778
- * Set when the edit gave a map a MASK section it did not have (the first fog stroke
1779
- * on such a map). Undo removes the section again.
1780
- */
1781
- createdMask?: Uint8Array;
1782
- }
1783
1897
  export type ClipPart = "terrain" | "doodads" | "units" | "sprites" | "locations" | "fog";
1784
1898
  export type ClipParts = Record<ClipPart, boolean>;
1785
1899
  /** Whether a paste adds to what is in the target area or clears its objects first. */
@@ -2121,6 +2235,13 @@ export interface PluginApi {
2121
2235
  /** The plugin's words in the editor's language: its own catalogues, and a `t` over them. */
2122
2236
  readonly i18n: I18nApi;
2123
2237
  readonly events: EventsApi;
2238
+ /**
2239
+ * Editing the map in front together with other editors: every change to it is handed out
2240
+ * as an op for the plugin to carry to them, and theirs come back in, in the order a
2241
+ * server puts them. The scmjs.dev plugin's shared maps are built on it; the transport,
2242
+ * the server and who may join are the plugin's.
2243
+ */
2244
+ readonly sync: SyncApi;
2124
2245
  /**
2125
2246
  * A small key-value store of the plugin's own, kept in the browser's local storage under
2126
2247
  * the plugin's id and listed with everything else in Preferences ▸ Browser storage.
@@ -3308,8 +3429,9 @@ export interface GraphicsApi {
3308
3429
  * overlays with the viewport's own graphics, then location boxes — a thumbnail for a
3309
3430
  * list of clips, or the ghost under the pointer while a plugin stamps one. It is drawn
3310
3431
  * with the graphics of the clip's *own* tileset (`clip.era`), which are in memory for
3311
- * the open map once loaded and otherwise not, so a clip from another tileset answers
3312
- * null; so does a missing tileset or a page with no canvas. Synchronous and uncached:
3432
+ * the open map once loaded; a clip from another tileset answers null until
3433
+ * `tileset.load(id)` has fetched that one. So does a missing tileset or a page with no
3434
+ * canvas. Synchronous and uncached:
3313
3435
  * keep the result while the clip and the tileset stay the same.
3314
3436
  */
3315
3437
  renderClip(clip: Clip, options?: RenderClipOptions): PluginImage | null;
@@ -3670,8 +3792,14 @@ export interface TilesetApi {
3670
3792
  id(): TilesetId | null;
3671
3793
  name(): string;
3672
3794
  isLoaded(): boolean;
3673
- /** Fetch and decode the graphics; resolves false when they were never extracted. */
3674
- load(): Promise<boolean>;
3795
+ /**
3796
+ * Fetch and decode the graphics — the open map's tileset's, or `tileset`'s — and keep
3797
+ * them in memory; resolves false when they were never extracted. Loading another
3798
+ * tileset changes nothing about the map: it is for `graphics.renderClip` drawing a clip
3799
+ * that came from a map on that tileset (a stamp, a recording), which answers null until
3800
+ * its tileset's graphics are loaded.
3801
+ */
3802
+ load(tileset?: TilesetId): Promise<boolean>;
3675
3803
  raw(): LoadedTileset | null;
3676
3804
  }
3677
3805
  export interface SelectionApi {
@@ -4317,6 +4445,11 @@ export interface PickFilesOptions {
4317
4445
  multiple?: boolean;
4318
4446
  }
4319
4447
  export interface UiApi {
4448
+ /**
4449
+ * The dialogs open now, bottom to top, by id: the built-in ones by their `DialogId`, a
4450
+ * plugin's as `"pluginDialog"`. What a shared map shows others ("in Player Settings").
4451
+ */
4452
+ openDialogs(): string[];
4320
4453
  /** Set the status bar line. */
4321
4454
  status(text: string): void;
4322
4455
  /** The status bar line as it stands. */
@@ -4840,6 +4973,8 @@ export interface HotkeyApi {
4840
4973
  export type PluginEvent =
4841
4974
  /** A map was opened, closed or replaced. */
4842
4975
  "document"
4976
+ /** A change was committed to the map in front; the listener gets a `CommitEvent` saying what and where. */
4977
+ | "commit"
4843
4978
  /** The editor's language changed (Preferences ▸ Display): re-label what is showing through `api.i18n.t`. */
4844
4979
  | "language"
4845
4980
  /** Any committed edit (every `document.edit`, stroke, undo and redo bumps it, terrain or not), and a fog edit. */
@@ -4864,8 +4999,113 @@ export type PluginEvent =
4864
4999
  | "commands"
4865
5000
  /** A plugin provided or withdrew a service — `services.watch` is the usual way to hear this for one name. */
4866
5001
  | "services"
5002
+ /** A dialog opened or closed — `ui.openDialogs()` says which are open. */
5003
+ | "dialogs"
4867
5004
  /** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
4868
5005
  | "gameData";
5006
+ /**
5007
+ * What the `"commit"` event hands its listeners: one change to the map in front, after it
5008
+ * is in the scenario. Every stroke, `document.edit`, undo and redo is one commit; so is a
5009
+ * dialog's OK or a `document.update` (reason `"tables"`), a resize, tileset change or raw
5010
+ * section edit (`"whole"`), and a batch of other people's edits on a shared map
5011
+ * (`"remote"`). A dialog that writes both settings and triggers may send two. Opening,
5012
+ * closing and switching maps are not commits — the `"document"` event says those.
5013
+ *
5014
+ * @example
5015
+ * api.events.on("commit", (e) => {
5016
+ * if (e.parts.terrain && e.area) redrawTiles(e.area);
5017
+ * else if (e.reason === "whole" || e.reason === "remote") redrawAll();
5018
+ * });
5019
+ */
5020
+ export interface CommitEvent {
5021
+ /** `document.id()` of the map it happened to (always the one in front). */
5022
+ id: number | null;
5023
+ reason: CommitReason;
5024
+ /**
5025
+ * The history label — the words Edit ▸ Undo shows, in the editor's language; for an undo
5026
+ * or redo, the label of the entry taken back or put back. The update's label for a
5027
+ * `document.update`, the operation's name for `"whole"`, and "" for a built-in dialog's
5028
+ * OK and for other people's edits.
5029
+ */
5030
+ label: string;
5031
+ /**
5032
+ * The tiles the change fell on, far edges exclusive: every changed tile, and the tile
5033
+ * under each moved, placed or removed object's position (its picture reaches further —
5034
+ * widen the rect by the largest picture you draw). Null when the change has no place on
5035
+ * the map (`"tables"`) or may have touched all of it (`"whole"`, `"remote"`).
5036
+ */
5037
+ area: Rect | null;
5038
+ /** Which parts changed. All of them for `"whole"` and `"remote"`, which do not say. */
5039
+ parts: CommitParts;
5040
+ }
5041
+ /** Why other people's changes are waiting: a stroke under way on the map, a dialog that edits the map open, another map in front. */
5042
+ export type SyncHold = "stroke" | "dialog" | "behind";
5043
+ export interface SyncReport {
5044
+ /** Other people's ops applied. */
5045
+ ops: number;
5046
+ /** Parts of them that could not be applied — the unit they moved was deleted, the map was resized… */
5047
+ dropped: number;
5048
+ /** Parts of this editor's unconfirmed changes that no longer applied on top of theirs. */
5049
+ lost: number;
5050
+ }
5051
+ export interface SyncStartOptions {
5052
+ /**
5053
+ * Every change made to the shared map, as a plain object JSON can carry, in the order
5054
+ * made: commits, undo and redo, the dialogs' writes, archive files, and a resize or a
5055
+ * tileset change (the whole scenario). Each must reach the server, and every other
5056
+ * editor, in this order.
5057
+ */
5058
+ send(op: SyncOp): void;
5059
+ /** The session ended: the shared map was closed or replaced by another, or `stop` was called. */
5060
+ onEnd?(reason: "closed" | "stopped"): void;
5061
+ /** Other people's changes were applied to the map. */
5062
+ onApplied?(report: SyncReport): void;
5063
+ }
5064
+ /**
5065
+ * One shared map. The server confirms each op this editor sent (`confirm`, in order) and
5066
+ * relays everyone else's (`receive`, in the order it gave them); the session applies
5067
+ * them to the map when nothing is in the way (`holding`) and rebases this editor's
5068
+ * unconfirmed changes on top, so every editor that has seen the same ops has the same map.
5069
+ *
5070
+ * @example
5071
+ * const session = api.sync.start({ send: (op) => socket.send(JSON.stringify({ type: "op", op })) });
5072
+ * socket.onmessage = (m) => {
5073
+ * const msg = JSON.parse(m.data);
5074
+ * if (msg.type === "ack") session?.confirm();
5075
+ * if (msg.type === "op") session?.receive(msg.op);
5076
+ * };
5077
+ */
5078
+ export interface SyncSession {
5079
+ /** The shared map's `document.id()`. */
5080
+ readonly documentId: number;
5081
+ /** Another editor's op, in the server's order. False, and nothing done, for a value that is not an op. */
5082
+ receive(op: unknown): boolean;
5083
+ /** The server confirmed the oldest op this editor sent. */
5084
+ confirm(): void;
5085
+ /** Ops sent and not yet confirmed. */
5086
+ pending(): number;
5087
+ /** Ops and confirmations received and not yet applied. */
5088
+ waiting(): number;
5089
+ /**
5090
+ * The shared map as a file (`.scx` / `.scm`, not built), copied at this moment — for a
5091
+ * server to hand people joining, labelled with the last op this editor applied. Null
5092
+ * while anything is pending or waiting (the copy would not match any point in the
5093
+ * server's order) or while another map is in front. The copy is taken before the first
5094
+ * `await`, so a change made while the file is written is not in it.
5095
+ */
5096
+ snapshot(): Promise<Uint8Array | null>;
5097
+ holding(): SyncHold | null;
5098
+ stop(): void;
5099
+ }
5100
+ export interface SyncApi {
5101
+ /**
5102
+ * Share the map in front. Null when no map is open or another session is running (one
5103
+ * at a time). A session a plugin started stops when the plugin is turned off.
5104
+ */
5105
+ start(options: SyncStartOptions): SyncSession | null;
5106
+ /** The running session, whichever plugin started it. */
5107
+ current(): SyncSession | null;
5108
+ }
4869
5109
  /** Why the document changed. */
4870
5110
  export type DocumentChangeReason =
4871
5111
  /** File ▸ Open, drag-and-drop, `document.open`: a file the user chose. */
@@ -4924,8 +5164,10 @@ export interface EventsApi {
4924
5164
  * if (e.reason === "open") check(e.fileName);
4925
5165
  * });
4926
5166
  * api.events.on("terrain", () => redraw());
5167
+ * api.events.on("commit", (e) => console.log(e.reason, e.label, e.area));
4927
5168
  */
4928
5169
  on(event: "document", listener: (event: DocumentEvent) => void): Disposable;
5170
+ on(event: "commit", listener: (event: CommitEvent) => void): Disposable;
4929
5171
  on(event: PluginEvent, listener: () => void): Disposable;
4930
5172
  }
4931
5173
  export interface StorageApi {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.30.0",
3
+ "version": "1.32.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",