khanat-opennel-code/code/ryzom/client/src/r2/object_factory_client.cpp
2010-05-06 02:08:41 +02:00

380 lines
12 KiB
C++

// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero 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 Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "stdpch.h"
#include "object_factory_client.h"
#include "editor.h"
#include "instance.h"
#include "../interface_v3/lua_ihm.h"
namespace R2
{
///////////////////////////////////////
// CObjectRefIdClient implementation //
///////////////////////////////////////
// ************************************************************************
CObjectRefIdClient::CObjectRefIdClient(const std::string &value) : CObjectRefId(""), _ObserverHandle(CEditor::BadInstanceObserverHandle),
_IndexInParent(-1),
_IndexInParentArray(-1),
_Enabled(true)
{
//nlwarning("# Creating CObjectRefIdClient 0x%x", (int) this);
set("", value);
}
// ************************************************************************
CObjectRefIdClient::~CObjectRefIdClient()
{
if (_Enabled)
{
nlassert(getValue().empty() == (_ObserverHandle == CEditor::BadInstanceObserverHandle));
set("", ""); // force to release the observer
}
}
// ************************************************************************
CObject* CObjectRefIdClient::clone() const
{
//H_AUTO(R2_CObjectRefIdClient_clone)
return new CObjectRefIdClient(getValue());
}
// ************************************************************************
void CObjectRefIdClient::enable(bool enabled)
{
//H_AUTO(R2_CObjectRefIdClient_enable)
if (enabled == _Enabled) return;
_Enabled = enabled;
if (_Enabled)
{
addObserverHandle();
}
else
{
removeObserverHandle();
}
}
// ************************************************************************
void CObjectRefIdClient::removeObserverHandle()
{
//H_AUTO(R2_CObjectRefIdClient_removeObserverHandle)
if (_ObserverHandle != CEditor::BadInstanceObserverHandle)
{
getEditor().removeInstanceObserver(_ObserverHandle);
_ObserverHandle = CEditor::BadInstanceObserverHandle;
}
}
// ************************************************************************
void CObjectRefIdClient::addObserverHandle()
{
//H_AUTO(R2_CObjectRefIdClient_addObserverHandle)
if (!getValue().empty())
{
_ObserverHandle = getEditor().addInstanceObserver(getValue(), this);
}
}
// ************************************************************************
bool CObjectRefIdClient::set(const std::string &key, const std::string & value)
{
//H_AUTO(R2_CObjectRefIdClient_set)
//nlwarning("# Setting CObjectRefIdClient 0x%x value to %s", (int) this, value.c_str());
if (_Enabled)
{
nlassert(getValue().empty() == (_ObserverHandle == CEditor::BadInstanceObserverHandle));
}
if (value == getValue()) return true;
if (_Enabled)
{
removeObserverHandle();
}
bool nodeSet = CObjectRefId::set(key, value);
if (_Enabled)
{
if (!value.empty())
{
_ObserverHandle = getEditor().addInstanceObserver(value, this);
}
nlassert(getValue().empty() == (_ObserverHandle == CEditor::BadInstanceObserverHandle));
}
return nodeSet;
}
// ************************************************************************
void CObjectRefIdClient::onInstanceCreated(CInstance &/* instance */)
{
//H_AUTO(R2_CObjectRefIdClient_onInstanceCreated)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstanceCreated(nameInParent, indexInArray);
}
// ************************************************************************
void CObjectRefIdClient::onInstanceErased(CInstance &/* instance */)
{
//H_AUTO(R2_CObjectRefIdClient_onInstanceErased)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstanceErased(nameInParent, indexInArray);
}
// ************************************************************************
void CObjectRefIdClient::onPreHrcMove(CInstance &/* instance */)
{
//H_AUTO(R2_CObjectRefIdClient_onPreHrcMove)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstancePreHrcMove(nameInParent, indexInArray);
}
// ************************************************************************
void CObjectRefIdClient::onPostHrcMove(CInstance &/* instance */)
{
//H_AUTO(R2_CObjectRefIdClient_onPostHrcMove)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstancePostHrcMove(nameInParent, indexInArray);
}
// ************************************************************************
void CObjectRefIdClient::onInstanceEraseRequest(CInstance &/* instance */)
{
//H_AUTO(R2_CObjectRefIdClient_onInstanceEraseRequest)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstanceEraseRequested(nameInParent, indexInArray);
}
// ************************************************************************
void CObjectRefIdClient::onAttrModified(CInstance &/* instance */, const std::string &modifiedAttrName, sint32 modifiedAttrIndexInArray)
{
//H_AUTO(R2_CObjectRefIdClient_onAttrModified)
if (!_Enabled) return;
std::string nameInParent;
sint32 indexInArray;
getNameInParent(nameInParent, indexInArray); // parent ptr will be updated
if (!_ParentInstance) return;
_ParentInstance->onTargetInstanceAttrModified(nameInParent, indexInArray, modifiedAttrName, modifiedAttrIndexInArray);
}
// ************************************************************************
void CObjectRefIdClient::updateParentInstancePtr() const
{
//H_AUTO(R2_CObjectRefIdClient_updateParentInstancePtr)
_ParentInstance = NULL;
CObject *currParent = this->getParent();
while (currParent)
{
_ParentInstance = getEditor().getInstanceFromObject(currParent);
if (_ParentInstance) break;
currParent = currParent->getParent();
}
}
// ************************************************************************
void CObjectRefIdClient::getNameInParent(std::string &name, sint32 &indexInArray) const
{
//H_AUTO(R2_CObjectRefIdClient_getNameInParent)
if (_IndexInParent != -1 && _ParentInstance)
{
CObjectTable *parentInstanceTable = _ParentInstance->getObjectTable();
// check that index is still valid (true most of the case unless instance has been moved)
if (_IndexInParent <= (sint32) parentInstanceTable->getSize())
{
if (_IndexInParentArray == -1)
{
if (parentInstanceTable->getValue(_IndexInParent) == static_cast<const CObject *>(this))
{
name = parentInstanceTable->getKey(_IndexInParent);
indexInArray = -1;
return;
}
}
else
{
CObject *subObject = parentInstanceTable->getValue(_IndexInParent);
if (subObject->isTable())
{
CObjectTable *subTable = (CObjectTable *) subObject;
if (_IndexInParentArray < (sint32) subTable->getSize())
{
if (subTable->getValue(_IndexInParentArray) == static_cast<const CObject *>(this))
{
name = parentInstanceTable->getKey(_IndexInParent);
indexInArray = _IndexInParentArray;
}
}
}
}
}
}
// must search name in parent (on init or when object is moved)
updateParentInstancePtr();
if (!_ParentInstance)
{
_IndexInParent = -1;
_IndexInParentArray = -1;
name.clear();
indexInArray = -1;
return;
}
CObjectTable *parentInstanceTable = _ParentInstance->getObjectTable();
const CObject *ptrInParent = (parentInstanceTable == this->getParent()) ? static_cast<const CObject *>(this) : this->getParent();
// if instance is the direct parent (e.g object is not in an array of the parent)
for (uint k = 0; k < parentInstanceTable->getSize(); ++k)
{
if (parentInstanceTable->getValue(k) == ptrInParent)
{
_IndexInParent = k;
if (ptrInParent == this)
{
_IndexInParentArray = -1;
indexInArray = -1;
name = parentInstanceTable->getKey(_IndexInParent);
return;
}
else
{
// I'm in an array in my parent, retrieve the index
for (uint l = 0; l < getParent()->getSize(); ++l)
{
if (getParent()->getValue(l) == static_cast<const CObject *>(this))
{
name = parentInstanceTable->getKey(_IndexInParent);
_IndexInParentArray = l;
return;
}
}
}
}
}
// TMP TMP
nlwarning("=========================================");
CLuaIHM::dumpCallStack();
nlwarning("=========================================");
nlwarning("ObservedObject = %s", getValue().c_str());
CInstance *obsInstance = getEditor().getInstanceFromId(getValue().c_str());
nlwarning("ObservedObject instance ptr = %p", obsInstance);
nlwarning("=========================================");
if (obsInstance)
{
obsInstance->getLuaProjection().dump();
CInstance *parent = obsInstance->getParent();
nlwarning("ObservedObject parent instance ptr = %p", parent);
parent->getLuaProjection().dump();
}
Driver->systemMessageBox("Bug catched, please send log.log to vizerie@nevrax.com", "nevrax internal", NL3D::UDriver::okType, NL3D::UDriver::exclamationIcon);
nlassert(0); // not found in parent
}
///////////////////////////////////////
// CObjectTableClient implementation //
///////////////////////////////////////
// ************************************************************************
void CObjectTableClient::pushOnLuaStack(CLuaState &state, CLuaObject &metatable) const
{
//H_AUTO(R2_CObjectTableClient_pushOnLuaStack)
// cache refptr here to avoid costly allocations
CLuaStackChecker lsc(&state, 1);
if (!_Ref.isValid())
{
nlassert(metatable.isValid());
// return a new refptr on the sub table
void *block = state.newUserData(sizeof(TRefPtrConst));
new (block) CObjectTable::TRefPtrConst(this); // create in place
metatable.push();
state.setMetaTable(-2);
_Ref.pop(state);
}
nlassert(_Ref.getLuaState() == &state);
_Ref.push();
}
// ************************************************************************
CObject* CObjectTableClient::clone() const
{
//H_AUTO(R2_CObjectTableClient_clone)
CObjectTableClient *ret = new CObjectTableClient();
// NB : don't copy the reference because there can be only one CObjectTableClient per instance (other copy are for undo/redo or network)
TContainer::const_iterator first(_Value.begin()), last(_Value.end());
for ( ;first != last; ++first )
{
nlassert(first->second);
ret->add(first->first, first->second->clone());
}
ret->setGhost(getGhost());
return ret;
}
// ************************************************************************
CObjectTableClient::CObjectTableClient()
{
}
///////////////////////////////////////
// CClientObjectFactory implementation //
///////////////////////////////////////
// ************************************************************************
CObject* CObjectFactoryClient::newBasic(const std::string & type)
{
//H_AUTO(R2_CObjectFactoryClient_newBasic)
if (type == "RefId")
{
return new CObjectRefIdClient("");
}
else if (type == "Table")
{
return new CObjectTableClient;
}
else
{
return CObjectFactory::newBasic(type);
}
}
// ************************************************************************
CObjectFactoryClient::CObjectFactoryClient(const std::string &prefix) : CObjectFactory(prefix)
{
}
} // R2