Skip to content

Instantly share code, notes, and snippets.

@Xinayder
Last active July 28, 2019 04:38
Show Gist options
  • Save Xinayder/6ce4b15017873a3942336f8399306797 to your computer and use it in GitHub Desktop.
Save Xinayder/6ce4b15017873a3942336f8399306797 to your computer and use it in GitHub Desktop.
Converts offline player.dat files to online player.dat files
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()
@Xinayder
Copy link
Author

Requires pip install nbt and works only on Python 3.6.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment