#include "StarNetElementSystem.hpp" #include "gtest/gtest.h" using namespace Star; TEST(NetElements, DataRounding) { NetElementFloat masterField1; NetElementFloat masterField2; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); masterField1.setFixedPointBase(0.1f); masterField2.setFixedPointBase(0.5); masterField1.set(2.1999f); masterField2.set(100.04); // Check to make sure encoded data is actually sent with the expected // limitations to the client side. NetElementFloat slaveField1; NetElementFloat slaveField2; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slaveField1.setFixedPointBase(0.1f); slaveField2.setFixedPointBase(0.5); auto masterUpdate1 = master.writeNetState(); slave.readNetState(masterUpdate1.first); EXPECT_LT(fabs(slaveField1.get() - 2.2f), 0.00001f); EXPECT_LT(fabs(slaveField2.get() - 100), 0.0000001); // Make sure that jittering a fixed point or limited value doesn't cause // extra deltas masterField1.set(2.155f); masterField1.set(2.24f); masterField2.set(99.96); masterField2.set(100.00); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); EXPECT_TRUE(masterUpdate2.first.empty()); slave.readNetState(masterUpdate2.first); masterField1.set(10.0f); masterField2.set(50.0f); auto masterUpdate3 = master.writeNetState(masterUpdate2.second); EXPECT_FALSE(masterUpdate3.first.empty()); slave.readNetState(masterUpdate3.first); EXPECT_LT(fabs(slaveField1.get() - 10.0f), 0.00001f); EXPECT_LT(fabs(slaveField2.get() - 50.0f), 0.0000001); } TEST(NetElements, DirectWriteRead) { NetElementUInt masterField1; NetElementUInt masterField2; NetElementUInt masterField3; NetElementUInt masterField4; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); master.addNetElement(&masterField4); masterField1.set(1); masterField2.set(2); masterField3.set(3); masterField4.set(4); NetElementUInt slaveField1; NetElementUInt slaveField2; NetElementUInt slaveField3; NetElementUInt slaveField4; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slave.addNetElement(&slaveField3); slave.addNetElement(&slaveField4); auto masterUpdate1 = master.writeNetState(); slave.readNetState(masterUpdate1.first); EXPECT_EQ(slaveField1.get(), 1u); EXPECT_EQ(slaveField2.get(), 2u); EXPECT_EQ(slaveField3.get(), 3u); EXPECT_EQ(slaveField4.get(), 4u); masterField1.set(10); masterField3.set(30); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); slave.readNetState(masterUpdate2.first); EXPECT_EQ(slaveField1.get(), 10u); EXPECT_EQ(slaveField2.get(), 2u); EXPECT_EQ(slaveField3.get(), 30u); EXPECT_EQ(slaveField4.get(), 4u); masterField2.set(20); masterField4.set(40); auto masterUpdate3 = master.writeNetState(masterUpdate2.second); slave.readNetState(masterUpdate3.first); EXPECT_EQ(slaveField1.get(), 10u); EXPECT_EQ(slaveField2.get(), 20u); EXPECT_EQ(slaveField3.get(), 30u); EXPECT_EQ(slaveField4.get(), 40u); } TEST(NetElements, DeltaSize) { NetElementInt masterField1; NetElementUInt masterField2; NetElementUInt masterField3; NetElementSize masterField4; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); master.addNetElement(&masterField4); NetElementInt slaveField1; NetElementUInt slaveField2; NetElementUInt slaveField3; NetElementSize slaveField4; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slave.addNetElement(&slaveField3); slave.addNetElement(&slaveField4); masterField1.set(10); masterField2.set(20); masterField3.set(30); masterField4.set(40); EXPECT_EQ(masterField1.get(), 10); EXPECT_EQ(masterField2.get(), 20u); EXPECT_EQ(masterField3.get(), 30u); EXPECT_EQ(masterField4.get(), 40u); auto masterUpdate1 = master.writeNetState(); // Initial state should be 5 bytes, 1 byte for header, then 4 1 byte values. EXPECT_EQ(masterUpdate1.first.size(), 5u); slave.readNetState(masterUpdate1.first); EXPECT_EQ(slaveField1.get(), 10); EXPECT_EQ(slaveField2.get(), 20u); EXPECT_EQ(slaveField3.get(), 30u); EXPECT_EQ(slaveField4.get(), 40u); masterField1.set(50); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); // Second delta should be not include any other data than the single 1 byte // changed state, so make sure that it is 1 byte for header, 1 byte for field // number, 1 byte for state, 1 byte for end marker. EXPECT_EQ(masterUpdate2.first.size(), 4u); slave.readNetState(masterUpdate2.first); EXPECT_EQ(slaveField1.get(), 50); } TEST(NetElements, Forwarding) { NetElementInt masterField1; NetElementData masterField2; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); NetElementInt forwarderField1; NetElementData forwarderField2; NetElementTop forwarder; forwarder.addNetElement(&forwarderField1); forwarder.addNetElement(&forwarderField2); NetElementInt slaveField1; NetElementData slaveField2; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); masterField1.set(413); masterField2.set("foo"); auto masterUpdate1 = master.writeNetState(); forwarder.readNetState(masterUpdate1.first); auto forwarderUpdate1 = forwarder.writeNetState(); slave.readNetState(forwarderUpdate1.first); EXPECT_EQ(forwarderField1.get(), 413); EXPECT_EQ(forwarderField2.get(), "foo"); EXPECT_EQ(slaveField1.get(), 413); EXPECT_EQ(slaveField2.get(), "foo"); } TEST(NetElements, StepForwarding) { NetElementInt masterField1; NetElementInt masterField2; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); NetElementInt forwarderField1; NetElementInt forwarderField2; NetElementTop forwarder; forwarder.addNetElement(&forwarderField1); forwarder.addNetElement(&forwarderField2); NetElementInt slaveField1; NetElementInt slaveField2; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); // First emulate store / load that would happen in entity initialization. masterField1.set(10); masterField2.set(20); auto masterUpdate1 = master.writeNetState(); forwarder.readNetState(masterUpdate1.first); auto forwarderUpdate1 = forwarder.writeNetState(); slave.readNetState(forwarderUpdate1.first); EXPECT_EQ(forwarderField1.get(), 10); EXPECT_EQ(forwarderField2.get(), 20); EXPECT_EQ(slaveField1.get(), 10); EXPECT_EQ(slaveField2.get(), 20); // Then, update one field and transmit that delta[ to the forwarder. masterField1.set(413); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); forwarder.readNetState(masterUpdate2.first); EXPECT_EQ(forwarderField1.get(), 413); auto forwarderUpdate2 = forwarder.writeNetState(forwarderUpdate1.second); slave.readNetState(forwarderUpdate2.first); EXPECT_EQ(slaveField1.get(), 413); EXPECT_EQ(forwarderField1.get(), 413); EXPECT_EQ(forwarderField2.get(), 20); EXPECT_EQ(slaveField1.get(), 413); EXPECT_EQ(slaveField2.get(), 20); } TEST(NetElements, InterpolationForwarding) { NetElementInt masterField1; NetElementFloat masterField2; NetElementData masterField3; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); NetElementInt forwarderField1; NetElementFloat forwarderField2; NetElementData forwarderField3; NetElementTop forwarder; forwarder.addNetElement(&forwarderField1); forwarder.addNetElement(&forwarderField2); forwarder.addNetElement(&forwarderField3); NetElementInt slaveField1; NetElementFloat slaveField2; NetElementData slaveField3; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slave.addNetElement(&slaveField3); forwarder.enableNetInterpolation(); slave.enableNetInterpolation(); masterField1.set(10); masterField2.set(10.0f); masterField3.set("10"); auto masterUpdate1 = master.writeNetState(); forwarder.readNetState(masterUpdate1.first); auto forwarderUpdate1 = forwarder.writeNetState(); slave.readNetState(forwarderUpdate1.first); EXPECT_EQ(forwarderField1.get(), 10); EXPECT_EQ(forwarderField2.get(), 10.0f); EXPECT_EQ(forwarderField3.get(), "10"); EXPECT_EQ(slaveField1.get(), 10); EXPECT_EQ(slaveField2.get(), 10.0f); EXPECT_EQ(slaveField3.get(), "10"); masterField1.set(20); masterField2.set(20.0f); masterField3.set("20"); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); forwarder.readNetState(masterUpdate2.first, 1.0f); // Forwarder should not be updated yet, still 1.0f interpolationTime behind EXPECT_EQ(forwarderField1.get(), 10); EXPECT_EQ(forwarderField2.get(), 10.0f); EXPECT_EQ(forwarderField3.get(), "10"); // But the forwarder should STILL forward the absolute latest data to the // slave auto forwarderUpdate2 = forwarder.writeNetState(forwarderUpdate1.second); slave.readNetState(forwarderUpdate2.first, 1.0f); // Slave should not be updated yet, still 1.0f interpolationTime behind EXPECT_EQ(slaveField1.get(), 10); EXPECT_EQ(slaveField2.get(), 10.0f); EXPECT_EQ(slaveField3.get(), "10"); // After ticking forward interpolation, both the forwarder and the slave // should both pick up the new values. forwarder.tickNetInterpolation(1.0f); EXPECT_EQ(forwarderField1.get(), 20); EXPECT_EQ(forwarderField2.get(), 20.0f); EXPECT_EQ(forwarderField3.get(), "20"); slave.tickNetInterpolation(1.0f); EXPECT_EQ(slaveField1.get(), 20); EXPECT_EQ(slaveField2.get(), 20.0f); EXPECT_EQ(slaveField3.get(), "20"); } TEST(NetElements, MasterSetGet) { // Make sure that Master mode sets, gets, and pullEventOccurred work // properly. NetElementInt masterField1; NetElementData masterField2; NetElementEvent masterField3; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); EXPECT_EQ(masterField3.pullOccurrences(), 0u); masterField1.set(10); masterField2.set("foo"); EXPECT_EQ(masterField1.get(), 10); EXPECT_EQ(masterField2.get(), "foo"); masterField3.trigger(); masterField3.trigger(); EXPECT_EQ(masterField3.pullOccurrences(), 2u); EXPECT_EQ(masterField3.pullOccurrences(), 0u); } TEST(NetElements, IsolatedSetGet) { // Make sure fields work without being connected NetElementInt masterField1; NetElementData masterField2; NetElementEvent masterField3; EXPECT_EQ(masterField2.pullUpdated(), false); EXPECT_EQ(masterField3.pullOccurrences(), 0u); masterField1.set(10); masterField2.set("foo"); EXPECT_EQ(masterField2.pullUpdated(), true); EXPECT_EQ(masterField2.pullUpdated(), false); EXPECT_EQ(masterField1.get(), 10); EXPECT_EQ(masterField2.get(), "foo"); masterField3.trigger(); masterField3.trigger(); EXPECT_EQ(masterField3.pullOccurrences(), 2u); EXPECT_EQ(masterField3.pullOccurrences(), 0u); masterField1.set(20); masterField2.set("bar"); masterField3.trigger(); masterField3.trigger(); EXPECT_EQ(masterField3.pullOccurrences(), 2u); } TEST(NetElements, EventTest) { NetElementData masterField1; NetElementEvent masterField2; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); NetElementData slaveField1; NetElementEvent slaveField2; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); // Events should always start with occurred false. EXPECT_EQ(slaveField1.pullUpdated(), false); EXPECT_EQ(slaveField2.pullOccurrences(), 0u); masterField1.set("foo"); masterField2.trigger(); EXPECT_TRUE(masterField1.pullUpdated()); EXPECT_FALSE(masterField1.pullUpdated()); auto masterUpdate1 = master.writeNetState(); slave.readNetState(masterUpdate1.first); EXPECT_TRUE(slaveField1.pullUpdated()); EXPECT_FALSE(slaveField1.pullUpdated()); EXPECT_EQ(slaveField2.pullOccurrences(), 1u); EXPECT_EQ(slaveField2.pullOccurrences(), 0u); // Delta should be empty, nothing happened on step 1. auto masterUpdate2 = master.writeNetState(masterUpdate1.second); EXPECT_TRUE(masterUpdate2.first.empty()); slave.readNetState(masterUpdate2.first); EXPECT_EQ(slaveField2.pullOccurrences(), 0u); masterField2.trigger(); auto masterUpdate3 = master.writeNetState(masterUpdate2.second); EXPECT_FALSE(masterUpdate3.first.empty()); slave.readNetState(masterUpdate3.first); EXPECT_EQ(slaveField2.pullOccurrences(), 1u); EXPECT_EQ(slaveField2.pullOccurrences(), 0u); } TEST(NetElements, FieldUpdated) { NetElementData masterField1; NetElementInt masterField2; NetElementEvent masterField3; NetElementEvent masterField4; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); master.addNetElement(&masterField4); NetElementData slaveField1; NetElementInt slaveField2; NetElementEvent slaveField3; NetElementEvent slaveField4; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slave.addNetElement(&slaveField3); slave.addNetElement(&slaveField4); slaveField4.setIgnoreOccurrencesOnNetLoad(true); masterField1.set("foo"); masterField3.trigger(); masterField4.trigger(); auto masterUpdate1 = master.writeNetState(); slave.readNetState(masterUpdate1.first); EXPECT_EQ(slaveField1.pullUpdated(), true); EXPECT_EQ(slaveField1.get(), "foo"); EXPECT_EQ(slaveField1.pullUpdated(), false); EXPECT_EQ(masterField3.pullOccurrences(), 1u); EXPECT_EQ(slaveField3.pullOccurrences(), 1u); // Ignore occurrences on full load should stop slaveField4 from getting any // occurrences EXPECT_EQ(masterField4.pullOccurrences(), 1u); EXPECT_EQ(slaveField4.pullOccurrences(), 0u); masterField1.set("baz"); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); EXPECT_FALSE(masterUpdate2.first.empty()); slave.readNetState(masterUpdate2.first); EXPECT_EQ(slaveField1.get(), "baz"); EXPECT_EQ(slaveField1.pullUpdated(), true); masterField1.set("bar"); auto masterUpdate3 = master.writeNetState(masterUpdate2.second); EXPECT_FALSE(masterUpdate3.first.empty()); slave.readNetState(masterUpdate3.first); EXPECT_EQ(slaveField1.get(), "bar"); EXPECT_EQ(slaveField1.pullUpdated(), true); masterField1.push("bar"); auto masterUpdate4 = master.writeNetState(masterUpdate3.second); EXPECT_FALSE(masterUpdate4.first.empty()); slave.readNetState(masterUpdate4.first); EXPECT_EQ(slaveField1.get(), "bar"); EXPECT_EQ(slaveField1.pullUpdated(), true); auto masterUpdate5 = master.writeNetState(masterUpdate4.second); EXPECT_TRUE(masterUpdate5.first.empty()); slave.readNetState(masterUpdate5.first); EXPECT_EQ(slaveField1.get(), "bar"); EXPECT_EQ(slaveField1.pullUpdated(), false); masterField3.trigger(); masterField3.trigger(); auto masterUpdate6 = master.writeNetState(masterUpdate5.second); EXPECT_FALSE(masterUpdate6.first.empty()); slave.readNetState(masterUpdate6.first); slaveField3.ignoreOccurrences(); // occurrence should not come through after "ignoreOccurrences" EXPECT_EQ(slaveField3.pullOccurrences(), 0u); EXPECT_EQ(masterField3.pullOccurrences(), 2u); masterField3.trigger(); masterField3.trigger(); masterField3.ignoreOccurrences(); auto masterUpdate7 = master.writeNetState(masterUpdate6.second); EXPECT_FALSE(masterUpdate7.first.empty()); slave.readNetState(masterUpdate7.first); // ignoreOccurrences is LOCAL only, so events should still go through to the // slave EXPECT_EQ(masterField3.pullOccurrences(), 0u); EXPECT_EQ(slaveField3.pullOccurrences(), 2u); EXPECT_EQ(slaveField3.pullOccurrences(), 0u); } TEST(NetElements, Interpolation) { NetElementFloat masterField1; NetElementData masterField2; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); masterField1.set(1.0f); masterField2.set("yes"); NetElementFloat slaveField1; NetElementData slaveField2; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slaveField1.setInterpolator(lerp); slave.enableNetInterpolation(); auto masterUpdate1 = master.writeNetState(); slave.readNetState(masterUpdate1.first); masterField1.set(2.0f); masterField2.set("no"); auto masterUpdate2 = master.writeNetState(masterUpdate1.second); slave.readNetState(masterUpdate2.first, 2.0); masterField1.set(3.0f); masterField2.set("yes"); auto masterUpdate3 = master.writeNetState(masterUpdate2.second); slave.readNetState(masterUpdate3.first, 4.0); masterField1.set(4.0f); masterField2.set("no"); auto masterUpdate4 = master.writeNetState(masterUpdate3.second); slave.readNetState(masterUpdate4.first, 6.0); EXPECT_TRUE(fabs(slaveField1.get() - 1.0) < 0.001); EXPECT_EQ(slaveField2.get(), "yes"); EXPECT_EQ(slaveField2.pullUpdated(), true); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 1.5) < 0.001); EXPECT_EQ(slaveField2.get(), "yes"); EXPECT_EQ(slaveField2.pullUpdated(), false); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 2.0) < 0.001); EXPECT_EQ(slaveField2.get(), "no"); EXPECT_EQ(slaveField2.pullUpdated(), true); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 2.5) < 0.001); EXPECT_EQ(slaveField2.get(), "no"); EXPECT_EQ(slaveField2.pullUpdated(), false); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 3.0) < 0.001); EXPECT_EQ(slaveField2.get(), "yes"); EXPECT_EQ(slaveField2.pullUpdated(), true); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 3.5) < 0.001); EXPECT_EQ(slaveField2.get(), "yes"); EXPECT_EQ(slaveField2.pullUpdated(), false); slave.tickNetInterpolation(1.0f); EXPECT_TRUE(fabs(slaveField1.get() - 4.0) < 0.001); EXPECT_EQ(slaveField2.pullUpdated(), true); EXPECT_EQ(slaveField2.get(), "no"); } enum class TestEnum { Value1, Value2, Value3 }; TEST(NetElements, AllTypes) { NetElementInt masterField1; NetElementUInt masterField2; NetElementSize masterField3; NetElementFloat masterField4; NetElementDouble masterField5; NetElementFloat masterField6; masterField6.setFixedPointBase(0.01f); NetElementDouble masterField7; masterField7.setFixedPointBase(0.01); NetElementBool masterField8; NetElementEnum masterField9; NetElementEvent masterField10; NetElementData masterField11; NetElementTop master; master.addNetElement(&masterField1); master.addNetElement(&masterField2); master.addNetElement(&masterField3); master.addNetElement(&masterField4); master.addNetElement(&masterField5); master.addNetElement(&masterField6); master.addNetElement(&masterField7); master.addNetElement(&masterField8); master.addNetElement(&masterField9); master.addNetElement(&masterField10); master.addNetElement(&masterField11); masterField1.set(567); masterField2.set(17000); masterField3.set(22222); masterField4.set(1.55f); masterField5.set(1.12345678910111213); masterField6.set(2000.62f); masterField7.set(2000.62); masterField8.set(true); masterField9.set(TestEnum::Value2); masterField10.trigger(); masterField11.set(Vec2F(2.0f, 2.0f)); EXPECT_EQ(masterField1.get(), 567); EXPECT_EQ(masterField2.get(), 17000u); EXPECT_EQ(masterField3.get(), 22222u); EXPECT_FLOAT_EQ(masterField4.get(), 1.55f); EXPECT_FLOAT_EQ(masterField5.get(), 1.12345678910111213); EXPECT_FLOAT_EQ(masterField6.get(), 2000.62f); EXPECT_FLOAT_EQ(masterField7.get(), 2000.62); EXPECT_EQ(masterField8.get(), true); EXPECT_EQ(masterField9.get(), TestEnum::Value2); EXPECT_TRUE(masterField10.pullOccurred()); EXPECT_TRUE(masterField11.get() == Vec2F(2.0f, 2.0f)); NetElementInt slaveField1; NetElementUInt slaveField2; NetElementSize slaveField3; NetElementFloat slaveField4; NetElementDouble slaveField5; NetElementFloat slaveField6; slaveField6.setFixedPointBase(0.01f); NetElementDouble slaveField7; slaveField7.setFixedPointBase(0.01); NetElementBool slaveField8; NetElementEnum slaveField9; NetElementEvent slaveField10; NetElementData slaveField11; NetElementTop slave; slave.addNetElement(&slaveField1); slave.addNetElement(&slaveField2); slave.addNetElement(&slaveField3); slave.addNetElement(&slaveField4); slave.addNetElement(&slaveField5); slave.addNetElement(&slaveField6); slave.addNetElement(&slaveField7); slave.addNetElement(&slaveField8); slave.addNetElement(&slaveField9); slave.addNetElement(&slaveField10); slave.addNetElement(&slaveField11); slave.readNetState(master.writeNetState().first); EXPECT_EQ(slaveField1.get(), 567); EXPECT_EQ(slaveField2.get(), 17000u); EXPECT_EQ(slaveField3.get(), 22222u); EXPECT_FLOAT_EQ(slaveField4.get(), 1.55f); EXPECT_FLOAT_EQ(slaveField5.get(), 1.12345678910111213); EXPECT_FLOAT_EQ(slaveField6.get(), 2000.62f); EXPECT_FLOAT_EQ(slaveField7.get(), 2000.62); EXPECT_EQ(slaveField8.get(), true); EXPECT_EQ(slaveField9.get(), TestEnum::Value2); EXPECT_TRUE(slaveField10.pullOccurred()); EXPECT_TRUE(slaveField11.get() == Vec2F(2.0f, 2.0f)); } TEST(NetElements, NetElementDynamicGroup) { class TestElement : public NetElementGroup { public: TestElement(int value = 0) { addNetElement(&dataState); dataState.set(value); } void setData(int value) { dataState.set(value); } int getData() const { return dataState.get(); } private: NetElementInt dataState; }; NetElementTop> masterGroup; NetElementTop> slaveGroup; uint64_t lastSlaveUpdateVersion = 0; auto sendSlaveUpdate = [&]() { auto p = masterGroup.writeNetState(lastSlaveUpdateVersion); lastSlaveUpdateVersion = p.second; slaveGroup.readNetState(p.first); }; auto objId1 = masterGroup.addNetElement(make_shared(1000)); auto objId2 = masterGroup.addNetElement(make_shared(2000)); EXPECT_EQ(masterGroup.netElementIds().size(), 2u); EXPECT_EQ(masterGroup.getNetElement(objId1)->getData(), 1000); EXPECT_EQ(masterGroup.getNetElement(objId2)->getData(), 2000); sendSlaveUpdate(); EXPECT_EQ(slaveGroup.netElementIds().size(), 2u); EXPECT_EQ(slaveGroup.getNetElement(objId1)->getData(), 1000); EXPECT_EQ(slaveGroup.getNetElement(objId2)->getData(), 2000); masterGroup.getNetElement(objId1)->setData(1001); masterGroup.getNetElement(objId2)->setData(2001); sendSlaveUpdate(); EXPECT_EQ(slaveGroup.getNetElement(objId1)->getData(), 1001); EXPECT_EQ(slaveGroup.getNetElement(objId2)->getData(), 2001); masterGroup.getNetElement(objId1)->setData(1002); masterGroup.getNetElement(objId2)->setData(2002); sendSlaveUpdate(); EXPECT_EQ(masterGroup.getNetElement(objId1)->getData(), 1002); EXPECT_EQ(masterGroup.getNetElement(objId2)->getData(), 2002); EXPECT_EQ(slaveGroup.getNetElement(objId1)->getData(), 1002); EXPECT_EQ(slaveGroup.getNetElement(objId2)->getData(), 2002); auto objId3 = masterGroup.addNetElement(make_shared(3001)); sendSlaveUpdate(); EXPECT_EQ(slaveGroup.netElementIds().size(), 3u); EXPECT_EQ(slaveGroup.getNetElement(objId3)->getData(), 3001); // Delta must be greater than MaxChangeDataSteps auto objId4 = masterGroup.addNetElement(make_shared(4001)); masterGroup.getNetElement(objId3)->setData(3002); masterGroup.getNetElement(objId4)->setData(4002); sendSlaveUpdate(); EXPECT_EQ(slaveGroup.netElementIds().size(), 4u); EXPECT_EQ(slaveGroup.getNetElement(objId1)->getData(), 1002); EXPECT_EQ(slaveGroup.getNetElement(objId2)->getData(), 2002); EXPECT_EQ(slaveGroup.getNetElement(objId3)->getData(), 3002); EXPECT_EQ(slaveGroup.getNetElement(objId4)->getData(), 4002); NetElementTop> forwardedSlaveGroup; uint64_t lastForwardedSlaveUpdateVersion = 0; auto sendForwardedSlaveUpdate = [&]() { auto p = slaveGroup.writeNetState(lastForwardedSlaveUpdateVersion); lastForwardedSlaveUpdateVersion = p.second; forwardedSlaveGroup.readNetState(p.first); }; sendForwardedSlaveUpdate(); EXPECT_EQ(forwardedSlaveGroup.netElementIds().size(), 4u); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId1)->getData(), 1002); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId2)->getData(), 2002); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId3)->getData(), 3002); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId4)->getData(), 4002); masterGroup.removeNetElement(objId1); masterGroup.removeNetElement(objId3); masterGroup.getNetElement(objId2)->setData(2003); masterGroup.getNetElement(objId4)->setData(4003); sendSlaveUpdate(); sendForwardedSlaveUpdate(); auto obj5 = masterGroup.addNetElement(make_shared(5001)); masterGroup.removeNetElement(obj5); sendSlaveUpdate(); sendForwardedSlaveUpdate(); EXPECT_EQ(slaveGroup.netElementIds().size(), 2u); EXPECT_EQ(slaveGroup.getNetElement(objId2)->getData(), 2003); EXPECT_EQ(slaveGroup.getNetElement(objId4)->getData(), 4003); EXPECT_EQ(forwardedSlaveGroup.netElementIds().size(), 2u); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId2)->getData(), 2003); EXPECT_EQ(forwardedSlaveGroup.getNetElement(objId4)->getData(), 4003); } TEST(NetElements, NetElementMap) { NetElementTop> masterMap; NetElementTop> slaveMap; uint64_t lastUpdateVersion = 0; auto sendUpdate = [&]() { DataStreamBuffer ds; auto p = masterMap.writeNetState(lastUpdateVersion); slaveMap.readNetState(p.first); lastUpdateVersion = p.second; return !p.first.empty(); }; masterMap.add("foo", "bar"); masterMap.add("baz", "bof"); EXPECT_EQ(masterMap.size(), 2u); sendUpdate(); EXPECT_EQ(slaveMap.size(), 2u); EXPECT_EQ(slaveMap.get("foo"), "bar"); EXPECT_EQ(slaveMap.get("baz"), "bof"); masterMap.add("bif", "fob"); masterMap.remove("foo"); sendUpdate(); EXPECT_EQ(slaveMap.size(), 2u); EXPECT_EQ(slaveMap.get("bif"), "fob"); masterMap.clear(); masterMap.set("fib", "fab"); sendUpdate(); EXPECT_EQ(slaveMap.size(), 1u); EXPECT_EQ(slaveMap.get("fib"), "fab"); masterMap.set("fib", "fab"); EXPECT_FALSE(sendUpdate()); masterMap.reset({{"a", "b"}, {"c", "d"}, {"e", "f"}}); sendUpdate(); EXPECT_EQ(slaveMap.size(), 3u); EXPECT_EQ(slaveMap.get("a"), "b"); EXPECT_EQ(slaveMap.get("c"), "d"); EXPECT_EQ(slaveMap.get("e"), "f"); } TEST(NetElements, NetElementMapInterpolated) { typedef NetElementTop> TestMap; TestMap masterMap; TestMap forwarderMap; uint64_t lastForwarderUpdateVersion = 0; auto sendForwarderUpdate = [&]() { auto p = masterMap.writeNetState(lastForwarderUpdateVersion); lastForwarderUpdateVersion = p.second; forwarderMap.readNetState(p.first); return !p.first.empty(); }; TestMap slaveMap; uint64_t lastSlaveUpdateVersion = 0; auto sendSlaveUpdate = [&](float interpolationTime) { auto p = forwarderMap.writeNetState(lastSlaveUpdateVersion); lastSlaveUpdateVersion = p.second; slaveMap.readNetState(p.first, interpolationTime); return !p.first.empty(); }; slaveMap.enableNetInterpolation(); masterMap.add("foo", "bar"); masterMap.add("baz", "bof"); EXPECT_EQ(masterMap.size(), 2u); sendForwarderUpdate(); sendSlaveUpdate(0.0f); EXPECT_EQ(slaveMap.size(), 2u); EXPECT_EQ(slaveMap.get("foo"), "bar"); EXPECT_EQ(slaveMap.get("baz"), "bof"); masterMap.add("bif", "fob"); masterMap.add("qux", "qux"); masterMap.remove("foo"); sendForwarderUpdate(); sendSlaveUpdate(1.0f); EXPECT_EQ(slaveMap.size(), 2u); EXPECT_EQ(slaveMap.get("foo"), "bar"); EXPECT_EQ(slaveMap.get("baz"), "bof"); slaveMap.tickNetInterpolation(1.0f); EXPECT_EQ(slaveMap.size(), 3u); EXPECT_EQ(slaveMap.get("baz"), "bof"); EXPECT_EQ(slaveMap.get("bif"), "fob"); EXPECT_EQ(slaveMap.get("qux"), "qux"); masterMap.clear(); masterMap.set("fib", "fab"); sendForwarderUpdate(); sendSlaveUpdate(1.0f); EXPECT_EQ(slaveMap.size(), 3u); slaveMap.tickNetInterpolation(1.0f); EXPECT_EQ(forwarderMap.size(), 1u); EXPECT_EQ(slaveMap.size(), 1u); EXPECT_EQ(slaveMap.get("fib"), "fab"); masterMap.set("fob", "fub"); sendForwarderUpdate(); sendSlaveUpdate(1.0f); EXPECT_EQ(slaveMap.size(), 1u); slaveMap.disableNetInterpolation(); EXPECT_EQ(slaveMap.size(), 2u); EXPECT_EQ(slaveMap.get("fib"), "fab"); EXPECT_EQ(slaveMap.get("fob"), "fub"); } TEST(NetElements, NetElementSignal) { NetElementSignal masterSignal1; NetElementSignal masterSignal2; NetElementTopGroup masterGroup; masterGroup.addNetElement(&masterSignal1); masterGroup.addNetElement(&masterSignal2); NetElementSignal slaveSignal1; NetElementSignal slaveSignal2; NetElementTopGroup slaveGroup; slaveGroup.addNetElement(&slaveSignal1); slaveGroup.addNetElement(&slaveSignal2); // No signals are supposed to be sent for the initial write auto masterUpdate1 = masterGroup.writeNetState(); slaveGroup.readNetState(masterUpdate1.first); masterSignal1.send(101); masterSignal2.send(201); EXPECT_EQ(masterSignal1.receive(), List({101})); EXPECT_EQ(masterSignal2.receive(), List({201})); EXPECT_EQ(masterSignal1.receive(), List({})); EXPECT_EQ(masterSignal2.receive(), List({})); auto masterUpdate2 = masterGroup.writeNetState(masterUpdate1.second); slaveGroup.readNetState(masterUpdate2.first); EXPECT_EQ(slaveSignal1.receive(), List({101})); EXPECT_EQ(slaveSignal2.receive(), List({201})); EXPECT_EQ(slaveSignal1.receive(), List({})); EXPECT_EQ(slaveSignal2.receive(), List({})); masterSignal1.send(102); masterSignal2.send(202); slaveGroup.enableNetInterpolation(); auto masterUpdate3 = masterGroup.writeNetState(masterUpdate2.second); slaveGroup.readNetState(masterUpdate3.first, 1.0f); EXPECT_EQ(slaveSignal1.receive(), List({})); EXPECT_EQ(slaveSignal2.receive(), List({})); slaveGroup.tickNetInterpolation(1.0f); EXPECT_EQ(slaveSignal1.receive(), List({102})); EXPECT_EQ(slaveSignal2.receive(), List({202})); EXPECT_EQ(slaveSignal1.receive(), List({})); EXPECT_EQ(slaveSignal2.receive(), List({})); }