Page Menu
Home
Wildfire Games
Search
Configure Global Search
Log In
Paste
P267
Fix D4584.
Active
Public
Actions
Authored by
Freagarach
on Mar 14 2022, 7:55 AM.
Edit Paste
Archive Paste
View Raw File
Subscribe
Mute Notifications
Award Token
Flag For Later
Tags
None
Subscribers
None
#!/usr/bin/env python3
from
lxml
import
etree
as
ET
import
fileinput
import
glob
import
json
import
os
import
pysvn
import
sys
class
StyleFixer
:
def
fix_template_style
(
template_path
):
changes
=
[
[
"version='1.0'"
,
'version="1.0"'
],
[
"'UTF-8'"
,
'"utf-8"'
]
]
StyleFixer
.
sed
(
template_path
,
changes
)
def
sed
(
path
,
changes
):
for
line
in
fileinput
.
input
(
path
,
inplace
=
True
):
for
change
in
changes
:
line
=
line
.
replace
(
change
[
0
],
change
[
1
])
print
(
line
,
end
=
""
)
def
simplify_requirements
(
reqs
):
if
len
(
reqs
)
!=
1
:
return
all_req
=
reqs
.
find
(
"All"
)
if
all_req
==
None
:
return
reqs
.
remove
(
all_req
)
for
child
in
all_req
:
reqs
.
append
(
child
)
def
sort_xml
(
node
):
node
[:]
=
sorted
(
node
,
key
=
lambda
child
:
child
.
tag
)
for
child
in
node
:
StyleFixer
.
sort_xml
(
child
)
class
TechnologyConverter
:
def
__init__
(
self
,
vfs_root
):
self
.
scc
=
pysvn
.
Client
()
self
.
tech_folder
=
os
.
path
.
join
(
vfs_root
,
'simulation'
,
'data'
,
'technologies'
)
self
.
template_folder
=
os
.
path
.
join
(
vfs_root
,
'simulation'
,
'templates'
)
self
.
tech_template_folder
=
os
.
path
.
join
(
self
.
template_folder
,
'technologies'
)
self
.
civs
=
[]
os
.
makedirs
(
self
.
tech_template_folder
,
exist_ok
=
True
)
self
.
scc
.
add
(
self
.
tech_template_folder
,
force
=
True
)
with
os
.
scandir
(
os
.
path
.
join
(
self
.
template_folder
,
'players'
))
as
civ_files
:
for
civ_file
in
civ_files
:
if
civ_file
.
is_file
():
civ
=
civ_file
.
name
.
removesuffix
(
".xml"
)
if
civ
==
'gaia'
:
continue
self
.
civs
.
append
(
civ
)
civ_folder
=
os
.
path
.
join
(
self
.
tech_template_folder
,
civ
)
os
.
makedirs
(
civ_folder
,
exist_ok
=
True
)
self
.
scc
.
add
(
civ_folder
,
force
=
True
)
def
add_requirements
(
self
,
req_json
,
reqs
):
if
'tech'
in
req_json
:
techs
=
ET
.
SubElement
(
reqs
,
"Techs"
)
techs
.
set
(
"datatype"
,
"tokens"
)
techs
.
text
=
req_json
[
'tech'
]
if
'entity'
in
req_json
:
ent_req
=
ET
.
SubElement
(
ET
.
SubElement
(
reqs
,
"Entities"
),
req_json
[
'entity'
][
'class'
])
if
'number'
in
req_json
[
'entity'
]:
ET
.
SubElement
(
ent_req
,
"Count"
)
.
text
=
str
(
req_json
[
'entity'
][
'number'
])
if
'variants'
in
req_json
[
'entity'
]:
ET
.
SubElement
(
ent_req
,
"Variants"
)
.
text
=
str
(
req_json
[
'entity'
][
'variants'
])
if
'all'
in
req_json
:
all_req
=
ET
.
SubElement
(
reqs
,
"All"
)
for
req
in
req_json
[
'all'
]:
self
.
add_requirements
(
req
,
all_req
)
if
len
(
all_req
)
==
0
:
reqs
.
remove
(
all_req
)
if
'any'
in
req_json
:
any_req
=
ET
.
SubElement
(
reqs
,
"Any"
)
for
req
in
req_json
[
'any'
]:
self
.
add_requirements
(
req
,
any_req
)
if
len
(
any_req
)
==
0
:
reqs
.
remove
(
any_req
)
def
add_modifications
(
self
,
cmp_tech
,
tech_json
):
mods
=
ET
.
SubElement
(
cmp_tech
,
"Modifiers"
)
i
=
1
for
mod
in
tech_json
[
'modifications'
]:
modifier
=
ET
.
SubElement
(
mods
,
"modifier"
+
str
(
i
))
i
+=
1
paths
=
ET
.
SubElement
(
modifier
,
"Paths"
)
paths
.
set
(
"datatype"
,
"tokens"
)
paths
.
text
=
mod
[
'value'
]
if
'add'
in
mod
:
ET
.
SubElement
(
modifier
,
"Add"
)
.
text
=
str
(
mod
[
'add'
])
elif
'multiply'
in
mod
:
ET
.
SubElement
(
modifier
,
"Multiply"
)
.
text
=
str
(
mod
[
'multiply'
])
elif
'replace'
in
mod
:
ET
.
SubElement
(
modifier
,
"Replace"
)
.
text
=
str
(
mod
[
'replace'
])
affects
=
ET
.
SubElement
(
modifier
,
"Affects"
)
affects
.
set
(
"datatype"
,
"tokens"
)
if
'affects'
in
tech_json
:
affects
.
text
=
tech_json
[
'affects'
][
0
]
.
replace
(
" "
,
"+"
)
for
affect
in
tech_json
[
'affects'
][
1
:]:
affects
.
text
=
affects
.
text
+
" "
+
affect
.
replace
(
" "
,
"+"
)
if
'affects'
in
mod
:
if
affects
.
text
==
None
:
affects
.
text
=
mod
[
'affects'
]
else
:
affects
.
text
=
affects
.
text
+
"+"
+
mod
[
'affects'
]
if
affects
.
text
==
None
:
modifier
.
remove
(
affects
)
def
create_civ_tech
(
self
,
tech_json
,
name
,
civ
):
file_path
=
os
.
path
.
join
(
self
.
tech_template_folder
,
civ
,
name
)
+
".xml"
root
=
ET
.
Element
(
"Technology"
)
root
.
set
(
"parent"
,
"template_technology_"
+
name
)
cmp_identity
=
ET
.
SubElement
(
root
,
"Identity"
)
ET
.
SubElement
(
cmp_identity
,
"Civ"
)
.
text
=
civ
if
'specificName'
in
tech_json
and
civ
in
tech_json
[
'specificName'
]:
ET
.
SubElement
(
cmp_identity
,
"SpecificName"
)
.
text
=
tech_json
[
'specificName'
][
civ
]
StyleFixer
.
sort_xml
(
root
)
ET
.
ElementTree
(
root
)
.
write
(
file_path
,
xml_declaration
=
True
,
pretty_print
=
True
,
encoding
=
'utf-8'
)
StyleFixer
.
fix_template_style
(
file_path
)
self
.
scc
.
add
(
file_path
)
if
'autoResearch'
in
tech_json
:
player_template_path
=
os
.
path
.
join
(
self
.
template_folder
,
'players'
,
civ
)
+
".xml"
tree
=
ET
.
parse
(
player_template_path
)
root
=
tree
.
getroot
()
cmp_technology_manager
=
root
.
find
(
'TechnologyManager'
)
if
cmp_technology_manager
==
None
:
cmp_technology_manager
=
ET
.
SubElement
(
root
,
"TechnologyManager"
)
auto_researched
=
cmp_technology_manager
.
find
(
'AutoResearched'
)
if
auto_researched
==
None
:
auto_researched
=
ET
.
SubElement
(
cmp_technology_manager
,
"AutoResearched')
indentation
=
' '
if
auto_researched
.
text
==
None
:
auto_researched
.
text
=
"
\n
"
+
indentation
+
"technologies/"
+
civ
+
name
+
"
\n
"
+
indentation
else
:
auto_researched
.
text
=
auto_researched
.
text
+
" "
+
"technologies/"
+
civ
+
name
+
"
\n
"
+
indentation
StyleFixer
.
sort_xml
(
root
)
ET
.
ElementTree
(
root
)
.
write
(
player_template_path
,
xml_declaration
=
True
,
pretty_print
=
True
,
encoding
=
'utf-8'
)
StyleFixer
.
fix_template_style
(
player_template_path
)
def
convert_tech_to_template
(
self
,
tech_path
,
name
):
tech_json
=
json
.
load
(
tech_path
)
root
=
ET
.
Element
(
"Technology"
)
cmp_tech
=
ET
.
SubElement
(
root
,
"Technology"
)
if
'top'
in
tech_json
:
ET
.
SubElement
(
cmp_tech
,
"Choices"
)
.
text
=
"technologies/{civ}/"
+
tech_json
[
'top'
]
+
" "
+
"technologies/{civ}/"
+
tech_json
[
'bottom'
]
cmp_identity
=
ET
.
SubElement
(
root
,
"Identity"
)
ET
.
SubElement
(
cmp_identity
,
"GenericName"
)
.
text
=
tech_json
[
'genericName'
]
ET
.
SubElement
(
cmp_identity
,
"History"
)
.
text
=
tech_json
[
'description'
]
if
'description'
in
tech_json
else
""
ET
.
SubElement
(
cmp_identity
,
"Icon"
)
.
text
=
"technologies/"
+
tech_json
[
'icon'
]
ET
.
SubElement
(
cmp_identity
,
"Tooltip"
)
.
text
=
tech_json
[
'tooltip'
]
# The identity spec requires this.
ET
.
SubElement
(
cmp_identity
,
"Undeletable"
)
.
text
=
"true"
# It would be nice to not have this dual relationship.
if
'pair'
in
tech_json
:
ET
.
SubElement
(
cmp_tech
,
"ChoiceRoot"
)
.
text
=
tech_json
[
'pair'
]
if
'phase'
in
name
:
classes
=
ET
.
SubElement
(
cmp_identity
,
"Classes"
)
classes
.
set
(
"datatype"
,
"tokens"
)
classes
.
text
=
"Phase"
if
'supersedes'
in
tech_json
:
ET
.
SubElement
(
cmp_tech
,
"Supersedes"
)
.
text
=
"technologies/{civ}/"
+
tech_json
[
'supersedes'
]
allowed_civs
=
[]
disallowed_civs
=
[]
if
'requirements'
in
tech_json
:
reqs
=
ET
.
Element
(
"Requirements"
)
self
.
add_requirements
(
tech_json
[
'requirements'
],
reqs
)
if
'all'
in
tech_json
[
'requirements'
]:
for
req
in
tech_json
[
'requirements'
][
'all'
]:
if
'civ'
in
req
:
allowed_civs
.
append
(
req
[
'civ'
])
if
'notciv'
in
req
:
disallowed_civs
.
append
(
req
[
'notciv'
])
if
'any'
in
req
:
for
civ_req
in
req
[
'any'
]:
allowed_civs
.
append
(
civ_req
[
'civ'
])
elif
'any'
in
tech_json
[
'requirements'
]:
for
req
in
tech_json
[
'requirements'
][
'any'
]:
if
'civ'
in
req
:
allowed_civs
.
append
(
req
[
'civ'
])
elif
'civ'
in
tech_json
[
'requirements'
]:
allowed_civs
.
append
(
tech_json
[
'requirements'
][
'civ'
])
StyleFixer
.
simplify_requirements
(
reqs
)
if
'requirementsTooltip'
in
tech_json
:
techs
=
reqs
.
find
(
'Techs'
)
if
len
(
reqs
)
!=
1
or
techs
==
None
:
ET
.
SubElement
(
reqs
,
"Tooltip"
)
.
text
=
tech_json
[
'requirementsTooltip'
]
if
len
(
reqs
)
>
0
:
cmp_identity
.
append
(
reqs
)
if
'cost'
in
tech_json
:
cmp_cost
=
ET
.
SubElement
(
root
,
"Cost"
)
resource_cost
=
ET
.
SubElement
(
cmp_cost
,
"Resources"
)
for
element
in
tech_json
[
'cost'
]:
ET
.
SubElement
(
resource_cost
,
element
)
.
text
=
str
(
tech_json
[
'cost'
][
element
])
if
'researchTime'
in
tech_json
:
ET
.
SubElement
(
cmp_cost
,
"BuildTime"
)
.
text
=
str
(
tech_json
[
'researchTime'
])
# cmpCost expects this node.
else
:
ET
.
SubElement
(
cmp_cost
,
"BuildTime"
)
.
text
=
'0'
# cmpCost expects this node.
ET
.
SubElement
(
cmp_cost
,
"Population"
)
.
text
=
'0'
if
'soundComplete'
in
tech_json
:
ET
.
SubElement
(
ET
.
SubElement
(
ET
.
SubElement
(
root
,
"Sound"
),
"SoundGroups"
),
"completed"
)
.
text
=
tech_json
[
'soundComplete'
]
if
'modifications'
in
tech_json
:
self
.
add_modifications
(
cmp_tech
,
tech_json
)
if
len
(
allowed_civs
)
>
0
and
len
(
disallowed_civs
)
>
0
:
print
(
"Warning: complex (dis)allowed civs: "
+
name
)
if
len
(
disallowed_civs
)
>
0
:
for
civ
in
self
.
civs
:
if
not
civ
in
disallowed_civs
:
allowed_civs
.
append
(
civ
)
elif
len
(
allowed_civs
)
==
0
:
allowed_civs
=
self
.
civs
[:]
for
civ
in
allowed_civs
:
self
.
create_civ_tech
(
tech_json
,
name
,
civ
)
StyleFixer
.
sort_xml
(
root
)
ET
.
ElementTree
(
root
)
.
write
(
tech_path
.
name
,
xml_declaration
=
True
,
pretty_print
=
True
,
encoding
=
'utf-8'
)
def
run
(
self
):
for
tech_path
in
glob
.
iglob
(
self
.
tech_folder
+
'/**/*.json'
,
recursive
=
True
):
name
=
os
.
path
.
basename
(
tech_path
)
.
removesuffix
(
".json"
)
if
'phase'
in
name
:
if
'generic'
in
name
:
name
=
name
.
removesuffix
(
"_generic"
)
else
:
continue
tech_template_path
=
os
.
path
.
join
(
self
.
template_folder
,
"template_technology_"
+
name
)
+
".xml"
self
.
scc
.
move
(
tech_path
,
tech_template_path
)
with
open
(
tech_template_path
,
'r'
)
as
file
:
try
:
self
.
convert_tech_to_template
(
file
,
name
)
StyleFixer
.
fix_template_style
(
tech_template_path
)
except
Exception
as
e
:
print
(
"Error: Failed conversion: "
+
name
)
print
(
e
)
self
.
scc
.
move
(
tech_template_path
,
tech_path
)
def
convert_input_file
(
self
,
relative_path
):
new_path
=
relative_path
if
'json'
in
relative_path
:
new_path
=
relative_path
.
removesuffix
(
".json"
)
+
".xml"
self
.
scc
.
move
(
relative_path
,
new_path
)
name
=
os
.
path
.
basename
(
new_path
)
.
removesuffix
(
".xml"
)
with
open
(
new_path
,
'r'
)
as
file
:
try
:
self
.
convert_tech_to_template
(
file
,
name
)
except
Exception
as
e
:
print
(
"Error: Failed conversion: "
+
relative_path
)
print
(
e
)
StyleFixer
.
fix_template_style
(
new_path
)
class
TemplateFixer
:
def
__init__
(
self
,
vfs_root
):
self
.
template_folder
=
os
.
path
.
join
(
vfs_root
,
'simulation'
,
'templates'
)
def
fix_template
(
self
,
template_path
):
tree
=
ET
.
parse
(
template_path
)
root
=
tree
.
getroot
()
changed
=
False
if
self
.
fix_researcher
(
root
):
changed
=
True
if
self
.
check_requirements
(
root
):
changed
=
True
tree
.
write
(
template_path
,
xml_declaration
=
True
,
pretty_print
=
True
,
encoding
=
'utf-8'
)
return
changed
def
fix_researcher
(
self
,
root
):
cmp_researcher
=
root
.
find
(
'Researcher'
)
if
cmp_researcher
==
None
:
return
False
technologies
=
cmp_researcher
.
find
(
'Technologies'
)
if
technologies
==
None
:
return
False
self
.
fix_technology_names
(
technologies
,
' '
)
return
True
def
fix_technology_names
(
self
,
node
,
indentation
):
new_names
=
[]
for
technology
in
node
.
text
.
split
():
prefix
=
"technologies/{civ}/"
if
technology
[
0
]
==
'!'
:
prefix
=
'!'
+
prefix
technology
=
technology
[
1
:]
if
technology
[
0
]
==
'-'
:
if
technology
[
1
]
==
'!'
:
prefix
=
'!'
+
prefix
technology
=
technology
[
1
:]
prefix
=
'-'
+
prefix
technology
=
technology
[
1
:]
if
prefix
in
technology
:
new_names
.
append
(
technology
.
removesuffix
(
"_{civ}"
))
else
:
new_names
.
append
(
prefix
+
technology
.
removesuffix
(
"_{civ}"
))
node
.
text
=
"
\n
"
+
indentation
+
(
'
\n
'
+
indentation
)
.
join
(
sorted
(
new_names
))
+
"
\n
"
+
indentation
def
check_requirements
(
self
,
root
):
changed
=
False
cmp_identity
=
root
.
find
(
'Identity'
)
if
cmp_identity
!=
None
:
requirements
=
cmp_identity
.
find
(
'Requirements'
)
if
requirements
!=
None
and
self
.
fix_requirements
(
requirements
,
' '
):
changed
=
True
cmp_upgrade
=
root
.
find
(
'Upgrade'
)
if
cmp_upgrade
!=
None
:
for
upgrade
in
cmp_upgrade
.
findall
(
'./'
):
requirements
=
upgrade
.
find
(
'Requirements'
)
if
requirements
!=
None
and
self
.
fix_requirements
(
requirements
,
' '
):
changed
=
True
cmp_entity_limits
=
root
.
find
(
'EntityLimits'
)
if
cmp_entity_limits
!=
None
:
limit_removers
=
cmp_entity_limits
.
find
(
'LimitRemovers'
)
if
limit_removers
!=
None
:
for
class_entry
in
limit_removers
:
req_techs
=
class_entry
.
find
(
'RequiredTechs'
)
if
req_techs
!=
None
:
self
.
fix_technology_names
(
req_techs
,
' '
)
changed
=
True
return
changed
def
fix_requirements
(
self
,
requirements
,
indentation
):
technologies
=
requirements
.
find
(
'Techs'
)
if
technologies
==
None
:
return
False
self
.
fix_technology_names
(
technologies
,
indentation
)
return
True
def
run
(
self
):
for
template_path
in
glob
.
iglob
(
self
.
template_folder
+
'/**/*.xml'
,
recursive
=
True
):
if
self
.
fix_template
(
template_path
):
StyleFixer
.
fix_template_style
(
template_path
)
if
__name__
==
'__main__'
:
script_dir
=
os
.
path
.
dirname
(
os
.
path
.
realpath
(
__file__
))
tech_converter
=
TechnologyConverter
(
script_dir
)
if
len
(
sys
.
argv
)
>
1
:
for
tech_path
in
sys
.
argv
[
1
:]:
tech_converter
.
convert_input_file
(
tech_path
)
else
:
tech_converter
.
run
()
template_fixer
=
TemplateFixer
(
script_dir
)
template_fixer
.
run
()
Event Timeline
Freagarach
created this paste.
Mar 14 2022, 7:55 AM
Freagarach
created this object with visibility "No One".
Freagarach
edited the content of this paste.
(Show Details)
Mar 14 2022, 5:18 PM
Freagarach
edited the content of this paste.
(Show Details)
Mar 25 2022, 4:46 PM
Freagarach
mentioned this in
D4584: [WIP] - Technologies to templates.
.
Mar 31 2022, 8:24 AM
Freagarach
changed the title of this paste from
Fix Dxxxx.
to
Fix D4584.
.
Mar 31 2022, 8:24 AM
Freagarach
edited the content of this paste.
(Show Details)
Freagarach
changed the visibility from "No One" to "Public (No Login Required)".
Freagarach
edited the content of this paste.
(Show Details)
Apr 1 2022, 5:51 PM
Freagarach
edited the content of this paste.
(Show Details)
Apr 9 2022, 9:35 AM
Freagarach
edited the content of this paste.
(Show Details)
Apr 17 2022, 7:16 AM
Freagarach
edited the content of this paste.
(Show Details)
Nov 25 2022, 8:47 AM
Freagarach
edited the content of this paste.
(Show Details)
Mar 10 2023, 3:35 PM
Freagarach
edited the content of this paste.
(Show Details)
Mar 13 2023, 4:07 PM
Freagarach
edited the content of this paste.
(Show Details)
Mar 24 2023, 12:29 PM
Freagarach
edited the content of this paste.
(Show Details)
Mar 24 2023, 2:23 PM
Freagarach
edited the content of this paste.
(Show Details)
Mar 31 2023, 3:06 PM
Freagarach
edited the content of this paste.
(Show Details)
Apr 4 2023, 3:37 PM
Log In to Comment