diff options
Diffstat (limited to 'source/test/net_states_test.cpp')
-rw-r--r-- | source/test/net_states_test.cpp | 1058 |
1 files changed, 1058 insertions, 0 deletions
diff --git a/source/test/net_states_test.cpp b/source/test/net_states_test.cpp new file mode 100644 index 0000000..ac168a0 --- /dev/null +++ b/source/test/net_states_test.cpp @@ -0,0 +1,1058 @@ +#include "StarNetElementSystem.hpp" + +#include "gtest/gtest.h" + +using namespace Star; + +TEST(NetElements, DataRounding) { + NetElementFloat masterField1; + NetElementFloat masterField2; + + NetElementTop<NetElementGroup> 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<NetElementGroup> 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<NetElementGroup> 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<NetElementGroup> 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<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + master.addNetElement(&masterField3); + master.addNetElement(&masterField4); + + NetElementInt slaveField1; + NetElementUInt slaveField2; + NetElementUInt slaveField3; + NetElementSize slaveField4; + + NetElementTop<NetElementGroup> 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<String> masterField2; + + NetElementTop<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + + NetElementInt forwarderField1; + NetElementData<String> forwarderField2; + + NetElementTop<NetElementGroup> forwarder; + forwarder.addNetElement(&forwarderField1); + forwarder.addNetElement(&forwarderField2); + + NetElementInt slaveField1; + NetElementData<String> slaveField2; + + NetElementTop<NetElementGroup> 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<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + + NetElementInt forwarderField1; + NetElementInt forwarderField2; + + NetElementTop<NetElementGroup> forwarder; + forwarder.addNetElement(&forwarderField1); + forwarder.addNetElement(&forwarderField2); + + NetElementInt slaveField1; + NetElementInt slaveField2; + + NetElementTop<NetElementGroup> 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<String> masterField3; + + NetElementTop<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + master.addNetElement(&masterField3); + + NetElementInt forwarderField1; + NetElementFloat forwarderField2; + NetElementData<String> forwarderField3; + + NetElementTop<NetElementGroup> forwarder; + forwarder.addNetElement(&forwarderField1); + forwarder.addNetElement(&forwarderField2); + forwarder.addNetElement(&forwarderField3); + + NetElementInt slaveField1; + NetElementFloat slaveField2; + NetElementData<String> slaveField3; + + NetElementTop<NetElementGroup> 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<String> masterField2; + NetElementEvent masterField3; + + NetElementTop<NetElementGroup> 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<String> 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<String> masterField1; + NetElementEvent masterField2; + + NetElementTop<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + + NetElementData<String> slaveField1; + NetElementEvent slaveField2; + + NetElementTop<NetElementGroup> 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<String> masterField1; + NetElementInt masterField2; + NetElementEvent masterField3; + NetElementEvent masterField4; + + NetElementTop<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + master.addNetElement(&masterField3); + master.addNetElement(&masterField4); + + NetElementData<String> slaveField1; + NetElementInt slaveField2; + NetElementEvent slaveField3; + NetElementEvent slaveField4; + + NetElementTop<NetElementGroup> 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<String> masterField2; + + NetElementTop<NetElementGroup> master; + master.addNetElement(&masterField1); + master.addNetElement(&masterField2); + + masterField1.set(1.0f); + masterField2.set("yes"); + + NetElementFloat slaveField1; + NetElementData<String> slaveField2; + + NetElementTop<NetElementGroup> slave; + slave.addNetElement(&slaveField1); + slave.addNetElement(&slaveField2); + + slaveField1.setInterpolator(lerp<double, double>); + + 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<TestEnum> masterField9; + NetElementEvent masterField10; + NetElementData<Vec2F> masterField11; + + NetElementTop<NetElementGroup> 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<TestEnum> slaveField9; + NetElementEvent slaveField10; + NetElementData<Vec2F> slaveField11; + + NetElementTop<NetElementGroup> 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<NetElementDynamicGroup<TestElement>> masterGroup; + + NetElementTop<NetElementDynamicGroup<TestElement>> 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<TestElement>(1000)); + auto objId2 = masterGroup.addNetElement(make_shared<TestElement>(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<TestElement>(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<TestElement>(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<NetElementDynamicGroup<TestElement>> 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<TestElement>(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<NetElementMap<String, String>> masterMap; + NetElementTop<NetElementMap<String, String>> 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<NetElementMap<String, String>> 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<int> masterSignal1; + NetElementSignal<int> masterSignal2; + + NetElementTopGroup masterGroup; + masterGroup.addNetElement(&masterSignal1); + masterGroup.addNetElement(&masterSignal2); + + NetElementSignal<int> slaveSignal1; + NetElementSignal<int> 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<int>({101})); + EXPECT_EQ(masterSignal2.receive(), List<int>({201})); + + EXPECT_EQ(masterSignal1.receive(), List<int>({})); + EXPECT_EQ(masterSignal2.receive(), List<int>({})); + + auto masterUpdate2 = masterGroup.writeNetState(masterUpdate1.second); + slaveGroup.readNetState(masterUpdate2.first); + + EXPECT_EQ(slaveSignal1.receive(), List<int>({101})); + EXPECT_EQ(slaveSignal2.receive(), List<int>({201})); + + EXPECT_EQ(slaveSignal1.receive(), List<int>({})); + EXPECT_EQ(slaveSignal2.receive(), List<int>({})); + + 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<int>({})); + EXPECT_EQ(slaveSignal2.receive(), List<int>({})); + + slaveGroup.tickNetInterpolation(1.0f); + + EXPECT_EQ(slaveSignal1.receive(), List<int>({102})); + EXPECT_EQ(slaveSignal2.receive(), List<int>({202})); + + EXPECT_EQ(slaveSignal1.receive(), List<int>({})); + EXPECT_EQ(slaveSignal2.receive(), List<int>({})); +} |