Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ jobs:
- run: black . --check


Python2:
docker:
- image: circleci/python:2.7.18
steps: *build_and_test_steps

Python3:
docker:
- image: circleci/python:3.10
Expand All @@ -41,5 +36,4 @@ workflows:
build:
jobs:
- StyleCheck
- Python2
- Python3
16 changes: 6 additions & 10 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
What is sc2reader?
====================

sc2reader is a python library for extracting information from various different Starcraft II resources. These resources currently include Replays, Maps, and Game Summaries; we have plans to add support for Battle.net profiles and would gladly accept adapters to the more entrenched SCII sites such as sc2ranks.
sc2reader is a Python 3 library for extracting information from various different Starcraft II resources. These resources currently include Replays, Maps, and Game Summaries; we have plans to add support for Battle.net profiles and would gladly accept adapters to the more entrenched SCII sites such as sc2ranks.

There is a pressing need in the SC2 community for better statistics, better analytics, better tools for organizing and searching replays. Better websites for sharing replays and hosting tournaments. These tools can't be created without first being able to open up Starcraft II game files and analyze the data within. Our goal is to give anyone and everyone the power to construct their own tools, do their own analysis, and hack on their own Starcraft II projects under the open MIT license.

Expand Down Expand Up @@ -195,26 +195,22 @@ The new GameHeartNormalizerplugin is registered by default.
Installation
================

sc2reader runs on any system with Python 2.6+, 3.2+, or PyPy installed.
sc2reader runs on any system with Python 3.7+, or PyPy3 installed.


From PyPI (stable)
---------------------

Install from the latest release on PyPI with pip::

pip install sc2reader

or easy_install::

easy_install sc2reader
python3 -m pip install sc2reader

or with setuptools (specify a valid x.x.x)::

wget http://pypi.python.org/packages/source/s/sc2reader/sc2reader-x.x.x.tar.gz
tar -xzf sc2reader-x.x.x.tar.gz
cd sc2reader-x.x.x
python setup.py install
python3 setup.py install

Releases to PyPi can be very delayed (sorry!), for the latest and greatest you are encouraged to install from Github upstream.

Expand All @@ -235,7 +231,7 @@ or with setuptools::
wget -O sc2reader-upstream.tar.gz https://github.com/ggtracker/sc2reader/tarball/upstream
tar -xzf sc2reader-upstream.tar.gz
cd sc2reader-upstream
python setup.py install
python3 setup.py install

