Bundle mission speech with an admin mute option and fix live audio downloads
This commit is contained in:
@@ -135,7 +135,7 @@ print('PASS: production incremental decoder preserves binary data, bounds each s
|
||||
def client_cpp(text):
|
||||
text = cpp(text)
|
||||
for old, new in [
|
||||
('ERR_WelcomeVoiceRules.', 'Rules::'), ('ERR_GameMode.Get()', 'ERR_GameMode::Get()'),
|
||||
('ResourceName', 'string'), ('ERR_BakedSpeech.', 'ERR_BakedSpeech::'), ('ERR_WelcomeVoiceRules.', 'Rules::'), ('ERR_GameMode.Get()', 'ERR_GameMode::Get()'),
|
||||
('FileIO.', 'FileIO::'), ('AudioSystem.', 'AudioSystem::'),
|
||||
('AudioHandle.Invalid', 'AudioHandle::Invalid'),
|
||||
('FileMode.', 'FileMode::'), ('RestContext context', 'RestContext* context'),
|
||||
@@ -154,7 +154,7 @@ def client_cpp(text):
|
||||
|
||||
client_methods = '\n'.join(client_cpp(body(SOURCE, signature)) for signature in [
|
||||
'protected bool Current()', 'bool PreparingDownload()', 'void Tick(',
|
||||
'protected void Downloaded(', 'protected void CancelDownload()',
|
||||
'protected void BeginPreparation(', 'protected void CancelDownload()',
|
||||
'bool PrepareDownload()', 'void Stop()',
|
||||
]).replace('void Tick(', 'virtual void Tick(').replace('void Stop()', 'virtual void Stop()')
|
||||
soldier_source = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_SoldierSpeech.c'
|
||||
@@ -175,16 +175,48 @@ connection = 'struct Connection { bool m_Attempted=false;' + '\n'.join(
|
||||
wav = b'RIFF' + (9992).to_bytes(4, 'little') + b'WAVE' + random.Random(71).randbytes(9988)
|
||||
wav64 = json.dumps(base64.b64encode(wav).decode())
|
||||
expected = 'Array<int>{' + ','.join(map(str, wav)) + '}'
|
||||
run(PREAMBLE + decoder + connection + r'''
|
||||
transfer = cpp(body(SOURCE, 'class ERR_VoiceTransfer')).replace('class ERR_VoiceTransfer', 'struct ERR_VoiceTransfer').replace('int m_Total;', 'int m_Total=0;') + ';'
|
||||
run(PREAMBLE + transfer + r'''
|
||||
int main(){
|
||||
for(int size:{60,262140,262144,262148,1600060,2796204}){
|
||||
ERR_VoiceTransfer transfer;string expected(size, 'A');int offset=0,requests=0;
|
||||
while(offset<size){
|
||||
assert(transfer.Part()==offset/262144);
|
||||
int length=std::min(262144,size-offset);
|
||||
int result=transfer.Accept(offset,size,expected.substr(offset,length));
|
||||
offset+=length;requests++;
|
||||
assert(result==(offset==size?1:0));assert(requests<=11);
|
||||
}
|
||||
assert(transfer.Data()==expected);
|
||||
assert(transfer.Accept(offset,size,"AAAA")==-1);
|
||||
transfer.Clear();assert(transfer.Data().IsEmpty()&&transfer.Part()==0);
|
||||
}
|
||||
for(int total:{0,59,61,2796208}){
|
||||
ERR_VoiceTransfer bad;assert(bad.Accept(0,total,"AAAA")==-1);
|
||||
assert(bad.Data().IsEmpty());
|
||||
}
|
||||
ERR_VoiceTransfer partial;assert(partial.Accept(0,524288,string(262144,'A'))==0);
|
||||
assert(partial.Accept(0,524288,string(262144,'A'))==-1); // duplicate
|
||||
assert(partial.Accept(524288,786432,string(262144,'A'))==-1); // gap
|
||||
assert(partial.Accept(262144,524292,string(262144,'A'))==-1); // changed size
|
||||
assert(partial.Accept(262144,524288,string(262140,'A'))==-1); // truncated
|
||||
assert(partial.Accept(262144,524288,string(262148,'A'))==-1); // oversized
|
||||
assert(partial.Data().Length()==262144);
|
||||
assert(partial.Accept(262144,524288,string(262144,'A'))==1);
|
||||
}
|
||||
''')
|
||||
print('PASS: production speech transfer checks order, exact part sizes and stable bounded totals without changing audio')
|
||||
run(PREAMBLE + decoder + transfer + connection + r'''
|
||||
namespace AudioHandle {const int Invalid=-1;}
|
||||
namespace AudioSystem {int stopped=0;void TerminateSound(int){stopped++;}}
|
||||
struct ERR_GameMode {static inline ERR_GameMode* live=nullptr;bool active=true;
|
||||
struct ERR_GameMode {static inline ERR_GameMode* live=nullptr;bool active=true;bool ERR_RecordingsEnabled(){return true;}
|
||||
static ERR_GameMode* Get(){return live;}bool Active(){return active;}};
|
||||
struct RestCallback {string data;void SetOnSuccess(int){}void SetOnError(int){}string GetData(){return data;}};
|
||||
int requests=0;
|
||||
struct RestContext {void SetTimeout(int){}void GET(RestCallback*,string){requests++;}};
|
||||
struct Api {RestContext context;RestContext* GetContext(string){return &context;}};
|
||||
struct Rules {static bool HTTPReady(){return true;}
|
||||
struct ERR_BakedSpeech {static string Graph(string){return "";}};
|
||||
struct Rules {static bool HTTPReady(){return true;}static bool Source(string value){return URL(value);}
|
||||
''' + body(SOURCE, 'static bool URL(') + r'''
|
||||
};
|
||||
namespace FileMode {enum Type {WRITE,READ};}
|
||||
@@ -222,6 +254,8 @@ struct Game {
|
||||
} game;
|
||||
Game* GetGame(){return &game;}
|
||||
struct Client {
|
||||
ERR_VoiceTransfer* m_Transfer=nullptr;string m_DownloadURL,m_BakedGraph;
|
||||
void RequestPart(){requests++;}
|
||||
ERR_GameMode* m_Mode=nullptr;string m_Path,m_Text;Connection connection;Connection* m_Connection=&connection;
|
||||
bool m_Stopped=false,m_Downloaded=false,m_Started=false;float m_Wait=0;
|
||||
RestCallback* m_Callback=nullptr;ERR_WelcomeVoiceDecoder* m_Decoder=nullptr;File* m_Output=nullptr;
|
||||
@@ -229,7 +263,7 @@ struct Client {
|
||||
explicit Client(string path):m_Mode(ERR_GameMode::live),m_Path(path){}
|
||||
bool Permit(){return true;}virtual void Play(){plays++;}
|
||||
''' + client_methods + r'''
|
||||
void Receive(string encoded){Tick(3,true,"http://voice/clip","hello");RestCallback response;response.data=encoded;Downloaded(&response);}
|
||||
void Receive(string encoded){Tick(3,true,"http://voice/clip","hello");BeginPreparation(encoded);}
|
||||
};
|
||||
''' + '\n'.join(queue_methods) + r'''
|
||||
struct Soldier:Client {
|
||||
@@ -276,7 +310,7 @@ int main(){
|
||||
game.ERR_PrepareVoiceDownloads();int beforeCloses=closes;stopped.Stop();
|
||||
assert(closes==beforeCloses+1&&!FileIO::files["stopped"].exists&&!stopped.PreparingDownload());
|
||||
assert(game.m_ERRVoiceDownloads.Count()==1);beforeWrites=writes;
|
||||
stopped.Stop();RestCallback late;late.data=wav;stopped.Downloaded(&late);
|
||||
stopped.Stop();stopped.BeginPreparation(wav);
|
||||
stopped.Tick(1,true,"","");assert(stopped.plays==0&&writes==beforeWrites&&game.m_ERRVoiceDownloads.Count()==1);
|
||||
Drain();assert(survivor.m_Downloaded);
|
||||
// Each failure path removes the partial file and never announces readiness.
|
||||
|
||||
Reference in New Issue
Block a user