日韩性视频-久久久蜜桃-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计算的全部內容,希望文章能夠幫你解決所遇到的問題。

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

主站蜘蛛池模板: 日本三级视频在线 | 动漫av网站免费观看 | 日韩欧美国产一区二区在线观看 | 91av毛片| av在线资源站 | 欧美三级一区二区 | 国产乱淫av公 | 96精品| 国产精品免费在线播放 | 五月天婷婷在线视频 | 国产精品毛片一区二区在线看舒淇 | 四虎一区二区 | 美女又黄又免费 | 老司机免费精品视频 | 亚洲欧洲综合网 | 老司机精品视频在线播放 | 亚洲4438 | www一区二区三区 | 中文字幕一区二区在线观看视频 | 日韩精品专区 | 天堂…中文在线最新版在线 | av在线网址大全 | 疯狂做爰的爽文多肉小说王爷 | 久综合| 亚洲午夜精品在线观看 | 巨大乳の揉んで乳榨り奶水 | 国产一区成人 | 久草手机在线视频 | 中文在线天堂网 | 潘金莲黄色一级片 | 午夜激情福利电影 | 欧美性受xxxx黑人xyx性 | 看片免费黄在线观看入口 | 久久高清内射无套 | 网站黄在线 | 日韩人妻一区二区三区蜜桃 | 欧美少妇在线 | 丰满人妻中伦妇伦精品app | 欧美绿帽合集videosex | 国产大片一区二区三区 | 亚洲男人网站 | 在线观看成人动漫 | 肉色丝袜小早川怜子av | 中国一级大黄大黄大色毛片 | 国产一区二区三区中文字幕 | 午夜性色福利影院 | 亚洲综合涩 | 久久女女 | www.色就是色.com | 一卡二卡三卡在线 | 精品在线视频一区 | 欧美一级淫片免费视频黄 | 亚洲va视频| 无人码人妻一区二区三区免费 | 调教91 | 亚洲网在线观看 | 男女互操视频 | 亚洲专区一区二区三区 | 亚洲另类色综合网站 | 中国一级特黄真人毛片免费观看 | 在线看片福利 | www日本高清视频 | 国产无码精品视频 | 国产美女免费网站 | 午夜精品国产精品大乳美女 | 澳门色网| 国产免费av一区二区三区 | jzzijzzij亚洲成熟少妇18 欧美www在线观看 | 奶妈的诱惑| 亚洲天堂资源在线 | 男人的天堂狠狠干 | 秋霞综合网 | 成全影视在线观看第8季 | 伊人av网 | 5级黄色片| 成人h动漫精品一区二区器材 | 干干天天 | www.色播.com | 日本国产在线播放 | 国产三级三级在线观看 | 懂色av一区二区在线播放 | 亚洲小视频 | 久久久久久av无码免费网站 | 国产精品日日做人人爱 | 国产 日韩 欧美 综合 | 国产传媒在线观看 | 少妇又色又紧又黄又刺激免费 | 亚洲色图国产视频 | 激情小说中文字幕 | 午夜看看 | 一区二区三区四区五区av | 神马午夜91 | 日本精品一区二区在线观看 | 殴美一级特黄aaaaaa | 国产精品自拍视频 | 亚洲国产婷婷香蕉久久久久久99 | 波多野结衣绝顶大高潮 | 亚洲AV无码成人精品国产一区 | 免费成人深夜小野草 |