2017-03-04 5 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のUserInfoを使用していることです。問題を作っている、あなたがそれらを削除する必要があり

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

これらすべての静的宣言:へ

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

:からその行を変更し

AdventureServer.characters.add(character); 

またはあなたの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

関連する問題