2017-03-04 37 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