提供: Minecraft Modding Wiki
移動先: 案内検索
(解説の追加)
12行目: 12行目:
 
<source lang = "java">
 
<source lang = "java">
 
package yourpackage;
 
package yourpackage;
 +
//ClientProxyのみ必要だが、拡張性も考えCommonProxyも用意。GUI等追加するなら、IGuiHandlerを実装のこと。
 
public class CommonProxy {
 
public class CommonProxy {
  
26行目: 27行目:
 
public class ClientProxy extends CommonProxy {
 
public class ClientProxy extends CommonProxy {
 
     //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名
 
     //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名
     public static KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName");
+
     public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName");
 
     @Override
 
     @Override
 
     public void registerClientInfo() {
 
     public void registerClientInfo() {
57行目: 58行目:
 
     //キーが押されたかどうかを保存する変数
 
     //キーが押されたかどうかを保存する変数
 
     public static boolean pressSampleKey = false;
 
     public static boolean pressSampleKey = false;
 +
    //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。
 
     @SubscribeEvent
 
     @SubscribeEvent
 
     public void KeyHandlingEvent(KeyInputEvent event) {
 
     public void KeyHandlingEvent(KeyInputEvent event) {
71行目: 73行目:
 
             }
 
             }
 
             if (pressSampleKey) {
 
             if (pressSampleKey) {
                 //クライアントとサーバーの両方で呼ばれる。
+
                 //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述
                 pressSampleKey = false;
+
                 pressSampleKey = false;//呼ばれ続けるため、ここでクリア
 
             }
 
             }
 
         }
 
         }
125行目: 127行目:
 
</source>
 
</source>
 
==解説==
 
==解説==
後日掲載。
+
===ClientProxy===
 +
<source lang = "java">
 +
package yourpackage.client;
 +
import yourpackage.CommonProxy;
 +
import net.minecraft.client.settings.KeyBinding;
 +
import cpw.mods.fml.client.registry.ClientRegistry;
 +
public class ClientProxy extends CommonProxy {
 +
    //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名
 +
    public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName");
 +
    @Override
 +
    public void registerClientInfo() {
 +
        ClientRegistry.registerKeyBinding(sampleKey);
 +
    }
 +
}
 +
</source>
 +
KeyBindingは1.6からインスタンス生成時の引数に“カテゴリー名”が追加されている。<br>
 +
キーのローカライズはlangファイル利用。<br>
 +
KeyBindingクラスとClientRegistryクラスはクライアント側のみなので、Proxyで分ける必要がある。
 +
===KeyInputEvent===
 +
<source lang = "java">
 +
//キーが押されたかどうかを保存する変数
 +
public static boolean pressSampleKey = false;
 +
//キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。
 +
@SubscribeEvent
 +
public void KeyHandlingEvent(KeyInputEvent event) {
 +
    while (ClientProxy.sampleKey.isPressed()) {
 +
        pressSampleKey = true;//クライアント側のみの変更。
 +
    }
 +
}
 +
</source>
 +
1.7より追加されたイベント。いづれかのキーが押された時に、呼ばれる。<br>
 +
どのキーが押されたかはeventに保存されていないので、用意しているKeyBinding変数のメソッドを利用する必要が有る。<br>
 +
isPressedメソッドはキーが“押された回数”が0以上の時にtrueになるが、呼ばれた際に、押された回数を1減らす。
 +
チャタリング等の防止のため、while文で押された回数が0になるまで呼んでいる。
 +
このため、同じキーの登録被りが起こった場合確実にどちらかは動作しなくなる。
 +
中途半端に動作するよりは良いので、この方法をとっている。<br>
 +
このイベントはクライアント側のみであるので、サーバーにキー判定を伝えるにはパケットを送る必要が有る。
 +
===KeyHandlingPacket===
 +
<source lang = "java">
 +
package yourpackage;
 +
 
 +
import io.netty.buffer.ByteBuf;
 +
import io.netty.channel.ChannelHandlerContext;
 +
import net.minecraft.entity.player.EntityPlayer;
 +
 
 +
//クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承
 +
public class KeyHandlingPacket extends AbstractPacket
 +
{
 +
//保持しておくboolean型変数
 +
boolean pressSampleKey;
 +
 
 +
//引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。
 +
public KeyHandlingPacket() {
 +
}
 +
 
 +
//パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。
 +
public KeyHandlingPacket(boolean ver1) {
 +
pressSampleKey = ver1;
 +
}
 +
 
 +
@Override
 +
public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
 +
//ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。
 +
buffer.writeBoolean(pressSampleKey);
 +
}
 +
 
 +
@Override
 +
public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
 +
//ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。
 +
pressSampleKey = buffer.readBoolean();
 +
}
 +
 
 +
@Override
 +
public void handleClientSide(EntityPlayer player) {
 +
//今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。
 +
}
 +
 
