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.
4630 lines
124 KiB
4630 lines
124 KiB
14 years ago
|
/*==LICENSE==*
|
||
|
|
||
|
CyanWorlds.com Engine - MMOG client, server and tools
|
||
13 years ago
|
Copyright (C) 2011 Cyan Worlds, Inc.
|
||
14 years ago
|
|
||
|
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
|
||
13 years ago
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
14 years ago
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License
|
||
13 years ago
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
|
||
|
Additional permissions under GNU GPL version 3 section 7
|
||
|
|
||
|
If you modify this Program, or any covered work, by linking or
|
||
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
|
||
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
|
||
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
|
||
|
(or a modified version of those libraries),
|
||
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
|
||
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
|
||
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
|
||
|
licensors of this Program grant you additional
|
||
|
permission to convey the resulting work. Corresponding Source for a
|
||
|
non-source form of such a combination shall include the source code for
|
||
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
|
||
|
work.
|
||
14 years ago
|
|
||
|
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/plVault/plVaultClientApi.cpp
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
|
||
|
#include "Pch.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#ifdef CLIENT
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Private
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
struct IVaultCallback {
|
||
|
LINK(IVaultCallback) link;
|
||
|
VaultCallback * cb;
|
||
|
};
|
||
|
|
||
|
struct INotifyAfterDownload : THashKeyVal<unsigned> {
|
||
|
HASHLINK(INotifyAfterDownload) link;
|
||
|
unsigned parentId;
|
||
|
unsigned childId;
|
||
|
|
||
|
INotifyAfterDownload (unsigned parentId, unsigned childId)
|
||
|
: THashKeyVal<unsigned>(childId)
|
||
|
, parentId(parentId)
|
||
|
, childId(childId)
|
||
|
{}
|
||
|
};
|
||
|
|
||
|
struct DeviceInbox : CHashKeyStr {
|
||
|
HASHLINK(DeviceInbox) link;
|
||
|
wchar inboxName[kMaxVaultNodeStringLength];
|
||
|
|
||
|
DeviceInbox (const wchar device[], const wchar inbox[])
|
||
|
: CHashKeyStr(device)
|
||
|
{
|
||
|
StrCopy(inboxName, inbox, arrsize(inboxName));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// A RelVaultNodeLink may be either stored in the global table,
|
||
|
// or stored in an IRelVaultNode's parents or children table.
|
||
|
struct RelVaultNodeLink : THashKeyVal<unsigned> {
|
||
|
HASHLINK(RelVaultNodeLink) link;
|
||
|
RelVaultNode * node;
|
||
|
unsigned ownerId;
|
||
|
bool seen;
|
||
|
|
||
|
RelVaultNodeLink (bool seen, unsigned ownerId, unsigned nodeId, RelVaultNode * node)
|
||
|
: THashKeyVal<unsigned>(nodeId)
|
||
|
, seen(seen)
|
||
|
, ownerId(ownerId)
|
||
|
, node(node)
|
||
|
{
|
||
|
node->IncRef();
|
||
|
}
|
||
|
~RelVaultNodeLink () {
|
||
|
node->DecRef();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
struct IRelVaultNode {
|
||
|
RelVaultNode * node;
|
||
|
|
||
|
HASHTABLEDECL(
|
||
|
RelVaultNodeLink,
|
||
|
THashKeyVal<unsigned>,
|
||
|
link
|
||
|
) parents;
|
||
|
|
||
|
HASHTABLEDECL(
|
||
|
RelVaultNodeLink,
|
||
|
THashKeyVal<unsigned>,
|
||
|
link
|
||
|
) children;
|
||
|
|
||
|
IRelVaultNode (RelVaultNode * node);
|
||
|
~IRelVaultNode ();
|
||
|
|
||
|
// Unlink our node from all our parent and children
|
||
|
void UnlinkFromRelatives ();
|
||
|
|
||
|
// Unlink the node from our parent and children lists
|
||
|
void Unlink (RelVaultNode * other);
|
||
|
};
|
||
|
|
||
|
|
||
|
struct VaultCreateNodeTrans {
|
||
|
FVaultCreateNodeCallback callback;
|
||
|
void * state;
|
||
|
void * param;
|
||
|
|
||
|
unsigned nodeId;
|
||
|
RelVaultNode * node;
|
||
|
|
||
|
static void VaultNodeCreated (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned nodeId
|
||
|
);
|
||
|
static void VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
);
|
||
|
|
||
|
void Complete (ENetError result);
|
||
|
};
|
||
|
|
||
|
|
||
|
struct VaultFindNodeTrans {
|
||
|
FVaultFindNodeCallback callback;
|
||
|
void * param;
|
||
|
|
||
|
static void VaultNodeFound (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned nodeIdCount,
|
||
|
const unsigned nodeIds[]
|
||
|
);
|
||
|
};
|
||
|
|
||
|
|
||
|
struct VaultDownloadTrans {
|
||
|
FVaultDownloadCallback callback;
|
||
|
void * cbParam;
|
||
|
FVaultProgressCallback progressCallback;
|
||
|
void * cbProgressParam;
|
||
|
|
||
|
wchar tag[MAX_PATH];
|
||
|
unsigned nodeCount;
|
||
|
unsigned nodesLeft;
|
||
|
unsigned vaultId;
|
||
|
ENetError result;
|
||
|
|
||
|
VaultDownloadTrans ();
|
||
|
|
||
|
static void VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
);
|
||
|
static void VaultNodeRefsFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount
|
||
|
);
|
||
|
};
|
||
|
|
||
|
struct VaultAgeInitTrans {
|
||
|
FVaultInitAgeCallback callback;
|
||
|
void * cbState;
|
||
|
void * cbParam;
|
||
|
|
||
|
static void AgeInitCallback (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
);
|
||
|
};
|
||
|
|
||
|
struct AddChildNodeFetchTrans {
|
||
|
FVaultAddChildNodeCallback callback;
|
||
|
void * cbParam;
|
||
|
ENetError result;
|
||
|
long opCount;
|
||
|
|
||
|
static void VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
);
|
||
|
static void VaultNodeRefsFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount
|
||
|
);
|
||
|
};
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Private data
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
static bool s_running;
|
||
|
|
||
|
static HASHTABLEDECL(
|
||
|
RelVaultNodeLink,
|
||
|
THashKeyVal<unsigned>,
|
||
|
link
|
||
|
) s_nodes;
|
||
|
|
||
|
static LISTDECL(
|
||
|
IVaultCallback,
|
||
|
link
|
||
|
) s_callbacks;
|
||
|
|
||
|
static HASHTABLEDECL(
|
||
|
INotifyAfterDownload,
|
||
|
THashKeyVal<unsigned>,
|
||
|
link
|
||
|
) s_notifyAfterDownload;
|
||
|
|
||
|
static HASHTABLEDECL(
|
||
|
DeviceInbox,
|
||
|
CHashKeyStr,
|
||
|
link
|
||
|
) s_ageDeviceInboxes;
|
||
|
|
||
|
static bool s_processPlayerInbox = false;
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Local functions
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
static void VaultProcessVisitNote(RelVaultNode * rvnVisit);
|
||
|
static void VaultProcessUnvisitNote(RelVaultNode * rvnUnVisit);
|
||
|
|
||
|
static void VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
);
|
||
|
static void VaultNodeFound (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned nodeIdCount,
|
||
|
const unsigned nodeIds[]
|
||
|
);
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeAddedDownloadCallback(ENetError result, void * param) {
|
||
|
unsigned childId = (unsigned)param;
|
||
|
|
||
|
INotifyAfterDownload* notify = s_notifyAfterDownload.Find(childId);
|
||
|
|
||
|
if (notify) {
|
||
|
if (IS_NET_SUCCESS(result)) {
|
||
|
RelVaultNodeLink* parentLink = s_nodes.Find(notify->parentId);
|
||
|
RelVaultNodeLink* childLink = s_nodes.Find(notify->childId);
|
||
|
|
||
|
if (parentLink && childLink) {
|
||
|
if (childLink->node->nodeType == plVault::kNodeType_TextNote) {
|
||
|
VaultTextNoteNode textNote(childLink->node);
|
||
|
if (textNote.noteType == plVault::kNoteType_Visit)
|
||
|
VaultProcessVisitNote(childLink->node);
|
||
|
else if (textNote.noteType == plVault::kNoteType_UnVisit)
|
||
|
VaultProcessUnvisitNote(childLink->node);
|
||
|
}
|
||
|
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->AddedChildNode(parentLink->node, childLink->node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DEL(notify);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void __cdecl LogDumpProc (
|
||
|
void * ,
|
||
|
const wchar fmt[],
|
||
|
...
|
||
|
) {
|
||
|
va_list args;
|
||
|
va_start(args, fmt);
|
||
|
LogMsgV(kLogDebug, fmt, args);
|
||
|
va_end(args);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
// Returns ids of nodes that had to be created (so we can fetch them)
|
||
|
static void BuildNodeTree (
|
||
|
const NetVaultNodeRef refs[],
|
||
|
unsigned refCount,
|
||
|
ARRAY(unsigned) * newNodeIds,
|
||
|
ARRAY(unsigned) * existingNodeIds,
|
||
|
bool notifyNow = true
|
||
|
) {
|
||
|
for (unsigned i = 0; i < refCount; ++i) {
|
||
|
// Find/Create global links
|
||
|
RelVaultNodeLink * parentLink = s_nodes.Find(refs[i].parentId);
|
||
|
if (!parentLink) {
|
||
|
newNodeIds->Add(refs[i].parentId);
|
||
|
parentLink = NEWZERO(RelVaultNodeLink)(false, 0, refs[i].parentId, NEWZERO(RelVaultNode));
|
||
|
parentLink->node->nodeId = refs[i].parentId; // set directly so that the field's dirty flag isn't set
|
||
|
s_nodes.Add(parentLink);
|
||
|
}
|
||
|
else {
|
||
|
existingNodeIds->Add(refs[i].parentId);
|
||
|
}
|
||
|
RelVaultNodeLink * childLink = s_nodes.Find(refs[i].childId);
|
||
|
if (!childLink) {
|
||
|
newNodeIds->Add(refs[i].childId);
|
||
|
childLink = NEWZERO(RelVaultNodeLink)(refs[i].seen, refs[i].ownerId, refs[i].childId, NEWZERO(RelVaultNode));
|
||
|
childLink->node->nodeId = refs[i].childId; // set directly so that the field's dirty flag isn't set
|
||
|
s_nodes.Add(childLink);
|
||
|
}
|
||
|
else {
|
||
|
existingNodeIds->Add(refs[i].childId);
|
||
|
if (unsigned ownerId = refs[i].ownerId)
|
||
|
childLink->ownerId = ownerId;
|
||
|
}
|
||
|
|
||
|
RelVaultNode * parentNode = parentLink->node;
|
||
|
RelVaultNode * childNode = childLink->node;
|
||
|
|
||
|
bool isImmediateParent = parentNode->IsParentOf(refs[i].childId, 1);
|
||
|
bool isImmediateChild = childNode->IsChildOf(refs[i].parentId, 1);
|
||
|
|
||
|
if (!isImmediateParent) {
|
||
|
// Add parent to child's parents table
|
||
|
parentLink = NEWZERO(RelVaultNodeLink)(false, 0, parentNode->nodeId, parentNode);
|
||
|
childNode->state->parents.Add(parentLink);
|
||
|
LogMsg(kLogDebug, L"Added relationship: p:%u,c:%u", refs[i].parentId, refs[i].childId);
|
||
|
}
|
||
|
|
||
|
if (!isImmediateChild) {
|
||
|
// Add child to parent's children table
|
||
|
childLink = NEWZERO(RelVaultNodeLink)(refs[i].seen, refs[i].ownerId, childNode->nodeId, childNode);
|
||
|
parentNode->state->children.Add(childLink);
|
||
|
|
||
|
if (notifyNow || childNode->nodeType != 0) {
|
||
|
// We made a new link, so make the callbacks
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->AddedChildNode(parentNode, childNode);
|
||
|
}
|
||
|
else {
|
||
|
INotifyAfterDownload* notify = NEWZERO(INotifyAfterDownload)(parentNode->nodeId, childNode->nodeId);
|
||
|
s_notifyAfterDownload.Add(notify);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void InitFetchedNode (RelVaultNode * rvn) {
|
||
|
|
||
|
switch (rvn->nodeType) {
|
||
|
case plVault::kNodeType_SDL: {
|
||
|
VaultSDLNode access(rvn);
|
||
|
if (!access.sdlData || !access.sdlDataLen)
|
||
|
access.InitStateDataRecord(access.sdlName);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void FetchRefOwners (
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount
|
||
|
) {
|
||
|
ARRAY(unsigned) ownerIds;
|
||
|
{ for (unsigned i = 0; i < refCount; ++i)
|
||
|
if (unsigned ownerId = refs[i].ownerId)
|
||
|
ownerIds.Add(ownerId);
|
||
|
}
|
||
|
QSORT(unsigned, ownerIds.Ptr(), ownerIds.Count(), elem1 < elem2);
|
||
|
RelVaultNode * templateNode = NEWZERO(RelVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_PlayerInfo);
|
||
|
{ unsigned prevId = 0;
|
||
|
for (unsigned i = 0; i < ownerIds.Count(); ++i) {
|
||
|
if (ownerIds[i] != prevId) {
|
||
|
prevId = ownerIds[i];
|
||
|
VaultPlayerInfoNode access(templateNode);
|
||
|
access.SetPlayerId(refs[i].ownerId);
|
||
|
if (RelVaultNode * rvn = VaultGetNodeIncRef(templateNode)) {
|
||
|
rvn->DecRef();
|
||
|
continue;
|
||
|
}
|
||
|
NetCliAuthVaultNodeFind(
|
||
|
templateNode,
|
||
|
VaultNodeFound,
|
||
|
nil
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void FetchNodesFromRefs (
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount,
|
||
|
FNetCliAuthVaultNodeFetched fetchCallback,
|
||
|
void * fetchParam,
|
||
|
unsigned * fetchCount
|
||
|
|
||
|
) {
|
||
|
// On the side, start downloading PlayerInfo nodes of ref owners we don't already have locally
|
||
|
FetchRefOwners(refs, refCount);
|
||
|
|
||
|
*fetchCount = 0;
|
||
|
|
||
|
ARRAY(unsigned) newNodeIds;
|
||
|
ARRAY(unsigned) existingNodeIds;
|
||
|
|
||
|
BuildNodeTree(refs, refCount, &newNodeIds, &existingNodeIds);
|
||
|
|
||
|
ARRAY(unsigned) nodeIds;
|
||
|
nodeIds.Add(newNodeIds.Ptr(), newNodeIds.Count());
|
||
|
nodeIds.Add(existingNodeIds.Ptr(), existingNodeIds.Count());
|
||
|
QSORT(unsigned, nodeIds.Ptr(), nodeIds.Count(), elem1 < elem2);
|
||
|
|
||
|
// Fetch the nodes that do not yet have a nodetype
|
||
|
unsigned prevId = 0;
|
||
|
{for (unsigned i = 0; i < nodeIds.Count(); ++i) {
|
||
|
RelVaultNodeLink * link = s_nodes.Find(nodeIds[i]);
|
||
|
if (link->node->nodeType != 0)
|
||
|
continue;
|
||
|
// filter duplicates
|
||
|
if (link->node->nodeId == prevId)
|
||
|
continue;
|
||
|
prevId = link->node->nodeId;
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
nodeIds[i],
|
||
|
fetchCallback,
|
||
|
fetchParam
|
||
|
);
|
||
|
++(*fetchCount);
|
||
|
}}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeFound (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
unsigned nodeIdCount,
|
||
|
const unsigned nodeIds[]
|
||
|
) {
|
||
|
// TODO: Support some sort of optional transaction object/callback state
|
||
|
|
||
|
// error?
|
||
|
if (IS_NET_ERROR(result))
|
||
|
return;
|
||
|
|
||
|
for (unsigned i = 0; i < nodeIdCount; ++i) {
|
||
|
|
||
|
// See if we already have this node
|
||
|
if (RelVaultNodeLink * link = s_nodes.Find(nodeIds[i]))
|
||
|
return;
|
||
|
|
||
|
// Start fetching the node
|
||
|
NetCliAuthVaultNodeFetch(nodeIds[i], VaultNodeFetched, nil);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
LogMsg(kLogDebug, L"VaultNodeFetched failed: %u (%s)", result, NetErrorToString(result));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// Add to global node table
|
||
|
RelVaultNodeLink * link = s_nodes.Find(node->nodeId);
|
||
|
if (!link) {
|
||
|
link = NEWZERO(RelVaultNodeLink)(false, 0, node->nodeId, NEWZERO(RelVaultNode));
|
||
|
link->node->nodeId = node->nodeId; // set directly so that the field's dirty flag isn't set
|
||
|
s_nodes.Add(link);
|
||
|
}
|
||
|
link->node->CopyFrom(node, NetVaultNode::kCopyOverwrite);
|
||
|
InitFetchedNode(link->node);
|
||
|
|
||
|
link->node->Print(L"Fetched", LogDumpProc, 0);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void ChangedVaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
LogMsg(kLogDebug, L"ChangedVaultNodeFetched failed: %u (%s)", result, NetErrorToString(result));
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VaultNodeFetched(result, param, node);
|
||
|
|
||
|
RelVaultNodeLink* savedLink = s_nodes.Find(node->nodeId);
|
||
|
|
||
|
if (savedLink) {
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->ChangedNode(savedLink->node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeChanged (
|
||
|
unsigned nodeId,
|
||
|
const Uuid & revisionId
|
||
|
) {
|
||
|
LogMsg(kLogDebug, L"Notify: Node changed: %u", nodeId);
|
||
|
|
||
|
RelVaultNodeLink * link = s_nodes.Find(nodeId);
|
||
|
|
||
|
// We don't have the node, so we don't care that it changed (we actually
|
||
|
// shouldn't have been notified)
|
||
|
if (!link) {
|
||
|
LogMsg(kLogDebug, L"rcvd change notification for node %u, but node doesn't exist locally.", nodeId);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// We are the party responsible for the change, so we already have the
|
||
|
// latest version of the node; no need to fetch it.
|
||
|
if (link->node->revisionId == revisionId)
|
||
|
return;
|
||
|
|
||
|
// We have the node and we weren't the one that changed it, so fetch it.
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
nodeId,
|
||
|
ChangedVaultNodeFetched,
|
||
|
nil
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeAdded (
|
||
|
unsigned parentId,
|
||
|
unsigned childId,
|
||
|
unsigned ownerId
|
||
|
) {
|
||
|
LogMsg(kLogDebug, L"Notify: Node added: p:%u,c:%u", parentId, childId);
|
||
|
|
||
|
unsigned inboxId = 0;
|
||
|
if (RelVaultNode * rvnInbox = VaultGetPlayerInboxFolderIncRef()) {
|
||
|
inboxId = rvnInbox->nodeId;
|
||
|
rvnInbox->DecRef();
|
||
|
}
|
||
|
|
||
|
// Build the relationship locally
|
||
|
NetVaultNodeRef refs[] = {
|
||
|
{ parentId, childId, ownerId }
|
||
|
};
|
||
|
ARRAY(unsigned) newNodeIds;
|
||
|
ARRAY(unsigned) existingNodeIds;
|
||
|
|
||
|
BuildNodeTree(refs, arrsize(refs), &newNodeIds, &existingNodeIds, false);
|
||
|
|
||
|
ARRAY(unsigned) nodeIds;
|
||
|
nodeIds.Add(newNodeIds.Ptr(), newNodeIds.Count());
|
||
|
nodeIds.Add(existingNodeIds.Ptr(), existingNodeIds.Count());
|
||
|
QSORT(unsigned, nodeIds.Ptr(), nodeIds.Count(), elem1 < elem2);
|
||
|
|
||
|
// Fetch the nodes that do not yet have a nodetype
|
||
|
unsigned prevId = 0;
|
||
|
unsigned i = 0;
|
||
|
{for (; i < nodeIds.Count(); ++i) {
|
||
|
RelVaultNodeLink * link = s_nodes.Find(nodeIds[i]);
|
||
|
if (link->node->nodeType != 0)
|
||
|
continue;
|
||
|
// filter duplicates
|
||
|
if (link->node->nodeId == prevId)
|
||
|
continue;
|
||
|
prevId = link->node->nodeId;
|
||
|
VaultDownload(
|
||
|
L"NodeAdded",
|
||
|
nodeIds[i],
|
||
|
VaultNodeAddedDownloadCallback,
|
||
|
(void*)nodeIds[i],
|
||
|
nil,
|
||
|
nil
|
||
|
);
|
||
|
}}
|
||
|
|
||
|
if (parentId == inboxId) {
|
||
|
if (i > 0)
|
||
|
s_processPlayerInbox = true;
|
||
|
else
|
||
|
VaultProcessPlayerInbox();
|
||
|
}
|
||
|
|
||
|
// if the added element is already downloaded then send the callbacks now
|
||
|
RelVaultNodeLink* parentLink = s_nodes.Find(parentId);
|
||
|
RelVaultNodeLink* childLink = s_nodes.Find(childId);
|
||
|
|
||
|
if (childLink->node->nodeType != 0) {
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->AddedChildNode(parentLink->node, childLink->node);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeRemoved (
|
||
|
unsigned parentId,
|
||
|
unsigned childId
|
||
|
) {
|
||
|
LogMsg(kLogDebug, L"Notify: Node removed: p:%u,c:%u", parentId, childId);
|
||
|
for (;;) {
|
||
|
// Unlink 'em locally, if we can
|
||
|
RelVaultNodeLink * parentLink = s_nodes.Find(parentId);
|
||
|
if (!parentLink)
|
||
|
break;
|
||
|
|
||
|
RelVaultNodeLink * childLink = s_nodes.Find(childId);
|
||
|
if (!childLink)
|
||
|
break;
|
||
|
|
||
|
if (parentLink->node->IsParentOf(childId, 1)) {
|
||
|
// We have the relationship, so make the callbacks
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->RemovingChildNode(parentLink->node, childLink->node);
|
||
|
}
|
||
|
|
||
|
parentLink->node->state->Unlink(childLink->node);
|
||
|
childLink->node->state->Unlink(parentLink->node);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void VaultNodeDeleted (
|
||
|
unsigned nodeId
|
||
|
) {
|
||
|
LogMsg(kLogDebug, L"Notify: Node deleted: %u", nodeId);
|
||
|
VaultCull(nodeId);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static void SaveDirtyNodes () {
|
||
|
// Save a max of 5Kb every quarter second
|
||
|
static const unsigned kSaveUpdateIntervalMs = 250;
|
||
|
static const unsigned kMaxBytesPerSaveUpdate = 5 * 1024;
|
||
|
static unsigned s_nextSaveMs;
|
||
|
unsigned currTimeMs = TimeGetMs() | 1;
|
||
|
if (!s_nextSaveMs || signed(s_nextSaveMs - currTimeMs) <= 0) {
|
||
|
s_nextSaveMs = (currTimeMs + kSaveUpdateIntervalMs) | 1;
|
||
|
unsigned bytesWritten = 0;
|
||
|
for (RelVaultNodeLink * link = s_nodes.Head(); link; link = s_nodes.Next(link)) {
|
||
|
if (bytesWritten >= kMaxBytesPerSaveUpdate)
|
||
|
break;
|
||
|
if (link->node->dirtyFlags) {
|
||
|
|
||
|
// Auth server needs the name of the sdl record
|
||
|
if (link->node->nodeType == plVault::kNodeType_SDL)
|
||
|
link->node->dirtyFlags |= VaultSDLNode::kSDLName;
|
||
|
|
||
|
if (unsigned bytes = NetCliAuthVaultNodeSave(link->node, nil, nil)) {
|
||
|
bytesWritten += bytes;
|
||
|
link->node->Print(L"Saving", LogDumpProc, 0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetChildFolderNode (
|
||
|
RelVaultNode * parent,
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (!parent)
|
||
|
return nil;
|
||
|
|
||
|
RelVaultNode * rvn = parent->GetChildFolderNodeIncRef(folderType, maxDepth);
|
||
|
if (rvn)
|
||
|
rvn->DecRef();
|
||
|
|
||
|
return rvn;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetChildPlayerInfoListNode (
|
||
|
RelVaultNode * parent,
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (!parent)
|
||
|
return nil;
|
||
|
|
||
|
RelVaultNode * rvn = parent->GetChildPlayerInfoListNodeIncRef(folderType, maxDepth);
|
||
|
if (rvn)
|
||
|
rvn->DecRef();
|
||
|
|
||
|
return rvn;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* VaultCreateNodeTrans
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCreateNodeTrans::VaultNodeCreated (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned nodeId
|
||
|
) {
|
||
|
VaultCreateNodeTrans * trans = (VaultCreateNodeTrans *)param;
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
trans->Complete(result);
|
||
|
}
|
||
|
else {
|
||
|
trans->nodeId = nodeId;
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
nodeId,
|
||
|
VaultCreateNodeTrans::VaultNodeFetched,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCreateNodeTrans::VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
::VaultNodeFetched(result, param, node);
|
||
|
|
||
|
VaultCreateNodeTrans * trans = (VaultCreateNodeTrans *)param;
|
||
|
|
||
|
if (IS_NET_SUCCESS(result))
|
||
|
trans->node = s_nodes.Find(node->nodeId)->node;
|
||
|
else
|
||
|
trans->node = nil;
|
||
|
|
||
|
trans->Complete(result);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCreateNodeTrans::Complete (ENetError result) {
|
||
|
|
||
|
if (callback)
|
||
|
callback(
|
||
|
result,
|
||
|
state,
|
||
|
param,
|
||
|
node
|
||
|
);
|
||
|
|
||
|
DEL(this);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* VaultFindNodeTrans
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultFindNodeTrans::VaultNodeFound (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned nodeIdCount,
|
||
|
const unsigned nodeIds[]
|
||
|
) {
|
||
|
VaultFindNodeTrans * trans = (VaultFindNodeTrans*)param;
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
result,
|
||
|
trans->param,
|
||
|
nodeIdCount,
|
||
|
nodeIds
|
||
|
);
|
||
|
DEL(trans);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* VaultDownloadTrans
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
VaultDownloadTrans::VaultDownloadTrans () {
|
||
|
ASSERT(!nodeCount); // must be alloced with
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDownloadTrans::VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
::VaultNodeFetched(result, param, node);
|
||
|
|
||
|
VaultDownloadTrans * trans = (VaultDownloadTrans *)param;
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
trans->result = result;
|
||
|
//LogMsg(kLogError, L"Error fetching node...most likely trying to fetch a nodeid of 0");
|
||
|
}
|
||
|
|
||
|
--trans->nodesLeft;
|
||
|
// LogMsg(kLogDebug, L"(Download) %u of %u nodes fetched", trans->nodeCount - trans->nodesLeft, trans->nodeCount);
|
||
|
|
||
|
if (trans->progressCallback) {
|
||
|
trans->progressCallback(
|
||
|
trans->nodeCount,
|
||
|
trans->nodeCount - trans->nodesLeft,
|
||
|
trans->cbProgressParam
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (!trans->nodesLeft) {
|
||
|
VaultDump(trans->tag, trans->vaultId, LogDumpProc);
|
||
|
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
trans->result,
|
||
|
trans->cbParam
|
||
|
);
|
||
|
|
||
|
DEL(trans);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDownloadTrans::VaultNodeRefsFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount
|
||
|
) {
|
||
|
VaultDownloadTrans * trans = (VaultDownloadTrans *)param;
|
||
|
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
LogMsg(kLogDebug, L"VaultNodeRefsFetched failed: %u (%s)", result, NetErrorToString(result));
|
||
|
trans->result = result;
|
||
|
trans->nodesLeft = 0;
|
||
|
}
|
||
|
else {
|
||
|
if (refCount) {
|
||
|
FetchNodesFromRefs(
|
||
|
refs,
|
||
|
refCount,
|
||
|
VaultDownloadTrans::VaultNodeFetched,
|
||
|
param,
|
||
|
&trans->nodeCount
|
||
|
);
|
||
|
trans->nodesLeft = trans->nodeCount;
|
||
|
}
|
||
|
else {
|
||
|
// root node has no child heirarchy? Make sure we still d/l the root node if necessary.
|
||
|
RelVaultNodeLink* rootNodeLink = s_nodes.Find(trans->vaultId);
|
||
|
if (!rootNodeLink || rootNodeLink->node->nodeType == 0) {
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
trans->vaultId,
|
||
|
VaultDownloadTrans::VaultNodeFetched,
|
||
|
trans
|
||
|
);
|
||
|
trans->nodesLeft = 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Make the callback now if there are no nodes to fetch, or if error
|
||
|
if (!trans->nodesLeft) {
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
trans->result,
|
||
|
trans->cbParam
|
||
|
);
|
||
|
|
||
|
DEL(trans);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* VaultAgeInitTrans
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAgeInitTrans::AgeInitCallback (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
) {
|
||
|
VaultAgeInitTrans * trans = (VaultAgeInitTrans *)param;
|
||
|
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
result,
|
||
|
trans->cbState,
|
||
|
trans->cbParam,
|
||
|
ageVaultId,
|
||
|
ageInfoVaultId
|
||
|
);
|
||
|
|
||
|
DEL(trans);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* AddChildNodeFetchTrans
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void AddChildNodeFetchTrans::VaultNodeRefsFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNodeRef * refs,
|
||
|
unsigned refCount
|
||
|
) {
|
||
|
AddChildNodeFetchTrans * trans = (AddChildNodeFetchTrans *)param;
|
||
|
|
||
|
if (IS_NET_ERROR(result)) {
|
||
|
trans->result = result;
|
||
|
}
|
||
|
else {
|
||
|
unsigned incFetchCount = 0;
|
||
|
FetchNodesFromRefs(
|
||
|
refs,
|
||
|
refCount,
|
||
|
AddChildNodeFetchTrans::VaultNodeFetched,
|
||
|
param,
|
||
|
&incFetchCount
|
||
|
);
|
||
|
AtomicAdd(&trans->opCount, incFetchCount);
|
||
|
}
|
||
|
|
||
|
// Make the callback now if there are no nodes to fetch, or if error
|
||
|
AtomicAdd(&trans->opCount, -1);
|
||
|
if (!trans->opCount) {
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
trans->result,
|
||
|
trans->cbParam
|
||
|
);
|
||
|
DEL(trans);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void AddChildNodeFetchTrans::VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
::VaultNodeFetched(result, param, node);
|
||
|
|
||
|
AddChildNodeFetchTrans * trans = (AddChildNodeFetchTrans *)param;
|
||
|
|
||
|
if (IS_NET_ERROR(result))
|
||
|
trans->result = result;
|
||
|
|
||
|
AtomicAdd(&trans->opCount, -1);
|
||
|
if (!trans->opCount) {
|
||
|
if (trans->callback)
|
||
|
trans->callback(
|
||
|
trans->result,
|
||
|
trans->cbParam
|
||
|
);
|
||
|
DEL(trans);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* IRelVaultNode
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
IRelVaultNode::IRelVaultNode (RelVaultNode * node)
|
||
|
: node(node)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
IRelVaultNode::~IRelVaultNode () {
|
||
|
ASSERT(!parents.Head());
|
||
|
ASSERT(!children.Head());
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void IRelVaultNode::UnlinkFromRelatives () {
|
||
|
|
||
|
RelVaultNodeLink * link, * next;
|
||
|
for (link = parents.Head(); link; link = next) {
|
||
|
next = parents.Next(link);
|
||
|
|
||
|
// We have the relationship, so make the callbacks
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->RemovingChildNode(link->node, this->node);
|
||
|
|
||
|
link->node->state->Unlink(node);
|
||
|
}
|
||
|
for (link = children.Head(); link; link = next) {
|
||
|
next = children.Next(link);
|
||
|
link->node->state->Unlink(node);
|
||
|
}
|
||
|
|
||
|
ASSERT(!parents.Head());
|
||
|
ASSERT(!children.Head());
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
void IRelVaultNode::Unlink (RelVaultNode * other) {
|
||
|
ASSERT(other != node);
|
||
|
|
||
|
RelVaultNodeLink * link;
|
||
|
if (nil != (link = parents.Find(other->nodeId))) {
|
||
|
// make them non-findable in our parents table
|
||
|
link->link.Unlink();
|
||
|
// remove us from other's tables.
|
||
|
link->node->state->Unlink(node);
|
||
|
DEL(link);
|
||
|
}
|
||
|
if (nil != (link = children.Find(other->nodeId))) {
|
||
|
// make them non-findable in our children table
|
||
|
link->link.Unlink();
|
||
|
// remove us from other's tables.
|
||
|
link->node->state->Unlink(node);
|
||
|
DEL(link);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* RelVaultNode
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode::RelVaultNode () {
|
||
|
state = NEWZERO(IRelVaultNode)(this);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode::~RelVaultNode () {
|
||
|
DEL(state);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool RelVaultNode::IsParentOf (unsigned childId, unsigned maxDepth) {
|
||
|
if (nodeId == childId)
|
||
|
return false;
|
||
|
if (maxDepth == 0)
|
||
|
return false;
|
||
|
if (state->children.Find(childId))
|
||
|
return true;
|
||
|
RelVaultNodeLink * link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link))
|
||
|
if (link->node->IsParentOf(childId, maxDepth - 1))
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool RelVaultNode::IsChildOf (unsigned parentId, unsigned maxDepth) {
|
||
|
if (nodeId == parentId)
|
||
|
return false;
|
||
|
if (maxDepth == 0)
|
||
|
return false;
|
||
|
if (state->parents.Find(parentId))
|
||
|
return true;
|
||
|
RelVaultNodeLink * link = state->parents.Head();
|
||
|
for (; link; link = state->parents.Next(link))
|
||
|
if (link->node->IsChildOf(parentId, maxDepth - 1))
|
||
|
return true;
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetRootIds (ARRAY(unsigned) * nodeIds) {
|
||
|
RelVaultNodeLink * link = state->parents.Head();
|
||
|
if (!link) {
|
||
|
nodeIds->Add(nodeId);
|
||
|
}
|
||
|
else {
|
||
|
for (; link; link = state->parents.Next(link))
|
||
|
link->node->GetRootIds(nodeIds);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
unsigned RelVaultNode::RemoveChildNodes (unsigned maxDepth) {
|
||
|
hsAssert(false, "eric, implement me.");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetChildNodeIds (
|
||
|
ARRAY(unsigned) * nodeIds,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (!maxDepth)
|
||
|
return;
|
||
|
RelVaultNodeLink * link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link)) {
|
||
|
nodeIds->Add(link->node->nodeId);
|
||
|
link->node->GetChildNodeIds(nodeIds, maxDepth-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetParentNodeIds (
|
||
|
ARRAY(unsigned) * nodeIds,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (!maxDepth)
|
||
|
return;
|
||
|
RelVaultNodeLink * link = state->parents.Head();
|
||
|
for (; link; link = state->parents.Next(link)) {
|
||
|
nodeIds->Add(link->node->nodeId);
|
||
|
link->node->GetParentNodeIds(nodeIds, maxDepth-1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetParentNodeIncRef (
|
||
|
NetVaultNode * templateNode,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (maxDepth == 0)
|
||
|
return false;
|
||
|
|
||
|
RelVaultNodeLink * link;
|
||
|
link = state->parents.Head();
|
||
|
for (; link; link = state->parents.Next(link)) {
|
||
|
if (link->node->Matches(templateNode)) {
|
||
|
link->node->IncRef("Found");
|
||
|
return link->node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
link = state->parents.Head();
|
||
|
for (; link; link = state->parents.Next(link)) {
|
||
|
if (RelVaultNode * node = link->node->GetParentNodeIncRef(templateNode, maxDepth-1))
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetChildNodeIncRef (
|
||
|
NetVaultNode * templateNode,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
if (maxDepth == 0)
|
||
|
return false;
|
||
|
|
||
|
RelVaultNodeLink * link;
|
||
|
link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link)) {
|
||
|
if (link->node->Matches(templateNode)) {
|
||
|
link->node->IncRef("Found");
|
||
|
return link->node;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link)) {
|
||
|
if (RelVaultNode * node = link->node->GetChildNodeIncRef(templateNode, maxDepth-1))
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetChildNodeIncRef (
|
||
|
unsigned nodeType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(nodeType);
|
||
|
RelVaultNode * result = GetChildNodeIncRef(templateNode, maxDepth);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetChildFolderNodeIncRef (
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Folder);
|
||
|
VaultFolderNode folder(templateNode);
|
||
|
folder.SetFolderType(folderType);
|
||
|
RelVaultNode * result = GetChildNodeIncRef(templateNode, maxDepth);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetChildPlayerInfoListNodeIncRef (
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_PlayerInfoList);
|
||
|
VaultPlayerInfoListNode access(templateNode);
|
||
|
access.SetFolderType(folderType);
|
||
|
RelVaultNode * result = GetChildNodeIncRef(templateNode, maxDepth);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetChildAgeInfoListNodeIncRef (
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfoList);
|
||
|
VaultAgeInfoListNode access(templateNode);
|
||
|
access.SetFolderType(folderType);
|
||
|
RelVaultNode * result = GetChildNodeIncRef(templateNode, maxDepth);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetChildNodesIncRef (
|
||
|
unsigned maxDepth,
|
||
|
ARRAY(RelVaultNode*) * nodes
|
||
|
) {
|
||
|
if (maxDepth == 0)
|
||
|
return;
|
||
|
|
||
|
RelVaultNodeLink * link;
|
||
|
link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link)) {
|
||
|
nodes->Add(link->node);
|
||
|
link->node->IncRef();
|
||
|
link->node->GetChildNodesIncRef(
|
||
|
maxDepth - 1,
|
||
|
nodes
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetChildNodesIncRef (
|
||
|
NetVaultNode * templateNode,
|
||
|
unsigned maxDepth,
|
||
|
ARRAY(RelVaultNode*) * nodes
|
||
|
) {
|
||
|
RelVaultNodeLink * link;
|
||
|
link = state->children.Head();
|
||
|
for (; link; link = state->children.Next(link)) {
|
||
|
if (link->node->Matches(templateNode)) {
|
||
|
nodes->Add(link->node);
|
||
|
link->node->IncRef();
|
||
|
}
|
||
|
link->node->GetChildNodesIncRef(
|
||
|
templateNode,
|
||
|
maxDepth - 1,
|
||
|
nodes
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetChildNodesIncRef (
|
||
|
unsigned nodeType,
|
||
|
unsigned maxDepth,
|
||
|
ARRAY(RelVaultNode*) * nodes
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(nodeType);
|
||
|
GetChildNodesIncRef(
|
||
|
templateNode,
|
||
|
maxDepth,
|
||
|
nodes
|
||
|
);
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::GetChildFolderNodesIncRef (
|
||
|
unsigned folderType,
|
||
|
unsigned maxDepth,
|
||
|
ARRAY(RelVaultNode*) * nodes
|
||
|
) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Folder);
|
||
|
VaultFolderNode fldr(templateNode);
|
||
|
fldr.SetFolderType(folderType);
|
||
|
GetChildNodesIncRef(
|
||
|
templateNode,
|
||
|
maxDepth,
|
||
|
nodes
|
||
|
);
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
unsigned RelVaultNode::GetRefOwnerId (unsigned parentId) {
|
||
|
// find our parents' link to us and return its ownerId
|
||
|
if (RelVaultNodeLink * parentLink = state->parents.Find(parentId))
|
||
|
if (RelVaultNodeLink * childLink = parentLink->node->state->children.Find(nodeId))
|
||
|
return childLink->ownerId;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool RelVaultNode::BeenSeen (unsigned parentId) const {
|
||
|
// find our parents' link to us and return its seen flag
|
||
|
if (RelVaultNodeLink * parentLink = state->parents.Find(parentId))
|
||
|
if (RelVaultNodeLink * childLink = parentLink->node->state->children.Find(nodeId))
|
||
|
return childLink->seen;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::SetSeen (unsigned parentId, bool seen) {
|
||
|
// find our parents' link to us and set its seen flag
|
||
|
if (RelVaultNodeLink * parentLink = state->parents.Find(parentId))
|
||
|
if (RelVaultNodeLink * childLink = parentLink->node->state->children.Find(nodeId))
|
||
|
if (childLink->seen != seen) {
|
||
|
childLink->seen = seen;
|
||
|
NetCliAuthVaultSetSeen(parentId, nodeId, seen);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::Print (const wchar tag[], FStateDump dumpProc, unsigned level) {
|
||
|
wchar str[1024];
|
||
|
StrPrintf(
|
||
|
str,
|
||
|
arrsize(str),
|
||
|
L"%s%*s%*s%u, %S",
|
||
|
tag ? tag : L"",
|
||
|
tag ? 1 : 0,
|
||
|
" ",
|
||
|
level * 2,
|
||
|
" ",
|
||
|
nodeId,
|
||
|
plVault::NodeTypeStr(nodeType, false)
|
||
|
);
|
||
|
|
||
|
NetVaultNodeFieldArray fields(this);
|
||
|
for (qword bit = 1; bit; bit <<= 1) {
|
||
|
if (!(fieldFlags & bit))
|
||
|
continue;
|
||
|
if (bit > fieldFlags)
|
||
|
break;
|
||
|
|
||
|
StrPack(str, L", ", arrsize(str));
|
||
|
StrPack(str, fields.GetFieldName(bit), arrsize(str));
|
||
|
if (fields.GetFieldAddress(bit)) {
|
||
|
StrPack(str, L"=", arrsize(str));
|
||
|
const unsigned chars = StrLen(str);
|
||
|
fields.GetFieldValueString_LCS(bit, str + chars, arrsize(str) - chars * sizeof(str[0]));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dumpProc(nil, str);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void RelVaultNode::PrintTree (FStateDump dumpProc, unsigned level) {
|
||
|
Print(L"", dumpProc, level);
|
||
|
for (RelVaultNodeLink * link = state->children.Head(); link; link = state->children.Next(link))
|
||
|
link->node->PrintTree(dumpProc, level + 1);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * RelVaultNode::GetParentAgeLinkIncRef () {
|
||
|
|
||
|
// this function only makes sense when called on age info nodes
|
||
|
ASSERT(nodeType == plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
RelVaultNode * result = nil;
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
|
||
|
// Get our parent AgeLink node
|
||
|
if (RelVaultNode * rvnLink = GetParentNodeIncRef(templateNode, 1)) {
|
||
|
// Get the next AgeLink node in our parent tree
|
||
|
result = rvnLink->GetParentNodeIncRef(templateNode, 3);
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Callbacks
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultRegisterCallback (VaultCallback * cb) {
|
||
|
IVaultCallback * internal = NEW(IVaultCallback);
|
||
|
internal->cb = cb;
|
||
|
cb->internal = internal;
|
||
|
s_callbacks.Link(internal);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultUnregisterCallback (VaultCallback * cb) {
|
||
|
ASSERT(cb->internal);
|
||
|
DEL(cb->internal);
|
||
|
cb->internal = nil;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Initialize
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultInitialize () {
|
||
|
s_running = true;
|
||
|
|
||
|
NetCliAuthVaultSetRecvNodeChangedHandler(VaultNodeChanged);
|
||
|
NetCliAuthVaultSetRecvNodeAddedHandler(VaultNodeAdded);
|
||
|
NetCliAuthVaultSetRecvNodeRemovedHandler(VaultNodeRemoved);
|
||
|
NetCliAuthVaultSetRecvNodeDeletedHandler(VaultNodeDeleted);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDestroy () {
|
||
|
s_running = false;
|
||
|
|
||
|
NetCliAuthVaultSetRecvNodeChangedHandler(nil);
|
||
|
NetCliAuthVaultSetRecvNodeAddedHandler(nil);
|
||
|
NetCliAuthVaultSetRecvNodeRemovedHandler(nil);
|
||
|
NetCliAuthVaultSetRecvNodeDeletedHandler(nil);
|
||
|
|
||
|
VaultClearDeviceInboxMap();
|
||
|
|
||
|
RelVaultNodeLink * next, * link = s_nodes.Head();
|
||
|
for (; link; link = next) {
|
||
|
next = s_nodes.Next(link);
|
||
|
link->node->state->UnlinkFromRelatives();
|
||
|
DEL(link);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultUpdate () {
|
||
|
SaveDirtyNodes();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Generic Vault Access
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetNode (
|
||
|
unsigned id
|
||
|
) {
|
||
|
RelVaultNodeLink * link = s_nodes.Find(id);
|
||
|
if (link)
|
||
|
return link->node;
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetNode (
|
||
|
NetVaultNode * templateNode
|
||
|
) {
|
||
|
ASSERT(templateNode);
|
||
|
RelVaultNodeLink * link = s_nodes.Head();
|
||
|
while (link) {
|
||
|
if (link->node->Matches(templateNode))
|
||
|
return link->node;
|
||
|
link = s_nodes.Next(link);
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetNodeIncRef (
|
||
|
NetVaultNode * templateNode
|
||
|
) {
|
||
|
if (RelVaultNode * node = GetNode(templateNode)) {
|
||
|
node->IncRef();
|
||
|
return node;
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetNodeIncRef (
|
||
|
unsigned nodeId
|
||
|
) {
|
||
|
if (RelVaultNode * node = GetNode(nodeId)) {
|
||
|
node->IncRef();
|
||
|
return node;
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetNodeIncRef (
|
||
|
unsigned nodeId,
|
||
|
const char reftag[]
|
||
|
) {
|
||
|
if (RelVaultNodeLink * link = s_nodes.Find(nodeId)) {
|
||
|
link->node->IncRef(reftag);
|
||
|
return link->node;
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAddChildNode (
|
||
|
unsigned parentId,
|
||
|
unsigned childId,
|
||
|
unsigned ownerId,
|
||
|
FVaultAddChildNodeCallback callback,
|
||
|
void * param
|
||
|
) {
|
||
|
// Make sure we only do the callback once
|
||
|
bool madeCallback = false;
|
||
|
|
||
|
// Too much of the client relies on the assumption that the node will be immediately
|
||
|
// associated with its parent. THIS SUCKS, because there's no way to guarantee the
|
||
|
// association won't be circular (the db checks this in a comprehensive way).
|
||
|
// Because the client depends on this so much, we just link 'em together here if
|
||
|
// we have both of them present locally.
|
||
|
// This directly affects: New clothing items added to the avatar outfit folder,
|
||
|
// new chronicle entries in some ages, and I'm sure several other situations.
|
||
|
|
||
|
if (RelVaultNodeLink * parentLink = s_nodes.Find(parentId)) {
|
||
|
RelVaultNodeLink * childLink = s_nodes.Find(childId);
|
||
|
if (!childLink) {
|
||
|
childLink = NEWZERO(RelVaultNodeLink)(false, ownerId, childId, NEWZERO(RelVaultNode));
|
||
|
childLink->node->nodeId = childId; // set directly so that the field's dirty flag isn't set
|
||
|
s_nodes.Add(childLink);
|
||
|
}
|
||
|
else if (ownerId) {
|
||
|
childLink->ownerId = ownerId;
|
||
|
}
|
||
|
|
||
|
// We can do a sanity check for a would-be circular link, but it isn't
|
||
|
// authoritative. The db will prevent circular links from entering into
|
||
|
// the persistent state, but because we are hacking in the association
|
||
|
// before the authoritative check, we're risking the local client operating
|
||
|
// on bad, possibly harmful vault state. Not harmful in a national security
|
||
|
// kinda way, but still harmful.
|
||
|
if (parentLink->node->IsChildOf(childId, 255)) {
|
||
|
LogMsg(kLogDebug, L"Node relationship would be circular: p:%u, c:%u", parentId, childId);
|
||
|
// callback now with error code
|
||
|
if (callback)
|
||
|
callback(kNetErrCircularReference, param);
|
||
|
}
|
||
|
else if (childLink->node->IsParentOf(parentId, 255)) {
|
||
|
LogMsg(kLogDebug, L"Node relationship would be circular: p:%u, c:%u", parentId, childId);
|
||
|
// callback now with error code
|
||
|
if (callback)
|
||
|
callback(kNetErrCircularReference, param);
|
||
|
}
|
||
|
else {
|
||
|
NetVaultNodeRef refs[] = {
|
||
|
{ parentId, childId, ownerId }
|
||
|
};
|
||
|
|
||
|
ARRAY(unsigned) newNodeIds;
|
||
|
ARRAY(unsigned) existingNodeIds;
|
||
|
|
||
|
BuildNodeTree(refs, arrsize(refs), &newNodeIds, &existingNodeIds);
|
||
|
|
||
|
if (!childLink->node->nodeType || !parentLink->node->nodeType) {
|
||
|
// One or more nodes need to be fetched before the callback is made
|
||
|
AddChildNodeFetchTrans * trans = NEWZERO(AddChildNodeFetchTrans);
|
||
|
trans->callback = callback;
|
||
|
trans->cbParam = param;
|
||
|
if (!childLink->node->nodeType) {
|
||
|
AtomicAdd(&trans->opCount, 1);
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
childId,
|
||
|
AddChildNodeFetchTrans::VaultNodeFetched,
|
||
|
trans
|
||
|
);
|
||
|
AtomicAdd(&trans->opCount, 1);
|
||
|
NetCliAuthVaultFetchNodeRefs(
|
||
|
childId,
|
||
|
AddChildNodeFetchTrans::VaultNodeRefsFetched,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
if (!parentLink->node->nodeType) {
|
||
|
AtomicAdd(&trans->opCount, 1);
|
||
|
NetCliAuthVaultNodeFetch(
|
||
|
parentId,
|
||
|
AddChildNodeFetchTrans::VaultNodeFetched,
|
||
|
trans
|
||
|
);
|
||
|
AtomicAdd(&trans->opCount, 1);
|
||
|
NetCliAuthVaultFetchNodeRefs(
|
||
|
parentId,
|
||
|
AddChildNodeFetchTrans::VaultNodeRefsFetched,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// We have both nodes already, so make the callback now.
|
||
|
if (callback) {
|
||
|
callback(kNetSuccess, param);
|
||
|
madeCallback = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// Parent doesn't exist locally (and we may not want it to), just make the callback now.
|
||
|
if (callback) {
|
||
|
callback(kNetSuccess, param);
|
||
|
madeCallback = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Send it on up to the vault. The db server filters out duplicate and
|
||
|
// circular node relationships. We send the request up even if we think
|
||
|
// the relationship would be circular since the db does a universal
|
||
|
// check and is the only real authority in this matter.
|
||
|
NetCliAuthVaultNodeAdd(
|
||
|
parentId,
|
||
|
childId,
|
||
|
ownerId,
|
||
|
madeCallback ? nil : callback,
|
||
|
madeCallback ? nil : param
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultAddChildNodeAndWait {
|
||
|
|
||
|
struct _AddChildNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _AddChildNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_AddChildNodeParam * param = (_AddChildNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultAddChildNodeAndWait
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAddChildNodeAndWait (
|
||
|
unsigned parentId,
|
||
|
unsigned childId,
|
||
|
unsigned ownerId
|
||
|
) {
|
||
|
using namespace _VaultAddChildNodeAndWait;
|
||
|
|
||
|
_AddChildNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
parentId,
|
||
|
childId,
|
||
|
ownerId,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result))
|
||
|
LogMsg(kLogError, L"VaultAddChildNodeAndWait: Failed to add child node: p:%u,c:%u. %s", parentId, childId, NetErrorToString(param.result));
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultRemoveChildNode (
|
||
|
unsigned parentId,
|
||
|
unsigned childId,
|
||
|
FVaultRemoveChildNodeCallback callback,
|
||
|
void * param
|
||
|
) {
|
||
|
for (;;) {
|
||
|
// Unlink 'em locally, if we can
|
||
|
RelVaultNodeLink * parentLink = s_nodes.Find(parentId);
|
||
|
if (!parentLink)
|
||
|
break;
|
||
|
|
||
|
RelVaultNodeLink * childLink = s_nodes.Find(childId);
|
||
|
if (!childLink)
|
||
|
break;
|
||
|
|
||
|
if (parentLink->node->IsParentOf(childId, 1)) {
|
||
|
// We have the relationship, so make the callbacks
|
||
|
for (IVaultCallback * cb = s_callbacks.Head(); cb; cb = s_callbacks.Next(cb))
|
||
|
cb->cb->RemovingChildNode(parentLink->node, childLink->node);
|
||
|
}
|
||
|
|
||
|
parentLink->node->state->Unlink(childLink->node);
|
||
|
childLink->node->state->Unlink(parentLink->node);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Send it on up to the vault
|
||
|
NetCliAuthVaultNodeRemove(
|
||
|
parentId,
|
||
|
childId,
|
||
|
callback,
|
||
|
param
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultSetNodeSeen (
|
||
|
unsigned nodeId,
|
||
|
bool seen
|
||
|
) {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDeleteNode (
|
||
|
unsigned nodeId
|
||
|
) {
|
||
|
// Send request up to vault. We will remove it locally upon notification of deletion.
|
||
|
NetCliAuthVaultNodeDelete(nodeId);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultPublishNode (
|
||
|
unsigned nodeId,
|
||
|
const wchar deviceName[]
|
||
|
) {
|
||
|
RelVaultNode * rvn;
|
||
|
|
||
|
rvn = VaultAgeGetDeviceInboxIncRef(deviceName);
|
||
|
if (!rvn) {
|
||
|
LogMsg(kLogDebug, L"Failed to find inbox for device %s, adding it on-the-fly", deviceName);
|
||
|
VaultAgeSetDeviceInboxAndWaitIncRef(deviceName, DEFAULT_DEVICE_INBOX);
|
||
|
|
||
|
rvn = VaultAgeGetDeviceInboxIncRef(deviceName);
|
||
|
if (!rvn) {
|
||
|
LogMsg(kLogDebug, L"Failed to add inbox to device %s on-the-fly", deviceName);
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VaultAddChildNode(rvn->nodeId, nodeId, VaultGetPlayerId(), nil, nil);
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultSendNode (
|
||
|
RelVaultNode* srcNode,
|
||
|
unsigned dstPlayerId
|
||
|
) {
|
||
|
NetCliAuthVaultNodeSave(srcNode, nil, nil);
|
||
|
NetCliAuthVaultSendNode(srcNode->nodeId, dstPlayerId);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCreateNode (
|
||
|
NetVaultNode * templateNode,
|
||
|
FVaultCreateNodeCallback callback,
|
||
|
void * state,
|
||
|
void * param
|
||
|
) {
|
||
|
VaultCreateNodeTrans * trans = NEWZERO(VaultCreateNodeTrans);
|
||
|
trans->callback = callback;
|
||
|
trans->state = state;
|
||
|
trans->param = param;
|
||
|
|
||
|
if (RelVaultNode * age = VaultGetAgeNodeIncRef()) {
|
||
|
VaultAgeNode access(age);
|
||
|
if (!(templateNode->fieldFlags & NetVaultNode::kCreateAgeName))
|
||
|
templateNode->SetCreateAgeName(access.ageName);
|
||
|
if (!(templateNode->fieldFlags & NetVaultNode::kCreateAgeUuid))
|
||
|
templateNode->SetCreateAgeUuid(access.ageInstUuid);
|
||
|
age->DecRef();
|
||
|
}
|
||
|
|
||
|
NetCliAuthVaultNodeCreate(
|
||
|
templateNode,
|
||
|
VaultCreateNodeTrans::VaultNodeCreated,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCreateNode (
|
||
|
plVault::NodeTypes nodeType,
|
||
|
FVaultCreateNodeCallback callback,
|
||
|
void * state,
|
||
|
void * param
|
||
|
) {
|
||
|
RelVaultNode * templateNode = NEWZERO(RelVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(nodeType);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
templateNode,
|
||
|
callback,
|
||
|
state,
|
||
|
param
|
||
|
);
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultCreateNodeAndWaitIncRef {
|
||
|
|
||
|
struct _CreateNodeParam {
|
||
|
RelVaultNode * node;
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _CreateNodeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
RelVaultNode * node
|
||
|
) {
|
||
|
_CreateNodeParam * param = (_CreateNodeParam *)vparam;
|
||
|
param->node = node;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultCreateNodeAndWaitIncRef
|
||
|
|
||
|
RelVaultNode * VaultCreateNodeAndWaitIncRef (
|
||
|
NetVaultNode * templateNode,
|
||
|
ENetError * result
|
||
|
) {
|
||
|
using namespace _VaultCreateNodeAndWaitIncRef;
|
||
|
|
||
|
_CreateNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
templateNode,
|
||
|
_CreateNodeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
*result = param.result;
|
||
|
if (IS_NET_SUCCESS(param.result))
|
||
|
param.node->IncRef();
|
||
|
return param.node;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultCreateNodeAndWaitIncRef (
|
||
|
plVault::NodeTypes nodeType,
|
||
|
ENetError * result
|
||
|
) {
|
||
|
RelVaultNode * node;
|
||
|
RelVaultNode * templateNode = NEWZERO(RelVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(nodeType);
|
||
|
|
||
|
node = VaultCreateNodeAndWaitIncRef(templateNode, result);
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
return node;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultForceSaveNodeAndWait {
|
||
|
|
||
|
struct _SaveNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _SaveNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_SaveNodeParam * param = (_SaveNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultForceSaveNodeAndWait
|
||
|
|
||
|
void VaultForceSaveNodeAndWait (
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
using namespace _VaultForceSaveNodeAndWait;
|
||
|
|
||
|
_SaveNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
NetCliAuthVaultNodeSave(
|
||
|
node,
|
||
|
_SaveNodeCallback,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultFindNodes (
|
||
|
NetVaultNode * templateNode,
|
||
|
FVaultFindNodeCallback callback,
|
||
|
void * param
|
||
|
) {
|
||
|
VaultFindNodeTrans * trans = NEWZERO(VaultFindNodeTrans);
|
||
|
trans->callback = callback;
|
||
|
trans->param = param;
|
||
|
|
||
|
NetCliAuthVaultNodeFind(
|
||
|
templateNode,
|
||
|
VaultFindNodeTrans::VaultNodeFound,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultFindNodesAndWait {
|
||
|
struct _FindNodeParam {
|
||
|
ARRAY(unsigned) nodeIds;
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _FindNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam,
|
||
|
unsigned nodeIdCount,
|
||
|
const unsigned nodeIds[]
|
||
|
) {
|
||
|
_FindNodeParam * param = (_FindNodeParam *)vparam;
|
||
|
param->nodeIds.Set(nodeIds, nodeIdCount);
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultFindNodesAndWait
|
||
|
|
||
|
void VaultFindNodesAndWait (
|
||
|
NetVaultNode * templateNode,
|
||
|
ARRAY(unsigned) * nodeIds
|
||
|
) {
|
||
|
using namespace _VaultFindNodesAndWait;
|
||
|
|
||
|
_FindNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
NetCliAuthVaultNodeFind(
|
||
|
templateNode,
|
||
|
_FindNodeCallback,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_SUCCESS(param.result))
|
||
|
nodeIds->Add(param.nodeIds.Ptr(), param.nodeIds.Count());
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultLocalFindNodes (
|
||
|
NetVaultNode * templateNode,
|
||
|
ARRAY(unsigned) * nodeIds
|
||
|
) {
|
||
|
for (RelVaultNodeLink * link = s_nodes.Head(); link != nil; link = s_nodes.Next(link)) {
|
||
|
if (link->node->Matches(templateNode))
|
||
|
nodeIds->Add(link->node->nodeId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultFetchNodesAndWait {
|
||
|
|
||
|
static void _VaultNodeFetched (
|
||
|
ENetError result,
|
||
|
void * param,
|
||
|
NetVaultNode * node
|
||
|
) {
|
||
|
::VaultNodeFetched(result, nil, node);
|
||
|
|
||
|
long * nodeCount = (long *)param;
|
||
|
AtomicAdd(nodeCount, -1);
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultFetchNodesAndWait
|
||
|
|
||
|
void VaultFetchNodesAndWait (
|
||
|
const unsigned nodeIds[],
|
||
|
unsigned count,
|
||
|
bool force
|
||
|
) {
|
||
|
using namespace _VaultFetchNodesAndWait;
|
||
|
|
||
|
long nodeCount = (long)count;
|
||
|
|
||
|
for (unsigned i = 0; i < count; ++i) {
|
||
|
|
||
|
if (!force) {
|
||
|
// See if we already have this node
|
||
|
if (RelVaultNodeLink * link = s_nodes.Find(nodeIds[i])) {
|
||
|
AtomicAdd(&nodeCount, -1);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Start fetching the node
|
||
|
NetCliAuthVaultNodeFetch(nodeIds[i], _VaultNodeFetched, (void *)&nodeCount);
|
||
|
}
|
||
|
|
||
|
while (nodeCount) {
|
||
|
NetClientUpdate();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultInitAge (
|
||
|
const plAgeInfoStruct * info,
|
||
|
const Uuid & parentAgeInstId, // optional
|
||
|
FVaultInitAgeCallback callback,
|
||
|
void * state,
|
||
|
void * param
|
||
|
) {
|
||
|
VaultAgeInitTrans * trans = NEWZERO(VaultAgeInitTrans);
|
||
|
trans->callback = callback;
|
||
|
trans->cbState = state;
|
||
|
trans->cbParam = param;
|
||
|
|
||
|
wchar ageFilename[MAX_PATH];
|
||
|
wchar ageInstName[MAX_PATH];
|
||
|
wchar ageUserName[MAX_PATH];
|
||
|
wchar ageDesc[1024];
|
||
|
|
||
|
StrToUnicode(ageFilename, info->GetAgeFilename(), arrsize(ageFilename));
|
||
|
StrToUnicode(ageInstName, info->GetAgeInstanceName(), arrsize(ageInstName));
|
||
|
StrToUnicode(ageUserName, info->GetAgeUserDefinedName(), arrsize(ageUserName));
|
||
|
StrToUnicode(ageDesc, info->GetAgeDescription(), arrsize(ageDesc));
|
||
|
|
||
|
NetCliAuthVaultInitAge(
|
||
|
(Uuid)*info->GetAgeInstanceGuid(),
|
||
|
parentAgeInstId,
|
||
|
ageFilename,
|
||
|
ageInstName,
|
||
|
ageUserName,
|
||
|
ageDesc,
|
||
|
info->GetAgeSequenceNumber(),
|
||
|
info->GetAgeLanguage(),
|
||
|
VaultAgeInitTrans::AgeInitCallback,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Player Vault Access
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetPlayerNode () {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_VNodeMgrPlayer);
|
||
|
if (NetCommGetPlayer())
|
||
|
templateNode->SetNodeId(NetCommGetPlayer()->playerInt);
|
||
|
RelVaultNode * result = GetNode(templateNode);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
unsigned VaultGetPlayerId () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->nodeId;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetPlayerNodeIncRef () {
|
||
|
if (RelVaultNode * rvnPlr = GetPlayerNode()) {
|
||
|
rvnPlr->IncRef();
|
||
|
return rvnPlr;
|
||
|
}
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetPlayerInfoNodeIncRef () {
|
||
|
RelVaultNode * rvnPlr = VaultGetPlayerNodeIncRef();
|
||
|
if (!rvnPlr)
|
||
|
return nil;
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_PlayerInfo);
|
||
|
VaultPlayerInfoNode plrInfo(templateNode);
|
||
|
plrInfo.SetPlayerId(rvnPlr->nodeId);
|
||
|
|
||
|
rvnPlr->DecRef();
|
||
|
|
||
|
RelVaultNode * result = nil;
|
||
|
if (RelVaultNode * rvnPlrInfo = rvnPlr->GetChildNodeIncRef(templateNode, 1))
|
||
|
result = rvnPlrInfo;
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAvatarOutfitFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kAvatarOutfitFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAvatarClosetFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kAvatarClosetFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetChronicleFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kChronicleFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgesIOwnFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildAgeInfoListNodeIncRef(plVault::kAgesIOwnFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgesICanVisitFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildAgeInfoListNodeIncRef(plVault::kAgesICanVisitFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetPlayerInboxFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetPlayerNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kInboxFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetLinkToMyNeighborhood (plAgeLinkStruct * link) {
|
||
|
RelVaultNode * rvnFldr = VaultGetAgesIOwnFolderIncRef();
|
||
|
if (!rvnFldr)
|
||
|
return false;
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, kNeighborhoodAgeFilename, arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
RelVaultNode * node;
|
||
|
if (nil != (node = rvnFldr->GetChildNodeIncRef(templateNode, 2))) {
|
||
|
VaultAgeInfoNode info(node);
|
||
|
info.CopyTo(link->GetAgeInfo());
|
||
|
node->DecRef();
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
|
||
|
return node != nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetLinkToMyPersonalAge (plAgeLinkStruct * link) {
|
||
|
RelVaultNode * rvnFldr = VaultGetAgesIOwnFolderIncRef();
|
||
|
if (!rvnFldr)
|
||
|
return false;
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, kPersonalAgeFilename, arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
RelVaultNode * node;
|
||
|
if (nil != (node = rvnFldr->GetChildNodeIncRef(templateNode, 2))) {
|
||
|
VaultAgeInfoNode info(node);
|
||
|
info.CopyTo(link->GetAgeInfo());
|
||
|
node->DecRef();
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
|
||
|
return node != nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetLinkToCity (plAgeLinkStruct * link) {
|
||
|
RelVaultNode * rvnFldr = VaultGetAgesIOwnFolderIncRef();
|
||
|
if (!rvnFldr)
|
||
|
return false;
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, kCityAgeFilename, arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
RelVaultNode * node;
|
||
|
if (nil != (node = rvnFldr->GetChildNodeIncRef(templateNode, 2))) {
|
||
|
VaultAgeInfoNode info(node);
|
||
|
info.CopyTo(link->GetAgeInfo());
|
||
|
node->DecRef();
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
|
||
|
return node != nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetOwnedAgeLinkIncRef (const plAgeInfoStruct * info) {
|
||
|
|
||
|
RelVaultNode * rvnLink = nil;
|
||
|
|
||
|
if (RelVaultNode * rvnFldr = VaultGetAgesIOwnFolderIncRef()) {
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
if (info->HasAgeFilename()) {
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
}
|
||
|
if (info->HasAgeInstanceGuid()) {
|
||
|
ageInfo.SetAgeInstGuid(*info->GetAgeInstanceGuid());
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnFldr->GetChildNodeIncRef(templateNode, 2)) {
|
||
|
templateNode->fieldFlags = 0;
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
rvnLink = rvnInfo->GetParentNodeIncRef(templateNode, 1);
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return rvnLink;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetOwnedAgeInfoIncRef (const plAgeInfoStruct * info) {
|
||
|
|
||
|
RelVaultNode * rvnInfo = nil;
|
||
|
|
||
|
if (RelVaultNode * rvnFldr = VaultGetAgesIOwnFolderIncRef()) {
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
if (info->HasAgeFilename()) {
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
}
|
||
|
if (info->HasAgeInstanceGuid()) {
|
||
|
ageInfo.SetAgeInstGuid(*info->GetAgeInstanceGuid());
|
||
|
}
|
||
|
|
||
|
rvnInfo = rvnFldr->GetChildNodeIncRef(templateNode, 2);
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return rvnInfo;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetOwnedAgeLink (const plAgeInfoStruct * info, plAgeLinkStruct * link) {
|
||
|
bool result = false;
|
||
|
if (RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(info)) {
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode ageInfo(rvnInfo);
|
||
|
ageInfo.CopyTo(link->GetAgeInfo());
|
||
|
rvnInfo->DecRef();
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultFindOrCreateChildAgeLinkAndWait (const wchar ownedAgeName[], const plAgeInfoStruct * info, plAgeLinkStruct * link) {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAddOwnedAgeSpawnPoint (const Uuid & ageInstId, const plSpawnPointInfo & spawnPt) {
|
||
|
|
||
|
RelVaultNode * fldr = nil;
|
||
|
RelVaultNode * link = nil;
|
||
|
|
||
|
for (;;) {
|
||
|
if (!spawnPt.GetName())
|
||
|
break;
|
||
|
if (!spawnPt.GetTitle())
|
||
|
break;
|
||
|
if (!StrLen(spawnPt.GetName()))
|
||
|
break;
|
||
|
if (!StrLen(spawnPt.GetTitle()))
|
||
|
break;
|
||
|
|
||
|
fldr = VaultGetAgesIOwnFolderIncRef();
|
||
|
if (!fldr)
|
||
|
break;
|
||
|
|
||
|
ARRAY(unsigned) nodeIds;
|
||
|
fldr->GetChildNodeIds(&nodeIds, 1);
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
VaultAgeInfoNode access(templateNode);
|
||
|
access.SetAgeInstGuid(ageInstId);
|
||
|
|
||
|
for (unsigned i = 0; i < nodeIds.Count(); ++i) {
|
||
|
link = VaultGetNodeIncRef(nodeIds[i]);
|
||
|
if (!link)
|
||
|
continue;
|
||
|
if (RelVaultNode * info = link->GetChildNodeIncRef(templateNode, 1)) {
|
||
|
VaultAgeLinkNode access(link);
|
||
|
access.AddSpawnPoint(spawnPt);
|
||
|
info->DecRef();
|
||
|
link->DecRef();
|
||
|
link = nil;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (fldr)
|
||
|
fldr->DecRef();
|
||
|
if (link)
|
||
|
link->DecRef();
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultSetOwnedAgePublicAndWait (const plAgeInfoStruct * info, bool publicOrNot) {
|
||
|
if (RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(info)) {
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
10 years ago
|
VaultSetAgePublicAndWait(rvnInfo, publicOrNot);
|
||
14 years ago
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
10 years ago
|
//============================================================================
|
||
|
bool VaultSetAgePublicAndWait (NetVaultNode * ageInfoNode, bool publicOrNot) {
|
||
|
NetCliAuthSetAgePublic(ageInfoNode->nodeId, publicOrNot);
|
||
|
|
||
|
VaultAgeInfoNode access(ageInfoNode);
|
||
|
char ageName[MAX_PATH];
|
||
|
StrToAnsi(ageName, access.ageFilename, arrsize(ageName));
|
||
|
|
||
|
plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
|
||
|
if (publicOrNot)
|
||
|
msg->SetType(plVaultNotifyMsg::kPublicAgeCreated);
|
||
|
else
|
||
|
msg->SetType(plVaultNotifyMsg::kPublicAgeRemoved);
|
||
|
msg->SetResultCode(true);
|
||
|
msg->GetArgs()->AddString(plNetCommon::VaultTaskArgs::kAgeFilename, ageName);
|
||
|
msg->Send();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
14 years ago
|
//============================================================================
|
||
|
RelVaultNode * VaultGetVisitAgeLinkIncRef (const plAgeInfoStruct * info) {
|
||
|
RelVaultNode * rvnLink = nil;
|
||
|
|
||
|
if (RelVaultNode * rvnFldr = VaultGetAgesICanVisitFolderIncRef()) {
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
if (info->HasAgeFilename()) {
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
}
|
||
|
if (info->HasAgeInstanceGuid()) {
|
||
|
ageInfo.SetAgeInstGuid(*info->GetAgeInstanceGuid());
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnFldr->GetChildNodeIncRef(templateNode, 2)) {
|
||
|
templateNode->fieldFlags = 0;
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
rvnLink = rvnInfo->GetParentNodeIncRef(templateNode, 1);
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return rvnLink;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetVisitAgeLink (const plAgeInfoStruct * info, class plAgeLinkStruct * link) {
|
||
|
RelVaultNode * rvn = VaultGetVisitAgeLinkIncRef(info);
|
||
|
if (!rvn)
|
||
|
return false;
|
||
|
|
||
|
VaultAgeLinkNode ageLink(rvn);
|
||
|
ageLink.CopyTo(link);
|
||
|
|
||
|
rvn->DecRef();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultRegisterOwnedAgeAndWait {
|
||
|
|
||
|
struct _InitAgeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned ageInfoId;
|
||
|
};
|
||
|
static void _InitAgeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
) {
|
||
|
_InitAgeParam * param = (_InitAgeParam *)vparam;
|
||
|
param->ageInfoId = ageInfoVaultId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _FetchVaultParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _FetchVaultCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_FetchVaultParam * param = (_FetchVaultParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _CreateNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned nodeId;
|
||
|
};
|
||
|
static void _CreateNodeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
RelVaultNode * node
|
||
|
) {
|
||
|
_CreateNodeParam * param = (_CreateNodeParam *)vparam;
|
||
|
if (IS_NET_SUCCESS(result))
|
||
|
param->nodeId = node->nodeId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _AddChildNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _AddChildNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_AddChildNodeParam * param = (_AddChildNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultRegisterOwnedAgeAndWait
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultRegisterOwnedAgeAndWait (const plAgeLinkStruct * link) {
|
||
|
using namespace _VaultRegisterOwnedAgeAndWait;
|
||
|
|
||
|
unsigned ageLinkId = 0;
|
||
|
unsigned ageInfoId;
|
||
|
unsigned agesIOwnId;
|
||
|
|
||
|
bool result = false;
|
||
|
|
||
|
for (;;) {
|
||
|
if (RelVaultNode * rvn = VaultGetAgesIOwnFolderIncRef()) {
|
||
|
agesIOwnId = rvn->nodeId;
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
else {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to get player's AgesIOwnFolder");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check for existing link to this age
|
||
|
plAgeLinkStruct existing;
|
||
|
if (VaultGetOwnedAgeLink(link->GetAgeInfo(), &existing)) {
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
{ // Init age vault
|
||
|
_InitAgeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultInitAge(
|
||
|
link->GetAgeInfo(),
|
||
|
kNilGuid,
|
||
|
_InitAgeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to init age %S", link->GetAgeInfo()->GetAgeFilename());
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ageInfoId = param.ageInfoId;
|
||
|
}
|
||
|
|
||
|
{ // Create age link
|
||
|
_CreateNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
plVault::kNodeType_AgeLink,
|
||
|
_CreateNodeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed create age link node");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ageLinkId = param.nodeId;
|
||
|
}
|
||
|
|
||
|
{ // Fetch age info node tree
|
||
|
_FetchVaultParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultDownload(
|
||
|
L"RegisterOwnedAge",
|
||
|
ageInfoId,
|
||
|
_FetchVaultCallback,
|
||
|
¶m,
|
||
|
nil,
|
||
|
nil
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to download age info vault");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{ // Link:
|
||
|
// ageLink to player's bookshelf folder
|
||
|
// ageInfo to ageLink
|
||
|
// playerInfo to ageOwners
|
||
|
_AddChildNodeParam param1;
|
||
|
_AddChildNodeParam param2;
|
||
|
_AddChildNodeParam param3;
|
||
|
ZERO(param1);
|
||
|
ZERO(param2);
|
||
|
ZERO(param3);
|
||
|
|
||
|
unsigned ageOwnersId = 0;
|
||
|
if (RelVaultNode * rvnAgeInfo = VaultGetNodeIncRef(ageInfoId)) {
|
||
|
if (RelVaultNode * rvnAgeOwners = rvnAgeInfo->GetChildPlayerInfoListNodeIncRef(plVault::kAgeOwnersFolder, 1)) {
|
||
|
ageOwnersId = rvnAgeOwners->nodeId;
|
||
|
rvnAgeOwners->DecRef();
|
||
|
}
|
||
|
rvnAgeInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
unsigned playerInfoId = 0;
|
||
|
if (RelVaultNode * rvnPlayerInfo = VaultGetPlayerInfoNodeIncRef()) {
|
||
|
playerInfoId = rvnPlayerInfo->nodeId;
|
||
|
rvnPlayerInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
agesIOwnId,
|
||
|
ageLinkId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m1
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageLinkId,
|
||
|
ageInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m2
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageOwnersId,
|
||
|
playerInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m3
|
||
|
);
|
||
|
|
||
|
while (!param1.complete && !param2.complete && !param3.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param1.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to add link to player's bookshelf");
|
||
|
break;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param2.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to add info to link");
|
||
|
break;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param3.result)) {
|
||
|
LogMsg(kLogError, L"RegisterOwnedAge: Failed to add playerInfo to ageOwners");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy the link spawn point to the link node
|
||
|
if (RelVaultNode * node = VaultGetNodeIncRef(ageLinkId)) {
|
||
|
VaultAgeLinkNode access(node);
|
||
|
access.AddSpawnPoint(link->SpawnPoint());
|
||
|
node->DecRef();
|
||
|
}
|
||
|
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
|
||
|
msg->SetType(plVaultNotifyMsg::kRegisteredOwnedAge);
|
||
|
msg->SetResultCode(result);
|
||
|
msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, ageLinkId);
|
||
|
msg->Send();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultRegisterVisitAgeAndWait {
|
||
|
|
||
|
struct _InitAgeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned ageInfoId;
|
||
|
};
|
||
|
static void _InitAgeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
) {
|
||
|
_InitAgeParam * param = (_InitAgeParam *)vparam;
|
||
|
param->ageInfoId = ageInfoVaultId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _FetchVaultParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _FetchVaultCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_FetchVaultParam * param = (_FetchVaultParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _CreateNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned nodeId;
|
||
|
};
|
||
|
static void _CreateNodeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
RelVaultNode * node
|
||
|
) {
|
||
|
_CreateNodeParam * param = (_CreateNodeParam *)vparam;
|
||
|
if (IS_NET_SUCCESS(result))
|
||
|
param->nodeId = node->nodeId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _AddChildNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _AddChildNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_AddChildNodeParam * param = (_AddChildNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultRegisterVisitAgeAndWait
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultRegisterVisitAgeAndWait (const plAgeLinkStruct * link) {
|
||
|
using namespace _VaultRegisterVisitAgeAndWait;
|
||
|
|
||
|
unsigned ageLinkId = 0;
|
||
|
unsigned ageInfoId;
|
||
|
unsigned agesICanVisitId;
|
||
|
|
||
|
bool result = false;
|
||
|
for (;;) {
|
||
|
if (RelVaultNode * rvn = VaultGetAgesICanVisitFolderIncRef()) {
|
||
|
agesICanVisitId = rvn->nodeId;
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
else {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to get player's AgesICanVisitFolder");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Check for existing link to this age
|
||
|
plAgeLinkStruct existing;
|
||
|
if (VaultGetVisitAgeLink(link->GetAgeInfo(), &existing)) {
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
{ // Init age vault
|
||
|
_InitAgeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultInitAge(
|
||
|
link->GetAgeInfo(),
|
||
|
kNilGuid,
|
||
|
_InitAgeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to init age %S", link->GetAgeInfo()->GetAgeFilename());
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ageInfoId = param.ageInfoId;
|
||
|
}
|
||
|
|
||
|
{ // Create age link
|
||
|
_CreateNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
plVault::kNodeType_AgeLink,
|
||
|
_CreateNodeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed create age link node");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
ageLinkId = param.nodeId;
|
||
|
}
|
||
|
|
||
|
{ // Fetch age info node tree
|
||
|
_FetchVaultParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultDownload(
|
||
|
L"RegisterVisitAge",
|
||
|
ageInfoId,
|
||
|
_FetchVaultCallback,
|
||
|
¶m,
|
||
|
nil,
|
||
|
nil
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to download age info vault");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{ // Link:
|
||
|
// ageLink to player's "can visit" folder
|
||
|
// ageInfo to ageLink
|
||
|
_AddChildNodeParam param1;
|
||
|
_AddChildNodeParam param2;
|
||
|
_AddChildNodeParam param3;
|
||
|
ZERO(param1);
|
||
|
ZERO(param2);
|
||
|
ZERO(param3);
|
||
|
|
||
|
unsigned ageVisitorsId = 0;
|
||
|
if (RelVaultNode * rvnAgeInfo = VaultGetNodeIncRef(ageInfoId)) {
|
||
|
if (RelVaultNode * rvnAgeVisitors = rvnAgeInfo->GetChildPlayerInfoListNodeIncRef(plVault::kCanVisitFolder, 1)) {
|
||
|
ageVisitorsId = rvnAgeVisitors->nodeId;
|
||
|
rvnAgeVisitors->DecRef();
|
||
|
}
|
||
|
rvnAgeInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
unsigned playerInfoId = 0;
|
||
|
if (RelVaultNode * rvnPlayerInfo = VaultGetPlayerInfoNodeIncRef()) {
|
||
|
playerInfoId = rvnPlayerInfo->nodeId;
|
||
|
rvnPlayerInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
agesICanVisitId,
|
||
|
ageLinkId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m1
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageLinkId,
|
||
|
ageInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m2
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageVisitorsId,
|
||
|
playerInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m3
|
||
|
);
|
||
|
|
||
|
while (!param1.complete && !param2.complete && !param3.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param1.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to add link to folder");
|
||
|
break;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param2.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to add info to link");
|
||
|
break;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param3.result)) {
|
||
|
LogMsg(kLogError, L"RegisterVisitAge: Failed to add playerInfo to canVisit folder");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Copy the link spawn point to the link node
|
||
|
if (RelVaultNode * node = VaultGetNodeIncRef(ageLinkId)) {
|
||
|
VaultAgeLinkNode access(node);
|
||
|
access.AddSpawnPoint(link->SpawnPoint());
|
||
|
node->DecRef();
|
||
|
}
|
||
|
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
|
||
|
msg->SetType(plVaultNotifyMsg::kRegisteredVisitAge);
|
||
|
msg->SetResultCode(result);
|
||
|
msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, ageLinkId);
|
||
|
msg->Send();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultUnregisterOwnedAgeAndWait (const plAgeInfoStruct * info) {
|
||
|
|
||
|
unsigned ageLinkId = 0;
|
||
|
unsigned agesIOwnId;
|
||
|
|
||
|
bool result = false;
|
||
|
for (;;) {
|
||
|
RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(info);
|
||
|
if (!rvnLink) {
|
||
|
result = true;
|
||
|
break; // we aren't an owner of the age, just return true
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvn = VaultGetAgesIOwnFolderIncRef()) {
|
||
|
agesIOwnId = rvn->nodeId;
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
else {
|
||
|
LogMsg(kLogError, L"UnregisterOwnedAge: Failed to get player's AgesIOwnFolder");
|
||
|
break; // something's wrong with the player vault, it doesn't have a required folder node
|
||
|
}
|
||
|
|
||
|
ageLinkId = rvnLink->nodeId;
|
||
|
|
||
|
unsigned ageOwnersId = 0;
|
||
|
if (RelVaultNode * rvnAgeInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
if (RelVaultNode * rvnAgeOwners = rvnAgeInfo->GetChildPlayerInfoListNodeIncRef(plVault::kAgeOwnersFolder, 1)) {
|
||
|
ageOwnersId = rvnAgeOwners->nodeId;
|
||
|
rvnAgeOwners->DecRef();
|
||
|
}
|
||
|
rvnAgeInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
unsigned playerInfoId = 0;
|
||
|
if (RelVaultNode * rvnPlayerInfo = VaultGetPlayerInfoNodeIncRef()) {
|
||
|
playerInfoId = rvnPlayerInfo->nodeId;
|
||
|
rvnPlayerInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
|
||
|
// remove our playerInfo from the ageOwners folder
|
||
|
VaultRemoveChildNode(ageOwnersId, playerInfoId, nil, nil);
|
||
|
|
||
|
// remove the link from AgesIOwn folder
|
||
|
VaultRemoveChildNode(agesIOwnId, ageLinkId, nil, nil);
|
||
|
|
||
|
// delete the link node since link nodes aren't shared with anyone else
|
||
|
// VaultDeleteNode(ageLinkId);
|
||
|
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
|
||
|
msg->SetType(plVaultNotifyMsg::kUnRegisteredOwnedAge);
|
||
|
msg->SetResultCode(result);
|
||
|
msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, ageLinkId);
|
||
|
msg->Send();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultUnregisterVisitAgeAndWait (const plAgeInfoStruct * info) {
|
||
|
|
||
|
unsigned ageLinkId = 0;
|
||
|
unsigned agesICanVisitId;
|
||
|
|
||
|
bool result = false;
|
||
|
for (;;) {
|
||
|
RelVaultNode * rvnLink = VaultGetVisitAgeLinkIncRef(info);
|
||
|
if (!rvnLink) {
|
||
|
result = true;
|
||
|
break; // we aren't an owner of the age, just return true
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvn = VaultGetAgesICanVisitFolderIncRef()) {
|
||
|
agesICanVisitId = rvn->nodeId;
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
else {
|
||
|
LogMsg(kLogError, L"UnregisterOwnedAge: Failed to get player's AgesICanVisitFolder");
|
||
|
break; // something's wrong with the player vault, it doesn't have a required folder node
|
||
|
}
|
||
|
|
||
|
ageLinkId = rvnLink->nodeId;
|
||
|
|
||
|
unsigned ageVisitorsId = 0;
|
||
|
if (RelVaultNode * rvnAgeInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
if (RelVaultNode * rvnAgeVisitors = rvnAgeInfo->GetChildPlayerInfoListNodeIncRef(plVault::kCanVisitFolder, 1)) {
|
||
|
ageVisitorsId = rvnAgeVisitors->nodeId;
|
||
|
rvnAgeVisitors->DecRef();
|
||
|
}
|
||
|
rvnAgeInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
unsigned playerInfoId = 0;
|
||
|
if (RelVaultNode * rvnPlayerInfo = VaultGetPlayerInfoNodeIncRef()) {
|
||
|
playerInfoId = rvnPlayerInfo->nodeId;
|
||
|
rvnPlayerInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
|
||
|
// remove our playerInfo from the ageVisitors folder
|
||
|
VaultRemoveChildNode(ageVisitorsId, playerInfoId, nil, nil);
|
||
|
|
||
|
// remove the link from AgesICanVisit folder
|
||
|
VaultRemoveChildNode(agesICanVisitId, ageLinkId, nil, nil);
|
||
|
|
||
|
// delete the link node since link nodes aren't shared with anyone else
|
||
|
// VaultDeleteNode(ageLinkId);
|
||
|
|
||
|
result = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
plVaultNotifyMsg * msg = NEWZERO(plVaultNotifyMsg);
|
||
|
msg->SetType(plVaultNotifyMsg::kUnRegisteredVisitAge);
|
||
|
msg->SetResultCode(result);
|
||
|
msg->GetArgs()->AddInt(plNetCommon::VaultTaskArgs::kAgeLinkNode, ageLinkId);
|
||
|
msg->Send();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultFindChronicleEntryIncRef (const wchar entryName[], int entryType) {
|
||
|
|
||
|
RelVaultNode * result = nil;
|
||
|
if (RelVaultNode * rvnFldr = GetChildFolderNode(GetPlayerNode(), plVault::kChronicleFolder, 1)) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Chronicle);
|
||
|
VaultChronicleNode chrn(templateNode);
|
||
|
chrn.SetEntryName(entryName);
|
||
|
if (entryType >= 0)
|
||
|
chrn.SetEntryType(entryType);
|
||
|
if (RelVaultNode * rvnChrn = rvnFldr->GetChildNodeIncRef(templateNode, 255))
|
||
|
result = rvnChrn;
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultHasChronicleEntry (const wchar entryName[], int entryType) {
|
||
|
if (RelVaultNode * rvn = VaultFindChronicleEntryIncRef(entryName, entryType)) {
|
||
|
rvn->DecRef();
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAddChronicleEntryAndWait (
|
||
|
const wchar entryName[],
|
||
|
int entryType,
|
||
|
const wchar entryValue[]
|
||
|
) {
|
||
|
if (RelVaultNode * rvnChrn = VaultFindChronicleEntryIncRef(entryName, entryType)) {
|
||
|
VaultChronicleNode chrnNode(rvnChrn);
|
||
|
chrnNode.SetEntryValue(entryValue);
|
||
|
}
|
||
|
else if (RelVaultNode * rvnFldr = GetChildFolderNode(GetPlayerNode(), plVault::kChronicleFolder, 1)) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Chronicle);
|
||
|
VaultChronicleNode chrnNode(templateNode);
|
||
|
chrnNode.SetEntryName(entryName);
|
||
|
chrnNode.SetEntryType(entryType);
|
||
|
chrnNode.SetEntryValue(entryValue);
|
||
|
ENetError result;
|
||
|
if (RelVaultNode * rvnChrn = VaultCreateNodeAndWaitIncRef(templateNode, &result)) {
|
||
|
VaultAddChildNode(rvnFldr->nodeId, rvnChrn->nodeId, 0, nil, nil);
|
||
|
rvnChrn->DecRef();
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmIgnoringPlayer (unsigned playerId) {
|
||
|
bool retval = false;
|
||
|
if (RelVaultNode * rvnFldr = GetChildPlayerInfoListNode(GetPlayerNode(), plVault::kIgnoreListFolder, 1)) {
|
||
|
rvnFldr->IncRef();
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_PlayerInfo);
|
||
|
VaultPlayerInfoNode pinfoNode(templateNode);
|
||
|
pinfoNode.SetPlayerId(playerId);
|
||
|
|
||
|
if (RelVaultNode * rvnPlayerInfo = rvnFldr->GetChildNodeIncRef(templateNode, 1)) {
|
||
|
retval = true;
|
||
|
rvnPlayerInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
unsigned VaultGetKILevel () {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return pfKIMsg::kNanoKI;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultGetCCRStatus () {
|
||
|
bool retval = false;
|
||
|
if (RelVaultNode * rvnSystem = VaultGetSystemNodeIncRef()) {
|
||
|
VaultSystemNode sysNode(rvnSystem);
|
||
|
retval = (sysNode.ccrStatus != 0);
|
||
|
|
||
|
rvnSystem->DecRef();
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultSetCCRStatus (bool online) {
|
||
|
bool retval = false;
|
||
|
if (RelVaultNode * rvnSystem = VaultGetSystemNodeIncRef()) {
|
||
|
VaultSystemNode sysNode(rvnSystem);
|
||
|
sysNode.SetCCRStatus(online ? 1 : 0);
|
||
|
|
||
|
rvnSystem->DecRef();
|
||
|
retval = true;
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDump (const wchar tag[], unsigned vaultId, FStateDump dumpProc) {
|
||
|
LogMsg(kLogDebug, L"<---- ID:%u, Begin Vault%*s%s ---->", vaultId, tag ? 1 : 0, L" ", tag);
|
||
|
|
||
|
if (RelVaultNode * rvn = GetNode(vaultId))
|
||
|
rvn->PrintTree(dumpProc, 0);
|
||
|
|
||
|
LogMsg(kLogDebug, L"<---- ID:%u, End Vault%*s%s ---->", vaultId, tag ? 1 : 0, L" ", tag);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDump (const wchar tag[], unsigned vaultId) {
|
||
|
VaultDump (tag, vaultId, LogDumpProc);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmInMyPersonalAge () {
|
||
|
bool result = false;
|
||
|
|
||
|
plAgeInfoStruct info;
|
||
|
info.SetAgeFilename(kPersonalAgeFilename);
|
||
|
|
||
|
if (RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(&info)) {
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode ageInfo(rvnInfo);
|
||
|
|
||
|
if (RelVaultNode* currentAgeInfoNode = VaultGetAgeInfoNodeIncRef()) {
|
||
|
VaultAgeInfoNode curAgeInfo(currentAgeInfoNode);
|
||
|
|
||
|
if (ageInfo.ageInstUuid == curAgeInfo.ageInstUuid)
|
||
|
result = true;
|
||
|
|
||
|
currentAgeInfoNode->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmInMyNeighborhoodAge () {
|
||
|
bool result = false;
|
||
|
|
||
|
plAgeInfoStruct info;
|
||
|
info.SetAgeFilename(kNeighborhoodAgeFilename);
|
||
|
|
||
|
if (RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(&info)) {
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode ageInfo(rvnInfo);
|
||
|
|
||
|
if (RelVaultNode* currentAgeInfoNode = VaultGetAgeInfoNodeIncRef()) {
|
||
|
VaultAgeInfoNode curAgeInfo(currentAgeInfoNode);
|
||
|
|
||
|
if (ageInfo.ageInstUuid == curAgeInfo.ageInstUuid)
|
||
|
result = true;
|
||
|
|
||
|
currentAgeInfoNode->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmOwnerOfCurrentAge () {
|
||
|
bool result = false;
|
||
|
|
||
|
if (RelVaultNode* currentAgeInfoNode = VaultGetAgeInfoNodeIncRef()) {
|
||
|
VaultAgeInfoNode curAgeInfo(currentAgeInfoNode);
|
||
|
|
||
|
char* ageFilename = StrDupToAnsi(curAgeInfo.ageFilename);
|
||
|
|
||
|
plAgeInfoStruct info;
|
||
|
info.SetAgeFilename(ageFilename);
|
||
|
|
||
|
FREE(ageFilename);
|
||
|
|
||
|
if (RelVaultNode * rvnLink = VaultGetOwnedAgeLinkIncRef(&info)) {
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode ageInfo(rvnInfo);
|
||
|
|
||
|
if (ageInfo.ageInstUuid == curAgeInfo.ageInstUuid)
|
||
|
result = true;
|
||
|
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
currentAgeInfoNode->DecRef();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmCzarOfCurrentAge () {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmOwnerOfAge (const Uuid & ageInstId) {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAmCzarOfAge (const Uuid & ageInstId) {
|
||
|
// hsAssert(false, "eric, implement me");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultRegisterMTStationAndWait (
|
||
|
const wchar stationName[],
|
||
|
const wchar linkBackSpawnPtObjName[]
|
||
|
) {
|
||
|
plAgeInfoStruct info;
|
||
|
info.SetAgeFilename(kCityAgeFilename);
|
||
|
if (RelVaultNode * rvn = VaultGetOwnedAgeLinkIncRef(&info)) {
|
||
|
char title[MAX_PATH], spawnPt[MAX_PATH];
|
||
|
StrToAnsi(title, stationName, arrsize(title));
|
||
|
StrToAnsi(spawnPt, linkBackSpawnPtObjName, arrsize(spawnPt));
|
||
|
VaultAgeLinkNode link(rvn);
|
||
|
link.AddSpawnPoint(plSpawnPointInfo(title, spawnPt));
|
||
|
rvn->DecRef();
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultProcessVisitNote(RelVaultNode * rvnVisit) {
|
||
|
if (RelVaultNode * rvnInbox = VaultGetPlayerInboxFolderIncRef()) {
|
||
|
rvnVisit->IncRef();
|
||
|
|
||
|
VaultTextNoteNode visitAcc(rvnVisit);
|
||
|
plAgeLinkStruct link;
|
||
|
if (visitAcc.GetVisitInfo(link.GetAgeInfo())) {
|
||
|
// Add it to our "ages i can visit" folder
|
||
|
VaultRegisterVisitAgeAndWait(&link);
|
||
|
}
|
||
|
// remove it from the inbox
|
||
|
VaultRemoveChildNode(rvnInbox->nodeId, rvnVisit->nodeId, nil, nil);
|
||
|
rvnVisit->DecRef();
|
||
|
|
||
|
rvnInbox->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultProcessUnvisitNote(RelVaultNode * rvnUnVisit) {
|
||
|
if (RelVaultNode * rvnInbox = VaultGetPlayerInboxFolderIncRef()) {
|
||
|
rvnUnVisit->IncRef();
|
||
|
VaultTextNoteNode unvisitAcc(rvnUnVisit);
|
||
|
plAgeInfoStruct info;
|
||
|
if (unvisitAcc.GetVisitInfo(&info)) {
|
||
|
// Remove it from our "ages i can visit" folder
|
||
|
VaultUnregisterVisitAgeAndWait(&info);
|
||
|
}
|
||
|
// remove it from the inbox
|
||
|
VaultRemoveChildNode(rvnInbox->nodeId, rvnUnVisit->nodeId, nil, nil);
|
||
|
rvnUnVisit->DecRef();
|
||
|
|
||
|
rvnInbox->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultProcessPlayerInbox () {
|
||
|
if (RelVaultNode * rvnInbox = VaultGetPlayerInboxFolderIncRef()) {
|
||
|
{ // Process new visit requests
|
||
|
ARRAY(RelVaultNode*) visits;
|
||
|
RelVaultNode * templateNode = NEWZERO(RelVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_TextNote);
|
||
|
VaultTextNoteNode tmpAcc(templateNode);
|
||
|
tmpAcc.SetNoteType(plVault::kNoteType_Visit);
|
||
|
rvnInbox->GetChildNodesIncRef(templateNode, 1, &visits);
|
||
|
templateNode->DecRef();
|
||
|
|
||
|
for (unsigned i = 0; i < visits.Count(); ++i) {
|
||
|
RelVaultNode * rvnVisit = visits[i];
|
||
|
VaultTextNoteNode visitAcc(rvnVisit);
|
||
|
plAgeLinkStruct link;
|
||
|
if (visitAcc.GetVisitInfo(link.GetAgeInfo())) {
|
||
|
// Add it to our "ages i can visit" folder
|
||
|
VaultRegisterVisitAgeAndWait(&link);
|
||
|
}
|
||
|
// remove it from the inbox
|
||
|
VaultRemoveChildNode(rvnInbox->nodeId, rvnVisit->nodeId, nil, nil);
|
||
|
rvnVisit->DecRef();
|
||
|
}
|
||
|
}
|
||
|
{ // Process new unvisit requests
|
||
|
ARRAY(RelVaultNode*) unvisits;
|
||
|
RelVaultNode * templateNode = NEWZERO(RelVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_TextNote);
|
||
|
VaultTextNoteNode tmpAcc(templateNode);
|
||
|
tmpAcc.SetNoteType(plVault::kNoteType_UnVisit);
|
||
|
rvnInbox->GetChildNodesIncRef(templateNode, 1, &unvisits);
|
||
|
templateNode->DecRef();
|
||
|
|
||
|
for (unsigned i = 0; i < unvisits.Count(); ++i) {
|
||
|
RelVaultNode * rvnUnVisit = unvisits[i];
|
||
|
VaultTextNoteNode unvisitAcc(rvnUnVisit);
|
||
|
plAgeInfoStruct info;
|
||
|
if (unvisitAcc.GetVisitInfo(&info)) {
|
||
|
// Remove it from our "ages i can visit" folder
|
||
|
VaultUnregisterVisitAgeAndWait(&info);
|
||
|
}
|
||
|
// remove it from the inbox
|
||
|
VaultRemoveChildNode(rvnInbox->nodeId, rvnUnVisit->nodeId, nil, nil);
|
||
|
rvnUnVisit->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
rvnInbox->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Age Vault Access
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetAgeNode () {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_VNodeMgrAge);
|
||
|
if (NetCommGetAge())
|
||
|
templateNode->SetNodeId(NetCommGetAge()->ageVaultId);
|
||
|
RelVaultNode * result = GetNode(templateNode);
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeNodeIncRef () {
|
||
|
RelVaultNode * result = nil;
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_VNodeMgrAge);
|
||
|
if (NetCommGetAge())
|
||
|
templateNode->SetNodeId(NetCommGetAge()->ageVaultId);
|
||
|
if (RelVaultNode * rvnAge = VaultGetNodeIncRef(templateNode))
|
||
|
result = rvnAge;
|
||
|
templateNode->DecRef();
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
static RelVaultNode * GetAgeInfoNode () {
|
||
|
RelVaultNode * rvnAge = VaultGetAgeNodeIncRef();
|
||
|
if (!rvnAge)
|
||
|
return nil;
|
||
|
|
||
|
RelVaultNode * result = nil;
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
templateNode->SetCreatorId(rvnAge->nodeId);
|
||
|
|
||
|
if (RelVaultNode * rvnAgeInfo = rvnAge->GetChildNodeIncRef(templateNode, 1)) {
|
||
|
rvnAgeInfo->DecRef();
|
||
|
result = rvnAgeInfo;
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnAge->DecRef();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeInfoNodeIncRef () {
|
||
|
RelVaultNode * rvnAge = VaultGetAgeNodeIncRef();
|
||
|
if (!rvnAge)
|
||
|
return nil;
|
||
|
|
||
|
RelVaultNode * result = nil;
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
templateNode->SetCreatorId(rvnAge->nodeId);
|
||
|
|
||
|
if (RelVaultNode * rvnAgeInfo = rvnAge->GetChildNodeIncRef(templateNode, 1))
|
||
|
result = rvnAgeInfo;
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnAge->DecRef();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeChronicleFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kChronicleFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeDevicesFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeNode())
|
||
|
return rvn->GetChildFolderNodeIncRef(plVault::kAgeDevicesFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeAgeOwnersFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeInfoNode())
|
||
|
return rvn->GetChildPlayerInfoListNodeIncRef(plVault::kAgeOwnersFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeCanVisitFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeInfoNode())
|
||
|
return rvn->GetChildPlayerInfoListNodeIncRef(plVault::kCanVisitFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgePeopleIKnowAboutFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeNode())
|
||
|
return rvn->GetChildPlayerInfoListNodeIncRef(plVault::kPeopleIKnowAboutFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgeSubAgesFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeNode())
|
||
|
return rvn->GetChildAgeInfoListNodeIncRef(plVault::kSubAgesFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetAgePublicAgesFolderIncRef () {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultAgeGetBookshelfFolderIncRef () {
|
||
|
if (RelVaultNode * rvn = GetAgeNode())
|
||
|
return rvn->GetChildAgeInfoListNodeIncRef(plVault::kAgesIOwnFolder, 1);
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultFindAgeSubAgeLinkIncRef (const plAgeInfoStruct * info) {
|
||
|
RelVaultNode * rvnLink = nil;
|
||
|
|
||
|
if (RelVaultNode * rvnFldr = VaultGetAgeSubAgesFolderIncRef()) {
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnFldr->GetChildNodeIncRef(templateNode, 2)) {
|
||
|
templateNode->fieldFlags = 0;
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
rvnLink = rvnInfo->GetParentNodeIncRef(templateNode, 1);
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return rvnLink;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultFindAgeChronicleEntryIncRef (const wchar entryName[], int entryType) {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return nil;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAddAgeChronicleEntry (
|
||
|
const wchar entryName[],
|
||
|
int entryType,
|
||
|
const wchar entryValue[]
|
||
|
) {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultAgeAddDeviceAndWaitIncRef (const wchar deviceName[]) {
|
||
|
if (RelVaultNode * existing = VaultAgeGetDeviceIncRef(deviceName))
|
||
|
return existing;
|
||
|
|
||
|
RelVaultNode * device = nil;
|
||
|
RelVaultNode * folder = nil;
|
||
|
|
||
|
for (;;) {
|
||
|
folder = VaultGetAgeDevicesFolderIncRef();
|
||
|
if (!folder)
|
||
|
break;
|
||
|
|
||
|
ENetError result;
|
||
|
device = VaultCreateNodeAndWaitIncRef(plVault::kNodeType_TextNote, &result);
|
||
|
if (!device)
|
||
|
break;
|
||
|
|
||
|
VaultTextNoteNode access(device);
|
||
|
access.SetNoteType(plVault::kNoteType_Device);
|
||
|
access.SetNoteTitle(deviceName);
|
||
|
|
||
|
VaultAddChildNodeAndWait(folder->nodeId, device->nodeId, 0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (folder)
|
||
|
folder->DecRef();
|
||
|
|
||
|
return device;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAgeRemoveDevice (const wchar deviceName[]) {
|
||
|
if (RelVaultNode * folder = VaultGetAgeDevicesFolderIncRef()) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_TextNote);
|
||
|
VaultTextNoteNode access(templateNode);
|
||
|
access.SetNoteTitle(deviceName);
|
||
|
if (RelVaultNode * device = folder->GetChildNodeIncRef(templateNode, 1)) {
|
||
|
VaultRemoveChildNode(folder->nodeId, device->nodeId, nil, nil);
|
||
|
device->DecRef();
|
||
|
|
||
|
if (DeviceInbox * deviceInbox = s_ageDeviceInboxes.Find(CHashKeyStr(deviceName)))
|
||
|
DEL(device);
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
folder->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAgeHasDevice (const wchar deviceName[]) {
|
||
|
bool found = false;
|
||
|
if (RelVaultNode * folder = VaultGetAgeDevicesFolderIncRef()) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_TextNote);
|
||
|
VaultTextNoteNode access(templateNode);
|
||
|
access.SetNoteTitle(deviceName);
|
||
|
if (RelVaultNode * device = folder->GetChildNodeIncRef(templateNode, 1)) {
|
||
|
found = true;
|
||
|
device->DecRef();
|
||
|
}
|
||
|
templateNode->DecRef();
|
||
|
folder->DecRef();
|
||
|
}
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultAgeGetDeviceIncRef (const wchar deviceName[]) {
|
||
|
RelVaultNode * result = nil;
|
||
|
if (RelVaultNode * folder = VaultGetAgeDevicesFolderIncRef()) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_TextNote);
|
||
|
VaultTextNoteNode access(templateNode);
|
||
|
access.SetNoteTitle(deviceName);
|
||
|
if (RelVaultNode * device = folder->GetChildNodeIncRef(templateNode, 1))
|
||
|
result = device;
|
||
|
templateNode->DecRef();
|
||
|
folder->DecRef();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultAgeSetDeviceInboxAndWaitIncRef (const wchar deviceName[], const wchar inboxName[]) {
|
||
|
DeviceInbox * devInbox = s_ageDeviceInboxes.Find(CHashKeyStr(deviceName));
|
||
|
if (devInbox) {
|
||
|
StrCopy(devInbox->inboxName, inboxName, arrsize(devInbox->inboxName));
|
||
|
}
|
||
|
else {
|
||
|
devInbox = NEWZERO(DeviceInbox)(deviceName, inboxName);
|
||
|
s_ageDeviceInboxes.Add(devInbox);
|
||
|
}
|
||
|
|
||
|
// if we found the inbox or its a global inbox then return here, otherwise if its the default inbox and
|
||
|
// it wasn't found then continue on and create the inbox
|
||
|
RelVaultNode * existing = VaultAgeGetDeviceInboxIncRef(deviceName);
|
||
|
if (existing || StrCmp(inboxName, DEFAULT_DEVICE_INBOX) != 0)
|
||
|
return existing;
|
||
|
|
||
|
RelVaultNode * device = nil;
|
||
|
RelVaultNode * inbox = nil;
|
||
|
|
||
|
for (;;) {
|
||
|
device = VaultAgeGetDeviceIncRef(deviceName);
|
||
|
if (!device)
|
||
|
break;
|
||
|
|
||
|
ENetError result;
|
||
|
inbox = VaultCreateNodeAndWaitIncRef(plVault::kNodeType_Folder, &result);
|
||
|
if (!inbox)
|
||
|
break;
|
||
|
|
||
|
VaultFolderNode access(inbox);
|
||
|
access.SetFolderName(inboxName);
|
||
|
access.SetFolderType(plVault::kDeviceInboxFolder);
|
||
|
|
||
|
VaultAddChildNodeAndWait(device->nodeId, inbox->nodeId, 0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return inbox;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultAgeGetDeviceInboxIncRef (const wchar deviceName[]) {
|
||
|
RelVaultNode * result = nil;
|
||
|
DeviceInbox * devInbox = s_ageDeviceInboxes.Find(CHashKeyStr(deviceName));
|
||
|
|
||
|
if (devInbox)
|
||
|
{
|
||
|
RelVaultNode * parentNode = nil;
|
||
|
const wchar * inboxName = nil;
|
||
|
|
||
|
if (StrCmp(devInbox->inboxName, DEFAULT_DEVICE_INBOX) == 0) {
|
||
|
parentNode = VaultAgeGetDeviceIncRef(deviceName);
|
||
|
}
|
||
|
else {
|
||
|
parentNode = VaultGetGlobalInboxIncRef();
|
||
|
}
|
||
|
|
||
|
if (parentNode) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Folder);
|
||
|
VaultFolderNode access(templateNode);
|
||
|
access.SetFolderType(plVault::kDeviceInboxFolder);
|
||
|
access.SetFolderName(devInbox->inboxName);
|
||
|
result = parentNode->GetChildNodeIncRef(templateNode, 1);
|
||
|
templateNode->DecRef();
|
||
|
parentNode->DecRef();
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultClearDeviceInboxMap () {
|
||
|
while (DeviceInbox * inbox = s_ageDeviceInboxes.Head()) {
|
||
|
DEL(inbox);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAgeGetAgeSDL (plStateDataRecord * out) {
|
||
|
bool result = false;
|
||
|
if (RelVaultNode * rvn = VaultGetAgeInfoNodeIncRef()) {
|
||
|
if (RelVaultNode * rvnSdl = rvn->GetChildNodeIncRef(plVault::kNodeType_SDL, 1)) {
|
||
|
VaultSDLNode sdl(rvnSdl);
|
||
|
result = sdl.GetStateDataRecord(out, plSDL::kKeepDirty);
|
||
|
if (!result) {
|
||
|
sdl.InitStateDataRecord(sdl.sdlName);
|
||
|
result = sdl.GetStateDataRecord(out, plSDL::kKeepDirty);
|
||
|
}
|
||
|
rvnSdl->DecRef();
|
||
|
}
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultAgeUpdateAgeSDL (const plStateDataRecord * rec) {
|
||
|
if (RelVaultNode * rvn = VaultGetAgeInfoNodeIncRef()) {
|
||
|
if (RelVaultNode * rvnSdl = rvn->GetChildNodeIncRef(plVault::kNodeType_SDL, 1)) {
|
||
|
VaultSDLNode sdl(rvnSdl);
|
||
|
sdl.SetStateDataRecord(rec, plSDL::kDirtyOnly | plSDL::kTimeStampOnRead);
|
||
|
rvnSdl->DecRef();
|
||
|
}
|
||
|
rvn->DecRef();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
unsigned VaultAgeGetAgeTime () {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetSubAgeLinkIncRef (const plAgeInfoStruct * info) {
|
||
|
|
||
|
RelVaultNode * rvnLink = nil;
|
||
|
|
||
|
if (RelVaultNode * rvnFldr = VaultGetAgeSubAgesFolderIncRef()) {
|
||
|
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnFldr->GetChildNodeIncRef(templateNode, 2)) {
|
||
|
templateNode->fieldFlags = 0;
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
rvnLink = rvnInfo->GetParentNodeIncRef(templateNode, 1);
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnFldr->DecRef();
|
||
|
}
|
||
|
|
||
|
return rvnLink;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAgeGetSubAgeLink (const plAgeInfoStruct * info, plAgeLinkStruct * link) {
|
||
|
bool result = false;
|
||
|
if (RelVaultNode * rvnLink = VaultGetSubAgeLinkIncRef(info)) {
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode ageInfo(rvnInfo);
|
||
|
ageInfo.CopyTo(link->GetAgeInfo());
|
||
|
rvnInfo->DecRef();
|
||
|
result = true;
|
||
|
}
|
||
|
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultCreateSubAgeAndWait {
|
||
|
|
||
|
struct _InitAgeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned ageInfoId;
|
||
|
};
|
||
|
static void _InitAgeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
) {
|
||
|
_InitAgeParam * param = (_InitAgeParam *)vparam;
|
||
|
param->ageInfoId = ageInfoVaultId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _FetchVaultParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _FetchVaultCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_FetchVaultParam * param = (_FetchVaultParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _CreateNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned nodeId;
|
||
|
};
|
||
|
static void _CreateNodeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
RelVaultNode * node
|
||
|
) {
|
||
|
_CreateNodeParam * param = (_CreateNodeParam *)vparam;
|
||
|
if (IS_NET_SUCCESS(result))
|
||
|
param->nodeId = node->nodeId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _AddChildNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _AddChildNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_AddChildNodeParam * param = (_AddChildNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultCreateSubAgeAndWait
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAgeFindOrCreateSubAgeLinkAndWait (
|
||
|
const plAgeInfoStruct * info,
|
||
|
plAgeLinkStruct * link,
|
||
|
const Uuid & parentAgeInstId
|
||
|
) {
|
||
|
if (RelVaultNode * rvnLink = VaultFindAgeSubAgeLinkIncRef(info)) {
|
||
|
VaultAgeLinkNode linkAcc(rvnLink);
|
||
|
linkAcc.CopyTo(link);
|
||
|
if (RelVaultNode * rvnInfo = rvnLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1)) {
|
||
|
VaultAgeInfoNode infoAcc(rvnInfo);
|
||
|
infoAcc.CopyTo(link->GetAgeInfo());
|
||
|
rvnInfo->DecRef();
|
||
|
rvnLink->DecRef();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
using namespace _VaultCreateSubAgeAndWait;
|
||
|
|
||
|
unsigned subAgesId;
|
||
|
unsigned ageInfoId;
|
||
|
unsigned ageLinkId;
|
||
|
|
||
|
if (RelVaultNode * rvnSubAges = VaultGetAgeSubAgesFolderIncRef()) {
|
||
|
subAgesId = rvnSubAges->nodeId;
|
||
|
rvnSubAges->DecRef();
|
||
|
}
|
||
|
else {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed to get ages's SubAges folder");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
{ // Init age vault
|
||
|
_InitAgeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultInitAge(
|
||
|
info,
|
||
|
parentAgeInstId,
|
||
|
_InitAgeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed to init age %S", link->GetAgeInfo()->GetAgeFilename());
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ageInfoId = param.ageInfoId;
|
||
|
}
|
||
|
|
||
|
{ // Create age link
|
||
|
_CreateNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
plVault::kNodeType_AgeLink,
|
||
|
_CreateNodeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed create age link node");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ageLinkId = param.nodeId;
|
||
|
}
|
||
|
|
||
|
{ // Fetch age info node tree
|
||
|
_FetchVaultParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultDownload(
|
||
|
L"CreateSubAge",
|
||
|
ageInfoId,
|
||
|
_FetchVaultCallback,
|
||
|
¶m,
|
||
|
nil,
|
||
|
nil
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed to download age info vault");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{ // Link:
|
||
|
// ageLink to ages's subages folder
|
||
|
// ageInfo to ageLink
|
||
|
_AddChildNodeParam param1;
|
||
|
_AddChildNodeParam param2;
|
||
|
ZERO(param1);
|
||
|
ZERO(param2);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
subAgesId,
|
||
|
ageLinkId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m1
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageLinkId,
|
||
|
ageInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m2
|
||
|
);
|
||
|
|
||
|
while (!param1.complete && !param2.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param1.result)) {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed to add link to ages's subages");
|
||
|
return false;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param2.result)) {
|
||
|
LogMsg(kLogError, L"CreateSubAge: Failed to add info to link");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnLink = VaultGetNodeIncRef(ageLinkId)) {
|
||
|
VaultAgeLinkNode linkAcc(rvnLink);
|
||
|
linkAcc.CopyTo(link);
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = VaultGetNodeIncRef(ageInfoId)) {
|
||
|
VaultAgeInfoNode infoAcc(rvnInfo);
|
||
|
infoAcc.CopyTo(link->GetAgeInfo());
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
//============================================================================
|
||
|
namespace _VaultCreateChildAgeAndWait {
|
||
|
|
||
|
struct _InitAgeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned ageInfoId;
|
||
|
};
|
||
|
static void _InitAgeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
unsigned ageVaultId,
|
||
|
unsigned ageInfoVaultId
|
||
|
) {
|
||
|
_InitAgeParam * param = (_InitAgeParam *)vparam;
|
||
|
param->ageInfoId = ageInfoVaultId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _FetchVaultParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _FetchVaultCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_FetchVaultParam * param = (_FetchVaultParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _CreateNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
unsigned nodeId;
|
||
|
};
|
||
|
static void _CreateNodeCallback (
|
||
|
ENetError result,
|
||
|
void * ,
|
||
|
void * vparam,
|
||
|
RelVaultNode * node
|
||
|
) {
|
||
|
_CreateNodeParam * param = (_CreateNodeParam *)vparam;
|
||
|
if (IS_NET_SUCCESS(result))
|
||
|
param->nodeId = node->nodeId;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
struct _AddChildNodeParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _AddChildNodeCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_AddChildNodeParam * param = (_AddChildNodeParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
} // namespace _VaultCreateChildAgeAndWait
|
||
|
|
||
|
//============================================================================
|
||
|
bool VaultAgeFindOrCreateChildAgeLinkAndWait (
|
||
|
const wchar parentAgeName[],
|
||
|
const plAgeInfoStruct * info,
|
||
|
plAgeLinkStruct * link
|
||
|
) {
|
||
|
using namespace _VaultCreateChildAgeAndWait;
|
||
|
|
||
|
unsigned childAgesId;
|
||
|
unsigned ageInfoId;
|
||
|
unsigned ageLinkId;
|
||
|
|
||
|
{ // Get id of child ages folder
|
||
|
RelVaultNode * rvnAgeInfo = nil;
|
||
|
if (parentAgeName) {
|
||
|
char ansi[MAX_PATH];
|
||
|
StrToAnsi(ansi, parentAgeName, arrsize(ansi));
|
||
|
plAgeInfoStruct pinfo;
|
||
|
pinfo.SetAgeFilename(ansi);
|
||
|
if (RelVaultNode * rvnAgeLink = VaultGetOwnedAgeLinkIncRef(&pinfo)) {
|
||
|
rvnAgeInfo = rvnAgeLink->GetChildNodeIncRef(plVault::kNodeType_AgeInfo, 1);
|
||
|
rvnAgeLink->DecRef();
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
rvnAgeInfo = VaultGetAgeInfoNodeIncRef();
|
||
|
}
|
||
|
|
||
|
if (!rvnAgeInfo) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to get ages's AgeInfo node");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
RelVaultNode * rvnChildAges;
|
||
|
if (nil != (rvnChildAges = rvnAgeInfo->GetChildAgeInfoListNodeIncRef(plVault::kChildAgesFolder, 1))) {
|
||
|
childAgesId = rvnChildAges->nodeId;
|
||
|
}
|
||
|
else {
|
||
|
rvnAgeInfo->DecRef();
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to get ages's ChildAges folder");
|
||
|
return false;
|
||
|
}
|
||
|
rvnAgeInfo->DecRef();
|
||
|
|
||
|
// Check for existing child age in folder
|
||
|
RelVaultNode * rvnLink = nil;
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeInfo);
|
||
|
|
||
|
VaultAgeInfoNode ageInfo(templateNode);
|
||
|
wchar str[MAX_PATH];
|
||
|
StrToUnicode(str, info->GetAgeFilename(), arrsize(str));
|
||
|
ageInfo.SetAgeFilename(str);
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = rvnChildAges->GetChildNodeIncRef(templateNode, 2)) {
|
||
|
templateNode->fieldFlags = 0;
|
||
|
templateNode->SetNodeType(plVault::kNodeType_AgeLink);
|
||
|
rvnLink = rvnInfo->GetParentNodeIncRef(templateNode, 1);
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
templateNode->DecRef();
|
||
|
rvnChildAges->DecRef();
|
||
|
|
||
|
if (rvnLink) {
|
||
|
VaultAgeLinkNode access(rvnLink);
|
||
|
access.CopyTo(link);
|
||
|
rvnLink->DecRef();
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{ // Init age vault
|
||
|
_InitAgeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
Uuid parentAgeInstId;
|
||
|
ZERO(parentAgeInstId);
|
||
|
if (RelVaultNode * rvnAge = VaultGetAgeNodeIncRef()) {
|
||
|
VaultAgeNode access(rvnAge);
|
||
|
parentAgeInstId = access.ageInstUuid;
|
||
|
rvnAge->DecRef();
|
||
|
}
|
||
|
|
||
|
VaultInitAge(
|
||
|
info,
|
||
|
parentAgeInstId,
|
||
|
_InitAgeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to init age %S", link->GetAgeInfo()->GetAgeFilename());
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ageInfoId = param.ageInfoId;
|
||
|
}
|
||
|
|
||
|
{ // Create age link
|
||
|
_CreateNodeParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultCreateNode(
|
||
|
plVault::kNodeType_AgeLink,
|
||
|
_CreateNodeCallback,
|
||
|
nil,
|
||
|
¶m
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed create age link node");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
ageLinkId = param.nodeId;
|
||
|
}
|
||
|
|
||
|
{ // Fetch age info node tree
|
||
|
_FetchVaultParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultDownload(
|
||
|
L"CreateChildAge",
|
||
|
ageInfoId,
|
||
|
_FetchVaultCallback,
|
||
|
¶m,
|
||
|
nil,
|
||
|
nil
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param.result)) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to download age info vault");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
{ // Link:
|
||
|
// ageLink to ages's subages folder
|
||
|
// ageInfo to ageLink
|
||
|
_AddChildNodeParam param1;
|
||
|
_AddChildNodeParam param2;
|
||
|
ZERO(param1);
|
||
|
ZERO(param2);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
childAgesId,
|
||
|
ageLinkId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m1
|
||
|
);
|
||
|
|
||
|
VaultAddChildNode(
|
||
|
ageLinkId,
|
||
|
ageInfoId,
|
||
|
0,
|
||
|
_AddChildNodeCallback,
|
||
|
¶m2
|
||
|
);
|
||
|
|
||
|
while (!param1.complete && !param2.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
|
||
|
if (IS_NET_ERROR(param1.result)) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to add link to ages's subages");
|
||
|
return false;
|
||
|
}
|
||
|
if (IS_NET_ERROR(param2.result)) {
|
||
|
LogMsg(kLogError, L"CreateChildAge: Failed to add info to link");
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnLink = VaultGetNodeIncRef(ageLinkId)) {
|
||
|
VaultAgeLinkNode linkAcc(rvnLink);
|
||
|
linkAcc.CopyTo(link);
|
||
|
rvnLink->DecRef();
|
||
|
}
|
||
|
|
||
|
if (RelVaultNode * rvnInfo = VaultGetNodeIncRef(ageInfoId)) {
|
||
|
VaultAgeInfoNode infoAcc(rvnInfo);
|
||
|
infoAcc.CopyTo(link->GetAgeInfo());
|
||
|
rvnInfo->DecRef();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* CCR Vault Access
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCCRDumpPlayers() {
|
||
|
hsAssert(false, "eric, implement me");
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Vault download
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultDownload (
|
||
|
const wchar tag[],
|
||
|
unsigned vaultId,
|
||
|
FVaultDownloadCallback callback,
|
||
|
void * cbParam,
|
||
|
FVaultProgressCallback progressCallback,
|
||
|
void * cbProgressParam
|
||
|
) {
|
||
|
VaultDownloadTrans * trans = NEWZERO(VaultDownloadTrans);
|
||
|
StrCopy(trans->tag, tag, arrsize(trans->tag));
|
||
|
trans->callback = callback;
|
||
|
trans->cbParam = cbParam;
|
||
|
trans->progressCallback = progressCallback;
|
||
|
trans->cbProgressParam = cbProgressParam;
|
||
|
trans->vaultId = vaultId;
|
||
|
|
||
|
NetCliAuthVaultFetchNodeRefs(
|
||
|
vaultId,
|
||
|
VaultDownloadTrans::VaultNodeRefsFetched,
|
||
|
trans
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
struct _DownloadVaultParam {
|
||
|
ENetError result;
|
||
|
bool complete;
|
||
|
};
|
||
|
static void _DownloadVaultCallback (
|
||
|
ENetError result,
|
||
|
void * vparam
|
||
|
) {
|
||
|
_DownloadVaultParam * param = (_DownloadVaultParam *)vparam;
|
||
|
param->result = result;
|
||
|
param->complete = true;
|
||
|
}
|
||
|
|
||
|
void VaultDownloadAndWait (
|
||
|
const wchar tag[],
|
||
|
unsigned vaultId,
|
||
|
FVaultProgressCallback progressCallback,
|
||
|
void * cbProgressParam
|
||
|
) {
|
||
|
_DownloadVaultParam param;
|
||
|
ZERO(param);
|
||
|
|
||
|
VaultDownload(
|
||
|
tag,
|
||
|
vaultId,
|
||
|
_DownloadVaultCallback,
|
||
|
¶m,
|
||
|
progressCallback,
|
||
|
cbProgressParam
|
||
|
);
|
||
|
|
||
|
while (!param.complete) {
|
||
|
NetClientUpdate();
|
||
|
plgDispatch::Dispatch()->MsgQueueProcess();
|
||
|
AsyncSleep(10);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
void VaultCull (unsigned vaultId) {
|
||
|
// Remove the node from the global table
|
||
|
if (RelVaultNodeLink * link = s_nodes.Find(vaultId)) {
|
||
|
LogMsg(kLogDebug, L"Vault: Culling node %u", link->node->nodeId);
|
||
|
link->node->state->UnlinkFromRelatives();
|
||
|
DEL(link);
|
||
|
}
|
||
|
|
||
|
// Remove all orphaned nodes from the global table
|
||
|
for (RelVaultNodeLink * next, * link = s_nodes.Head(); link; link = next) {
|
||
|
next = s_nodes.Next(link);
|
||
|
|
||
|
if (link->node->nodeType > plVault::kNodeType_VNodeMgrLow && link->node->nodeType < plVault::kNodeType_VNodeMgrHigh)
|
||
|
continue;
|
||
|
|
||
|
ARRAY(unsigned) nodeIds;
|
||
|
link->node->GetRootIds(&nodeIds);
|
||
|
bool foundRoot = false;
|
||
|
for (unsigned i = 0; i < nodeIds.Count(); ++i) {
|
||
|
RelVaultNodeLink * root = s_nodes.Find(nodeIds[i]);
|
||
|
if (root && root->node->nodeType > plVault::kNodeType_VNodeMgrLow && root->node->nodeType < plVault::kNodeType_VNodeMgrHigh) {
|
||
|
foundRoot = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (!foundRoot) {
|
||
|
LogMsg(kLogDebug, L"Vault: Culling node %u", link->node->nodeId);
|
||
|
link->node->state->UnlinkFromRelatives();
|
||
|
DEL(link);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Exports - Vault global node handling
|
||
|
*
|
||
|
***/
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetSystemNodeIncRef () {
|
||
|
RelVaultNode * result = nil;
|
||
|
if (RelVaultNode * player = VaultGetPlayerNodeIncRef()) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_System);
|
||
|
if (RelVaultNode * systemNode = player->GetChildNodeIncRef(templateNode, 1))
|
||
|
result = systemNode;
|
||
|
templateNode->DecRef();
|
||
|
player->DecRef();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
//============================================================================
|
||
|
RelVaultNode * VaultGetGlobalInboxIncRef () {
|
||
|
RelVaultNode * result = nil;
|
||
|
if (RelVaultNode * system = VaultGetSystemNodeIncRef()) {
|
||
|
NetVaultNode * templateNode = NEWZERO(NetVaultNode);
|
||
|
templateNode->IncRef();
|
||
|
templateNode->SetNodeType(plVault::kNodeType_Folder);
|
||
|
VaultFolderNode folder(templateNode);
|
||
|
folder.SetFolderType(plVault::kGlobalInboxFolder);
|
||
|
if (RelVaultNode * inbox = system->GetChildNodeIncRef(templateNode, 1))
|
||
|
result = inbox;
|
||
|
templateNode->DecRef();
|
||
|
system->DecRef();
|
||
|
}
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
#endif // def CLIENT
|