우당탕탕 개발일지

[방치RPG 서버 제작기] 1. 프로젝트 생성 + 통신 구현 본문

Server/방치RPG 서버

[방치RPG 서버 제작기] 1. 프로젝트 생성 + 통신 구현

devchop 2025. 1. 26. 18:43

 

서버는 springboot 와 mysql로 진행할 예정이다. 

필요한 기능은 유저 로그인, 백업, 뽑기, 랭킹, 메일 등등 방치형 RPG에 필요한 기본 기능들을 위주로 만들려 한다. 클라이언트는 유니티로 제작할 예정이다. 첫 시도라 매우 두근두근!

 

오늘의 목표

  • springboot 프로젝트 생성하기
  • test api 만들기
  • 유니티 프로젝트 생성하기
  • backendmanager, apiManager를 만들어서 서버와 통신하기

1. 프로젝트 생성하기

https://start.spring.io/ 

 

  • 버전은 snapshot이 붙지 않은 버전 중 가장 최신버전으로 선택했다.
  • gradle-groovy , java로 선택한다.
  • 추가할 dependencies는 다음과 같다.
    1. Spring Web (Rest API개발용)
    2. Spring Boot DevTools (편의성)
    3. Lombok (코드 간결화)
    4. Spring Data  JPA (db)
    5. H2 Database (테스트용 db)

 

VSCode에 JDK 설정 후 gradle sync

gradle for java 설치 후 gradle sync 버튼눌러!

 

vscode에서 개발하기 위해서, .settings.json에 jdk경로를 적어줘야 한다. extionsions 에 있는 gradle for java를 설치하면 왼쪽메뉴에 코끼리 아이콘이 생기는데,거기에서 gradle sync를 할 수 있다.

 

2. 테스트용 API 작성

패키지를 이쁘게 만들어주자.

 

패키지를 위에처럼 종류별로 만들어주고, 통신 테스트를 위해 controller > test 안에 testController.java를 만들었다. 

package com.esa.rpg_server.controller.test;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @GetMapping("/api/hello")
    public String hello(){
        return "Hello from RPG Server!";
    }
}

 

 

 

3. Unity 에서 통신해보기 - BackendManager , API Manager 

유니티에서 BackendManager를 만들고, /api/hello API를 호출해보자.

using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class BackendManager : MonoBehaviour
{
    private string apiURL = "http://localhost:8080/api/hello";
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {
        StartCoroutine(GetHelloMessage());
    }

    IEnumerator GetHelloMessage()
    {
        using (UnityWebRequest request = UnityWebRequest.Get(apiURL))
        {
            yield return request.SendWebRequest();

            if (request.result == UnityWebRequest.Result.Success)
            {
                Debug.Log("Response:" + request.downloadHandler.text);
            }
            else
            {
                Debug.Log("Error::" + request.error);
            }
        }
    }
}

 

오예! 매우 순조롭다.

 

 

 

뽑기를 한다고 가정하면 BackendManager.Gacha() 호출 >> BackendManager는 알맞는 API url 과 함께 APIManager를 통해 통신요청, 결과를 파싱해서 반환하도록 만들고싶다. 총 2개의 매니저이고, 외부에서는 API Manager의 존재는 알 필요가 없도록 할것이다. 나중에 인증에 필요한 토큰을 넣을 예정인데, 그런 토큰관리 및 갱신도 API Manager에서 자동으로 하도록 구현한다. 중복코드를 제거하고, 외부에서 알필요가 없어서 좋다.

 

순수하게 통신만 담당하는 APIManager

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UIElements;

public class APIManager : MonoBehaviour
{
    private static APIManager _instance;
    public static APIManager Instance => _instance;

    private string baseUrl = "http://localhost:8080";
    private string authToken = "";
    // Start is called once before the first execution of Update after the MonoBehaviour is created

    void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(this);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    #region  Get API

    public void GetAPI(string endpoint, Action<int, string> callback)
    {
        StartCoroutine(IGetAPI(endpoint, callback));
    }

    IEnumerator IGetAPI(string endPoint, Action<int, string> callback)
    {
        using (UnityWebRequest request = UnityWebRequest.Get(baseUrl + endPoint))
        {
            request.SetRequestHeader("Authorization", "Barer" + authToken); //추후 진행
            yield return request.SendWebRequest();

            if (request.result == UnityWebRequest.Result.Success) callback?.Invoke(200, request.downloadHandler.text);
            else callback?.Invoke((int)request.result, request.error);
        }
    }

    #endregion

    #region  Post API
    public void PostAPI(string endpoint, string body, Action<int, string> callback)
    {
        StartCoroutine(IPostAPI(endpoint, body, callback));
    }

    IEnumerator IPostAPI(string endpoint, string body, Action<int, string> callback)
    {
        using (UnityWebRequest request = new UnityWebRequest(baseUrl + endpoint, "POST"))
        {
            byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(body);
            request.uploadHandler = new UploadHandlerRaw(bodyRaw);
            request.downloadHandler = new DownloadHandlerBuffer();
            request.SetRequestHeader("Content-Type", "application/json");
            request.SetRequestHeader("Authorization", "Bearer " + authToken); // 필요시 인증 추가

            yield return request.SendWebRequest();

            if (request.result == UnityWebRequest.Result.Success) callback?.Invoke(200, request.downloadHandler.text);
            else callback?.Invoke((int)request.result, request.error);
        }
    }
    #endregion
}

 

어떤 요청인지 받아서 url변환, 포맷화를 담당하는 backendManager

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Networking;

public class BackendManager : MonoBehaviour
{
    private static BackendManager _instance;
    public static BackendManager Instance => _instance;

    void Awake()
    {
        if (_instance == null)
        {
            _instance = this;
            DontDestroyOnLoad(this);
        }
        else
        {
            Destroy(gameObject);
        }
    }

    public void GetHello(Action<string> handler)
    {
        APIManager.Instance.GetAPI("/api/hello", (code, message) =>
        {
            Debug.Log(code + " : " + message);
            handler?.Invoke(code == 200 ? message : "");
        });
    }
}

 

요청할땐 이렇게 하면되겠다.

using UnityEngine;

public class btnHello : MonoBehaviour
{

    public void OnClickHello()
    {
        BackendManager.Instance.GetHello(handler =>
        {
            //todo something;
        });
    }
}

 

 

내일은 로그인하고, 엑세스토큰을 이용하여 유저데이터를 주고받는 부분을 구현하겠다!

시작이 좋아~