日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(五):Action和APM计算

發布時間:2024/8/1 java 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(五):Action和APM计算 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在游戲進行中,玩家會進行各種操作,例如編隊、移動、技能、造建筑等,這些操作就是Action。APM(Actions Per Minute),表示每分鐘的操作次數,APM可以很好的反映玩家的手速和實力,當然也有高APM的菜鳥和低APM的高手。

在魔獸錄像文件中,需要記錄下玩家的操作,這些操作是記錄在游戲時間段(TimeSlot)數據塊中的,這在上一篇博文中有提到。

結構:

在TimeSlot中從第6字節開始到數據塊結尾的部分,包含多個玩家數據塊(CommandData Block):

1字節:玩家ID;

2~3字節:數據塊剩余字節數n;

4~n+4字節:包含該玩家對應的多個操作數據塊(ActionBlock)。

ActionBlock結構:

1字節:ActionID,表示操作類型,例如暫停游戲操作的ActionID是0x01;

剩余字節:Action參數,該部分結構需要根據ActionID來確定,有些Action沒有這部分。

由于Action類型很多,每種ActionID對應的ActionBlock結構這里不一一列出,下面列出一小部分:

1.暫停游戲

ActionID:0x01

字節數:1

計算APM:否

2.繼續游戲

ActionID:0x02

字節數:1

計算APM:否

3.編隊

ActionID:0x17

字節數:4+n*8

計算APM:是

結構:

1字節:ActionID;

2字節:隊伍編號(0~9);

3~4字節:選擇單位的數量n;

5~4+n*8:選擇單位

4.選擇編隊

ActionID:0x18

字節數:3

計算APM:是

結構:

1字節:ActionID;

2字節:隊伍編號(0~9);

3字節:未知0x03

APM計算:

由于暴雪官方并沒有提供APM的計算方式,所以APM計算的方式都是前輩牛人們總結出來的,不同的錄像分析軟件算出來的APM可能會有一些誤差。

APM的值等于玩家的有效Action數量除以玩家游戲時間的分鐘數。

一個ActionBlock一般表示玩家的一次操作,例如一次編隊、暫停游戲。其中部分操作要算入APM中,例如編隊,而有些操作不計算APM,例如暫停游戲。另外,還有的ActionBlock是自動生成的,也不算入APM。Action是否算入APM可以查看文檔w3g_actions.txt。

其中比較特殊的有ActionID為0x16的Action。這個Action表示選擇或取消選擇。ActionBlock的第二個字節為0x01表示選擇,0x02表示取消選擇。一般來說這個Action是算入APM的,但是如果兩個相鄰的ActionID為0x16的ActionBlock,前一個為取消選擇,后一個為選擇,那么這兩個ActionBlock只算一次有效的Action,因為前一個是自動生成的。

在游戲進行過程中,可能會有玩家暫停游戲的情況,也有玩家在游戲結束前提前退出游戲的情況。在計算APM的時候一定要去掉這部分的時間,這樣算出來的APM才準確。

下面的截圖就是RepKing錄像分析軟件沒有考慮游戲暫停導致的問題,導致玩家游戲時間大于錄像的時長,APM計算不準確。

Java解析Action和APM:

在Player.java中加入action表示玩家的有效操作數:

/**

* 操作次數

*/

private int action;

public int getAction() {

return action;

}

public void setAction(int action){

this.action = action;

}在ReplayData.java中,加入對Action的解析,在ReplayData中加入isPause表示游戲是否暫停,在游戲暫停時游戲時間不能增加:

/**

* 是否暫停

*/

private boolean isPause;

/**

* 解析一個時間塊

*/

private void analysisTimeSlot() {

offset++;

int bytes = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset);

offset += 2;

// 游戲時間在非暫停狀態下增加

int timeIncrement = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset);

if(!isPause) {

time += timeIncrement;

}

offset += 2;

// 解析Action

analysisAction(offset + bytes - 2);

}

/**

* 解析TimeSlot中的Action

* @param end TimeSlot的結束位置

*/

