# 作业

制作2个自定义物品,可以长按空白处使用,有不同的效果

  • 物品1:播放一个中国版特效
  • 物品2:修改玩家模型

# 客户端实现

客户端的部分将基于之前所制作的testEffecttestModeltestItem客户端模组来实现。制作过程见中国版特效的配置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

使用编辑器打开之前所编辑的附加包,继续添加新物品。方便起见,直接使用自定义剑的配置,进行复制。

复制两个新物品,识别符分别为item1item2,物品名分别为物品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)

客户端实现

testModel

testItem

服务端实现

特效播放

模型更改

效果测试

参考插件下载