Continue safe roadblock placement after admission and prison unlock, build posts incrementally, and clean up incomplete transactions. Add bounded stuck-patrol dismount recovery, defer deployment initialization during terrain takeover, reset deferred site search timing on first player arrival, and fix atlas page serialization and terrain resource lookup. Validation: 30 native Everon posts with 120 living guards after unlock; seven affected regression suites pass; two final restart smoke rounds complete with 21 assertions and no script/runtime failures. Existing dependency asset errors remain.
98 lines
5.7 KiB
Python
98 lines
5.7 KiB
Python
"""Run shipped sheet geometry; no engine or multiplayer claims."""
|
|
import re
|
|
from policy_harness import ROOT, body, run
|
|
source = ROOT/'addons/core/Scripts/Game/ERR/30_Map/ERRM_SharedMapPages.c'
|
|
def adapt(signature):
|
|
text = body(source, signature)
|
|
for a,b in [('out float zoom','float& zoom'),('out int columns','int& columns'),('out int rows','int& rows'),('SCR_MapConstants.MAX_PIX_PER_METER','20.f'),('Math.Min','minf'),('Math.Max','maxf'),('Math.Ceil','ceilf'),('Math.Clamp','clampf'),('static const int','static constexpr int')]:
|
|
text=text.replace(a,b)
|
|
return re.sub(r"out (int|vector) (\w+)", r"\1& \2", text)
|
|
run(r'''
|
|
#include <array>
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <cmath>
|
|
using vector=std::array<float,3>;
|
|
vector Vector(float x,float y,float z){return {x,y,z};}
|
|
float minf(float a,float b){return std::min(a,b);}
|
|
float maxf(float a,float b){return std::max(a,b);}
|
|
float clampf(float a,float b,float c){return std::clamp(a,b,c);}
|
|
'''+'constexpr int COVER=16777215, OVERVIEW=16777214, REGION=16777216;\n'+adapt('static bool Layout(')+adapt('static vector Centre(')+''.join(adapt(sig) for sig in ['static bool IsRegion(', 'static int RegionColumns(', 'static int RegionRows(', 'static int RegionCount(', 'static int LastNumber(', 'static void RegionCells(', 'static int ParentRegion(', 'static float Boundary(', 'static void RegionBounds('])+adapt('static int Number(')+adapt('static int State(')+r'''
|
|
void check(vector size, vector offset){
|
|
float zoom;int cols,rows;
|
|
assert(Layout(size,.5f,zoom,cols,rows));
|
|
assert(cols>=1&&rows>=1&&cols*rows<=400);
|
|
assert(Number(COVER,cols,rows)==0&&Number(OVERVIEW,cols,rows)==1);
|
|
assert(State(0,cols,rows)==COVER&&State(1,cols,rows)==OVERVIEW);
|
|
assert(State(-1,cols,rows)==-1&&State(LastNumber(cols,rows)+1,cols,rows)==-1);
|
|
for(int n=2;n<=LastNumber(cols,rows);n++) assert(Number(State(n,cols,rows),cols,rows)==n);
|
|
assert(LastNumber(cols,rows)<1000);
|
|
for(int region=0;region<RegionCount(cols,rows);region++) {
|
|
int l,t,r,b; RegionCells(REGION+region,cols,rows,l,t,r,b);
|
|
assert(l>=0&&t>=0&&r<=cols&&b<=rows&&r>l&&b>t&&r-l<=3&&b-t<=3);
|
|
vector low,high; RegionBounds(REGION+region,cols,rows,size,zoom,low,high);
|
|
assert(low[0]>=0&&low[2]>=0&&high[0]<=1&&high[2]<=1&&high[0]>low[0]&&high[2]>low[2]);
|
|
for(int y=t;y<b;y++) for(int x=l;x<r;x++) assert(ParentRegion(x+y*4096,cols,rows)==REGION+region);
|
|
if(region%RegionColumns(cols)>0) {
|
|
vector prevLow,prevHigh;RegionBounds(REGION+region-1,cols,rows,size,zoom,prevLow,prevHigh);
|
|
assert(std::abs(prevHigh[0]-low[0])<.00001f);
|
|
}
|
|
}
|
|
float w=744/zoom,h=1024/zoom;
|
|
for(int row=0;row<rows;row++) for(int col=0;col<cols;col++) {
|
|
auto p=Centre(offset,size,zoom,cols,rows,col,row);
|
|
assert(p[0]-w/2>=offset[0]-.01f&&p[0]+w/2<=offset[0]+size[0]+.01f);
|
|
assert(p[2]-h/2>=offset[2]-.01f&&p[2]+h/2<=offset[2]+size[2]+.01f);
|
|
if(col) {
|
|
auto prev=Centre(offset,size,zoom,cols,rows,col-1,row);
|
|
assert(p[0]>prev[0]&&p[0]-prev[0]<=w*.91f);
|
|
}
|
|
if(row) {
|
|
auto prev=Centre(offset,size,zoom,cols,rows,col,row-1);
|
|
assert(p[2]<prev[2]&&prev[2]-p[2]<=h*.91f);
|
|
}
|
|
}
|
|
auto nw=Centre(offset,size,zoom,cols,rows,0,0);
|
|
auto se=Centre(offset,size,zoom,cols,rows,cols-1,rows-1);
|
|
// Every border is covered up to the explicit two-pixel rounding margin.
|
|
assert(nw[0]-w/2-offset[0]<=4.01f/zoom);
|
|
assert(offset[2]+size[2]-nw[2]-h/2<=4.01f/zoom);
|
|
assert(offset[0]+size[0]-se[0]-w/2<=4.01f/zoom);
|
|
assert(se[2]-h/2-offset[2]<=4.01f/zoom);
|
|
}
|
|
int main(){
|
|
for(auto size:{vector{15360,0,15360},vector{12800,0,12800},vector{1024,0,512},vector{32768,0,8192},vector{8192,0,32768},vector{300,0,300},vector{100000,0,100000},vector{100000,0,500}})
|
|
for(auto offset:{vector{0,0,0},vector{-1234,0,4321}}) check(size,offset);
|
|
float zoom;int cols,rows;
|
|
assert(Layout({15360,0,15360},.5f,zoom,cols,rows)&&cols==12&&rows==9&&zoom==.5f);
|
|
assert(Layout({12800,0,12800},.5f,zoom,cols,rows)&&cols==10&&rows==7);
|
|
assert(!Layout({1000000,0,100},.5f,zoom,cols,rows));
|
|
assert(!Layout({0,0,10},.5f,zoom,cols,rows));
|
|
assert(!Layout({100,0,100},0,zoom,cols,rows));
|
|
}
|
|
''')
|
|
print('PASS: shipped sheet geometry covers square, rectangular and small terrains with overlap and shifted origins; regional grids cover all detail pages with round-trip numbering; Chernarus has 12 x 9 fixed detail sheets')
|
|
|
|
component=ROOT/'addons/core/Scripts/Game/ERR/30_Map/ERRM_SharedMapComponent.c'
|
|
wire='\n'.join(body(component,sig) for sig in ('override bool RplSave(', 'override bool RplLoad('))
|
|
wire=wire.replace('override ', '').replace('ScriptBitWriter writer', 'ScriptBitWriter& writer').replace('ScriptBitReader reader','ScriptBitReader& reader').replace('super.','Native::')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <vector>
|
|
struct ScriptBitWriter{std::vector<int32_t> data;void WriteInt(int value){data.push_back(value);}};
|
|
struct ScriptBitReader{std::vector<int32_t> data;bool ReadInt(int& value){if(data.empty())return false;value=data[0];data.erase(data.begin());return true;}};
|
|
struct Native{int saves=0,loads=0;bool RplSave(ScriptBitWriter&){saves++;return true;}bool RplLoad(ScriptBitReader&){loads++;return true;}};
|
|
struct Map:Native{int m_ESMPage=-1,m_ESMLastSelectedPage=-1;
|
|
'''+wire+r'''
|
|
};
|
|
int main(){
|
|
for(int page:{0,4097,16777214,16777215,16777216,16777227,16777615}){
|
|
Map source,target;source.m_ESMPage=page;ScriptBitWriter writer;assert(source.RplSave(writer)&&source.saves==1);
|
|
ScriptBitReader reader{writer.data};assert(target.RplLoad(reader)&&target.loads==1&&target.m_ESMPage==page&&target.m_ESMLastSelectedPage==page);
|
|
}
|
|
Map missing;ScriptBitReader empty;assert(!missing.RplLoad(empty)&&missing.loads==0&&missing.m_ESMLastSelectedPage==-1);
|
|
}
|
|
''')
|
|
print('PASS: actual map replication round-trips cover, overview, detail and regional pages, including the failing server value 16777227; truncated reads fail')
|