private void analysisAction(int timeSlotEnd) {

while(offset != timeSlotEnd) {

byte playerId = uncompressedDataBytes[offset];

Player player = getPlayById(playerId);

int action = player.getAction();

offset++;

int commandDataBlockbytes = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset);

offset += 2;

int commandDataBlockEnd = offset + commandDataBlockbytes;

boolean lastActionWasDeselect = false;

while(offset != commandDataBlockEnd) {

byte actionId = uncompressedDataBytes[offset];

boolean thisActionIsDeselect = false;

if(actionId == 0x16 && uncompressedDataBytes[offset + 1] == 0x02) {

thisActionIsDeselect = true;

}

switch (actionId) {

// 暫停游戲

case 0x01:

isPause = true;

offset++;

break;

// 繼續游戲

case 0x02:

isPause = false;

offset++;

break;

case 0x03:

offset += 2;

break;

case 0x04:

case 0x05:

offset++;

break;

case 0x06:

offset++;

while(uncompressedDataBytes[offset] != 0) {

offset++;

}

offset++;

break;

case 0x07:

offset += 5;

break;

case 0x10:

offset += 15;

action++;

break;

case 0x11:

offset += 23;

action++;

break;

case 0x12:

offset += 31;

action++;

break;

case 0x13:

offset += 39;

action++;

break;

case 0x14:

offset += 44;

action++;

break;

case 0x16:

offset++;

byte selectMode = uncompressedDataBytes[offset];

offset++;

if(selectMode == 0x02) {

action++;

} else {

if(!lastActionWasDeselect) {

action++;

}

}

int number = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset);

offset += 2;

offset += number * 8;

break;

case 0X17:

offset += 2;

int n = LittleEndianTool.getUnsignedInt16(uncompressedDataBytes, offset);

offset += 2;

offset += n * 8;

action++;

break;

case 0x18:

offset += 3;

action++;

break;

case 0x19:

offset += 13;

break;

case 0x1a:

offset++;

break;

case 0x1b:

offset += 10;

break;

case 0x1c:

offset += 10;

action++;

break;

case 0x1d:

offset += 9;

action++;

break;

case 0x1e:

offset += 6;

action++;

break;

case 0x21:

offset += 9;

break;

case 0x20:

case 0x22:

case 0x23:

case 0x24:

case 0x25:

case 0x26:

case 0x29:

case 0x2a:

case 0x2b:

case 0x2c:

case 0x2f:

case 0x30:

case 0x31:

case 0x32:

offset++;

break;

case 0x27:

case 0x28:

case 0x2d:

offset += 6;

break;

case 0x2e:

offset += 5;

break;

case 0x50:

offset += 6;

break;

case 0x51:

offset += 10;

break;

case 0x60:

offset += 9;

while(uncompressedDataBytes[offset] != 0) {

offset++;

}

offset++;

break;

case 0x61:

offset++;

action++;

break;

case 0x62:

offset += 13;

break;

case 0x66:

case 0x67:

offset++;

action++;

break;

case 0x68:

offset += 13;

break;

case 0x69:

case 0x6a:

offset += 17;

break;

case 0x75:

offset += 2;

break;

}

lastActionWasDeselect = thisActionIsDeselect;

}

player.setAction(action);

}

}在Test.java中,輸出計算得到的玩家APM值:

package com.xxg.w3gparser;

import java.io.File;

import java.io.IOException;

import java.util.List;

import java.util.zip.DataFormatException;

