Tag: "Join:"

1. 사용자는 Test 파일을 실행시켜서 Lobby를 생성한다.
2. 생성된 Lobby는 자신의 ClientManager를 생성한다.
3. 모든 사용자가 자신의 Lobby를 생성하고 서버 연결이 완료되면 화면에 각자 닉네임을 입력한다.
- 지금은 누가 뒤늦게 서버에 연결하면 화면에 이전에 입장한 플레이어의 닉네임이 보이지 않는다.
- 닉네임 하나를 입력할 때마다 그 String 하나씩 BroadCasting 하기 때문이다.
- 나중에 이 부분을 지금까지 입력된 플레이어 닉네임 리스트를 BroadCasting 하는 방식으로 업데이트할 수 있다.
4. Lobby가 입력받은 닉네임을 ClientManager에게 보낸다.
//닉네임 입력받기
nicknameInputField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JTextField nicknameField = (JTextField) e.getSource();
String nickname = nicknameField.getText();
nicknameField.setText("");
//Join 시퀀스 시작
clientManager.sendMessage("Join:" + nickname);
}
});
Lobby
5. ClientManager는 받은 닉네임을 ClientThread를 거쳐서 OutputThread를 통해 Server에게 보낸다.
// 서버로 메세지 전송
public void sendMessage(String message) {
if (clientThread != null) {
clientThread.sendMessage(message);
} else {
System.err.println("서버에 연결되지 않았습니다.");
}
//Join: 이면 내 이름으로 저장
if (message.startsWith("Join:")) {
String nickname = message.substring(5); // "Join:" 제거하고 닉네임만 추출
this.myName = nickname;
사회자.setLobby(lobby);
}
}
ClientManager
public void sendMessage(String message) {
if (outputThread != null) {
outputThread.sendMessage(message);
}
}
ClientThread
public class OutputThread extends Thread {
private final PrintWriter out;
private final BlockingQueue<String> queue; // 메시지 전송 대기열
public OutputThread(PrintWriter out) {
this.out = out;
this.queue = new LinkedBlockingQueue<>();
}
@Override
public void run() {
try {
while (!Thread.currentThread().isInterrupted()) {
// 큐에서 메시지를 꺼내 서버로 전송 (큐가 비면 대기)
String message = queue.take();
out.println(message);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 외부에서 호출하여 메시지를 큐에 넣음
public void sendMessage(String message) {
try {
queue.put(message);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
OutputThread
6. Server는 ServerThread로 메시지를 받아와서 CommandManager로 처리한 후 JoinCommand를 실행한다.
String request="";
while ((request = bf.readLine()) != null) {
networkBrain.processMessage(this, request);
}
ServerThread
// 클라이언트가 보내는 메세지 처리 메소드
public synchronized void processMessage(ServerThread sender, String rawMessage) {
if (rawMessage == null || rawMessage.equals("")) return;
System.out.println("[CommandManager] 메시지 받음: " + rawMessage);
String[] tokens = rawMessage.split(":", 2);
String commandKey = tokens[0]; // "Start", "Join", "Message", "Mafia_message" 중 하나
String payload; // 유저가 보낸 메세지(실제 내용)
if (tokens.length > 1) {
payload = tokens[1];
} else {
payload = "";
}
ICommand command = commandMap.get(commandKey);
if (command != null) {
command.execute(sender, payload, logicBrain.getState());
} else {
// Start 명령어일 시 모든 클라이언트에게 게임이 시작되었다고 알려주기.
logicBrain.init_game();
broadcastAll("Start:");
}
}
CommandManager
7. JoinCommand는 받은 닉네임으로 사회자한테 Player 생성하라고 하고 CommandManager, ServerThread를 통해서 모든 Client들에게 BroadCasting한다.
public void execute(ServerThread sender, String payload, IState currentState) {
logicBrain.createNewPlayer(payload);
networkBrain.broadcastAll("Join:"+payload); // 여기서 payload 플레이어의 닉네임
}
JoinCommand
public void broadcastAll(String message) {
// 동기화 리스트긴한데 혹시 반복 중에 캐릭터가 제거되거나 하면 에러나니까 동기화 블록으로 묶었습니다.
synchronized (allClients) {
for (ServerThread client : allClients) {
client.sendMessage(message);
}
}
}
CommandManager
// networkBrain가 메세지 보내라 하면 각자의 소켓으로 메세지를 보냄
public void sendMessage(String message) {
if (pw != null) {
pw.println(message);
} else {
log("PrintWriter 초기화 안 됨");
}
}
ServerThread
8 -1. InputThread는 Server가 BroadCasting한 메세지를 받아서 ClientManager에게 준다.
public void run() {
String message;
try {
// 서버로부터 메시지가 올 때까지 대기하다가 읽음
while ((message = in.readLine()) != null) {
// 메시지를 읽자마자 Manager에게 전달
clientManager.handleMessage(message);
}
} catch (IOException e) {
System.out.println("수신 스레드 종료 (연결 끊김)");
}
}
InputThread
9. ClientManager는 Lobby가 화면에 입장한 플레이어 이름을 띄우도록 한다.
// Case 1: 플레이어 입장 (서버가 "Join:닉네임"을 보냄)
if (message.startsWith("Join:")) {
String nickname = message.substring(5); // "Join:" 제거하고 닉네임만 추출
// 로비 화면의 리스트에 닉네임 추가
lobby.newPlayerEntered(nickname);
System.out.println("view 함수 호출");
}
ClientManeger
//Join 시퀀스의 끝
public void newPlayerEntered(String nickname) {
enteredPlayer.addElement(nickname);
if(enteredPlayer.getSize() >= 4) {
startButton.setEnabled(true);
}
}
Lobby
8-2. 사회자는 서버가 준 닉네임을 RoleRactory로 보내서 플레이어를 생성한다.
public Player createNewPlayer(String nickname) {
Player newPlayer = roleFactory.createPlayer(nickname, players.size()+1);
addPlayer(newPlayer);
return newPlayer;
}
사회자
public Player createPlayer(String nickname, int id) {
Player player = new Player(nickname, id);
return player;
}
RoleFactory
'JAVA' 카테고리의 다른 글
| [JAVA] Spring Boot - 2 (0) | 2025.11.25 |
|---|---|
| [마피아] Start Sequence (0) | 2025.11.21 |
| [JAVA] Spring Boot - 1 (0) | 2025.11.18 |
| [JAVA] DB (0) | 2025.11.16 |
| [JAVA] Network & Socket (0) | 2025.11.04 |