この記事では、サウンド再生をマルチプレイに対応させるよ!
Minecraft 1.7.10 の記事になります。

Minecraft の Modding の全体像については、こちらのページ をご覧ください。

ネットワークの通信を登録するクラス

ネットワークの通信に関する処理をまとめるパッケージを作る。

com.watermelonheadman.gopichandmod.network

先ほど作ったパッケージの中にクラスを作る。

package com.gopichandmod.network;

import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import cpw.mods.fml.relauncher.Side;

import com.gopichandmod.GopichandMod;

public class PacketHandler
{
	// ネットワークの通信に使うインスタンスを作成する。
	// 引数でユニークな文字列を渡す。(この場合は、MODID を渡している)
	public static final SimpleNetworkWrapper INSTANCE
		= NetworkRegistry.INSTANCE.newSimpleChannel( GopichandMod.MODID );

	// この関数は、クラス GopichandMod の関数 preInit から呼び出す。
	public static void init()
	{
		// 第1、第2引数で渡している MessageInstruments.class は
		// プレイヤーの楽器の演奏に関するメッセージを実装しているクラスです。
		INSTANCE.registerMessage(
			MessageInstruments.class,
			MessageInstruments.class,
			0,
			Side.CLIENT );
	}
}

プレイヤーの楽器の演奏に関するメッセージを実装するクラス

package comgopichandmod.network;

import io.netty.buffer.ByteBuf;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.network.simpleimpl.IMessage;
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
import cpw.mods.fml.common.network.simpleimpl.MessageContext;

import com.gopichandmod.audio.InstrumentManager;

public class MessageInstruments
	implements IMessage, IMessageHandler< MessageInstruments, IMessage >
{
	// 演奏者の X 座標
	private float x;
	// 演奏者の Y 座標
	private float y;
	// 演奏者の Z 座標
	private float z;
	// 演奏音の音量
	private float vol;
	// 演奏者の ID
	private int entityid;
	// 演奏音の ID
	private int soundid;

	public MessageInstruments() {}

	public MessageInstruments(
		float x,
		float y,
		float z,
		float vol,
		int entityid,
		int soundid )
	{
		this.x = x;
		this.y = y;
		this.z = z;
		this.vol = vol;
		this.entityid = entityid;
		this.soundid = soundid;
	}

	@Override
	public void fromBytes( ByteBuf buf )
	{
		this.x = buf.readFloat();
		this.y = buf.readFloat();
		this.z = buf.readFloat();
		this.vol = buf.readFloat();
		this.entityid = buf.readInt();
		this.soundid = buf.readInt();
	}

	@Override
	public void toBytes( ByteBuf buf )
	{
		buf.writeFloat( this.x );
		buf.writeFloat( this.y );
		buf.writeFloat( this.z );
		buf.writeFloat( this.vol );
		buf.writeInt( this.entityid );
		buf.writeInt( this.soundid );
	}

	// クライアントサイドのプログラムが通信を受けた時に情報に基づき、演奏音を鳴らす。
	@Override
	public IMessage onMessage( MessageInstruments message, MessageContext ctx )
	{
		switch ( FMLCommonHandler.instance().getEffectiveSide() ) {
		case CLIENT:
			InstrumentManager.play(
				message.soundid,
				message.entityid,
				message.x,
				message.y,
				message.z,
				message.vol,
				false );
		case SERVER:
			break;
		}

		return null;
	}
}

ソースコードの修正

package com.gopichandmod;

import net.minecraftforge.common.MinecraftForge;

import cpw.mods.fml.common.Mod;
import cpw.mods.fml.common.Mod.EventHandler;
import cpw.mods.fml.common.event.FMLInitializationEvent;
import cpw.mods.fml.common.event.FMLPreInitializationEvent;

import com.gopichandmod.audio.InstrumentManager;
import com.gopichandmod.events.EventPlayer;
import com.gopichandmod.items.GopichandItems;
import com.gopichandmod.network.PacketHandler;

@Mod( modid = GopichandMod.MODID, version = GopichandMod.VERSION )
public class GopichandMod
{
	@Mod.Instance( "GopichandMod" )
	public static final String MODID = "gopichandmod";
	public static final String VERSION = "1.0.0";

	@EventHandler
	public void preInit( FMLPreInitializationEvent e )
	{
		GopichandItems.registry( this );
		InstrumentManager.registry();
		PacketHandler.init();

		MinecraftForge.EVENT_BUS.register( new EventPlayer() );
	}

	@EventHandler
	public void Init( FMLInitializationEvent e )
	{
		Recipes.registry();
	}
}

package com.gopichandmod.items;

import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.entity.Entity;
import net.minecraft.entity.item.EntityItem;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.EnumAction;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

