@virid/core 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1 +1,309 @@
1
- todo
1
+ # @virid/core
2
+
3
+ `@virid/core` serves as the logical heartbeat of the entire Virid ecosystem. It provides a deterministic message distribution and scheduling mechanism, designed to completely decouple business logic from complex UI frameworks and runtime environments.
4
+
5
+ ⚠️ **Warning:** This framework heavily incorporates design philosophies from **Rust**, **Bevy**, and **NestJS**. It has a steep learning curve and requires the configuration of `reflect-metadata` with experimental metadata support enabled.
6
+
7
+ ### 🌟 Core Design Philosophy
8
+
9
+ - **Absolute Environment Independence:** This package does not rely on any browser-specific APIs, Node.js internals, or third-party libraries (with the sole exception of `reflect-metadata` for decorator functionality). This ensures the kernel can run seamlessly within Electron main processes, Worker threads, Web rendering layers, or even pure server-side environments.
10
+ - **Deterministic Scheduling:** By introducing a game-engine-inspired **Tick mechanism**, the framework utilizes double-buffered message pools to ensure the execution order of logic remains strictly predictable.
11
+ - **Strong Typing & Ownership:** All systems are built with robust type safety, enforcing the use of modern TypeScript types and classes as unique identifiers. It features a runtime "modification shield" to intercept any illegal write operations. Move beyond a reliance on hot-reloading; as the saying goes: *If it compiles, it works.*
12
+
13
+ ## 🛠️ Core Functional Overview
14
+
15
+ ### 1. Message-Driven & Dispatcher Mechanism
16
+
17
+ In `Virid`, all state changes must be triggered by sending a `Message` command.
18
+
19
+ - **Automatic Scheduling**: By defining specific types of `Message` and corresponding `System` handlers, the engine automatically invokes the registered logic in the next microtask cycle (`Tick`).
20
+ - **Message Types**:
21
+ - **`SingleMessage`**: Messages of the same type within the same Tick are automatically merged, suitable for state synchronization.
22
+ - **`EventMessage`**: Sequentially appended, ensuring the integrity of action sequences.
23
+ - **`ErrorMessage`**: Sequentially appended; errors are treated as a message type with a default handling System.
24
+ - **`WarnMessage`**: Sequentially appended; warnings are a message type with a default handling System.
25
+ - **`InfoMessage`**: Sequentially appended; information is a message type with a default handling System.
26
+
27
+ ### 2. Dependency Injection System (DI)
28
+
29
+ `Virid` implements a lightweight, decorator-based DI system, allowing Systems to access data entities with minimal effort.
30
+
31
+ - **Data Entities (Component)**: Classes marked with the `@Component()` decorator are defined as data containers.
32
+ - **Automatic Injection**: Once registered via `app.bindComponent()`, the Dispatcher automatically injects the corresponding instances based on the parameter types of the System function.
33
+
34
+ ```ts
35
+ class IncrementMessage extends SingleMessage {
36
+ constructor(public amount: number) {
37
+ super();
38
+ }
39
+ }
40
+
41
+ @Component()
42
+ class CounterComponent { public count = 0; }
43
+
44
+ class CounterSystem {
45
+ @System()
46
+ static onIncrement(
47
+ @Message(IncrementMessage) msg: IncrementMessage,
48
+ count: CounterComponent
49
+ ) {
50
+ count.count += msg.amount; // CounterComponent instance is automatically injected
51
+ }
52
+ }
53
+ ```
54
+
55
+ ### 3. Lifecycle Hooks
56
+
57
+ The Dispatcher provides comprehensive lifecycle monitoring:
58
+
59
+ - **Execution Hooks**: Supports `onBeforeExecute` and `onAfterExecute` for global auditing or filtering before and after logic execution.
60
+ - **Cycle Hooks**: `onBeforeTick` and `onAfterTick` monitor the start and end of each logic frame.
61
+
62
+ ### 4. Industrial-Grade Robustness
63
+
64
+ - **Deadlock Defense**: The Dispatcher includes an `internalDepth` counter. If a logic chain triggers more than 100 levels of recursion, the system automatically fuses and throws an error to prevent the environment from hanging.
65
+ - **Execution Priority**: Supports defining the order of multiple Systems handling the same message via `@System({ priority: number })`.
66
+
67
+ ------
68
+
69
+ ## 🛠️ @virid/core API Reference
70
+
71
+ ### 1. Engine Initialization
72
+
73
+ #### `createVirid()`
74
+
75
+ - **Function**: Initializes the logical kernel and creates the globally unique `Dispatcher` and container.
76
+
77
+ ------
78
+
79
+ ### 2. Instructions & Messages
80
+
81
+ #### `SingleMessage`
82
+
83
+ - **Feature**: State synchronization message.
84
+ - **Logic**: Multiple messages of the same type in one Tick are merged; the System typically receives only the latest one.
85
+ - **Example**:
86
+
87
+ ```ts
88
+ import { SingleMessage } from "@virid/core";
89
+ class MyMessage extends SingleMessage {}
90
+ //Send messages anywhere
91
+ MyMessage.send(); // Parameters correspond to the constructor
92
+ ```
93
+
94
+ #### `EventMessage`
95
+
96
+ - **Feature**: Action command message.
97
+ - **Logic**: Sequential, no merging. Every `EventMessage` triggers a System execution strictly.
98
+ - **Example**: Same as `EventMessage`
99
+
100
+ ## 3. Data & Logic Definitions (Decorators)
101
+
102
+ ### `@Controller()`
103
+
104
+ - **Function:** Marks a class as a UI Controller. Instances of this class are tied to the lifecycle of Vue components—created when the component is mounted and destroyed when it is unmounted. For details, see `@virid/vue`.
105
+
106
+ - **Design:** Used in conjunction with `bindController`. Once registered, instances can be retrieved in `@virid/vue` using the `useController` hook.
107
+
108
+ - **Example:**
109
+
110
+ ```ts
111
+ @Controller()
112
+ class PageController {}
113
+
114
+ // Registration is required before use
115
+ app.bindController(PageController);
116
+ ```
117
+
118
+ ------
119
+
120
+ ### `@Component()`
121
+
122
+ - **Function:** Marks a class as a Data Entity. This class acts as a global singleton and persists throughout the application lifecycle.
123
+
124
+ - **Design:** Used with `bindComponent`. Once registered, it can be declared as a parameter type in a `@System` to enable automatic Dependency Injection (DI).
125
+
126
+ - **Example:**
127
+
128
+ ```ts
129
+ @Component()
130
+ class CounterComponent {
131
+ public count = 0;
132
+ }
133
+
134
+ // Registration is required before use
135
+ app.bindComponent(CounterComponent);
136
+ ```
137
+
138
+ ------
139
+
140
+ ### `@System(params?)`
141
+
142
+ - **Function:** Registers a static method as a business logic processor. It implements **"Automatic Dependency Wiring."** By simply specifying the `Component` type in the parameters, the engine automatically injects the corresponding instance during execution.
143
+
144
+ - **Parameters:**
145
+
146
+ - `priority`: Execution priority. Higher values execute earlier within the same **Tick**.
147
+ - `messageClass`: The specific message type that triggers this System. (Cannot be used simultaneously with the `@Message` decorator on parameters).
148
+
149
+ - **Example:**
150
+
151
+
152
+ ```ts
153
+ import { System, Message } from "@virid/core";
154
+
155
+ class CounterSystem {
156
+ // Setting priority; CounterComponent is automatically injected
157
+ @System({ priority: 0 })
158
+ static onIncrement(
159
+ @Message(IncrementMessage) message: IncrementMessage,
160
+ count: CounterComponent,
161
+ ) {
162
+ count.count += message.amount;
163
+ }
164
+
165
+ // Alternative: Define messageClass in the System decorator
166
+ @System({ messageClass: IncrementMessage })
167
+ static onQuickAdd(count: CounterComponent) {
168
+ count.count += 1;
169
+ }
170
+
171
+ @System()
172
+ static onProcess(msg: SomeMessage) {
173
+ // Return a message (or an array of messages) to trigger a logic chain
174
+ // This removes the need to manually call a MessageWriter
175
+ return new NextStepMessage();
176
+ }
177
+ }
178
+
179
+ // Triggering logic via the .send() method
180
+ IncrementMessage.send(5);
181
+ ```
182
+
183
+ ------
184
+
185
+ ### `@Message(Class, single?)`
186
+
187
+ - **Function:** A parameter-level decorator that explicitly defines which message type the System is listening to.
188
+ - **Batch Mode:** If `single: false` is set, the System receives an **array** of all messages of that type sent within the current Tick. This is ideal for high-performance batch processing (e.g., physics calculations or log aggregation).
189
+ - **Example:** See the `@System` section above.
190
+
191
+ ------
192
+
193
+ ### `@Observer(callback)`
194
+
195
+ - **Function:** A property-level decorator for change detection, used to handle "non-command-driven" side effects.
196
+
197
+ - **Logic:** When a decorated property in a `Component` changes, the engine automatically triggers the specified callback function.
198
+
199
+ - **Example:**
200
+
201
+
202
+ ```ts
203
+ @Component()
204
+ class PlayerComponent {
205
+ // Automatically send a sync message or execute a callback when 'progress' changes
206
+ @Observer((old, val) => new SyncLyricMessage(val))
207
+ public progress = 0;
208
+ }
209
+ ```
210
+
211
+ ------
212
+
213
+ ### `@Safe()`
214
+
215
+ - **Function:** A method access modifier. In Virid, external environments (UI layers) are strictly prohibited from directly modifying logic-layer data; all modifications and method calls are intercepted by default. However, "read-only" or "safe calculation" methods can be explicitly authorized via `@Safe()`, allowing the view layer to call them directly.
216
+
217
+ - **Design:** Primarily serves external projection layers like `@virid/vue`. See **Deep Shield** in the `@virid/vue` documentation for more details.
218
+
219
+ - **Example:**
220
+
221
+
222
+ ```ts
223
+ @Component()
224
+ class PlayerComponent {
225
+ // Without @Safe, Virid will block calls to this method from any Vue Controller
226
+ @Safe()
227
+ public someMethod() {}
228
+ }
229
+ ```
230
+
231
+ ### 4. Dispatcher & Hooks
232
+
233
+ - **Double-Buffered Flip**: Each execution locks current messages; new messages generated during execution enter the next cycle.
234
+ - **Hooks Example**:
235
+
236
+ ```ts
237
+ const app = createVirid();
238
+ app.onBeforeExecute(MyMessage, (msg, context) => {
239
+ // Global performance tracking or permission validation
240
+ });
241
+ app.onAfterTick((context) => {
242
+ console.log("----------------onAfterTick------------------");
243
+ });
244
+ ```
245
+
246
+ ------
247
+
248
+ ### 4. Dispatcher & Hooks
249
+
250
+ #### **Dispatcher**
251
+
252
+ The core scheduling engine of Virid operates on the following logic:
253
+
254
+ - **Double-Buffered Flip**: The scheduler runs based on logical **Ticks**. A Tick starts at the beginning of a microtask and continues until no new messages are generated internally. During each execution, the scheduler locks the current pending messages; any new messages generated during this process are automatically moved to the next cycle.
255
+ - **Recursion Melt-down (Deadlock Defense)**: If the recursive execution depth (`internalDepth`) exceeds 100, the engine immediately halts and throws an error. This protects the main thread from being frozen by logical "black holes" or infinite loops.
256
+
257
+ #### **Life-Cycle Hooks**
258
+
259
+ - **onBeforeTick / onAfterTick**: Monitor the "pulse" of logical frames.
260
+ - **onBeforeExecute / onAfterExecute**: Audit the entire execution process for specific message types.
261
+ - **Example:**
262
+
263
+ ```ts
264
+ const app = createVirid();
265
+
266
+ app.onBeforeExecute(MyMessage, (msg, context) => {
267
+ // Implement global performance tracking or permission validation here
268
+ // This hook only triggers for MyMessage and its subclasses
269
+ });
270
+
271
+ app.onAfterTick((context) => {
272
+ console.log("----------------onAfterTick------------------");
273
+ });
274
+ ```
275
+
276
+ ### 5. System Communication (IO)
277
+
278
+ #### **MessageWriter**
279
+
280
+ - **Function**: A global static utility for system-wide communication.
281
+ - **API**:
282
+ - **`MessageWriter.write(MessageClass, ...args)`**: The underlying entry point for dispatching messages. It instantiates the message class with the provided arguments and sends it to the Dispatcher.
283
+ - **`MessageWriter.error(Error, context?)`**: Throws a system-level error, which automatically triggers an `ErrorMessage`.
284
+ - **`MessageWriter.warn(context)`**: Logs a warning, which automatically triggers a `WarnMessage`.
285
+ - **`MessageWriter.info(context)`**: Logs an informational message, which automatically triggers an `InfoMessage`.
286
+
287
+ ------
288
+
289
+ ### 🔬 Advanced: Atomic Operations
290
+
291
+ #### **AtomicModifyMessage**
292
+
293
+ - **Function**: Provides a "plug-and-play" solution for temporary logic modifications.
294
+ - **Scenario**: When you need to perform a one-time observation or tweak a `Component` without the overhead of defining a dedicated `System`, you can use this message to execute a closure logic in the next logical frame (Tick).
295
+ - **Example**:
296
+
297
+ ```ts
298
+ AtomicModifyMessage.send(
299
+ CounterComponent,
300
+ (comp) => {
301
+ // Perform one-time inspection or modification on the component instance
302
+ console.log("----------------AtomicModifyMessage------------------");
303
+ console.log("Current Component State:", comp);
304
+ },
305
+ "Check CounterComponent" // Optional: label for debugging/tracing
306
+ );
307
+ ```
308
+
309
+ ------
package/README.zh.md CHANGED
@@ -1 +1,278 @@
1
- todo
1
+ # @virid/core
2
+
3
+ `@virid/core` 是整个 Virid 生态系统的逻辑心脏。它提供了一套确定性的消息分发与调度机制,旨在将业务逻辑从复杂的 UI 框架与运行环境中彻底剥离。
4
+
5
+ ⚠️本框架吸收了大量Rust、Bevy、Nestjs设计哲学,上手难度较高,且需要配置`reflect-metadata`并开启元数据支持。
6
+
7
+ ## 🌟 核心设计理念
8
+
9
+ - **环境绝对独立**:本包不依赖任何浏览器、Node.js 的特殊 API 或第三方库(仅依赖 `reflect-metadata` 实现装饰器功能)。这确保了内核可以无缝运行在 Electron 主进程、Worker 线程、Web 渲染层甚至纯服务器环境中。
10
+ - **确定性调度**:引入了类似游戏引擎的 `Tick` 机制,通过双缓冲消息池确保逻辑执行顺序的可预测性。
11
+ - **强类型与所有权**:所有的系统使用强类型构建,强制使用现代TS类型和类本身作为标识,且拥有运行时修改护盾检查拦截任何非法写操作。**摆脱热更新依赖,If it compiles, it works**
12
+
13
+ ## 🛠️ 核心功能详解
14
+
15
+ ### 1. 消息驱动与分发机制 (Message & Dispatcher)
16
+
17
+ 在 Virid 中,所有的状态变更都必须通过发送一个 `Message` 指令来触发。
18
+
19
+ - **自动调度**:通过定义特定类型的 `Message` 和对应的 `System` 处理函数,引擎会自动在下一个微任务周期(`Tick`)内调用已注册的逻辑。
20
+ - **消息类型**:
21
+ - `SingleMessage`:同一 Tick 内的同类消息会自动合并,适用于状态同步。
22
+ - `EventMessage`:顺序追加,确保动作序列的完整性。
23
+ - `ErrorMessage`:顺序追加,错误也是一种消息类型,拥有默认处理`System`。
24
+ - `WarnMessage`:顺序追加,警告也是一种消息类型,拥有默认处理`System`。
25
+ - `InfoMessage`:顺序追加,信息也是一种消息类型,拥有默认处理`System`。
26
+
27
+ ### 2. 依赖注入系统 (Dependency Injection)
28
+
29
+ `Virid` 实现了基于装饰器的轻量依赖注入,使 `System` 能够以极简的方式访问数据实体。
30
+
31
+ - **数据实体 (Component)**:通过 `@Component()` 装饰器标记 class,将其定义为数据容器。
32
+ - **自动注入**:使用 `app.bindComponent()` 注册后,Dispatcher 会根据 System 函数的参数类型自动注入对应的实例。
33
+
34
+ ```ts
35
+ //定义消息
36
+ class IncrementMessage extends SingleMessage {
37
+ constructor(public amount: number) {
38
+ super();
39
+ }
40
+ }
41
+
42
+ //定义数据
43
+ @Component()
44
+ class CounterComponent { public count = 0; }
45
+
46
+ //纯静态static,当消息发送时引擎自动调用onIncrement
47
+ class CounterSystem {
48
+ @System()
49
+ static onIncrement(
50
+ @Message(IncrementMessage) msg: IncrementMessage,
51
+ count: CounterComponent
52
+ ) {
53
+ count.count += msg.amount; // 自动注入的 CounterComponent 实例
54
+ }
55
+ }
56
+ ```
57
+
58
+ ### 3. 系统调度与钩子 (Lifecycle Hooks)
59
+
60
+ `Dispatcher` 提供了完备的生命周期监控能力:
61
+
62
+ - **执行钩子**:支持 `onBeforeExecute` 和 `onAfterExecute`,允许在逻辑执行前后插入全局审计或过滤逻辑。
63
+ - **周期钩子**:`onBeforeTick` 与 `onAfterTick` 用于监控每一轮逻辑帧的起止。
64
+
65
+ ### 4. 工业级健壮性
66
+
67
+ - **死循环防御**:`Dispatcher` 内部设有 `internalDepth` 计数器。若逻辑链路产生超过 100 层的递归触发,系统将自动熔断并报错,防止环境假死。
68
+ - **执行优先级**:支持通过 `@System({ priority: number })` 明确多个系统处理同一消息时的先后顺序。
69
+
70
+ ## 🛠️ @virid/core 核心 API 概览
71
+
72
+ ### 1. 引擎初始化 (Engine Entry)
73
+
74
+ #### `createVirid()`
75
+
76
+ - **功能**:初始化逻辑内核,创建全局唯一的 `Dispatcher` 与容器。
77
+
78
+ ------
79
+
80
+ ### 2. 指令与消息 (Messages)
81
+
82
+ 消息是驱动系统的唯一原因。`Virid` 区分了两种不同的执行范式:
83
+
84
+ #### `SingleMessage`
85
+
86
+ - **特性**:**状态同步型消息**。
87
+
88
+ - **逻辑**:在同一个 `Tick` 内发送的多次同类型 `SingleMessage` 会被自动合并。默认情况下,`System` 仅会收到最新的一条。
89
+
90
+ - **示例:**
91
+
92
+ ```ts
93
+ import {SingleMessage} form "@virid/core"
94
+ class MyMessage extends SingleMessage{
95
+ construter(public someData:SomeType)
96
+ }
97
+
98
+ //在任何的地方,只要发送
99
+ //send内的参数为MyMessage的构造函数可以接受的参数
100
+ MyMessage.send(someData)
101
+ ```
102
+
103
+ #### `EventMessage`
104
+
105
+ - **特性**:**动作指令型消息**。
106
+ - **逻辑**:顺序追加,不合并。每一条 `EventMessage` 都会严格触发一次 `System` 执行。
107
+ - **示例:**同`SingleMessage`
108
+
109
+ ------
110
+
111
+ ### 3. 数据与逻辑定义 (Decorators)
112
+
113
+ #### `@Controller()`
114
+
115
+ - **功能**:标记一个类为**UI控制器**,该类将会随着每个`vue`组件的创建而创建,销毁而销毁。详情见`@virid/vue`。
116
+ - **设计**:配合 `bindController` 使用,注册后可以在`@virid/vue`中使用`useController`获得实例。
117
+ - **示例:**
118
+
119
+ ```ts
120
+ @Controller()
121
+ class PageController {}
122
+ // 使用之前要注册
123
+ app.bindController(PageController)
124
+ ```
125
+
126
+ #### `@Component()`
127
+
128
+ - **功能**:标记一个类为**数据实体**,该类将作为全局单例,并一直存在。
129
+ - **设计**:配合 `bindComponent` 使用,注册后可以在System中声明类型以获得依赖注入功能。
130
+ - **示例:**
131
+
132
+ ```ts
133
+ @Component()
134
+ class CounterComponent {
135
+ public count = 0;
136
+ }
137
+ // 使用之前要注册
138
+ app.bindController(CounterComponent)
139
+ ```
140
+
141
+ #### `@System(params?)`
142
+
143
+ - **功能**:将静态方法注册为业务逻辑处理器。它实现了“依赖自动装配”。只需要在参数里写上对应的 `Component` 类型,引擎就会在执行时自动注入实例。
144
+ - **参数**:
145
+ - `priority`: 执行优先级。数值越大,在同一个 `Tick` 中执行越早。
146
+ - `messageClass`: 触发该System需要的消息类型,不能与`@Message`共存
147
+ - **示例**:
148
+
149
+ ```ts
150
+ import {
151
+ System,
152
+ Message,
153
+ } from "@virid/core";
154
+
155
+ class CounterSystem {
156
+ // 可以为System设置优先级
157
+ // count参数将被自动注入
158
+ @System({ priority: 0})
159
+ static onIncrement(
160
+ @Message(IncrementMessage) message: IncrementMessage,
161
+ count: CounterComponent,
162
+ ) {
163
+ count.count += message.amount;
164
+ }
165
+ //可以不使用@Message
166
+ @System({messageClass:IncrementMessage})
167
+ static onIncrement(
168
+ count: CounterComponent,
169
+ ) {
170
+ count.count += 1;
171
+ }
172
+ @System()
173
+ static onProcess(msg: SomeMessage) {
174
+ // 直接 return 消息,即可实现逻辑链式触发,无需手动调用 MessageWriter
175
+ // 也可以return一个message数组来连续触发
176
+ return new NextStepMessage();
177
+ }
178
+ }
179
+ //直接通过.send来发送消息
180
+ IncrementMessage.send(5);
181
+ ```
182
+
183
+ #### `@Message(Class, single?)`
184
+
185
+ - **功能**:参数级装饰器,明确当前 `System` 关注的消息类型。
186
+ - **批处理模式**:若设置 `single: false`,`System` 会收到一个包含本轮 `Tick` 内所有该消息的数组,适用于高性能的批量计算(如物理引擎或日志聚合)。
187
+ - **示例:**见System
188
+
189
+ ### `@Observer(callback)`
190
+
191
+ - **功能**:属性级变更监听,用于处理那些“非指令驱动”的副作用
192
+ - **逻辑**:当 `Component` 中被标记的属性发生变更时,引擎会自动触发指定的回调函数。
193
+ - **示例**:
194
+
195
+ ```ts
196
+ @Component()
197
+ class PlayerComponent {
198
+ // 当 progress 变更时,自动发送一个同步消息或执行回调
199
+ @Observer((old, val) => new SyncLyricMessage(val))
200
+ public progress = 0;
201
+ }
202
+ ```
203
+
204
+ ### `@Safe()`
205
+
206
+ - **功能**:方法访问权限标记,在`Virid`中外部环境(UI 层)严禁直接修改逻辑层数据,所有的修改和方法调用都会被拦截。但对于某些“只读类”或“安全计算类”方法,可以通过 `@Safe()` 显式授权,允许视图层直接调用。
207
+ - **设计**:主要服务于 `@virid/vue` 等外部投影层,详情见`@virid/vue`中的`Deep Shield`
208
+ - **示例**:
209
+
210
+ ```ts
211
+ @Component()
212
+ class PlayerComponent {
213
+ // 如果不加Safe,virid将会禁止在任何vue的controller中调用该方法
214
+ @Safe()
215
+ public someMethod(){}
216
+ }
217
+ ```
218
+
219
+ ------
220
+
221
+ ### 4. 调度与拦截 (Dispatcher & Hooks)
222
+
223
+ #### `Dispatcher`
224
+
225
+ - **核心逻辑**:
226
+ 1. **双缓冲交换 (Flip)**:调度器基于逻辑Tick运行,以微任务开始为起点,直到系统内部不在产生新的Message为止为一个逻辑Tick。每次执行调度器锁定当前待处理消息,新产生的消息自动进入下一轮。
227
+ 2. **死循环熔断**:若递归执行深度 `internalDepth > 100`,立即停止执行并报错,保护主线程不被逻辑黑洞卡死。
228
+
229
+ #### 生命周期钩子 (Life-Cycle Hooks)
230
+
231
+ - `onBeforeTick` / `onAfterTick`: 监控逻辑帧的脉搏。
232
+ - `onBeforeExecute` / `onAfterExecute`: 针对特定消息的执行全过程进行审计。
233
+ - **示例**:
234
+
235
+ ```ts
236
+ const app = createVirid();
237
+ app.onBeforeExecute(MyMessage, (msg, context) => {
238
+ // 可以在这里实现全局的性能追踪或权限校验
239
+ // 只会对MyMessage和子类消息生效
240
+ });
241
+ app.onAfterTick((context) => {
242
+ console.log("----------------onAfterTick------------------");
243
+ });
244
+ ```
245
+
246
+ ------
247
+
248
+ ### 5. 系统通讯 (IO)
249
+
250
+ #### `MessageWriter`
251
+
252
+ - **功能**:全局静态通讯工具。
253
+ - **API**:
254
+ - `MessageWriter.write(MessageClass, ...args)`: 发送消息的底层入口。
255
+ - `MessageWriter.error(Error, context?)`: 抛出一个系统级错误,它会自动触发 `ErrorMessage`。
256
+ - `MessageWriter.warn(context)`: 写入一个警告,他会自动触发`WarnMessage`。
257
+ - `MessageWriter.info(context)`: 写入一个信息,它会自动触发 `InfoMessage`。
258
+
259
+ ------
260
+
261
+ ## 🔬 进阶:原子化修改 (Atomic Operations)
262
+
263
+ #### `AtomicModifyMessage`
264
+
265
+ - **功能**:提供一种“即插即用”的临时逻辑修改方案。
266
+ - **场景**:当你需要对某个 `Component` 进行一次性的观察或微调,又不想专门写一个 `System` 时,可以使用此消息在下一帧执行一段闭包逻辑。
267
+ - **示例**:
268
+
269
+ ```ts
270
+ AtomicModifyMessage.send(
271
+ CounterComponent,
272
+ (comp) => {
273
+ console.log("----------------AtomicModifyMessage------------------");
274
+ },
275
+ "Check CounterComponent",
276
+ );
277
+ ```
278
+
package/dist/index.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @virid/core v0.0.1
2
+ * @virid/core v0.1.1
3
3
  * A lightweight and powerful message core built using dependency injection and CCS concepts
