diff --git a/android/RunUsAndroid/app/src/main/java/MultiMode/MultiModeRoom.java b/android/RunUsAndroid/app/src/main/java/MultiMode/MultiModeRoom.java index 6579cb0c..780b3ea2 100644 --- a/android/RunUsAndroid/app/src/main/java/MultiMode/MultiModeRoom.java +++ b/android/RunUsAndroid/app/src/main/java/MultiMode/MultiModeRoom.java @@ -7,14 +7,18 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Queue; public class MultiModeRoom implements Serializable { - - private static final long serialVersionUID = 1L; + private final int GAME_STARTED = 1; + private final int GAME_NOT_STARTED = 0; private final transient List clientOutputStreams = new ArrayList<>(); + private final HashSet finishedUserSet = new HashSet<>(); + private int status = GAME_NOT_STARTED; + private int finishCount = 0; private int id; // 룸 ID private List userList; //유저 정보 private MultiModeUser roomOwner; // 방장 @@ -29,6 +33,7 @@ public class MultiModeRoom implements Serializable { private Queue updateQueue; + public MultiModeRoom(int roomId, RoomCreateInfo roomCreateInfo) { // 유저가 방을 만들때 userList = new ArrayList(); this.id = roomId; @@ -226,6 +231,21 @@ public int compare(UserDistance user1, UserDistance user2) { return null; } + public void addFinishCount(MultiModeUser user) { + if (!finishedUserSet.contains(user.getId())) { + finishCount++; + } + } + + public boolean checkGameFinished() { + return finishCount == userList.size(); + } + + public void startGame() { + status = GAME_STARTED; + } + + @Override public int hashCode() { return id; diff --git a/android/RunUsAndroid/app/src/main/java/MultiMode/Protocol.java b/android/RunUsAndroid/app/src/main/java/MultiMode/Protocol.java index 4d3338c4..e6c3e189 100644 --- a/android/RunUsAndroid/app/src/main/java/MultiMode/Protocol.java +++ b/android/RunUsAndroid/app/src/main/java/MultiMode/Protocol.java @@ -11,5 +11,8 @@ public class Protocol { public static final int UPDATE_USER_DISTANCE = 7; public static final int UPDATE_TOP3_STATES = 8; public static final int START_GAME = 9; + public static final int EXIT_GAME = 10; + public static final int FINISH_GAME = 11; + public static final int CLOSE_GAME = 12; } diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeAdapter.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeAdapter.java index 14edd9fc..652d5cce 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeAdapter.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeAdapter.java @@ -36,11 +36,8 @@ import MultiMode.Protocol; public class MultiModeAdapter extends RecyclerView.Adapter { - - //MultiModeUser user = new MultiModeUser(3, "apple"); private final SocketManager socketManager = SocketManager.getInstance(); // SocketManager 인스턴스를 가져옴 - MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 - //MultiModeUser user = new MultiModeUser(1, "choco"); // 유저 정보 임시로 더미데이터 활용 + MultiModeUser user = MultiModeFragment.user; MultiModeRoom selectedRoom; //MultiMode List 화면에서 각 Room Button과 관련된 Adapter private List roomList; diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeFragment.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeFragment.java index 06f6c10c..5073da73 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeFragment.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeFragment.java @@ -43,10 +43,10 @@ public class MultiModeFragment extends Fragment { - //MultiModeUser user = new MultiModeUser(3, "apple"); + public static MultiModeUser user = new MultiModeUser(1, "choco"); + //public static MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 + //public static MultiModeUser user = new MultiModeUser(3, "apple"); private final SocketManager socketManager = SocketManager.getInstance(); // SocketManager 인스턴스를 가져옴 - MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 - //MultiModeUser user = new MultiModeUser(1, "choco"); Dialog dialog; private Button createRoomButton; private RecyclerView recyclerView; @@ -114,8 +114,8 @@ public void onClick(View v) { if (startTime.isBefore(now)) { startTime = startTime.plusDays(1); } - //RoomCreateInfo roomInfo = new RoomCreateInfo(groupName, distance, LocalDateTime.now().plusSeconds(5), numRunners, duration); - RoomCreateInfo roomInfo = new RoomCreateInfo(groupName, 0, startTime, numRunners, duration); + RoomCreateInfo roomInfo = new RoomCreateInfo(groupName, 0, LocalDateTime.now().plusSeconds(5), numRunners, duration); + //RoomCreateInfo roomInfo = new RoomCreateInfo(groupName, 0, startTime, numRunners, duration); new SendRoomInfoTask().execute(roomInfo); //소켓에 연결하여 패킷 전송 } @@ -276,4 +276,6 @@ protected void onPostExecute(Boolean success) { } } + + } \ No newline at end of file diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModePlayFragment.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModePlayFragment.java index f082b0ce..44a29f72 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModePlayFragment.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModePlayFragment.java @@ -7,11 +7,11 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; -import android.os.Message; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; @@ -19,6 +19,8 @@ import androidx.annotation.Nullable; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; import com.example.runusandroid.MainActivity2; import com.example.runusandroid.R; @@ -47,9 +49,9 @@ public class MultiModePlayFragment extends Fragment { private final List pathPoints = new ArrayList<>(); - + MultiModeUser user = MultiModeFragment.user; //MultiModeUser user = new MultiModeUser(1, "choco"); - MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 + //MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 //MultiModeUser user = new MultiModeUser(3, "apple"); SocketManager socketManager = SocketManager.getInstance(); @@ -69,24 +71,12 @@ public class MultiModePlayFragment extends Fragment { TextView bronzeDistanceTextView; TextView bronzeNickNameTextView; ProgressBar progressBar; - private final Handler top3UpdateHandler = new Handler(Looper.getMainLooper()) {//탑3 유저 업데이트. 아마 handleMessage 코드가 실제로 실행되는지는 모르겟음 - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - - if (msg.obj instanceof Packet) { - Packet receivedPacket = (Packet) msg.obj; - if (receivedPacket.getProtocol() == Protocol.UPDATE_TOP3_STATES) { - UserDistance[] top3UserDistance = receivedPacket.getTop3UserDistance(); - updateTop3UserDistance(top3UserDistance); - } - } - } - }; LocalDateTime gameStartTime; TextView distancePresentContentTextView; //API 사용해서 구한 나의 현재 이동 거리 TextView pacePresentContentTextView; //API 사용해서 구한 나의 현재 페이스 + + Button playLeaveButton; SocketListenerThread socketListenerThread = null; private TextView timePresentContentTextView; private Handler timeHandler; @@ -103,14 +93,6 @@ public void handleMessage(Message msg) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { selectedRoom = (MultiModeRoom) getArguments().getSerializable("room"); - //socketListenerThread = (SocketListenerThread) getArguments().getSerializable("socketListenerThread"); //waitFragment의 socketListenrThread객체 가져와서 이어서 사용 - //socketListenerThread.addPlayFragment(this); - //socketListenerThread.resumeListening(); -// try { -// socketManager.openSocket(); -// } catch (IOException e) { -// throw new RuntimeException(e); -// } gameStartTime = LocalDateTime.now(); mainActivity = (MainActivity2) getActivity(); @@ -132,7 +114,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c distancePresentContentTextView = view.findViewById(R.id.distance_present_content); pacePresentContentTextView = view.findViewById(R.id.pace_present_content); progressBar = view.findViewById(R.id.linear_progress_bar); - + playLeaveButton = view.findViewById(R.id.play_leaveButton); //목표 시간 계산하기 위한 코드 long secondsRemaining = selectedRoom.getDuration().getSeconds(); @@ -147,6 +129,15 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c } + playLeaveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + new ExitGameTask().execute(); + NavController navController = Navigation.findNavController(v); + navController.navigate(R.id.navigation_multi_mode); + } + }); + //TODO: only draw lines if running is started //TODO: doesn't update location when app is in background -> straight lines are drawn from the last location when app is opened again //TODO: lines are ugly and noisy -> need to filter out some points or smoothed @@ -215,6 +206,8 @@ public void run() { if (isFinished == 0) { // 1초마다 Runnable 실행 timeHandler.postDelayed(this, 1000); + } else { + new SendFinishedTask().execute(); } } }; @@ -227,7 +220,7 @@ public void run() { public void run() { Packet requestPacket = new Packet(Protocol.UPDATE_USER_DISTANCE, user, distance); //distance += 1; - new SendPacketTask().execute(requestPacket); + new SendDistanceTask().execute(requestPacket); if (isFinished == 0) { // 1초마다 Runnable 실행 sendDataHandler.postDelayed(this, 5000); // 5초마다 전송. 처음에 socketlistnerthread 설정 때문에 약간의 딜레이가 필요할 듯 함 @@ -263,6 +256,12 @@ public void updateTop3UserDistance(UserDistance[] userDistances) { // 화면에 goldDistance = top3UserDistance[0].getDistance(); String goldDistanceString = String.format("%.3fkm", goldDistance); goldDistanceTextView.setText(goldDistanceString); + + silverNickNameTextView.setText("-"); + silverDistanceTextView.setText("-"); + + bronzeNickNameTextView.setText("-"); + bronzeDistanceTextView.setText("-"); } else if (top3UserDistance.length == 2) { goldNickNameTextView.setText(top3UserDistance[0].getUser().getNickName()); goldDistance = top3UserDistance[0].getDistance(); @@ -274,7 +273,8 @@ public void updateTop3UserDistance(UserDistance[] userDistances) { // 화면에 String silverDistanceString = String.format("%.3fkm", silverDistance); silverDistanceTextView.setText(silverDistanceString); - + bronzeNickNameTextView.setText("-"); + bronzeDistanceTextView.setText("-"); } else { goldNickNameTextView.setText(top3UserDistance[0].getUser().getNickName()); goldDistance = top3UserDistance[0].getDistance(); @@ -289,7 +289,7 @@ public void updateTop3UserDistance(UserDistance[] userDistances) { // 화면에 bronzeNickNameTextView.setText(top3UserDistance[2].getUser().getNickName()); double bronzeDistance = top3UserDistance[2].getDistance(); String bronzeDistanceString = String.format("%.3fkm", bronzeDistance); - silverDistanceTextView.setText(bronzeDistanceString); + bronzeDistanceTextView.setText(bronzeDistanceString); } int progress = 0; @@ -339,7 +339,7 @@ public void onDestroyView() { timeHandler.removeCallbacks(timeRunnable); } - private class SendPacketTask extends AsyncTask { // 서버에 업데이트할 거리 정보 전송 + private class SendDistanceTask extends AsyncTask { // 서버에 업데이트할 거리 정보 전송 @Override protected Boolean doInBackground(Packet... packets) { boolean success = true; @@ -376,4 +376,87 @@ protected void onPostExecute(Boolean success) { } } } + + + //경기 시간이 종료되었을 경우 해당 유저의 레이스가 종료되었다는 패킷을 보냄 + private class SendFinishedTask extends AsyncTask { + Packet packet; + + @Override + protected Boolean doInBackground(Void... voids) { + boolean success = true; + try { + ObjectOutputStream oos = socketManager.getOOS(); + Packet requestPacket = new Packet(Protocol.FINISH_GAME, user, selectedRoom); + oos.writeObject(requestPacket); + oos.flush(); + } catch (IOException e) { + e.printStackTrace(); + success = false; + } finally { + timeHandler.removeCallbacks(timeRunnable); + sendDataHandler.removeCallbacks(sendDataRunnable); + Log.d("response", "socket closed"); + } + return success; + } + + //ExitGameTask 실행 결과에 따라 수행 + @Override + protected void onPostExecute(Boolean success) { + super.onPostExecute(success); + if (success) { + Log.d("SendPacket", "Packet sent successfully!"); + + } else { + Log.d("ExitSendPacket", "Failed to send packet!"); + } + } + + } + + private class ExitGameTask extends AsyncTask { + Packet packet; + + @Override + protected Boolean doInBackground(Void... voids) { + boolean success = true; + try { + ObjectOutputStream oos = socketManager.getOOS(); + Packet requestPacket = new Packet(Protocol.EXIT_GAME, user, selectedRoom); + oos.writeObject(requestPacket); + oos.flush(); + } catch (IOException e) { + e.printStackTrace(); + success = false; + } finally { + try { + socketManager.closeSocket(); + timeHandler.removeCallbacks(timeRunnable); + sendDataHandler.removeCallbacks(sendDataRunnable); + Log.d("response", "socket closed"); + + + } catch (IOException e) { + Log.d("response", "socket close error"); + success = false; + } + + } + return success; + } + + //ExitGameTask 실행 결과에 따라 수행 + @Override + protected void onPostExecute(Boolean success) { + super.onPostExecute(success); + if (success) { + Log.d("SendPacket", "Packet sent successfully!"); + + } else { + Log.d("ExitSendPacket", "Failed to send packet!"); + } + } + + } } diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeResultFragment.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeResultFragment.java new file mode 100644 index 00000000..620594c8 --- /dev/null +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeResultFragment.java @@ -0,0 +1,88 @@ +package com.example.runusandroid.ui.multi_mode; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.Button; +import android.widget.ProgressBar; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; +import androidx.navigation.NavController; +import androidx.navigation.Navigation; + +import com.example.runusandroid.MainActivity2; +import com.example.runusandroid.R; + +import java.io.ObjectOutputStream; +import java.util.Locale; + +import MultiMode.MultiModeRoom; +import MultiMode.MultiModeUser; + +public class MultiModeResultFragment extends Fragment { + + MultiModeUser user = MultiModeFragment.user; + SocketManager socketManager = SocketManager.getInstance(); + ObjectOutputStream oos; + MultiModeRoom selectedRoom; + double distance = 0; + TextView paceGoalContentTextView; + MainActivity2 mainActivity; + TextView timeGoalContentTextView; + TextView goldDistanceTextView; + TextView goldNickNameTextView; + TextView silverDistanceTextView; + TextView silverNickNameTextView; + TextView bronzeDistanceTextView; + TextView bronzeNickNameTextView; + ProgressBar progressBar; + Button playLeaveButton; + SocketListenerThread socketListenerThread = null; + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + + View view = inflater.inflate(R.layout.fragment_multi_room_play, container, false); //각종 view 선언 + if (selectedRoom != null) { + timeGoalContentTextView = view.findViewById(R.id.time_goal_content); + goldNickNameTextView = view.findViewById(R.id.gold_nickname); + goldDistanceTextView = view.findViewById(R.id.gold_distance); + silverNickNameTextView = view.findViewById(R.id.silver_nickname); + silverDistanceTextView = view.findViewById(R.id.silver_distance); + bronzeNickNameTextView = view.findViewById(R.id.bronze_nickname); + bronzeDistanceTextView = view.findViewById(R.id.bronze_distance); + progressBar = view.findViewById(R.id.linear_progress_bar); + playLeaveButton = view.findViewById(R.id.play_leaveButton); + //목표 시간 계산하기 위한 코드 + long secondsRemaining = selectedRoom.getDuration().getSeconds(); + + // 시간, 분으로 변환 + long hours = secondsRemaining / 3600; + long minutes = (secondsRemaining % 3600) / 60; + long seconds = secondsRemaining % 60; + String formattedTime = String.format(Locale.getDefault(), "%02d:%02d:%02d", + hours, minutes, seconds); + + timeGoalContentTextView.setText(formattedTime); + + } + + playLeaveButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + NavController navController = Navigation.findNavController(v); + navController.navigate(R.id.navigation_multi_mode); + } + }); + + + return view; + + } +} diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeWaitFragment.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeWaitFragment.java index 52f1672a..f54faf73 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeWaitFragment.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/MultiModeWaitFragment.java @@ -40,41 +40,13 @@ public class MultiModeWaitFragment extends Fragment { private final Handler handler = new Handler(); // 남은 시간 계산 위한 Handler private final int updateTimeInSeconds = 1; // 1초마다 업데이트/ - //MultiModeUser user = new MultiModeUser(1, "choco"); // 유저 정보 임시로 더미데이터 활용 - MultiModeUser user = new MultiModeUser(2, "berry"); // 유저 정보 임시로 더미데이터 활용 - //MultiModeUser user = new MultiModeUser(3, "apple"); + MultiModeUser user = MultiModeFragment.user; SocketManager socketManager = SocketManager.getInstance(); // SocketManager 인스턴스를 가져옴 private MultiModeRoom selectedRoom; // MultiModeRoom 객체를 저장할 멤버 변수 private TextView titleTextView; private TextView startTimeTextView; private TextView timeRemainingTextView; - private ConstraintLayout waitingListBox; - private final Handler updateHandler = new Handler(Looper.getMainLooper()) { - @Override - public void handleMessage(Message msg) { - super.handleMessage(msg); - - if (msg.obj instanceof Packet) { - Packet receivedPacket = (Packet) msg.obj; - if (receivedPacket.getProtocol() == Protocol.UPDATE_ROOM) { - selectedRoom.setUserList(receivedPacket.getSelectedRoom().getUserList()); - - waitingListBox.removeAllViews(); - - List updatedUserList = selectedRoom.getUserList(); - if (updatedUserList != null && !updatedUserList.isEmpty()) { - for (MultiModeUser user : updatedUserList) { - addUserNameToWaitingList(user.getNickname()); - } - } - } - } - } - }; - private TextView participantCountTextView; - private ObjectInputStream ois; - private SocketListenerThread socketListenerThread; - + private Duration duration; //남은 시간 계산 로직 private final Runnable updateTimeRunnable = new Runnable() { @Override @@ -86,21 +58,9 @@ public void run() { LocalDateTime startTimeDateTime = selectedRoom.getStartTime(); // startTime을 LocalDateTime 객체로 가정합니다. // 남은 시간 계산 - Duration duration = Duration.between(currentDateTime, startTimeDateTime); + duration = Duration.between(currentDateTime, startTimeDateTime); - // startTime이 현재 시간보다 앞선 경우 - if (duration.isNegative() || duration.isZero()) { - timeRemainingTextView.setText("시작까지 0분 0초 남음"); - Bundle bundle = new Bundle(); - bundle.putSerializable("room", selectedRoom); - bundle.putSerializable("user", user); - bundle.putSerializable("socketListenerThread", socketListenerThread); - - NavController navController = Navigation.findNavController(requireView()); - navController.navigate(R.id.navigation_multi_room_play, bundle); - - return; // Runnable 종료 - } + startGame(); long secondsRemaining = duration.getSeconds(); @@ -113,8 +73,10 @@ public void run() { String remainingTime; if (hours > 0) { remainingTime = String.format(Locale.getDefault(), "시작까지 %d시간 %d분 남음", hours, minutes); - } else { + } else if (secondsRemaining >= 0) { remainingTime = String.format(Locale.getDefault(), "시작까지 %d분 %d초 남음", minutes, seconds); + } else { + remainingTime = "경기가 곧 시작됩니다"; } // 업데이트된 시간을 텍스트 뷰에 설정 @@ -124,10 +86,48 @@ public void run() { handler.postDelayed(this, 1000); } }; + private ConstraintLayout waitingListBox; + private final Handler updateHandler = new Handler(Looper.getMainLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + + if (msg.obj instanceof Packet) { + Packet receivedPacket = (Packet) msg.obj; + if (receivedPacket.getProtocol() == Protocol.UPDATE_ROOM) { + selectedRoom.setUserList(receivedPacket.getSelectedRoom().getUserList()); + + waitingListBox.removeAllViews(); + + List updatedUserList = selectedRoom.getUserList(); + if (updatedUserList != null && !updatedUserList.isEmpty()) { + for (MultiModeUser user : updatedUserList) { + addUserNameToWaitingList(user.getNickname()); + } + } + } + } + } + }; + private TextView participantCountTextView; + private ObjectInputStream ois; + private SocketListenerThread socketListenerThread; public MultiModeWaitFragment() { } + void startGame() { + // startTime이 현재 시간보다 앞선 경우 + if (duration.isNegative() || duration.isZero()) { + timeRemainingTextView.setText("곧 경기가 시작됩니다"); + if (selectedRoom.getRoomOwner().getId() == user.getId()) { + new StartRoomTask().execute(); + } + + // Runnable 종료 + } + } + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -178,19 +178,6 @@ public void onClick(View v) { } }); - testButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - new StartRoomTask().execute(); - /* - Bundle bundle = new Bundle(); - bundle.putSerializable("room", selectedRoom); - bundle.putSerializable("user", user); - NavController navController = Navigation.findNavController(requireView()); - navController.navigate(R.id.navigation_multi_room_play, bundle); - */ - } - }); return view; } diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketListenerThread.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketListenerThread.java index 14d57cee..428782bb 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketListenerThread.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketListenerThread.java @@ -12,7 +12,6 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; -import java.net.Socket; import java.net.SocketException; import MultiMode.MultiModeRoom; @@ -79,12 +78,19 @@ public void run() { selectedRoom.enterUser(user); waitFragment.addUserNameToWaitingList(user.getNickName()); } else { + selectedRoom.exitUser(user); waitFragment.removeUserNameFromWaitingList(user.getNickName()); } Log.d("event", "user list: " + room.getUserList()); Log.d("event", "user num: " + room.getUserSize()); waitFragment.updateParticipantCount(room.getUserSize(), room.getNumRunners()); + + if (selectedRoom.getOwner().getId() == user.getId()) { //만약 기존 방장이 방을 나가는 경우 방장 변경 + selectedRoom.setRoomOwner(room.getRoomOwner()); + waitFragment.startGame(); + } + } }); } else if (packet.getProtocol() == Protocol.START_GAME) { @@ -119,6 +125,13 @@ public void run() { } }); + } else if (packet.getProtocol() == Protocol.CLOSE_GAME) { + handler.post(new Runnable() { + @Override + public void run() { + UserDistance[] userDistance = packet.getTop3UserDistance(); + } + }); } } } diff --git a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketManager.java b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketManager.java index 7605f62a..de71a718 100644 --- a/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketManager.java +++ b/android/RunUsAndroid/app/src/main/java/com/example/runusandroid/ui/multi_mode/SocketManager.java @@ -27,7 +27,11 @@ public static synchronized SocketManager getInstance() { public void openSocket() throws IOException { //소켓 열기 if (socket == null || socket.isClosed()) { - socket = new Socket("172.20.10.3", 5001); + socket = new Socket("192.168.0.4", 5001); + + //socket = new Socket("172.20.10.3", 5001); + //socket = new Socket("10.0.2.2", 5001); + oos = new ObjectOutputStream(socket.getOutputStream()); //서버로 보내는 바이트스트림을 직렬화 하기 위해 사용 ois = new ObjectInputStream(socket.getInputStream()); //서버로부터 받는 바이트스트림을 역직렬화 하기 위해 사용 diff --git a/android/RunUsAndroid/app/src/main/res/layout/fragment_multi_room_result.xml b/android/RunUsAndroid/app/src/main/res/layout/fragment_multi_room_result.xml new file mode 100644 index 00000000..26f31fa9 --- /dev/null +++ b/android/RunUsAndroid/app/src/main/res/layout/fragment_multi_room_result.xml @@ -0,0 +1,279 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom$1.class b/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom$1.class index 0958aabe..359d0b5e 100644 Binary files a/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom$1.class and b/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom$1.class differ diff --git a/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom.class b/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom.class index 82c0da3c..90a059f0 100644 Binary files a/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom.class and b/android/SocketServer/out/production/SocketServer/MultiMode/MultiModeRoom.class differ diff --git a/android/SocketServer/out/production/SocketServer/MultiMode/Protocol.class b/android/SocketServer/out/production/SocketServer/MultiMode/Protocol.class index 1ebbb830..6ca100ee 100644 Binary files a/android/SocketServer/out/production/SocketServer/MultiMode/Protocol.class and b/android/SocketServer/out/production/SocketServer/MultiMode/Protocol.class differ diff --git a/android/SocketServer/out/production/SocketServer/Server.class b/android/SocketServer/out/production/SocketServer/Server.class index ef90fe0a..f6ee1702 100644 Binary files a/android/SocketServer/out/production/SocketServer/Server.class and b/android/SocketServer/out/production/SocketServer/Server.class differ diff --git a/android/SocketServer/src/MultiMode/MultiModeRoom.java b/android/SocketServer/src/MultiMode/MultiModeRoom.java index 01470ef2..2404d2ad 100644 --- a/android/SocketServer/src/MultiMode/MultiModeRoom.java +++ b/android/SocketServer/src/MultiMode/MultiModeRoom.java @@ -7,16 +7,17 @@ import java.util.*; public class MultiModeRoom implements Serializable { - - private static final long serialVersionUID = 1L; + private final int GAME_STARTED = 1; + private final int GAME_NOT_STARTED = 0; + private final transient List clientOutputStreams = new ArrayList<>(); + private int status = GAME_NOT_STARTED; + private final HashSet finishedUserSet = new HashSet<>(); + private int finishCount = 0; private int id; // 룸 ID private List userList; //유저 정보 private MultiModeUser roomOwner; // 방장 - private RoomCreateInfo roomCreateInfo; //방 정보 - private final transient List clientOutputStreams = new ArrayList<>(); - private String title; //방 제목 private double distance; //목표 거리 private int numRunners; //제한 인원 @@ -27,6 +28,7 @@ public class MultiModeRoom implements Serializable { private Queue updateQueue = new LinkedList<>(); + public MultiModeRoom(int roomId, RoomCreateInfo roomCreateInfo) { // 유저가 방을 만들때 userList = new ArrayList(); this.id = roomId; @@ -76,6 +78,10 @@ public int exitUser(MultiModeUser user) { } if (userList.size() < 1) { + System.out.println("exitroom - roomId is " + id); + System.out.println(); + System.out.println(); + System.out.println(); RoomManager.removeRoom(this); return index; } @@ -158,7 +164,7 @@ public void setRoomOwner(MultiModeUser roomOwner) { this.roomOwner = roomOwner; } - public Duration getDuration(){ + public Duration getDuration() { return duration; } @@ -183,18 +189,15 @@ public void addUser(MultiModeUser user) { userList.add(user); } - public boolean isRoomOwner(MultiModeUser user){ - if(user.getId() == roomOwner.getId()){ - return true; - } - return false; + public boolean isRoomOwner(MultiModeUser user) { + return user.getId() == roomOwner.getId(); } - public void updateDistance(UserDistance userDistance){ //유저의 distance를 업데이트 + public void updateDistance(UserDistance userDistance) { //유저의 distance를 업데이트 updateQueue.add(userDistance); } - public UserDistance[] getTop3UserDistance(){ //탑3 유저 distance를 리턴 + public UserDistance[] getTop3UserDistance() { //탑3 유저 distance를 리턴 if (updateQueue.size() >= userList.size()) { // userList의 크기만큼의 원소를 updateQueue에서 빼내어 저장할 리스트 List topUserDistances = new ArrayList<>(); @@ -223,9 +226,25 @@ public int compare(UserDistance user1, UserDistance user2) { return top3UserDistances; } + return null; } + public void addFinishCount(MultiModeUser user) { + if (!finishedUserSet.contains(user.getId())) { + finishCount++; + } + } + + public boolean checkGameFinished() { + return finishCount == userList.size(); + } + + public void startGame(){ + status = GAME_STARTED; + } + + @Override public int hashCode() { return id; diff --git a/android/SocketServer/src/MultiMode/Protocol.java b/android/SocketServer/src/MultiMode/Protocol.java index 4d3338c4..e6c3e189 100644 --- a/android/SocketServer/src/MultiMode/Protocol.java +++ b/android/SocketServer/src/MultiMode/Protocol.java @@ -11,5 +11,8 @@ public class Protocol { public static final int UPDATE_USER_DISTANCE = 7; public static final int UPDATE_TOP3_STATES = 8; public static final int START_GAME = 9; + public static final int EXIT_GAME = 10; + public static final int FINISH_GAME = 11; + public static final int CLOSE_GAME = 12; } diff --git a/android/SocketServer/src/Server.java b/android/SocketServer/src/Server.java index c482d018..759064f5 100644 --- a/android/SocketServer/src/Server.java +++ b/android/SocketServer/src/Server.java @@ -115,23 +115,24 @@ private void handleClient(Socket socket, ObjectOutputStream oos) { if(updateRoom.isRoomOwner(user)){ - UserDistance[] top3UserDistance = null; - while(true){ - top3UserDistance = updateRoom.getTop3UserDistance(); - if(top3UserDistance != null){ - break; - } - } - - for(int i = 0; i < top3UserDistance.length; i++){ - System.out.println("user " + i + " : " + top3UserDistance[0].getUser().getNickName() + " , distance : " + top3UserDistance[0].getDistance()); - } - Packet updateTop3Packet = new Packet(Protocol.UPDATE_TOP3_STATES, top3UserDistance); - broadcastToRoomUsers(updateRoom, updateTop3Packet); + updateTop3Users(Protocol.UPDATE_TOP3_STATES, updateRoom); } } else if (((Packet) data).getProtocol() == Protocol.START_GAME) { MultiModeRoom enteredRoom = RoomManager.getRoom(((Packet) data).getSelectedRoom().getId()); + enteredRoom.startGame(); broadcastToRoomUsers(enteredRoom, new Packet(Protocol.START_GAME, enteredRoom)); + }else if(((Packet) data).getProtocol() == Protocol.EXIT_GAME){ + MultiModeRoom exitRoom = RoomManager.getRoom(((Packet) data).getSelectedRoom().getId()); + System.out.println("EXIT_GAME packet received from " + user.getId() + user.getNickName() + "\n\n\n\n"); + int index = exitRoom.exitUser(user); + if(index != -1) exitRoom.removeOutputStream(index); + }else if(((Packet) data).getProtocol() == Protocol.FINISH_GAME){ + MultiModeRoom finishRoom = RoomManager.getRoom(((Packet) data).getSelectedRoom().getId()); + System.out.println("!!!!!!!!FINISH_GAME packet received from " + user.getId() + user.getNickName() + "\n\n\n\n"); + finishRoom.addFinishCount(user); + if(finishRoom.isRoomOwner(user) && finishRoom.checkGameFinished()){ + updateTop3Users(Protocol.CLOSE_GAME, finishRoom); + } } } else if(data instanceof String){ System.out.println((String) data); @@ -170,6 +171,23 @@ private void handleClient(Socket socket, ObjectOutputStream oos) { } finally { //유저가 경기 방에 있다가 서버와의 연결이 갑자기 끊겼을 때 유저를 방에서 내보내는 코드 } } + + private void updateTop3Users(int protocol, MultiModeRoom room){ + UserDistance[] top3UserDistance = null; + while(true){ + top3UserDistance = room.getTop3UserDistance(); + if(top3UserDistance != null){ + break; + } + } + + for(int i = 0; i < top3UserDistance.length; i++){ + System.out.println("user " + i + " : " + top3UserDistance[0].getUser().getNickName() + " , distance : " + top3UserDistance[0].getDistance()); + } + Packet updateTop3Packet = new Packet(protocol, top3UserDistance); + broadcastToRoomUsers(room, updateTop3Packet); + } + private void addNewUserToList(MultiModeUser newUser) { userList.add(newUser); }