playerInspect.py Python3 refactor
This commit is contained in:
@@ -2,19 +2,19 @@
|
|||||||
Very basic player.dat inspection script
|
Very basic player.dat inspection script
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import argparse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
# incantation to be able to import overviewer_core
|
# incantation to be able to import overviewer_core
|
||||||
if not hasattr(sys, "frozen"):
|
if not hasattr(sys, "frozen"):
|
||||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.split(__file__)[0], '..')))
|
sys.path.insert(0, os.path.abspath(os.path.join(os.path.split(__file__)[0], '..')))
|
||||||
|
|
||||||
|
|
||||||
from overviewer_core.nbt import load
|
from overviewer_core.nbt import load
|
||||||
from overviewer_core import items
|
from overviewer_core import items
|
||||||
|
|
||||||
|
|
||||||
def print_player(data, sub_entry=False):
|
def print_player(data, sub_entry=False):
|
||||||
indent = ""
|
indent = ""
|
||||||
if sub_entry:
|
if sub_entry:
|
||||||
@@ -36,26 +36,58 @@ def print_player(data, sub_entry=False):
|
|||||||
print(" %-3d %s" % (item['Count'], items.id2item(item['id'])))
|
print(" %-3d %s" % (item['Count'], items.id2item(item['id'])))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
def find_all_player_files(dir_path):
|
||||||
if len(sys.argv) < 2 or len(sys.argv) > 3:
|
for player_file in dir_path.iterdir():
|
||||||
print("Usage: {} <Player .dat or directory> [selected player]"
|
player = player_file.stem
|
||||||
.format(sys.argv[0]), file=sys.stderr)
|
yield player_file, player
|
||||||
sys.exit(1)
|
|
||||||
print("Inspecting %s" % sys.argv[1])
|
|
||||||
|
|
||||||
if os.path.isdir(sys.argv[1]):
|
|
||||||
directory = sys.argv[1]
|
def find_player_file(dir_path, selected_player):
|
||||||
if len(sys.argv) > 2:
|
for player_file, player in find_all_player_files(dir_path):
|
||||||
selected_player = sys.argv[2]
|
if selected_player == player:
|
||||||
else:
|
return player_file, player
|
||||||
selected_player = None
|
raise FileNotFoundError()
|
||||||
for player_file in os.listdir(directory):
|
|
||||||
player = player_file.split(".")[0]
|
|
||||||
if selected_player in [None, player]:
|
def load_and_output_player(player_file_path, player, sub_entry=False):
|
||||||
|
with player_file_path.open('rb') as f:
|
||||||
|
player_data = load(f)[1]
|
||||||
print("")
|
print("")
|
||||||
print(player)
|
print(player)
|
||||||
data = load(os.path.join(directory, player_file))[1]
|
print_player(player_data, sub_entry=sub_entry)
|
||||||
print_player(data, sub_entry=(selected_player is None))
|
|
||||||
else:
|
|
||||||
data = load(sys.argv[1])[1]
|
def dir_or_file(path):
|
||||||
print_player(data)
|
p = Path(path)
|
||||||
|
if not p.is_file() and not p.is_dir():
|
||||||
|
raise argparse.ArgumentTypeError("Not a valid file or directory path")
|
||||||
|
return p
|
||||||
|
|
||||||
|
|
||||||
|
def main(path, selected_player=None):
|
||||||
|
print("Inspecting %s" % args.path)
|
||||||
|
|
||||||
|
if not path.is_dir():
|
||||||
|
load_and_output_player(args.path)
|
||||||
|
return
|
||||||
|
|
||||||
|
if selected_player is None:
|
||||||
|
for player_file, player in find_all_player_files(args.path):
|
||||||
|
load_and_output_player(player_file, player)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
player_file, player = find_player_file(args.path, args.selected_player)
|
||||||
|
load_and_output_player(player_file, player, sub_entry=True)
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("No %s.dat in %s" % (args.selected_player, args.path))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
parser.add_argument('path', metavar='<Player.dat or directory>', type=dir_or_file)
|
||||||
|
parser.add_argument('selected_player', nargs='?', default=None)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
main(args.path, selected_player=args.selected_player)
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from test_tileset import TilesetTest
|
|||||||
from test_cache import TestLRU
|
from test_cache import TestLRU
|
||||||
from test_contributors import TestContributors
|
from test_contributors import TestContributors
|
||||||
from test_cyrillic_convert import TestCyrillicConvert
|
from test_cyrillic_convert import TestCyrillicConvert
|
||||||
|
from test_playerInspect import TestPlayerInspect
|
||||||
|
|
||||||
# DISABLE THIS BLOCK TO GET LOG OUTPUT FROM TILESET FOR DEBUGGING
|
# DISABLE THIS BLOCK TO GET LOG OUTPUT FROM TILESET FOR DEBUGGING
|
||||||
if 0:
|
if 0:
|
||||||
|
|||||||
176
test/test_playerInspect.py
Normal file
176
test/test_playerInspect.py
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
import unittest
|
||||||
|
from io import StringIO
|
||||||
|
from pathlib import Path
|
||||||
|
from textwrap import dedent
|
||||||
|
from unittest.mock import patch, MagicMock
|
||||||
|
|
||||||
|
import contrib.playerInspect as player_inspect
|
||||||
|
|
||||||
|
|
||||||
|
class TestPlayerInspect(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.player_data = {
|
||||||
|
'AbsorptionAmount': 0.0,
|
||||||
|
'Air': 300,
|
||||||
|
'Attributes': [
|
||||||
|
{'Base': 20.0, 'Name': 'generic.maxHealth'},
|
||||||
|
{'Base': 0.0, 'Name': 'generic.knockbackResistance'},
|
||||||
|
{'Base': 0.10000000149011612, 'Name': 'generic.movementSpeed'},
|
||||||
|
{'Base': 0.0, 'Name': 'generic.armor'},
|
||||||
|
{'Base': 0.0, 'Name': 'generic.armorToughness'},
|
||||||
|
{'Base': 1.0, 'Name': 'generic.attackDamage'},
|
||||||
|
{'Base': 4.0, 'Name': 'generic.attackSpeed'},
|
||||||
|
{'Base': 0.0, 'Name': 'generic.luck'}
|
||||||
|
],
|
||||||
|
'DataVersion': 1631,
|
||||||
|
'DeathTime': 0,
|
||||||
|
'Dimension': 0,
|
||||||
|
'EnderItems': [],
|
||||||
|
'FallDistance': 0.0,
|
||||||
|
'FallFlying': 0,
|
||||||
|
'Fire': -20,
|
||||||
|
'Health': 20.0,
|
||||||
|
'HurtByTimestamp': 0,
|
||||||
|
'HurtTime': 0,
|
||||||
|
'Inventory': [{'Count': 1, 'Slot': -106, 'id': 'minecraft:sign'}],
|
||||||
|
'Invulnerable': 0,
|
||||||
|
'Motion': [0.0, -0.0784000015258789, 0.0],
|
||||||
|
'OnGround': 1,
|
||||||
|
'PortalCooldown': 0,
|
||||||
|
'Pos': [-96.11859857363737, 70.0, -44.17768261916891],
|
||||||
|
'Rotation': [-72.00011444091797, 38.250030517578125],
|
||||||
|
'Score': 0,
|
||||||
|
'SelectedItemSlot': 0,
|
||||||
|
'SleepTimer': 0,
|
||||||
|
'Sleeping': 0,
|
||||||
|
"SpawnX": 10,
|
||||||
|
"SpawnY": 52,
|
||||||
|
"SpawnZ": 10,
|
||||||
|
'UUIDLeast': -7312926203658200544,
|
||||||
|
'UUIDMost': 6651100054519957107,
|
||||||
|
'XpLevel': 0,
|
||||||
|
'XpP': 0.0,
|
||||||
|
'XpSeed': 0,
|
||||||
|
'XpTotal': 0,
|
||||||
|
'abilities': {
|
||||||
|
'flySpeed': 0.05000000074505806,
|
||||||
|
'flying': 0,
|
||||||
|
'instabuild': 1,
|
||||||
|
'invulnerable': 1,
|
||||||
|
'mayBuild': 1,
|
||||||
|
'mayfly': 1,
|
||||||
|
'walkSpeed': 0.10000000149011612
|
||||||
|
},
|
||||||
|
'foodExhaustionLevel': 0.0,
|
||||||
|
'foodLevel': 20,
|
||||||
|
'foodSaturationLevel': 5.0,
|
||||||
|
'foodTickTimer': 0,
|
||||||
|
'playerGameType': 1,
|
||||||
|
'recipeBook': {
|
||||||
|
'isFilteringCraftable': 0,
|
||||||
|
'isFurnaceFilteringCraftable': 0,
|
||||||
|
'isFurnaceGuiOpen': 0,
|
||||||
|
'isGuiOpen': 0,
|
||||||
|
'recipes': [],
|
||||||
|
'toBeDisplayed': []
|
||||||
|
},
|
||||||
|
'seenCredits': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_print_player(self, mock_stdout):
|
||||||
|
expected = "\n".join([
|
||||||
|
"Position:\t-96, 70, -44\t(dim: 0)",
|
||||||
|
"Spawn:\t\t10, 52, 10",
|
||||||
|
"Health:\t20\tLevel:\t\t0\t\tGameType:\t1",
|
||||||
|
"Food:\t20\tTotal XP:\t0",
|
||||||
|
"Inventory: 1 items",
|
||||||
|
" 1 minecraft:sign\n"])
|
||||||
|
|
||||||
|
player_inspect.print_player(self.player_data)
|
||||||
|
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected)
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_print_player_no_spawn(self, mock_stdout):
|
||||||
|
expected = "\n".join([
|
||||||
|
"Position:\t-96, 70, -44\t(dim: 0)",
|
||||||
|
"Health:\t20\tLevel:\t\t0\t\tGameType:\t1",
|
||||||
|
"Food:\t20\tTotal XP:\t0",
|
||||||
|
"Inventory: 1 items",
|
||||||
|
" 1 minecraft:sign\n"])
|
||||||
|
|
||||||
|
player_data = {
|
||||||
|
k: v for k, v in self.player_data.items()
|
||||||
|
if k not in("SpawnX", "SpawnY", "SpawnZ")
|
||||||
|
}
|
||||||
|
player_inspect.print_player(player_data)
|
||||||
|
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected)
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_print_player_sub_entry(self, mock_stdout):
|
||||||
|
expected = "\n".join([
|
||||||
|
"\tPosition:\t-96, 70, -44\t(dim: 0)",
|
||||||
|
"\tSpawn:\t\t10, 52, 10",
|
||||||
|
"\tHealth:\t20\tLevel:\t\t0\t\tGameType:\t1",
|
||||||
|
"\tFood:\t20\tTotal XP:\t0",
|
||||||
|
"\tInventory: 1 items\n"])
|
||||||
|
|
||||||
|
player_inspect.print_player(self.player_data, sub_entry=True)
|
||||||
|
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected)
|
||||||
|
|
||||||
|
@patch('sys.stdout', new_callable=StringIO)
|
||||||
|
def test_print_player_sub_entry_no_spawn(self, mock_stdout):
|
||||||
|
expected = "\n".join([
|
||||||
|
"\tPosition:\t-96, 70, -44\t(dim: 0)",
|
||||||
|
"\tHealth:\t20\tLevel:\t\t0\t\tGameType:\t1",
|
||||||
|
"\tFood:\t20\tTotal XP:\t0",
|
||||||
|
"\tInventory: 1 items\n"])
|
||||||
|
|
||||||
|
player_data = {
|
||||||
|
k: v for k, v in self.player_data.items()
|
||||||
|
if k not in("SpawnX", "SpawnY", "SpawnZ")
|
||||||
|
}
|
||||||
|
player_inspect.print_player(player_data, sub_entry=True)
|
||||||
|
|
||||||
|
self.assertEqual(mock_stdout.getvalue(), expected)
|
||||||
|
|
||||||
|
def test_find_all_player_files(self):
|
||||||
|
dir_path = MagicMock(Path)
|
||||||
|
files = [Path('def0492d-0fe9-43ff-a3d5-8c3fc9160c94.dat'),
|
||||||
|
Path('074c808a-1f04-4bdd-8385-bd74601210a1.dat'),
|
||||||
|
Path('104e149d-a802-4a27-ac8f-ceab5279087c.dat')]
|
||||||
|
dir_path.iterdir.return_value = (f for f in files)
|
||||||
|
|
||||||
|
expected = [(Path('def0492d-0fe9-43ff-a3d5-8c3fc9160c94.dat'),
|
||||||
|
'def0492d-0fe9-43ff-a3d5-8c3fc9160c94'),
|
||||||
|
(Path('074c808a-1f04-4bdd-8385-bd74601210a1.dat'),
|
||||||
|
'074c808a-1f04-4bdd-8385-bd74601210a1'),
|
||||||
|
(Path('104e149d-a802-4a27-ac8f-ceab5279087c.dat'),
|
||||||
|
'104e149d-a802-4a27-ac8f-ceab5279087c')]
|
||||||
|
result = player_inspect.find_all_player_files(dir_path)
|
||||||
|
self.assertListEqual(list(result), expected)
|
||||||
|
|
||||||
|
def test_find_player_file(self):
|
||||||
|
dir_path = MagicMock(Path)
|
||||||
|
files = [Path('def0492d-0fe9-43ff-a3d5-8c3fc9160c94.dat'),
|
||||||
|
Path('074c808a-1f04-4bdd-8385-bd74601210a1.dat'),
|
||||||
|
Path('104e149d-a802-4a27-ac8f-ceab5279087c.dat')]
|
||||||
|
dir_path.iterdir.return_value = (f for f in files)
|
||||||
|
|
||||||
|
expected = (Path('104e149d-a802-4a27-ac8f-ceab5279087c.dat'),
|
||||||
|
'104e149d-a802-4a27-ac8f-ceab5279087c')
|
||||||
|
result = player_inspect.find_player_file(
|
||||||
|
dir_path, selected_player='104e149d-a802-4a27-ac8f-ceab5279087c')
|
||||||
|
self.assertEqual(result, expected)
|
||||||
|
|
||||||
|
def test_find_player_file_raises_when_selected_player_not_found(self):
|
||||||
|
dir_path = MagicMock(Path)
|
||||||
|
files = [Path('def0492d-0fe9-43ff-a3d5-8c3fc9160c94.dat'),
|
||||||
|
Path('104e149d-a802-4a27-ac8f-ceab5279087c.dat')]
|
||||||
|
dir_path.iterdir.return_value = (f for f in files)
|
||||||
|
|
||||||
|
with self.assertRaises(FileNotFoundError):
|
||||||
|
player_inspect.find_player_file(dir_path, selected_player='NON_EXISTENT_UUID')
|
||||||
Reference in New Issue
Block a user