Commit f3d8287f authored by argon.sun's avatar argon.sun

recon

parent bcfd1afc
...@@ -8,44 +8,129 @@ int DuelClient::responseI; ...@@ -8,44 +8,129 @@ int DuelClient::responseI;
unsigned char DuelClient::responseB[64]; unsigned char DuelClient::responseB[64];
bool DuelClient::is_responseB; bool DuelClient::is_responseB;
unsigned char DuelClient::response_len; unsigned char DuelClient::response_len;
event_base* DuelClient::client_base = 0;
bufferevent* DuelClient::client_bev = 0;
char DuelClient::duel_client_read[0x2000];
char DuelClient::duel_client_write[0x2000];
bool DuelClient::is_host = false;
bool DuelClient::StartClient(unsigned int ip, unsigned short port) { bool DuelClient::StartClient(unsigned int ip, unsigned short port) {
if(connect_state) if(connect_state)
return false; return false;
event_base* evbase;
bufferevent* bev;
sockaddr_in sin; sockaddr_in sin;
evbase = event_base_new(); client_base = event_base_new();
if(!client_base)
return false;
memset(&sin, 0, sizeof(sin)); memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET; sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(ip); sin.sin_addr.s_addr = htonl(ip);
sin.sin_port = htons(port); sin.sin_port = htons(port);
bev = bufferevent_socket_new(evbase, -1, BEV_OPT_CLOSE_ON_FREE); client_bev = bufferevent_socket_new(client_base, -1, BEV_OPT_CLOSE_ON_FREE);
bufferevent_setcb(bev, ClientRead, NULL, ClientEvent, NULL); bufferevent_setcb(client_bev, ClientRead, NULL, ClientEvent, NULL);
if (bufferevent_socket_connect(bev, (sockaddr*)&sin, sizeof(sin)) < 0) { if (bufferevent_socket_connect(client_bev, (sockaddr*)&sin, sizeof(sin)) < 0) {
bufferevent_free(bev); bufferevent_free(client_bev);
return false; return false;
} }
connect_state = 1; connect_state = 1;
Thread::NewThread(ClientThread, evbase); Thread::NewThread(ClientThread, 0);
return true; return true;
} }
void DuelClient::StopClient() {
if(connect_state != 2)
return;
irr::SEvent sevt;
sevt.EventType = irr::EET_USER_EVENT;
sevt.UserEvent.UserData1 = UEVENT_EXIT;
sevt.UserEvent.UserData2 = 1;
mainGame->device->postEventFromUser(sevt);
event_base_loopexit(client_base, NULL);
}
void DuelClient::ClientRead(bufferevent* bev, void* ctx) { void DuelClient::ClientRead(bufferevent* bev, void* ctx) {
evbuffer* input = bufferevent_get_input(bev);
size_t len = evbuffer_get_length(input);
unsigned short packet_len = 0;
while(true) {
if(len < 2)
return;
evbuffer_copyout(input, &packet_len, 2);
if(len < packet_len + 2)
return;
evbuffer_remove(input, duel_client_read, packet_len + 2);
if(packet_len)
HandleSTOCPacket(&duel_client_read[2], packet_len);
len -= packet_len + 2;
}
} }
void DuelClient::ClientEvent(bufferevent *bev, short events, void *ptr) { void DuelClient::ClientEvent(bufferevent *bev, short events, void *ptr) {
if (events & BEV_EVENT_CONNECTED) { if (events & BEV_EVENT_CONNECTED) {
mainGame->HideElement(mainGame->wCreateHost);
mainGame->WaitFrameSignal(10);
CTOS_CreateGame cscg;
const wchar_t* phstr = mainGame->ebServerName->getText();
int i = 0;
while(i < 19 && phstr[i])
cscg.name[i] = phstr[i++];
cscg.name[i] = 0;
phstr = mainGame->ebServerPass->getText();
i = 0;
while(i < 19 && phstr[i])
cscg.pass[i] = phstr[i++];
cscg.pass[i] = 0;
cscg.info.rule = mainGame->cbRule->getSelected();
cscg.info.mode = mainGame->cbMatchMode->getSelected();
cscg.info.start_hand = _wtoi(mainGame->ebStartHand->getText());
cscg.info.start_lp = _wtoi(mainGame->ebStartLP->getText());
cscg.info.draw_count = _wtoi(mainGame->ebDrawCount->getText());
cscg.info.lflist = mainGame->cbLFlist->getItemData(mainGame->cbLFlist->getSelected());
cscg.info.no_check_deck = mainGame->chkNoCheckDeck->isChecked();
cscg.info.no_shuffle_deck = mainGame->chkNoShuffleDeck->isChecked();
SendPacketToServer(CTOS_CREATE_GAME, cscg);
connect_state = 2; connect_state = 2;
} else if (events & BEV_EVENT_ERROR) { } else if (events & BEV_EVENT_ERROR) {
mainGame->env->addMessageBox(L"", L"无法连接到主机。");
mainGame->btnCreateHost->setEnabled(true);
mainGame->btnJoinHost->setEnabled(true);
mainGame->btnJoinCancel->setEnabled(true);
event_base_loopexit(client_base, NULL);
} }
} }
int DuelClient::ClientThread(void* param) { int DuelClient::ClientThread(void* param) {
event_base* evbase = (event_base*)param; event_base_dispatch(client_base);
event_base_dispatch(evbase); event_base_free(client_base);
event_base_loopexit(evbase, NULL); bufferevent_free(client_bev);
client_base = 0;
connect_state = 0; connect_state = 0;
} }
void DuelClient::HandleSTOCPacket(char* data, unsigned int len) { void DuelClient::HandleSTOCPacket(char* data, unsigned int len) {
char* pdata = data;
unsigned char pktType = BufferIO::ReadUInt8(pdata);
switch(pktType) {
case STOC_JOIN_GAME: {
STOC_JoinGame* pkt = (STOC_JoinGame*)pdata;
mainGame->ShowElement(mainGame->wHostSingle);
mainGame->WaitFrameSignal(10);
break;
}
case STOC_JOIN_FAIL: {
STOC_JoinFail* pkt = (STOC_JoinFail*)pdata;
if(pkt->reason == 0)
mainGame->env->addMessageBox(L"", L"无法加入主机。");
else if(pkt->reason == 1)
mainGame->env->addMessageBox(L"", L"密码错误。");
else if(pkt->reason == 2)
mainGame->env->addMessageBox(L"", L"主机拒绝了连接。");
mainGame->btnCreateHost->setEnabled(true);
mainGame->btnJoinHost->setEnabled(true);
mainGame->btnJoinCancel->setEnabled(true);
break;
}
case STOC_HS_PLAYER_ENTER:
break;
case STOC_HS_PLAYER_CHANGE:
break;
case STOC_HS_WATCH_CHANGE:
break;
}
} }
void DuelClient::SetResponseI(int respI) { void DuelClient::SetResponseI(int respI) {
responseI = respI; responseI = respI;
......
...@@ -20,14 +20,35 @@ private: ...@@ -20,14 +20,35 @@ private:
static unsigned char responseB[64]; static unsigned char responseB[64];
static bool is_responseB; static bool is_responseB;
static unsigned char response_len; static unsigned char response_len;
static event_base* client_base;
static bufferevent* client_bev;
static char duel_client_read[0x2000];
static char duel_client_write[0x2000];
static bool is_host;
public: public:
static bool StartClient(unsigned int ip, unsigned short port); static bool StartClient(unsigned int ip, unsigned short port);
static void StopClient();
static void ClientRead(bufferevent* bev, void* ctx); static void ClientRead(bufferevent* bev, void* ctx);
static void ClientEvent(bufferevent *bev, short events, void *ptr); static void ClientEvent(bufferevent *bev, short events, void *ptr);
static int ClientThread(void* param); static int ClientThread(void* param);
static void HandleSTOCPacket(char* data, unsigned int len); static void HandleSTOCPacket(char* data, unsigned int len);
static void SetResponseI(int respI); static void SetResponseI(int respI);
static void SetResponseB(unsigned char* respB, unsigned char len); static void SetResponseB(unsigned char* respB, unsigned char len);
template<typename ST>
static void SendPacketToServer(unsigned char proto, ST& st) {
char* p = duel_client_write;
BufferIO::WriteInt16(p, 1 + sizeof(ST));
BufferIO::WriteInt8(p, proto);
memcpy(p, &st, sizeof(ST));
evbuffer_add(bufferevent_get_output(client_bev), duel_client_write, sizeof(ST) + 3);
}
static void SendBufferToServer(unsigned char proto, void* buffer, size_t len) {
char* p = duel_client_write;
BufferIO::WriteInt16(p, 1 + len);
BufferIO::WriteInt8(p, proto);
memcpy(p, buffer, len);
evbuffer_add(bufferevent_get_output(client_bev), duel_client_write, len + 3);
}
}; };
} }
......
...@@ -100,7 +100,7 @@ bool Game::Initialize() { ...@@ -100,7 +100,7 @@ bool Game::Initialize() {
env->addStaticText(dataManager.GetSysString(1226), rect<s32>(20, 60, 220, 80), false, false, wCreateHost); env->addStaticText(dataManager.GetSysString(1226), rect<s32>(20, 60, 220, 80), false, false, wCreateHost);
cbLFlist = env->addComboBox(rect<s32>(140, 55, 300, 80), wCreateHost); cbLFlist = env->addComboBox(rect<s32>(140, 55, 300, 80), wCreateHost);
for(int i = 0; i < deckManager._lfList.size(); ++i) for(int i = 0; i < deckManager._lfList.size(); ++i)
cbLFlist->addItem(deckManager._lfList[i].listName); cbLFlist->addItem(deckManager._lfList[i].listName, deckManager._lfList[i].hash);
env->addStaticText(dataManager.GetSysString(1227), rect<s32>(20, 90, 220, 110), false, false, wCreateHost); env->addStaticText(dataManager.GetSysString(1227), rect<s32>(20, 90, 220, 110), false, false, wCreateHost);
cbMatchMode = env->addComboBox(rect<s32>(140, 85, 300, 110), wCreateHost); cbMatchMode = env->addComboBox(rect<s32>(140, 85, 300, 110), wCreateHost);
cbMatchMode->addItem(dataManager.GetSysString(1244)); cbMatchMode->addItem(dataManager.GetSysString(1244));
......
#include "config.h" #include "config.h"
#include "menu_handler.h" #include "menu_handler.h"
#include "netserver.h"
#include "duelclient.h"
#include "game.h" #include "game.h"
namespace ygo { namespace ygo {
...@@ -21,6 +23,9 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -21,6 +23,9 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break; break;
} }
case BUTTON_JOIN_HOST: { case BUTTON_JOIN_HOST: {
mainGame->btnCreateHost->setEnabled(false);
mainGame->btnJoinHost->setEnabled(false);
mainGame->btnJoinCancel->setEnabled(false);
break; break;
} }
case BUTTON_JOIN_CANCEL: { case BUTTON_JOIN_CANCEL: {
...@@ -28,11 +33,20 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) { ...@@ -28,11 +33,20 @@ bool MenuHandler::OnEvent(const irr::SEvent& event) {
break; break;
} }
case BUTTON_CREATE_HOST: { case BUTTON_CREATE_HOST: {
mainGame->btnHostConfirm->setEnabled(true);
mainGame->btnHostCancel->setEnabled(true);
mainGame->HideElement(mainGame->wLanWindow, false, mainGame->wCreateHost); mainGame->HideElement(mainGame->wLanWindow, false, mainGame->wCreateHost);
break; break;
} }
case BUTTON_HOST_CONFIRM: { case BUTTON_HOST_CONFIRM: {
mainGame->HideElement(mainGame->wCreateHost, false, mainGame->wHostSingle); if(NetServer::StartServer(mainGame->gameConf.serverport))
break;
if(!DuelClient::StartClient(0x7f000001, mainGame->gameConf.serverport)) {
NetServer::StopServer();
break;
}
mainGame->btnHostConfirm->setEnabled(false);
mainGame->btnHostCancel->setEnabled(false);
break; break;
} }
case BUTTON_HOST_CANCEL: { case BUTTON_HOST_CANCEL: {
......
...@@ -44,7 +44,8 @@ void NetServer::ServerAccept(evconnlistener* listener, evutil_socket_t fd, socka ...@@ -44,7 +44,8 @@ void NetServer::ServerAccept(evconnlistener* listener, evutil_socket_t fd, socka
bufferevent* bev = bufferevent_socket_new(net_evbase, fd, BEV_OPT_CLOSE_ON_FREE); bufferevent* bev = bufferevent_socket_new(net_evbase, fd, BEV_OPT_CLOSE_ON_FREE);
DuelPlayer dp; DuelPlayer dp;
dp.name[0] = 0; dp.name[0] = 0;
dp.output = bufferevent_get_output(bev); dp.type = 0xff;
dp.bev = bev;
users[bev] = dp; users[bev] = dp;
bufferevent_setcb(bev, ServerEchoRead, NULL, ServerEchoEvent, NULL); bufferevent_setcb(bev, ServerEchoRead, NULL, ServerEchoEvent, NULL);
bufferevent_enable(bev, EV_READ | EV_WRITE); bufferevent_enable(bev, EV_READ | EV_WRITE);
...@@ -77,9 +78,18 @@ void NetServer::ServerEchoEvent(bufferevent* bev, short events, void* ctx) { ...@@ -77,9 +78,18 @@ void NetServer::ServerEchoEvent(bufferevent* bev, short events, void* ctx) {
int NetServer::ServerThread(void* param) { int NetServer::ServerThread(void* param) {
event_base_dispatch(net_evbase); event_base_dispatch(net_evbase);
event_base_free(net_evbase); event_base_free(net_evbase);
for(auto bit = users.begin(); bit != users.end(); ++bit)
bufferevent_free(bit->first);
net_evbase = 0; net_evbase = 0;
return 0; return 0;
} }
void NetServer::DisconnectPlayer(DuelPlayer* dp) {
auto bit = users.find(dp->bev);
if(bit != users.end()) {
users.erase(bit);
bufferevent_free(dp->bev);
}
}
void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) { void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) {
char* pdata = data; char* pdata = data;
unsigned char pktType = BufferIO::ReadUInt8(pdata); unsigned char pktType = BufferIO::ReadUInt8(pdata);
...@@ -106,12 +116,30 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) { ...@@ -106,12 +116,30 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) {
duel_mode = new MatchDuel; duel_mode = new MatchDuel;
} }
duel_mode->host_info = pkt->info; duel_mode->host_info = pkt->info;
for(int i = 0; i < 20; ++i) {
duel_mode->name[i] = pkt->name[i];
duel_mode->pass[i] = pkt->pass[i];
}
} }
case CTOS_JOIN_GAME: { case CTOS_JOIN_GAME: {
if(dp->game) if(pktType != CTOS_CREATE_GAME) {
return; if((dp->game && dp->type != 0xff) || !duel_mode) {
if(!duel_mode) STOC_JoinFail scjf;
return; scjf.reason = 0;
SendPacketToPlayer(dp, STOC_JOIN_FAIL, scjf);
break;
}
CTOS_JoinGame* pkt = (CTOS_JoinGame*)pdata;
wchar_t jpass[20];
for(int i = 0; i < 20; ++i) jpass[i] = pkt->pass[i];
jpass[20] = 0;
if(wcscmp(jpass, duel_mode->pass)) {
STOC_JoinFail scjf;
scjf.reason = 1;
SendPacketToPlayer(dp, STOC_JOIN_FAIL, scjf);
break;
}
}
dp->game = duel_mode; dp->game = duel_mode;
if(!duel_mode->players[0] && !duel_mode->players[1] && duel_mode->observers.size() == 0) if(!duel_mode->players[0] && !duel_mode->players[1] && duel_mode->observers.size() == 0)
duel_mode->host_player = dp; duel_mode->host_player = dp;
...@@ -141,14 +169,14 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) { ...@@ -141,14 +169,14 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) {
duel_mode->observers.insert(dp); duel_mode->observers.insert(dp);
dp->type = NETPLAYER_TYPE_OBSERVER; dp->type = NETPLAYER_TYPE_OBSERVER;
scjg.type |= NETPLAYER_TYPE_OBSERVER; scjg.type |= NETPLAYER_TYPE_OBSERVER;
STOC_HS_ReadyChange scrc; STOC_HS_WatchChange scwc;
scrc.ready = duel_mode->observers.size(); scwc.watch_count = duel_mode->observers.size();
if(duel_mode->players[0]) if(duel_mode->players[0])
NetServer::SendPacketToPlayer(duel_mode->players[0], STOC_HS_READY_CHANGE, scrc); NetServer::SendPacketToPlayer(duel_mode->players[0], STOC_HS_WATCH_CHANGE, scwc);
if(duel_mode->players[1]) if(duel_mode->players[1])
NetServer::SendPacketToPlayer(duel_mode->players[1], STOC_HS_READY_CHANGE, scrc); NetServer::SendPacketToPlayer(duel_mode->players[1], STOC_HS_WATCH_CHANGE, scwc);
for(auto pit = duel_mode->observers.begin(); pit != duel_mode->observers.end(); ++pit) for(auto pit = duel_mode->observers.begin(); pit != duel_mode->observers.end(); ++pit)
NetServer::SendPacketToPlayer(*pit, STOC_HS_READY_CHANGE, scrc); NetServer::SendPacketToPlayer(*pit, STOC_HS_WATCH_CHANGE, scwc);
} }
NetServer::SendPacketToPlayer(dp, STOC_JOIN_GAME, scjg); NetServer::SendPacketToPlayer(dp, STOC_JOIN_GAME, scjg);
if(duel_mode->players[0]) { if(duel_mode->players[0]) {
...@@ -174,9 +202,9 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) { ...@@ -174,9 +202,9 @@ void NetServer::HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len) {
} }
} }
if(duel_mode->observers.size()) { if(duel_mode->observers.size()) {
STOC_HS_ReadyChange scrc; STOC_HS_WatchChange scwc;
scrc.ready = duel_mode->observers.size(); scwc.watch_count = duel_mode->observers.size();
NetServer::SendPacketToPlayer(dp, STOC_HS_READY_CHANGE, scrc); NetServer::SendPacketToPlayer(dp, STOC_HS_WATCH_CHANGE, scwc);
} }
break; break;
} }
......
...@@ -23,14 +23,12 @@ struct DuelPlayer { ...@@ -23,14 +23,12 @@ struct DuelPlayer {
DuelMode* game; DuelMode* game;
unsigned char type; unsigned char type;
unsigned char state; unsigned char state;
unsigned int uid; bufferevent* bev;
evbuffer* output;
DuelPlayer() { DuelPlayer() {
uid = 0;
game = 0; game = 0;
type = 0; type = 0;
state = 0; state = 0;
output = 0; bev = 0;
} }
}; };
...@@ -56,6 +54,8 @@ public: ...@@ -56,6 +54,8 @@ public:
DuelPlayer* host_player; DuelPlayer* host_player;
HostInfo host_info; HostInfo host_info;
unsigned long pduel; unsigned long pduel;
wchar_t name[20];
wchar_t pass[20];
}; };
class NetServer { class NetServer {
...@@ -75,6 +75,7 @@ public: ...@@ -75,6 +75,7 @@ public:
static void ServerEchoRead(bufferevent* bev, void* ctx); static void ServerEchoRead(bufferevent* bev, void* ctx);
static void ServerEchoEvent(bufferevent* bev, short events, void* ctx); static void ServerEchoEvent(bufferevent* bev, short events, void* ctx);
static int ServerThread(void* param); static int ServerThread(void* param);
static void DisconnectPlayer(DuelPlayer* dp);
static void HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len); static void HandleCTOSPacket(DuelPlayer* dp, char* data, unsigned int len);
template<typename ST> template<typename ST>
static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, ST& st) { static void SendPacketToPlayer(DuelPlayer* dp, unsigned char proto, ST& st) {
...@@ -83,7 +84,7 @@ public: ...@@ -83,7 +84,7 @@ public:
BufferIO::WriteInt8(p, proto); BufferIO::WriteInt8(p, proto);
memcpy(p, &st, sizeof(ST)); memcpy(p, &st, sizeof(ST));
last_sent = sizeof(ST) + 3; last_sent = sizeof(ST) + 3;
evbuffer_add(dp->output, net_server_write, last_sent); evbuffer_add(bufferevent_get_output(dp->bev), net_server_write, last_sent);
} }
static void SendBufferToPlayer(DuelPlayer* dp, unsigned char proto, void* buffer, size_t len) { static void SendBufferToPlayer(DuelPlayer* dp, unsigned char proto, void* buffer, size_t len) {
char* p = net_server_write; char* p = net_server_write;
...@@ -91,10 +92,10 @@ public: ...@@ -91,10 +92,10 @@ public:
BufferIO::WriteInt8(p, proto); BufferIO::WriteInt8(p, proto);
memcpy(p, buffer, len); memcpy(p, buffer, len);
last_sent = len + 3; last_sent = len + 3;
evbuffer_add(dp->output, net_server_write, last_sent); evbuffer_add(bufferevent_get_output(dp->bev), net_server_write, last_sent);
} }
static void ReSendToPlayer(DuelPlayer* dp) { static void ReSendToPlayer(DuelPlayer* dp) {
evbuffer_add(dp->output, net_server_write, last_sent); evbuffer_add(bufferevent_get_output(dp->bev), net_server_write, last_sent);
} }
}; };
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
namespace ygo { namespace ygo {
struct HostInfo { struct HostInfo {
unsigned short name[20];
unsigned char rule; unsigned char rule;
unsigned char mode; unsigned char mode;
unsigned int lflist; unsigned int lflist;
...@@ -40,11 +39,13 @@ struct CTOS_PlayerInfo { ...@@ -40,11 +39,13 @@ struct CTOS_PlayerInfo {
}; };
struct CTOS_CreateGame { struct CTOS_CreateGame {
HostInfo info; HostInfo info;
unsigned short name[20];
unsigned short pass[20];
}; };
struct CTOS_JoinGame { struct CTOS_JoinGame {
unsigned int gameid; unsigned int gameid;
unsigned short pass[20];
}; };
struct STOC_CreateGame { struct STOC_CreateGame {
unsigned int gameid; unsigned int gameid;
}; };
...@@ -54,15 +55,18 @@ struct STOC_JoinGame { ...@@ -54,15 +55,18 @@ struct STOC_JoinGame {
}; };
struct STOC_ExitGame { struct STOC_ExitGame {
}; };
struct STOC_JoinFail {
//0 - common error
//1 - password incorrect
//2 - host denied
unsigned int reason;
};
struct STOC_HS_PlayerEnter { struct STOC_HS_PlayerEnter {
unsigned short name[20]; unsigned short name[20];
}; };
struct STOC_HS_PlayerChange { struct STOC_HS_PlayerChange {
unsigned char status; unsigned char status;
}; };
struct STOC_HS_ReadyChange {
unsigned char ready;
};
struct STOC_HS_WatchChange { struct STOC_HS_WatchChange {
unsigned short watch_count; unsigned short watch_count;
}; };
...@@ -90,10 +94,10 @@ extern const unsigned short PROTO_VERSION; ...@@ -90,10 +94,10 @@ extern const unsigned short PROTO_VERSION;
#define STOC_CREATE_GAME 0x11 #define STOC_CREATE_GAME 0x11
#define STOC_JOIN_GAME 0x12 #define STOC_JOIN_GAME 0x12
#define STOC_EXIT_GAME 0x13 #define STOC_EXIT_GAME 0x13
#define STOC_JOIN_FAIL 0x14
#define STOC_HS_PLAYER_ENTER 0x20 #define STOC_HS_PLAYER_ENTER 0x20
#define STOC_HS_PLAYER_CHANGE 0x21 #define STOC_HS_PLAYER_CHANGE 0x21
#define STOC_HS_READY_CHANGE 0x22 #define STOC_HS_WATCH_CHANGE 0x22
#define STOC_HS_WATCH_CHANGE 0x23
#define PLAYERCHANGE_READY 0x1 #define PLAYERCHANGE_READY 0x1
#define PLAYERCHANGE_NOTREADY 0x2 #define PLAYERCHANGE_NOTREADY 0x2
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment