/*==LICENSE==* CyanWorlds.com Engine - MMOG client, server and tools Copyright (C) 2011 Cyan Worlds, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . 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 { HASHLINK(INotifyAfterDownload) link; unsigned parentId; unsigned childId; INotifyAfterDownload (unsigned parentId, unsigned childId) : THashKeyVal(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 { HASHLINK(RelVaultNodeLink) link; RelVaultNode * node; unsigned ownerId; bool seen; RelVaultNodeLink (bool seen, unsigned ownerId, unsigned nodeId, RelVaultNode * node) : THashKeyVal(nodeId) , seen(seen) , ownerId(ownerId) , node(node) { node->IncRef(); } ~RelVaultNodeLink () { node->DecRef(); } }; struct IRelVaultNode { RelVaultNode * node; HASHTABLEDECL( RelVaultNodeLink, THashKeyVal, link ) parents; HASHTABLEDECL( RelVaultNodeLink, THashKeyVal, 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, link ) s_nodes; static LISTDECL( IVaultCallback, link ) s_callbacks; static HASHTABLEDECL( INotifyAfterDownload, THashKeyVal, 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)) { NetCliAuthSetAgePublic(rvnInfo->nodeId, publicOrNot); VaultAgeInfoNode access(rvnInfo); 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(); rvnInfo->DecRef(); } rvnLink->DecRef(); } return true; } //============================================================================ 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