Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarNetElementSignal.hpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarNetElementSignal.hpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/core/StarNetElementSignal.hpp')
-rw-r--r--source/core/StarNetElementSignal.hpp145
1 files changed, 145 insertions, 0 deletions
diff --git a/source/core/StarNetElementSignal.hpp b/source/core/StarNetElementSignal.hpp
new file mode 100644
index 0000000..c1a89ac
--- /dev/null
+++ b/source/core/StarNetElementSignal.hpp
@@ -0,0 +1,145 @@
+#ifndef STAR_NET_ELEMENT_SIGNAL_HPP
+#define STAR_NET_ELEMENT_SIGNAL_HPP
+
+#include "StarNetElement.hpp"
+
+namespace Star {
+
+// NetElement that sends signals during delta writes that can be received by
+// slaves. It has no 'state', and nothing is sent during a store / load, and
+// it only keeps past signals for a maximum number of versions. Thus, it is
+// not appropriate to use to send updates to long term states, only for event
+// like things that are not harmful if missed.
+template <typename Signal>
+class NetElementSignal : public NetElement {
+public:
+ NetElementSignal(size_t maxSignalQueue = 32);
+
+ void initNetVersion(NetElementVersion const* version = nullptr) override;
+
+ void netStore(DataStream& ds) const override;
+ void netLoad(DataStream& ds) override;
+
+ void enableNetInterpolation(float extrapolationHint = 0.0f) override;
+ void disableNetInterpolation() override;
+ void tickNetInterpolation(float dt) override;
+
+ bool writeNetDelta(DataStream& ds, uint64_t fromVersion) const override;
+ void readNetDelta(DataStream& ds, float interpolationTime = 0.0) override;
+
+ void send(Signal signal);
+ List<Signal> receive();
+
+private:
+ struct SignalEntry {
+ uint64_t version;
+ Signal signal;
+ bool received;
+ };
+
+ size_t m_maxSignalQueue;
+ NetElementVersion const* m_netVersion = nullptr;
+ bool m_netInterpolationEnabled = false;
+ Deque<SignalEntry> m_signals;
+ Deque<pair<float, Signal>> m_pendingSignals;
+};
+
+template <typename Signal>
+NetElementSignal<Signal>::NetElementSignal(size_t maxSignalQueue) {
+ m_maxSignalQueue = maxSignalQueue;
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::initNetVersion(NetElementVersion const* version) {
+ m_netVersion = version;
+ m_signals.clear();
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::netStore(DataStream&) const {}
+
+template <typename Signal>
+void NetElementSignal<Signal>::netLoad(DataStream&) {
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::enableNetInterpolation(float) {
+ m_netInterpolationEnabled = true;
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::disableNetInterpolation() {
+ m_netInterpolationEnabled = false;
+ for (auto& p : take(m_pendingSignals))
+ send(move(p.second));
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::tickNetInterpolation(float dt) {
+ for (auto& p : m_pendingSignals)
+ p.first -= dt;
+
+ while (!m_pendingSignals.empty() && m_pendingSignals.first().first <= 0.0f)
+ send(m_pendingSignals.takeFirst().second);
+}
+
+template <typename Signal>
+bool NetElementSignal<Signal>::writeNetDelta(DataStream& ds, uint64_t fromVersion) const {
+ size_t numToWrite = 0;
+ for (auto const& p : m_signals) {
+ if (p.version >= fromVersion)
+ ++numToWrite;
+ }
+ if (numToWrite == 0)
+ return false;
+
+ ds.writeVlqU(numToWrite);
+
+ for (auto const& p : m_signals) {
+ if (p.version >= fromVersion)
+ ds.write(p.signal);
+ }
+
+ return true;
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::readNetDelta(DataStream& ds, float interpolationTime) {
+ size_t numToRead = ds.readVlqU();
+ for (size_t i = 0; i < numToRead; ++i) {
+ Signal s;
+ ds.read(s);
+ if (m_netInterpolationEnabled && interpolationTime > 0.0f) {
+ if (!m_pendingSignals.empty() && m_pendingSignals.last().first > interpolationTime) {
+ for (auto& p : take(m_pendingSignals))
+ send(move(p.second));
+ }
+ m_pendingSignals.append({interpolationTime, move(s)});
+ } else {
+ send(move(s));
+ }
+ }
+}
+
+template <typename Signal>
+void NetElementSignal<Signal>::send(Signal signal) {
+ m_signals.append({m_netVersion ? m_netVersion->current() : 0, signal, false});
+ while (m_signals.size() > m_maxSignalQueue)
+ m_signals.removeFirst();
+}
+
+template <typename Signal>
+List<Signal> NetElementSignal<Signal>::receive() {
+ List<Signal> received;
+ for (auto& p : m_signals) {
+ if (!p.received) {
+ received.append(p.signal);
+ p.received = true;
+ }
+ }
+ return received;
+}
+
+}
+
+#endif