 +
@Override
 +
public void handleServerSide(EntityPlayer player) {
 +
SampleKeyCore.pressSampleKey = pressSampleKey;
 +
}
 +
}
 +
</source>
 +
キー判定を送るパケットクラス。
 +
1つのクラスで両方向のパケットの記述が可能なため、慣れると重宝する。
 +
ここでは、pressSampleKeyの内容をサーバーに送っている。
 +
===キー判定後の処理部分===
 +
<source lang = "java">
 +
@SubscribeEvent
 +
public void LivingUpdate(LivingUpdateEvent event) {
 +
    if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) {
 +
        if (event.entityLiving.worldObj.isRemote) {
 +
            //ここで、クライアントでの変数の変更をサーバーに伝える。
 +
            packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey ));
 +
        }
 +
        if (pressSampleKey) {
 +
            //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述
 +
            pressSampleKey = false;//呼ばれ続けるため、ここでクリア
 +
        }
 +
    }
 +
}
 +
</source>
 +
キー判定で処理を行う方法はいくつかあるが、今回はLivingUpdateEventを利用する。<br>
 +
まず、EntityPlayerから呼ばれているかを判定している。
 +
次にisRemote変数がtrue、つまりクライアント側でパケットをサーバーに送信。
 +
同期されるので、pressSampleKey判定はクライアントとサーバー両方で、同じ結果を得る。<br>
 +
このif文内でpressSampleKeyをfalseに戻さないと、一度キーを押したら実行されっぱなしになる。<br>
 +
押しっぱなしかどうかを見たいのであれば、tick処理ループ内で、KeyBinding変数のgetIsKeyPressed()メソッドを監視し続ければよい。

2014年5月15日 (木) 22:05時点における版

この記事は"Minecraft Forge Universal 10.12.0.xxx~"を前提MODとしています。

1.6におけるキーの処理

1.6までは、KeyHandlerクラスを継承して、KeyUpとKeyDownをtick単位で見ることが出来ました。 1.7では、tick処理自体がイベントになったので、キーの処理もイベントになりました。

1.7でのキーイベント追加

キーイベントの追加方法 (前提記事:1.7のパケットについて

ソースコード

CommonProxy.java

package yourpackage;
//ClientProxyのみ必要だが、拡張性も考えCommonProxyも用意。GUI等追加するなら、IGuiHandlerを実装のこと。
public class CommonProxy {

    public void registerClientInfo(){}

}

ClientProxy.java

package yourpackage.client;
import yourpackage.CommonProxy;
import net.minecraft.client.settings.KeyBinding;
import cpw.mods.fml.client.registry.ClientRegistry;
public class ClientProxy extends CommonProxy {
    //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名
    public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName");
    @Override
    public void registerClientInfo() {
        ClientRegistry.registerKeyBinding(sampleKey);
    }

}

SampleKeyCore.java(importは省略)

package yourpackage;
@Mod(modid="KeySampleMod", name="KeySampleMod", version="1.0")
public class SampleKeyCore
{
    @SidedProxy(clientSide = "yourpackage.Client.ClientProxy", serverSide = "yourpackage.CommonProxy")
    public static CommonProxy proxy;
    //パケットハンドラー。解説は前提記事を参照のこと。
    public static final PacketPipeline packetPipeline = new PacketPipeline();
    @EventHandler
    public void load(FMLInitializationEvent event) {
        packetPipeline.initialise();
        packetPipeline.registerPacket(KeyHandlingPacket.class);//パケットの登録
        FMLCommonHandler.instance().bus().register(this);//KeyHandlingEvent用
        MinecraftForge.EVENT_BUS.register(this);//LivingUpdate用
    }
    @EventHandler
    public void postInit(FMLPostInitializationEvent event) {
        packetPipeline.postInitialise();
    }
    //キーが押されたかどうかを保存する変数
    public static boolean pressSampleKey = false;
    //キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。
    @SubscribeEvent
    public void KeyHandlingEvent(KeyInputEvent event) {
        while (ClientProxy.sampleKey.isPressed()) {
            pressSampleKey = true;//クライアント側のみの変更。
        }
    }
    @SubscribeEvent
    public void LivingUpdate(LivingUpdateEvent event) {
        if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) {
            if (event.entityLiving.worldObj.isRemote) {
                //ここで、クライアントでの変数の変更をサーバーに伝える。
                packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey ));
            }
            if (pressSampleKey) {
                //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述
                pressSampleKey = false;//呼ばれ続けるため、ここでクリア
            }
        }
    }
}

KeyHandlingPacket.java

package yourpackage;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;

//クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承
public class KeyHandlingPacket extends AbstractPacket
{
	//保持しておくboolean型変数
	boolean pressSampleKey;

	//引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。
	public KeyHandlingPacket() {
	}

	//パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。
	public KeyHandlingPacket(boolean ver1) {
		pressSampleKey = ver1;
	}

	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
		//ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。
		buffer.writeBoolean(pressSampleKey);
	}

	@Override
	public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
		//ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。
		pressSampleKey = buffer.readBoolean();
	}

	@Override
	public void handleClientSide(EntityPlayer player) {
		//今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。
	}

	@Override
	public void handleServerSide(EntityPlayer player) {
		SampleKeyCore.pressSampleKey = pressSampleKey;
	}
}

