# 作业
制作2个自定义物品,可以长按空白处使用,有不同的效果
- 物品1:播放一个中国版特效
- 物品2:修改玩家模型
# 客户端实现
客户端的部分将基于之前所制作的testEffect
、testModel
、testItem
客户端模组来实现。制作过程见中国版特效的配置、BlockBench模型的使用、自定义物品的制作。
其中testEffect
模组已经实现了监听服务端的事件来播放特效的功能。
# testModel
testModel
模组 需要让其监听服务端事件再做出修改即可。
修改的部分:
- OnLocalPlayerStopLoading 后通知服务端
- 监听服务端事件OnChangeLocalModelEvent,事件触发后再更改模型
修改后的代码:
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作为依赖。
- 创建监听器,监听玩家长按空白处(鼠标右键点击)
- 获取物品基岩版标识符,根据不同的标识符执行不同的逻辑
@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
。
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
。
private void changeModel(Player player) {
spigotMaster.notifyToClient(player, "testModel", "testModelDev", "OnChangeLocalModelEvent", new HashMap<>());
}
# 效果测试
进入游戏后,打开创造物品栏,拿出物品1、物品2。分别手持物品右键。
- 物品1:播放特效
- 物品2:切换模型
# 参考插件下载
Java插件下载 点我 (opens new window)
Python模组下载 点我 (opens new window)