"""Actual readable journal formatter and retained-record transport semantics.""" import re from policy_harness import ROOT,body,run p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_JournalText.c' formatter=p.read_text()[p.read_text().index('class ERR_JournalText'):] formatter=formatter.replace('class ERR_JournalText', 'struct ERR_JournalText').replace('\n}\n','\n};\n') formatter=re.sub(r'(sequence|messageId)\.ToString\(\)',r'string(std::to_string(\1))',formatter) journal=ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQJournal.c' write=body(journal,'void Write(').replace('Replication.IsServer()', 'Replication::server').replace('GetGame().GetWorld().GetWorldTime() / 1000','12.7f').replace('Math.Round(seconds * 10)', 'std::round(seconds * 10)').replace('string.Format', 'string::Format').replace('ERR_JournalText.Entry','ERR_JournalText::Entry').replace('SCR_DateTimeHelper.GetTimeLocal()', 'SCR_DateTimeHelper::GetTimeLocal()') read=body(journal,'void Read(').replace('out array lines','Array& lines').replace('out int cursor','int& cursor').replace('Math.Clamp','Math::Clamp').replace('string.Format','string::Format').replace('int characters;','int characters=0;') run(r''' #include #include #include #include #include #include struct string:std::string{ using std::string::string;string(std::string s):std::string(s){} int Length()const{return size();}bool IsEmpty()const{return empty();} int IndexOf(string s)const{auto i=find(s);return i==npos?-1:int(i);} string Substring(int p,int n)const{return substr(p,n);}bool Contains(string s)const{return find(s)!=npos;} void Replace(string a,string b){size_t i=0;while((i=find(a,i))!=npos){replace(i,a.size(),b);i+=b.size();}} void ToLower(){for(char& c:*this)c=std::tolower((unsigned char)c);} templatestatic string Convert(T v){std::ostringstream out;out<static string Format(string fmt,T...args){std::vector values{Convert(args)...};for(int i=values.size();i>0;i--)fmt.Replace("%"+std::to_string(i),values[i-1]);return fmt;} }; templatestruct Array:std::vector{int Count()const{return this->size();}bool IsEmpty()const{return this->empty();}void Insert(T v){this->push_back(v);}void Remove(int i){this->erase(this->begin()+i);}void Clear(){this->clear();}}; namespace Replication{bool server=true;} namespace SCR_DateTimeHelper{string clock="09:05:07";string GetTimeLocal(){return clock;}} namespace Math{int Clamp(int v,int a,int b){return std::clamp(v,a,b);}} '''+formatter+r''' struct Journal{ Array m_Recent,m_Pending;int m_Sequence=0,m_Lost=0;string m_Session="fixture"; string Path(){return "test.log";} '''+write+read+r''' }; int main(){ assert(ERR_JournalText::Field("destination=<10, 20, 30>; foo=bar","destination")=="<10, 20, 30>"); assert(ERR_JournalText::Field("foo=bar; baz=","baz")=="unknown"); assert(ERR_JournalText::Field("no fields","crew")=="unknown"); auto ended=ERR_JournalText::Description("BODY RECOVERY END","job=1 stage=0 delivered=0; preparation deadline"); assert(ended.Contains("without an inspection report")); assert(ERR_JournalText::Description("BODY RECOVERY END","job=1 stage=3 delivered=1;").Contains("HQ received")); assert(ERR_JournalText::Description("BODY RECOVERY TEAM","job=1").Contains("preparation may still be pending")); auto queued=ERR_JournalText::Description("ORDER QUEUED","group 4 search"); assert(queued.Contains("not received")&&!queued.Contains("order delivered")); assert(ERR_JournalText::Description("ORDER DELIVERED","group 4 search").Contains("order delivered")); assert(ERR_JournalText::Description("CONTACT LOCAL","group=3 observed=<1,2,3>").Contains("still needs to reach HQ")); assert(ERR_JournalText::Description("LOST","caller died").Contains("failed")); auto spawned=ERR_JournalText::Description("SPAWN MEMBER","group=3 actor=Character<0x123> prefab={ABC}asset position=<10,20,30>"); assert(spawned.Contains("Group 3")&&spawned.Contains("<10,20,30>")&&!spawned.Contains("0x")&&!spawned.Contains("prefab")); auto escalation=ERR_JournalText::Description("AGGRESSION","bodies=9 aggression=3/30 hunter allowance=5/15"); assert(escalation.Contains("9 bodies")&&escalation.Contains("3/30")&&escalation.Contains("5/15")); auto mortar=ERR_JournalText::Description("MORTAR SITE STATUS","site=2 operational=0 fighting=4 inventory HE=27 radio connected=1"); assert(mortar.Contains("operational: no")&&mortar.Contains("27")&&mortar.Contains("connected: yes")); auto mine=ERR_JournalText::Description("MINE EQUIPMENT","actor=Character<0x123> finite two-mine allowance issued"); assert(mine.Contains("up to two")&&!mine.Contains("0x")); assert(ERR_JournalText::Description("FUTURE_EVENT","something happened")=="future event: something happened"); Journal journal;Replication::server=false;journal.Write("REGISTER","group=1");assert(journal.m_Sequence==0);Replication::server=true; journal.Write("ORDER QUEUED","group 4 search",7); string full=journal.m_Recent[0];assert(full.Contains("#1 t=")&&full.Contains("M7 ORDER QUEUED group 4 search [session=fixture]")); assert(journal.m_Pending[0]==full&&full.Contains("not received")&&full.find("[09:05:07] ")==0); SCR_DateTimeHelper::clock="00:00:01"; // later viewing must not restamp the stored event string summary=ERR_JournalText::Menu(full,false),details=ERR_JournalText::Menu(full,true); assert(!summary.Contains("session=")&&summary.Contains("event 1, message 7")); assert(details.Contains("session=")&&details.Contains("No. 1")&&details.Contains(summary)); assert(journal.m_Recent[0]==full&&summary.find("[09:05:07] ")==0); // retained event time survives later rendering Journal midnight;midnight.Write("REPORT","after midnight"); assert(midnight.m_Recent[0].find("[00:00:01] ")==0); assert(ERR_JournalText::Menu("#4 legacy",false)=="No. 4 legacy"); for(int i=0;i<304;i++)journal.Write("REPORT","position known",i); Array lines;int cursor; journal.Read(0,lines,cursor,8); assert(journal.m_Recent.Count()==300&&lines.Count()==8&&lines[0].Contains("5 older entries")&&cursor==12); int before=cursor;journal.Read(cursor,lines,cursor,8);assert(lines.Count()==8&&cursor==before+8); Journal large;string huge(9000,'x');large.Write("UNKNOWN",huge);large.Write("UNKNOWN",huge); large.Read(0,lines,cursor,40);assert(lines.Count()==1&&cursor==1); large.Read(cursor,lines,cursor,40);assert(lines.Count()==1&&cursor==2); // unread event not skipped at RPC limit } ''') print('PASS: actual summaries preserve queued/delivered meaning, clear counts and IDs; raw records, legacy display, cursor gaps and RPC limits remain intact')