Updates to component classes -

Shift from ghosted components to entity-managed for networking
Initial implementation of Systems through the Mesh Component
This commit is contained in:
Areloch 2018-01-28 14:57:02 -06:00
parent 4341428d53
commit 8eb442490a
15 changed files with 706 additions and 312 deletions

View file

@ -47,7 +47,9 @@
#include "T3D/gameBase/std/stdMoveList.h"
#include "T3D/prefab.h"
#include "T3D/gameBase/gameConnection.h"
#include <thread>
//
#include "gfx/sim/debugDraw.h"
//
@ -118,6 +120,8 @@ Entity::Entity()
mInitialized = false;
mLifetimeMS = 0;
mGameObjectAssetId = StringTable->insert("");
}
@ -147,6 +151,10 @@ void Entity::initPersistFields()
endGroup("Transform");
addGroup("Misc");
addField("LifetimeMS", TypeS32, Offset(mLifetimeMS, Entity), "Object world orientation.");
endGroup("Misc");
addGroup("GameObject");
addProtectedField("gameObjectName", TypeGameObjectAssetPtr, Offset(mGameObjectAsset, Entity), &_setGameObject, &defaultProtectedGetFn,
"The asset Id used for the game object this entity is based on.");
@ -231,8 +239,19 @@ bool Entity::onAdd()
addToScene();
//Make sure we get positioned
setMaskBits(TransformMask);
setMaskBits(NamespaceMask);
if (isServerObject())
{
setMaskBits(TransformMask);
setMaskBits(NamespaceMask);
}
else
{
//We can shortcut the initialization here because stuff generally ghosts down in order, and onPostAdd isn't called on ghosts.
onPostAdd();
}
if (mLifetimeMS != 0)
mStartTimeMS = Platform::getRealMilliseconds();
return true;
}
@ -245,6 +264,8 @@ void Entity::onRemove()
onDataSet.removeAll();
mGameObjectAsset.clear();
Parent::onRemove();
}
@ -258,6 +279,27 @@ void Entity::onPostAdd()
mComponents[i]->onComponentAdd();
}
//Set up the networked components
mNetworkedComponents.clear();
for (U32 i = 0; i < mComponents.size(); i++)
{
if (mComponents[i]->isNetworked())
{
NetworkedComponent netComp;
netComp.componentIndex = i;
netComp.updateState = NetworkedComponent::Adding;
netComp.updateMaskBits = -1;
mNetworkedComponents.push_back(netComp);
}
}
if (!mNetworkedComponents.empty())
{
setMaskBits(AddComponentsMask);
setMaskBits(ComponentsUpdateMask);
}
if (isMethod("onAdd"))
Con::executef(this, "onAdd");
}
@ -396,6 +438,14 @@ void Entity::processTick(const Move* move)
mDelta.rot[1] = mRot.asQuatF();
setTransform(getPosition(), mRot);
//Lifetime test
if (mLifetimeMS != 0)
{
S32 currentTime = Platform::getRealMilliseconds();
if (currentTime - mStartTimeMS >= mLifetimeMS)
deleteObject();
}
}
}
@ -446,62 +496,107 @@ U32 Entity::packUpdate(NetConnection *con, U32 mask, BitStream *stream)
mathWrite(*stream, mObjBox);
}
//pass our behaviors around
if (mask & ComponentsMask || mask & InitialUpdateMask)
if (stream->writeFlag(mask & AddComponentsMask))
{
stream->writeFlag(true);
//now, we run through a list of our to-be-sent behaviors and begin sending them
//if any fail, we keep our list and re-queue the mask
S32 componentCount = mToLoadComponents.size();
U32 toAddComponentCount = 0;
//build our 'ready' list
//This requires both the instance and the instances' template to be prepped(if the template hasn't been ghosted,
//then we know we shouldn't be passing the instance's ghosts around yet)
U32 ghostedCompCnt = 0;
for (U32 i = 0; i < componentCount; i++)
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (con->getGhostIndex(mToLoadComponents[i]) != -1)
ghostedCompCnt++;
}
if (ghostedCompCnt != 0)
{
stream->writeFlag(true);
stream->writeFlag(mStartComponentUpdate);
//if not all the behaviors have been ghosted, we'll need another pass
if (ghostedCompCnt != componentCount)
retMask |= ComponentsMask;
//write the currently ghosted behavior count
stream->writeInt(ghostedCompCnt, 16);
for (U32 i = 0; i < mToLoadComponents.size(); i++)
if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
{
//now fetch them and pass the ghost
S32 ghostIndex = con->getGhostIndex(mToLoadComponents[i]);
if (ghostIndex != -1)
{
stream->writeInt(ghostIndex, NetConnection::GhostIdBitSize);
mToLoadComponents.erase(i);
i--;
mStartComponentUpdate = false;
}
toAddComponentCount++;
}
}
else if (componentCount)
//you reaaaaally shouldn't have >255 networked components on a single entity
stream->writeInt(toAddComponentCount, 8);
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
//on the odd chance we have behaviors to ghost, but NONE of them have been yet, just set the flag now
stream->writeFlag(false);
retMask |= ComponentsMask;
NetworkedComponent::UpdateState state = mNetworkedComponents[i].updateState;
if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
{
const char* className = mComponents[mNetworkedComponents[i].componentIndex]->getClassName();
stream->writeString(className, strlen(className));
mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
}
}
else
stream->writeFlag(false);
}
else
stream->writeFlag(false);
if (stream->writeFlag(mask & RemoveComponentsMask))
{
/*U32 toRemoveComponentCount = 0;
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (mNetworkedComponents[i].updateState == NetworkedComponent::Adding)
{
toRemoveComponentCount++;
}
}
//you reaaaaally shouldn't have >255 networked components on a single entity
stream->writeInt(toRemoveComponentCount, 8);
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (mNetworkedComponents[i].updateState == NetworkedComponent::Removing)
{
stream->writeInt(i, 16);
}
}*/
/*for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (mNetworkedComponents[i].updateState == NetworkedComponent::UpdateState::Removing)
{
removeComponent(mComponents[mNetworkedComponents[i].componentIndex], true);
mNetworkedComponents.erase(i);
i--;
}
}*/
}
//Update our components
if (stream->writeFlag(mask & ComponentsUpdateMask))
{
U32 toUpdateComponentCount = 0;
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
{
toUpdateComponentCount++;
}
}
//you reaaaaally shouldn't have >255 networked components on a single entity
stream->writeInt(toUpdateComponentCount, 8);
bool forceUpdate = false;
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
if (mNetworkedComponents[i].updateState == NetworkedComponent::Updating)
{
stream->writeInt(i, 8);
mNetworkedComponents[i].updateMaskBits = mComponents[mNetworkedComponents[i].componentIndex]->packUpdate(con, mNetworkedComponents[i].updateMaskBits, stream);
if (mNetworkedComponents[i].updateMaskBits != 0)
forceUpdate = true;
else
mNetworkedComponents[i].updateState = NetworkedComponent::None;
}
}
//If we have leftover, we need to re-iterate our packing
if (forceUpdate)
setMaskBits(ComponentsUpdateMask);
}
/*if (stream->writeFlag(mask & NamespaceMask))
{
@ -594,25 +689,52 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
resetWorldBox();
}
//AddComponentMask
if (stream->readFlag())
{
//are we passing any behaviors currently?
if (stream->readFlag())
U32 addedComponentCount = stream->readInt(8);
for (U32 i = 0; i < addedComponentCount; i++)
{
//if we've just started the update, clear our behaviors
if (stream->readFlag())
clearComponents(false);
char className[256] = "";
stream->readString(className);
S32 componentCount = stream->readInt(16);
//Change to components, so iterate our list and create any new components
// Well, looks like we have to create a new object.
const char* componentType = className;
for (U32 i = 0; i < componentCount; i++)
ConsoleObject *object = ConsoleObject::create(componentType);
// Finally, set currentNewObject to point to the new one.
Component* newComponent = dynamic_cast<Component *>(object);
if (newComponent)
{
S32 gIndex = stream->readInt(NetConnection::GhostIdBitSize);
addComponent(dynamic_cast<Component*>(con->resolveGhost(gIndex)));
addComponent(newComponent);
}
}
}
//RemoveComponentMask
if (stream->readFlag())
{
}
//ComponentUpdateMask
if (stream->readFlag())
{
U32 updatingComponents = stream->readInt(8);
for (U32 i = 0; i < updatingComponents; i++)
{
U32 updateComponentIndex = stream->readInt(8);
Component* comp = mComponents[updateComponentIndex];
comp->unpackUpdate(con, stream);
}
}
/*if (stream->readFlag())
{
if (stream->readFlag())
@ -640,6 +762,26 @@ void Entity::unpackUpdate(NetConnection *con, BitStream *stream)
}*/
}
void Entity::setComponentNetMask(Component* comp, U32 mask)
{
setMaskBits(Entity::ComponentsUpdateMask);
for (U32 i = 0; i < mNetworkedComponents.size(); i++)
{
U32 netCompId = mComponents[mNetworkedComponents[i].componentIndex]->getId();
U32 compId = comp->getId();
if (netCompId == compId &&
(mNetworkedComponents[i].updateState == NetworkedComponent::None || mNetworkedComponents[i].updateState == NetworkedComponent::Updating))
{
mNetworkedComponents[i].updateState = NetworkedComponent::Updating;
mNetworkedComponents[i].updateMaskBits |= mask;
break;
}
}
}
//Manipulation
void Entity::setTransform(const MatrixF &mat)
{
@ -758,7 +900,11 @@ void Entity::setTransform(Point3F position, RotationF rotation)
// Update the transforms.
Parent::setTransform(newMat);
onTransformSet.trigger(&newMat);
U32 compCount = mComponents.size();
for (U32 i = 0; i < compCount; ++i)
{
mComponents[i]->ownerTransformSet(&newMat);
}
Point3F newPos = newMat.getPosition();
RotationF newRot = newMat;
@ -800,7 +946,11 @@ void Entity::setRenderTransform(Point3F position, RotationF rotation)
Parent::setRenderTransform(newMat);
onTransformSet.trigger(&newMat);
U32 compCount = mComponents.size();
for (U32 i = 0; i < compCount; ++i)
{
mComponents[i]->ownerTransformSet(&newMat);
}
}
}
@ -1155,11 +1305,28 @@ bool Entity::addComponent(Component *comp)
// Register the component with this owner.
comp->setOwner(this);
comp->setIsServerObject(isServerObject());
//if we've already been added and this is being added after the fact(at runtime),
//then just go ahead and call it's onComponentAdd so it can get to work
if (mInitialized)
//if (mInitialized)
{
comp->onComponentAdd();
if (comp->isNetworked())
{
NetworkedComponent netComp;
netComp.componentIndex = mComponents.size() - 1;
netComp.updateState = NetworkedComponent::Adding;
netComp.updateMaskBits = -1;
mNetworkedComponents.push_back(netComp);
setMaskBits(AddComponentsMask);
setMaskBits(ComponentsUpdateMask);
}
}
onComponentAdded.trigger(comp);
return true;
@ -1269,7 +1436,7 @@ Component *Entity::getComponent(String componentType)
Namespace *NS = comp->getNamespace();
//we shouldn't ever go past Component into net object, as we're no longer dealing with component classes
while (dStrcmp(NS->getName(), "NetObject"))
while (dStrcmp(NS->getName(), "SimObject"))
{
String namespaceName = NS->getName();
@ -1497,7 +1664,8 @@ void Entity::notifyComponents(String signalFunction, String argA, String argB, S
void Entity::setComponentsDirty()
{
if (mToLoadComponents.empty())
bool tmp = true;
/*if (mToLoadComponents.empty())
mStartComponentUpdate = true;
//we need to build a list of behaviors that need to be pushed across the network
@ -1522,7 +1690,7 @@ void Entity::setComponentsDirty()
}
}
setMaskBits(ComponentsMask);
setMaskBits(ComponentsMask);*/
}
void Entity::setComponentDirty(Component *comp, bool forceUpdate)
@ -1654,7 +1822,7 @@ ConsoleMethod(Entity, addComponents, void, 2, 2, "() - Add all fielded behaviors
object->addComponents();
}*/
ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavior to the object\n"
ConsoleMethod(Entity, addComponent, bool, 3, 3, "(ComponentInstance bi) - Add a behavior to the object\n"
"@param bi The behavior instance to add"
"@return (bool success) Whether or not the behavior was successfully added")
{
@ -1679,7 +1847,7 @@ ConsoleMethod(Entity, addComponent, bool, 3, 3, "(Component* bi) - Add a behavio
return false;
}
ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(Component* bi, [bool deleteBehavior = true])\n"
ConsoleMethod(Entity, removeComponent, bool, 3, 4, "(ComponentInstance bi, [bool deleteBehavior = true])\n"
"@param bi The behavior instance to remove\n"
"@param deleteBehavior Whether or not to delete the behavior\n"
"@return (bool success) Whether the behavior was successfully removed")
@ -1834,4 +2002,43 @@ DefineConsoleMethod(Entity, notify, void, (String signalFunction, String argA, S
return;
object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);
}
DefineConsoleFunction(findEntitiesByTag, const char*, (SimGroup* searchingGroup, String tags), (nullAsType<SimGroup*>(), ""),
"Finds all entities that have the provided tags.\n"
"@param searchingGroup The SimGroup to search inside. If null, we'll search the entire dictionary(this can be slow!).\n"
"@param tags Word delimited list of tags to search for. If multiple tags are included, the list is eclusively parsed, requiring all tags provided to be found on an entity for a match.\n"
"@return A word list of IDs of entities that match the tag search terms.")
{
//if (tags.isEmpty())
return "";
/*if (searchingGroup == nullptr)
{
searchingGroup = Sim::getRootGroup();
}
StringTableEntry entityStr = StringTable->insert("Entity");
std::thread threadBob;
std::thread::id a = threadBob.get_id();
std::thread::id b = std::this_thread::get_id().;
if (a == b)
{
//do
}
for (SimGroup::iterator itr = searchingGroup->begin(); itr != searchingGroup->end(); itr++)
{
Entity* ent = dynamic_cast<Entity*>((*itr));
if (ent != nullptr)
{
ent->mTags.
}
}
object->notifyComponents(signalFunction, argA, argB, argC, argD, argE);*/
}