public class Test {

public static void main(String[] args) throws IOException, W3GException, DataFormatException {

Replay replay = new Replay(new File("C:/Documents and Settings/Administrator/桌面/131224_[UD]crabby_VS_[ORC]LuciferLVZ_LostTemple_RN.w3g"));

Header header = replay.getHeader();

System.out.println("版本:1." + header.getVersionNumber() + "." + header.getBuildNumber());

long duration = header.getDuration();

System.out.println("時長:" + convertMillisecondToString(duration));

UncompressedData uncompressedData = replay.getUncompressedData();

System.out.println("游戲名稱:" + uncompressedData.getGameName());

System.out.println("游戲創建者:" + uncompressedData.getCreaterName());

System.out.println("游戲地圖:" + uncompressedData.getMap());

List list = uncompressedData.getPlayerList();

for(Player player : list) {

System.out.println("---玩家" + player.getPlayerId() + "---");

System.out.println("玩家名稱:" + player.getPlayerName());

if(player.isHost()) {

System.out.println("是否主機:主機");

} else {

System.out.println("是否主機:否");

}

System.out.println("游戲時間:" + convertMillisecondToString(player.getPlayTime()));

System.out.println("操作次數:" + player.getAction());

System.out.println("APM:" + player.getAction() * 60000 / player.getPlayTime());

if(player.getTeamNumber() != 12) {

System.out.println("玩家隊伍:" + (player.getTeamNumber() + 1));

switch(player.getRace()) {

case 0x01:

case 0x41:

System.out.println("玩家種族:人族");

break;

case 0x02:

case 0x42:

System.out.println("玩家種族:獸族");

break;

case 0x04:

case 0x44:

System.out.println("玩家種族:暗夜精靈");

break;

case 0x08:

case 0x48:

System.out.println("玩家種族:不死族");

break;

case 0x20:

case 0x60:

System.out.println("玩家種族:隨機");

break;

}

switch(player.getColor()) {

case 0:

System.out.println("玩家顏色:紅");

break;

case 1:

System.out.println("玩家顏色:藍");

break;

case 2:

System.out.println("玩家顏色:青");

break;

case 3:

System.out.println("玩家顏色:紫");

break;

case 4:

System.out.println("玩家顏色:黃");

break;

case 5:

System.out.println("玩家顏色:橘");

break;

case 6:

System.out.println("玩家顏色:綠");

break;

case 7:

System.out.println("玩家顏色:粉");

break;

case 8:

System.out.println("玩家顏色:灰");

break;

case 9:

System.out.println("玩家顏色:淺藍");

break;

case 10:

System.out.println("玩家顏色:深綠");

break;

case 11:

System.out.println("玩家顏色:棕");

break;

}

System.out.println("障礙(血量):" + player.getHandicap() + "%");

if(player.isComputer()) {

System.out.println("是否電腦玩家:電腦玩家");

switch (player.getAiStrength())

{

case 0:

System.out.println("電腦難度:簡單的");

break;

case 1:

System.out.println("電腦難度:中等難度的");

break;

case 2:

System.out.println("電腦難度:令人發狂的");

break;

}

} else {

System.out.println("是否電腦玩家:否");

}

} else {

System.out.println("玩家隊伍:裁判或觀看者");

}

}

List chatList = uncompressedData.getReplayData().getChatList();

for(ChatMessage chatMessage : chatList) {

String chatString = "[" + convertMillisecondToString(chatMessage.getTime()) + "]";

chatString += chatMessage.getFrom().getPlayerName() + " 對 ";

switch ((int)chatMessage.getMode()) {

case 0:

chatString += "所有人";

break;

case 1:

chatString += "隊伍";

break;

case 2:

chatString += "裁判或觀看者";

break;

default:

chatString += chatMessage.getTo().getPlayerName();

}

chatString += " 說:" + chatMessage.getMessage();

System.out.println(chatString);

}

}

private static String convertMillisecondToString(long millisecond) {

long second = (millisecond / 1000) % 60;

long minite = (millisecond / 1000) / 60;

if (second < 10) {

return minite + ":0" + second;

} else {

return minite + ":" + second;

}

}

}輸出:

版本:1.26.6059

時長:15:39

