Skip to content

Commit 93baaee

Browse files
committed
feat: add record & clear history API
1 parent 11bad47 commit 93baaee

35 files changed

+689
-472
lines changed

README.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,14 @@ If you want to use it in your own project, you can refer to:
252252
| :-----------------------------------------------------: | :-----------------------------------------------------------: |
253253
| ![Top nav and zoom toolbar](./screenshots/lesson18.png) | ![Layers and properties panels](./screenshots/lesson18-2.png) |
254254

255-
## Lesson 19 - History and Collaboration [🔗](https://infinitecanvas.cc/guide/lesson-019)
255+
## Lesson 19 - History [🔗](https://infinitecanvas.cc/guide/lesson-019)
256256

257257
- Implement a simple history system, including undo and redo
258+
259+
<img src="./screenshots/lesson19.png" width="300" alt="Lesson 19 - history">
260+
261+
## Lesson 20 - Collaboration [🔗](https://infinitecanvas.cc/guide/lesson-020)
262+
258263
- Implement collaboration through CRDT
259264

260265
[infinitecanvas]: https://infinitecanvas.tools/

README.zh_CN.md

+6-1
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,14 @@ pnpm run dev
252252
| :-----------------------------------------------------: | :-----------------------------------------------------------: |
253253
| ![Top nav and zoom toolbar](./screenshots/lesson18.png) | ![Layers and properties panels](./screenshots/lesson18-2.png) |
254254

255-
## 课程 19 - 历史记录与协同 [🔗](https://infinitecanvas.cc/zh/guide/lesson-019)
255+
## 课程 19 - 历史记录 [🔗](https://infinitecanvas.cc/zh/guide/lesson-019)
256256

257257
- 实现简单的历史记录功能,包含撤销和重做
258+
259+
<img src="./screenshots/lesson19.png" width="300" alt="Lesson 19 - history">
260+
261+
## 课程 20 - 协同 [🔗](https://infinitecanvas.cc/zh/guide/lesson-020)
262+
258263
- 通过 CRDT 实现协同
259264

260265
[infinitecanvas]: https://infinitecanvas.tools/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* @see https://lastolivegames.github.io/becsy/guide/architecture/entities#deleting-entities
3+
*/
4+
export class ToBeDeleted {}

packages/ecs/src/components/renderable/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ export * from './GlobalRenderOrder';
1010
export * from './Rough';
1111
export * from './ComputedBounds';
1212
export * from './Visibility';
13+
export * from './ToBeDeleted';

packages/ecs/src/plugins/Camera.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,25 @@ import {
55
CameraControl,
66
ComputeCamera,
77
EventWriter,
8+
PropagateTransforms,
89
SetupDevice,
10+
SyncSimpleTransforms,
911
} from '../systems';
1012

1113
export const CameraPlugin: Plugin = () => {
1214
component(Camera);
1315
component(ComputedCamera);
1416
component(ComputedCameraControl);
1517

16-
system((s) => s.afterWritersOf(Camera).after(EventWriter, SetupDevice))(
17-
CameraControl,
18-
);
19-
system((s) => s.afterWritersOf(Camera))(ComputeCamera);
18+
system((s) =>
19+
s
20+
.afterWritersOf(Camera)
21+
.after(
22+
EventWriter,
23+
SetupDevice,
24+
SyncSimpleTransforms,
25+
PropagateTransforms,
26+
),
27+
)(CameraControl);
28+
system((s) => s.afterWritersOf(Camera).after(CameraControl))(ComputeCamera);
2029
};

packages/ecs/src/plugins/Culling.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { component, system } from '@lastolivegames/becsy';
22
import { Plugin } from './types';
3-
import { PostUpdate, ViewportCulling } from '../systems';
3+
import { ComputeCamera, PostUpdate, ViewportCulling } from '../systems';
44
import { ComputedBounds, Culled } from '../components';
55

66
export const CullingPlugin: Plugin = () => {
77
component(Culled);
88

99
system(PostUpdate)(ViewportCulling);
10-
system((s) => s.afterWritersOf(ComputedBounds))(ViewportCulling);
10+
system((s) => s.afterWritersOf(ComputedBounds).after(ComputeCamera))(
11+
ViewportCulling,
12+
);
1113
};

packages/ecs/src/plugins/Pen.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ import { Plugin } from './types';
33
import { CameraControl, Select } from '../systems';
44

