@scm-js/plugin-api 1.30.0 → 1.31.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.
- package/index.d.ts +204 -27
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -1694,7 +1694,6 @@ export interface ChangeTilesetResult {
|
|
|
1694
1694
|
spritesDropped: number;
|
|
1695
1695
|
refilled: boolean;
|
|
1696
1696
|
}
|
|
1697
|
-
export type SymmetryMode = "none" | "h" | "v" | "hv" | "rot180" | "rot90" | "diag" | "adiag";
|
|
1698
1697
|
export interface DoodadChange {
|
|
1699
1698
|
index: number;
|
|
1700
1699
|
before: DoodadRecord | null;
|
|
@@ -1715,32 +1714,6 @@ export interface DoodadVerdict {
|
|
|
1715
1714
|
/** Cell indices (row-major) whose ground fails the check, for the ghost to mark red. */
|
|
1716
1715
|
bad: number[];
|
|
1717
1716
|
}
|
|
1718
|
-
export type StartLayout = "ring" | "corners";
|
|
1719
|
-
export interface StartPlacementResult {
|
|
1720
|
-
changes: UnitChange[];
|
|
1721
|
-
/** Per player (0-based), where the start location landed, or null when nothing within reach fit. */
|
|
1722
|
-
placed: ({
|
|
1723
|
-
x: number;
|
|
1724
|
-
y: number;
|
|
1725
|
-
} | null)[];
|
|
1726
|
-
removed: number;
|
|
1727
|
-
}
|
|
1728
|
-
export type Side = "left" | "top" | "right" | "bottom";
|
|
1729
|
-
export interface BlendCandidate {
|
|
1730
|
-
/** MTXM tile id to place. */
|
|
1731
|
-
id: number;
|
|
1732
|
-
megatile: number;
|
|
1733
|
-
/** `edgeDistance` between the anchor's side and this tile's opposite side. */
|
|
1734
|
-
distance: number;
|
|
1735
|
-
}
|
|
1736
|
-
export interface BlendOptions {
|
|
1737
|
-
/** Largest distance still listed. */
|
|
1738
|
-
maxDistance: number;
|
|
1739
|
-
/** Most candidates listed per side. */
|
|
1740
|
-
limit: number;
|
|
1741
|
-
/** Optional filter over tile ids (the palette's group-kind dropdown). */
|
|
1742
|
-
include?: (id: number) => boolean;
|
|
1743
|
-
}
|
|
1744
1717
|
/** The change lists of one edit; `HistoryEntry` adds the label. */
|
|
1745
1718
|
export interface HistoryEdit {
|
|
1746
1719
|
changes: TileChange[];
|
|
@@ -1780,6 +1753,128 @@ export interface HistoryEdit {
|
|
|
1780
1753
|
*/
|
|
1781
1754
|
createdMask?: Uint8Array;
|
|
1782
1755
|
}
|
|
1756
|
+
export interface WireListChange<T> {
|
|
1757
|
+
index: number;
|
|
1758
|
+
before: T | null;
|
|
1759
|
+
after: T | null;
|
|
1760
|
+
}
|
|
1761
|
+
export interface WireLocationChange {
|
|
1762
|
+
index: number;
|
|
1763
|
+
after: LocationRecord;
|
|
1764
|
+
/** The name as text (`after.nameIndex` is resolved again where it lands); null for none. */
|
|
1765
|
+
name: string | null;
|
|
1766
|
+
/** The slot was empty before: a new location, which moves to a free slot if someone else took this one. */
|
|
1767
|
+
created: boolean;
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* One undo step's worth of terrain and objects. The grids are flat number lists: terrain
|
|
1771
|
+
* `[at, mtxm, tile, …]`, the others `[at, value, …]`. `reverse` marks the undo of an edit:
|
|
1772
|
+
* its parts go in the reverse of the usual order, as undo walks them.
|
|
1773
|
+
*/
|
|
1774
|
+
export interface SyncEditOp {
|
|
1775
|
+
kind: "edit";
|
|
1776
|
+
label: string;
|
|
1777
|
+
/** The map size the cells index; a grid part is skipped on a map of another size. */
|
|
1778
|
+
width: number;
|
|
1779
|
+
height: number;
|
|
1780
|
+
reverse?: boolean;
|
|
1781
|
+
terrain?: number[];
|
|
1782
|
+
isom?: number[];
|
|
1783
|
+
doodadTiles?: number[];
|
|
1784
|
+
fog?: number[];
|
|
1785
|
+
/** The whole ISOM lattice (base64 of the u16 cells) the edit gave the map, or null for taking it away. */
|
|
1786
|
+
isomWhole?: string | null;
|
|
1787
|
+
maskWhole?: string | null;
|
|
1788
|
+
units?: WireListChange<UnitRecord>[];
|
|
1789
|
+
doodads?: WireListChange<DoodadRecord>[];
|
|
1790
|
+
sprites?: WireListChange<SpriteRecord>[];
|
|
1791
|
+
locations?: WireLocationChange[];
|
|
1792
|
+
}
|
|
1793
|
+
declare const SYNC_FIELDS: readonly [
|
|
1794
|
+
"type",
|
|
1795
|
+
"fileVersion",
|
|
1796
|
+
"nameIndex",
|
|
1797
|
+
"descriptionIndex",
|
|
1798
|
+
"playerTypes",
|
|
1799
|
+
"editorPlayerTypes",
|
|
1800
|
+
"playerRaces",
|
|
1801
|
+
"playerColors",
|
|
1802
|
+
"playerRgb",
|
|
1803
|
+
"forces",
|
|
1804
|
+
"unitSettings",
|
|
1805
|
+
"unitAvailability",
|
|
1806
|
+
"upgradeSettings",
|
|
1807
|
+
"upgradeRestrictions",
|
|
1808
|
+
"techSettings",
|
|
1809
|
+
"techRestrictions",
|
|
1810
|
+
"wavs",
|
|
1811
|
+
"cuwp",
|
|
1812
|
+
"cuwpUsed",
|
|
1813
|
+
"triggers",
|
|
1814
|
+
"briefing",
|
|
1815
|
+
"switchNames"
|
|
1816
|
+
];
|
|
1817
|
+
export type SyncField = (typeof SYNC_FIELDS)[number];
|
|
1818
|
+
export interface SyncFieldsOp {
|
|
1819
|
+
kind: "fields";
|
|
1820
|
+
/** Each changed field's new value, packed (`pack`). */
|
|
1821
|
+
set: Partial<Record<SyncField, unknown>>;
|
|
1822
|
+
/** String slots that changed: `[index, before, after]`. */
|
|
1823
|
+
strings?: [
|
|
1824
|
+
number,
|
|
1825
|
+
string | null,
|
|
1826
|
+
string | null
|
|
1827
|
+
][];
|
|
1828
|
+
/** The table's length afterwards (trailing blank slots are dropped). */
|
|
1829
|
+
stringsLength?: number;
|
|
1830
|
+
/** The table's width and text encoding, when they changed. */
|
|
1831
|
+
stringsFormat?: {
|
|
1832
|
+
extended: boolean;
|
|
1833
|
+
encoding: TextEncoding;
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
export interface SyncExtrasOp {
|
|
1837
|
+
kind: "extras";
|
|
1838
|
+
/** `[member name, base64 bytes]`, or null bytes for a member taken out. */
|
|
1839
|
+
set: [
|
|
1840
|
+
string,
|
|
1841
|
+
string | null
|
|
1842
|
+
][];
|
|
1843
|
+
}
|
|
1844
|
+
export interface SyncResetOp {
|
|
1845
|
+
kind: "reset";
|
|
1846
|
+
label: string;
|
|
1847
|
+
/** The whole scenario, base64. */
|
|
1848
|
+
chk: string;
|
|
1849
|
+
}
|
|
1850
|
+
export type SyncOp = SyncEditOp | SyncFieldsOp | SyncExtrasOp | SyncResetOp;
|
|
1851
|
+
export type SymmetryMode = "none" | "h" | "v" | "hv" | "rot180" | "rot90" | "diag" | "adiag";
|
|
1852
|
+
export type StartLayout = "ring" | "corners";
|
|
1853
|
+
export interface StartPlacementResult {
|
|
1854
|
+
changes: UnitChange[];
|
|
1855
|
+
/** Per player (0-based), where the start location landed, or null when nothing within reach fit. */
|
|
1856
|
+
placed: ({
|
|
1857
|
+
x: number;
|
|
1858
|
+
y: number;
|
|
1859
|
+
} | null)[];
|
|
1860
|
+
removed: number;
|
|
1861
|
+
}
|
|
1862
|
+
export type Side = "left" | "top" | "right" | "bottom";
|
|
1863
|
+
export interface BlendCandidate {
|
|
1864
|
+
/** MTXM tile id to place. */
|
|
1865
|
+
id: number;
|
|
1866
|
+
megatile: number;
|
|
1867
|
+
/** `edgeDistance` between the anchor's side and this tile's opposite side. */
|
|
1868
|
+
distance: number;
|
|
1869
|
+
}
|
|
1870
|
+
export interface BlendOptions {
|
|
1871
|
+
/** Largest distance still listed. */
|
|
1872
|
+
maxDistance: number;
|
|
1873
|
+
/** Most candidates listed per side. */
|
|
1874
|
+
limit: number;
|
|
1875
|
+
/** Optional filter over tile ids (the palette's group-kind dropdown). */
|
|
1876
|
+
include?: (id: number) => boolean;
|
|
1877
|
+
}
|
|
1783
1878
|
export type ClipPart = "terrain" | "doodads" | "units" | "sprites" | "locations" | "fog";
|
|
1784
1879
|
export type ClipParts = Record<ClipPart, boolean>;
|
|
1785
1880
|
/** Whether a paste adds to what is in the target area or clears its objects first. */
|
|
@@ -2121,6 +2216,13 @@ export interface PluginApi {
|
|
|
2121
2216
|
/** The plugin's words in the editor's language: its own catalogues, and a `t` over them. */
|
|
2122
2217
|
readonly i18n: I18nApi;
|
|
2123
2218
|
readonly events: EventsApi;
|
|
2219
|
+
/**
|
|
2220
|
+
* Editing the map in front together with other editors: every change to it is handed out
|
|
2221
|
+
* as an op for the plugin to carry to them, and theirs come back in, in the order a
|
|
2222
|
+
* server puts them. The scmjs.dev plugin's shared maps are built on it; the transport,
|
|
2223
|
+
* the server and who may join are the plugin's.
|
|
2224
|
+
*/
|
|
2225
|
+
readonly sync: SyncApi;
|
|
2124
2226
|
/**
|
|
2125
2227
|
* A small key-value store of the plugin's own, kept in the browser's local storage under
|
|
2126
2228
|
* the plugin's id and listed with everything else in Preferences ▸ Browser storage.
|
|
@@ -4317,6 +4419,11 @@ export interface PickFilesOptions {
|
|
|
4317
4419
|
multiple?: boolean;
|
|
4318
4420
|
}
|
|
4319
4421
|
export interface UiApi {
|
|
4422
|
+
/**
|
|
4423
|
+
* The dialogs open now, bottom to top, by id: the built-in ones by their `DialogId`, a
|
|
4424
|
+
* plugin's as `"pluginDialog"`. What a shared map shows others ("in Player Settings").
|
|
4425
|
+
*/
|
|
4426
|
+
openDialogs(): string[];
|
|
4320
4427
|
/** Set the status bar line. */
|
|
4321
4428
|
status(text: string): void;
|
|
4322
4429
|
/** The status bar line as it stands. */
|
|
@@ -4864,8 +4971,78 @@ export type PluginEvent =
|
|
|
4864
4971
|
| "commands"
|
|
4865
4972
|
/** A plugin provided or withdrew a service — `services.watch` is the usual way to hear this for one name. */
|
|
4866
4973
|
| "services"
|
|
4974
|
+
/** A dialog opened or closed — `ui.openDialogs()` says which are open. */
|
|
4975
|
+
| "dialogs"
|
|
4867
4976
|
/** The game data source changed: installed, switched to another data set, or a copy removed. `gameData.source()` says what it is now. */
|
|
4868
4977
|
| "gameData";
|
|
4978
|
+
/** 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. */
|
|
4979
|
+
export type SyncHold = "stroke" | "dialog" | "behind";
|
|
4980
|
+
export interface SyncReport {
|
|
4981
|
+
/** Other people's ops applied. */
|
|
4982
|
+
ops: number;
|
|
4983
|
+
/** Parts of them that could not be applied — the unit they moved was deleted, the map was resized… */
|
|
4984
|
+
dropped: number;
|
|
4985
|
+
/** Parts of this editor's unconfirmed changes that no longer applied on top of theirs. */
|
|
4986
|
+
lost: number;
|
|
4987
|
+
}
|
|
4988
|
+
export interface SyncStartOptions {
|
|
4989
|
+
/**
|
|
4990
|
+
* Every change made to the shared map, as a plain object JSON can carry, in the order
|
|
4991
|
+
* made: commits, undo and redo, the dialogs' writes, archive files, and a resize or a
|
|
4992
|
+
* tileset change (the whole scenario). Each must reach the server, and every other
|
|
4993
|
+
* editor, in this order.
|
|
4994
|
+
*/
|
|
4995
|
+
send(op: SyncOp): void;
|
|
4996
|
+
/** The session ended: the shared map was closed or replaced by another, or `stop` was called. */
|
|
4997
|
+
onEnd?(reason: "closed" | "stopped"): void;
|
|
4998
|
+
/** Other people's changes were applied to the map. */
|
|
4999
|
+
onApplied?(report: SyncReport): void;
|
|
5000
|
+
}
|
|
5001
|
+
/**
|
|
5002
|
+
* One shared map. The server confirms each op this editor sent (`confirm`, in order) and
|
|
5003
|
+
* relays everyone else's (`receive`, in the order it gave them); the session applies
|
|
5004
|
+
* them to the map when nothing is in the way (`holding`) and rebases this editor's
|
|
5005
|
+
* unconfirmed changes on top, so every editor that has seen the same ops has the same map.
|
|
5006
|
+
*
|
|
5007
|
+
* @example
|
|
5008
|
+
* const session = api.sync.start({ send: (op) => socket.send(JSON.stringify({ type: "op", op })) });
|
|
5009
|
+
* socket.onmessage = (m) => {
|
|
5010
|
+
* const msg = JSON.parse(m.data);
|
|
5011
|
+
* if (msg.type === "ack") session?.confirm();
|
|
5012
|
+
* if (msg.type === "op") session?.receive(msg.op);
|
|
5013
|
+
* };
|
|
5014
|
+
*/
|
|
5015
|
+
export interface SyncSession {
|
|
5016
|
+
/** The shared map's `document.id()`. */
|
|
5017
|
+
readonly documentId: number;
|
|
5018
|
+
/** Another editor's op, in the server's order. False, and nothing done, for a value that is not an op. */
|
|
5019
|
+
receive(op: unknown): boolean;
|
|
5020
|
+
/** The server confirmed the oldest op this editor sent. */
|
|
5021
|
+
confirm(): void;
|
|
5022
|
+
/** Ops sent and not yet confirmed. */
|
|
5023
|
+
pending(): number;
|
|
5024
|
+
/** Ops and confirmations received and not yet applied. */
|
|
5025
|
+
waiting(): number;
|
|
5026
|
+
/**
|
|
5027
|
+
* The shared map as a file (`.scx` / `.scm`, not built), copied at this moment — for a
|
|
5028
|
+
* server to hand people joining, labelled with the last op this editor applied. Null
|
|
5029
|
+
* while anything is pending or waiting (the copy would not match any point in the
|
|
5030
|
+
* server's order) or while another map is in front. The copy is taken before the first
|
|
5031
|
+
* `await`, so a change made while the file is written is not in it.
|
|
5032
|
+
*/
|
|
5033
|
+
snapshot(): Promise<Uint8Array | null>;
|
|
5034
|
+
holding(): SyncHold | null;
|
|
5035
|
+
stop(): void;
|
|
5036
|
+
}
|
|
5037
|
+
export interface SyncApi {
|
|
5038
|
+
/**
|
|
5039
|
+
* Share the map in front. Null when no map is open or another session is running (one
|
|
5040
|
+
* at a time). A session a plugin started stops when the plugin is turned off.
|
|
5041
|
+
*/
|
|
5042
|
+
start(options: SyncStartOptions): SyncSession | null;
|
|
5043
|
+
/** The running session, whichever plugin started it. */
|
|
5044
|
+
current(): SyncSession | null;
|
|
5045
|
+
}
|
|
4869
5046
|
/** Why the document changed. */
|
|
4870
5047
|
export type DocumentChangeReason =
|
|
4871
5048
|
/** File ▸ Open, drag-and-drop, `document.open`: a file the user chose. */
|