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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/base/StarMixer.cpp10
-rw-r--r--source/base/StarMixer.hpp3
-rw-r--r--source/client/StarClientApplication.cpp12
-rw-r--r--source/client/StarClientApplication.hpp5
-rw-r--r--source/core/StarDataStream.cpp4
-rw-r--r--source/core/StarDataStreamDevices.cpp7
-rw-r--r--source/core/StarDataStreamDevices.hpp3
-rw-r--r--source/frontend/StarMainMixer.cpp4
-rw-r--r--source/frontend/StarMainMixer.hpp2
-rw-r--r--source/game/CMakeLists.txt2
-rw-r--r--source/game/StarNetworkedAnimator.cpp9
-rw-r--r--source/game/StarNetworkedAnimator.hpp2
-rw-r--r--source/game/StarPlayer.cpp49
-rw-r--r--source/game/StarPlayer.hpp22
-rw-r--r--source/game/StarVoice.cpp35
-rw-r--r--source/game/StarVoice.hpp32
16 files changed, 189 insertions, 12 deletions
diff --git a/source/base/StarMixer.cpp b/source/base/StarMixer.cpp
index 96705b0..7b8e338 100644
--- a/source/base/StarMixer.cpp
+++ b/source/base/StarMixer.cpp
@@ -221,7 +221,7 @@ void Mixer::stopAll(float rampTime) {
p.first->stop(vel);
}
-void Mixer::read(int16_t* outBuffer, size_t frameCount) {
+void Mixer::read(int16_t* outBuffer, size_t frameCount, ExtraMixFunction extraMixFunction) {
// Make this method as least locky as possible by copying all the needed
// member data before the expensive audio / effect stuff.
unsigned sampleRate;
@@ -326,7 +326,7 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount) {
m_mixBuffer[s * channels + c] = 0;
} else {
for (size_t c = 0; c < channels; ++c)
- m_mixBuffer[s * channels + c] = m_mixBuffer[s * channels + c] * volume;
+ m_mixBuffer[s * channels + c] *= volume;
}
}
}
@@ -338,7 +338,8 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount) {
float vol = lerp((float)s / frameCount, beginVolume * groupVolume * audioStopVolBegin, endVolume * groupEndVolume * audioStopVolEnd);
for (size_t c = 0; c < channels; ++c) {
float sample = m_mixBuffer[s * channels + c] * vol * audioState.positionalChannelVolumes[c] * audioInstance->m_volume.value;
- outBuffer[s * channels + c] = clamp(sample + outBuffer[s * channels + c], -32767.0f, 32767.0f);
+ int16_t& outSample = outBuffer[s * channels + c];
+ outSample = clamp(sample + outSample, -32767.0f, 32767.0f);
}
}
@@ -347,6 +348,9 @@ void Mixer::read(int16_t* outBuffer, size_t frameCount) {
}
}
+ if (extraMixFunction)
+ extraMixFunction(outBuffer, bufferSize, channels);
+
{
MutexLocker locker(m_effectsMutex);
// Apply all active effects
diff --git a/source/base/StarMixer.hpp b/source/base/StarMixer.hpp
index 079549f..d369cfb 100644
--- a/source/base/StarMixer.hpp
+++ b/source/base/StarMixer.hpp
@@ -95,6 +95,7 @@ private:
// Thread safe mixer class with basic effects support.
class Mixer {
public:
+ typedef function<void(int16_t* buffer, size_t frames, unsigned channels)> ExtraMixFunction;
typedef function<void(int16_t* buffer, size_t frames, unsigned channels)> EffectFunction;
typedef function<float(unsigned, Vec2F, float)> PositionalAttenuationFunction;
@@ -126,7 +127,7 @@ public:
// Reads pending audio data. This is thread safe with the other Mixer
// methods, but only one call to read may be active at a time.
- void read(int16_t* samples, size_t frameCount);
+ void read(int16_t* samples, size_t frameCount, ExtraMixFunction extraMixFunction = {});
// Call within the main loop of the program using Mixer, calculates
// positional attenuation of audio and does cleanup.
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 356421b..e2a1515 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -14,6 +14,9 @@
#include "StarWorldTemplate.hpp"
#include "StarWorldClient.hpp"
#include "StarRootLoader.hpp"
+#include "StarInput.hpp"
+#include "StarVoice.hpp"
+
#include "StarInterfaceLuaBindings.hpp"
#include "StarInputLuaBindings.hpp"
@@ -171,6 +174,7 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
m_guiContext = make_shared<GuiContext>(m_mainMixer->mixer(), appController);
m_input = make_shared<Input>();
+ m_voice = make_shared<Voice>();
auto configuration = m_root->configuration();
bool vsync = configuration->get("vsync").toBool();
@@ -417,8 +421,12 @@ void ClientApplication::render() {
}
void ClientApplication::getAudioData(int16_t* sampleData, size_t frameCount) {
- if (m_mainMixer)
- m_mainMixer->read(sampleData, frameCount);
+ if (m_mainMixer) {
+ m_mainMixer->read(sampleData, frameCount, [&](int16_t* buffer, size_t frames, unsigned channels) {
+ if (m_voice)
+ m_voice->mix(buffer, frames, channels);
+ });
+ }
}
void ClientApplication::changeState(MainAppState newState) {
diff --git a/source/client/StarClientApplication.hpp b/source/client/StarClientApplication.hpp
index 186efaf..4ee837e 100644
--- a/source/client/StarClientApplication.hpp
+++ b/source/client/StarClientApplication.hpp
@@ -11,11 +11,13 @@
#include "StarErrorScreen.hpp"
#include "StarCinematic.hpp"
#include "StarKeyBindings.hpp"
-#include "StarInput.hpp"
#include "StarMainApplication.hpp"
namespace Star {
+STAR_CLASS(Input);
+STAR_CLASS(Voice);
+
class ClientApplication : public Application {
protected:
virtual void startup(StringList const& cmdLineArgs) override;
@@ -76,6 +78,7 @@ private:
MainMixerPtr m_mainMixer;
GuiContextPtr m_guiContext;
InputPtr m_input;
+ VoicePtr m_voice;
// Valid after renderInit is called the first time
CinematicPtr m_cinematicOverlay;
diff --git a/source/core/StarDataStream.cpp b/source/core/StarDataStream.cpp
index c8d50a4..834f4de 100644
--- a/source/core/StarDataStream.cpp
+++ b/source/core/StarDataStream.cpp
@@ -205,7 +205,7 @@ size_t DataStream::readVlqU(uint64_t& i) {
size_t bytesRead = Star::readVlqU(i, makeFunctionInputIterator([this]() { return this->read<uint8_t>(); }));
if (bytesRead == NPos)
- throw DataStreamException("Error reading VLQ encoded intenger!");
+ throw DataStreamException("Error reading VLQ encoded integer!");
return bytesRead;
}
@@ -214,7 +214,7 @@ size_t DataStream::readVlqI(int64_t& i) {
size_t bytesRead = Star::readVlqI(i, makeFunctionInputIterator([this]() { return this->read<uint8_t>(); }));
if (bytesRead == NPos)
- throw DataStreamException("Error reading VLQ encoded intenger!");
+ throw DataStreamException("Error reading VLQ encoded integer!");
return bytesRead;
}
diff --git a/source/core/StarDataStreamDevices.cpp b/source/core/StarDataStreamDevices.cpp
index 0c37d8d..85e6d3f 100644
--- a/source/core/StarDataStreamDevices.cpp
+++ b/source/core/StarDataStreamDevices.cpp
@@ -164,4 +164,11 @@ void DataStreamExternalBuffer::reset(char const* externalData, size_t len) {
m_buffer.reset(externalData, len);
}
+void DataStreamExternalBuffer::readData(char* data, size_t len) {
+ m_buffer.readFull(data, len);
+}
+void DataStreamExternalBuffer::writeData(char const* data, size_t len) {
+ m_buffer.writeFull(data, len);
+}
+
}
diff --git a/source/core/StarDataStreamDevices.hpp b/source/core/StarDataStreamDevices.hpp
index 88ee0e9..4a12d24 100644
--- a/source/core/StarDataStreamDevices.hpp
+++ b/source/core/StarDataStreamDevices.hpp
@@ -140,6 +140,9 @@ public:
void reset(char const* externalData, size_t len);
+ void readData(char* data, size_t len) override;
+ void writeData(char const* data, size_t len) override;
+
private:
ExternalBuffer m_buffer;
};
diff --git a/source/frontend/StarMainMixer.cpp b/source/frontend/StarMainMixer.cpp
index c49a0fc..59b6b52 100644
--- a/source/frontend/StarMainMixer.cpp
+++ b/source/frontend/StarMainMixer.cpp
@@ -127,8 +127,8 @@ void MainMixer::setVolume(float volume, float rampTime) {
m_mixer->setVolume(volume, rampTime);
}
-void MainMixer::read(int16_t* sampleData, size_t frameCount) {
- m_mixer->read(sampleData, frameCount);
+void MainMixer::read(int16_t* sampleData, size_t frameCount, Mixer::ExtraMixFunction extraMixFunction) {
+ m_mixer->read(sampleData, frameCount, extraMixFunction);
}
}
diff --git a/source/frontend/StarMainMixer.hpp b/source/frontend/StarMainMixer.hpp
index ecf9443..2582a2f 100644
--- a/source/frontend/StarMainMixer.hpp
+++ b/source/frontend/StarMainMixer.hpp
@@ -22,7 +22,7 @@ public:
MixerPtr mixer() const;
void setVolume(float volume, float rampTime = 0.0f);
- void read(int16_t* sampleData, size_t frameCount);
+ void read(int16_t* sampleData, size_t frameCount, Mixer::ExtraMixFunction = {});
private:
UniverseClientPtr m_universeClient;
diff --git a/source/game/CMakeLists.txt b/source/game/CMakeLists.txt
index 120e9e8..fa55950 100644
--- a/source/game/CMakeLists.txt
+++ b/source/game/CMakeLists.txt
@@ -156,6 +156,7 @@ SET (star_game_HEADERS
StarVehicle.hpp
StarVehicleDatabase.hpp
StarVersioningDatabase.hpp
+ StarVoice.hpp
StarWarping.hpp
StarWeather.hpp
StarWeatherTypes.hpp
@@ -414,6 +415,7 @@ SET (star_game_SOURCES
StarVehicle.cpp
StarVehicleDatabase.cpp
StarVersioningDatabase.cpp
+ StarVoice.cpp
StarWarping.cpp
StarWeather.cpp
StarWeatherTypes.cpp
diff --git a/source/game/StarNetworkedAnimator.cpp b/source/game/StarNetworkedAnimator.cpp
index f76882f..6f74f02 100644
--- a/source/game/StarNetworkedAnimator.cpp
+++ b/source/game/StarNetworkedAnimator.cpp
@@ -383,6 +383,15 @@ void NetworkedAnimator::setGlobalTag(String tagName, String tagValue) {
m_globalTags.set(move(tagName), move(tagValue));
}
+void NetworkedAnimator::removeGlobalTag(String const& tagName) {
+ m_globalTags.remove(tagName);
+}
+
+String const* NetworkedAnimator::globalTagPtr(String const& tagName) const {
+ return m_globalTags.ptr(tagName);
+}
+
+
void NetworkedAnimator::setPartTag(String const& partType, String tagName, String tagValue) {
m_partTags[partType].set(move(tagName), move(tagValue));
}
diff --git a/source/game/StarNetworkedAnimator.hpp b/source/game/StarNetworkedAnimator.hpp
index 563a21e..63f7774 100644
--- a/source/game/StarNetworkedAnimator.hpp
+++ b/source/game/StarNetworkedAnimator.hpp
@@ -115,6 +115,8 @@ public:
// Drawables can also have a <frame> tag which will be set to whatever the
// current state frame is (1 indexed, so the first frame is 1).
void setGlobalTag(String tagName, String tagValue);
+ void removeGlobalTag(String const& tagName);
+ String const* globalTagPtr(String const& tagName) const;
void setPartTag(String const& partType, String tagName, String tagValue);
void setProcessingDirectives(Directives const& directives);
diff --git a/source/game/StarPlayer.cpp b/source/game/StarPlayer.cpp
index af8a2ed..c9b337f 100644
--- a/source/game/StarPlayer.cpp
+++ b/source/game/StarPlayer.cpp
@@ -2464,4 +2464,53 @@ Vec2F Player::cameraPosition() {
return position();
}
+NetworkedAnimatorPtr Player::effectsAnimator() {
+ return m_effectsAnimator;
+}
+
+const String secretProprefix = strf("{:c}JsonProperty{:c}", 0, 0);
+
+Maybe<StringView> Player::getSecretPropertyView(String const& name) const {
+ if (auto tag = m_effectsAnimator->globalTagPtr(secretProprefix + name)) {
+ auto& view = tag->utf8();
+ DataStreamExternalBuffer buffer(view.data(), view.size());
+ try {
+ uint8_t typeIndex = buffer.read<uint8_t>() - 1;
+ if ((Json::Type)typeIndex == Json::Type::String) {
+ size_t len = buffer.readVlqU();
+ size_t pos = buffer.pos();
+ if (pos + len == buffer.size())
+ return StringView(buffer.ptr() + pos, len);
+ }
+ }
+ catch (StarException const& e) {}
+ }
+
+ return {};
+}
+
+Json Player::getSecretProperty(String const& name, Json defaultValue) const {
+ if (auto tag = m_effectsAnimator->globalTagPtr(secretProprefix + name)) {
+ DataStreamExternalBuffer buffer(tag->utf8Ptr(), tag->utf8Size());
+ try
+ { return buffer.read<Json>(); }
+ catch (StarException const& e)
+ { Logger::error("Exception reading secret player property '{}': {}", name, e.what()); }
+ }
+
+ return move(defaultValue);
+}
+
+void Player::setSecretProperty(String const& name, Json const& value) {
+ if (value) {
+ DataStreamBuffer ds;
+ ds.write(value);
+ auto& data = ds.data();
+ m_effectsAnimator->setGlobalTag(secretProprefix + name, String(data.ptr(), data.size()));
+ }
+ else
+ m_effectsAnimator->removeGlobalTag(secretProprefix + name);
+}
+
+
}
diff --git a/source/game/StarPlayer.hpp b/source/game/StarPlayer.hpp
index c63fe15..d534e03 100644
--- a/source/game/StarPlayer.hpp
+++ b/source/game/StarPlayer.hpp
@@ -447,6 +447,28 @@ public:
using Entity::setTeam;
+ NetworkedAnimatorPtr effectsAnimator();
+
+ // We need to store ephemeral/large/always-changing networked properties that other clients can read. Candidates:
+ // genericProperties:
+ // Non-starter, is not networked.
+ // statusProperties:
+ // Nope! Changes to the status properties aren't networked efficiently - one change resends the whole map.
+ // We can't fix that because it would break compatibility with vanilla servers.
+ // effectsAnimator's globalTags:
+ // Cursed, but viable.
+ // Efficient networking due to using a NetElementMapWrapper.
+ // Unfortunately values are Strings, so to work with Json we need to serialize/deserialize. Whatever.
+ // Additionally, this is compatible with vanilla networking.
+ // I call this a 'secret property'.
+
+ // If the secret property exists as a serialized Json string, returns a view to it without deserializing.
+ Maybe<StringView> getSecretPropertyView(String const& name) const;
+ // Gets a secret Json property. It will be de-serialized.
+ Json getSecretProperty(String const& name, Json defaultValue = Json()) const;
+ // Sets a secret Json property. It will be serialized.
+ void setSecretProperty(String const& name, Json const& value);
+
private:
enum class State {
Idle,
diff --git a/source/game/StarVoice.cpp b/source/game/StarVoice.cpp
new file mode 100644
index 0000000..1c949c1
--- /dev/null
+++ b/source/game/StarVoice.cpp
@@ -0,0 +1,35 @@
+#include "StarVoice.hpp"
+
+namespace Star {
+
+STAR_EXCEPTION(VoiceException, StarException);
+
+void Voice::mix(int16_t* buffer, size_t frames, unsigned channels) {
+
+}
+
+Voice* Voice::s_singleton;
+
+Voice* Voice::singletonPtr() {
+ return s_singleton;
+}
+
+Voice& Voice::singleton() {
+ if (!s_singleton)
+ throw VoiceException("Voice::singleton() called with no Voice instance available");
+ else
+ return *s_singleton;
+}
+
+Voice::Voice() {
+ if (s_singleton)
+ throw VoiceException("Singleton Voice has been constructed twice");
+
+ s_singleton = this;
+}
+
+Voice::~Voice() {
+ s_singleton = nullptr;
+}
+
+} \ No newline at end of file
diff --git a/source/game/StarVoice.hpp b/source/game/StarVoice.hpp
new file mode 100644
index 0000000..f102889
--- /dev/null
+++ b/source/game/StarVoice.hpp
@@ -0,0 +1,32 @@
+#ifndef STAR_VOICE_HPP
+#define STAR_VOICE_HPP
+#include "StarString.hpp"
+
+namespace Star {
+
+ STAR_CLASS(Voice);
+
+ class Voice {
+ public:
+ void mix(int16_t* buffer, size_t frames, unsigned channels);
+
+ // Get pointer to the singleton Voice instance, if it exists. Otherwise,
+ // returns nullptr.
+ static Voice* singletonPtr();
+
+ // Gets reference to Voice singleton, throws VoiceException if root
+ // is not initialized.
+ static Voice& singleton();
+
+ Voice();
+ ~Voice();
+
+ Voice(Voice const&) = delete;
+ Voice& operator=(Voice const&) = delete;
+ private:
+ static Voice* s_singleton;
+ };
+
+}
+
+#endif \ No newline at end of file