游戲名稱:當地局域網內的游戲 (96

游戲創建者:962030958

游戲地圖:Maps\E-WCLMAP\(2)AncientIsles.w3x

---玩家1---

玩家名稱:962030958

是否主機:主機

游戲時間:15:38

操作次數:2635

APM:168玩家隊伍:1

玩家種族:不死族

玩家顏色:黃

障礙(血量):100%

是否電腦玩家:否

---玩家2---

玩家名稱:flygogogo

是否主機:否

游戲時間:15:37

操作次數:3483

APM:222玩家隊伍:2

玩家種族:獸族

玩家顏色:藍

障礙(血量):100%

是否電腦玩家:否

[0:12]962030958 對 所有人 說:glgl

[4:53]962030958 對 所有人 說:==

[4:53]962030958 對 所有人 說:貓咪爬到鍵盤上了

[4:53]962030958 對 所有人 說:g?

[4:53]flygogogo 對 所有人 說:g

[15:32]flygogogo 對 所有人 說:

[15:35]flygogogo 對 所有人 說:gg

[15:36]flygogogo 對 所有人 說:

結束語:

《Java解析魔獸爭霸3錄像W3G文件》系列博文就寫到這里了,當然還有很多可以繼續寫的東西,例如判斷玩家勝負,判斷玩家的英雄、單位等。需要源碼的同學可以在評論中留下E-mail。

總結

以上是生活随笔為你收集整理的java解析魔兽争霸3录像_Java解析魔兽争霸3录像W3G文件(五):Action和APM计算的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 小萝莉末成年一区二区 | 亚洲砖区区免费 | 亚洲爆乳无码精品aaa片蜜桃 | 成人123区| 黄色av片三级三级三级免费看 | 播色网 | 日本h片在线观看 | 国产剧情演绎av | 日韩视频一区二区三区在线播放免费观看 | 99精品一级欧美片免费播放 | 91麻豆国产在线观看 | 欧美成人精品欧美一级 | 色综合九九 | 国产一区二区三区视频在线观看 | 奇米影视第四色7777 | 超碰成人网 | 国产日本亚洲 | 91精品国产99 | 大地资源影视在线播放观看高清视频 | 国产寡妇亲子伦一区二区三区四区 | 天天摸天天干天天操 | 中文字幕少妇 | av综合站 | 国产成人精品一区二区色戒 | 国产精品第七页 | 欧美精品免费视频 | 侵犯亲女在线播放视频 | 日本毛片在线观看 | 国产免费黄色片 | 精东影业一区二区三区 | 蜜臀久久99精品久久久无需会员 | 日本毛片网站 | 国产情侣激情自拍 | 国产又粗又猛又爽视频 | 亚洲av人人夜夜澡人人 | 欧美草逼视频 | 一区二区av| 日韩狠狠操 | 波多野结衣之潜藏淫欲 | 国产视频你懂的 | 久久艹精品 | 人妻夜夜爽天天爽三区麻豆av网站 | 国产三级国产精品国产国在线观看 | 黄色小视频入口 | 字幕网在线观看 | 日韩视频一区在线观看 | 中文字幕88页 | 成人国产片女人爽到高潮 | 国产一区二区三区久久久 | 国产成人亚洲精品自产在线 | 艳妇乳肉豪妇荡乳av无码福利 | 99精品国产99久久久久久97 | 3d动漫精品啪啪一区二区免费 | 97人人插| 久久夜色精品国产噜噜亚洲av | 黄色美女片 | 亚洲欧美a | 日韩成人精品一区二区 | 噜噜噜久久,亚洲精品国产品 | 亚洲专区在线 | a人片 | 国产一二三四五区 | 日韩黄色a级片 | 久久人人插 | 亚洲天堂v | 成人精品免费看 | 少妇中文字幕 | 一区二区三区四区在线 | 中文字幕人妻一区二区 | 久操视频在线播放 | 久久午夜精品视频 | 国产精品你懂的 | 91麻豆精品秘密入口 | 国产视频一二三区 | 日本a在线播放 | 欧美顶级少妇做爰 | 国产精品美女一区二区 | 国产精品国产三级国产播12软件 | 日韩中文字幕网址 | 欧美精品三区 | 91麻豆视频 | 久久久老熟女一区二区三区91 | 亚洲三级影视 | 欧美中文字幕第一页 | 粗大的内捧猛烈进出在线视频 | 国产超碰人人模人人爽人人添 | 国产精品午夜福利视频234区 | av小片| 天天草影院 | 岛国av在线 | 亚洲最新 | 亚洲国产精品成人综合 | 扒丝袜| 成人在线免费观看网站 | 免费毛片a | 成人影视免费观看 | 成人免费黄色片 | 欧美爽爽 | 俄罗斯av片|