4
4
  */
5
5
  var C=Object.defineProperty;var ue=Object.getOwnPropertyDescriptor;var de=Object.getOwnPropertyNames;var fe=Object.prototype.hasOwnProperty;var pe=(s,e,t)=>e in s?C(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var o=(s,e)=>C(s,"name",{value:e,configurable:!0});var ge=(s,e)=>{for(var t in e)C(s,t,{get:e[t],enumerable:!0})},me=(s,e,t,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of de(e))!fe.call(s,n)&&n!==t&&C(s,n,{get:()=>e[n],enumerable:!(r=ue(e,n))||r.enumerable});return s};var ye=s=>me(C({},"__esModule",{value:!0}),s);var i=(s,e,t)=>pe(s,typeof e!="symbol"?e+"":e,t);var He={};ge(He,{AtomicModifyMessage:()=>w,BaseMessage:()=>y,Component:()=>$e,Controller:()=>Ae,ErrorMessage:()=>v,EventMessage:()=>p,InfoMessage:()=>S,Message:()=>we,MessageInternal:()=>M,MessageRegistry:()=>E,MessageWriter:()=>a,Observer:()=>Me,Safe:()=>Ee,SingleMessage:()=>x,System:()=>ke,VIRID_METADATA:()=>g,WarnMessage:()=>b,activateInstance:()=>J,bindObservers:()=>R,createVirid:()=>Ce,handleResult:()=>A,publisher:()=>oe});module.exports=ye(He);var j=class j{static send(...e){a.write(this,...e)}};o(j,"BaseMessage");var y=j,L=class L extends y{constructor(){super();i(this,"__kind","SingleMessage")}};o(L,"SingleMessage");var x=L,W=class W extends y{constructor(){super();i(this,"__kind","EventMessage")}};o(W,"EventMessage");var p=W,F=class F extends p{constructor(t,r){super();i(this,"error");i(this,"context");this.error=t,this.context=r}};o(F,"ErrorMessage");var v=F,Q=class Q extends p{constructor(t){super();i(this,"context");this.context=t}};o(Q,"WarnMessage");var b=Q,z=class z extends p{constructor(t){super();i(this,"context");this.context=t}};o(z,"InfoMessage");var S=z,U=class U extends p{constructor(t,r,n){super();i(this,"ComponentClass");i(this,"recipe");i(this,"label");this.ComponentClass=t,this.recipe=r,this.label=n}};o(U,"AtomicModifyMessage");var w=U;var D=null;function J(s){D=s}o(J,"activateInstance");var oe=new Proxy({},{get(s,e){return e==="dispatch"?t=>{if(!D){console.error(`[Virid] Message dispatched before system init: ${t.constructor.name}`);return}return D.dispatch(t)}:Reflect.get(D||{},e)}}),Y=class Y{static write(e,...t){let r=typeof e=="function"?new e(...t):e;oe.dispatch(r)}static error(e,t=""){this.write(new v(e,t))}static warn(e){this.write(new b(e))}static info(e){this.write(new S(e))}};o(Y,"MessageWriter");var a=Y;var q=class q{constructor(e){i(this,"dirtySignalTypes",new Set);i(this,"eventQueue",[]);i(this,"isRunning",!1);i(this,"globalTick",0);i(this,"internalDepth",0);i(this,"eventHub");i(this,"tickPayload",{});i(this,"beforeExecuteHooks",[]);i(this,"afterExecuteHooks",[]);i(this,"beforeTickHooks",[]);i(this,"afterTickHooks",[]);this.eventHub=e}addBeforeExecute(e,t,r){r?this.beforeExecuteHooks.unshift({type:e,handler:t}):this.beforeExecuteHooks.push({type:e,handler:t})}addAfterExecute(e,t,r){r?this.afterExecuteHooks.unshift({type:e,handler:t}):this.afterExecuteHooks.push({type:e,handler:t})}addBeforeTick(e,t){t?this.beforeTickHooks.unshift(e):this.beforeTickHooks.push(e)}addAfterTick(e,t){t?this.afterTickHooks.unshift(e):this.afterTickHooks.push(e)}markDirty(e){e instanceof p?this.eventQueue.push(e):e instanceof x&&this.dirtySignalTypes.add(e.constructor)}tick(e){if(!(this.isRunning||this.dirtySignalTypes.size===0&&this.eventQueue.length===0)){if(this.internalDepth>100){this.internalDepth=0,this.dirtySignalTypes.clear(),this.eventQueue=[],this.eventHub.reset(),a.error(new Error("[Virid Dispatcher] Deadlock: Recursive loop detected \u{1F4A5}."));return}this.isRunning=!0,this.internalDepth++,queueMicrotask(()=>{let t,r;try{this.internalDepth==0&&(this.tickPayload={},this.executeTickHooks(this.beforeTickHooks));let n=this.prepareSnapshot();t=n.signalSnapshot,r=n.eventSnapshot;let u=this.collectTasks(r,t,e);this.executeTasks(u)}catch(n){a.error(n,"[Virid Dispatcher] Unhandled Error")}finally{t&&r&&this.clear(r,t),this.isRunning=!1,this.dirtySignalTypes.size>0||this.eventQueue.length>0?this.tick(e):(this.executeTickHooks(this.afterTickHooks),this.globalTick++,this.internalDepth=0)}})}}collectTasks(e,t,r){let n=[];for(let l of e)(r.get(l.constructor)||[]).forEach(f=>{n.push(new P(f.fn,f.priority,l,{context:f.fn.systemContext,tick:this.globalTick,payload:{}}))});let u=new Set;for(let l of t)(r.get(l)||[]).forEach(f=>{u.has(f.fn)||(n.push(new P(f.fn,f.priority,this.eventHub.peekSignal(l),{context:f.fn.systemContext,tick:this.globalTick,payload:{}})),u.add(f.fn))});return n}executeTasks(e){e.sort((t,r)=>r.priority-t.priority);for(let t of e)try{let r=t.execute(this.beforeExecuteHooks,this.afterExecuteHooks);r instanceof Promise&&r.catch(n=>a.error(n,`[Virid Dispatcher]: Async System Error.
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @virid/core v0.0.1
2
+ * @virid/core v0.1.1
3
3
  * A lightweight and powerful message core built using dependency injection and CCS concepts
4
4
  */
5
5
  var se=Object.defineProperty;var he=(s,e,t)=>e in s?se(s,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):s[e]=t;var o=(s,e)=>se(s,"name",{value:e,configurable:!0});var i=(s,e,t)=>he(s,typeof e!="symbol"?e+"":e,t);var G=class G{static send(...e){a.write(this,...e)}};o(G,"BaseMessage");var y=G,j=class j extends y{constructor(){super();i(this,"__kind","SingleMessage")}};o(j,"SingleMessage");var x=j,L=class L extends y{constructor(){super();i(this,"__kind","EventMessage")}};o(L,"EventMessage");var g=L,W=class W extends g{constructor(t,r){super();i(this,"error");i(this,"context");this.error=t,this.context=r}};o(W,"ErrorMessage");var v=W,F=class F extends g{constructor(t){super();i(this,"context");this.context=t}};o(F,"WarnMessage");var b=F,Q=class Q extends g{constructor(t){super();i(this,"context");this.context=t}};o(Q,"InfoMessage");var S=Q,z=class z extends g{constructor(t,r,n){super();i(this,"ComponentClass");i(this,"recipe");i(this,"label");this.ComponentClass=t,this.recipe=r,this.label=n}};o(z,"AtomicModifyMessage");var M=z;var V=null;function ne(s){V=s}o(ne,"activateInstance");var ue=new Proxy({},{get(s,e){return e==="dispatch"?t=>{if(!V){console.error(`[Virid] Message dispatched before system init: ${t.constructor.name}`);return}return V.dispatch(t)}:Reflect.get(V||{},e)}}),U=class U{static write(e,...t){let r=typeof e=="function"?new e(...t):e;ue.dispatch(r)}static error(e,t=""){this.write(new v(e,t))}static warn(e){this.write(new b(e))}static info(e){this.write(new S(e))}};o(U,"MessageWriter");var a=U;var J=class J{constructor(e){i(this,"dirtySignalTypes",new Set);i(this,"eventQueue",[]);i(this,"isRunning",!1);i(this,"globalTick",0);i(this,"internalDepth",0);i(this,"eventHub");i(this,"tickPayload",{});i(this,"beforeExecuteHooks",[]);i(this,"afterExecuteHooks",[]);i(this,"beforeTickHooks",[]);i(this,"afterTickHooks",[]);this.eventHub=e}addBeforeExecute(e,t,r){r?this.beforeExecuteHooks.unshift({type:e,handler:t}):this.beforeExecuteHooks.push({type:e,handler:t})}addAfterExecute(e,t,r){r?this.afterExecuteHooks.unshift({type:e,handler:t}):this.afterExecuteHooks.push({type:e,handler:t})}addBeforeTick(e,t){t?this.beforeTickHooks.unshift(e):this.beforeTickHooks.push(e)}addAfterTick(e,t){t?this.afterTickHooks.unshift(e):this.afterTickHooks.push(e)}markDirty(e){e instanceof g?this.eventQueue.push(e):e instanceof x&&this.dirtySignalTypes.add(e.constructor)}tick(e){if(!(this.isRunning||this.dirtySignalTypes.size===0&&this.eventQueue.length===0)){if(this.internalDepth>100){this.internalDepth=0,this.dirtySignalTypes.clear(),this.eventQueue=[],this.eventHub.reset(),a.error(new Error("[Virid Dispatcher] Deadlock: Recursive loop detected \u{1F4A5}."));return}this.isRunning=!0,this.internalDepth++,queueMicrotask(()=>{let t,r;try{this.internalDepth==0&&(this.tickPayload={},this.executeTickHooks(this.beforeTickHooks));let n=this.prepareSnapshot();t=n.signalSnapshot,r=n.eventSnapshot;let u=this.collectTasks(r,t,e);this.executeTasks(u)}catch(n){a.error(n,"[Virid Dispatcher] Unhandled Error")}finally{t&&r&&this.clear(r,t),this.isRunning=!1,this.dirtySignalTypes.size>0||this.eventQueue.length>0?this.tick(e):(this.executeTickHooks(this.afterTickHooks),this.globalTick++,this.internalDepth=0)}})}}collectTasks(e,t,r){let n=[];for(let l of e)(r.get(l.constructor)||[]).forEach(f=>{n.push(new D(f.fn,f.priority,l,{context:f.fn.systemContext,tick:this.globalTick,payload:{}}))});let u=new Set;for(let l of t)(r.get(l)||[]).forEach(f=>{u.has(f.fn)||(n.push(new D(f.fn,f.priority,this.eventHub.peekSignal(l),{context:f.fn.systemContext,tick:this.globalTick,payload:{}})),u.add(f.fn))});return n}executeTasks(e){e.sort((t,r)=>r.priority-t.priority);for(let t of e)try{let r=t.execute(this.beforeExecuteHooks,this.afterExecuteHooks);r instanceof Promise&&r.catch(n=>a.error(n,`[Virid Dispatcher]: Async System Error.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@virid/core",
3
3
  "type": "module",
4
- "version": "0.1.0",
4
+ "version": "0.1.2",
5
5
  "description": "A lightweight and powerful message core built using dependency injection and CCS concepts",
6
6
  "author": "Ailrid",
7
7
  "license": "Apache 2.0",
@@ -15,7 +15,7 @@
15
15
  ],
16
16
  "repository": {
17
17
  "type": "git",
18
- "url": "git+https://github.com/ArisuYuki/virid.git"
18
+ "url": "git+https://github.com/Ailrid/virid.git"
19
19
  },
20
20
  "main": "./dist/index.cjs",
21
21
  "module": "./dist/index.js",