解説

ClientProxy

package yourpackage.client;
import yourpackage.CommonProxy;
import net.minecraft.client.settings.KeyBinding;
import cpw.mods.fml.client.registry.ClientRegistry;
public class ClientProxy extends CommonProxy {
    //キーのUnlocalizedName、バインドするキーの対応整数値(Keyboardクラス参照のこと)、カテゴリー名
    public static final KeyBinding sampleKey = new KeyBinding("Key.sample", Keyboard.KEY_R, "CategoryName");
    @Override
    public void registerClientInfo() {
        ClientRegistry.registerKeyBinding(sampleKey);
    }
}

KeyBindingは1.6からインスタンス生成時の引数に“カテゴリー名”が追加されている。
キーのローカライズはlangファイル利用。
KeyBindingクラスとClientRegistryクラスはクライアント側のみなので、Proxyで分ける必要がある。

KeyInputEvent

//キーが押されたかどうかを保存する変数
public static boolean pressSampleKey = false;
//キーが“押された時”に呼ばれる。“押しっぱなし”の判定は別途用意する必要あり。
@SubscribeEvent
public void KeyHandlingEvent(KeyInputEvent event) {
    while (ClientProxy.sampleKey.isPressed()) {
        pressSampleKey = true;//クライアント側のみの変更。
    }
}

1.7より追加されたイベント。いづれかのキーが押された時に、呼ばれる。
どのキーが押されたかはeventに保存されていないので、用意しているKeyBinding変数のメソッドを利用する必要が有る。
isPressedメソッドはキーが“押された回数”が0以上の時にtrueになるが、呼ばれた際に、押された回数を1減らす。 チャタリング等の防止のため、while文で押された回数が0になるまで呼んでいる。 このため、同じキーの登録被りが起こった場合確実にどちらかは動作しなくなる。 中途半端に動作するよりは良いので、この方法をとっている。
このイベントはクライアント側のみであるので、サーバーにキー判定を伝えるにはパケットを送る必要が有る。

KeyHandlingPacket

package yourpackage;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import net.minecraft.entity.player.EntityPlayer;

//クライアント側でキー入力によって変化したboolean変数をサーバー側に伝達するパケット。AbstractPacketを継承
public class KeyHandlingPacket extends AbstractPacket
{
	//保持しておくboolean型変数
	boolean pressSampleKey;

	//引数を持つコンストラクタを追加する場合は、空のコンストラクタを用意してくれとのこと。
	public KeyHandlingPacket() {
	}

	//パケット生成を簡略化するために、boolean型変数を引数に取るコンストラクタを追加。
	public KeyHandlingPacket(boolean ver1) {
		pressSampleKey = ver1;
	}

	@Override
	public void encodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
		//ByteBufに変数を代入。基本的にsetメソッドではなく、writeメソッドを使う。
		buffer.writeBoolean(pressSampleKey);
	}

	@Override
	public void decodeInto(ChannelHandlerContext ctx, ByteBuf buffer) {
		//ByteBufから変数を取得。こちらもgetメソッドではなく、readメソッドを使う。
		pressSampleKey = buffer.readBoolean();
	}

	@Override
	public void handleClientSide(EntityPlayer player) {
		//今回はクライアントの情報をサーバーに送るので、こちらはなにもしない。
	}

	@Override
	public void handleServerSide(EntityPlayer player) {
		SampleKeyCore.pressSampleKey = pressSampleKey;
	}
}

キー判定を送るパケットクラス。 1つのクラスで両方向のパケットの記述が可能なため、慣れると重宝する。 ここでは、pressSampleKeyの内容をサーバーに送っている。

キー判定後の処理部分

@SubscribeEvent
public void LivingUpdate(LivingUpdateEvent event) {
    if (event.entityLiving != null && event.entityLiving instanceof EntityPlayer) {
        if (event.entityLiving.worldObj.isRemote) {
            //ここで、クライアントでの変数の変更をサーバーに伝える。
            packetPipeline.sendToServer(new KeyHandlingPacket(pressSampleKey ));
        }
        if (pressSampleKey) {
            //クライアントとサーバーの両方で呼ばれる。ここに必要な処理を記述
            pressSampleKey = false;//呼ばれ続けるため、ここでクリア
        }
    }
}

キー判定で処理を行う方法はいくつかあるが、今回はLivingUpdateEventを利用する。
まず、EntityPlayerから呼ばれているかを判定している。 次にisRemote変数がtrue、つまりクライアント側でパケットをサーバーに送信。 同期されるので、pressSampleKey判定はクライアントとサーバー両方で、同じ結果を得る。
このif文内でpressSampleKeyをfalseに戻さないと、一度キーを押したら実行されっぱなしになる。
押しっぱなしかどうかを見たいのであれば、tick処理ループ内で、KeyBinding変数のgetIsKeyPressed()メソッドを監視し続ければよい。