Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

게임 메시지처리를위해 웹소켓을 이용할것이며,

스프링에 웹소켓을 탑재를 시도 해봅시다.

컨셉

Image Added

웹소켓을 액터와 연동하여 복잡해지는 메시지 전송을 단순화할것입니다.

여기서는 웹소켓모듈을 스프링에 탑재하여, 간단한 메시지 전송을 해보는것입니다. 


디펜던시

Code Block
languagejava
themeEmacs
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-websocket</artifactId>
</dependency>


<dependency>
   <groupId>org.webjars</groupId>
   <artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
   <groupId>org.webjars</groupId>
   <artifactId>sockjs-client</artifactId>
   <version>1.0.2</version>
</dependency>

<dependency>
   <groupId>org.webjars</groupId>
   <artifactId>stomp-websocket</artifactId>
   <version>2.3.3</version>
</dependency>

...

게임 로직에서도 이러한 이벤트를 전달하여, 사용자의 접속 처리를 하는것은 중요한 작업입니다. 


실제코드 참고:


서버 컨트롤러 준비

Code Block
languagejava
themeEmacs
@Controller
@SuppressWarnings("Duplicates")
public class GameController {

    private static final Logger logger = LoggerFactory.getLogger(GameController.class);

    @MessageMapping("/game.req")
    @SendTo("/topic/public")
    public GameMessage gameReq(@Payload GameMessage gameMessage,
                               SimpMessageHeaderAccessor headerAccessor) {

        String  sessionId = headerAccessor.getUser().getName();
        logger.info("GameMsg:" + gameMessage );
        String gamePacket = gameMessage.getContent();
        String splitMessage[] = gamePacket.split("!!");

        String userName = headerAccessor.getSessionAttributes().get("username").toString();
        String userSession =  headerAccessor.getUser().getName();

        Object objTableNo = headerAccessor.getSessionAttributes().get("tableNo");
        Integer tableNo = objTableNo!=null? (Integer)objTableNo : -1;
....
}

그다음 해야할것은, 클라이언트와 주고받을 메시지(여기서는 GameMessage)를 서버와 클라이언트가 주고받을 메시지를 정의하는것입니다.

디테일하게 여러메시지를 정의할수도 있지만, 여기서는 하나의 단일 메시지로 대부분의 게임처리를 가능하게끔 가능하게 심플하게 설계하였습니다.

그리고 클라이언트가 전송하면 처리할 다음해야할일은, 클라이언트의 전송을 받을수 있는 서버 컨트롤러를 준비하는것입니다.  서버 컨트롤러는 WS의 Endpoint 를 준비합니다. -/topic/public/game.req 


참고소스:


프론트 JS코드 준비

Code Block
languagejs
themeEmacs
var stompClient = null;

function setConnected(connected) {
    $("#connect").prop("disabled", connected);
    $("#disconnect").prop("disabled", !connected);
    if (connected) {
        $("#conversation").show();
    }
    else {
        $("#conversation").hide();
        sceneControler('intro');
    }
    $("#greetings").html("");
}

function connect() {
    var socket = new SockJS('/ws');
    stompClient = Stomp.over(socket);
    stompClient.connect({}, function (frame) {
        setConnected(true);
        console.log('Connected: ' + frame);

        // for broad cast
        stompClient.subscribe('/topic/public', onMessageReceived );

        // for send to some
        stompClient.subscribe('/user/topic/public', onMessageReceived );

        var username=$("#name").val();
        if(username.length<1){username="Unknown"};
        // Tell your username to the server
        stompClient.send("/app/lobby.addUser",
            {},
            JSON.stringify({sender: username, type: 'JOIN'})
        )
    });
}

function disconnect() {
    if (stompClient !== null) {
        stompClient.disconnect();
    }
    setConnected(false);
    console.log("Disconnected");
}

function joinTable(tableNo) {
    stompClient.send("/app/game.req",
        {},
        JSON.stringify({content: 'join',num1:tableNo, type: 'GAME'})
    )
}

function seatTable() {
    stompClient.send("/app/game.req",
        {},
        JSON.stringify({content: 'seat', type: 'GAME'})
    )
}


function sendChatMsg() {
    var content = $('#gamemsg').val();
    stompClient.send("/app/hello",
        {},
        JSON.stringify({content: content, type: 'CHAT'})
    )
}

function sendGameMsg() {
    var content = $('#gamemsg').val();
    stompClient.send("/app/game.req",
        {},
        JSON.stringify({content: content, type: 'GAME'})
    )
}

function sendGameAction(action) {
    var content = $('#gamemsg').val();
    stompClient.send("/app/game.req",
        {},
        JSON.stringify({content: action.content,num1:action.num1,num2:action.num2, type: 'ACTION'})
    )
}

function showGreeting(message) {
    $("#greetings").append("<tr><td>" + message + "</td></tr>");
}

function onMessageReceived(payload) {
    var message = JSON.parse(payload.body);

    var messageElement = document.createElement('li');

    if(message.type == 'JOIN') {
        showGreeting('Welcome ' + message.sender)
    } else if (message.type == 'LEAVE') {
        showGreeting(message.sender + 'left!')
    } else if(message.type == 'GAME'){
        messageControler(message);
        //showGreeting(message.content);
    } else{
        showGreeting(message.content);
    }
}

$(function () {
    $("form").on('submit', function (e) {
        e.preventDefault();
    });
    $( "#connect" ).click(function() { connect(); });
    $( "#disconnect" ).click(function() { disconnect(); });
    $( "#send" ).click(function() { sendGameMsg(); });


});

...

  • connect : 컨넥션을 시도하고 성공을 감지

  • disconnect : 서버에의한 접속해지 감지
  • onMessage : 서버에의한 메시지 이벤트
  • send : 서버에게 전송할 미시지메시지


참고소스: