我正在嘗試使用GWT開發基於Web客戶端的在線遊戲。字符串數組在分割字符串後拋出ArrayIndexOutOfBoundsException
現在遊戲機制工作得很好,我真的很想繼續我的開發計劃中的下一步,但現在我堅持使用一個簡單的編碼/解碼函數來存儲我的數據客戶端轉換爲字符串。
我採取的步驟並不複雜。在運行期間,我的服務器創建遊戲對象的「ImageStates」,以便在我的客戶端上的Canvas上繪製。每個ImageState都包含許多圖層,其中包含在什麼特定時間等地點需要繪製的細節。
我試過ObjectInput/OutputStream,結合GZip-Compression和ByteInputStreams,但是我找不到前兩個的任何GWT實現,所以我不得不考慮另一個解決方案並碰到gwt-lzma。
我的目標是將這些細節編碼成一個字符串,在服務器上壓縮它,將壓縮後的數據發送到客戶端,在那裏解壓並解碼,以便客戶端可以「讀取」。要做到這一點,我創建了一個編碼和解碼功能:
編碼器:
public static String encodeImageStateContainer(HashMap<String,HashMap<Long,ImageState>> imageStateContainer){
StringBuilder mainStringBuilder = new StringBuilder();
Iterator<Entry<String,HashMap<Long,ImageState>>> imageStateContainerIterator = imageStateContainer.entrySet().iterator();
while(imageStateContainerIterator.hasNext()){
Entry<String,HashMap<Long,ImageState>> tempImageStateManagerMetadata = imageStateContainerIterator.next();
HashMap<Long,ImageState> tempImageStateManager = tempImageStateManagerMetadata.getValue();
if(tempImageStateManager.size() > 0){
if(mainStringBuilder.length() > 0){
mainStringBuilder.append('}'); //Divisor between Image State Managers
}
mainStringBuilder.append(tempImageStateManagerMetadata.getKey());
mainStringBuilder.append('|'); //Divisor between Name and following Data
StringBuilder subOneStringBuilder = new StringBuilder();
Iterator<Entry<Long,ImageState>> tempImageStateManagerIterator = tempImageStateManager.entrySet().iterator();
while(tempImageStateManagerIterator.hasNext()){
Entry<Long,ImageState> tempImageStateMetaData = tempImageStateManagerIterator.next();
if(subOneStringBuilder.length() > 0){
subOneStringBuilder.append(')'); //Divisor between Image Objects
}
subOneStringBuilder.append(tempImageStateMetaData.getKey());
subOneStringBuilder.append('-'); //Divisor between Object Id and Image State Data
StringBuilder subTwoStringBuilder = new StringBuilder();
ImageState tempImageState = tempImageStateMetaData.getValue();
subOneStringBuilder.append(tempImageState.getFirstFrameId()); //1. => First Frame Id
subOneStringBuilder.append(';'); //Divisor between Image State data types
subOneStringBuilder.append(tempImageState.getFramesPerLayer()); //2. => Total Frame Count
subOneStringBuilder.append(';');
subOneStringBuilder.append(tempImageState.getMinumimScaleFactor()); //3. => Minimum Scale Factor
subOneStringBuilder.append(';');
ImageStateLayer[] tempImageStateLayers = tempImageState.getImageStateLayers();
for(int layerId = 0; layerId < tempImageStateLayers.length; ++layerId){
if(subTwoStringBuilder.length() > 0){
subTwoStringBuilder.append('/'); //Divisor between Image State Layers
}
//Frame Arrays
String[] imageNativePath = tempImageStateLayers[layerId].getImageNativePath();
short[] offsetX = tempImageStateLayers[layerId].getOffsetX();
short[] offsetY = tempImageStateLayers[layerId].getOffsetY();
short[] orientation = tempImageStateLayers[layerId].getOrientation();
//Finalization Arrays
byte[] imagePathChange = tempImageStateLayers[layerId].getImagePathChange();
byte[] offsetXChange = tempImageStateLayers[layerId].getOffsetXChange();
byte[] offsetYChange = tempImageStateLayers[layerId].getOffsetYChange();
byte[] orientationChange = tempImageStateLayers[layerId].getOrientationChange();
//Image Path Data
StringBuilder subThreeStrignBuilder = new StringBuilder();
for(int imagePathId = 0; imagePathId < imageNativePath.length; ++imagePathId){
if(subThreeStrignBuilder.length() > 0){
subThreeStrignBuilder.append('#'); //Divisor between Frame Data Sets
}
subThreeStrignBuilder.append(imageNativePath[imagePathId]);
subThreeStrignBuilder.append(','); //Divisor between Frame Data Set Data
subThreeStrignBuilder.append(imagePathChange[imagePathId]);
}
subTwoStringBuilder.append(subThreeStrignBuilder.toString());
subTwoStringBuilder.append('['); //Divisor between Frame Data Types
//OffsetX Data
subThreeStrignBuilder = new StringBuilder();
for(int offsetXId = 0; offsetXId < offsetX.length; ++offsetXId){
if(subThreeStrignBuilder.length() > 0){
subThreeStrignBuilder.append('#'); //Divisor between Frame Data Sets
}
subThreeStrignBuilder.append(offsetX[offsetXId]);
subThreeStrignBuilder.append(','); //Divisor between Frame Data Set Data
subThreeStrignBuilder.append(offsetXChange[offsetXId]);
}
subTwoStringBuilder.append(subThreeStrignBuilder.toString());
subTwoStringBuilder.append('['); //Divisor between Frame Data Types
//OffsetY Data
subThreeStrignBuilder = new StringBuilder();
for(int offsetYId = 0; offsetYId < offsetY.length; ++offsetYId){
if(subThreeStrignBuilder.length() > 0){
subThreeStrignBuilder.append('#'); //Divisor between Frame Data Sets
}
subThreeStrignBuilder.append(offsetY[offsetYId]);
subThreeStrignBuilder.append(','); //Divisor between Frame Data Set Data
subThreeStrignBuilder.append(offsetYChange[offsetYId]);
}
subTwoStringBuilder.append(subThreeStrignBuilder.toString());
subTwoStringBuilder.append('['); //Divisor between Frame Data Types
//Orientation Data
subThreeStrignBuilder = new StringBuilder();
for(int orientationId = 0; orientationId < orientation.length; ++orientationId){
if(subThreeStrignBuilder.length() > 0){
subThreeStrignBuilder.append('#'); //Divisor between Frame Data Sets
}
subThreeStrignBuilder.append(orientation[orientationId]);
subThreeStrignBuilder.append(','); //Divisor between Frame Data Set Data
subThreeStrignBuilder.append(orientationChange[orientationId]);
}
subTwoStringBuilder.append(subThreeStrignBuilder.toString());
}
subOneStringBuilder.append(subTwoStringBuilder.toString());
}
mainStringBuilder.append(subOneStringBuilder.toString());
}
}
return mainStringBuilder.toString();
}
解碼器:
public static HashMap<String,HashMap<Long,ImageState>> decodeImageStateContainer(String data){
String[] imageStateManagerArray = data.split("\\}");
HashMap<String,HashMap<Long,ImageState>> imageStateManagerContainer = new HashMap<String,HashMap<Long,ImageState>>(imageStateManagerArray.length);
for(int managerId = 0; managerId < imageStateManagerArray.length; ++managerId){
String[] tempImageStateData = imageStateManagerArray[managerId].split("\\|");
HashMap<Long,ImageState> tempImageStateManager = new HashMap<Long,ImageState>();
imageStateManagerContainer.put(tempImageStateData[0], tempImageStateManager);
String[] tempImageStateManagerObjects = tempImageStateData[1].split("\\)");
for(int objectId = 0; objectId < tempImageStateManagerObjects.length; ++objectId){
String[] tempImageObjectData = tempImageStateManagerObjects[objectId].split("\\-");
long imageObjectId = Long.parseLong(tempImageObjectData[0]);
String[] imageStateMetaData = tempImageObjectData[1].split("\\;");
ImageState tempImageState = new ImageState(Integer.parseInt(imageStateMetaData[1]), Integer.parseInt(imageStateMetaData[0]), Integer.parseInt(imageStateMetaData[2]));
tempImageStateManager.put(imageObjectId, tempImageState);
String[] tempImageStateLayerMetaData = imageStateMetaData[3].split("\\/");
ImageStateLayer[] tempImageStateLayers = new ImageStateLayer[tempImageStateLayerMetaData.length];
for(int layerId = 0; layerId < tempImageStateLayerMetaData.length; ++layerId){
String[] layerElements = tempImageStateLayerMetaData[layerId].split("\\[");
String[] imageNativePathDetails = layerElements[0].split("\\#");
String[] offsetXDetails = layerElements[1].split("\\#");
String[] offsetYDetails = layerElements[2].split("\\#");
**String[] orientationDetails = layerElements[3].split("\\#");**
//Image Path Data
String[] imageNativePaths = new String[imageNativePathDetails.length];
byte[] imagePathChange = new byte[imageNativePathDetails.length];
for(int id = 0; id < imageNativePathDetails.length; ++id){
String[] imagePathDetailElements = imageNativePathDetails[id].split("\\,");
imageNativePaths[id] = imagePathDetailElements[0];
imagePathChange[id] = Byte.parseByte(imagePathDetailElements[1]);
}
//OffsetX Data
short[] offsetX = new short[offsetXDetails.length];
byte[] offsetXChange = new byte[offsetXDetails.length];
for(int id = 0; id < offsetXDetails.length; ++id){
String[] offsetXDetailElements = offsetXDetails[id].split("\\,");
offsetX[id] = Short.parseShort(offsetXDetailElements[0]);
offsetXChange[id] = Byte.parseByte(offsetXDetailElements[1]);
}
//OffsetY Data
short[] offsetY = new short[offsetYDetails.length];
byte[] offsetYChange = new byte[offsetYDetails.length];
for(int id = 0; id < offsetYDetails.length; ++id){
String[] offsetYDetailElements = offsetYDetails[id].split("\\,");
offsetY[id] = Short.parseShort(offsetYDetailElements[0]);
offsetYChange[id] = Byte.parseByte(offsetYDetailElements[1]);
}
//Orientation Data
short[] orientation = new short[orientationDetails.length];
byte[] orientationChange = new byte[orientationDetails.length];
for(int id = 0; id < orientationDetails.length; ++id){
String[] orientationDetailElements = orientationDetails[id].split("\\,");
orientation[id] = Short.parseShort(orientationDetailElements[0]);
orientationChange[id] = Byte.parseByte(orientationDetailElements[1]);
}
//Create the Layer and Add it to the Array
tempImageStateLayers[layerId] = new ImageStateLayer(imageNativePaths,new short[][]{offsetX,offsetY,orientation}, new byte[][]{imagePathChange,offsetXChange,offsetYChange,orientationChange});
}
//Connect the Reference to the layers with the Image State
tempImageState.setImageStateLayers(tempImageStateLayers);
}
}
return imageStateManagerContainer;
}
現在我的問題:如果我編碼它的服務器和解碼上它直接後來它需要大約三個編碼週期,直到我在解碼器的這個特定位置得到一個IndexOutofBoundsException,最後一行是根據堆棧跟蹤錯誤的那條線:
for(int layerId = 0; layerId < tempImageStateLayerMetaData.length; ++layerId){
String[] layerElements = tempImageStateLayerMetaData[layerId].split("\\[");
String[] imageNativePathDetails = layerElements[0].split("\\#");
String[] offsetXDetails = layerElements[1].split("\\#");
String[] offsetYDetails = layerElements[2].split("\\#");
String[] orientationDetails = layerElements[3].split("\\#");
我不會說我是專家,但在測試編碼器後,我可以肯定地說它生成的字符串總是有效的,我得到這個錯誤的字符串也是完整的。我的解碼功能一定有問題,但我不知道它可能是什麼。
正如我所說的,前三個週期正確編碼和解碼,要編碼的數據沒有顯着變化。編碼字符串沒有辦法導致字符串數組小於4個元素。基本上,就我所瞭解的代碼而言,這個錯誤不能存在。
我認爲這可能是某種內存分配問題,它會阻止字符串被正確拆分,但這只是一個無知程序員的想法。
任何幫助深表感謝!
好的,我找到了解決我的問題的方法: 編碼時,我正在將數字類型打印到我的字符串中。在選擇我的Seperator符號時,我沒有采用負值,導致在考慮數字之前出現' - ',這導致我在嘗試用' - '分割時無法控制分割字符串。 我用另一個字符替換減號,現在一切正常! :-) – Corsair
下一次,請只發布相關代碼。如果您爲自己的問題找到了答案,請不要回複評論,而要有正確的答案,以便人們知道已經回答,並且不會浪費時間。 – Renato
您好,感謝您只發布相關信息的建議。這只是我在這個問題上停留了幾天,而當我在這裏發佈這個話題時,我將要完全放棄,這是純粹的運氣,我後來偶然遇到了這個解決方案。 是的,我應該回答這個問題,而不是評論它。事實上,這是我最初想要做的。但後來該網站告訴我,我必須等待8個小時,因爲我是一個新用戶,所以我希望有人至少會看到評論。 另外,我想我至少節省了時間來回答這個問題;-) – Corsair