import cpw.mods.fml.common.network.NetworkRegistry;
import cpw.mods.fml.common.registry.GameRegistry;

import com.gopichandmod.audio.InstrumentManager;
import com.gopichandmod.network.MessageInstruments;
import com.gopichandmod.network.PacketHandler;

public class ItemGopichand extends Item
{
	public ItemGopichand()
	{
		String localname = "gopichand";

		this.setCreativeTab( CreativeTabs.tabMisc );
		this.setUnlocalizedName( localname );
		this.setTextureName( "gopichandmod:gopichand" );
		maxStackSize = 1;

		GameRegistry.registerItem( this, localname );

		return;
	}

	@Override
	public ItemStack onItemRightClick(
		ItemStack item,
		World world,
		EntityPlayer player )
	{
		player.setItemInUse( item, this.getMaxItemUseDuration( item ) );

		if ( !world.isRemote ) {
			if ( player.onGround == false ) {
/*
				// シングルプレイ対応
				InstrumentManager.play(
						InstrumentManager.GOPICHAND_TREMOLO,
						player.getEntityId(),
						(float)player.posX,
						(float)player.posY,
						(float)player.posZ,
						1.0f,
						false );
*/
				// シングルプレイ、マルチプレイ対応
				PacketHandler.INSTANCE.sendToAllAround(
					new MessageInstruments(
						(float)player.posX,
						(float)player.posY,
						(float)player.posZ,
						1.0f,
						player.getEntityId(),
						InstrumentManager.GOPICHAND_TREMOLO ),
					new NetworkRegistry.TargetPoint(
						player.dimension,
						player.posX,
						player.posY,
						player.posZ,
						64.0 ) );
			} else if ( player.isSneaking() ) {
/*
				// シングルプレイ対応
				InstrumentManager.play(
						InstrumentManager.GOPICHAND_UP,
						player.getEntityId(),
						(float)player.posX,
						(float)player.posY,
						(float)player.posZ,
						1.0f,
						false );
*/
				// シングルプレイ、マルチプレイ対応
				PacketHandler.INSTANCE.sendToAllAround(
						new MessageInstruments(
							(float)player.posX,
							(float)player.posY,
							(float)player.posZ,
							1.0f,
							player.getEntityId(),
							InstrumentManager.GOPICHAND_UP ),
						new NetworkRegistry.TargetPoint(
							player.dimension,
							player.posX,
							player.posY,
							player.posZ,
							64.0 ) );
			} else {
/*
				// シングルプレイ対応
				InstrumentManager.play(
						InstrumentManager.GOPICHAND_PICK,
						player.getEntityId(),
						(float)player.posX,
						(float)player.posY,
						(float)player.posZ,
						1.0f,
						false );
*/
				// シングルプレイ、マルチプレイ対応
				PacketHandler.INSTANCE.sendToAllAround(
						new MessageInstruments(
							(float)player.posX,
							(float)player.posY,
							(float)player.posZ,
							1.0f,
							player.getEntityId(),
							InstrumentManager.GOPICHAND_PICK ),
						new NetworkRegistry.TargetPoint(
							player.dimension,
							player.posX,
							player.posY,
							player.posZ,
							64.0 ) );
			}
		}

		return item;
	}

	public int getMaxItemUseDuration( ItemStack par1ItemStack )
	{
		return 72000;
	}

	public EnumAction getItemUseAction( ItemStack par1ItemStack )
	{
		return EnumAction.block;
	}
}

プロジェクトの構成は、下記のようになった。

src/main/java
	com.gopichandmod
		GopichandMod.java
		Recipes.java
	com.gopichandmod.audio
		InstrumentManager.java
		InstrumentSound.java
	com.gopichandmod.items
		GopichandItems.java
		ItemGopichand.java
		ItemGopichandBody.java
		ItemGopichandHead.java
		ItemIronString.java
	com.gopichandmod.network
		MessageInstruments.java
		PacketHandler.java
src/main/resources
	assets.gopichandmod
		sounds.json
	assets.gopichandmod.lang
		en_US.lang
		ja_JP.lang
	assets.gopichandmod.sounds.instruments
		gopichand_pick.ogg
		gopichand_up.ogg
		gopichand_tremolo.ogg
	assets.gopichandmod.textures.items
		gopichand.png
		gopichandbody.png
		gopichandhead.png
		ironstring.png

サーバーのプロジェクト

Eclipse から Minecraft のサーバーを起動できるようにプロジェクトを作成する。

基本的にクライアントのプロジェクトと同じなので相違点のみ載せる。

メインタブ

メイン・クラス → GradleStartServer

引数タブ

プログラムの引数 → (空)

テスト

サーバーを起動した後、クライアントを起動してゴピチャンドを演奏してみよう!
無事に音が鳴れば、成功だよ!

お疲れ様でした!