Last active
July 28, 2019 04:38
-
-
Save Xinayder/6ce4b15017873a3942336f8399306797 to your computer and use it in GitHub Desktop.
Converts offline player.dat files to online player.dat files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import nbt | |
import uuid | |
import requests | |
import json | |
import os | |
import argparse | |
def convert_playerdata(world, from_mode): | |
# Retrieve an online UUID from player name | |
# player_names: list of string | |
def get_online_uuid(player_names): | |
mojang_api_url = "https://api.mojang.com/profiles/minecraft" | |
req = requests.post(mojang_api_url, json=player_names) | |
response = req.json() | |
result = dict() | |
for player in response: | |
if not player['name'] in result: | |
result[player['name']] = player['id'] | |
return result | |
# Retrieve the offline UUID from a player name | |
# player_name: string | |
def get_offline_uuid(player_name): | |
class OFFLINE_NAMESPACE: | |
bytes = b'OfflinePlayer:' | |
return str(uuid.uuid3(OFFLINE_NAMESPACE, player_name)) | |
# Returns the last known name of a player based on its offline UUID | |
# offline_uuid: uuid3 | |
def get_last_player_name(offline_uuid): | |
nbt_file = nbt.nbt.NBTFile(str(offline_uuid) + ".dat", "rb") | |
if 'bukkit' in nbt_file: | |
if 'lastKnownName' in nbt_file['bukkit']: | |
return str(nbt_file['bukkit']['lastKnownName']) | |
return None | |
# Returns the list of player UUIDs in a world | |
def get_players_from_world(): | |
if os.path.exists('playerdata') and os.path.isdir('playerdata'): | |
players = list() | |
for player in os.scandir('playerdata'): | |
player_uuid = uuid.UUID(player.name[0:36]) | |
player_uuid_str = str(player_uuid) | |
if not player_uuid_str in players: | |
# Offline mode player.dat uses UUID v3 | |
# online mode uses UUID v4 | |
if from_mode == 'offline': | |
if player_uuid.version == 3: | |
players.append(player_uuid_str[0:36]) | |
elif from_mode == 'online': | |
if player_uuid.version == 4: | |
players.append(player_uuid_str[0:36]) | |
return players | |
return None | |
os.chdir(world) | |
old_player_uuids = get_players_from_world() | |
players = dict() | |
os.chdir('playerdata') | |
# Get the last known name TAGCompound from Bukkit | |
for old_uuid in old_player_uuids: | |
player_name = get_last_player_name(old_uuid) | |
if player_name != None and player_name not in players: | |
players[player_name] = {'old': old_uuid} | |
if from_mode == 'online': | |
for player in players: | |
if not 'new' in player: | |
players[player]['new'] = get_offline_uuid(player) | |
else: | |
online_uuids = get_online_uuid(list(players.keys())) | |
for player, online_uuid in online_uuids.items(): | |
if player in players and not 'new' in players[player]: | |
players[player]['new'] = str(uuid.UUID(online_uuid)) | |
# Copy the old UUID to the new UUID | |
for player in players.keys(): | |
if 'old' in players[player] and 'new' in players[player]: | |
src_file = players[player]['old'] + '.dat' | |
dst_file = players[player]['new'] + '.dat' | |
import shutil | |
shutil.copy(src_file, dst_file) | |
print(f'Converted player data from "{player}":') | |
print(f'\tCopied "{src_file}" to "{dst_file}"') | |
def do_the_magic(server_location, from_mode): | |
overwold_path = os.path.join(server_location, 'world') | |
nether_path = os.path.join(server_location, 'world_nether') | |
ender_path = os.path.join(server_location, 'world_the_end') | |
if not os.path.exists(os.path.join(server_location, 'bukkit.yml')): | |
print("This script only works with servers based on Spigot.") | |
return | |
if not os.access(overwold_path, os.W_OK): | |
print("You don't have permission to write to the server folder. Maybe try running the script as root?") | |
return | |
convert_playerdata(overwold_path, from_mode) | |
def main(): | |
parser = argparse.ArgumentParser(description='Convert Minecraft player.dat files to offline or online mode.') | |
parser.add_argument('--server-root', required=False, dest='server_root', metavar='[location]', type=str, help='specify a server location to convert player.dat files', default='.') | |
parser.add_argument('--convert-from', required=False, dest='convert_from', metavar='[offline|online]', type=str, help='select to convert from online to offline or vice versa', default='offline') | |
args = parser.parse_args() | |
do_the_magic(args.server_root, args.convert_from) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Requires
pip install nbt
and works only on Python 3.6.