.. _circle-ci: https://circleci.com/
.. _coveralls.io: https://coveralls.io
Expand All @@ -250,7 +246,7 @@ Contributors should install from an active git repository using setuptools in `d

git clone https://github.com/ggtracker/sc2reader.git
cd sc2reader
python setup.py develop
python3 setup.py develop

Please review the `CONTRIBUTING.md`_ file and get in touch with us before doing too much work. It'll make everyone happier in the long run.

Expand Down
1 change: 0 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
#
# sc2reader documentation build configuration file, created by
# sphinx-quickstart on Sun May 01 12:39:48 2011.
Expand Down
41 changes: 20 additions & 21 deletions examples/sc2autosave.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""sc2autosave is a utility for reorganizing and renaming Starcraft II files.

Overview
Expand Down Expand Up @@ -78,16 +77,16 @@
keeps the script from looking into the 'Saved' subdirectory.

sc2autosave \
--source ~/My\ Documents/Starcraft\ II/Accounts/.../Mutliplayer \
--dest ~/My\ Documents/Starcraft\ II/Accounts/.../Multiplater/Saved \
--source ~/My\\ Documents/Starcraft\\ II/Accounts/.../Mutliplayer \
--dest ~/My\\ Documents/Starcraft\\ II/Accounts/.../Multiplater/Saved \
--period 10 \
--depth 0

This next configuration runs in batch mode using the default renaming format.

sc2autosave \
--source ~/My\ Documents/Starcraft\ II/Accounts/.../Mutliplayer \
--dest ~/My\ Documents/Starcraft\ II/Accounts/.../Multiplater/Saved \
--source ~/My\\ Documents/Starcraft\\ II/Accounts/.../Mutliplayer \
--dest ~/My\\ Documents/Starcraft\\ II/Accounts/.../Multiplater/Saved \
--rename

(ZvP) Lost Temple: ShadesofGray(Z) vs Trisfall(P).SC2Replay
Expand All @@ -97,8 +96,8 @@
by replay format and favors ShadesofGray in the player and team orderings.

sc2autosave \
--source ~/My\ Documents/Starcraft\ II/Accounts/.../Mutliplayer \
--dest ~/My\ Documents/Starcraft\ II/Accounts/.../Multiplater/Saved \
--source ~/My\\ Documents/Starcraft\\ II/Accounts/.../Mutliplayer \
--dest ~/My\\ Documents/Starcraft\\ II/Accounts/.../Multiplater/Saved \
--rename "{:format}/{:matchup} on {:map}: {:teams}" \
--player-format "{:name}({:play_race})" \
--team-order-by number \
Expand All @@ -113,8 +112,8 @@
length to show both minutes and seconds.

sc2autosave \
--source ~/My\ Documents/Starcraft\ II/Accounts/.../Mutliplayer \
--dest ~/My\ Documents/Starcraft\ II/Accounts/.../Multiplater/Saved \
--source ~/My\\ Documents/Starcraft\\ II/Accounts/.../Mutliplayer \
--dest ~/My\\ Documents/Starcraft\\ II/Accounts/.../Multiplater/Saved \
--rename "{:matchup}/({:length}) {:map}: {:teams}" \
--player-format "{:name}({:play_race})" \
--team-order-by number \
Expand Down Expand Up @@ -200,7 +199,7 @@ def run(args):
directory = make_directory(args, ("parse_error",))
new_path = os.path.join(directory, file_name)
source_path = path[len(args.source) :]
args.log.write("Error parsing replay: {0}".format(source_path))
args.log.write(f"Error parsing replay: {source_path}")
if not args.dryrun:
args.action.run(path, new_path)

Expand Down Expand Up @@ -250,7 +249,7 @@ def run(args):


def filter_out_replay(args, replay):
player_names = set([player.name for player in replay.players])
player_names = {player.name for player in replay.players}
filter_out_player = not set(args.filter_player) & player_names

if args.filter_rule == "ALLOW":
Expand All @@ -262,7 +261,7 @@ def filter_out_replay(args, replay):
# We need to create these compare functions at runtime because the ordering
# hinges on the --favored PLAYER options passed in from the command line.
def create_compare_funcs(args):
favored_set = set(name.lower() for name in args.favored)
favored_set = {name.lower() for name in args.favored}

def player_compare(player1, player2):
# Normalize the player names and generate our key metrics
Expand Down Expand Up @@ -290,8 +289,8 @@ def player_compare(player1, player2):

def team_compare(team1, team2):
# Normalize the team name lists and generate our key metrics
team1_names = set(p.name.lower() for p in team1.players)
team2_names = set(p.name.lower() for p in team2.players)
team1_names = {p.name.lower() for p in team1.players}
team2_names = {p.name.lower() for p in team2.players}
team1_favored = team1_names & favored_set
team2_favored = team2_names & favored_set

Expand Down Expand Up @@ -341,7 +340,7 @@ def make_directory(args, path_parts):
for part in path_parts:
directory = os.path.join(directory, part)
if not os.path.exists(directory):
args.log.write("Creating subfolder: {0}\n".format(directory))
args.log.write(f"Creating subfolder: {directory}\n")
if not args.dryrun:
os.mkdir(directory)
elif not os.path.isdir(directory):
Expand All @@ -351,7 +350,7 @@ def make_directory(args, path_parts):


def scan(args, state):
args.log.write("SCANNING: {0}\n".format(args.source))
args.log.write(f"SCANNING: {args.source}\n")
files = sc2reader.utils.get_files(
path=args.source,
regex=args.exclude_files,
Expand All @@ -374,13 +373,13 @@ def reset(args):
exit("Cannot reset, destination must be directory: {0}", args.dest)

print(
"About to reset directory: {0}\nAll files and subdirectories will be removed.".format(
"About to reset directory: {}\nAll files and subdirectories will be removed.".format(
args.dest
)
)
choice = raw_input("Proceed anyway? (y/n) ")
if choice.lower() == "y":
args.log.write("Removing old directory: {0}\n".format(args.dest))
args.log.write(f"Removing old directory: {args.dest}\n")
if not args.dryrun:
print(args.dest)
shutil.rmtree(args.dest)
Expand All @@ -404,13 +403,13 @@ def setup(args):
if not args.dryrun:
os.mkdir(args.dest)
else:
args.log.write("Creating destination: {0}\n".format(args.dest))
args.log.write(f"Creating destination: {args.dest}\n")
elif not os.path.isdir(args.dest):
sys.exit("Destination must be a directory.\n\nScript Aborted")

data_file = os.path.join(args.dest, "sc2autosave.dat")

args.log.write("Loading state from file: {0}\n".format(data_file))
args.log.write(f"Loading state from file: {data_file}\n")
if os.path.isfile(data_file) and not args.reset:
with open(data_file) as file:
return cPickle.load(file)
Expand All @@ -425,7 +424,7 @@ def save_state(state, args):
with open(data_file, "w") as file:
cPickle.dump(state, file)
else:
args.log.write("Writing state to file: {0}\n".format(data_file))
args.log.write(f"Writing state to file: {data_file}\n")


def main():
Expand Down
3 changes: 1 addition & 2 deletions examples/sc2store.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import cPickle
import os
Expand Down Expand Up @@ -196,7 +195,7 @@ def main():

for path in args.paths:
for file_name in sc2reader.utils.get_files(path, depth=0):
print("CREATING: {0}".format(file_name))
print(f"CREATING: {file_name}")
db.add(Game(sc2reader.read_file(file_name), db))

db.commit()
Expand Down
22 changes: 11 additions & 11 deletions generate_build_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def generate_build_data(balance_data_path):
elif unit_id == "Drone":
build_ability_name = "ZergBuild"
else:
build_ability_name = "{}Build".format(unit_id)
build_ability_name = f"{unit_id}Build"

if build_ability_index:
abilities[build_ability_index] = build_ability_name
Expand All @@ -77,7 +77,7 @@ def generate_build_data(balance_data_path):
while len(ability_lookup[build_ability_name]) <= command_index:
ability_lookup[build_ability_name].append("")

build_command_name = "Build{}".format(built_unit_id)
build_command_name = f"Build{built_unit_id}"
ability_lookup[build_ability_name][
command_index
] = build_command_name
Expand All @@ -87,7 +87,7 @@ def generate_build_data(balance_data_path):
train_ability_index = train_unit_elements[0].get("ability")

if train_ability_index:
train_ability_name = "{}Train".format(unit_id)
train_ability_name = f"{unit_id}Train"
abilities[train_ability_index] = train_ability_name

if train_ability_name not in ability_lookup:
Expand Down Expand Up @@ -137,15 +137,15 @@ def generate_build_data(balance_data_path):
):
ability_lookup[train_ability_name].append("")

train_command_name = "Train{}".format(trained_unit_name)
train_command_name = f"Train{trained_unit_name}"
ability_lookup[train_ability_name][
command_index
] = train_command_name

research_upgrade_elements = root.findall("./researches/upgrade")
if research_upgrade_elements:
research_ability_index = research_upgrade_elements[0].get("ability")
research_ability_name = "{}Research".format(unit_id)
research_ability_name = f"{unit_id}Research"

abilities[research_ability_index] = research_ability_name

Expand All @@ -163,7 +163,7 @@ def generate_build_data(balance_data_path):
while len(ability_lookup[research_ability_name]) <= command_index:
ability_lookup[research_ability_name].append("")

research_command_name = "Research{}".format(researched_upgrade_id)
research_command_name = f"Research{researched_upgrade_id}"
ability_lookup[research_ability_name][
command_index
] = research_command_name
Expand All @@ -175,7 +175,7 @@ def generate_build_data(balance_data_path):
sorted(abilities.items(), key=lambda x: int(x[0]))
)

unit_lookup = dict((unit_name, unit_name) for _, unit_name in sorted_units.items())
unit_lookup = {unit_name: unit_name for _, unit_name in sorted_units.items()}

return sorted_units, sorted_abilities, unit_lookup, ability_lookup

Expand Down Expand Up @@ -258,7 +258,7 @@ def main():
unit_lookup_path = os.path.join(
args.project_path, "sc2reader", "data", "unit_lookup.csv"
)
with open(unit_lookup_path, "r") as file:
with open(unit_lookup_path) as file:
csv_reader = csv.reader(file, delimiter=",", lineterminator=os.linesep)
old_unit_lookup = collections.OrderedDict(
[(row[0], row[1]) for row in csv_reader if len(row) > 1]
Expand All @@ -267,7 +267,7 @@ def main():
ability_lookup_path = os.path.join(
args.project_path, "sc2reader", "data", "ability_lookup.csv"
)
with open(ability_lookup_path, "r") as file:
with open(ability_lookup_path) as file:
csv_reader = csv.reader(file, delimiter=",", lineterminator=os.linesep)
old_ability_lookup = collections.OrderedDict(
[(row[0], row[1:]) for row in csv_reader if len(row) > 0]
Expand All @@ -290,7 +290,7 @@ def main():
"sc2reader",
"data",
args.expansion,
"{}_units.csv".format(args.build_version),
f"{args.build_version}_units.csv",
)
with open(units_file_path, "w") as file:
csv_writer = csv.writer(file, delimiter=",", lineterminator=os.linesep)
Expand All @@ -302,7 +302,7 @@ def main():
"sc2reader",
"data",
args.expansion,
"{}_abilities.csv".format(args.build_version),
f"{args.build_version}_abilities.csv",
)
with open(abilities_file_path, "w") as file:
csv_writer = csv.writer(file, delimiter=",", lineterminator=os.linesep)
Expand Down
8 changes: 4 additions & 4 deletions new_units.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@
str_id, title = entry.strip().split(",")
UNIT_LOOKUP[str_id] = title

with open(sys.argv[1], "r") as new_units:
with open(sys.argv[1]) as new_units:
for line in new_units:
new_unit_name = line.strip().split(",")[1]
if new_unit_name not in UNIT_LOOKUP:
print("{0},{1}".format(new_unit_name, new_unit_name))
print(f"{new_unit_name},{new_unit_name}")

print("")
print("")
Expand All @@ -31,8 +31,8 @@
str_id, abilities = entry.split(",", 1)
ABIL_LOOKUP[str_id] = abilities.split(",")

with open(sys.argv[2], "r") as new_abilities:
with open(sys.argv[2]) as new_abilities:
for line in new_abilities:
new_ability_name = line.strip().split(",")[1]
if new_ability_name not in ABIL_LOOKUP:
print("{0},{1}".format(new_ability_name, new_ability_name))
print(f"{new_ability_name},{new_ability_name}")
2 changes: 0 additions & 2 deletions sc2reader/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
"""
sc2reader
~~~~~~~~~~~
Expand All @@ -18,7 +17,6 @@
:copyright: (c) 2011 by Graylin Kim.
:license: MIT, see LICENSE for more details.
"""
from __future__ import absolute_import, print_function, unicode_literals, division

__version__ = "1.8.0"

Expand Down
3 changes: 0 additions & 3 deletions sc2reader/constants.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals, division

# These are found in Repack-MPQ/fileset.{locale}#Mods#Core.SC2Mod#{locale}.SC2Data/LocalizedData/Editor/EditorCategoryStrings.txt
# EDSTR_CATEGORY_Race
# EDSTR_PLAYERPROPS_RACE
Expand Down
Loading