Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enabling online-mode will not preserve player data, achivements or quest advancements #2

Open
Rykee opened this issue Nov 10, 2024 · 0 comments

Comments

@Rykee
Copy link

Rykee commented Nov 10, 2024

Heyo!

When updating the server.properties to turn on online-mode, after the server was being used in offline mode, the quest progress, teams and player data will be reset for the players. This is caused by different UUID generation used by Mojang for online/offline mode.

The following folders/files contain UUID information that should be updated(as far as I know):

  • world/advancements - list of .json files
  • world/betterquesting/QuestingParties.json
  • world/betterquesting/QuestProgress - list of .json files the files themselves reference the UUID as well
  • world/betterquesting/NameCache.json
  • world/playerdata - list of .dat files

As the offline UUID itself does not contain information about the username the server/usernamecache.json can be used to resolve them.

https://api.mojang.com/users/profiles/minecraft/{username} request can be used to retrieve a user's online UUID, this returns the short form UUID without dashes so a conversion is needed: str(uuid.UUID(response.json()['id']))

I was experimenting with implementing this myself, havent't really coded in python so reader discretion is advised. 😄
❗ This does not currently contains replacing the UUID's in the QuestProgress files
I tested it and aside from the quest progress other stuff worked.
Edit: Edited 1 questProgress json file manually, and it fixed quest progress as well.

import os
import requests
import json
import uuid

# Paths to player data and other relevant folders
world_path = "/path/to/your/server/world"
usernamecache_path = "/path/to/your/server/usernamecache.json"

# Directories where files need renaming
directories_to_update = {
    "advancements": ".json",
    "betterquesting/QuestProgress": ".json",
    "playerdata": ".dat"
}

#Some delay between request could be needed, not sure about Mojang API rate limits
def get_online_uuid(username):
    """Fetch the Mojang online UUID for a given username."""
    url = f"https://api.mojang.com/users/profiles/minecraft/{username}"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        return str(uuid.UUID(data['id']))
    else:
        print(f"Could not fetch UUID for {username}")
        return None

def create_uuid_map():
    """Create a map of old UUIDs to their corresponding username and online UUID."""
    uuid_map = {}
    with open(usernamecache_path, "r") as f:
        username_cache = json.load(f)
    
    for offline_uuid, username in username_cache.items():
        online_uuid = get_online_uuid(username)
        if online_uuid:
            uuid_map[offline_uuid] = {
                'username': username,
                'online_uuid': online_uuid
            }
        else:
            print(f"Skipping {username} due to failed UUID fetch.")
    
    return uuid_map

def rename_files(uuid_map):
    """Rename the files based on the UUID map."""
    for offline_uuid, data in uuid_map.items():
        online_uuid = data['online_uuid']
        username = data['username']

        # Rename files in specified directories
        for folder, extension in directories_to_update.items():
            old_file = os.path.join(world_path, folder, f"{offline_uuid}{extension}")
            new_file = os.path.join(world_path, folder, f"{online_uuid}{extension}")
            if os.path.exists(old_file):
                os.replace(old_file, new_file)
                print(f"Renamed {old_file} to {new_file}")
            else:
                print(f"No file found for offline UUID {offline_uuid} in {folder}")

    # Delete the username cache file after processing
    os.remove(usernamecache_path)
    print(f"Deleted {usernamecache_path}")

def update_questing_parties(uuid_map):
    """Directly replace offline UUIDs with online UUIDs in QuestingParties.json."""
    questing_file = os.path.join(world_path, "betterquesting", "QuestingParties.json")
    
    if os.path.exists(questing_file):
        with open(questing_file, "r") as f:
            questing_data = f.read()  # Read the file as text
        
        # Replace all instances of the offline UUIDs with the corresponding online UUIDs
        for offline_uuid, data in uuid_map.items():
            online_uuid = data['online_uuid']
            questing_data = questing_data.replace(offline_uuid, online_uuid)
        
        # Write the modified data back to the file
        with open(questing_file, "w") as f:
            f.write(questing_data)
        print(f"Updated UUIDs in {questing_file}")
    else:
        print(f"{questing_file} not found.")

# Run the process
uuid_map = create_uuid_map()  # Step 1: Create the UUID map
rename_files(uuid_map)  # Step 2: Rename files
update_questing_parties(uuid_map) # Step 3: Update QuestingParties.json
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant