2.6
This commit is contained in:
118
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/0-中国版特效的配置.md
Normal file
118
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/0-中国版特效的配置.md
Normal file
@@ -0,0 +1,118 @@
|
||||
# 中国版特效的使用
|
||||
|
||||
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=64818d8ec31a9c0f360dc5de" width="800" height="600" allow="fullscreen"/>
|
||||
|
||||
在我的世界中国版中的特效,有两种:
|
||||
|
||||
- 微软特效
|
||||
- 中国版特效
|
||||
|
||||
微软特效是游戏原生支持的特效,使用`/particle`原版指令来生成。
|
||||
|
||||
中国版特效基于特效编辑器来制作,可以实现更多效果的特效。
|
||||
|
||||
中国版特效主要有两种形式,它们应用的场景各不相同
|
||||
|
||||
- 序列帧特效:通过在场景中绘制一张单面片的贴图,在这个贴图上不断的更换新的图片,这个过程形成完整的序列帧特效。
|
||||
- 粒子特效:通过在场景中生成大量粒子图像来产生视觉效果,每个粒子都代表着效果中的单个元素,所有的粒子组合起来就形成了完整的粒子特效。
|
||||
|
||||
特效编辑器的使用教程,可以参考[官方文档](https://mc.163.com/dev/mcmanual/mc-dev/mcguide/16-%E7%BE%8E%E6%9C%AF/9-%E7%89%B9%E6%95%88/00-%E7%89%B9%E6%95%88%E7%BC%96%E8%BE%91%E5%99%A8%E7%AE%80%E4%BB%8B.html?catalog=1)。本教程将主要介绍,如何使用官方内容库中的现成的特效,将其使用到开服工具2.0制作的网络游戏中。
|
||||
|
||||
## 素材下载和导入
|
||||
|
||||
开发者工作台的内容库中,包含了众多已经编辑好的特效包,可以供开发者自由使用。
|
||||
|
||||
本教程中,下载`代号羲和特效包`,并以该特效包为例,介绍如何在游戏中使用这些特效。
|
||||
|
||||

|
||||
|
||||
点击下载按钮后,我们可以新建一个空白基岩版附加包,用来导入、调试这个特效。
|
||||
|
||||
打开编辑器后,在左上角选择`特效`,切换到特效编辑器。
|
||||
|
||||

|
||||
|
||||
在编辑器打开的情况下,切换到开发者工作台的内容库,点击导入按钮,即可导入特效包。
|
||||
|
||||

|
||||
|
||||
弹出的对话框,全选导入即可。
|
||||
|
||||

|
||||
|
||||
这时在资源管理窗口中,切换到中国版特效分类,就可以看到所有我们导入的特效。
|
||||
|
||||

|
||||
|
||||
如果需要预览特效,可以将特效拖动到模型挂接的窗口中,然后点击播放按钮进行播放。
|
||||
|
||||
比如将Attack_2这个特效,拖动到`head`上,可以看到它是粒子特效。点击时间轴的播放按钮,就可以看到特效在玩家模型头部被播放。
|
||||
|
||||

|
||||
|
||||
选中Attack_2这个特效后,右侧属性窗口可以看到粒子特效的相关属性设置。
|
||||
|
||||
主要包括粒子的尺寸、速度、旋转、发射器的设置等等参数。
|
||||
|
||||

|
||||
|
||||
除此之外,资源包中还有部分序列帧特效,例如`test_xuanyun`这个特效。挂接播放后可以看到,它就是一个不断变化的图片。
|
||||
|
||||
属性窗口中也只有贴图相关选项,没有粒子的发射器等参数。
|
||||
|
||||

|
||||
|
||||
## 使用代码控制播放
|
||||
|
||||
我们可以首先新建一个插件,比如这里名为`testEffects`,删除其`developer_mods`的内容后,复制到Mod目录。
|
||||
|
||||
然后对刚刚创建的空白附加包右键,打开目录
|
||||
|
||||

|
||||
|
||||
将资源包目录中的`effects`,`particles`,`textures`文件夹,复制到插件的资源包目录。
|
||||
|
||||
这三个文件夹 分别存放了`中国版特效`,`原版特效`,`材质`,如果需要完整的使用特效包内的特效,缺一不可。
|
||||
|
||||

|
||||
|
||||
### 粒子
|
||||
|
||||
接下来就是代码编写的部分,模组SDK内提供了丰富的接口来控制特效的播放,参考[链接](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/%E6%8E%A5%E5%8F%A3/%E7%89%B9%E6%95%88/%E7%B2%92%E5%AD%90.html?catalog=1#createengineparticle)。
|
||||
|
||||
例如我们可以将播放特效的代码封装到一个函数内,然后另外编写监听来自服务器的事件的代码,通过服务器控制粒子特效的播放。
|
||||
|
||||
```python
|
||||
def PlayEffect(self, effectName, pos):
|
||||
particleEntityId = self.CreateEngineParticle(effectName, pos)
|
||||
particleControlComp = clientApi.GetEngineCompFactory().CreateParticleControl(particleEntityId)
|
||||
particleControlComp.Play()
|
||||
return particleEntityId
|
||||
```
|
||||
|
||||
例如监听来自服务端的PlayEffectEvent,播放特效,服务端的部分大同小异,这里不再介绍。
|
||||
|
||||
```python
|
||||
def __init__(self, namespace, systemName):
|
||||
ClientSystem.__init__(self, namespace, systemName)
|
||||
self.ListenForEvent(EffectsConst.ModName, EffectsConst.ServerSystemName, "PlayEffectEvent", self, self.OnPlayEffect)
|
||||
|
||||
def OnPlayEffect(self, args):
|
||||
name = args["name"]
|
||||
pos = tuple(args["pos"])
|
||||
particleId = self.PlayEffect(name, pos)
|
||||
print "播放了特效,实体id", particleId
|
||||
```
|
||||
|
||||
### 序列帧
|
||||
|
||||
序列帧的播放控制代码和粒子略有不同,参考[文档](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/%E6%8E%A5%E5%8F%A3/%E7%89%B9%E6%95%88/%E5%BA%8F%E5%88%97%E5%B8%A7.html?catalog=1)。
|
||||
|
||||
主要通过两个接口创建序列帧特效:
|
||||
|
||||
- CreateEngineSfx
|
||||
- CreateEngineSfxFromEditor
|
||||
|
||||
推荐使用`CreateEngineSfxFromEditor`,可以按照编辑器中编辑好的参数创建序列帧。支持环状序列帧。
|
||||
|
||||
在完成创建后,也可以使用其他接口对序列帧特效进行控制,使用上和粒子特效大同小异。
|
||||
@@ -0,0 +1,121 @@
|
||||
# BlockBench模型的使用
|
||||
|
||||
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=64818e09ef3bb6958baf3886" width="800" height="600" allow="fullscreen"/>
|
||||
|
||||
在制作游戏玩法时,经常会遇到需要修改玩家模型,或者实体模型的场景。我们可以使用Blockbench制作的模型,配合模组SDK来轻松实现修改实体模型的功能。
|
||||
|
||||
## 本地玩家模型的修改
|
||||
|
||||
在开始之前,首先前往内容库,找到`Spigot示例Demo`,下载并打开。本节课将使用官方Demo中提供的模型素材来进行演示。
|
||||
|
||||
接下来创建一个插件,这里命名为`testModel`,复制到Mod部署目录。
|
||||
|
||||
打开Demo的目录,找到`SpigotDemo\CustomHumanModelDemo\DemoClientMod\resource_packs\resource_pack_geyser_demo_mod`,为Demo中的资源包文件夹,将其中的`models`和`textures`复制到`testModel`的资源包文件夹中。
|
||||
|
||||

|
||||
|
||||
通过IDE打开这个目录,可以看到目录结构中,主要是复制了2个`.geo.json`后缀的模型文件和1个贴图。
|
||||
|
||||
接下来我们尝试,将玩家的模型替换为`player.geo.json`所存储的模型,贴图替换为`player.png`的贴图。
|
||||
|
||||

|
||||
|
||||
首先要替换模型,我们要知道模型的identifier,打开`player.geo.json`,可以看到identifier字段的值为`geometry.player`,这个值就是模型的识别符,需要保证它在所有资源包中是唯一的。
|
||||
|
||||

|
||||
|
||||
接下来我们还需要知道模型所对应的贴图的路径。在资源包中对应路径`textures/entity/player`
|
||||
|
||||

|
||||
|
||||
接下来我们就可以调用在[OnLocalPlayerStopLoading](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/%E4%BA%8B%E4%BB%B6/%E4%B8%96%E7%95%8C.html?key=OnLocalPlayerStopLoading&docindex=3&type=0)事件触发时,为本地玩家[重建数据渲染器](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/%E6%8E%A5%E5%8F%A3/%E7%8E%A9%E5%AE%B6/%E6%B8%B2%E6%9F%93.html?key=AddPlayerGeometry&docindex=1&type=0#rebuildplayerrender),修改其参数。
|
||||
|
||||
```python
|
||||
def __init__(self, namespace, systemName):
|
||||
ClientSystem.__init__(self, namespace, systemName)
|
||||
self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "OnLocalPlayerStopLoading", self, self.OnStopLoading)
|
||||
|
||||
def OnStopLoading(self, args):
|
||||
playerId = args.get("playerId")
|
||||
# 更换模型贴图
|
||||
actorRenderComp = clientApi.GetEngineCompFactory().CreateActorRender(playerId)
|
||||
actorRenderComp.AddPlayerGeometry('default', "geometry.player")
|
||||
actorRenderComp.AddPlayerTexture('default', "textures/entity/player")
|
||||
actorRenderComp.RebuildPlayerRender()
|
||||
|
||||
def Destroy(self):
|
||||
self.UnListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "OnLocalPlayerStopLoading", self, self.OnStopLoading)
|
||||
```
|
||||
|
||||
> 在这里所调用的接口,实际上是为单独的实体修改了它的客户端实体json,并重建。自定义模型以及json详细参数详见: [自定义生物](https://mc.163.com/dev/mcmanual/mc-dev/mcguide/20-玩法开发/15-自定义游戏内容/3-自定义生物/01-自定义基础生物.html)
|
||||
>
|
||||
> 因此只能客户端本地看到这个修改,如果需要让**所有玩家都看到**新模型,那么需要借助服务器**广播给所有客户端**,让其他客户端也为这个实体修改参数并重建数据渲染器。
|
||||
>
|
||||
> 同理,如果需要为不同玩家设置不同模型,也可以由服务端来控制,什么玩家显示什么模型。并在新玩家加入时给所有在线客户端广播,通知其他客户端修改新加入的玩家的模型。
|
||||
|
||||
进入游戏后,可以看到本地玩家的模型被修改。
|
||||
|
||||

|
||||
|
||||
## 本地实体模型的修改
|
||||
|
||||
仍继续使用官方Demo中的模型资源,复制下方资源文件到testModel插件的对应资源包目录:
|
||||
|
||||
- `SpigotDemo\CustomPigModelDemo\CustomPigModelClientMod\resource_packs\resource_pack_pig_model\textures\entity\pig` 贴图文件
|
||||
- `SpigotDemo\CustomPigModelDemo\CustomPigModelClientMod\resource_packs\resource_pack_pig_model\render_controllers` 渲染控制器
|
||||
- `SpigotDemo\CustomPigModelDemo\CustomPigModelClientMod\resource_packs\resource_pack_pig_model\entity` 客户端实体定义
|
||||
|
||||
修改的思路如下:
|
||||
|
||||
1. 修改客户端实体定义,添加贴图文件引用。修改渲染控制器
|
||||
|
||||
```json
|
||||
"textures": {
|
||||
"default": "textures/entity/pig/pig",
|
||||
"saddled": "textures/entity/pig/pig_saddle",
|
||||
// 黄猪贴图引用
|
||||
"default_yellow": "textures/entity/pig/yellow_pig",
|
||||
// 黄猪上鞍贴图引用
|
||||
"saddled_yellow": "textures/entity/pig/yellow_pig_saddle"
|
||||
},
|
||||
```
|
||||
|
||||
```json
|
||||
// 替换成自定义的猪渲染控制器,可变成黄猪
|
||||
"render_controllers": [ "controller.render.pig_custom" ],
|
||||
```
|
||||
|
||||
2. 修改渲染控制器,根据molang选择贴图的使用。
|
||||
|
||||
> molang的解释参考[Wiki](https://zh.minecraft.wiki/w/Molang)
|
||||
|
||||
```json
|
||||
// 自定义猪渲染器,增加黄猪皮肤
|
||||
"controller.render.pig_custom": {
|
||||
"arrays": {
|
||||
"textures": {
|
||||
"Array.skins": [ "Texture.default", "Texture.saddled" ],
|
||||
"Array.skins_custom": ["Texture.default_yellow", "Texture.saddled_yellow"]
|
||||
}
|
||||
},
|
||||
"geometry": "Geometry.default",
|
||||
"materials": [ { "*": "Material.default" } ],
|
||||
// 在Python脚本内注册query.mod.custom_pig节点,默认值为0.0。该处表达式意思为:当某只猪的实例的query自定义节点不为1时,则皮肤组切换至黄猪组。
|
||||
"textures": [ "query.mod.custom_pig == 0 ? Array.skins[query.is_saddled] : Array.skins_custom[query.is_saddled]" ]
|
||||
}
|
||||
```
|
||||
|
||||
3. Python脚本注册molang节点,通过脚本控制molang的值,来显示不同的模型或贴图。
|
||||
|
||||
|
||||
|
||||
在修改玩家模型的客户端的代码基础上做修改,框选部分为新增部分:
|
||||
|
||||

|
||||
|
||||
同样 如果需要指定某个实体ID为某个模型,则需要通过服务端存储实体ID和对应模型之间的映射关系,并广播给所有客户端对指定实体进行molang值的修改。
|
||||
|
||||
进入游戏生成猪,可以看到随机的猪的颜色。
|
||||
|
||||

|
||||
|
||||
201
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/2-自定义物品制作.md
Normal file
201
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/2-自定义物品制作.md
Normal file
@@ -0,0 +1,201 @@
|
||||
# 自定义物品制作
|
||||
|
||||
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=64818e58c31a9c0f360dc5f2" width="800" height="600" allow="fullscreen"/>
|
||||
|
||||
基于目前Spigot服相关接口、自定义物品流程,Spigot服的自定义物品实际上是原生Java物品的换皮物品,客户端Mod利用字段**java_identifier**来标识
|
||||
|
||||
在玩家通过Geyser转发之后,利用**java_identifier**实现基岩版自定义物品和Java版物品的映射。
|
||||
|
||||
因此要实现自定义物品,我们不仅需要在服务端编写相关逻辑,还需要定义客户端行为包和资源包文件。
|
||||
|
||||
## 客户端定义物品
|
||||
|
||||
首先提前准备好一个服务端插件,这里命名为`testItem`。除此之外,为了更加方便地编辑客户端物品,我们可以另外再创建一个空白Addon,用来完成物品之后,复制到插件中。
|
||||
|
||||
编辑新创建的空白附加包,在编辑器中,首先在右上角作品菜单中,修改命名空间。教程中命名空间修改为`testitem`。
|
||||
|
||||

|
||||
|
||||
找到资源管理的新建按钮->配置->物品。
|
||||
|
||||

|
||||
|
||||
接下来填写文件命名,同时它也是物品名,例如这里填写`example`。模板选择自定义武器。
|
||||
|
||||
**那么这个物品的标识符就是`命名空间:物品名`,即`testitem:example`。**
|
||||
|
||||

|
||||
|
||||
接下来我们可以给这个物品设置贴图,贴图我们可以使用Spigot示例Demo中的武器贴图。
|
||||
|
||||
在资源管理中,点击导入,选择贴图,物品贴图。
|
||||
|
||||

|
||||
|
||||
找到目录`SpigotDemo\CustomItemDemo\CustomItemClientMod\resource_packs\CustomItemsMod_resource\textures\items`,导入`customitems_test_sword`,作为自定义武器的贴图。
|
||||
|
||||
如果你足够熟悉附加包的目录结构,也可以直接打开作品文件夹,将贴图复制到`资源包/textures/items`目录中,也可以不使用编辑器的贴图导入功能。
|
||||
|
||||
接下来在右侧属性窗口中,选择刚刚导入的贴图,也可以根据自己的需要,修改`游戏内名字`,它将会作为物品的默认物品名。
|
||||
|
||||

|
||||
|
||||
编辑完成后,点击`配套文件`中的`物品行为文件`后面的`打开文件`按钮。
|
||||
|
||||

|
||||
|
||||
在文件中添加`java_identifier`字段。这个字段用来表示在Java服中,它所对应的实际的物品的标识符。
|
||||
|
||||
```json
|
||||
{
|
||||
"format_version": "1.10",
|
||||
"minecraft:item": {
|
||||
"components": {
|
||||
"minecraft:max_damage": 10,
|
||||
"netease:weapon": {
|
||||
"attack_damage": 12,
|
||||
"enchantment": 10,
|
||||
"level": 3,
|
||||
"speed": 5,
|
||||
"type": "sword"
|
||||
}
|
||||
},
|
||||
"description": {
|
||||
"category": "Equipment",
|
||||
"identifier": "testitem:example"
|
||||
},
|
||||
"java_identifier": "wooden_sword"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
例如这里填写`wooden_sword`,那么在Java服中,木剑将尝试换皮为我们创建的自定义物品。
|
||||
|
||||
|
||||
|
||||
在编辑器的属性窗口中,还包含了一些行为包组件。需要注意的是,因为自定义物品本质上是Java版物品换皮,这里的大多数属性都只是用来给客户端设置物品的表现的,很多属性都无法生效。
|
||||
|
||||
### **需要注意的点**
|
||||
|
||||
- 字段工具挖掘速度、挖掘等级需要和Java物品对应,不然会出现方块破坏速率不一致导致的卡方块现象。对应物品json中: `"netease:weapon":{ "type":"shovel", "level":0, "speed":2 }`
|
||||
|
||||
具体对应关系如下:
|
||||
|
||||
| 键 | 类型 | 默认值 | 解释 |
|
||||
| ----- | ---- | ------ | ------------------------------------------------------------ |
|
||||
| type | str | | 武器/工具的类型,目前支持类型有: sword:剑 shovel:铲 pickaxe:镐 hatchet:斧 hoe:锄头 |
|
||||
| level | int | | level为0:当速度为2对应木板,否则对应金锭 level为1:对应石头 level为2:对应铁锭 level为3:对应钻石 level大于3:无法使用铁砧修复 |
|
||||
| speed | int | 0 | 对采集工具生效,表示挖掘方块时的基础速度 木头:2 石头:4 铁:6 钻石:8 金:12 |
|
||||
|
||||
使用编辑器,可以直接在`行为包组件中`进行修改,在`武器属性`中,选择对应的`类型`,`工具等级`,`挖掘基础速度`。
|
||||
|
||||
- 同理,盔甲字段,json中,需要和Java物品对应 `"netease:armor":{ "armor_slot":2 }` 盔甲槽位,详见[ ArmorSlotType](https://mc.163.com/dev/mcmanual/mc-dev/mcdocs/1-ModAPI/枚举值/ArmorSlotType.html)。使用编辑器,可以直接在`盔甲穿戴属性`类别中就可以选择槽位。
|
||||
|
||||
也有部分行为包组件不会生效,目前已知的有
|
||||
|
||||
````
|
||||
- 基岩版自定义物品中用于物品防火的组件
|
||||
```
|
||||
设置物品是否防火
|
||||
"netease:fire_resistant"{ "value" : true}
|
||||
```
|
||||
|
||||
- 基岩版自定义物品中用于物品是否可做燃料的组件
|
||||
```
|
||||
设置物品是否可作为燃料
|
||||
"netease:fuel" { "value" : true}
|
||||
```
|
||||
|
||||
- 基岩版自定义物品中用于物品的使用间隔
|
||||
```
|
||||
设置物品使用间隔
|
||||
"netease:cooldown" : { "duration" : 5}
|
||||
```
|
||||
|
||||
````
|
||||
|
||||
|
||||
|
||||
完成了客户端物品的配置,我们就可以关闭编辑器。
|
||||
|
||||
打开附加包文件夹,将资源包和行为包目录中的部分涉及到自定义物品的内容,复制到`testItem`插件中的对应位置。
|
||||
|
||||
### 行为包
|
||||
|
||||
- netease_items_beh
|
||||
|
||||

|
||||
|
||||
### 资源包
|
||||
|
||||
- netease_items_res
|
||||
- texts
|
||||
- textures
|
||||
|
||||

|
||||
|
||||
至此,我们就完成了客户端物品的定义。
|
||||
|
||||
## 服务端逻辑
|
||||
|
||||
首先新建一个项目,依赖SpigotMaster。
|
||||
|
||||
### 创建物品
|
||||
|
||||
```java
|
||||
ItemStack itemStack = new ItemStack(Material.WOOD_SWORD);
|
||||
itemStack = spigotMaster.setCustomItemIdentifier(itemStack, "testitem:example");
|
||||
```
|
||||
|
||||
像正常Spigot插件一样,直接实例化ItemStack来新建一个物品,物品的Material为`java_identifier`字段中的值,即木剑。
|
||||
|
||||
然后调用spigotMaster的`setCustomItemIdentifier`方法,为这个物品设置自定义物品标识符,即`testitem:example`。
|
||||
|
||||
### 获取物品
|
||||
|
||||
```java
|
||||
String customIdentifier = spigotMaster.getCustomItemIdentifier(itemStack);
|
||||
```
|
||||
|
||||
调用spigotMaster的`getCustomItemIdentifier`方法来获取自定义物品标识符。如果是自定义物品,返回标识符,否则返回null。
|
||||
|
||||
我们可以编写测试一些测试用监听器,查看自定义物品如何生效。
|
||||
|
||||
```java
|
||||
public class Listeners implements Listener {
|
||||
private final SpigotMaster spigotMaster = TutorialItem.getInstance().getSpigotMaster();
|
||||
|
||||
@EventHandler
|
||||
public void onJoin(PlayerJoinEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
ItemStack itemStack = new ItemStack(Material.WOOD_SWORD);
|
||||
itemStack = spigotMaster.setCustomItemIdentifier(itemStack, "testitem:example");
|
||||
player.getInventory().addItem(itemStack);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent e) {
|
||||
Player player = e.getPlayer();
|
||||
ItemStack itemStack = player.getInventory().getItemInMainHand();
|
||||
if (itemStack == null) {
|
||||
return;
|
||||
}
|
||||
String customIdentifier = spigotMaster.getCustomItemIdentifier(itemStack);
|
||||
if (customIdentifier == null) {
|
||||
player.sendMessage("你手持的物品不是自定义物品");
|
||||
return;
|
||||
}
|
||||
player.sendMessage("你手持的物品的自定义ID为: " + customIdentifier);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
安装插件到服务器,然后勾选`testItem`,重新部署。
|
||||
|
||||
进入游戏后,可以看到背包发送了一个我们的自定义物品。
|
||||
|
||||

|
||||
|
||||
对物品交互,可以看到正常输出,成功获取到了自定义物品的identifier。
|
||||
|
||||

|
||||
161
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/3-作业.md
Normal file
161
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/3-作业.md
Normal file
@@ -0,0 +1,161 @@
|
||||
# 作业
|
||||
|
||||
<iframe src="https://cc.163.com/act/m/daily/iframeplayer/?id=64818ea7c31a9c0f360dc5f4" width="800" height="600" allow="fullscreen"/>
|
||||
|
||||
制作2个自定义物品,可以长按空白处使用,有不同的效果
|
||||
|
||||
- 物品1:播放一个中国版特效
|
||||
- 物品2:修改玩家模型
|
||||
|
||||
## 客户端实现
|
||||
|
||||
客户端的部分将基于之前所制作的`testEffect`、`testModel`、`testItem`客户端模组来实现。制作过程见[中国版特效的配置](./0-中国版特效的配置.md)、[BlockBench模型的使用](./1-BlockBench模型的使用.md)、[自定义物品的制作](./2-自定义物品制作.md)。
|
||||
|
||||
其中`testEffect`模组已经实现了监听服务端的事件来播放特效的功能。
|
||||
|
||||
### testModel
|
||||
|
||||
`testModel`模组 需要让其监听服务端事件再做出修改即可。
|
||||
|
||||
修改的部分:
|
||||
|
||||
- OnLocalPlayerStopLoading 后通知服务端
|
||||
- 监听服务端事件OnChangeLocalModelEvent,事件触发后再更改模型
|
||||
|
||||
修改后的代码:
|
||||
|
||||
```python
|
||||
class ModelClientSystem(ClientSystem):
|
||||
"""
|
||||
该mod的客户端类
|
||||
根据服务端推送下来的数据显示通用显示界面
|
||||
"""
|
||||
|
||||
def __init__(self, namespace, systemName):
|
||||
ClientSystem.__init__(self, namespace, systemName)
|
||||
self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "OnLocalPlayerStopLoading", self, self.OnStopLoading)
|
||||
self.ListenForEvent(ModelConst.ModName, ModelConst.ServerSystemName, "OnChangeLocalModelEvent", self, self.OnChangeLocalModel)
|
||||
self.ListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "AddEntityClientEvent", self, self.OnAddEntity)
|
||||
|
||||
def OnChangeLocalModel(self, args):
|
||||
playerId = clientApi.GetLocalPlayerId()
|
||||
# 更换模型贴图
|
||||
actorRenderComp = clientApi.GetEngineCompFactory().CreateActorRender(playerId)
|
||||
actorRenderComp.AddPlayerGeometry('default', "geometry.player")
|
||||
actorRenderComp.AddPlayerTexture('default', "textures/entity/player")
|
||||
actorRenderComp.RebuildPlayerRender()
|
||||
|
||||
def OnStopLoading(self, args):
|
||||
# query节点注册时,为全局属性,创建的QueryComp应传入世界参数
|
||||
query_comp = clientApi.GetEngineCompFactory().CreateQueryVariable(clientApi.GetLevelId())
|
||||
query_comp.Register('query.mod.custom_pig', 0.0)
|
||||
self.NotifyToServer("ClientStopLoadingEvent", {})
|
||||
|
||||
def OnAddEntity(self, args):
|
||||
entity_id = args['id']
|
||||
identifier = args['engineTypeStr']
|
||||
if identifier != 'minecraft:pig':
|
||||
return
|
||||
# query节点在某个实体实例被设置是,创建的QueryComp应传入实体ID参数
|
||||
query_comp = clientApi.GetEngineCompFactory().CreateQueryVariable(entity_id)
|
||||
# 50%概率创建一个黄猪。若需要全部玩家看到该实体都为黄猪,需在服务端做好同步处理,并广播至每个客户端。
|
||||
if random.randint(0, 100) < 50:
|
||||
query_comp.Set('query.mod.custom_pig', 1.0)
|
||||
|
||||
def Destroy(self):
|
||||
self.UnListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "OnLocalPlayerStopLoading", self, self.OnStopLoading)
|
||||
self.UnListenForEvent(clientApi.GetEngineNamespace(), clientApi.GetEngineSystemName(), "AddEntityClientEvent", self, self.OnAddEntity)
|
||||
self.UnListenForEvent(ModelConst.ModName, ModelConst.ServerSystemName, "OnChangeLocalModelEvent", self, self.OnChangeLocalModel)
|
||||
```
|
||||
|
||||
### testItem
|
||||
|
||||
使用编辑器打开之前所编辑的附加包,继续添加新物品。方便起见,直接使用自定义剑的配置,进行复制。
|
||||
|
||||

|
||||
|
||||
复制两个新物品,识别符分别为`item1`、`item2`,物品名分别为`物品1`、`物品2`。
|
||||
|
||||

|
||||
|
||||
因为编辑器可能会覆盖字段,对**所有**的物品,打开`物品行为文件`,添加`java_identifier`,都为`wooden_sword`。
|
||||
|
||||
> 需要注意的是:
|
||||
>
|
||||
> 添加完`java_identifier`后,再次使用编辑器打开,可能会将字段覆盖。
|
||||
>
|
||||
> 建议编辑完成后将文件进行备份,防止字段丢失。
|
||||
|
||||
完成后打开文件夹,将行为包和资源包对应内容复制到testItem插件中。
|
||||
|
||||
## 服务端实现
|
||||
|
||||
新建一个项目,命名为`TutorialItemDemo`,并导入SpigotMaster作为依赖。
|
||||
|
||||
- 创建监听器,监听玩家长按空白处(鼠标右键点击)
|
||||
- 获取物品基岩版标识符,根据不同的标识符执行不同的逻辑
|
||||
|
||||
```java
|
||||
@EventHandler
|
||||
public void onInteract(PlayerInteractEvent e) {
|
||||
|
||||
Action action = e.getAction();
|
||||
if (action != Action.RIGHT_CLICK_BLOCK && action != Action.RIGHT_CLICK_AIR) {
|
||||
return;
|
||||
}
|
||||
ItemStack itemStack = e.getItem();
|
||||
String identifier = spigotMaster.getCustomItemIdentifier(itemStack);
|
||||
Player player = e.getPlayer();
|
||||
if (identifier.equalsIgnoreCase("testitem:item1")) {
|
||||
sendEffect(player);
|
||||
} else if (identifier.equalsIgnoreCase("testitem:item2")) {
|
||||
changeModel(player);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 特效播放
|
||||
|
||||
实现特效播放的事件信息发送。
|
||||
|
||||
需要注意的是,根据之前所编写的客户端模组,命名空间为`testEffects`,系统名为`testEffectsDev`,事件为`PlayEffectEvent`。
|
||||
|
||||
```java
|
||||
private void sendEffect(Player player) {
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("name", "effects/Attack_2.json");
|
||||
Location location = player.getLocation();
|
||||
data.put("pos", Arrays.asList(location.getX(), location.getY(), location.getZ()));
|
||||
spigotMaster.notifyToClient(player, "testEffects", "testEffectsDev", "PlayEffectEvent", data);
|
||||
}
|
||||
```
|
||||
|
||||
### 模型更改
|
||||
|
||||
发送`OnChangeLocalModelEvent`事件给客户端,命名空间为`testModel`,系统名为`testModelDev`。
|
||||
|
||||
```java
|
||||
private void changeModel(Player player) {
|
||||
spigotMaster.notifyToClient(player, "testModel", "testModelDev", "OnChangeLocalModelEvent", new HashMap<>());
|
||||
}
|
||||
```
|
||||
|
||||
## 效果测试
|
||||
|
||||
进入游戏后,打开创造物品栏,拿出物品1、物品2。分别手持物品右键。
|
||||
|
||||
- 物品1:播放特效
|
||||
|
||||

|
||||
|
||||
- 物品2:切换模型
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 参考插件下载
|
||||
|
||||
Java插件下载 [点我](https://g79.gdl.netease.com/TutorialItemDemo.zip)
|
||||
|
||||
Python模组下载 [点我](https://g79.gdl.netease.com/TutorialItemDemo-Python.zip)
|
||||
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/01.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/01.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/02.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/02.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/03.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/03.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/04.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/04.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/05.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/05.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/06.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/06.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/07.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/07.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/08.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/08.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/09.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/09.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/10.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/10.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/11.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/11.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/12.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/12.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/13.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/13.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/14.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/14.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/15.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/15.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/16.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/16.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/17.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/17.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/18.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/18.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/19.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/19.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/20.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/20.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/21.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/21.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/22.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/22.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/23.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/23.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/24.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/24.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/25.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/25.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/26.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/26.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/27.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/27.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/28.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/28.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/29.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/29.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/30.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/30.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/31.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/31.png
LFS
Normal file
Binary file not shown.
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/32.png
LFS
Normal file
BIN
docs/mconline/60-我的世界创造营教程/网络游戏开服教程/3-客户端效果的制作/images/32.png
LFS
Normal file
Binary file not shown.
Reference in New Issue
Block a user