osrsbox-db/scripts/cache/determine_changes.py

222 lines
8.1 KiB
Python

"""
Author: PH01L
Email: phoil@osrsbox.com
Website: https://www.osrsbox.com
Description:
A script to determine new items and monsters added after a game
update. This is used to help update the CHANGELOG in the repository.
This script takes two different files inputs for items and monsters:
- items: data/items-cache-data.json
- monsters: data/monsters-cache-data.json
When generated, both files should exist in: data/cache/ and the files
should be copied to: data/
Copyright (c) 2020, PH01L
###############################################################################
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
###############################################################################
"""
import json
import os
from pathlib import Path
from pprint import pprint
from typing import List
from typing import Dict
import config
class DetermineCacheChanges:
"""A class to determine added, removed, changed and unchanged entries.
Every OSRS weekly update has the potential to add, remove or change item
and monster properties. This class analyzes the OSRS cache dump of the
existing entries and compares to a new database dump.
:param current_dict: A dictionary of the new items_scraper.json file
:param past_dict: A dictionary of the old items_scraper.json file
"""
def __init__(self, current_dict: Dict, past_dict: Dict):
self.current_dict = current_dict
self.past_dict = past_dict
self.set_current = set(current_dict.keys())
self.set_past = set(past_dict.keys())
self.intersect = self.set_current.intersection(self.set_past)
def added(self) -> List:
"""Return a set of only new IDs that is sorted."""
added = self.set_current - self.intersect
added = sorted(added)
return added
def removed(self) -> List:
"""Return a set of only removed IDs that is sorted."""
removed = self.set_past - self.intersect
removed = sorted(removed)
return removed
def changed(self) -> List:
"""Return a set of only changed entries (including properties) that is sorted."""
changed = set(o for o in self.intersect if self.past_dict[o] != self.current_dict[o])
changed = sorted(changed)
return changed
def unchanged(self) -> List:
"""Return a set of only unchanged entries (including properties) that is sorted."""
unchanged = set(o for o in self.intersect if self.past_dict[o] == self.current_dict[o])
unchanged = sorted(unchanged)
return unchanged
def items():
"""The main function for determining item changes."""
# Read in the old items-cache-data.json file
fi_name = Path(config.DATA_ITEMS_PATH / "items-cache-data.json")
os.makedirs(os.path.dirname(fi_name), exist_ok=True)
fi_name.touch(exist_ok=True)
with open(fi_name, mode='r+') as f:
try:
old_items = json.load(f)
except json.decoder.JSONDecodeError:
old_items = dict()
pprint(f"No old item cache data")
# Read in the new items-cache-data.json file
fi_name = Path(config.DATA_ITEMS_PATH / "items-cache-data-new.json")
os.makedirs(os.path.dirname(fi_name), exist_ok=True)
with open(fi_name, mode='r+') as f:
new_items = json.load(f)
# Initialize class
dd = DetermineCacheChanges(new_items, old_items)
# Determine added items
added = dd.added()
print("- Added items: %d" % len(added))
for itemID in added:
print(" - %s,%s" % (itemID,
new_items[itemID]["name"]))
# Determine removed items
removed = dd.removed()
print("- Removed items: %d" % len(removed))
for itemID in removed:
print(" - %s,%s" % (itemID,
old_items[itemID]["name"]))
# Determine changed items
changed = dd.changed()
print("- Changed items: %d" % len(changed))
for itemID in changed:
changed_keys = list()
for key in new_items[itemID]:
if new_items[itemID][key] != old_items[itemID][key]:
changed_keys.append(key)
if changed_keys:
print(" - %s,%s,%s" % (itemID,
old_items[itemID]["name"],
'|'.join(changed_keys)))
# # Determine unchanged items
# # This is commented out, as the results are always large
# unchanged = dd.unchanged()
# print("- Unchanged items: %d" % len(unchanged))
# for itemID in unchanged:
# print(" - %s,%s" % (itemID,
# new_items[itemID]["name"]))
def monsters():
"""The main function for determining monster changes."""
# Read in the old monsters-cache-data.json file
fi_name = Path(config.DATA_MONSTERS_PATH / "monsters-cache-data.json")
os.makedirs(os.path.dirname(fi_name), exist_ok=True)
fi_name.touch(exist_ok=True)
with open(fi_name) as f:
try:
old_monsters = json.load(f)
except json.decoder.JSONDecodeError:
old_monsters = dict()
pprint(f"No old monster cache data")
# Read in the new monsters-cache-data.json file
fi_name = Path(config.DATA_MONSTERS_PATH / "monsters-cache-data-new.json")
with open(fi_name) as f:
new_monsters = json.load(f)
# Initialize class
dd = DetermineCacheChanges(new_monsters, old_monsters)
# Determine added monsters
added = dd.added()
print("- Added monsters: %d" % len(added))
for monsterID in added:
print(" - %s,%s" % (monsterID,
new_monsters[monsterID]["name"]))
# Determine removed monsters
removed = dd.removed()
print("- Removed monsters: %d" % len(removed))
for monsterID in removed:
print(" - %s,%s" % (monsterID,
old_monsters[monsterID]["name"]))
# Determine changed monsters
changed = dd.changed()
print("- Changed monsters: %d" % len(changed))
for monsterID in changed:
changed_keys = list()
for key in new_monsters[monsterID]:
new_monsters_key = new_monsters[monsterID].get(key)
old_monsters_key = old_monsters[monsterID].get(key)
if new_monsters_key is None or old_monsters_key is None:
continue
if new_monsters[monsterID][key] != old_monsters[monsterID][key]:
changed_keys.append(key)
if changed_keys:
print(" - %s,%s,%s" % (monsterID,
old_monsters[monsterID]["name"],
'|'.join(changed_keys)))
# # Determine unchanged monsters
# # This is commented out, as the results are always large
# unchanged = dd.unchanged()
# print("- Unchanged monsters: %d" % len(unchanged))
# for monsterID in unchanged:
# print(" - %s,%s" % (monsterID,
# new_monsters[monsterID]["name"]))
def move():
"""Move cache files."""
old = Path(config.DATA_ITEMS_PATH / "items-cache-data.json")
new = Path(config.DATA_ITEMS_PATH / "items-cache-data-new.json")
old.unlink()
new.rename(old)
old = Path(config.DATA_MONSTERS_PATH / "monsters-cache-data.json")
new = Path(config.DATA_MONSTERS_PATH / "monsters-cache-data-new.json")
old.unlink()
new.rename(old)
if __name__ == "__main__":
print("Determining item changes using items-cache-data.json files...")
items()
print("Determining monster changes using monsters-cache-data.json files...")
monsters()
print("Overwrite old files")
move()