Simplify content controls and add vehicle roles; record Workshop 0.0.144
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.
This commit is contained in:
2026-11-06 22:06:38 +01:00
parent 518a1a5744
commit 460d9808e5
116 changed files with 14244 additions and 404 deletions
+28 -3
View File
@@ -2,11 +2,12 @@
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 WeightKey(', 'static bool WeightValue(', 'static bool Valid(', 'protected void Rebuild(', 'bool Enabled(', 'bool Allows(', 'bool Set(', 'int WeightSetting(', 'int Weight(', 'bool SetWeight(', 'bool Preset('))
methods=methods.replace('weight.ToString()', 'string(std::to_string(weight))').replace('Math.Max', 'std::max').replace('ERR_CommandArguments.Integer', 'Integer')
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>
@@ -16,7 +17,7 @@ run(r'''
#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 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();}}};
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;
@@ -55,6 +56,8 @@ int main(){
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"));
@@ -66,6 +69,28 @@ int main(){
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));
}
''')