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

그것은이 라인은 다음과 같은

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<>(); 

그냥 보조 노트, 당신의 클래스가 더 자바 코드처럼이 방법은 찾아야한다 어떤 것이 엉망이되는 코드 dventureServer.characters.add (character); – Dean

+0

'ClientHandler'의 필드가 정적 인 것이 아니라는 것이 확실합니까? 이는 모든 클라이언트 처리기가 동일한 문자, 동일한 이름 및 동일한 명령을 공유 함을 의미합니다. – immibis

답변

0

당신은 시도 할 수 있습니다 :

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

업데이트 : 문제는 당신이 비 동기화 된 HashMap의 사용자 정보를 사용하고 있다는 점이다. 당신의 HashMap 동기화를

AdventureServer.characters.add(character); 

를 또는합니다 :

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

도착 : 그 줄을 변경

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

그 모든 정적 선언 문제를 만들고있다, 당신이 그들을 제거해야합니다. 일반적으로 정적 사용은 피해야합니다.

ClientHandler에 :

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

GameCharacter :

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

미안하지만, 여전히 고장났다. 그것의 이름을 변경하는 생성자를 호출 한 후에. 그래서 arlerylist에 추가하기 전에 – 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

관련 문제