continuous-integration/drone/push Build is passing
Discover installed mod vehicles and save independent garage, traffic, patrol and convoy assignments. Retire the superseded RHS 1.9 overrides. Include native menu, crew/driving and publication evidence.
98 lines
8.0 KiB
Python
98 lines
8.0 KiB
Python
"""Production rule/preset operations; native fixture separately covers disk IO."""
|
|
from policy_harness import ROOT, body, run
|
|
import re
|
|
p=ROOT/'addons/core/Scripts/Game/ERR/00_Core/ERR_ItemPreferences.c'
|
|
methods='\n'.join(body(p,n) for n in ('static bool Name(', 'static bool Guid(', 'static bool RoleKey(', 'static bool WeightKey(', 'static bool WeightValue(', 'static bool Valid(', 'protected void Rebuild(', 'bool Enabled(', 'bool ModEnabled(', 'bool VehicleEnabled(', 'bool SetSwitch(', 'bool SetVehicleRole(', 'int VehicleRole(', 'bool AllowsVehicleRole(', 'bool AllowsVehicle(', 'bool Allows(', 'bool Set(', 'int WeightSetting(', 'int Weight(', 'bool SetWeight(', 'bool Preset('))
|
|
methods=methods.replace('role.ToString()', 'string(std::to_string(role))').replace('weight.ToString()', 'string(std::to_string(weight))').replace('Math.Max', 'std::max').replace('ERR_CommandArguments.Integer', 'Integer')
|
|
methods=methods.replace('protected ', '').replace('array<string>', 'Array<string>').replace('set<string> keys = new set<string>();','Array<string> keys;')
|
|
methods=methods.replace('foreach (', 'for (').replace('ResourceName','string').replace('ERR_TerrainCatalog.Key(prefab)', 'prefab').replace('SCR_AddonTool.GetResourceAddons(prefab)', 'sources')
|
|
methods=methods.replace('Array<string> sources = sources;', 'Array<string> resourceSources = sources;').replace('project : sources','project : resourceSources')
|
|
methods=methods.replace('"01234".IndexOf', 'string("01234").IndexOf')
|
|
methods=methods.replace('"0123456789abcdef".IndexOf','string("0123456789abcdef").IndexOf').replace('!records || ', '')
|
|
run(r'''
|
|
#include <cassert>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <algorithm>
|
|
#include <map>
|
|
struct string;
|
|
template<class T>struct Array:std::vector<T>{using std::vector<T>::vector;using std::vector<T>::operator=;int Count(){return this->size();}void Insert(T x){this->push_back(x);}bool Contains(T x){return std::find(this->begin(),this->end(),x)!=this->end();}void Clear(){this->clear();}};
|
|
struct string:std::string{using std::string::string;string(std::string x):std::string(x){}bool StartsWith(string s){return find(s)==0;}bool IsEmpty(){return empty();}int Length(){return size();}int IndexOf(string s){auto i=find(s);return i==npos?-1:int(i);}string Substring(int a,int n){return substr(a,n);}int ToInt(){return std::stoi(*this);}void Split(string delim,Array<string>& out,bool){size_t a=0;while(true){auto b=find(delim,a);out.Insert(substr(a,b==npos?b:b-a));if(b==npos)break;a=b+delim.size();}}};
|
|
template<class T>struct Map{std::map<string,T> data;bool Contains(string k){return data.count(k);}T Get(string k){return data[k];}void Set(string k,T v){data[k]=v;}void Clear(){data.clear();}};
|
|
bool Integer(string s,int& n){try{size_t end;n=std::stoi(s,&end);return end==s.size();}catch(...){return false;}}
|
|
struct Prefs{Array<string> m_Records={"active"},sources={"base-project","mod-project"};Map<int> m_Rules;Map<string> m_Loaded;int m_Revision=0;bool fail=false;
|
|
bool Save(Array<string> rows){if(fail||!Valid(rows))return false;m_Records=rows;Rebuild();return true;}
|
|
'''+methods+r'''
|
|
};
|
|
int main(){
|
|
string a="1111111111111111",b="2222222222222222",i="aaaaaaaaaaaaaaaa",j="bbbbbbbbbbbbbbbb";
|
|
Prefs p;p.m_Loaded.Set("base-project",a);p.m_Loaded.Set("mod-project",b);
|
|
assert(p.Allows(i));assert(p.Set(a,"*",false)&&!p.Allows(i));
|
|
assert(p.Set(a,i,true)&&p.Allows(i)&&!p.Allows(j));
|
|
assert(p.Set(b,i,false)&&!p.Allows(i)); // Shared source disable wins.
|
|
assert(p.Preset("save","custom"));
|
|
assert(p.Set(a,"*",true)&&p.Set(b,"*",true)&&p.Allows(i)&&p.Allows(j));
|
|
assert(p.Preset("load","custom")&&!p.Allows(i)&&!p.Allows(j));
|
|
p.m_Loaded.Clear();assert(p.Allows(i)&&p.Allows(j)); // Missing sources are dormant.
|
|
p.m_Loaded.Set("mod-project",b);assert(!p.Allows(i)); // Returns when source is loaded again.
|
|
// Weight records coexist with booleans and travel with named presets.
|
|
p.m_Loaded.Set("base-project",a);
|
|
assert(p.Weight(i)==1);assert(p.SetWeight(b,"*",100)&&p.Weight(i)==100);
|
|
assert(p.SetWeight(b,i,10)&&p.Weight(i)==1000&&p.Weight(j)==100);
|
|
assert(p.Set(a,"*",true)&&p.Set(b,"*",true)&&p.Weight(i)==1000);
|
|
assert(p.Preset("save","weighted"));
|
|
assert(p.SetWeight(b,"*",1)&&p.Weight(i)==10);
|
|
assert(p.SetWeight(b,i,0)&&p.Weight(i)==0&&p.Weight(j)==1);
|
|
assert(p.Preset("load","weighted")&&p.Weight(i)==1000);
|
|
assert(p.SetWeight(a,"*",0)&&p.Weight(i)==0); // Shared source exclusion wins.
|
|
assert(p.SetWeight(a,"*",1)&&p.Weight(i)==1000);
|
|
assert(!p.SetWeight(a,i,-1)&&!p.SetWeight(a,i,101));
|
|
for(string bad:{"100junk","-1","101","1.5",""})assert(!p.WeightValue(bad));
|
|
assert(p.WeightValue("0")&&p.WeightValue("100"));
|
|
assert(!p.Valid({"active","active|1111111111111111|w*|101"}));
|
|
p.m_Loaded.Clear();assert(p.Weight(i)==1); // Absent mod has no effect.
|
|
p.m_Loaded.Set("mod-project",b);assert(p.Weight(i)==1000);
|
|
assert(p.Preset("delete","weighted"));
|
|
auto old=p.m_Records;int revision=p.m_Revision;p.fail=true;
|
|
assert(!p.Set(b,"*",true)&&p.m_Records==old&&p.m_Revision==revision);
|
|
assert(!p.Preset("save","failed")&&p.m_Records==old);
|
|
assert(!p.SetSwitch(a,"mod",false)&&p.m_Records==old&&p.m_Revision==revision);
|
|
assert(!p.SetSwitch(a,"v"+i,false)&&p.m_Records==old&&p.m_Revision==revision);
|
|
assert(!p.Preset("delete","custom")&&p.m_Records==old);
|
|
p.fail=false;
|
|
assert(p.Preset("save","custom")&&p.Preset("delete","custom")&&!p.Preset("load","custom"));
|
|
for(string name:{"", "active", "../bad", "two words", "abcdefghijklmnopqrstuvwxy"})assert(!p.Preset("save",name));
|
|
assert(!p.Preset("delete","missing")&&!p.Preset("load","missing")&&!p.Preset("evil","x"));
|
|
for(int n=0;n<16;n++)assert(p.Preset("save",string("preset_")+std::to_string(n)));
|
|
assert(!p.Preset("save","overflow"));assert(p.Preset("save","preset_0"));
|
|
assert(p.Preset("delete","preset_0")&&p.Preset("save","replacement"));
|
|
assert(!p.Valid({"active","active|1111111111111111|*|2"}));
|
|
assert(!p.Valid({"active","active|1111111111111111|*|0","active|1111111111111111|*|1"}));
|
|
assert(!p.Valid({"active","missing|1111111111111111|*|0"}));
|
|
// Master disable preserves per-item and per-vehicle decisions; all-items does not erase either gate or vehicle rules.
|
|
p.fail=false; p.m_Loaded.Set("base-project",a);p.m_Loaded.Set("mod-project",b);
|
|
assert(p.Set(a,"*",true)&&p.Set(b,"*",true));
|
|
assert(p.Set(a,i,false));assert(p.SetSwitch(a,"v"+j,false));
|
|
assert(p.SetSwitch(a,"mod",false)&&!p.Allows(j)&&!p.AllowsVehicle(i));
|
|
assert(p.Set(a,"*",true)&&!p.ModEnabled(a)&&!p.VehicleEnabled(a,j));
|
|
assert(p.SetSwitch(a,"mod",true)&&p.Allows(j)&&p.AllowsVehicle(i)&&!p.AllowsVehicle(j));
|
|
assert(p.Set(a,i,false)&&p.SetSwitch(a,"v*",true)&&!p.Allows(i)&&p.AllowsVehicle(j));
|
|
assert(p.Preset("save","replacement")&&p.SetSwitch(a,"mod",false)&&p.Preset("load","replacement")&&p.ModEnabled(a));
|
|
assert(!p.SetSwitch(a,"vbad",false)&&!p.SetSwitch("../", "mod",false));
|
|
// New vehicles are opt-in, role choices independent, explicit source denials win.
|
|
assert(p.SetVehicleRole(a,j,2,true)&&p.AllowsVehicleRole(j,2,false));
|
|
assert(!p.AllowsVehicleRole(j,3,false));
|
|
assert(p.SetVehicleRole(b,j,2,false)&&!p.AllowsVehicleRole(j,2,false));
|
|
assert(p.SetVehicleRole(b,j,2,true)&&p.AllowsVehicleRole(j,2,false));
|
|
assert(p.SetVehicleRole(a,"*",3,true)&&p.AllowsVehicleRole(j,3,false));
|
|
assert(p.SetVehicleRole(a,j,3,false)&&!p.AllowsVehicleRole(j,3,false)&&p.AllowsVehicleRole(j,2,false));
|
|
assert(p.Preset("save","replacement")&&p.SetVehicleRole(a,j,2,false)&&p.Preset("load","replacement")&&p.AllowsVehicleRole(j,2,false));
|
|
assert(p.SetSwitch(a,"mod",false)&&!p.AllowsVehicleRole(j,2,true)&&p.SetSwitch(a,"mod",true)&&p.AllowsVehicleRole(j,2,false));
|
|
int before=p.m_Revision;p.fail=true;assert(!p.SetVehicleRole(a,j,2,false)&&p.m_Revision==before&&p.AllowsVehicleRole(j,2,false));p.fail=false;
|
|
assert(!p.SetVehicleRole(a,j,5,true)&&!p.SetVehicleRole(a,j,-1,true)&&!p.SetVehicleRole(a,"bad",0,true));
|
|
assert(!p.Valid({"active","active|1111111111111111|r5*|1"}));
|
|
assert(!p.Set("../x",i,true)&&!p.Set(a,"unknown",true));
|
|
}
|
|
''')
|
|
print('PASS: actual item rules, shared-source conflicts, missing/returning mods, bulk reset, independent named presets, bounds, malformed data and failed-save state preservation')
|