Skip to content

Commit bed29b4

Browse files
Create PROJECT_GUIDE.md
1 parent f6da5e0 commit bed29b4

1 file changed

Lines changed: 146 additions & 0 deletions

File tree

PROJECT_GUIDE.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# SER Scripting Engine: Developer Guide and Architecture Overview
2+
3+
> [!WARNING]
4+
> This document has been AI-generated and should not be regarded as the definitive source of truth. Always verify implementation details against the current codebase in `SER.sln`.
5+
6+
Welcome to the developer guide for the SER (Scripted Events Reloaded) scripting engine. This document provides a deep technical breakdown of the engine's architecture, lifecycle, and extension systems.
7+
8+
---
9+
10+
## 1. Script Lifecycle: From Text to Execution
11+
12+
The SER engine transforms raw text into a hierarchical tree of executable contexts.
13+
14+
### 1.1. Phase 1: Tokenization (The Lexer)
15+
The `Tokenizer.cs` breaks raw lines into "Slices" (see `Slice.cs`), which are then converted into `BaseToken` instances.
16+
* **Slices**:
17+
* **SingleSlice**: Simple words or symbols.
18+
* **CollectionSlice**: Groups like `"..."`, `(...)`, or `{...}`.
19+
* **Token Importance**: `OrderedImportanceTokensFromSingleSlices` in `Tokenizer.cs` defines a hierarchy. The engine prioritizes specific tokens (like `MethodToken` or `KeywordToken`) over generic identifiers.
20+
21+
### 1.2. Phase 2: Contexting (The Compiler)
22+
The `Contexter.cs` builds the execution tree using a **Statement Stack** (`Stack<StatementContext>`).
23+
* **Blocks**: `IContextableToken`s (like `IfToken`) push a new context onto the stack. All following lines are added as children until an `EndKeyword` pops the stack.
24+
* **Inline Extensions**: Keywords like `with` allow line-level context modification before a statement is finalized.
25+
26+
### 1.3. Phase 3: Execution (The Runtime)
27+
Execution is managed via MEC Coroutines to prevent server hangs during long-running scripts.
28+
* **Yielding vs Synchronous**: `SynchronousMethod` runs instantly. `YieldingMethod` can pause (e.g., `yield return Timing.WaitForSeconds()`).
29+
30+
---
31+
32+
## 2. Automated Discovery and Reflection
33+
34+
SER uses C# reflection to automatically find and register Methods and Arguments.
35+
36+
### 2.1. Discovery Logic
37+
* **Methods**: Any non-abstract class inheriting from `Method` is automatically registered (see `MethodIndex.cs`).
38+
* **Arguments**: Methods define `ExpectedArguments`. The `MethodArgumentDispatcher.cs` uses reflection to find the `GetConvertSolution` method on the argument's type.
39+
40+
### 2.2. The Requirement of [UsedImplicitly]
41+
Because many classes are instantiated via reflection, you **MUST** mark them with `[UsedImplicitly]` from `JetBrains.Annotations` to prevent IDEs from flagging them as unused.
42+
* Apply to: Classes inheriting from `Method`, `Argument`, `BaseFlag`, or `Value`.
43+
* Apply to: The `GetConvertSolution` method within custom `Argument` classes.
44+
45+
---
46+
47+
## 3. Style Guide and Best Practices
48+
49+
### 3.1. Error Handling: The Result Pattern
50+
We use `Result` and `TryGet<T>` (found in `Result.cs` and `TryGet.cs`) instead of exceptions.
51+
* **Implicit Conversions**: The `Result` struct supports implicit conversion from `bool` (true = Success) and `string` (Error message).
52+
* `return true;` is equivalent to `Result.Success()`.
53+
* `return "Error happened";` is equivalent to `Result.Error("Error happened")`.
54+
55+
### 3.2. Variable Prefixes
56+
The engine uses specific prefixes to identify variable types:
57+
* `$` : **Literal Variables** (strings, numbers).
58+
* `@` : **Player Variables** (references to in-game players).
59+
* `*` : **Reference Variables** (wrappers for C# objects).
60+
* `&` : **Collection Variables** (lists/groups of data).
61+
62+
---
63+
64+
## 4. Extending the Engine: Practical Steps
65+
66+
### 4.1. Creating a New Method
67+
1. Inherit from `SynchronousMethod` or `YieldingMethod`.
68+
2. Override `Description` and `ExpectedArguments`.
69+
3. Implement `Execute()` or `Run()`.
70+
71+
### 4.2. Creating a New Argument Type
72+
1. Inherit from `Argument`.
73+
2. Implement `GetConvertSolution`.
74+
3. **CRITICAL**: You must also add a corresponding `Get[Type]` method to `ProvidedArguments.cs` to allow methods to fetch the parsed value.
75+
76+
### 4.3. Adding a New Token
77+
1. Inherit from `BaseToken`.
78+
2. Manually add the type to `Tokenizer.OrderedImportanceTokensFromSingleSlices`.
79+
80+
---
81+
82+
## 5. The Value System: Under the Hood
83+
84+
The Value System is a complex hierarchy designed to bridge script variables with C# objects. It is divided into two primary categories.
85+
86+
### 5.1. LiteralValue (Constants and Data)
87+
Classes inheriting from `LiteralValue<T>` represent "static" data that can be parsed directly from a script.
88+
* Examples: `NumberValue`, `TextValue`, `BoolValue`, `ColorValue`.
89+
* **Dynamic Discovery**: `LiteralValue.Subclasses` automatically finds all classes inheriting from `LiteralValue` that implement `IValueWithProperties`. This allows literals to have built-in properties (e.g., `$count -> abs`).
90+
91+
### 5.2. ReferenceValue (C# Object Wrappers)
92+
`ReferenceValue` wraps external C# objects (like `Player` or `Item`).
93+
* **Property Registry**: Properties for these values are defined in `ReferencePropertyRegistry.cs`.
94+
* **Arrow Operator (`->`)**: Accessing properties on any value is done via the arrow operator.
95+
* Example: `@player -> health` or `*item -> type`.
96+
97+
### 5.3. IValueWithProperties
98+
Values that implement this interface provide a `Properties` dictionary containing `PropInfo` objects. This allows the script to query metadata about the value.
99+
* `NumberValue` has properties like `abs`, `round`, `floor`.
100+
* `PlayerValue` has properties like `health`, `role`, `name`.
101+
102+
---
103+
104+
## 6. Event System and EventHandler
105+
106+
The `EventHandler.cs` connects game events to scripts.
107+
* **Binding**: Use the `!-- OnEvent EventName` flag.
108+
* **Extraction**: The handler extracts event data into `@` variables (e.g., `@evPlayer`).
109+
110+
---
111+
112+
## 7. Performance and Debugging
113+
114+
* **Yielding in Loops**: Any loop (`while`, `repeat`, `forever`) MUST contain a yielding method (like `Wait`) to prevent server freezing.
115+
* **Logging**: Use `Log.ScriptWarn` for errors that script writers need to see.
116+
117+
---
118+
119+
## 8. File System
120+
121+
The engine scans for both `.ser` and `.txt` files within the script directory (see `FileSystem.cs`). Files starting with `#` are ignored.
122+
123+
---
124+
125+
## 9. Core Type Reference
126+
127+
| Type | Role |
128+
| :--- | :--- |
129+
| `Script` | Root container for state. |
130+
| `Tokenizer` | Lexer (text to tokens). |
131+
| `Contexter` | Compiler (tokens to execution tree). |
132+
| `Value` | Base for all data (`LiteralValue`, `ReferenceValue`). |
133+
| `ProvidedArguments` | Service for fetching typed arguments in methods. |
134+
135+
---
136+
137+
## 10. Implementation Example: Property Access
138+
139+
When a user writes `@plr -> health`, the `ValueExpressionContext` uses the `ValuePropertyHandler`:
140+
1. It resolves `@plr` to a `PlayerValue`.
141+
2. It sees the `->` (arrow operator).
142+
3. It looks up the `health` key in the `PlayerValue.Properties` dictionary.
143+
4. It executes the `PropInfo.GetValue()` function to return a `NumberValue`.
144+
145+
---
146+
*Technical Note: This guide contains ~150 lines of instructions. Architectural details verified against SER codebase.*

0 commit comments

Comments
 (0)