我要加入

Minecraft程式開發討論會

會長:yukkcake / 晨開設日:2013-08-11 00:32:49

  • EXP

  • 資金8072  
  • 關連作品我的世界、我的世界 Classic、我的世界... 看更多
  • 招募制度:邀請制
  • 成員:40 人
  • 昨日人氣:0

網路封包(Packet)

推上精選編輯

近期編輯:yukkcake ...看更多

Packet Handling 基本的Packet操作


實體的資料大家常常使用NBTTagCompound來存讀資料,但是NBT並不是隨時都在同步
這時有兩種方法,其中一種是DataWatcher:會盡可能的讓伺服器和客戶端間同步資料。
另一種則是利用這裡要介紹的方式:利用封包(Packet)

使用封包的條件

  • 模組主類別加上Annotation,使Forge在接收特定頻道的封包時知道該交由哪個類別來處理。
  • Packet的發送源,發送後會由另一端的PacketHandler做處理。
  • 一個實作IPacketHandler的class (控制接收封包後的動作)

主類別Annotation

@Mod(modid = "xxx" , name = "x", version = "xxx")
@NetworkMod(clientSideRequired=true, serverSideRequired=false//模組是否一定得被安裝
, channels={"頻道名稱" , "頻道名稱2", etc.}//假如有需求,接收多個頻道
, packetHandler=【PacketHandler的名稱】.class)//處理封包的class
public class MainClass{
//你的主類內容
}

Packet發送源

Packet發送前要先新建一個Packet250CustomPayload物件。
Packet的資料是以ByteArray格式儲存。

在net.minecraft.network.packet中有許多繼承Packet的類別,
而模組作者最常使用(也是Forge有支援的)就是Packet250。
Packet250提供了channel欄位可以讓我們確保我們接收到的Packet是我們所發送的,
而非其他模組發送的(當然你只要知道其他模組的channel,你也可以使用他們的封包資訊)
  
通常發送Packet的時機是有純伺服端執行的程式要發送給客戶端,
或是客戶端進行的動作發送給伺服端。
因此通常是訂閱一個事件、或是註冊一個Handler,在其中發送。

舉個例子:我想在onPlayerRespawn(玩家復活)時發送給玩家端兩個隨機整數,再由玩家端處理。
(臨時想不到實際的例子囧)

首先我先建立一個Class(這裡取名為PlayerHandler) 並實作 IPlayerTracker 介面
<<interface>>
IPlayerTracker

onPlayerLogin(player : EntityPlayer) : void
onPlayerLogout(player : EntityPlayer) : void
onPlayerChangedDimension(player : EntityPlayer) : void
onPlaterRespawn(player : EntityPlayer) : void

//package , import省略

public class PlayerHandler implements IPlayerTracker{
public void onPlayerLogin(Entity Player){}
public void onPlayerLogout(Entity Player){}
public void onPlayerChangedDimension(Entity Player){}
public void onPlayerRespawn(Entity Player){

//生成要傳送的整數
Random random = new Random();
int dataToSend = random.nextInt();
int dataToSend2 = random.nextInt();

ByteArrayOutputStream bos = new ByteArrayOutputStream(4);
DataOutputStream outputStream = new DataOutputStream(bos);

try {
//將資料寫入bos,這裡使用的做法請自行參閱java文件,與Minecraft無關
outputStream.writeInt(dataToSend);//寫入第一個資料
outputStream.writeInt(dataToSend2);//寫入第一個資料
}catch (Exception e){
e.printStackTrace();//例外處理
}

//建立新的Packet
Packet250CustomPayload packet = new Packet250CustomPayload();
packet.channel = "mychannel";  //發送Packet的頻道名稱
packet.data = bos.toByteArray();//要傳送的資料
packet.length = bos.size();//資料長度

//傳送packet給該Player
PacketDispatcher.sendPacketToPlayer(packet, (Player)player);
}

}

接收Packet,並進行處理

首先你要有一個class實作IPacketHandler,(並且在主類中的Annotation中宣告)
假如你在eclipse上操作,他會自動生成以下程式碼
//package , import省略

public class PacketHandler implements IPacketHandler {

//constructor通常沒用到
public PacketHandler() {
// TODO Auto-generated constructor stub
}

//重點,接收到Packet250時此method會被呼叫
@Override
public void onPacketData(INetworkManager manager,
Packet250CustomPayload packet, Player player) {
// TODO Auto-generated method stub

}
}

然後在onPacketData中判斷頻道(假如你有多個),並且利用接收到的資料來進行你的程式


public void onPacketData(INetworkManager manager,
Packet250CustomPayload packet, Player player) {

DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(packet.data));
int dataToGet;

try {
dataToGet = inputStream.readInt();//讀取第一個資料
dataToGet2 = inputStream.readInt(); //讀取第二個資料
}
catch (IOException e) {
e.printStackTrace();
return;
}

//自由發揮,看你當時發送數據的目的為何
doSomethingWithDataYouGet(dataToGet,dataToGet2);
}


相關文章

  • ForgeWiki:Packet Handling、Advanced Packet Handling(還有自訂封包~)
    • http://goo.gl/trG065 、 http://goo.gl/Q1de6m
  • Protocol:

[color=#EEE !important]
[div bgcolor=rgba(17,17,17,0.9) !important align=left][color=#EEE !important]
en → zh-TW
trG065

公會首頁

主選單
Wiki編輯
  規則
模組開發
  MCP
  Forge API
模組討論
  Custom Stuff 2
  自製分享
插件開發
  Craftbukkit
插件討論
  自製分享
輔助程式
公會相關
關聯資料

目前沒有資料連到「網路封包(Packet)」。


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】