2017-03-04 70 views
0

我正在爲我的網絡課程製作多人冒險遊戲。我有一個客戶端和一個服務器,服務器是多線程的,並且每當新客戶端連接時就啓動一個新線程。我有一個數組列表,用於跟蹤玩家以確保不添加新玩家。出於某種原因,當一個新客戶連接時,它會取代舊客戶並填補一個新的空白。這是我對於這部分從線程訪問數組列表

public class ClientHandler implements Runnable{ 
private AsynchronousSocketChannel clientChannel; 
private static String command[]; 
private static String name; 
private static GameCharacter character; 
public ClientHandler(AsynchronousSocketChannel clientChannel) 
{ 
    this.clientChannel = clientChannel; 
} 

public void run(){ 
    try{ 
     System.out.println("Client Handler started for " + this.clientChannel); 
     System.out.println("Messages from Client: "); 
     while ((clientChannel != null) && clientChannel.isOpen()) { 
      ByteBuffer buffer = ByteBuffer.allocate(32); 
      Future result = clientChannel.read(buffer); 
      //Wait until buffer is ready 
      result.get(); 
      buffer.flip(); 
      String message = new String(buffer.array()).trim(); 
      if(message == null || message.equals("")) 
      { 
       break; 
      } 
      System.out.println(message); 
      clientChannel.write(buffer); 
      try { 
       //Add the character to the routing table and the character table 
       if (message.contains("connect")) { 
        System.out.println("I'm here too?"); 
        command = message.split(" "); 
        name = command[1]; 
        AdventureServer.userInfo.put(name, this); 
        //Check to see if this game character exists 
        GameCharacter test; 
        boolean exists = false; 
        for(int i=0; i < AdventureServer.characters.size(); i++) 
        { 
         test = AdventureServer.characters.get(i); 
         System.out.println(test.getName()); 
         System.out.println(this.name); 
         if(this.name.equals(test.getName())) 
         { 
          System.out.println("already Here"); 
          exists = true; 
         } 
        } 
        if (exists == true) 
        { 
         //This person has connected to the server before 
        } 
        else { 
         //Create a game character 
         System.out.println("didn't exist before"); 
         character = new GameCharacter(this.name, World.getRow(), World.getCol()); 
         AdventureServer.characters.add(AdventureServer.userInfo.size() - 1, character); 
         System.out.println(AdventureServer.characters.get(0).getName() + " " +AdventureServer.characters.get(1).getName()); 
        } 
       } 

據我所知,在底部的打印線將拋出一個錯誤連接第一客戶端代碼,但這不是問題的一部分。 這裏是服務器的聲明

public class AdventureServer { 
public static Map<String, ClientHandler> userInfo = new HashMap<>(); 
public static World world; 
public static List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>()); 
public static void main(String args[]) { 
    //Create the games map that all of the users will exist on 
    world = new World(args[0]); 

    System.out.println("Asynchronous Chat Server Started"); 
    try { 
     AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); 
     InetSocketAddress hostAddress = new InetSocketAddress("192.168.1.7", 5000); 
     serverChannel.bind(hostAddress); 
     while (true) 
     { 
      System.out.println("Waiting for client to connect"); 
      Future acceptResult = serverChannel.accept(); 
      AsynchronousSocketChannel clientChannel = (AsynchronousSocketChannel) acceptResult.get(); 
      new Thread (new ClientHandler(clientChannel)).start(); 
     } 
    } catch (Exception e) { 
     System.out.println("error interrupted"); 
     e.printStackTrace(); 
     System.exit(0); 
    } 
} 
} 

這裏是我的遊戲人物

public class GameCharacter { 
public static int xpos; 
public static int ypos; 
private static String name; 
private static int rowSize; 
private static int columnSize; 
static List<String> inventory = new ArrayList<>(); 

//Constructor 
GameCharacter(String n, int rSize, int cSize) 
{ 
    xpos = 0; 
    ypos = 0; 
    name = n; 
    rowSize = rSize; 
    columnSize = cSize; 
} 

GameCharacter() 
{ 
    xpos = 0; 
    ypos = 0; 
    name = "billybob"; 
    rowSize = 10; 
    columnSize = 10; 
} 
+0

正是這條線代碼的東西搞砸了 dventureServer.characters.add(character); – Dean

+0

你確定這不只是因爲'ClientHandler'中的字段是靜態的嗎?這意味着每個客戶端處理程序共享相同的字符,相同的名稱和相同的命令。 – immibis

回答

0

你可以試試:

public static volatile List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>()); 

更新: 的問題是,您使用的是非同步的HashMap的用戶信息。 更改該行從:

AdventureServer.characters.add(AdventureServer.userInfo.size() - 1, character); 

要:

AdventureServer.characters.add(character); 

或者讓你的HashMap的同步:

public static Map<String, ClientHandler> userInfo = Collections.synchronizedMap(new HashMap<>()); 

所有這些靜態的聲明正在的問題,您應該刪除它們。一般來說,你應該避免使用靜態的。

ClientHandler的:

private static String command[]; 
private static String name; 
private static GameCharacter character; 

GameCharacter:

public static int xpos; 
public static int ypos; 
private static String name; 
private static int rowSize; 
private static int columnSize; 
static List<String> inventory = new ArrayList<>(); 

只是一個側面說明,這樣你的類更像是Java代碼應該是這樣的:

import java.util.ArrayList; 
import java.util.List; 

public class GameCharacter { 
private int xpos; 
private int ypos; 
private String name; 
private int rowSize; 
private int columnSize; 

private List<String> inventory = new ArrayList<>(); 

// Constructor 
GameCharacter(String n, int rSize, int cSize) { 
    this.xpos = 0; 
    this.ypos = 0; 
    this.name = n; 
    this.rowSize = rSize; 
    this.columnSize = cSize; 
} 

GameCharacter() { 
    this.xpos = 0; 
    this.ypos = 0; 
    this.name = "billybob"; 
    this.rowSize = 10; 
    this.columnSize = 10; 
} 

public int getXpos() { 
    return xpos; 
} 

public void setXpos(int xpos) { 
    this.xpos = xpos; 
} 

public int getYpos() { 
    return ypos; 
} 

public void setYpos(int ypos) { 
    this.ypos = ypos; 
} 

public String getName() { 
    return name; 
} 

public void setName(String name) { 
    this.name = name; 
} 

public int getRowSize() { 
    return rowSize; 
} 

public void setRowSize(int rowSize) { 
    this.rowSize = rowSize; 
} 

public int getColumnSize() { 
    return columnSize; 
} 

public void setColumnSize(int columnSize) { 
    this.columnSize = columnSize; 
} 

public List<String> getInventory() { 
    return inventory; 
} 

public void setInventory(List<String> inventory) { 
    this.inventory = inventory; 
} 

} 
+0

那不行,不幸的是 – Dean

+0

對不起,還是壞了。它在我調用名稱更改的構造函數之後。所以在我將它添加到arraylist之前 – Dean

+0

問題在於構造函數中,我只是添加它給你看。 – Dean

0

可讀性,可測試性和風格的問題的構造,我也建議你不要直接訪問數據屬於另一類的結構。取而代之的

Adventureserver.characters.add(blah blah) 

我會建議做人物的私人領域Adventureserver的,然後創建從中添加或刪除字符的方法。事實上,我傾向於不要讓角色變成靜態 - 沒有任何真正的優勢,並且您可能在某個時刻想要運行多個Adventureserver。

有點像這樣:

public class AdventureServer { 
<...> 
private List<GameCharacter> characters = Collections.synchronizedList(new ArrayList<>); 

<...> 
public void addCharacter(GameCharacter char) { 
    <... error checking ...> 
    characters.add(char); 
} 
public void removeCharacter(GameCharacter char) { 
    <... implementation ... > 
} 
public boolean isCharacterHere(GameCharacter char) { 
} 
public List<GameCharacter> getCharacters() { 
    <... you could either return characters here, or a copy of it, 
    depending upon how paranoid you want to be > 
+0

問題出在構造函數中,我只是添加它給你看。 – Dean