Java解析魔兽争霸3录像W3G文件(四):解析游戏进行时的信息(二)

2014-11-24 03:16:45 · 作者: · 浏览: 3
et += 2; int timeIncrement = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset); time += timeIncrement; offset += 2; offset += bytes - 2; } /** * 玩家离开游戏Block解析 */ private void analysisLeaveGame() { offset += 5; // 玩家离开游戏就不再计算游戏时间 byte playerId = uncompressedDataBytes[offset]; Player player = getPlayById(playerId); player.setPlayTime(time); offset += 9; } /** * 通过玩家ID获取Player对象 * @param playerId 玩家ID * @return 对应的Player对象 */ private Player getPlayById(byte playerId) { Player p = null; for(Player player : playerList) { if(playerId == player.getPlayerId()) { p = player; break; } } return p; } /** * 通过玩家SlotNumber获取Player对象 * @param slotNumber 玩家SlotNumber * @return 对应的Player对象 */ private Player getPlayBySlotNumber(int slotNumber) { Player p = null; for(Player player : playerList) { if(slotNumber == player.getSlotNumber()) { p = player; break; } } return p; } public List getChatList() { return chatList; } }
ChatMessage.java是玩家游戏过程中的聊天信息对应的Java对象,通过解析玩家聊天信息的数据块获取。

ChatMessage.java

package com.xxg.w3gparser;

public class ChatMessage {

	/**
	 * 发送者
	 */
	private Player from;
	
	/**
	 * 发送方式
	 * 0:发送给所有玩家
	 * 1:发送给队友
	 * 2:发送给裁判或观看者
	 * 3+N:发送给指定玩家
	 */
	private long mode;
	
	/**
	 * 接收者(mode为3+N时有效)
	 */
	private Player to;
	
	/**
	 * 消息发送时间
	 */
	private long time;
	
	/**
	 * 消息内容
	 */
	private String message;

	public Player getFrom() {
		return from;
	}

	public void setFrom(Player from) {
		this.from = from;
	}

	public long getMode() {
		return mode;
	}

	public void setMode(long mode) {
		this.mode = mode;
	}

	public Player getTo() {
		return to;
	}

	public void setTo(Player to) {
		this.to = to;
	}

	public long getTime() {
		return time;
	}

	public void setTime(long time) {
		this.time = time;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}
	
}

由于玩家可能在游戏过程中离开游戏,要想知道玩家的实际游戏时间,就要排除玩家离开游戏之后的时间,而不能直接使用录像的时长。如果要计算APM的话,就必须使用玩家的实际游戏时间来计算。所以在Player.java中加入playTime表示实际游戏时间,通过解析玩家离开游戏的数据块来设置。

Player.java

/**
* 游戏时间
*/
private long playTime;

public long getPlayTime() {
	return playTime;
}

public void setPlayTime(long playTime) {
	this.playTime = playTime;
}

在UncompressedData类中加入对游戏进行时的信息的解析。

UncompressedData.java

/**
 * 游戏进行时的信息
 */
private ReplayData replayData;

public UncompressedData(byte[] uncompressedDataBytes) throws UnsupportedEncodingException, W3GException {
		
	this.uncompressedDataBytes = uncompressedDataBytes;
				
	// 跳过前4个未知字节
	offset += 4;
	
	// 解析第一个玩家
	analysisPlayerRecode();
	
	// 游戏名称(UTF-8编码)
	int begin = offset;
	while(uncompressedDataBytes[offset] != 0) {
		offset++;
	}
	gameName = new String(uncompressedDataBytes, begin, offset - begin, "UTF-8");
	offset++;
	
	// 跳过一个空字节
	offset++;
	
	// 解析一段特殊编码的字节串,其中包含游戏设置、地图和创建者
	analysisEncodedBytes();
	
	// 跳过PlayerCount、GameType、LanguageID
	offset += 12;
	
	// 解析玩家列表
	while(uncompressedDataBytes[offset] == 0x16) {
		
		analysisPlayerRecode();
		
		// 跳过4个未知的字节0x00000000
		offset += 4;
	}
	
	// GameStartRecord - RecordID、number of data bytes following
	offset += 3;
	
	// 解析每个Slot
	byte slotCount = uncompressedDataBytes[offset];
	offset++;
	for(int i = 0; i < slotCount; i++) {
		analysisSlotRecode(i);
	}
	
	// RandomSeed、RandomSeed、StartSpotCount
	offset += 6;
	
	// 游戏进行时的信息解析
	replayData = new ReplayData(uncompressedDataBytes, offset, playerList);
}

public ReplayData getReplayData() {
	return replayData;
}

修改Test.java类中main方法进行测试。

Test.java

package com.xxg.w3gparser;

import java.io.File;
import java.io.IOExcepti