Files
netease-modsdk-wiki/docs/wiki/modsdk/why-system.md
2025-03-20 11:52:46 +08:00

181 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
hidden: true
---
### 🧩 为什么需要两个系统System用餐厅来理解
想象一下游戏就像一家餐厅:
- **服务器系统** = 厨房(决定食物实际内容)
- **客户端系统** = 餐厅前厅(呈现给顾客看到的体验)
```mermaid
graph TB
subgraph "游戏架构(像餐厅一样)"
ServerSystem["服务器系统(厨房)"] -->|发送实际变化| ClientSystem["客户端系统(前厅)"]
ClientSystem -->|发送玩家请求| ServerSystem
end
```
### 👨‍🍳 服务器系统:游戏的"厨房"
- **职责**: 决定游戏中真正发生了什么
- **简单理解**:
- 计算伤害(怪物真的死了吗?)
- 决定方块是否被破坏
- 控制物品掉落
- 存储真实的游戏数据
### 👨‍💼 客户端系统:游戏的"前厅"
- **职责**: 让玩家看到并互动
- **简单理解**:
- 显示画面和声音
- 处理你的鼠标点击和按键
- 播放爆炸、火焰等特效
- 展示菜单和界面
### 📮 系统间如何交流:像传纸条一样
当你在游戏中点击方块,发生了什么?
```mermaid
sequenceDiagram
participant 你
participant 前厅 as 客户端
participant 厨房 as 服务器
你->>前厅: 点击挖石头
前厅->>厨房: 传纸条:"玩家想挖石头"
厨房->>厨房: 检查:允许挖吗?
厨房->>前厅: 回复:"可以,石头没了,掉落石头物品"
前厅->>你: 播放挖矿动画和声音,显示物品
```
### ⚠️ 为什么不能混在一起?
就像餐厅里顾客不能随便进厨房一样:
- ❌ 客户端不能直接修改游戏数据(否则会作弊)
- ❌ 服务器不负责播放声音和动画(它只关心真实数据)
### 🌟 简单例子:击打树木得钻石
### 简化理解版
1. **你点击树木**(客户端检测到)
2. **客户端发消息**"嘿,服务器,玩家点击了这棵树"
3. **服务器决定**"好,我给他一颗钻石"
4. **服务器通知客户端**"请在玩家背包里显示一颗新钻石"
5. **客户端更新画面**:你看到钻石出现在背包里
### 🔑 记住这个简单规则
想象游戏是一部电影:
- **服务器是导演**(决定故事情节)
- **客户端是摄像机和屏幕**(展示给观众看)
记住:**服务器决定发生什么,客户端决定如何展示**
### 💡 初学者提示
如果遇到问题,先问自己:
- "这个功能应该由谁负责?是真实游戏规则还是显示效果?"
- "我需要发送什么消息让另一边知道?"
学会这种思考方式你的Mod就能正确运行啦
### :ribbon: 那么总结一下吧!
#### 核心架构:客户端-服务器分离
```mermaid
graph TB
subgraph "游戏架构"
ServerSystem["服务器系统(游戏逻辑)"] -->|发送状态更新| ClientSystem["客户端系统(视觉呈现)"]
ClientSystem -->|发送玩家操作| ServerSystem
ServerSystem -->|读写| GameState["游戏状态(权威数据)"]
ServerSystem -->|管理| Components["游戏组件"]
ClientSystem -->|渲染| UI["界面与特效"]
end
```
#### 双系统模型的必要性
##### 服务器系统 (ServerSystem)
- **职责**: 维护游戏的"真实状态"
- **具体功能**:
- 处理游戏核心逻辑(如战斗计算、物品掉落)
- 管理AI行为与路径寻找
- 执行世界生成与物理规则
- **拥有数据的最终决定权**
##### 客户端系统 (ClientSystem)
- **职责**: 处理玩家的直接体验
- **具体功能**:
- 渲染游戏画面与UI界面
- 处理玩家输入
- 播放音效与粒子效果
- 进行预测性渲染(平滑过渡)
#### 系统间通信的关键:事件机制
```mermaid
sequenceDiagram
participant Player as 玩家
participant Client as 客户端系统
participant Server as 服务器系统
Player->>Client: 点击方块
Client->>Server: 发送BlockUseEvent事件
Server->>Server: 处理游戏逻辑
Server->>Client: 发送状态更新事件
Client->>Player: 显示视觉反馈
```
##### 事件驱动设计的优势
- **松耦合**: 系统间无需直接相互调用
- **可扩展**: 多个系统可响应同一事件
- **清晰职责**: 服务端决定结果,客户端呈现效果
##### 实例:击打方块流程
1. **客户端**: 检测到玩家点击方块,发送`BlockUseEvent`
2. **服务端**:
- 接收到事件,判断方块是否可被破坏
- 更新方块状态,计算掉落物
3. **客户端**:
- 播放方块破坏动画和音效
- 显示掉落物
#### 常见问题与最佳实践
##### 避免的错误模式
- ❌ 在客户端直接修改游戏状态
- ❌ 在服务端处理UI渲染逻辑
- ❌ 遗漏事件监听导致功能不同步
##### 最佳实践
- ✅ 服务端验证所有游戏逻辑(防作弊)
- ✅ 合理使用自定义事件进行系统间通信
- ✅ 保持客户端代码专注于视觉体验优化
- ✅ 在事件参数中携带足够的上下文信息
#### 跨系统通信示例
```python
# 服务端发送自定义事件到客户端
def spawn_special_effect(self, position):
comp = serverApi.GetEngineCompFactory().CreateGame(serverApi.GetLevelId())
comp.NotifyToClient(player_id, "ShowSpecialEffect", {"position": position})
# 客户端监听并处理
def listen_events(self):
self.ListenForEvent("MyMod", "MyServerSystem", "ShowSpecialEffect",
self, self.on_special_effect)
def on_special_effect(self, event_data):
pos = event_data["position"]
# 在客户端显示特效...
```
通过掌握客户端-服务端分离的设计模式你将能够创建更稳定、可扩展且性能优秀的Mod。记住**服务端决定发生什么,客户端决定如何展示**。