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

summaryrefslogtreecommitdiff
path: root/source/client/StarClientApplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/client/StarClientApplication.cpp')
-rw-r--r--source/client/StarClientApplication.cpp69
1 files changed, 66 insertions, 3 deletions
diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp
index 356421b..33327fa 100644
--- a/source/client/StarClientApplication.cpp
+++ b/source/client/StarClientApplication.cpp
@@ -14,9 +14,13 @@
#include "StarWorldTemplate.hpp"
#include "StarWorldClient.hpp"
#include "StarRootLoader.hpp"
+#include "StarInput.hpp"
+#include "StarVoice.hpp"
+#include "StarCurve25519.hpp"
#include "StarInterfaceLuaBindings.hpp"
#include "StarInputLuaBindings.hpp"
+#include "StarVoiceLuaBindings.hpp"
namespace Star {
@@ -171,6 +175,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>(appController);
auto configuration = m_root->configuration();
bool vsync = configuration->get("vsync").toBool();
@@ -204,6 +209,12 @@ void ClientApplication::applicationInit(ApplicationControllerPtr appController)
appController->setMaxFrameSkip(assets->json("/client.config:maxFrameSkip").toUInt());
appController->setUpdateTrackWindow(assets->json("/client.config:updateTrackWindow").toFloat());
+
+ if (auto jVoice = configuration->get("voice"))
+ m_voice->loadJson(jVoice.toObject(), true);
+
+ m_voice->init();
+ m_voice->setLocalSpeaker(0);
}
void ClientApplication::renderInit(RendererPtr renderer) {
@@ -365,6 +376,12 @@ void ClientApplication::update() {
updateTitle();
else if (m_state > MainAppState::Title)
updateRunning();
+
+ // Swallow leftover encoded voice data if we aren't in-game to allow mic read to continue for settings.
+ if (m_state <= MainAppState::Title) {
+ DataStreamBuffer ext;
+ m_voice->send(ext);
+ } // TODO: directly disable encoding at menu so we don't have to do this
m_guiContext->cleanup();
m_edgeKeyEvents.clear();
@@ -417,8 +434,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) {
@@ -450,6 +471,8 @@ void ClientApplication::changeState(MainAppState newState) {
}
m_cinematicOverlay->stop();
+ m_voice->clearSpeakers();
+
if (auto p2pNetworkingService = appController()->p2pNetworkingService()) {
p2pNetworkingService->setJoinUnavailable();
p2pNetworkingService->setAcceptingP2PConnections(false);
@@ -483,6 +506,7 @@ void ClientApplication::changeState(MainAppState newState) {
m_statistics = make_shared<Statistics>(m_root->toStoragePath("player"), appController()->statisticsService());
m_universeClient = make_shared<UniverseClient>(m_playerStorage, m_statistics);
m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks());
+ m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks());
m_mainMixer->setUniverseClient(m_universeClient);
m_titleScreen = make_shared<TitleScreen>(m_playerStorage, m_mainMixer->mixer());
@@ -601,6 +625,7 @@ void ClientApplication::changeState(MainAppState newState) {
m_worldPainter = make_shared<WorldPainter>();
m_mainInterface = make_shared<MainInterface>(m_universeClient, m_worldPainter, m_cinematicOverlay);
m_universeClient->setLuaCallbacks("interface", LuaBindings::makeInterfaceCallbacks(m_mainInterface.get()));
+ m_universeClient->startLua();
m_mainMixer->setWorldPainter(m_worldPainter);
@@ -839,13 +864,51 @@ void ClientApplication::updateRunning() {
if (checkDisconnection())
return;
+ m_voice->setInput(m_input->bindHeld("opensb", "pushToTalk"));
+ DataStreamBuffer voiceData;
+ voiceData.setByteOrder(ByteOrder::LittleEndian);
+ //voiceData.writeBytes(VoiceBroadcastPrefix.utf8Bytes()); transmitting with SE compat for now
+ bool needstoSendVoice = m_voice->send(voiceData, 5000);
m_universeClient->update();
if (checkDisconnection())
return;
- if (auto worldClient = m_universeClient->worldClient())
+ if (auto worldClient = m_universeClient->worldClient()) {
+ auto& broadcastCallback = worldClient->broadcastCallback();
+ if (!broadcastCallback) {
+ broadcastCallback = [&](PlayerPtr player, StringView broadcast) -> bool {
+ auto& view = broadcast.utf8();
+ if (view.rfind(VoiceBroadcastPrefix.utf8(), 0) != NPos) {
+ auto entityId = player->entityId();
+ auto speaker = m_voice->speaker(connectionForEntity(entityId));
+ speaker->entityId = entityId;
+ speaker->name = player->name();
+ speaker->position = player->mouthPosition();
+ m_voice->receive(speaker, view.substr(VoiceBroadcastPrefix.utf8Size()));
+ }
+ return true;
+ };
+ }
+
+ if (worldClient->inWorld()) {
+ if (needstoSendVoice) {
+ auto signature = Curve25519::sign(voiceData.ptr(), voiceData.size());
+ std::string_view signatureView((char*)signature.data(), signature.size());
+ std::string_view audioDataView(voiceData.ptr(), voiceData.size());
+ auto broadcast = strf("data\0voice\0{}{}"s, signatureView, audioDataView);
+ worldClient->sendSecretBroadcast(broadcast, true);
+ }
+ if (auto mainPlayer = m_universeClient->mainPlayer()) {
+ auto localSpeaker = m_voice->localSpeaker();
+ localSpeaker->position = mainPlayer->position();
+ localSpeaker->entityId = mainPlayer->entityId();
+ localSpeaker->name = mainPlayer->name();
+ }
+ m_voice->setLocalSpeaker(worldClient->connection());
+ }
worldClient->setInteractiveHighlightMode(isActionTaken(InterfaceAction::ShowLabels));
+ }
updateCamera();