2021. 2. 5. 14:43ㆍ무작정 프로젝트/API - C#
AutoBot 개발 과정 포스팅 #2과 동일한 포스팅입니다.
AutoBot | 개발 과정 포스팅 #2 - API (Riot LCU C#)
목차 - Riot LCU? : 조금 특별한 API인 Riot LCU에 대한 소개 - 프로젝트 제작 : WinForm으로 리그 오브 레전드 클라이언트 연결, 데이터 확인 - 코드 설명 : 코드에 대한 자세한 설명 끝으로 : 마지막 말 다
jaeho0613.tistory.com
목차
- Riot LCU?
: 조금 특별한 API인 Riot LCU에 대한 소개
- 프로젝트 제작
: WinForm으로 리그 오브 레전드 클라이언트 연결, 데이터 확인
- 코드 설명
: 코드에 대한 자세한 설명
끝으로
: 마지막 말
다운로드
들어가기 전
저 또한 공부하며 만든 프로젝트입니다.
많이 부족하고 부실한 코드지만 조금이나마 도움이 됐으면 하는 마음에 포스팅합니다!
최대한 이해하기 쉽게 작성했지만 부족한 점은 댓글로 남겨주세요!
피드백을 받고 수정하겠습니다!
Riot LCU?
Riot의 API는 2가지가 있습니다.
기본 Riot API와 Riot LCU API입니다.
Riot API
Riot Developer Portal
About the Riot Games API With this site we hope to provide the League of Legends developer community with access to game data in a secure and reliable way. This is just part of our ongoing effort to respond to players' and developers' requests for data and
developer.riotgames.com
저번 포스팅에 사용했던 Kakao API와 비슷한 API입니다.
각종 데이터를 받을 수 있고 활용 가능하게 서비스를 제공합니다만,
제약이 존재합니다. 저 또한 처음 AutoBot을 제작할 땐 Riot API를 사용했지만,
속도 제한에 걸려서 기능 구현에 어려움이 있었죠.
그리고 현재 AutoBot에 제공되는 '자동 수락' 기능에 관해선 여기선 지원하지 않습니다.
* 물론 라이엇 측에게 인증을 받으면 속도 제한선을 넓힐 수 있습니다.
그럼 LCU API는 무엇이냐?
http://lcu.vivide.re/
Cancels the asynchronous operation or removes its completion status. POST /AsyncDelete Tags: builtin asyncToken ID of the asynchronous operation to remove query integer (int32) 200 OK Retrieves the result of a completed asynchronous operation. POST /AsyncR
lcu.vivide.re
특별하게 클라이언트와 통신하는 API입니다.
라이엇은 우리가 사용하는 리그 오브 레전드 클라이언트와 연결하여 클라이언트 데이터를 조작할 수 있게 서비스를 제공하는데요. 바로 이 서비스에 '수락 버튼 클릭', '룬 페이지 설정'등 좀 더 다양한 기능을 제공합니다.
우리가 제작하는 프로젝트는 이 'Riot LCU API'를 활용한 프로그램입니다.
정리하자면
Riot API : 통계 차트, 소환사 데이터 등 OP.GG처럼 전적 검색 사이트를 만들 때 필요한 데이터를 얻기에 유리합니다.
Riot LCU API : 자동 수락, 룬 페이지 설정 등 사용자 유틸리티 프로그램 만들 때 필요한 데이터를 얻기에 유리합니다.
프로젝트 제작
1. 프로젝트 생성
Windows Forms 앱(. NET Framework) 템플릿으로 생성합니다.
프로젝트 명은 'RIOT_TEST_API'로 설정해 주겠습니다.
솔루션 탐색기 > 추가 > 새 폴더로 폴더를 한 개 만들어줍니다.
폴더 이름은 ' Scripts'로 하겠습니다.
Scripts 폴더에 새 항목을 만들어 줍니다.
클래스 설정 후 ClientData.cs로 이름을 설정해줍니다.
위와 같은 방식으로 총 2개의. cs파일을 생성합니다.
2. UI 설정
메인 UI는 사진과 같습니다.
빨간색 부분은 Button
노란색 부분은 TextBox
도구 상자(Ctrl + Alt + x)에서 각 도구를 검색 후 드래그 드롭을 하면 설정이 가능합니다.
3. UI 속성 설정
도구(UI)를 클릭 후 F4를 누르면 속성을 편집할 수 있습니다.
여기서,
(Name)은 변수 이름을 설정해주는 부분이고
Text는 UI의 텍스트를 설정해주는 부분입니다.
각 속성은 아래와 같습니다.
클라이언트 버튼
- (Name) : Btn_ClientInit
- Text : 클라이언트
시작 버튼
- (Name) : Btn_Using
- Text : 시작
룬 페이지 버튼
- (Name) : Btn_RunePage
- Text : 룬 페이지
URL 주소 텍스트 박스
- (Name) : TextBox_Url
메서드 타입 텍스트 박스
- (Name) : TextBox_Method
출력 텍스트 박스
- (Name) : TextBox_OutPut
- Multiline : True
- ScrollBars : Vertical
4. 패키지 추가
도구 > NuGet 패키지 관리자 > 설루션용 NuGet 패키지 관리
패키지 추가란 우리가 프로그램 제작에 좀 더 편리한 외부 도구를 추가하는 작업입니다.
우리가 추가할 패키지는 총 1가지로
* Newtonsoft.JSON : JSON파일 조작에 더 편리한 기능을 제공합니다.
정상적으로 설치가 되면 이렇게 1가지 패키지가 보이게 됩니다.
자! 코딩을 해볼까요?
5. 코딩
ClientData.cs
using System.Diagnostics;
class ClientData
{
public const string CLIENT_NAME = "LeagueClientUx";
public const string GAME_CLIENT_NAME = "League of Legends";
public static string LeaguePath { get; set; } // 롤 클라이언트 실행 경로
public static string ToKen { get; set; } // 롤 클라이언트 토큰
public static ushort Port { get; set; } // 롤 클라이언트 포트
public static string ApiUrl { get; set; } // 롤 클라이언트 ApiUrl
// 메인 프로세스
public static Process clientProcess = null;
// 게임 프로세스
public static Process gameClientProcess = null;
}
RiotClientManager.cs
using System.Diagnostics;
class ClientData
{
public const string CLIENT_NAME = "LeagueClientUx";
public const string GAME_CLIENT_NAME = "League of Legends";
public static string LeaguePath { get; set; } // 롤 클라이언트 실행 경로
public static string ToKen { get; set; } // 롤 클라이언트 토큰
public static ushort Port { get; set; } // 롤 클라이언트 포트
public static string ApiUrl { get; set; } // 롤 클라이언트 ApiUrl
// 메인 프로세스
public static Process clientProcess = null;
// 게임 프로세스
public static Process gameClientProcess = null;
}
Form.1
using Newtonsoft.Json.Linq;
using System;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
namespace RIOT_API
{
public partial class Form1 : Form
{
RiotClientManager clientManager;
public Form1()
{
InitializeComponent();
clientManager = new RiotClientManager();
this.Btn_Using.Click += new System.EventHandler(this.Btn_Using_Click);
this.Btn_RunePage.Click += new System.EventHandler(this.Btn_RunePage_Click);
this.Btn_ClientInit.Click += new System.EventHandler(this.Btn_ClientInit_Click);
clientManager.LeagueClosed += () =>
{
Console.WriteLine("클라이언트 종료");
};
}
// 기본 Http 메시지
private async void Btn_Using_Click(object sender, EventArgs e)
{
// HttpMessage로 받기
var message = await clientManager.UsingApiEventHttpMessage(TextBox_Method.Text, TextBox_Url.Text);
var sMessage = message.Content.ReadAsStringAsync().Result;
TextBox_OutPut.Text = sMessage;
// JObject로 받기
//var message = await clientManager.UsingApiEventJObject(TextBox_Method.Text, TextBox_Url.Text);
//TextBox_OutPut.Text = message.ToString();
}
// 룬페이지 설정
private async void Btn_RunePage_Click(object sender, EventArgs e)
{
// 룬페이지 추가
var jObject = RunePage();
var message = await clientManager.UsingApiEventHttpMessage(TextBox_Method.Text, "/lol-perks/v1/pages", jObject);
}
// 클라이언트 연결
private void Btn_ClientInit_Click(object sender, EventArgs e)
{
try
{
Process[] processes = Process.GetProcessesByName(ClientData.CLIENT_NAME);
ClientData.clientProcess = processes[0];
ClientData.LeaguePath = Path.GetDirectoryName(ClientData.clientProcess.MainModule.FileName);
var lockFilePath = Path.Combine(ClientData.LeaguePath, "lockfile");
using (var fileStream = new FileStream(lockFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(fileStream))
{
var text = reader.ReadToEnd();
string[] items = text.Split(':');
ClientData.ToKen = items[3];
ClientData.Port = ushort.Parse(items[2]);
ClientData.ApiUrl = "https://127.0.0.1:" + ClientData.Port.ToString() + "/";
Console.WriteLine($"Token : {ClientData.ToKen}");
Console.WriteLine($"Port : {ClientData.Port}");
Console.WriteLine($"ApiUri : {ClientData.ApiUrl}");
}
clientManager.Connect();
TextBox_OutPut.Text = "클라이언트 찾기 완료";
}
catch
{
TextBox_OutPut.Text = "클라이언트 찾기 실패";
}
}
// 테스트 룬 페이지
private JObject RunePage()
{
JObject jObject = new JObject();
JArray jArray = new JArray();
jArray.Add("8214");
jArray.Add("8226");
jArray.Add("8210");
jArray.Add("8237");
jArray.Add("8345");
jArray.Add("8347");
jArray.Add("5008");
jArray.Add("5008");
jArray.Add("5002");
jObject.Add("primaryStyleId", "8200");
jObject.Add("subStyleId", "8300");
jObject.Add("selectedPerkIds", jArray);
jObject.Add("name", "테스트룬");
TextBox_OutPut.Text = jObject.ToString();
return jObject;
}
}
}
* 코드에 대한 궁금점은 댓글로 남겨주세요!
위 코드를 작성 후 F5를 눌러서 실행시켜 줍시다.
클라이언트에 연결에 성공하면 출력 박스에 표시가 됩니다.
* 리그 오브 레전드 클라이언트를 실행 후 눌러주시면 됩니다.
클라이언트에 연결됐다면 총 2가지 기능을 테스트해 보겠습니다.
첫 번째 기능은 간단한 API 테스트입니다.
Riot LCU를 설명한 목차에 링크해뒀던 페이지를 참조하여
소환사 정보를 얻는 링크를 사용하겠습니다.
주소 URL 박스에
/lol-summoner/v1/current-summoner
타입 Method 박스에
Get
을 작성 후 '시작' 버튼을 눌러주면 현재 접속된 소환사의 데이터가 출력됩니다.
만약 넘어오는 값(Retrun)이 JSON형태면
Form1.cs의 Btn_Using_Click의 주석 부분을 JObject로 받기를 설정한 후 다시 실행해보면
좀 더 깔끔하게 정리된 게 보이시나요?
두 번째 기능은 룬 설정 기능입니다.
주소 URL 박스에는 아무것도 작성하지 않고
타입 Method 박스에는 Post를 입력하겠습니다.
그리고 '룬 페이지' 버튼을 클릭하면
룬 설정이 저장된 것을 확인할 수 있습니다.
코드 설명
1. ClientData.cs
클라이언트의 데이터를 저장하는 클래스입니다.
각 String값은 전역 변수로 만들어서 어디서든 불러올 수 있도록 만들었습니다.
코드에서 CLIENT_NAME과 GAME_CLIENT_NAME 2가지 종류가 존재하는 이유는
우리가 매칭을 잡는 클라이언트와 게임을 시작했을 때 생성되는 클라이언트명이
다르기 때문인데 지금 프로젝트에선 CLIENT_NAME만 사용되므로 그냥 그렇구나
하고 넘겨주시면 되겠습니다!
* gameClientProcess 또한 동일합니다.
2. RiotClientManager.cs
가장 중요한 클라이언트 매니저 스크립트입니다. 하나하나 뜯어봅시다.
2-1. ConnectInit()
기본 httpClient 변수를 초기화하는 기능을 합니다.
httpClient를 null로 초기화하는 이유는 클라이언트 로그아웃을 했을 때
저번 로그인 설정을 초기화해주기 위함입니다.
2-2. Connect()
롤 클라이언트와 연결하는 기능을 합니다.
후에 설명할 토큰을 읽어와 사용자 인증을 한 후 연결합니다.
그리고 클라이언트를 종료했을 때(로그아웃 했을 때) 발생시킬 이벤트 또한 설정해 줍니다.
2-3. *async UsingApiEventHttpMessage()
API를 사용하는 기능을 합니다.
눈여겨봐야 할 점은 *async 비동기 메서드로 작성돼있는데요.
여기서 비동기란?
엄청나게 큰 데이터를 받는 코드가 있습니다. 약 100GB의 데이터를 받는다고 생각해 봅시다.
그 데이터를 받는 동안은 다른 코드가 실행이 되지 않고 멈춰버리는 현상이 생기는데
비동기적으로 코드를 구현하면 데이터를 받으면서 다음 코드가 정상적으로 동작하게 만들 수 있습니다.
비동기는 조금 이해하기 어려운 문법입니다.
C# async await를 이용하여 비동기를 동기처럼 구현하기 -1
비동기 프로그래밍의 원칙은, 오래 실행되는(또는 오래 실행될 가능성이 있는) 함수는 비동기 연산의 형태로 작성하라는 것이다. 이는, 오래 실행되는 함수를 그냥 동기적으로 작성하고, 필요하
velog.io
위 링크에 자세한 설명이 있으니 참고 바랍니다!
2-4. *async UsingApiEventJObject()
2-3의 전달 값(return)을 받아서 JSON형태로 전환해 주는 기능을 합니다.
크게 설명할 부분은 없습니다.
2-5. ClientProcess_Exited
클라이언트가 종료될 때 실행하는 기능을 합니다.
delegate(대리자)를 실행시키므로 체인을 걸어서 사용이 가능합니다.
Delegate(대리자)?
jaeho0613.tistory.com/79?category=819752
ch13 대리자와 이벤트
챕터13 '대리자와 이벤트' 입니다 메소드를 참조하여 대신 수행해 주는 대리자와 특정 이벤트를 만드는 방법, 콜 백(call back)을 배웁니다. '이것이 C#이다' 교재를 바탕으로 정리했습니다. 이전 정
jaeho0613.tistory.com
옛날에 정리해 뒀던 포스팅이 있는데 참고가 됐으면 좋겠네요.
3. Form1.cs
중요한 부분인 클라이언트를 연결하는 부분과 룬을 추가하는 부분의 코드를 설명하겠습니다.
3-1. 클라이언트 연결
위 코드는 클라이언트를 연결하는 부분입니다.
여기서 우리가 알아야 할 점은 'lockfile'를 찾는 부분입니다.
이 'lockfile'은 우리가 리그 오브 레전드를 실행시킬 때마다 1회성으로 발급되는 토큰 파일입니다.
한번 확인해 볼까요?
리그 오브 레전드가 다운로드돼 있는 폴더로 들어갑니다.
[ C:\Riot Games\League of Legends ] 저는 이 경로로 저장돼 있네요.
클라이언트를 켜고 'lockfile'을 찾아서 메모장으로 열게 되면
이렇게 토큰이 생성됩니다. 우리는 이 토큰을 이용하여 클라이언트와 통신하는 것이죠.
이 파일을 찾아서 내용을 읽고
이렇게 각 위치에 데이터를 넣어주게 됩니다.
위 역할을 수행하는 코드라고 보시면 되겠습니다.
3-2. 룬 설정
룬 설정은 JSON 데이터를 넘겨주면 됩니다.
여기서 각 룬의 특정 번호가 있는데 이 번호는 [다운로드] 부분에 Rune.cs로 첨부하겠습니다.
여러분이 추가하고 싶은 룬 번호로 테스트해보면 좋을 거 같네요.
PrimaryStyleId : 메인 룬 번호 (정밀, 마법, 영감, 지배)
SubStyleId : 서브 룬 번호 (정밀, 마법, 영감, 지배)
SelectedPerkids : 룬 번호 (Rune.cs 참조)
끝으로
http://lcu.vivide.re/
Cancels the asynchronous operation or removes its completion status. POST /AsyncDelete Tags: builtin asyncToken ID of the asynchronous operation to remove query integer (int32) 200 OK Retrieves the result of a completed asynchronous operation. POST /AsyncR
lcu.vivide.re
각 기능과 어떤 데이터를 받아오는지는 위 사이트에서 하나하나 테스트해야 됩니다...
저 또한 각 기능을 확인하려고 위 사이트의 주소 값을 하나하나 테스트해봤죠.
제가 사용한 주소(EndPoint) 또한 [다운로드] 부분에 첨부하며 마치겠습니다.