2025-03-09 16:28:03 -04:00
#!/bin/env python3
import sys
import json
2025-03-15 17:21:18 -04:00
import argparse
import re
2025-03-09 16:28:03 -04:00
# weapon required data
WEAPONS = {
" Laser " : {
" T0 " : {
" damage_inflicted " : 42 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
" T1 " : {
" damage_inflicted " : 420 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
" T2 " : {
" damage_inflicted " : 4200 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
" T3 " : {
" damage_inflicted " : 42000 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
" T4 " : {
" damage_inflicted " : 420000 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
" T5 " : {
" damage_inflicted " : 4200000 ,
2025-03-15 11:03:35 -04:00
" group_fire_scales " : [ 1.0 ] ,
2025-03-09 16:28:03 -04:00
} ,
} ,
}
2025-03-15 11:03:35 -04:00
STATS_TRANSLATIONS = {
" CPU LOAD " : " strCPU " ,
" CPU " : " strCPU " ,
" MASS " : " strMass " ,
" ARMOR " : " strHealth " ,
" ROBOT RANKING " : " strRobotRanking " ,
" ROBOT RATING " : " strRobotRanking " ,
" MAX LIFT " : " strLiftDS " ,
" LIFT " : " strLiftDS " ,
" MAX SPEED " : " strMaxSpeedDS " ,
" CARRYING CAPACITY " : " strCapacity " ,
" LOAD CAPACITY PER WING " : " strCapacity " ,
" TOP SPEED " : " strMaxSpeedDS " ,
" DAMAGE AT 160M " : " strDamageNearDS " ,
" DAMAGE AT 320M " : " strDamageFarDS " ,
" DAMAGE " : " strDamageDS " ,
" BLAST " : " strBlastRadiusDS " ,
" DAMAGE RATE " : " strWeaponDamageRateDS " ,
" HEAL RATE " : " strHealRate " ,
}
STATS_VALUE_REPLACEMENTS = {
" pFLOP " : " [strPFlops] " ,
" Kg " : " [strKilograms] " ,
" kg " : " [strKilograms] " ,
}
IGNORED_STATS = [
" OVERCLOCK " ,
" OVERCLOCKER " ,
" THRUST " ,
" SHIELD " ,
" LIGHT OUTPUT " ,
]
2025-03-09 16:28:03 -04:00
# different from the enum
''' CATEGORIES = {
0 : " NotAFunctionalItem " ,
1 : " Wheel " ,
2 : " Hover " ,
3 : " Wing " ,
4 : " Rudder " ,
5 : " Thruster " ,
6 : " InsectLeg " ,
7 : " MechLeg " ,
8 : " Ski " ,
9 : " TankTrack " ,
10 : " Rotor " ,
11 : " SprinterLeg " ,
12 : " Propeller " ,
100 : " Laser " ,
200 : " Plasma " ,
250 : " Mortar " ,
300 : " Rail " ,
400 : " Nano " ,
500 : " Tesla " ,
600 : " Aeroflak " ,
650 : " Ion " ,
701 : " Seeker " ,
750 : " Chaingun " ,
800 : " ShieldModule " ,
801 : " GhostModule " ,
802 : " BlinkModule " ,
803 : " EmpModule " ,
804 : " WindowmakerModule " ,
900 : " EnergyModule " ,
} '''
CATEGORIES = [
" NotAFunctionalItem " ,
" Wheel " ,
" Hover " ,
" Wing " ,
" Rudder " ,
" Thruster " ,
" InsectLeg " ,
" MechLeg " ,
" Ski " ,
" TankTrack " ,
" Rotor " ,
" SprinterLeg " ,
" Propeller " ,
" Laser " , #13
" Plasma " ,
" Mortar " ,
" Rail " ,
" Nano " ,
" Tesla " ,
" Aeroflak " ,
" Ion " ,
" Seeker " ,
" Chaingun " ,
" ShieldModule " , #23
" GhostModule " ,
" BlinkModule " ,
" EmpModule " ,
" WindowmakerModule " ,
" EnergyModule " ,
]
2025-03-15 11:03:35 -04:00
CATEGORY_IGNORES = [
" VaporTrail " ,
" Vapor_Trail " ,
" FusionTower " ,
]
ALL_FACES = 63 ;
CATEGORIES_PLACEMENTS = {
" NotAFunctionalItem " : ALL_FACES ,
" Wheel " : 0b00001100 ,
" Hover " : 0b00111100 ,
2025-05-19 17:17:09 -04:00
" Wing " : ALL_FACES , #0b00111100,
" Rudder " : ALL_FACES , #0b00111100,
2025-03-15 11:03:35 -04:00
" Thruster " : ALL_FACES ,
" InsectLeg " : 0b00111100 ,
" MechLeg " : 0b00000011 ,
" Ski " : 0b00000011 ,
" TankTrack " : 0b00111100 ,
2025-05-19 17:17:09 -04:00
" Rotor " : ALL_FACES , #0b00111100,
2025-03-15 11:03:35 -04:00
" SprinterLeg " : 0b00000011 ,
" Propeller " : ALL_FACES ,
" Laser " : None ,
" Plasma " : ALL_FACES ,
" Mortar " : 0b00000011 ,
" Rail " : ALL_FACES ,
" Nano " : ALL_FACES ,
" Tesla " : ALL_FACES ,
" Aeroflak " : ALL_FACES ,
" Ion " : ALL_FACES ,
" Seeker " : ALL_FACES ,
" Chaingun " : ALL_FACES ,
" ShieldModule " : ALL_FACES ,
" GhostModule " : ALL_FACES ,
" BlinkModule " : ALL_FACES ,
" EmpModule " : ALL_FACES ,
" WindowmakerModule " : ALL_FACES ,
" EnergyModule " : ALL_FACES ,
}
2025-03-30 17:54:06 -04:00
LOGIN_MESSAGES = [
" No jam was harmed in the reverse-engineering of this game " ,
" Struggling to open jars since 2013 " ,
" If you can read this, you ' ve benefitted from an education department! " ,
" Support your local minorities " ,
" Слава Україні! Slava Ukraini! " ,
" Now with more poutine " ,
" Free Palestine! " ,
" Hacker free " ,
" Hey cutie " ,
" Tesla Coils are the only useful Teslas " ,
" Welcome to OpenJam ' s servers " ,
" Made in sovereign Canada " ,
" Finally, how to craft Robo " ,
" Warning, live without warning \n I say, warning, live without warning \n Without, all right " ,
]
2025-03-15 11:03:35 -04:00
def guess_category ( name : str , sprite : str ) - > str :
2025-03-09 16:28:03 -04:00
name = name . lower ( )
sprite = sprite . lower ( )
for variant in CATEGORIES :
variant_sanitized = variant . lower ( )
2025-03-15 11:03:35 -04:00
if ( variant_sanitized in name and not str_contains_any ( name , CATEGORY_IGNORES ) ) or ( variant_sanitized in sprite and not str_contains_any ( sprite , CATEGORY_IGNORES ) ) :
2025-03-09 16:28:03 -04:00
return variant
return CATEGORIES [ 0 ]
2025-03-15 11:03:35 -04:00
def str_contains_any ( s : str , l : list ) - > bool :
for variant in l :
variant_sanitized = variant . lower ( )
if variant_sanitized in s :
print ( s + " contains " + variant )
return True
return False
def guess_type ( category : str ) - > str :
2025-03-09 16:28:03 -04:00
cat_i = CATEGORIES . index ( category )
if cat_i == 0 :
return " NotAFunctionalItem "
elif cat_i > = 23 :
return " Module "
elif cat_i > = 13 :
return " Weapon "
elif cat_i > = 1 :
return " Movement "
else :
return " NotAFunctionalItem "
2025-03-15 17:21:18 -04:00
TIERS = [
" NoTier " ,
" T0 " ,
" T1 " ,
" T2 " ,
" T3 " ,
" T4 " ,
" T5 " ,
]
2025-03-09 16:28:03 -04:00
def guess_tier ( name : str , sprite : str ) - > str :
2025-03-15 11:03:35 -04:00
if guess_category ( name , sprite ) == " NotAFunctionalItem " and " medium " in name . lower ( ) : # Medium cube variants
return " NoTier "
return guess_tier_by_name_str_key ( name ) or guess_tier_by_size ( sprite ) or guess_tier_by_name_str_key ( sprite ) or " NoTier "
2025-03-09 16:28:03 -04:00
def guess_tier_by_size ( sprite : str ) - > str :
sprite = sprite . lower ( )
if " tiny " in sprite :
return " T0 "
elif " small " in sprite :
return " T1 "
elif " medium " in sprite :
return " T2 "
elif " large " in sprite :
return " T3 "
elif " huge " in sprite :
return " T4 "
elif " mega " in sprite :
return " T5 "
else :
return None
def guess_tier_by_name_str_key ( name : str ) - > str :
name = name . upper ( )
if " T0 " in name :
return " T0 "
elif " T1 " in name :
return " T1 "
elif " T2 " in name :
return " T2 "
elif " T3 " in name :
return " T3 "
elif " T4 " in name :
return " T4 "
elif " T5 " in name :
return " T5 "
else :
return None
def placements_to_int ( placements : dict ) - > int :
return int ( placements [ " 1 UInt8 up " ] ) | \
int ( placements [ " 1 UInt8 down " ] ) << 1 | \
int ( placements [ " 1 UInt8 left " ] ) << 2 | \
int ( placements [ " 1 UInt8 right " ] ) << 3 | \
int ( placements [ " 1 UInt8 back " ] ) << 4 | \
int ( placements [ " 1 UInt8 front " ] ) << 5
2025-03-15 11:03:35 -04:00
def guess_placement ( placements : dict , category : str , name : str ) - > int :
by_category = CATEGORIES_PLACEMENTS [ category ]
if by_category is not None :
return by_category
name = name . lower ( )
if " front " in name :
return 0b0011000000
elif category == " Laser " :
return ALL_FACES
return placements_to_int ( placements )
def translate_stat_key ( key : str ) - > str :
return STATS_TRANSLATIONS [ key . upper ( ) ]
def replace_stat_values ( value : str ) - > str :
for replace in STATS_VALUE_REPLACEMENTS . keys ( ) :
value = value . replace ( replace , STATS_VALUE_REPLACEMENTS [ replace ] )
return value
VARIANT_STRINGS = [
" frontlaser " ,
" golden " ,
" carbon6 " ,
" egglauncher " ,
" cardlife " ,
" seekerfirework " ,
" rudderbat " ,
" wingbat " ,
" legspider " ,
]
def is_variant_guess ( name : str , sprite : str ) - > bool :
name_lower = name . lower ( )
for s in VARIANT_STRINGS :
if s in name_lower :
return True
return False
2025-03-15 17:21:18 -04:00
FIELD_NAME_EXCEPTIONS = {
" verticalTopSpeed " : " max_vertical_velocity " ,
}
def rename_field ( original : str ) - > str :
if original in FIELD_NAME_EXCEPTIONS :
return FIELD_NAME_EXCEPTIONS [ original ]
else :
return camel_to_snake_case ( original )
SEEN_MOVEMENTS = { }
SEEN_WEAPONS = { }
EXCLUDED_FIELDS = [
" T0 " ,
" T1 " ,
" T2 " ,
" T3 " ,
" T4 " ,
" T5 " ,
]
def apply_entry_overrides ( entry : dict , cubes_data : dict , weapons_data : dict , movement_data : dict ) :
if cubes_data is not None :
if entry [ " hexId " ] in cubes_data :
cube_data = cubes_data [ entry [ " hexId " ] ]
entry [ " info " ] [ " description " ] = cube_data [ " Description " ]
entry [ " info " ] [ " health " ] = cube_data [ " health " ]
entry [ " info " ] [ " cpu " ] = cube_data [ " cpuRating " ]
entry [ " info " ] [ " visibility " ] = cube_data [ " buildVisibility " ]
entry [ " info " ] [ " ranking " ] = cube_data [ " robotRanking " ]
if " ItemSize " in cube_data :
entry [ " info " ] [ " size " ] = cube_data [ " ItemSize " ]
if " ItemType " in cube_data :
entry [ " info " ] [ " type " ] = cube_data [ " ItemType " ]
if " ItemCategory " in cube_data :
entry [ " info " ] [ " category " ] = cube_data [ " ItemCategory " ]
if " PlacementFaces " in cube_data :
entry [ " info " ] [ " placements " ] = cube_data [ " PlacementFaces " ]
2025-05-22 20:40:39 -04:00
if " variantOf " in cube_data :
entry [ " info " ] [ " variant_of " ] = int ( cube_data [ " variantOf " ] , 16 )
entry [ " isVariant " ] = True
2025-03-15 17:21:18 -04:00
if movement_data is not None and not entry [ " isVariant " ] :
if entry [ " info " ] [ " category " ] in movement_data [ " Movements " ] :
if entry [ " info " ] [ " size " ] in movement_data [ " Movements " ] [ entry [ " info " ] [ " category " ] ] :
if entry [ " info " ] [ " category " ] not in SEEN_MOVEMENTS :
SEEN_MOVEMENTS [ entry [ " info " ] [ " category " ] ] = dict ( )
SEEN_MOVEMENTS [ entry [ " info " ] [ " category " ] ] [ entry [ " info " ] [ " size " ] ] = True
specific_data = movement_data [ " Movements " ] [ entry [ " info " ] [ " category " ] ] [ entry [ " info " ] [ " size " ] ]
if " movement " not in entry :
entry [ " movement " ] = dict ( )
for ( key , val ) in specific_data . items ( ) :
entry [ " movement " ] [ rename_field ( key ) ] = specific_data [ key ]
entry [ " movement " ] [ " movement_enum_variant " ] = entry [ " info " ] [ " category " ]
if weapons_data is not None and not entry [ " isVariant " ] :
weapon_key = entry [ " info " ] [ " size " ] + " _ " + entry [ " info " ] [ " category " ]
if weapon_key in weapons_data :
if weapon_key in SEEN_WEAPONS :
print ( " WARN: Already seen weapon key " , weapon_key )
SEEN_WEAPONS [ weapon_key ] = True
if " weapon " not in entry :
entry [ " weapon " ] = dict ( )
for ( key , val ) in weapons_data [ weapon_key ] . items ( ) :
entry [ " weapon " ] [ rename_field ( key ) ] = val
def apply_global_overrides ( conf : dict , cubes_data : dict , weapons_data : dict , movement_data : dict ) :
if movement_data is not None :
if " movement " not in conf :
conf [ " movement " ] = dict ( )
for ( category , cat_setting ) in movement_data [ " Movements " ] . items ( ) :
if category not in conf [ " movement " ] :
conf [ " movement " ] [ category ] = dict ( )
for ( field , setting ) in cat_setting . items ( ) :
if field not in EXCLUDED_FIELDS :
conf [ " movement " ] [ category ] [ rename_field ( field ) ] = setting
conf [ " movement " ] [ category ] [ " movement_enum_variant " ] = category
def load_or_none ( file_json ) :
if file_json is None :
return None
else :
with open ( file_json ) as f :
return json . load ( f )
CAMEL_TO_SNAKE_PATTERN = re . compile ( r ' (?<!^)(?=[A-Z]) ' )
def camel_to_snake_case ( s : str ) - > str :
return CAMEL_TO_SNAKE_PATTERN . sub ( ' _ ' , s ) . lower ( )
def main ( asset_in , cubes = None , weapons = None , movement = None ) :
cubes_data = load_or_none ( cubes )
weapons_data = load_or_none ( weapons )
movement_data = load_or_none ( movement )
with open ( asset_in ) as f :
2025-03-09 16:28:03 -04:00
cubes_asset = json . load ( f )
2025-03-15 17:21:18 -04:00
2025-03-09 16:28:03 -04:00
name = cubes_asset [ " 0 MonoBehaviour Base " ] [ " 1 string m_Name " ]
print ( f " found name (expected to be empty): ` { name } ` " )
cubes = cubes_asset [ " 0 MonoBehaviour Base " ] [ " 0 CubeTypeData cubeTypes " ] [ " 0 Array Array " ]
print ( f " found { len ( cubes ) } cubes to process " )
2025-03-15 17:21:18 -04:00
conf_out = {
2025-03-09 16:28:03 -04:00
" cubes " : dict ( ) ,
" movement " : dict ( ) ,
2025-03-15 17:21:18 -04:00
" lerp_value " : 0.1 ,
" battle " : {
" regen " : {
" wait_for_heal_s " : 5.0 ,
" wait_full_heal_s " : 5.0 ,
" sound_start_s " : 2.5 ,
" auto_heal " : True ,
} ,
" votes " : {
" BestPlayed " : [
{
" name " : " Best Played " ,
" localised_name " : " strBestPlayed " ,
" color " : " 0000ff " ,
" votes_required " : 1 ,
}
] ,
" BestLooking " : [
{
" name " : " Best Looking " ,
" localised_name " : " strBestLooking " ,
" color " : " ff0000 " ,
" votes_required " : 2 ,
}
] ,
2025-03-29 22:08:08 -04:00
} ,
2025-03-30 17:54:06 -04:00
} ,
2025-04-14 21:17:41 -04:00
" chat " : {
" public_channels " : [
" main " ,
" sys " ,
" jam_club " ,
] ,
} ,
2025-05-19 17:17:09 -04:00
" factory " : {
" adapter " : {
" variant " : " Arc " ,
" uri " : " sqlite:../../arc/rc_archive.db?mode=ro "
}
} ,
2025-03-30 17:54:06 -04:00
" settings " : {
" banners " : [ {
" message " : msg ,
" duration " : 20 ,
} for msg in LOGIN_MESSAGES ] ,
} ,
2025-03-09 16:28:03 -04:00
}
2025-03-15 11:03:35 -04:00
last_tech_tree_id = 0
tech_tree_index = 0
tech_tree_specials_index = 0
2025-03-09 16:28:03 -04:00
for i in range ( len ( cubes ) ) :
#print(f"processing cube {i}")
cube = cubes [ i ] [ " 0 CubeTypeData data " ]
name = str ( cube [ " 1 string nameStrKey " ] )
if name . startswith ( " str " ) :
name = name [ 3 : ]
if name . endswith ( " Name " ) :
name = name [ : - 4 ]
new_key = name + " hexCode: " + str ( cube [ " 1 string itemCode " ] ) + " intCode: " + str ( cube [ " 0 unsigned int itemCodeValue " ] )
stats = dict ( )
for stat_i in range ( 1 , 7 ) : # 1 to 6 (inclusive)
stat_key = " 1 string stat " + str ( stat_i )
if stat_key in cube :
stat_val = cube [ stat_key ]
#print(f"stat {stat_key} -> {stat_val}")
if len ( stat_val ) == 0 :
continue
if " = " in stat_val :
new_stat_key = str ( cube [ stat_key ] ) . split ( " = " ) [ 0 ]
new_stat_val = str ( cube [ stat_key ] ) . split ( " = " ) [ 1 ]
else :
new_stat_key = str ( cube [ stat_key ] ) . split ( " : " ) [ 0 ]
new_stat_val = str ( cube [ stat_key ] ) . split ( " : " ) [ 1 ]
stats [ new_stat_key ] = new_stat_val
2025-03-15 11:03:35 -04:00
category = guess_category ( cube [ " 1 string nameStrKey " ] , cube [ " 1 string spriteName " ] ) ;
2025-03-09 16:28:03 -04:00
new_entry = {
" id " : int ( cube [ " 0 unsigned int itemCodeValue " ] ) ,
" info " : {
2025-03-15 11:03:35 -04:00
" category " : category ,
" placements " : guess_placement ( cube [ " 0 PersistentCubeData cubeData " ] [ " 0 CubeFaces selectableFaces " ] , category , cube [ " 1 string nameStrKey " ] ) ,
2025-03-09 16:28:03 -04:00
" stats " : stats , # required
" description " : str ( cube [ " 1 string description " ] ) , # required
" size " : guess_tier ( cube [ " 1 string nameStrKey " ] , cube [ " 1 string spriteName " ] ) , # required
2025-03-15 11:03:35 -04:00
" type " : guess_type ( category ) ,
2025-03-09 16:28:03 -04:00
" active " : int ( cube [ " 1 UInt8 active " ] ) != 0 , # ignored
} ,
# ignored
" spriteName " : cube [ " 1 string spriteName " ] ,
" nameStrKey " : cube [ " 1 string nameStrKey " ] ,
" mirrorCubeId " : cube [ " 0 PersistentCubeData cubeData " ] [ " 1 string mirrorCubeId " ] ,
" hexId " : str ( cube [ " 1 string itemCode " ] ) ,
2025-03-15 17:21:18 -04:00
" isVariant " : is_variant_guess ( cube [ " 1 string nameStrKey " ] , cube [ " 1 string spriteName " ] ) ,
2025-03-09 16:28:03 -04:00
}
2025-05-19 17:17:09 -04:00
if " protoniumcrystal " in name . lower ( ) :
2025-03-15 11:03:35 -04:00
new_entry [ " info " ] [ " protonium " ] = True
2025-05-19 17:17:09 -04:00
if " fusion " in name . lower ( ) or " equalizer " in name . lower ( ) or " protonium " in name . lower ( ) :
new_entry [ " info " ] [ " visibility " ] = " None "
2025-03-09 16:28:03 -04:00
if " CPU LOAD " in stats :
new_entry [ " info " ] [ " cpu " ] = int ( stats [ " CPU LOAD " ] . strip ( ) . split ( " " ) [ 0 ] . strip ( ) )
if " ARMOR " in stats :
new_entry [ " info " ] [ " health " ] = int ( stats [ " ARMOR " ] . replace ( " , " , " " ) . strip ( ) )
2025-03-15 11:03:35 -04:00
translated_stats = dict ( )
for ( key , val ) in new_entry [ " info " ] [ " stats " ] . items ( ) :
if key not in IGNORED_STATS :
trans_key = translate_stat_key ( key )
translated_stats [ trans_key ] = replace_stat_values ( val )
new_entry [ " info " ] [ " stats " ] = translated_stats
2025-03-09 16:28:03 -04:00
if len ( new_entry [ " info " ] [ " description " ] . strip ( ) ) == 0 :
new_entry [ " info " ] [ " description " ] = name + " ( " + str ( cube [ " 0 unsigned int itemCodeValue " ] ) + " _10| " + str ( cube [ " 1 string itemCode " ] ) + " _16) without a description "
2025-03-15 11:03:35 -04:00
else :
new_entry [ " info " ] [ " description " ] + = " ( " + str ( cube [ " 0 unsigned int itemCodeValue " ] ) + " _10| " + str ( cube [ " 1 string itemCode " ] ) + " _16) "
2025-03-15 17:21:18 -04:00
is_original = not new_entry [ " isVariant " ]
2025-03-15 11:03:35 -04:00
# weapons
if new_entry [ " info " ] [ " type " ] == " Weapon " :
if is_original and " module " not in new_entry [ " info " ] [ " category " ] . lower ( ) : # ignore variants and modules
print ( name , new_entry [ " info " ] [ " category " ] , new_entry [ " info " ] [ " size " ] )
tier_num = int ( new_entry [ " info " ] [ " size " ] [ 1 ] )
new_entry [ " weapon " ] = {
" damage_inflicted " : i ,
" group_fire_scales " : [ 1.0 ] ,
}
new_entry [ " weapon_upgrade " ] = {
" xp " : tier_num + 1.0 ,
" rating " : tier_num ,
" rank " : tier_num ,
" power " : 0 ,
}
if new_entry [ " info " ] [ " category " ] in WEAPONS :
if new_entry [ " info " ] [ " size " ] in WEAPONS [ new_entry [ " info " ] [ " category " ] ] :
new_entry [ " weapon " ] = WEAPONS [ new_entry [ " info " ] [ " category " ] ] [ new_entry [ " info " ] [ " size " ] ]
2025-05-19 17:17:09 -04:00
new_entry [ " info " ] [ " ignore_in_weapon_list " ] = new_entry [ " info " ] [ " type " ] not in [ " Weapon " , " Module " ]
2025-03-15 11:03:35 -04:00
# tech tree
if new_entry [ " info " ] [ " category " ] != " NotAFunctionalItem " and is_original :
if last_tech_tree_id != 0 :
neighbours = [ last_tech_tree_id ]
else :
neighbours = [ ]
last_tech_tree_id = new_entry [ " id " ]
new_entry [ " tree " ] = {
" position_x " : tech_tree_index % 16 ,
" position_y " : tech_tree_index / / 16 ,
" tech_points " : i ,
" neighbours " : neighbours ,
" requires " : neighbours ,
}
tech_tree_index + = 1
if not is_original :
new_entry [ " tree " ] = {
" position_x " : tech_tree_specials_index % 16 ,
" position_y " : ( tech_tree_specials_index / / 16 ) + 8 ,
" tech_points " : i ,
" neighbours " : [ ] ,
" requires " : [ 227205318 ] , # default cube (MediumCube)
}
tech_tree_specials_index + = 1
2025-03-15 17:21:18 -04:00
# overrides
apply_entry_overrides ( new_entry , cubes_data , weapons_data , movement_data )
2025-03-09 16:28:03 -04:00
print ( f " processed cube { i } into { new_entry } " )
2025-03-15 17:21:18 -04:00
conf_out [ " cubes " ] [ new_key ] = new_entry
# more overrides
apply_global_overrides ( conf_out , cubes_data , weapons_data , movement_data )
with open ( " ../assets/robocraft/config.json " , " w " ) as f :
json . dump ( conf_out , f , indent = 4 )
2025-03-09 16:28:03 -04:00
print ( f " processed { len ( cubes ) } cubes " )
2025-03-15 17:21:18 -04:00
if movement_data is not None :
for category in CATEGORIES [ 1 : 13 ] :
if category not in SEEN_MOVEMENTS :
print ( " Missed movement category " , category )
else :
if len ( SEEN_MOVEMENTS [ category ] ) != len ( TIERS ) - 1 :
print ( " Only found " , len ( SEEN_MOVEMENTS [ category ] ) , " of " , len ( TIERS ) - 1 , " tiers for movement category " , category )
''' for tier in TIERS[1:]:
if tier not in SEEN_MOVEMENTS [ category ] or SEEN_MOVEMENTS [ category ] [ tier ] == False :
print ( " Missed movement tier " , tier , " in category " , category ) '''
if weapons_data is not None :
if len ( weapons_data ) != len ( SEEN_WEAPONS ) :
print ( " Only found " , len ( SEEN_WEAPONS ) , " of " , len ( weapons_data ) , " weapon entries in reference " )
2025-03-09 16:28:03 -04:00
if __name__ == " __main__ " :
2025-03-15 17:21:18 -04:00
parser = argparse . ArgumentParser ( )
parser . add_argument ( " asset_json " )
parser . add_argument ( " --cubes " )
parser . add_argument ( " --weapons " )
parser . add_argument ( " --movement " )
args = parser . parse_args ( )
main ( args . asset_json , cubes = args . cubes , weapons = args . weapons , movement = args . movement )