Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix updating a component's data via SerializedState msg #1131

Merged
merged 3 commits into from
Oct 22, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 10 additions & 32 deletions src/EntityComponentManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <unordered_map>
#include <unordered_set>
Expand Down Expand Up @@ -1652,53 +1653,30 @@ void EntityComponentManager::SetState(
continue;
}

// Create component
auto newComp = components::Factory::Instance()->New(compMsg.type());

if (nullptr == newComp)
{
ignerr << "Failed to deserialize component of type [" << compMsg.type()
<< "]" << std::endl;
continue;
}

std::istringstream istr(compMsg.component());
newComp->Deserialize(istr);

// Get type id
auto typeId = newComp->TypeId();

// TODO(louise) Move into if, see TODO below
this->RemoveComponent(entity, typeId);

// Remove component
if (compMsg.remove())
{
this->RemoveComponent(entity, type);
continue;
}

// Get Component
auto comp = this->ComponentImplementation(entity, typeId);
auto comp = this->ComponentImplementation(entity, type);

// Create if new
if (nullptr == comp)
{
this->CreateComponentImplementation(entity, typeId, newComp.get());
auto newComp = components::Factory::Instance()->New(type);
std::istringstream istr(compMsg.component());
nkoenig marked this conversation as resolved.
Show resolved Hide resolved
newComp->Deserialize(istr);
this->CreateComponentImplementation(entity, type, newComp.get());
}
// Update component value
else
{
ignerr << "Internal error" << std::endl;
// TODO(louise) We're shortcutting above and always removing the
// component so that we don't get here, gotta figure out why this
// doesn't update the component. The following line prints the correct
// values.
// igndbg << *comp << " " << *newComp.get() << std::endl;
// *comp = *newComp.get();

// When above TODO is addressed, uncomment AddModifiedComponent below
// unless calling SetChanged (which already calls AddModifiedComponent)
// this->dataPtr->AddModifiedComponent(entity);
std::istringstream istr(compMsg.component());
comp->Deserialize(istr);
this->dataPtr->AddModifiedComponent(entity);
}
}
}
Expand Down
78 changes: 78 additions & 0 deletions src/EntityComponentManager_TEST.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3000,6 +3000,84 @@ TEST_P(EntityComponentManagerFixture, PinnedEntity)
EXPECT_EQ(0u, manager.EntityCount());
}

//////////////////////////////////////////////////
/// \brief Test using msgs::SerializedStateMap and msgs::SerializedState
/// to update existing component data between multiple ECMs
TEST_P(EntityComponentManagerFixture, StateMsgUpdateComponent)
{
// create 2 ECMs: one will be modified directly, and the other should be
// updated to match the first via msgs::SerializedStateMap
EntityComponentManager originalECMStateMap;
EntityComponentManager otherECMStateMap;

// create an entity and component
auto entity = originalECMStateMap.CreateEntity();
originalECMStateMap.CreateComponent(entity, components::IntComponent(1));

// update the other ECM to have the new entity and component
msgs::SerializedStateMap stateMapMsg;
originalECMStateMap.State(stateMapMsg);
otherECMStateMap.SetState(stateMapMsg);
int foundEntities = 0;
otherECMStateMap.Each<components::IntComponent>(
[&](const Entity &, const components::IntComponent *_intComp)
{
foundEntities++;
EXPECT_EQ(1, _intComp->Data());
return true;
});
EXPECT_EQ(1, foundEntities);

// modify a component and then share the update with the other ECM
stateMapMsg.Clear();
originalECMStateMap.SetComponentData<components::IntComponent>(entity, 2);
originalECMStateMap.State(stateMapMsg);
otherECMStateMap.SetState(stateMapMsg);
foundEntities = 0;
otherECMStateMap.Each<components::IntComponent>(
[&](const Entity &, const components::IntComponent *_intComp)
{
foundEntities++;
EXPECT_EQ(2, _intComp->Data());
return true;
});
EXPECT_EQ(1, foundEntities);

// Run the same test as above, but this time, use a msgs::SerializedState
// instead of a msgs::SerializedStateMap
EntityComponentManager originalECMState;
EntityComponentManager otherECMState;

entity = originalECMState.CreateEntity();
originalECMState.CreateComponent(entity, components::IntComponent(1));

auto stateMsg = originalECMState.State();
otherECMState.SetState(stateMsg);
foundEntities = 0;
otherECMState.Each<components::IntComponent>(
[&](const Entity &, const components::IntComponent *_intComp)
{
foundEntities++;
EXPECT_EQ(1, _intComp->Data());
return true;
});
EXPECT_EQ(1, foundEntities);

stateMsg.Clear();
originalECMState.SetComponentData<components::IntComponent>(entity, 2);
stateMsg = originalECMState.State();
otherECMState.SetState(stateMsg);
foundEntities = 0;
otherECMState.Each<components::IntComponent>(
[&](const Entity &, const components::IntComponent *_intComp)
{
foundEntities++;
EXPECT_EQ(2, _intComp->Data());
return true;
});
EXPECT_EQ(1, foundEntities);
}

// Run multiple times. We want to make sure that static globals don't cause
// problems.
INSTANTIATE_TEST_SUITE_P(EntityComponentManagerRepeat,
Expand Down