You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1524 lines
43 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
/*****************************************************************************
*
* $/Plasma20/Sources/Plasma/PubUtilLib/plNetClientComm/plNetClientComm.cpp
*
***/
#include "plNetClientComm.h"
#include "pnAsyncCore/pnAsyncCore.h"
#include "pnProduct/pnProduct.h"
#include "pnNetCli/pnNetCli.h"
#include "plNetGameLib/plNetGameLib.h"
#include "pnIni/pnIni.h"
#include "plMessage/plNetCommMsgs.h"
#include "plMessage/plNetClientMgrMsg.h"
#include "plNetMessage/plNetMessage.h"
#include "plNetCommon/plNetCommon.h"
#include "plVault/plVault.h"
#include "plMessage/plAccountUpdateMsg.h"
#include "plNetClient/plNetClientMgr.h"
#include "pfMessage/pfKIMsg.h"
#include "hsResMgr.h"
#include <malloc.h>
extern hsBool gDataServerLocal;
/*****************************************************************************
*
* Exported data
*
***/
const unsigned kNetCommAllMsgClasses = (unsigned)-1;
FNetCommMsgHandler * kNetCommAllMsgHandlers = (FNetCommMsgHandler*)-1;
const void * kNetCommAllUserStates = (void*)-1;
struct NetCommParam {
void * param;
plNetCommReplyMsg::EParamType type;
};
/*****************************************************************************
*
* Private
*
***/
/*****************************************************************************
*
* Private data
*
***/
static bool s_shutdown;
static NetCommAccount s_account;
static ARRAY(NetCommPlayer) s_players;
static NetCommPlayer * s_player;
static NetCommAge s_age;
static NetCommAge s_startupAge;
static bool s_needAvatarLoad = true;
static bool s_loginComplete = false;
static bool s_hasFileSrvIpAddress = false;
static ENetError s_authResult = kNetErrAuthenticationFailed;
static wchar s_fileSrvAddr[256];
static wchar s_iniServerAddr[256];
static wchar s_iniFileServerAddr[256];
static wchar s_iniAccountUsername[kMaxAccountNameLength];
static ShaDigest s_namePassHash;
static wchar s_iniAuthToken[kMaxPublisherAuthKeyLength];
static wchar s_iniOS[kMaxGTOSIdLength];
static bool s_iniReadAccountInfo = true;
static wchar s_iniStartupAgeName[kMaxAgeNameLength];
static Uuid s_iniStartupAgeInstId;
static wchar s_iniStartupPlayerName[kMaxPlayerNameLength];
static bool s_netError = false;
struct NetCommMsgHandler : THashKeyVal<unsigned> {
HASHLINK(NetCommMsgHandler) link;
FNetCommMsgHandler * proc;
void * state;
NetCommMsgHandler (
unsigned msgId,
FNetCommMsgHandler * proc,
void * state
) : THashKeyVal<unsigned>(msgId)
, proc(proc)
, state(state)
{ }
};
static HASHTABLEDECL(
NetCommMsgHandler,
THashKeyVal<unsigned>,
link
) s_handlers;
static NetCommMsgHandler s_defaultHandler(0, nil, nil);
static NetCommMsgHandler s_preHandler(0, nil, nil);
//============================================================================
static void INetLogCallback (
ELogSeverity severity,
const wchar msg[]
) {
// Use the async log facility
AsyncLogWriteMsg(ProductShortName(), severity, msg);
}
//============================================================================
static void INetErrorCallback (
ENetProtocol protocol,
ENetError error
) {
NetClientDestroy(false);
plNetClientMgrMsg * msg = NEWZERO(plNetClientMgrMsg);
msg->type = plNetClientMgrMsg::kCmdDisableNet;
msg->yes = true;
msg->AddReceiver(plNetClientApp::GetInstance()->GetKey());
switch (error)
{
case kNetErrKickedByCCR:
StrPrintf(
msg->str,
arrsize(msg->str),
"You have been kicked by a CCR."
);
break;
default:
// Until we get some real error handling, this'll ensure no errors
// fall thru the cracks and we hang forever wondering what's up.
StrPrintf(
// buf
msg->str,
arrsize(msg->str),
// fmt
"Network error %u, %S.\n"
"protocol: %S\n"
,// values
error,
NetErrorToString(error),
NetProtocolToString(protocol)
);
s_netError = true;
}
msg->Send();
}
//============================================================================
static void IPreInitNetErrorCallback (
ENetProtocol protocol,
ENetError error
) {
s_authResult = error;
s_loginComplete = true;
}
//============================================================================
static void INetBufferCallback (
unsigned type,
unsigned bytes,
const byte buffer[]
) {
if (!plFactory::IsValidClassIndex(type)) {
LogMsg(kLogError, "NetComm: received junk propagated buffer");
return;
}
plNetMessage * msg = plNetMessage::ConvertNoRef(plFactory::Create(type));
if (!msg) {
LogMsg(kLogError, "NetComm: could not convert plNetMessage to class %u", type);
return;
}
if (!msg->PeekBuffer((const char *)buffer, bytes)) {
LogMsg(kLogError, "NetComm: plNetMessage %u failed to peek buffer", type);
return;
}
NetCommRecvMsg(msg);
msg->UnRef();
}
//============================================================================
static void INotifyNewBuildCallback () {
if (!hsgResMgr::ResMgr())
return;
if (!NetCommGetPlayer())
return;
if (!NetCommGetPlayer()->playerInt)
return;
if (!NetCommGetAge())
return;
if (!NetCommGetAge()->ageInstId)
return;
pfKIMsg * msg = NEW(pfKIMsg)(pfKIMsg::kHACKChatMsg);
msg->SetString("Uru has been updated. Please quit the game and log back in.");
msg->SetUser("Updater Service", plNetClientApp::GetInstance()->GetPlayerID());
msg->SetFlags(pfKIMsg::kAdminMsg);
msg->SetBCastFlag(plMessage::kNetPropagate | plMessage::kNetForce, 0);
msg->SetBCastFlag(plMessage::kLocalPropagate, 1);
msg->Send();
}
//============================================================================
static void INotifyAuthConnectedCallback () {
if (!hsgResMgr::ResMgr())
return;
plNetCommAuthConnectedMsg * msg = NEWZERO(plNetCommAuthConnectedMsg);
msg->Send();
}
//============================================================================
static void PlayerInitCallback (
ENetError result,
void * param
) {
if (IS_NET_ERROR(result) && (result != kNetErrVaultNodeNotFound)) {
s_player = nil;
}
else {
// Ensure the city link has the required spawn points
plAgeInfoStruct info;
info.SetAgeFilename(kCityAgeFilename);
if (RelVaultNode * rvn = VaultGetOwnedAgeLinkIncRef(&info)) {
VaultAgeLinkNode acc(rvn);
acc.AddSpawnPoint(plSpawnPointInfo(kCityFerryTerminalLinkTitle, kCityFerryTerminalLinkSpawnPtName));
rvn->DecRef();
}
VaultProcessPlayerInbox();
}
plNetCommActivePlayerMsg * msg = NEW(plNetCommActivePlayerMsg);
msg->result = result;
msg->param = param;
msg->Send();
plAccountUpdateMsg * updateMsg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kActivePlayer);
updateMsg->SetPlayerInt(NetCommGetPlayer()->playerInt);
updateMsg->SetResult((unsigned)result);
updateMsg->SetBCastFlag(plMessage::kBCastByExactType);
updateMsg->Send();
}
//============================================================================
static void INetCliAuthSetPlayerRequestCallback (
ENetError result,
void * param
) {
if (!s_player) {
PlayerInitCallback(result, param);
}
else if (IS_NET_ERROR(result) && (result != kNetErrVaultNodeNotFound)) {
s_player = nil;
PlayerInitCallback(result, param);
}
else {
s_needAvatarLoad = true;
VaultDownload(
L"SetActivePlayer",
s_player->playerInt,
PlayerInitCallback,
param,
nil,
nil
);
}
}
//============================================================================
static void LoginPlayerInitCallback (
ENetError result,
void * param
) {
if (IS_NET_ERROR(result) && (result != kNetErrVaultNodeNotFound))
s_player = nil;
else
VaultProcessPlayerInbox();
{
plNetCommAuthMsg * msg = NEW(plNetCommAuthMsg);
msg->result = result;
msg->param = param;
msg->Send();
}
{
plNetCommActivePlayerMsg * msg = NEW(plNetCommActivePlayerMsg);
msg->result = result;
msg->param = param;
msg->Send();
}
{
plAccountUpdateMsg * msg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kActivePlayer);
msg->SetPlayerInt(NetCommGetPlayer()->playerInt);
msg->SetResult((unsigned)result);
msg->SetBCastFlag(plMessage::kBCastByExactType);
msg->Send();
}
}
//============================================================================
static void INetCliAuthLoginSetPlayerRequestCallback (
ENetError result,
void * param
) {
if (IS_NET_ERROR(result) && (result != kNetErrVaultNodeNotFound)) {
s_player = nil;
plNetCommAuthMsg * msg = NEW(plNetCommAuthMsg);
msg->result = result;
msg->param = param;
msg->Send();
}
else {
VaultDownload(
L"SetActivePlayer",
s_player->playerInt,
LoginPlayerInitCallback,
param,
nil,
nil
);
}
}
//============================================================================
static void INetCliAuthLoginRequestCallback (
ENetError result,
void * param,
const Uuid & accountUuid,
unsigned accountFlags,
unsigned billingType,
const NetCliAuthPlayerInfo playerInfoArr[],
unsigned playerCount
) {
s_authResult = result;
s_player = nil;
s_players.Clear();
bool wantsStartUpAge = (
!StrLen(s_startupAge.ageDatasetName) ||
0 == StrCmpI(s_startupAge.ageDatasetName, "StartUp")
);
s_loginComplete = true;
if (!IS_NET_ERROR(result) || result == kNetErrVaultNodeNotFound) {
s_account.accountUuid = accountUuid;
s_account.accountFlags = accountFlags;
s_account.billingType = billingType;
s_players.GrowToCount(playerCount, true);
for (unsigned i = 0; i < playerCount; ++i) {
LogMsg(kLogDebug, L"Player %u: %s explorer: %u", playerInfoArr[i].playerInt, playerInfoArr[i].playerName, playerInfoArr[i].explorer);
s_players[i].playerInt = playerInfoArr[i].playerInt;
s_players[i].explorer = playerInfoArr[i].explorer;
StrCopy(s_players[i].playerName, playerInfoArr[i].playerName, arrsize(s_players[i].playerName));
StrToAnsi(s_players[i].playerNameAnsi, playerInfoArr[i].playerName, arrsize(s_players[i].playerNameAnsi));
StrToAnsi(s_players[i].avatarDatasetName, playerInfoArr[i].avatarShape, arrsize(s_players[i].avatarDatasetName));
if (!wantsStartUpAge && 0 == StrCmpI(s_players[i].playerName, s_iniStartupPlayerName, (unsigned)-1))
s_player = &s_players[i];
}
}
else
s_account.accountUuid = kNilGuid;
// If they specified an alternate age, but we couldn't find the player, force
// the StartUp age to load so that they may select/create a player first.
if (!wantsStartUpAge && !s_player)
StrCopy(s_startupAge.ageDatasetName, "StartUp", arrsize(s_startupAge.ageDatasetName));
// If they specified an alternate age, and we found the player, set the active player now
// so that the link operation will be successful once the client is finished initializing.
if (!wantsStartUpAge && s_player) {
NetCliAuthSetPlayerRequest(
s_player->playerInt,
INetCliAuthLoginSetPlayerRequestCallback,
param
);
}
}
//============================================================================
static void INetCliAuthCreatePlayerRequestCallback (
ENetError result,
void * param,
const NetCliAuthPlayerInfo & playerInfo
) {
if (IS_NET_ERROR(result)) {
LogMsg(kLogDebug, L"Create player failed: %s", NetErrorToString(result));
}
else {
LogMsg(kLogDebug, L"Created player %s: %u", playerInfo.playerName, playerInfo.playerInt);
unsigned currPlayer = s_player ? s_player->playerInt : 0;
NetCommPlayer * newPlayer = s_players.New();
newPlayer->playerInt = playerInfo.playerInt;
newPlayer->explorer = playerInfo.explorer;
StrCopy(newPlayer->playerName, playerInfo.playerName, arrsize(newPlayer->playerName));
StrToAnsi(newPlayer->playerNameAnsi, playerInfo.playerName, arrsize(newPlayer->playerNameAnsi));
StrToAnsi(newPlayer->avatarDatasetName, playerInfo.avatarShape, arrsize(newPlayer->avatarDatasetName));
{ for (unsigned i = 0; i < s_players.Count(); ++i) {
if (s_players[i].playerInt == currPlayer) {
s_player = &s_players[i];
break;
}
}}
}
plAccountUpdateMsg* updateMsg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kCreatePlayer);
updateMsg->SetPlayerInt(playerInfo.playerInt);
updateMsg->SetResult((unsigned)result);
updateMsg->SetBCastFlag(plMessage::kBCastByExactType);
updateMsg->Send();
}
//============================================================================
static void INetCliAuthDeletePlayerCallback (
ENetError result,
void * param
) {
unsigned playerInt = (unsigned)param;
if (IS_NET_ERROR(result)) {
LogMsg(kLogDebug, L"Delete player failed: %d %s", playerInt, NetErrorToString(result));
}
else {
LogMsg(kLogDebug, L"Player deleted: %d", playerInt);
unsigned currPlayer = s_player ? s_player->playerInt : 0;
{for (unsigned i = 0; i < s_players.Count(); ++i) {
if (s_players[i].playerInt == playerInt) {
s_players.DeleteUnordered(i);
break;
}
}}
{for (unsigned i = 0; i < s_players.Count(); ++i) {
if (s_players[i].playerInt == currPlayer) {
s_player = &s_players[i];
break;
}
}}
}
plAccountUpdateMsg* updateMsg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kDeletePlayer);
updateMsg->SetPlayerInt(playerInt);
updateMsg->SetResult((unsigned)result);
updateMsg->SetBCastFlag(plMessage::kBCastByExactType);
updateMsg->Send();
}
//============================================================================
static void INetCliAuthChangePasswordCallback (
ENetError result,
void * param
) {
if (IS_NET_ERROR(result)) {
LogMsg(kLogDebug, L"Change password failed: %s", NetErrorToString(result));
}
else {
LogMsg(kLogDebug, L"Password changed!");
}
plAccountUpdateMsg* updateMsg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kChangePassword);
updateMsg->SetPlayerInt(0);
updateMsg->SetResult((unsigned)result);
updateMsg->SetBCastFlag(plMessage::kBCastByExactType);
updateMsg->Send();
}
//============================================================================
static void INetCliAuthGetPublicAgeListCallback (
ENetError result,
void * param,
const ARRAY(NetAgeInfo) & ages
) {
NetCommParam * cp = (NetCommParam *) param;
plNetCommPublicAgeListMsg * msg = NEWZERO(plNetCommPublicAgeListMsg);
msg->result = result;
msg->param = cp->param;
msg->ptype = cp->type;
msg->ages.Set(ages.Ptr(), ages.Count());
msg->Send();
DEL(cp);
}
//============================================================================
static void INetAuthFileListRequestCallback (
ENetError result,
void * param,
const NetCliAuthFileInfo infoArr[],
unsigned infoCount
) {
plNetCommFileListMsg * msg = NEW(plNetCommFileListMsg);
msg->result = result;
msg->param = param;
msg->fileInfoArr.Set(infoArr, infoCount);
msg->Send();
}
//============================================================================
static void INetCliAuthFileRequestCallback (
ENetError result,
void * param,
const wchar filename[],
hsStream * writer
) {
plNetCommFileDownloadMsg * msg = NEW(plNetCommFileDownloadMsg);
msg->result = result;
msg->writer = writer;
StrCopy(msg->filename, filename, arrsize(filename));
msg->Send();
}
//============================================================================
static void INetCliGameJoinAgeRequestCallback (
ENetError result,
void * param
) {
plNetCommLinkToAgeMsg * msg = NEW(plNetCommLinkToAgeMsg);
msg->result = result;
msg->param = param;
msg->Send();
}
//============================================================================
static void INetCliAuthAgeRequestCallback (
ENetError result,
void * param,
unsigned ageMcpId,
unsigned ageVaultId,
const Uuid & ageInstId,
NetAddressNode gameAddr
) {
if (!IS_NET_ERROR(result) || result == kNetErrVaultNodeNotFound) {
s_age.ageInstId = ageInstId;
s_age.ageVaultId = ageVaultId;
wchar gameAddrStr[64];
wchar ageInstIdStr[64];
NetAddressNodeToString(gameAddr, gameAddrStr, arrsize(gameAddrStr));
LogMsg(
kLogPerf,
L"Connecting to game server %s, ageInstId %s",
gameAddrStr,
GuidToString(ageInstId, ageInstIdStr, arrsize(ageInstIdStr))
);
NetCliGameDisconnect();
NetCliGameStartConnect(gameAddr);
NetCliGameJoinAgeRequest(
ageMcpId,
s_account.accountUuid,
s_player->playerInt,
INetCliGameJoinAgeRequestCallback,
param
);
}
else {
INetCliGameJoinAgeRequestCallback(
result,
param
);
}
}
//============================================================================
static void INetCliAuthUpgradeVisitorRequestCallback (
ENetError result,
void * param
) {
unsigned playerInt = (unsigned)param;
if (IS_NET_ERROR(result)) {
LogMsg(kLogDebug, L"Upgrade visitor failed: %d %s", playerInt, NetErrorToString(result));
}
else {
LogMsg(kLogDebug, L"Upgrade visitor succeeded: %d", playerInt);
{for (unsigned i = 0; i < s_players.Count(); ++i) {
if (s_players[i].playerInt == playerInt) {
s_players[i].explorer = true;
break;
}
}}
}
plAccountUpdateMsg* updateMsg = TRACKED_NEW plAccountUpdateMsg(plAccountUpdateMsg::kUpgradePlayer);
updateMsg->SetPlayerInt(playerInt);
updateMsg->SetResult((unsigned)result);
updateMsg->SetBCastFlag(plMessage::kBCastByExactType);
updateMsg->Send();
}
//============================================================================
static void INetCliAuthSendFriendInviteCallback (
ENetError result,
void * param
) {
pfKIMsg* kiMsg = TRACKED_NEW pfKIMsg(pfKIMsg::kFriendInviteSent);
kiMsg->SetIntValue((Int32)result);
kiMsg->Send();
}
//============================================================================
static void IReadNetIni() {
wchar filename[MAX_PATH];
StrPrintf(filename, arrsize(filename), L"%s.cfg", ProductCoreName());
wchar pathAndName[MAX_PATH];
PathGetInitDirectory(pathAndName, arrsize(pathAndName));
PathAddFilename(pathAndName, pathAndName, filename, arrsize(pathAndName));
#ifndef PLASMA_EXTERNAL_RELEASE
// internal dev build will override user-based setting with local folder if it's there
wchar localPathAndName[MAX_PATH];
PathAddFilename(localPathAndName, L"init", filename, arrsize(localPathAndName));
if (PathDoesFileExist(localPathAndName))
StrCopy(pathAndName, localPathAndName, arrsize(pathAndName));
#endif
Ini * ini = IniOpen(pathAndName);
wchar password[kMaxPasswordLength];
if (ini) {
// Read [Net.Server] section
IniGetString(
IniGetFirstValue(
ini,
L"Net.Server",
L"Addr",
nil
),
s_iniServerAddr,
arrsize(s_iniServerAddr),
0,
L""
);
// Read [Net.FileServer] section
IniGetString(
IniGetFirstValue(
ini,
L"Net.FileServer",
L"Addr",
nil
),
s_iniFileServerAddr,
arrsize(s_iniFileServerAddr),
0,
s_iniServerAddr
);
if (s_iniReadAccountInfo) {
// Read [Net.Account] section
IniGetString(
IniGetFirstValue(
ini,
L"Net.Account",
L"Username",
nil
),
s_iniAccountUsername,
arrsize(s_iniAccountUsername),
0,
L""
);
IniGetString(
IniGetFirstValue(
ini,
L"Net.Account",
L"Password",
nil
),
password,
arrsize(password),
0,
L""
);
// Read [Net.Startup] section
IniGetString(
IniGetFirstValue(
ini,
L"Net.Startup",
L"AgeName",
nil
),
s_iniStartupAgeName,
arrsize(s_iniStartupAgeName),
0,
L"StartUp"
);
IniGetString(
IniGetFirstValue(
ini,
L"Net.Startup",
L"PlayerName",
nil
),
s_iniStartupPlayerName,
arrsize(s_iniStartupPlayerName),
0,
L""
);
CryptHashPassword(s_iniAccountUsername, password, &s_namePassHash);
}
else {
StrCopy(s_iniStartupAgeName, L"StartUp", arrsize(s_iniStartupAgeName));
}
}
#ifndef PLASMA_EXTERNAL_RELEASE
// @@@: Internal dev build only: Drop a default version of the file if not found
if (!ini && BuildType() == BUILD_TYPE_DEV) {
EFileError fileError;
qword fileSize;
qword lastWrite;
AsyncFile file = AsyncFileOpen(
pathAndName,
nil,
&fileError,
kAsyncFileReadAccess|kAsyncFileWriteAccess,
kAsyncFileModeCreateNew,
0,
nil,
&fileSize,
&lastWrite
);
if (file) {
char line[2048];
StrPrintf(
line,
arrsize(line),
// format
"[Net.Server]\r\n"
"\tAddr=%S\r\n"
"\r\n"
"[Net.FileServer]\r\n"
"\tAddr=%S\r\n"
"\r\n"
"[Net.Account]\r\n"
"\tUsername=%S\r\n"
"\tPassword=AccountPassword\r\n"
"\r\n"
"[Net.Startup]\r\n"
"\tAgeName=%S\r\n"
"\tPlayerName=%S\r\n"
, // values
L"shard",
L"shard",
L"AccountUserName",
L"StartUp",
L"PlayerName",
nil
);
AsyncFileWrite(file, 0, line, StrLen(line), kAsyncFileRwSync, nil);
AsyncFileClose(file, kAsyncFileDontTruncate);
}
}
#endif
// Set startup age info
ZERO(s_startupAge);
if (StrLen(s_iniStartupAgeName) == 0)
StrCopy(s_startupAge.ageDatasetName, "StartUp", arrsize(s_startupAge.ageDatasetName));
else
StrToAnsi(s_startupAge.ageDatasetName, s_iniStartupAgeName, arrsize(s_startupAge.ageDatasetName));
s_startupAge.ageInstId = s_iniStartupAgeInstId;
StrCopy(s_startupAge.spawnPtName, "LinkInPointDefault", arrsize(s_startupAge.spawnPtName));
IniClose(ini);
}
//============================================================================
static void FileSrvIpAddressCallback (
ENetError result,
void * param,
const wchar addr[]
) {
StrCopy(s_fileSrvAddr, addr, arrsize(s_fileSrvAddr));
s_hasFileSrvIpAddress = true;
}
/*****************************************************************************
*
* Exports
*
***/
//============================================================================
const NetCommPlayer * const NetCommGetPlayer () {
static NetCommPlayer s_nilPlayer;
return s_player ? s_player : &s_nilPlayer;
}
//============================================================================
const ARRAY(NetCommPlayer)& NetCommGetPlayerList () {
return s_players;
}
//============================================================================
unsigned NetCommGetPlayerCount () {
return s_players.Count();
}
//============================================================================
const NetCommAccount * const NetCommGetAccount () {
return &s_account;
}
//============================================================================
bool NetCommIsLoginComplete() {
return s_loginComplete;
}
//============================================================================
const NetCommAge * const NetCommGetAge () {
return &s_age;
}
//============================================================================
const NetCommAge * const NetCommGetStartupAge () {
return &s_startupAge;
}
//============================================================================
bool NetCommNeedToLoadAvatar () {
return s_needAvatarLoad;
}
//============================================================================
void NetCommSetAvatarLoaded (bool loaded /* = true */) {
s_needAvatarLoad = !loaded;
}
//============================================================================
void NetCommChangeMyPassword (
const wchar password[]
) {
NetCliAuthAccountChangePasswordRequest(s_account.accountName, password, INetCliAuthChangePasswordCallback, nil);
}
//============================================================================
void NetCommStartup () {
s_shutdown = false;
LogRegisterHandler(INetLogCallback);
AsyncCoreInitialize();
AsyncLogInitialize(L"Log", false);
wchar productString[256];
ProductString(productString, arrsize(productString));
LogMsg(kLogPerf, L"Client: %s", productString);
NetClientInitialize();
NetClientSetErrorHandler(IPreInitNetErrorCallback);
NetCliGameSetRecvBufferHandler(INetBufferCallback);
// NetCliAuthSetRecvBufferHandler(INetBufferCallback);
NetCliAuthSetNotifyNewBuildHandler(INotifyNewBuildCallback);
NetCliAuthSetConnectCallback(INotifyAuthConnectedCallback);
IReadNetIni();
}
//============================================================================
void NetCommShutdown () {
s_shutdown = true;
NetCommSetDefaultMsgHandler(nil, nil);
NetCommSetMsgPreHandler(nil, nil);
NetCommRemoveMsgHandler(
kNetCommAllMsgClasses,
kNetCommAllMsgHandlers,
kNetCommAllUserStates
);
NetCliGameDisconnect();
NetCliAuthDisconnect();
if (!gDataServerLocal)
NetCliFileDisconnect();
NetClientDestroy(false);
AsyncLogDestroy();
AsyncCoreDestroy(30 * 1000);
LogUnregisterHandler(INetLogCallback);
}
//============================================================================
void NetCommEnableNet (
bool enabled,
bool wait
) {
if (enabled) {
NetClientInitialize();
NetClientSetErrorHandler(INetErrorCallback);
NetCliGameSetRecvBufferHandler(INetBufferCallback);
// NetCliAuthSetRecvBufferHandler(INetBufferCallback);
}
else {
NetClientDestroy(wait);
}
}
//============================================================================
void NetCommActivatePostInitErrorHandler () {
NetClientSetErrorHandler(INetErrorCallback);
}
//============================================================================
void NetCommUpdate () {
// plClient likes to recursively call us on occasion; debounce that crap.
static long s_updating;
if (0 == AtomicSet(&s_updating, 1)) {
NetClientUpdate();
AtomicSet(&s_updating, 0);
}
}
//============================================================================
void NetCommConnect () {
const wchar ** addrs;
unsigned count;
count = GetAuthSrvHostnames(&addrs);
NetCliAuthStartConnect(addrs, count);
if (!gDataServerLocal) {
// if a cmdline override was specified for a filesrv, connect directly to the fileserver rather than going through the gatekeeper
if(GetFileSrvHostnames(&addrs) && FileSrvHostnameOverride())
{
NetCliFileStartConnect(addrs, count);
}
else
{
count = GetGateKeeperSrvHostnames(&addrs);
NetCliGateKeeperStartConnect(addrs, count);
// request a file server ip address
NetCliGateKeeperFileSrvIpAddressRequest(FileSrvIpAddressCallback, nil, false);
while(!s_hasFileSrvIpAddress && !s_netError) {
NetClientUpdate();
AsyncSleep(10);
}
const wchar * fileSrv[] = {
s_fileSrvAddr
};
NetCliFileStartConnect(fileSrv, 1);
}
}
}
//============================================================================
void NetCommDisconnect () {
NetCliAuthDisconnect();
if (!gDataServerLocal) {
NetCliFileDisconnect();
}
}
//============================================================================
void NetCommSendMsg (
plNetMessage * msg
) {
msg->SetPlayerID(NetCommGetPlayer()->playerInt);
unsigned msgSize = msg->GetPackSize();
byte * buf = ALLOCA(byte, msgSize);
msg->PokeBuffer((char *)buf, msgSize);
switch (msg->GetNetProtocol()) {
case kNetProtocolCli2Auth:
NetCliAuthPropagateBuffer(
msg->ClassIndex(),
msgSize,
buf
);
break;
case kNetProtocolCli2Game:
NetCliGamePropagateBuffer(
msg->ClassIndex(),
msgSize,
buf
);
break;
DEFAULT_FATAL(msg->GetNetProtocol());
}
}
//============================================================================
void NetCommRecvMsg (
plNetMessage * msg
) {
for (;;) {
if (s_preHandler.proc && kOK_MsgConsumed == s_preHandler.proc(msg, s_preHandler.state))
break;
unsigned msgClassIdx = msg->ClassIndex();
NetCommMsgHandler * handler = s_handlers.Find(msgClassIdx);
if (!handler && s_defaultHandler.proc) {
s_defaultHandler.proc(msg, s_defaultHandler.state);
break;
}
while (handler) {
if (kOK_MsgConsumed == handler->proc(msg, handler->state))
break;
handler = s_handlers.FindNext(msgClassIdx, handler);
}
break;
}
}
//============================================================================
void NetCommAddMsgHandlerForType (
unsigned msgClassIdx,
FNetCommMsgHandler * proc,
void * state
) {
for (unsigned i = 0; i < plFactory::GetNumClasses(); ++i) {
if (plFactory::DerivesFrom(msgClassIdx, i))
NetCommAddMsgHandlerForExactType(i, proc, state);
}
}
//============================================================================
void NetCommAddMsgHandlerForExactType (
unsigned msgClassIdx,
FNetCommMsgHandler * proc,
void * state
) {
ASSERT(msgClassIdx != kNetCommAllMsgClasses);
ASSERT(proc && proc != kNetCommAllMsgHandlers);
ASSERT(!state || (state && state != kNetCommAllUserStates));
NetCommRemoveMsgHandler(msgClassIdx, proc, state);
NetCommMsgHandler * handler = NEW(NetCommMsgHandler)(msgClassIdx, proc, state);
s_handlers.Add(handler);
}
//============================================================================
void NetCommRemoveMsgHandler (
unsigned msgClassIdx,
FNetCommMsgHandler * proc,
const void * state
) {
NetCommMsgHandler * next, * handler = s_handlers.Head();
for (; handler; handler = next) {
next = handler->link.Next();
if (handler->GetValue() != msgClassIdx)
if (msgClassIdx != kNetCommAllMsgClasses)
continue;
if (handler->proc != proc)
if (proc != kNetCommAllMsgHandlers)
continue;
if (handler->state != state)
if (state != kNetCommAllUserStates)
continue;
// We found a matching handler, delete it
DEL(handler);
}
}
//============================================================================
void NetCommSetDefaultMsgHandler (
FNetCommMsgHandler * proc,
void * state
) {
s_defaultHandler.proc = proc;
s_defaultHandler.state = state;
}
//============================================================================
void NetCommSetMsgPreHandler (
FNetCommMsgHandler * proc,
void * state
) {
s_preHandler.proc = proc;
s_preHandler.state = state;
}
//============================================================================
void NetCommSetAccountUsernamePassword (
wchar username[],
const ShaDigest & namePassHash
) {
StrCopy(s_iniAccountUsername, username, arrsize(s_iniAccountUsername));
s_namePassHash = namePassHash;
s_iniReadAccountInfo = false;
}
//============================================================================
void NetCommSetAuthTokenAndOS (
wchar authToken[],
wchar os[]
) {
if (authToken)
StrCopy(s_iniAuthToken, authToken, arrsize(s_iniAuthToken));
if (os)
StrCopy(s_iniOS, os, arrsize(s_iniOS));
}
//============================================================================
ENetError NetCommGetAuthResult () {
return s_authResult;
}
//============================================================================
void NetCommSetReadIniAccountInfo(bool readFromIni) {
s_iniReadAccountInfo = readFromIni;
}
//============================================================================
void NetCommAuthenticate (
void * param
) {
s_loginComplete = false;
StrCopy(
s_account.accountName,
s_iniAccountUsername,
arrsize(s_account.accountName)
);
StrToAnsi(
s_account.accountNameAnsi,
s_iniAccountUsername,
arrsize(s_account.accountNameAnsi)
);
s_account.accountNamePassHash = s_namePassHash;
NetCliAuthLoginRequest(
s_account.accountName,
&s_account.accountNamePassHash,
s_iniAuthToken,
s_iniOS,
INetCliAuthLoginRequestCallback,
nil
);
}
//============================================================================
void NetCommLinkToAge ( // --> plNetCommLinkToAgeMsg
const NetCommAge & age,
void * param
) {
s_age = age;
if (plNetClientMgr::GetInstance()->GetFlagsBit(plNetClientApp::kLinkingToOfflineAge)) {
plNetCommLinkToAgeMsg * msg = NEW(plNetCommLinkToAgeMsg);
msg->result = kNetSuccess;
msg->param = nil;
msg->Send();
return;
}
wchar wAgeName[kMaxAgeNameLength];
StrToUnicode(wAgeName, s_age.ageDatasetName, arrsize(wAgeName));
NetCliAuthAgeRequest(
wAgeName,
s_age.ageInstId,
INetCliAuthAgeRequestCallback,
param
);
}
//============================================================================
void NetCommSetActivePlayer (//--> plNetCommActivePlayerMsg
unsigned desiredPlayerInt,
void * param
) {
unsigned playerInt = 0;
if (s_player) {
if (RelVaultNode* rvn = VaultGetPlayerInfoNodeIncRef()) {
VaultPlayerInfoNode pInfo(rvn);
pInfo.SetAgeInstName(nil);
pInfo.SetAgeInstUuid(kNilGuid);
pInfo.SetOnline(false);
NetCliAuthVaultNodeSave(rvn, nil, nil);
rvn->DecRef();
}
VaultCull(s_player->playerInt);
}
if (desiredPlayerInt == 0)
s_player = nil;
else {
for (unsigned i = 0; i < s_players.Count(); ++i) {
if (s_players[i].playerInt == desiredPlayerInt) {
playerInt = desiredPlayerInt;
s_player = &s_players[i];
break;
}
else if (0 == StrCmpI(s_players[i].playerName, s_iniStartupPlayerName, arrsize(s_players[i].playerName))) {
playerInt = s_players[i].playerInt;
s_player = &s_players[i];
}
}
ASSERT(s_player);
}
NetCliAuthSetPlayerRequest(
playerInt,
INetCliAuthSetPlayerRequestCallback,
param
);
}
//============================================================================
void NetCommCreatePlayer ( // --> plNetCommCreatePlayerMsg
const char playerName[],
const char avatarShape[],
const char friendInvite[],
unsigned createFlags,
void * param
) {
wchar wplayerName[kMaxPlayerNameLength];
wchar wavatarShape[MAX_PATH];
wchar wfriendInvite[MAX_PATH];
StrToUnicode(wplayerName, playerName, arrsize(wplayerName));
StrToUnicode(wavatarShape, avatarShape, arrsize(wavatarShape));
StrToUnicode(wfriendInvite, friendInvite, arrsize(wfriendInvite));
NetCliAuthPlayerCreateRequest(
wplayerName,
wavatarShape,
(friendInvite != NULL) ? wfriendInvite : NULL,
INetCliAuthCreatePlayerRequestCallback,
param
);
}
//============================================================================
void NetCommCreatePlayer ( // --> plNetCommCreatePlayerMsg
const wchar playerName[],
const wchar avatarShape[],
const wchar friendInvite[],
unsigned createFlags,
void * param
) {
NetCliAuthPlayerCreateRequest(
playerName,
avatarShape,
(friendInvite != NULL) ? friendInvite : NULL,
INetCliAuthCreatePlayerRequestCallback,
param
);
}
//============================================================================
void NetCommDeletePlayer ( // --> plNetCommDeletePlayerMsg
unsigned playerInt,
void * param
) {
ASSERTMSG(!param, "'param' will not be propagated to your callback function, you may modify the code to support this");
ASSERT(NetCommGetPlayer()->playerInt != playerInt);
NetCliAuthPlayerDeleteRequest(
playerInt,
INetCliAuthDeletePlayerCallback,
(void*)playerInt
);
}
//============================================================================
void NetCommGetPublicAgeList (//-> plNetCommPublicAgeListMsg
const char ageName[],
void * param,
plNetCommReplyMsg::EParamType ptype
) {
NetCommParam * cp = NEW(NetCommParam);
cp->param = param;
cp->type = ptype;
wchar wStr[MAX_PATH];
StrToUnicode(wStr, ageName, arrsize(wStr));
NetCliAuthGetPublicAgeList(
wStr,
INetCliAuthGetPublicAgeListCallback,
cp
);
}
//============================================================================
void NetCommSetAgePublic ( // --> no msg
unsigned ageInfoId,
bool makePublic
) {
NetCliAuthSetAgePublic(
ageInfoId,
makePublic
);
}
//============================================================================
void NetCommCreatePublicAge (// --> plNetCommPublicAgeMsg
const char ageName[],
const Uuid & ageInstId,
void * param
) {
}
//============================================================================
void NetCommRemovePublicAge(// --> plNetCommPublicAgeMsg
const Uuid & ageInstId,
void * param
) {
}
//============================================================================
void NetCommRegisterOwnedAge (
const NetCommAge & age,
const char ageInstDesc[],
unsigned playerInt,
void * param
) {
}
//============================================================================
void NetCommUnregisterOwnedAge (
const char ageName[],
unsigned playerInt,
void * param
) {
}
//============================================================================
void NetCommRegisterVisitAge (
const NetCommAge & age,
const char ageInstDesc[],
unsigned playerInt,
void * param
) {
}
//============================================================================
void NetCommUnregisterVisitAge (
const Uuid & ageInstId,
unsigned playerInt,
void * param
) {
}
//============================================================================
void NetCommConnectPlayerVault (
void * param
) {
}
//============================================================================
void NetCommConnectAgeVault (
const Uuid & ageInstId,
void * param
) {
}
//============================================================================
void NetCommUpgradeVisitorToExplorer (
unsigned playerInt,
void * param
) {
NetCliAuthUpgradeVisitorRequest(
playerInt,
INetCliAuthUpgradeVisitorRequestCallback,
(void*)playerInt
);
}
//============================================================================
void NetCommSetCCRLevel (
unsigned ccrLevel
) {
if (RelVaultNode * rvnInfo = VaultGetPlayerInfoNodeIncRef()) {
VaultPlayerInfoNode pInfo(rvnInfo);
pInfo.SetCCRLevel(ccrLevel);
rvnInfo->DecRef();
}
NetCliAuthSetCCRLevel(ccrLevel);
}
//============================================================================
void NetCommSendFriendInvite (
const wchar emailAddress[],
const wchar toName[],
const Uuid& inviteUuid
) {
NetCliAuthSendFriendInvite(
emailAddress,
toName,
inviteUuid,
INetCliAuthSendFriendInviteCallback,
nil
);
}
/*****************************************************************************
*
* Msg handler interface - compatibility layer with legacy code
*
***/
////////////////////////////////////////////////////////////////////
// plNetClientComm ----------------------------------------------
plNetClientComm::plNetClientComm()
{
}
// ~plNetClientComm ----------------------------------------------
plNetClientComm::~plNetClientComm()
{
NetCommSetMsgPreHandler(nil, nil);
}
// AddMsgHandlerForType ----------------------------------------------
void plNetClientComm::AddMsgHandlerForType( UInt16 msgClassIdx, MsgHandler* handler )
{
int i;
for( i = 0; i < plFactory::GetNumClasses(); i++ )
{
if ( plFactory::DerivesFrom( msgClassIdx, i ) )
AddMsgHandlerForExactType( i, handler );
}
}
// AddMsgHandlerForExactType ----------------------------------------------
void plNetClientComm::AddMsgHandlerForExactType( UInt16 msgClassIdx, MsgHandler* handler )
{
NetCommAddMsgHandlerForExactType(msgClassIdx, MsgHandler::StaticMsgHandler, handler);
}
// RemoveMsgHandler ----------------------------------------------
bool plNetClientComm::RemoveMsgHandler( MsgHandler* handler )
{
NetCommRemoveMsgHandler(kNetCommAllMsgClasses, kNetCommAllMsgHandlers, handler);
return true;
}
// SetDefaultHandler ----------------------------------------------
void plNetClientComm::SetDefaultHandler( MsgHandler* handler) {
NetCommSetDefaultMsgHandler(MsgHandler::StaticMsgHandler, handler);
}
// MsgHandler::StaticMsgHandler ----------------------------------------------
int plNetClientComm::MsgHandler::StaticMsgHandler (plNetMessage * msg, void * userState) {
plNetClientComm::MsgHandler * handler = (plNetClientComm::MsgHandler *) userState;
return handler->HandleMessage(msg);
}