"""Generate small numeric filter palettes from verified local original resources."""
import json
from pathlib import Path
root=Path(__file__).resolve().parents[1]
data=json.loads((root/'artifacts/galaxy-query-research/palette-resources/original-appearance.json').read_text())
code=json.loads((root/'artifacts/galaxy-query-research/palette-resources/code-tables.json').read_text())
services=json.loads((root/'artifacts/galaxy-query-research/service-options/service-options.json').read_text())
economy=json.loads((root/'artifacts/galaxy-query-research/palette-resources/original-economy-colours.json').read_text())
assert data['gameImageSha256']=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
assert data['sourceSha256']=='29a90189d0bb238c88d09dcc0f15ff751ea29aa208b1a90894ef3b47f8942e5f'
assert services['gameImageSha256']==data['gameImageSha256']
assert [row['index'] for row in services['rows']]==list(range(10))
assert economy['imageSha256']==data['gameImageSha256'] and economy['resourceSha256']==data['sourceSha256']
assert economy['binding']['name']=='RootGalaxyMap' and economy['binding']['count']==11
def number(v):
s=format(v,'.9g')
return s+('f' if '.' in s or 'e' in s.lower() else '.0f')
def colour(v):return 'new('+','.join(number(x) for x in v)+')'
def normalize(v):return ''.join(c.lower() for c in v if c.isalnum())
rows=[]
for field,category in {'0x98':'Allegiance','0xa8':'Exploration','0xb8':'TradeData','0xc8':'State','0xd8':'Security','0xe8':'Visited','0x1f0':'Civilization'}.items():
for row in data['tables'][field]:
key=normalize(row['key'])
if category=='Exploration':key={'nodata':'nodataavailable','data':'dataavailable'}[key]
if category=='TradeData':key={'nodata':'nodataavailable','dataavailable':'dataavailable','data':'havedata'}[key]
if category=='Security':key={'highsecurity':'high','mediumsecurity':'medium','lowsecurity':'low','anarchy':'anarchy'}[key]
rows.append(f' [(GalaxyFilterCategory.{category},"{key}")]={colour(row["rgb"])},')
for row in code['enumerations']['government']:
if row['value']>=len(data['commonPalette']):continue
rows.append(f' [(GalaxyFilterCategory.Government,"{normalize(row["name"])}")]={colour(data["commonPalette"][row["value"]])},')
for row in services['rows']:
rows.append(f' [(GalaxyFilterCategory.Services,"{normalize(row["name"])}")]={colour(row["rgba"])},')
for row in economy['rows']:
rows.append(f' [(GalaxyFilterCategory.Economy,"{row["key"]}")]={colour(row["rgb"])},')
stellar_names={row['value']:normalize(row['name']) for row in code['enumerations']['stellarType']}
stellar_colours={row['type']:row['rgba'] for row in code['spectralTypePalette']}
for group in code['starClassGroups']:
rgba=[v/255 for v in stellar_colours[group['paletteType']]]
for type_id in group['types']:
rows.append(f' [(GalaxyFilterCategory.StarClass,"{stellar_names[type_id]}")]={colour(rgba)},')
population=data['population'];commodity={row['key']:row['rgba'] for row in data['commodity']}
source='''// Generated by research/Build-GalaxyFilterColours.py from verified numeric tables.
using System.Collections.Frozen;
namespace XFEEDToolBox.Core.Galaxy;
public readonly record struct GalaxyRawColour(float R,float G,float B,float A=1)
{
// Labels use an SDR conversion; source RGB remains float through rendering.
public StarColour DisplayColour()=>new(Channel(R),Channel(G),Channel(B));
private static byte Channel(float value)=>(byte)Math.Clamp(Math.Round(value*255),0,255);
public GalaxyRawColour Interpolate(GalaxyRawColour other,float amount)=>new(R+(other.R-R)*amount,G+(other.G-G)*amount,B+(other.B-B)*amount,A+(other.A-A)*amount);
}
public static class GalaxyOriginalAppearance
{
public const string ResourceSha256="'''+data['sourceSha256']+'''";
public const string ImageSha256="'''+data['gameImageSha256']+'''";
public const double PopulationMaximum='''+format(population['allowedMaximum'],'.17g')+''';
public const float DefaultSize='''+number(data['defaultSize'])+''';
public const float PopulationSizeMinimum='''+number(population['sizeMinimum'])+''';
public const float PopulationSizeMaximum='''+number(population['sizeMaximum'])+''';
public static readonly GalaxyRawColour PopulationLow='''+colour(population['colourMinimum'])+''';
public static readonly GalaxyRawColour PopulationHigh='''+colour(population['colourMaximum'])+''';
public static readonly GalaxyRawColour CommodityImport='''+colour(commodity['Import'])+''';
public static readonly GalaxyRawColour CommodityExport='''+colour(commodity['Export'])+''';
public static readonly IReadOnlyList<GalaxyRawColour> Colonisation=['''+','.join(colour(v['rgb']) for v in data['colonisation'])+'''];
private static readonly FrozenDictionary<(GalaxyFilterCategory,string),GalaxyRawColour> colours=new Dictionary<(GalaxyFilterCategory,string),GalaxyRawColour>
{
'''+ '\n'.join(rows)+'''
}.ToFrozenDictionary();
public static bool TryColour(GalaxyFilterCategory category,string key,out GalaxyRawColour colour)=>colours.TryGetValue((category,GalaxyMapFilter.Normalize(key)),out colour);
public static bool TryStarColour(string type,out GalaxyRawColour colour)
{
var key=GalaxyMapFilter.StarKey(type)??GalaxyMapFilter.Normalize(type);
var giant=key.IndexOf('_');if(giant>=0)key=key[..giant];
return TryColour(GalaxyFilterCategory.StarClass,key,out colour);
}
}
'''
(root/'XFEEDToolBox.Core/Galaxy/GalaxyOriginalAppearance.cs').write_text(source,encoding='utf-8')
service_source='''// Generated by research/Build-GalaxyFilterColours.py from pinned original constructor 3AD17F0.
namespace XFEEDToolBox.Core.Galaxy;
/// <summary>ServicesOption is a ten-row original table index, not a station service ID.</summary>
public static class GalaxyOriginalServiceOptions
{
public static IReadOnlyList<string> Keys { get; }=Array.AsReadOnly(new string[]{'''+','.join('"'+normalize(row['name'])+'"' for row in services['rows'])+'''});
public static string? KeyForIndex(int index)=>index>=0&&index<Keys.Count?Keys[index]:null;
public static int? IndexForKey(string key)
{
var normalized=GalaxyMapFilter.Normalize(key);if(normalized=="facilitator")return 6;
for(var index=0;index<Keys.Count;index++)if(Keys[index]==normalized)return index;
return null;
}
}
'''
(root/'XFEEDToolBox.Core/Galaxy/GalaxyOriginalServiceOptions.cs').write_text(service_source,encoding='utf-8')
print('Generated',len(rows),'proven key colours; population, commodity and colony numeric endpoints.')
"""Generate small numeric filter palettes from verified local original resources."""
import json
from pathlib import Path
root=Path(__file__).resolve().parents[1]
data=json.loads((root/'artifacts/galaxy-query-research/palette-resources/original-appearance.json').read_text())
code=json.loads((root/'artifacts/galaxy-query-research/palette-resources/code-tables.json').read_text())
services=json.loads((root/'artifacts/galaxy-query-research/service-options/service-options.json').read_text())
economy=json.loads((root/'artifacts/galaxy-query-research/palette-resources/original-economy-colours.json').read_text())
assert data['gameImageSha256']=='6891f70a021fa9f3a0e00458c284f48d1226e68ae7fc02ad48081aed47857e93'
assert data['sourceSha256']=='29a90189d0bb238c88d09dcc0f15ff751ea29aa208b1a90894ef3b47f8942e5f'
assert services['gameImageSha256']==data['gameImageSha256']
assert [row['index'] for row in services['rows']]==list(range(10))
assert economy['imageSha256']==data['gameImageSha256'] and economy['resourceSha256']==data['sourceSha256']
assert economy['binding']['name']=='RootGalaxyMap' and economy['binding']['count']==11
def number(v):
s=format(v,'.9g')
return s+('f' if '.' in s or 'e' in s.lower() else '.0f')
def colour(v):return 'new('+','.join(number(x) for x in v)+')'
def normalize(v):return ''.join(c.lower() for c in v if c.isalnum())
rows=[]
for field,category in {'0x98':'Allegiance','0xa8':'Exploration','0xb8':'TradeData','0xc8':'State','0xd8':'Security','0xe8':'Visited','0x1f0':'Civilization'}.items():
for row in data['tables'][field]:
key=normalize(row['key'])
if category=='Exploration':key={'nodata':'nodataavailable','data':'dataavailable'}[key]
if category=='TradeData':key={'nodata':'nodataavailable','dataavailable':'dataavailable','data':'havedata'}[key]
if category=='Security':key={'highsecurity':'high','mediumsecurity':'medium','lowsecurity':'low','anarchy':'anarchy'}[key]
rows.append(f' [(GalaxyFilterCategory.{category},"{key}")]={colour(row["rgb"])},')
for row in code['enumerations']['government']:
if row['value']>=len(data['commonPalette']):continue
rows.append(f' [(GalaxyFilterCategory.Government,"{normalize(row["name"])}")]={colour(data["commonPalette"][row["value"]])},')
for row in services['rows']:
rows.append(f' [(GalaxyFilterCategory.Services,"{normalize(row["name"])}")]={colour(row["rgba"])},')
for row in economy['rows']:
rows.append(f' [(GalaxyFilterCategory.Economy,"{row["key"]}")]={colour(row["rgb"])},')
stellar_names={row['value']:normalize(row['name']) for row in code['enumerations']['stellarType']}
stellar_colours={row['type']:row['rgba'] for row in code['spectralTypePalette']}
for group in code['starClassGroups']:
rgba=[v/255 for v in stellar_colours[group['paletteType']]]
for type_id in group['types']:
rows.append(f' [(GalaxyFilterCategory.StarClass,"{stellar_names[type_id]}")]={colour(rgba)},')
population=data['population'];commodity={row['key']:row['rgba'] for row in data['commodity']}
source='''// Generated by research/Build-GalaxyFilterColours.py from verified numeric tables.
using System.Collections.Frozen;
namespace XFEEDToolBox.Core.Galaxy;
public readonly record struct GalaxyRawColour(float R,float G,float B,float A=1)
{
// Labels use an SDR conversion; source RGB remains float through rendering.
public StarColour DisplayColour()=>new(Channel(R),Channel(G),Channel(B));
private static byte Channel(float value)=>(byte)Math.Clamp(Math.Round(value*255),0,255);
public GalaxyRawColour Interpolate(GalaxyRawColour other,float amount)=>new(R+(other.R-R)*amount,G+(other.G-G)*amount,B+(other.B-B)*amount,A+(other.A-A)*amount);
}
public static class GalaxyOriginalAppearance
{
public const string ResourceSha256="'''+data['sourceSha256']+'''";
public const string ImageSha256="'''+data['gameImageSha256']+'''";
public const double PopulationMaximum='''+format(population['allowedMaximum'],'.17g')+''';
public const float DefaultSize='''+number(data['defaultSize'])+''';
public const float PopulationSizeMinimum='''+number(population['sizeMinimum'])+''';
public const float PopulationSizeMaximum='''+number(population['sizeMaximum'])+''';
public static readonly GalaxyRawColour PopulationLow='''+colour(population['colourMinimum'])+''';
public static readonly GalaxyRawColour PopulationHigh='''+colour(population['colourMaximum'])+''';
public static readonly GalaxyRawColour CommodityImport='''+colour(commodity['Import'])+''';
public static readonly GalaxyRawColour CommodityExport='''+colour(commodity['Export'])+''';
public static readonly IReadOnlyList<GalaxyRawColour> Colonisation=['''+','.join(colour(v['rgb']) for v in data['colonisation'])+'''];
private static readonly FrozenDictionary<(GalaxyFilterCategory,string),GalaxyRawColour> colours=new Dictionary<(GalaxyFilterCategory,string),GalaxyRawColour>
{
'''+ '\n'.join(rows)+'''
}.ToFrozenDictionary();
public static bool TryColour(GalaxyFilterCategory category,string key,out GalaxyRawColour colour)=>colours.TryGetValue((category,GalaxyMapFilter.Normalize(key)),out colour);
public static bool TryStarColour(string type,out GalaxyRawColour colour)
{
var key=GalaxyMapFilter.StarKey(type)??GalaxyMapFilter.Normalize(type);
var giant=key.IndexOf('_');if(giant>=0)key=key[..giant];
return TryColour(GalaxyFilterCategory.StarClass,key,out colour);
}
}
'''
(root/'XFEEDToolBox.Core/Galaxy/GalaxyOriginalAppearance.cs').write_text(source,encoding='utf-8')
service_source='''// Generated by research/Build-GalaxyFilterColours.py from pinned original constructor 3AD17F0.
namespace XFEEDToolBox.Core.Galaxy;
/// <summary>ServicesOption is a ten-row original table index, not a station service ID.</summary>
public static class GalaxyOriginalServiceOptions
{
public static IReadOnlyList<string> Keys { get; }=Array.AsReadOnly(new string[]{'''+','.join('"'+normalize(row['name'])+'"' for row in services['rows'])+'''});
public static string? KeyForIndex(int index)=>index>=0&&index<Keys.Count?Keys[index]:null;
public static int? IndexForKey(string key)
{
var normalized=GalaxyMapFilter.Normalize(key);if(normalized=="facilitator")return 6;
for(var index=0;index<Keys.Count;index++)if(Keys[index]==normalized)return index;
return null;
}
}
'''
(root/'XFEEDToolBox.Core/Galaxy/GalaxyOriginalServiceOptions.cs').write_text(service_source,encoding='utf-8')
print('Generated',len(rows),'proven key colours; population, commodity and colony numeric endpoints.')