Bundle mission speech with an admin mute option and fix live audio downloads

This commit is contained in:
2026-10-15 16:53:39 +02:00
parent 07c4d70de5
commit 009b2fb591
181 changed files with 19248 additions and 103 deletions
+19 -4
View File
@@ -17,9 +17,9 @@ def adapt(s):
s=s.replace('GetGame().','GetGame()->').replace('GetWorld().','GetWorld()->')
return s
rules='struct ERR_SpeechRules {\n'+'\n'.join(adapt(body(p,s)) for s in ['static bool Endpoint(', 'static string Normalize(', 'static bool Token(', 'static bool Text('])+'\n};'
methods=['string StaticURL()', 'bool Ready()', 'bool Busy()', 'bool Current()', 'bool IdleFor(',
methods=['bool Bundled()', 'string StaticURL()', 'bool Ready()', 'bool Busy()', 'bool Current()', 'bool IdleFor(',
'void ERR_SpeechService(', 'void Snapshot(', 'protected bool Save(',
'void Disable(', 'void TestAndEnable(', 'protected void Begin(',
'void SetRecordings(', 'void Disable(', 'void TestAndEnable(', 'protected void Begin(',
'bool Request(', 'void Tick()', 'void Finished(', 'void Stop()']
code='\n'.join(adapt(body(p,s)) for s in methods).replace('void ERR_SpeechService(', 'void Init(')
run(r'''
@@ -44,6 +44,8 @@ struct JsonSaveContext {std::map<string,string> data;void EnableTypeDiscriminato
namespace ERR_ProfileConfig {string VOICE="voice";bool Load(string,JsonLoadContext*){return loadOK;}bool Save(string,JsonSaveContext* json){if(!saveOK)return false;saves++;saved=json->data;return true;} }
namespace Replication {bool IsServer(){return server;}}
struct ERR_GameMode {static ERR_GameMode* live;static ERR_GameMode* Get(){return live;}bool active=true;int restored=0,published=0;bool pending=false;string lastURL,lastText;
bool recordings=true;bool ERR_RecordingsEnabled(){return recordings;}void ERR_SetRecordingsEnabled(bool v){recordings=v;}
bool bundled=false;bool ERR_UsesBundledWelcome(){return bundled;}
bool Active(){return active;}string ERR_CurrentWelcomeText(){return "Welcome to Nogova.";}
void ERR_RestoreStaticWelcome(){restored++;pending=false;}
void ERR_PublishWelcome(string url,string text){published++;lastURL=url;lastText=text;pending=false;}
@@ -59,7 +61,7 @@ struct ERR_SpeechRequest {string Text,Endpoint,Token;bool Enable=false,Boot=fals
};
struct ERR_SpeechService {
ERR_GameMode* m_Mode=nullptr;string m_Endpoint,m_Token,m_StaticURL,m_Status="Not configured";
bool m_Enabled=false,m_Ready=false,m_BootAttempted=false,m_Stopped=false;
bool m_Bundled=true;bool m_Enabled=false,m_Ready=false,m_BootAttempted=false,m_Stopped=false;
ERR_SpeechRequest* m_Request=nullptr;float m_Deadline=0,m_LastTest=-60000,m_LastRequest=-5000;
'''+code+r'''
};
@@ -72,6 +74,7 @@ int main(){
ERR_GameMode mode;ERR_GameMode::live=&mode;ERR_AdminSession admin,other;
profile={{"welcomeUrl","http://old/welcome.b64"}};
ERR_SpeechService service;service.Init(&mode);assert(service.StaticURL()=="http://old/welcome.b64");service.Tick();assert(starts==0&&saves==0&&!service.Ready());
mode.bundled=true;int beforeStarts=starts;service.Tick();assert(service.Bundled()&&starts==beforeStarts&&!service.Busy());mode.bundled=false;
ERR_SpeechReceiver receiver;assert(!service.Request("Hello",&receiver));
string secret="AbCdefghijklmnopqrstuvwxyz0123456789";
admin.valid=false;service.TestAndEnable(&admin,"https://speech/",secret);assert(starts==0);admin.valid=true;
@@ -86,6 +89,7 @@ int main(){
admin.valid=false;service.Finished(first,"https://speech/clip");assert(saves==0&&!service.Ready());admin.valid=true;
game.now+=60001;service.TestAndEnable(&admin,"https://speech/",secret);first=service.m_Request;
service.Finished(first,"https://speech/clip");assert(saves==1&&service.Ready()&&admin.previews==1&&mode.published==1);
assert(!service.Bundled()&&saved["bundledSpeech"]=="false");
assert(saved["briefingToken"]==secret&&saved["welcomeUrl"]=="http://old/welcome.b64"&&saved["ttsEnabled"]=="true");
Array snapshot;service.Snapshot(&snapshot);for(string line:snapshot)assert(line.find(secret)==string::npos);
game.now+=60001;service.TestAndEnable(&admin,"https://other/", "");assert(!service.Busy()&&saves==1);
@@ -94,8 +98,9 @@ int main(){
game.now+=60001;service.TestAndEnable(&admin,"https://speech/", "");first=service.m_Request;
service.Disable(&other);assert(!service.Ready()&&!service.Busy()&&first->cancelled&&saved["ttsEnabled"]=="false");
service.Finished(first,"https://speech/late");assert(!service.Ready()&&admin.previews==1); // late success cannot re-enable
assert(service.Bundled()&&saved["bundledSpeech"]=="true");
profile=saved;ERR_SpeechService disabled;disabled.Init(&mode);disabled.Tick();assert(!disabled.Ready()&&!disabled.Busy());
profile["ttsEnabled"]="true";ERR_SpeechService boot;boot.Init(&mode);int previous=starts;http=false;boot.Tick();assert(starts==previous);http=true;
profile["ttsEnabled"]="true";profile["bundledSpeech"]="false";ERR_SpeechService boot;boot.Init(&mode);int previous=starts;http=false;boot.Tick();assert(starts==previous);http=true;
boot.Tick();assert(boot.Busy()&&mode.pending);first=boot.m_Request;assert(first->Boot);
boot.Finished(first,"https://speech/cached");assert(boot.Ready()&&!mode.pending&&saves==2);
assert(!boot.IdleFor(65000));game.now+=65000;assert(boot.IdleFor(65000));
@@ -106,6 +111,16 @@ int main(){
boot.Finished(first,"https://speech/late");assert(receiver.completed==1&&boot.Ready());
ERR_SpeechService badBoot;badBoot.Init(&mode);badBoot.Tick();assert(badBoot.Busy());
badBoot.Finished(badBoot.m_Request,"");assert(!badBoot.Ready()&&!badBoot.Busy());
// A recordings toggle preserves live preferences and credentials, and commits only on successful save.
assert(mode.recordings);int beforeSaves=saves;
admin.valid=false;boot.SetRecordings(&admin,false);assert(mode.recordings&&saves==beforeSaves);admin.valid=true;
saveOK=false;boot.SetRecordings(&admin,false);assert(mode.recordings&&saves==beforeSaves);saveOK=true;
boot.SetRecordings(&admin,false);assert(!mode.recordings&&saved["recordingsEnabled"]=="false"&&saved["bundledSpeech"]=="false"&&saved["ttsEnabled"]=="true"&&saved["briefingToken"]==secret);
Array muted;boot.Snapshot(&muted);bool found=false;for(string line:muted)if(line=="recordingsEnabled=0")found=true;assert(found);
profile=saved;ERR_SpeechService reload;reload.Init(&mode);assert(!mode.recordings);
reload.Disable(&admin);assert(!mode.recordings&&saved["recordingsEnabled"]=="false");
reload.SetRecordings(&admin,true);assert(mode.recordings&&saved["recordingsEnabled"]=="true"&&saved["bundledSpeech"]=="true");
profile.erase("recordingsEnabled");mode.recordings=false;ERR_SpeechService legacy;legacy.Init(&mode);assert(mode.recordings);
boot.Stop();assert(!boot.Current()&&!boot.IdleFor(0));
}
''')