55
export const PenPlugin: Plugin = () => {
6-
system((s) => s.after(CameraControl))(Select);
6+
// system((s) => s.after(CameraControl))(Select);
77
};

packages/ecs/src/plugins/Renderer.ts

+21-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ import {
1616
PostUpdate,
1717
ComputeCamera,
1818
StartUp,
19+
Deleter,
20+
Last,
21+
PropagateTransforms,
22+
CameraControl,
23+
Select,
24+
ExportSVG,
1925
} from '../systems';
2026
import {
2127
Circle,
@@ -44,6 +50,7 @@ import {
4450
Visibility,
4551
GPUResource,
4652
Name,
53+
ToBeDeleted,
4754
} from '../components';
4855

4956
export const RendererPlugin: Plugin = () => {
@@ -56,6 +63,7 @@ export const RendererPlugin: Plugin = () => {
5663
component(Wireframe);
5764
component(GlobalRenderOrder);
5865
component(Visibility);
66+
component(ToBeDeleted);
5967
/**
6068
* Style
6169
*/
@@ -88,8 +96,20 @@ export const RendererPlugin: Plugin = () => {
8896
system(PreUpdate)(ComputePoints);
8997
system(PreUpdate)(ComputeRough);
9098
system(PreUpdate)(ComputeTextMetrics);
91-
system(PreUpdate)(ComputeBounds);
99+
system(PostUpdate)(ComputeBounds);
100+
system((s) => s.after(PropagateTransforms))(ComputeBounds);
92101
system(PostUpdate)(Sort);
93102
system(PostUpdate)(SetCursor);
94103
system((s) => s.after(ComputeCamera, SetupDevice))(MeshPipeline);
104+
system((s) =>
105+
s.after(
106+
Last,
107+
PropagateTransforms,
108+
CameraControl,
109+
// Select,
110+
ComputeCamera,
111+
MeshPipeline,
112+
ExportSVG,
113+
),
114+
)(Deleter);
95115
};

packages/ecs/src/plugins/Transform.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Transform, GlobalTransform } from '../components';
44
import {
55
SyncSimpleTransforms,
66
PropagateTransforms,
7-
PostStartUp,
7+
PostUpdate,
88
} from '../systems';
99

1010
/**
@@ -15,6 +15,6 @@ export const TransformPlugin: Plugin = () => {
1515
component(Transform);
1616
component(GlobalTransform);
1717

18-
system(PostStartUp)(SyncSimpleTransforms);
18+
system(PostUpdate)(SyncSimpleTransforms);
1919
system((s) => s.after(SyncSimpleTransforms))(PropagateTransforms);
2020
};

packages/ecs/src/systems/ComputeZIndex.ts

+16-19
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import { generateKeyBetween } from 'fractional-indexing';
33
import { Children, Parent, ZIndex } from '../components';
44

55
export class ComputeZIndex extends System {
6-
parents = this.query((q) => q.addedChangedOrRemoved.with(Parent).trackWrites);
6+
// parents = this.query((q) => q.addedChangedOrRemoved.with(Parent).trackWrites);
77

8-
children = this.query(
9-
(q) => q.addedChangedOrRemoved.with(Children).trackWrites,
10-
);
8+
// children = this.query(
9+
// (q) => q.addedChangedOrRemoved.with(Children).trackWrites,
10+
// );
1111

1212
constructor() {
1313
super();
@@ -25,20 +25,17 @@ export class ComputeZIndex extends System {
2525
}
2626

2727
execute() {
28-
this.parents.addedChangedOrRemoved.forEach((entity) => {
29-
if (!entity.has(ZIndex)) {
30-
entity.add(ZIndex);
31-
32-
// console.log('zindex', entity.__id);
33-
}
34-
});
35-
36-
this.children.addedChangedOrRemoved.forEach((entity) => {
37-
if (!entity.has(ZIndex)) {
38-
entity.add(ZIndex);
39-
40-
// console.log('zindex', entity.__id);
41-
}
42-
});
28+
// this.parents.addedChangedOrRemoved.forEach((entity) => {
29+
// if (!entity.has(ZIndex)) {
30+
// entity.add(ZIndex);
31+
// // console.log('zindex', entity.__id);
32+
// }
33+
// });
34+
// this.children.addedChangedOrRemoved.forEach((entity) => {
35+
// if (!entity.has(ZIndex)) {
36+
// entity.add(ZIndex);
37+
// // console.log('zindex', entity.__id);
38+
// }
39+
// });
4340
}
4441
}

packages/ecs/src/systems/Deleter.ts

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { System } from '@lastolivegames/becsy';
2+
import { ToBeDeleted } from '../components';
3+
4+
/**
5+
* Deletes entities with the {@link ToBeDeleted} component.
6+
* @see https://lastolivegames.github.io/becsy/guide/architecture/entities#deleting-entities
7+
*/
8+
export class Deleter extends System {
9+
// Note the usingAll.write below, which grants write entitlements on all component types.
10+
entities = this.query((q) => q.current.with(ToBeDeleted).usingAll.write);
11+
12+
execute() {
13+
for (const entity of this.entities.current) entity.delete();
14+
}
15+
}

packages/ecs/src/systems/MeshPipeline.ts

+9-2
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import {
4242
Stroke,
4343
Text,
4444
Theme,
45+
ToBeDeleted,
4546
Wireframe,
4647
} from '../components';
4748
import { paddingMat3 } from '../utils';
@@ -58,11 +59,15 @@ export class MeshPipeline extends System {
5859

5960
private renderables = this.query(
6061
(q) =>
61-
q.addedOrChanged.and.removed
62+
q.addedOrChanged
6263
.with(Renderable)
6364
.withAny(Circle, Ellipse, Rect, Polyline, Path, Text).trackWrites,
6465
);
6566

67+
private toBeDeleted = this.query(
68+
(q) => q.addedOrChanged.with(ToBeDeleted).trackWrites,
69+
);
70+
6671
private culleds = this.query(
6772
(q) => q.addedOrChanged.and.removed.with(Culled).trackWrites,
6873
);
@@ -236,6 +241,7 @@ export class MeshPipeline extends System {
236241
batchManager.add(entity);
237242
});
238243
this.pendingRenderables.get(camera).remove.forEach((entity) => {
244+
console.log('remove', entity);
239245
// TODO: split removed and culled
240246
batchManager.remove(entity, false);
241247
});
@@ -274,7 +280,8 @@ export class MeshPipeline extends System {
274280
});
275281

276282
new Set([
277-
...this.renderables.removed,
283+
...this.toBeDeleted.addedOrChanged,
284+
// ...this.renderables.removed,
278285
...this.culleds.addedOrChanged,
279286
]).forEach((entity) => {
280287
const camera = getSceneRoot(entity);

packages/ecs/src/systems/Sort.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
*/
1515
export class Sort extends System {
1616
renderables = this.query(
17-
(q) => q.addedChangedOrRemoved.with(Renderable).trackWrites,
17+
(q) => q.addedOrChanged.with(Renderable).trackWrites,
1818
);
1919

2020
visibilities = this.query(
@@ -31,7 +31,7 @@ export class Sort extends System {
3131

3232
execute() {
3333
let i = 1;
34-
this.renderables.addedChangedOrRemoved.forEach((entity) => {
34+
this.renderables.addedOrChanged.forEach((entity) => {
3535
if (!entity.has(GlobalRenderOrder)) {
3636
entity.add(GlobalRenderOrder);
3737
}

packages/ecs/src/systems/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ export * from './ExportSVG';
1717
export * from './Select';
1818
export * from './ViewportCulling';
1919
export * from './ComputeZIndex';
20+
export * from './Deleter';

packages/site/docs/.vitepress/config/en.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,13 @@ export const en = defineConfig({
8686
{ text: 'Lesson 017 - Gradient and pattern', link: 'lesson-017' },
8787
{ text: 'Lesson 018 - Refactor with ECS', link: 'lesson-018' },
8888
{
89-
text: 'Lesson 019 - History and collaboration',
89+
text: 'Lesson 019 - History',
9090
link: 'lesson-019',
9191
},
92+
{
93+
text: 'Lesson 020 - Collaboration',
94+
link: 'lesson-020',
95+
},
9296
],
9397
},
9498
],

packages/site/docs/.vitepress/config/zh.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export const zh = defineConfig({
5858
{ text: '课程16 - 文本的高级特性', link: 'lesson-016' },
5959
{ text: '课程17 - 渐变和重复图案', link: 'lesson-017' },
6060
{ text: '课程18 - 使用 ECS 重构', link: 'lesson-018' },
61-
{ text: '课程19 - 历史记录与协同', link: 'lesson-019' },
61+
{ text: '课程19 - 历史记录', link: 'lesson-019' },
62+
{ text: '课程20 - 协同', link: 'lesson-020' },
6263
],
6364
},
6465
],

0 commit comments

Comments
 (0)