2025-01-29 13:20:04 -05:00
|
|
|
package kamkeel.npcs.controllers;
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-08-27 16:27:40 -04:00
|
|
|
import kamkeel.npcs.controllers.AttributeController;
|
2025-07-23 14:22:52 -04:00
|
|
|
import kamkeel.npcs.controllers.data.profile.CNPCData;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.EnumProfileOperation;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.IProfileData;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.Profile;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.ProfileInfoEntry;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.ProfileOperation;
|
|
|
|
|
import kamkeel.npcs.controllers.data.profile.Slot;
|
2025-01-23 16:10:01 -05:00
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
|
|
|
import net.minecraft.nbt.CompressedStreamTools;
|
|
|
|
|
import net.minecraft.nbt.NBTTagCompound;
|
2025-07-23 14:22:52 -04:00
|
|
|
import noppes.npcs.CustomNpcs;
|
|
|
|
|
import noppes.npcs.CustomNpcsPermissions;
|
|
|
|
|
import noppes.npcs.EventHooks;
|
|
|
|
|
import noppes.npcs.LogWriter;
|
|
|
|
|
import noppes.npcs.NoppesUtilServer;
|
2025-02-20 21:39:02 -05:00
|
|
|
import noppes.npcs.api.entity.IPlayer;
|
|
|
|
|
import noppes.npcs.api.handler.IPlayerData;
|
2025-02-21 17:30:57 -05:00
|
|
|
import noppes.npcs.api.handler.IProfileHandler;
|
2025-03-13 17:14:45 -04:00
|
|
|
import noppes.npcs.api.handler.data.IProfile;
|
2025-02-21 17:30:57 -05:00
|
|
|
import noppes.npcs.api.handler.data.ISlot;
|
2025-02-18 22:22:40 -05:00
|
|
|
import noppes.npcs.config.ConfigMain;
|
2025-02-21 06:19:24 -05:00
|
|
|
import noppes.npcs.controllers.QuestController;
|
2025-03-11 17:16:54 -04:00
|
|
|
import noppes.npcs.controllers.ScriptController;
|
2025-02-18 06:25:09 -05:00
|
|
|
import noppes.npcs.controllers.data.PlayerData;
|
2025-03-11 17:16:54 -04:00
|
|
|
import noppes.npcs.controllers.data.PlayerDataScript;
|
2025-02-21 06:19:24 -05:00
|
|
|
import noppes.npcs.controllers.data.PlayerQuestData;
|
2025-03-11 17:16:54 -04:00
|
|
|
import noppes.npcs.scripted.NpcAPI;
|
2025-01-23 16:10:01 -05:00
|
|
|
import noppes.npcs.util.CustomNPCsThreader;
|
|
|
|
|
import noppes.npcs.util.NBTJsonUtil;
|
2025-02-20 21:40:39 -05:00
|
|
|
|
2025-07-23 14:22:52 -04:00
|
|
|
import java.io.BufferedReader;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.FileInputStream;
|
|
|
|
|
import java.io.FileOutputStream;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.io.InputStreamReader;
|
2025-02-18 06:25:09 -05:00
|
|
|
import java.net.HttpURLConnection;
|
|
|
|
|
import java.net.URL;
|
2025-02-18 22:22:40 -05:00
|
|
|
import java.text.SimpleDateFormat;
|
2025-07-23 14:22:52 -04:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Comparator;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.UUID;
|
2025-02-20 21:40:39 -05:00
|
|
|
|
2025-07-23 14:22:52 -04:00
|
|
|
import static noppes.npcs.CustomNpcsPermissions.PROFILE_MAX;
|
|
|
|
|
import static noppes.npcs.CustomNpcsPermissions.PROFILE_REGION_BYPASS;
|
|
|
|
|
import static noppes.npcs.CustomNpcsPermissions.hasCustomPermission;
|
2025-02-19 18:15:05 -05:00
|
|
|
|
2025-02-21 17:30:57 -05:00
|
|
|
public class ProfileController implements IProfileHandler {
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
// Message constants
|
2025-03-13 17:14:45 -04:00
|
|
|
private static final String MSG_PLAYER_NOT_FOUND = "Player not found.";
|
|
|
|
|
private static final String MSG_PROFILE_LOCKED_CLONE = "Profile is locked; cannot clone slot.";
|
|
|
|
|
private static final String MSG_SOURCE_SLOT_NOT_EXIST = "Source slot does not exist.";
|
|
|
|
|
private static final String MSG_CANNOT_CLONE_CURRENT = "Cannot clone to the current active slot.";
|
|
|
|
|
private static final String MSG_INVALID_DEST_SLOT = "Invalid destination slot id.";
|
|
|
|
|
private static final String MSG_CLONE_SUCCESS = "Slot cloned successfully.";
|
|
|
|
|
private static final String MSG_PROFILE_LOCKED_REMOVE = "Profile is locked; cannot remove slot.";
|
|
|
|
|
private static final String MSG_CANNOT_REMOVE_ACTIVE = "Cannot remove the currently active slot.";
|
|
|
|
|
private static final String MSG_SLOT_NOT_EXIST = "Slot does not exist.";
|
|
|
|
|
private static final String MSG_REMOVE_SUCCESS = "Slot removed successfully.";
|
|
|
|
|
private static final String MSG_PROFILE_LOCKED_CREATE = "Profile is locked; cannot create slot.";
|
|
|
|
|
private static final String MSG_MAX_SLOTS_REACHED = "Maximum allowed slots reached.";
|
|
|
|
|
private static final String MSG_NEW_SLOT_CREATED = "New slot created successfully.";
|
|
|
|
|
private static final String MSG_PROFILE_LOCKED_CHANGE = "Profile is locked; cannot change slot.";
|
|
|
|
|
private static final String MSG_SLOT_ALREADY_ACTIVE = "Slot is already active.";
|
|
|
|
|
private static final String MSG_REGION_NOT_ALLOWED = "Profile switching not allowed from your current location.";
|
|
|
|
|
private static final String MSG_CHANGE_SUCCESS = "Slot changed successfully.";
|
|
|
|
|
private static final String MSG_CANCELLED = "Operation cancelled.";
|
2025-02-19 18:15:05 -05:00
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public static Map<String, IProfileData> profileTypes = new HashMap<>();
|
|
|
|
|
public static Map<UUID, Profile> activeProfiles = new HashMap<>();
|
2025-01-23 16:10:01 -05:00
|
|
|
public static String profile_directory = "profiles";
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public static ProfileController Instance;
|
|
|
|
|
|
|
|
|
|
public ProfileController() {
|
|
|
|
|
Instance = this;
|
2025-01-23 16:10:01 -05:00
|
|
|
profileTypes = new HashMap<>();
|
|
|
|
|
activeProfiles = new HashMap<>();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public static boolean registerProfileType(IProfileData type) {
|
|
|
|
|
if (profileTypes.containsKey(type.getTagName()))
|
2025-01-23 16:10:01 -05:00
|
|
|
return false;
|
|
|
|
|
profileTypes.put(type.getTagName(), type);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public static File getProfileDir() {
|
2025-02-18 06:25:09 -05:00
|
|
|
try {
|
2025-01-23 16:10:01 -05:00
|
|
|
File file = new File(CustomNpcs.getWorldSaveDirectory(), profile_directory);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!file.exists())
|
2025-01-23 16:10:01 -05:00
|
|
|
file.mkdir();
|
|
|
|
|
return file;
|
2025-02-18 06:25:09 -05:00
|
|
|
} catch (Exception e) {
|
2025-01-23 16:10:01 -05:00
|
|
|
e.printStackTrace();
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-18 22:22:40 -05:00
|
|
|
public static File getBackupDir() {
|
|
|
|
|
File base = getProfileDir();
|
|
|
|
|
File backup = new File(base, "backup");
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!backup.exists()) {
|
2025-02-18 22:22:40 -05:00
|
|
|
backup.mkdir();
|
|
|
|
|
}
|
|
|
|
|
return backup;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public synchronized void login(EntityPlayer player) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (!ConfigMain.ProfilesEnabled)
|
2025-02-21 18:13:08 -05:00
|
|
|
return;
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
if (player == null)
|
2025-01-23 16:10:01 -05:00
|
|
|
return;
|
|
|
|
|
Profile profile;
|
2025-07-07 05:50:29 -04:00
|
|
|
boolean profileModified = false;
|
2025-02-20 21:39:02 -05:00
|
|
|
if (activeProfiles.containsKey(player.getUniqueID())) {
|
2025-01-23 16:10:01 -05:00
|
|
|
profile = activeProfiles.get(player.getUniqueID());
|
2025-02-21 06:19:24 -05:00
|
|
|
profile.player = player;
|
2025-01-23 16:10:01 -05:00
|
|
|
} else {
|
2025-02-18 06:25:09 -05:00
|
|
|
NBTTagCompound compound = load(player);
|
|
|
|
|
profile = new Profile(player, compound);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.getSlots().isEmpty()) {
|
2025-02-18 22:22:40 -05:00
|
|
|
Slot defaultSlot = new Slot(0, "Default Slot");
|
2025-02-20 21:39:02 -05:00
|
|
|
defaultSlot.setLastLoaded(System.currentTimeMillis());
|
|
|
|
|
profile.getSlots().put(0, defaultSlot);
|
|
|
|
|
profile.currentSlotId = 0;
|
2025-02-18 22:22:40 -05:00
|
|
|
saveSlotData(player);
|
2025-07-07 05:50:29 -04:00
|
|
|
profileModified = true;
|
2025-02-18 22:22:40 -05:00
|
|
|
}
|
2025-06-30 21:57:29 -04:00
|
|
|
if (!profile.getSlots().containsKey(profile.currentSlotId)) {
|
|
|
|
|
profile.currentSlotId = 0;
|
|
|
|
|
}
|
2025-02-21 06:19:24 -05:00
|
|
|
profile.player = player;
|
2025-01-23 16:10:01 -05:00
|
|
|
activeProfiles.put(player.getUniqueID(), profile);
|
2025-02-21 06:19:24 -05:00
|
|
|
verifySlotQuests(profile.player);
|
2025-07-07 05:50:29 -04:00
|
|
|
if (profileModified)
|
|
|
|
|
save(player, profile);
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public synchronized NBTTagCompound load(EntityPlayer player) {
|
2025-01-23 16:10:01 -05:00
|
|
|
File saveDir = getProfileDir();
|
2025-02-18 06:25:09 -05:00
|
|
|
String filename = player.getUniqueID().toString() + ".dat";
|
|
|
|
|
try {
|
|
|
|
|
File file = new File(saveDir, filename);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (file.exists()) {
|
2025-02-18 06:25:09 -05:00
|
|
|
return NBTJsonUtil.loadNBTData(file);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogWriter.error("Error loading profile file: " + filename, e);
|
|
|
|
|
}
|
|
|
|
|
return new NBTTagCompound();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public synchronized NBTTagCompound load(UUID uuid) {
|
2025-02-18 06:25:09 -05:00
|
|
|
File saveDir = getProfileDir();
|
|
|
|
|
String filename = uuid.toString() + ".dat";
|
2025-01-23 16:10:01 -05:00
|
|
|
try {
|
|
|
|
|
File file = new File(saveDir, filename);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (file.exists()) {
|
2025-01-23 16:10:01 -05:00
|
|
|
return NBTJsonUtil.loadNBTData(file);
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogWriter.error("Error loading profile file: " + filename, e);
|
|
|
|
|
}
|
|
|
|
|
return new NBTTagCompound();
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public synchronized void saveOffline(Profile profile, UUID uuid) {
|
2025-02-20 21:39:02 -05:00
|
|
|
profile.setLocked(true);
|
2025-06-30 21:57:29 -04:00
|
|
|
final NBTTagCompound compound = profile.writeToNBT();
|
|
|
|
|
final String filename = uuid.toString() + ".dat";
|
2025-02-20 13:48:40 -05:00
|
|
|
CustomNPCsThreader.customNPCThread.execute(() -> {
|
|
|
|
|
try {
|
|
|
|
|
File saveDir = getProfileDir();
|
|
|
|
|
File fileNew = new File(saveDir, filename + "_new");
|
|
|
|
|
File fileOld = new File(saveDir, filename);
|
|
|
|
|
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (fileOld.exists()) {
|
2025-02-20 13:48:40 -05:00
|
|
|
fileOld.delete();
|
|
|
|
|
}
|
|
|
|
|
fileNew.renameTo(fileOld);
|
|
|
|
|
backupProfile(uuid, compound);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogWriter.except(e);
|
2025-03-13 17:14:45 -04:00
|
|
|
} finally {
|
2025-02-23 22:26:08 -05:00
|
|
|
profile.setLocked(false);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 13:48:40 -05:00
|
|
|
});
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public synchronized void save(EntityPlayer player, Profile profile) {
|
2025-02-20 21:39:02 -05:00
|
|
|
profile.setLocked(true);
|
2025-06-30 21:57:29 -04:00
|
|
|
final NBTTagCompound compound = profile.writeToNBT();
|
|
|
|
|
final String filename = player.getUniqueID() + ".dat";
|
2025-01-23 16:10:01 -05:00
|
|
|
CustomNPCsThreader.customNPCThread.execute(() -> {
|
|
|
|
|
try {
|
|
|
|
|
File saveDir = getProfileDir();
|
2025-02-18 06:25:09 -05:00
|
|
|
File fileNew = new File(saveDir, filename + "_new");
|
|
|
|
|
File fileOld = new File(saveDir, filename);
|
|
|
|
|
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (fileOld.exists()) {
|
2025-02-18 06:25:09 -05:00
|
|
|
fileOld.delete();
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
2025-02-18 06:25:09 -05:00
|
|
|
fileNew.renameTo(fileOld);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (ConfigMain.AllowProfileBackups) {
|
2025-02-18 22:22:40 -05:00
|
|
|
backupProfile(player.getUniqueID(), compound);
|
|
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
} catch (Exception e) {
|
|
|
|
|
LogWriter.except(e);
|
2025-02-18 06:25:09 -05:00
|
|
|
} finally {
|
2025-02-20 21:39:02 -05:00
|
|
|
profile.setLocked(false);
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
private void backupProfile(UUID uuid, NBTTagCompound compound) {
|
2025-02-18 22:22:40 -05:00
|
|
|
try {
|
|
|
|
|
File backupDir = new File(getBackupDir(), uuid.toString());
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!backupDir.exists()) {
|
2025-02-18 22:22:40 -05:00
|
|
|
backupDir.mkdirs();
|
|
|
|
|
}
|
|
|
|
|
String dateStr = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
|
|
|
|
File backupFile = new File(backupDir, dateStr + ".dat");
|
|
|
|
|
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(backupFile));
|
|
|
|
|
File[] backups = backupDir.listFiles((dir, name) -> name.endsWith(".dat"));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (backups != null && backups.length > ConfigMain.ProfileBackupAmount) {
|
2025-02-18 22:22:40 -05:00
|
|
|
Arrays.sort(backups, Comparator.comparingLong(File::lastModified));
|
2025-02-20 21:39:02 -05:00
|
|
|
for (int i = 0; i < backups.length - ConfigMain.ProfileBackupAmount; i++) {
|
2025-02-18 22:22:40 -05:00
|
|
|
backups[i].delete();
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
} catch (Exception e) {
|
2025-02-18 22:22:40 -05:00
|
|
|
LogWriter.except(e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public boolean rollbackProfile(String username, File backupFile) {
|
2025-02-18 22:22:40 -05:00
|
|
|
UUID uuid = getUUIDFromUsername(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (uuid == null)
|
|
|
|
|
return false;
|
2025-02-18 22:22:40 -05:00
|
|
|
try (FileInputStream fis = new FileInputStream(backupFile)) {
|
|
|
|
|
NBTTagCompound compound = CompressedStreamTools.readCompressed(fis);
|
|
|
|
|
File saveDir = getProfileDir();
|
|
|
|
|
File mainFile = new File(saveDir, uuid.toString() + ".dat");
|
|
|
|
|
File fileNew = new File(saveDir, uuid.toString() + "_new");
|
|
|
|
|
CompressedStreamTools.writeCompressed(compound, new FileOutputStream(fileNew));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (mainFile.exists()) {
|
2025-02-18 22:22:40 -05:00
|
|
|
mainFile.delete();
|
|
|
|
|
}
|
|
|
|
|
fileNew.renameTo(mainFile);
|
2025-02-21 07:05:56 -05:00
|
|
|
EntityPlayer player = NoppesUtilServer.getPlayerByName(username);
|
2025-02-18 22:22:40 -05:00
|
|
|
Profile newProfile;
|
2025-02-20 21:39:02 -05:00
|
|
|
if (player != null) {
|
2025-02-18 22:22:40 -05:00
|
|
|
newProfile = new Profile(player, compound);
|
|
|
|
|
activeProfiles.put(uuid, newProfile);
|
|
|
|
|
loadSlotData(player);
|
2025-03-10 18:07:22 -04:00
|
|
|
return true;
|
2025-02-18 22:22:40 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
} catch (Exception e) {
|
2025-02-18 22:22:40 -05:00
|
|
|
LogWriter.except(e);
|
|
|
|
|
}
|
2025-03-10 18:07:22 -04:00
|
|
|
return false;
|
2025-02-18 22:22:40 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public synchronized void logout(EntityPlayer player) {
|
2025-08-27 16:27:40 -04:00
|
|
|
if (player != null && activeProfiles.containsKey(player.getUniqueID())) {
|
|
|
|
|
saveSlotData(player);
|
|
|
|
|
Profile profile = activeProfiles.get(player.getUniqueID());
|
|
|
|
|
save(player, profile);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public Profile getProfile(EntityPlayer player) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (player == null)
|
|
|
|
|
return null;
|
|
|
|
|
if (!activeProfiles.containsKey(player.getUniqueID()))
|
2025-02-18 06:25:09 -05:00
|
|
|
login(player);
|
|
|
|
|
return activeProfiles.get(player.getUniqueID());
|
|
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public Profile getProfile(UUID uuid) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (activeProfiles.containsKey(uuid))
|
2025-02-18 06:25:09 -05:00
|
|
|
return activeProfiles.get(uuid);
|
|
|
|
|
NBTTagCompound compound = load(uuid);
|
|
|
|
|
return new Profile(null, compound);
|
|
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public Profile getProfile(String username) {
|
2025-02-21 07:05:56 -05:00
|
|
|
EntityPlayer player = NoppesUtilServer.getPlayerByName(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (player != null) {
|
2025-02-18 06:25:09 -05:00
|
|
|
return getProfile(player);
|
|
|
|
|
} else {
|
|
|
|
|
UUID uuid = getUUIDFromUsername(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (uuid == null)
|
|
|
|
|
return null;
|
2025-02-18 06:25:09 -05:00
|
|
|
return getProfile(uuid);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public UUID getUUIDFromUsername(String username) {
|
2025-02-18 06:25:09 -05:00
|
|
|
try {
|
|
|
|
|
URL url = new URL("https://api.mojang.com/users/profiles/minecraft/" + username);
|
|
|
|
|
HttpURLConnection con = (HttpURLConnection) url.openConnection();
|
|
|
|
|
con.setRequestMethod("GET");
|
|
|
|
|
con.setConnectTimeout(5000);
|
|
|
|
|
con.setReadTimeout(5000);
|
|
|
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
|
|
|
|
StringBuilder temp = new StringBuilder();
|
|
|
|
|
String line;
|
2025-02-20 21:39:02 -05:00
|
|
|
while ((line = in.readLine()) != null) {
|
2025-02-18 06:25:09 -05:00
|
|
|
temp.append(line);
|
|
|
|
|
}
|
|
|
|
|
in.close();
|
|
|
|
|
con.disconnect();
|
|
|
|
|
String response = temp.toString();
|
2025-02-20 21:39:02 -05:00
|
|
|
if (response.contains("\"id\"")) {
|
2025-02-18 06:25:09 -05:00
|
|
|
int idIndex = response.indexOf("\"id\"");
|
|
|
|
|
int colonIndex = response.indexOf(":", idIndex);
|
|
|
|
|
int quoteStart = response.indexOf("\"", colonIndex);
|
|
|
|
|
int quoteEnd = response.indexOf("\"", quoteStart + 1);
|
|
|
|
|
String idString = response.substring(quoteStart + 1, quoteEnd);
|
|
|
|
|
idString = idString.replaceFirst(
|
|
|
|
|
"(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}+)",
|
|
|
|
|
"$1-$2-$3-$4-$5"
|
|
|
|
|
);
|
|
|
|
|
return UUID.fromString(idString);
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
LogWriter.error("Error retrieving UUID for " + username, e);
|
|
|
|
|
}
|
|
|
|
|
return null;
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
private int getNextAvailableTempSlot(Profile profile) {
|
2025-02-18 06:25:09 -05:00
|
|
|
int id = -1;
|
2025-02-20 21:39:02 -05:00
|
|
|
while (profile.getSlots().containsKey(id)) {
|
2025-02-18 06:25:09 -05:00
|
|
|
id--;
|
|
|
|
|
}
|
|
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
private ProfileOperation cloneSlotInternal(Profile profile, int sourceSlotId, int destinationSlotId, boolean temporary) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.isLocked()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CLONE);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.player != null) {
|
2025-02-18 20:05:55 -05:00
|
|
|
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
|
|
|
|
|
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
|
2025-02-20 21:39:02 -05:00
|
|
|
for (IProfileData pd : dataList) {
|
2025-02-19 18:15:05 -05:00
|
|
|
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
|
|
|
|
|
return pd.verifySwitch(profile.player);
|
2025-02-18 20:05:55 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!profile.getSlots().containsKey(sourceSlotId)) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_SOURCE_SLOT_NOT_EXIST);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (destinationSlotId == profile.getCurrentSlotId()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_CANNOT_CLONE_CURRENT);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (temporary) {
|
2025-02-18 06:25:09 -05:00
|
|
|
destinationSlotId = getNextAvailableTempSlot(profile);
|
|
|
|
|
} else {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (destinationSlotId <= 0) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_INVALID_DEST_SLOT);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
ISlot sourceSlot = profile.getSlots().get(sourceSlotId);
|
|
|
|
|
Map<String, NBTTagCompound> newComponents = new HashMap<>();
|
|
|
|
|
for (String key : sourceSlot.getComponents().keySet()) {
|
2025-02-20 21:44:15 -05:00
|
|
|
newComponents.put(key, (NBTTagCompound) sourceSlot.getComponentData(key).copy());
|
2025-02-20 21:39:02 -05:00
|
|
|
}
|
|
|
|
|
Slot clonedSlot = new Slot(destinationSlotId, "Cloned Slot " + destinationSlotId, System.currentTimeMillis(), temporary, newComponents);
|
|
|
|
|
profile.getSlots().put(destinationSlotId, clonedSlot);
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.success(MSG_CLONE_SUCCESS);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
private ProfileOperation removeSlotInternal(Profile profile, int slotId) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.isLocked()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.locked(MSG_PROFILE_LOCKED_REMOVE);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (slotId == profile.getCurrentSlotId()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_CANNOT_REMOVE_ACTIVE);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!profile.getSlots().containsKey(slotId)) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_SLOT_NOT_EXIST);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-03-11 17:16:54 -04:00
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile.player != null) {
|
2025-04-09 01:55:34 -04:00
|
|
|
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player);
|
2025-03-11 17:16:54 -04:00
|
|
|
IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (EventHooks.onProfileRemove(handler, scriptPlayer, profile, slotId, false))
|
2025-03-11 17:16:54 -04:00
|
|
|
return ProfileOperation.error(MSG_CANCELLED);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
profile.getSlots().remove(slotId);
|
2025-03-11 17:16:54 -04:00
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile.player != null) {
|
2025-04-09 01:55:34 -04:00
|
|
|
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player);
|
2025-03-11 17:16:54 -04:00
|
|
|
IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player);
|
2025-03-13 17:14:45 -04:00
|
|
|
EventHooks.onProfileRemove(handler, scriptPlayer, profile, slotId, true);
|
2025-03-11 17:16:54 -04:00
|
|
|
}
|
|
|
|
|
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.success(MSG_REMOVE_SUCCESS);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation createSlotInternal(Profile profile) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.isLocked()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CREATE);
|
2025-02-19 16:27:27 -05:00
|
|
|
}
|
|
|
|
|
int newSlotId = 0;
|
2025-02-20 21:39:02 -05:00
|
|
|
while (profile.getSlots().containsKey(newSlotId)) {
|
2025-02-19 16:27:27 -05:00
|
|
|
newSlotId++;
|
|
|
|
|
}
|
|
|
|
|
if (!allowSlotPermission(profile.player)) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_MAX_SLOTS_REACHED);
|
2025-02-19 16:27:27 -05:00
|
|
|
}
|
|
|
|
|
if (profile.player != null) {
|
|
|
|
|
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
|
|
|
|
|
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
|
|
|
|
|
for (IProfileData pd : dataList) {
|
2025-02-19 18:15:05 -05:00
|
|
|
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
|
|
|
|
|
return pd.verifySwitch(profile.player);
|
2025-02-19 16:27:27 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-11 17:16:54 -04:00
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile.player != null) {
|
2025-04-09 01:55:34 -04:00
|
|
|
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player);
|
2025-03-11 17:16:54 -04:00
|
|
|
IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (EventHooks.onProfileCreate(handler, scriptPlayer, profile, newSlotId, false))
|
2025-03-11 17:16:54 -04:00
|
|
|
return ProfileOperation.error(MSG_CANCELLED);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-19 16:27:27 -05:00
|
|
|
Slot newSlot = new Slot(newSlotId, "Slot " + newSlotId);
|
2025-02-20 21:39:02 -05:00
|
|
|
newSlot.setLastLoaded(System.currentTimeMillis());
|
|
|
|
|
profile.getSlots().put(newSlotId, newSlot);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile.player != null) {
|
2025-04-09 01:55:34 -04:00
|
|
|
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player);
|
2025-02-21 17:23:51 -05:00
|
|
|
verifySlotQuests(profile.player);
|
|
|
|
|
save(profile.player, profile);
|
2025-03-11 17:16:54 -04:00
|
|
|
|
|
|
|
|
IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player);
|
2025-03-13 17:14:45 -04:00
|
|
|
EventHooks.onProfileCreate(handler, scriptPlayer, profile, newSlotId, true);
|
2025-02-21 17:23:51 -05:00
|
|
|
}
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.success(MSG_NEW_SLOT_CREATED);
|
2025-02-19 16:27:27 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
private ProfileOperation changeSlotInternal(Profile profile, int newSlotId) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.isLocked()) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.locked(MSG_PROFILE_LOCKED_CHANGE);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.getCurrentSlotId() == newSlotId) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_SLOT_ALREADY_ACTIVE);
|
2025-02-18 22:22:40 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!profile.getSlots().containsKey(newSlotId)) {
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_SLOT_NOT_EXIST);
|
|
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.player != null) {
|
2025-02-20 13:36:07 -05:00
|
|
|
if (ConfigMain.RegionProfileSwitching) {
|
2025-04-08 13:39:25 -04:00
|
|
|
boolean allowed = hasCustomPermission(profile.player, PROFILE_REGION_BYPASS.name);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!allowed) {
|
2025-02-20 13:36:07 -05:00
|
|
|
int playerDim = profile.player.dimension;
|
|
|
|
|
int playerX = (int) profile.player.posX;
|
|
|
|
|
int playerY = (int) profile.player.posY;
|
|
|
|
|
int playerZ = (int) profile.player.posZ;
|
|
|
|
|
for (List<Integer> region : ConfigMain.RestrictedProfileRegions) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (region.size() == 7) {
|
2025-02-20 13:36:07 -05:00
|
|
|
int dim = region.get(0);
|
|
|
|
|
int x1 = Math.min(region.get(1), region.get(4));
|
|
|
|
|
int y1 = Math.min(region.get(2), region.get(5));
|
|
|
|
|
int z1 = Math.min(region.get(3), region.get(6));
|
|
|
|
|
int x2 = Math.max(region.get(1), region.get(4));
|
|
|
|
|
int y2 = Math.max(region.get(2), region.get(5));
|
|
|
|
|
int z2 = Math.max(region.get(3), region.get(6));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (playerDim == dim &&
|
2025-02-20 13:36:07 -05:00
|
|
|
playerX >= x1 && playerX <= x2 &&
|
|
|
|
|
playerY >= y1 && playerY <= y2 &&
|
|
|
|
|
playerZ >= z1 && playerZ <= z2) {
|
|
|
|
|
allowed = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2025-02-19 18:15:05 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-02-20 13:36:07 -05:00
|
|
|
if (!allowed) {
|
|
|
|
|
return ProfileOperation.error(MSG_REGION_NOT_ALLOWED);
|
|
|
|
|
}
|
2025-02-19 18:15:05 -05:00
|
|
|
}
|
2025-03-11 17:16:54 -04:00
|
|
|
|
2025-02-18 20:08:26 -05:00
|
|
|
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
|
2025-02-18 22:22:40 -05:00
|
|
|
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
|
2025-02-19 16:27:27 -05:00
|
|
|
for (IProfileData pd : dataList) {
|
2025-02-19 18:15:05 -05:00
|
|
|
if (pd.verifySwitch(profile.player).getResult() != EnumProfileOperation.SUCCESS) {
|
|
|
|
|
return pd.verifySwitch(profile.player);
|
2025-02-18 20:08:26 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-03-11 17:16:54 -04:00
|
|
|
|
|
|
|
|
int prevSlot = profile.getCurrentSlotId();
|
|
|
|
|
|
2025-04-09 01:55:34 -04:00
|
|
|
PlayerDataScript handler = ScriptController.Instance.getPlayerScripts(profile.player);
|
2025-03-11 17:16:54 -04:00
|
|
|
IPlayer scriptPlayer = (IPlayer) NpcAPI.Instance().getIEntity(profile.player);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, false))
|
2025-03-11 17:16:54 -04:00
|
|
|
return ProfileOperation.error(MSG_CANCELLED);
|
|
|
|
|
|
|
|
|
|
|
2025-02-18 06:25:09 -05:00
|
|
|
saveSlotData(profile.player);
|
2025-02-20 21:39:02 -05:00
|
|
|
profile.currentSlotId = newSlotId;
|
2025-02-18 06:25:09 -05:00
|
|
|
loadSlotData(profile.player);
|
2025-03-11 17:16:54 -04:00
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
EventHooks.onProfileChange(handler, scriptPlayer, profile, newSlotId, prevSlot, true);
|
2025-02-20 13:36:07 -05:00
|
|
|
} else {
|
|
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.success(MSG_CHANGE_SUCCESS);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation cloneSlot(EntityPlayer player, int sourceSlotId, int destinationSlotId, boolean temporary) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(player);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null) {
|
2025-02-18 06:25:09 -05:00
|
|
|
save(player, profile);
|
2025-02-19 18:15:05 -05:00
|
|
|
}
|
2025-02-18 06:25:09 -05:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation cloneSlot(UUID uuid, int sourceSlotId, int destinationSlotId, boolean temporary) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(uuid);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS) {
|
|
|
|
|
if (profile.player != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
save(profile.player, profile);
|
|
|
|
|
else
|
|
|
|
|
saveOffline(profile, uuid);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation cloneSlot(String username, int sourceSlotId, int destinationSlotId, boolean temporary) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = cloneSlotInternal(profile, sourceSlotId, destinationSlotId, temporary);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS) {
|
|
|
|
|
if (profile.player != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
save(profile.player, profile);
|
|
|
|
|
else {
|
|
|
|
|
UUID uuid = getUUIDFromUsername(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (uuid != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
saveOffline(profile, uuid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation removeSlot(EntityPlayer player, int slotId) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(player);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = removeSlotInternal(profile, slotId);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null) {
|
2025-02-18 06:25:09 -05:00
|
|
|
save(player, profile);
|
2025-02-19 18:15:05 -05:00
|
|
|
}
|
2025-02-18 06:25:09 -05:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation removeSlot(String username, int slotId) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = removeSlotInternal(profile, slotId);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS) {
|
|
|
|
|
if (profile.player != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
save(profile.player, profile);
|
|
|
|
|
else {
|
|
|
|
|
UUID uuid = getUUIDFromUsername(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (uuid != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
saveOffline(profile, uuid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation changeSlot(EntityPlayer player, int newSlotId) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(player);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = changeSlotInternal(profile, newSlotId);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS && player != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
save(player, profile);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public ProfileOperation changeSlot(String username, int newSlotId) {
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = getProfile(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile == null)
|
2025-02-19 18:15:05 -05:00
|
|
|
return ProfileOperation.error(MSG_PLAYER_NOT_FOUND);
|
2025-02-18 06:25:09 -05:00
|
|
|
ProfileOperation result = changeSlotInternal(profile, newSlotId);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (result.getResult() == EnumProfileOperation.SUCCESS) {
|
|
|
|
|
if (profile.player != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
save(profile.player, profile);
|
|
|
|
|
else {
|
|
|
|
|
UUID uuid = getUUIDFromUsername(username);
|
2025-02-20 21:39:02 -05:00
|
|
|
if (uuid != null)
|
2025-02-18 06:25:09 -05:00
|
|
|
saveOffline(profile, uuid);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
public void saveSlotData(EntityPlayer player) {
|
|
|
|
|
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
|
2025-01-23 16:10:01 -05:00
|
|
|
return;
|
2025-02-18 06:25:09 -05:00
|
|
|
Profile profile = activeProfiles.get(player.getUniqueID());
|
2025-02-20 21:39:02 -05:00
|
|
|
if (profile.isLocked()) {
|
2025-02-18 06:25:09 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
ISlot slot = profile.getSlots().get(profile.getCurrentSlotId());
|
|
|
|
|
if (slot == null) {
|
|
|
|
|
slot = new Slot(profile.getCurrentSlotId(), "Slot " + profile.getCurrentSlotId());
|
|
|
|
|
profile.getSlots().put(profile.getCurrentSlotId(), slot);
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
for (IProfileData profileData : profileTypes.values()) {
|
2025-02-20 21:44:15 -05:00
|
|
|
NBTTagCompound cloned = (NBTTagCompound) profileData.getCurrentNBT(player).copy();
|
2025-02-20 21:39:02 -05:00
|
|
|
slot.setComponentData(profileData.getTagName(), cloned);
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
2025-02-19 05:43:28 -05:00
|
|
|
slot.setLastLoaded(System.currentTimeMillis());
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public void loadSlotData(EntityPlayer player) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (player == null || !activeProfiles.containsKey(player.getUniqueID()))
|
2025-01-23 16:10:01 -05:00
|
|
|
return;
|
|
|
|
|
Profile profile = activeProfiles.get(player.getUniqueID());
|
2025-02-20 21:39:02 -05:00
|
|
|
ISlot slot = profile.getSlots().get(profile.getCurrentSlotId());
|
|
|
|
|
if (slot == null)
|
2025-02-18 06:25:09 -05:00
|
|
|
return;
|
2025-06-11 17:36:03 -05:00
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
for (IProfileData profileData : profileTypes.values()) {
|
2025-02-18 06:25:09 -05:00
|
|
|
NBTTagCompound data;
|
2025-02-20 21:39:02 -05:00
|
|
|
if (slot.getComponents().containsKey(profileData.getTagName()))
|
2025-06-30 21:57:29 -04:00
|
|
|
data = (NBTTagCompound) slot.getComponentData(profileData.getTagName()).copy();
|
2025-02-18 06:25:09 -05:00
|
|
|
else
|
|
|
|
|
data = new NBTTagCompound();
|
|
|
|
|
profileData.setNBT(player, data);
|
2025-02-18 20:05:55 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
for (IProfileData profileData : profileTypes.values()) {
|
2025-01-23 16:10:01 -05:00
|
|
|
profileData.save(player);
|
|
|
|
|
}
|
2025-03-10 18:07:22 -04:00
|
|
|
|
2025-08-27 16:27:40 -04:00
|
|
|
PlayerData pdata = PlayerData.get(player);
|
|
|
|
|
pdata.profileSlot = profile.getCurrentSlotId();
|
|
|
|
|
pdata.save();
|
|
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
if (ConfigMain.AttributesEnabled)
|
2025-03-10 18:32:24 -04:00
|
|
|
AttributeController.getTracker(player).recalcAttributes(player);
|
2025-02-18 06:25:09 -05:00
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
|
2025-02-27 15:54:42 -05:00
|
|
|
public List<ProfileInfoEntry> getProfileInfo(EntityPlayer player, int slotId) {
|
|
|
|
|
List<ProfileInfoEntry> infoList = new ArrayList<>();
|
2025-02-19 00:21:40 -05:00
|
|
|
Profile profile = getProfile(player);
|
|
|
|
|
if (profile == null)
|
|
|
|
|
return infoList;
|
2025-02-23 22:43:55 -05:00
|
|
|
|
|
|
|
|
List<IProfileData> dataList = new ArrayList<>(profileTypes.values());
|
|
|
|
|
dataList.sort(Comparator.comparingInt(IProfileData::getSwitchPriority));
|
2025-02-20 21:39:02 -05:00
|
|
|
if (slotId == profile.getCurrentSlotId()) {
|
2025-02-23 22:43:55 -05:00
|
|
|
for (IProfileData pd : dataList) {
|
2025-02-19 00:21:40 -05:00
|
|
|
NBTTagCompound currentNBT = pd.getCurrentNBT(player);
|
2025-02-27 15:54:42 -05:00
|
|
|
List<ProfileInfoEntry> subInfo = pd.getInfo(player, currentNBT);
|
2025-02-19 00:21:40 -05:00
|
|
|
infoList.addAll(subInfo);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (!profile.getSlots().containsKey(slotId))
|
2025-02-19 00:21:40 -05:00
|
|
|
return infoList;
|
2025-02-20 21:39:02 -05:00
|
|
|
ISlot slot = profile.getSlots().get(slotId);
|
2025-02-23 22:43:55 -05:00
|
|
|
for (IProfileData pd : dataList) {
|
2025-02-20 21:39:02 -05:00
|
|
|
if (slot.getComponents().containsKey(pd.getTagName())) {
|
2025-06-30 21:57:29 -04:00
|
|
|
NBTTagCompound sub = (NBTTagCompound) slot.getComponentData(pd.getTagName()).copy();
|
2025-02-27 15:54:42 -05:00
|
|
|
List<ProfileInfoEntry> subInfo = pd.getInfo(player, sub);
|
2025-02-19 00:21:40 -05:00
|
|
|
infoList.addAll(subInfo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return infoList;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:44:15 -05:00
|
|
|
public boolean allowSlotPermission(EntityPlayer player) {
|
2025-02-20 21:39:02 -05:00
|
|
|
Profile profile = getProfile(player);
|
|
|
|
|
int currentSlots = profile.getSlots().size();
|
2025-03-09 18:58:42 -04:00
|
|
|
if (CustomNpcsPermissions.hasCustomPermission(player, PROFILE_MAX.name)) {
|
2025-02-19 16:27:27 -05:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
int highestAllowed = 0;
|
|
|
|
|
for (int i = 1; i <= 50; i++) {
|
|
|
|
|
String perm = "customnpcs.profile.max." + i;
|
|
|
|
|
if (CustomNpcsPermissions.hasCustomPermission(player, perm)) {
|
|
|
|
|
highestAllowed = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-04-08 13:39:25 -04:00
|
|
|
if (highestAllowed == 0 || highestAllowed < ConfigMain.DefaultProfileSlots) {
|
|
|
|
|
highestAllowed = ConfigMain.DefaultProfileSlots;
|
2025-02-19 16:27:27 -05:00
|
|
|
}
|
|
|
|
|
return currentSlots < highestAllowed;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-20 21:39:02 -05:00
|
|
|
@Override
|
|
|
|
|
public IProfile getProfile(IPlayer player) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return null;
|
2025-02-20 21:44:15 -05:00
|
|
|
return getProfile((EntityPlayer) player.getMCEntity());
|
2025-02-20 21:39:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean changeSlot(IPlayer player, int slotID) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
|
|
|
|
|
ProfileOperation profileOperation = changeSlot(entityPlayer, slotID);
|
|
|
|
|
return profileOperation.getResult() == EnumProfileOperation.SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean hasSlot(IPlayer player, int slotID) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
|
|
|
|
|
Profile profile = getProfile(entityPlayer);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return false;
|
|
|
|
|
return profile.getSlots().containsKey(slotID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean removeSlot(IPlayer player, int slotID) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
|
|
|
|
|
ProfileOperation profileOperation = removeSlot(entityPlayer, slotID);
|
|
|
|
|
return profileOperation.getResult() == EnumProfileOperation.SUCCESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public IPlayerData getSlotPlayerData(IPlayer player, int slotID) {
|
|
|
|
|
PlayerData playerData;
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
|
|
|
|
|
Profile profile = getProfile(entityPlayer);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile == null)
|
2025-02-21 06:19:24 -05:00
|
|
|
return null;
|
|
|
|
|
return getSlotPlayerData(entityPlayer, slotID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void saveSlotData(IPlayer player) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (player == null || player.getMCEntity() == null)
|
2025-02-21 06:19:24 -05:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
EntityPlayer entityPlayer = (EntityPlayer) player.getMCEntity();
|
|
|
|
|
saveSlotData(entityPlayer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IPlayerData getSlotPlayerData(EntityPlayer player, int slotID) {
|
|
|
|
|
PlayerData playerData;
|
|
|
|
|
Profile profile = getProfile(player);
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile == null)
|
2025-02-20 21:39:02 -05:00
|
|
|
return null;
|
|
|
|
|
|
2025-03-13 17:14:45 -04:00
|
|
|
if (profile.currentSlotId == slotID) {
|
2025-02-21 06:19:24 -05:00
|
|
|
playerData = PlayerData.get(player);
|
2025-02-20 21:39:02 -05:00
|
|
|
} else {
|
|
|
|
|
Slot slot = (Slot) profile.getSlots().get(slotID);
|
2025-02-21 17:23:51 -05:00
|
|
|
playerData = getSlotPlayerData(player, slot);
|
2025-02-20 21:39:02 -05:00
|
|
|
}
|
|
|
|
|
return playerData;
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-21 06:19:24 -05:00
|
|
|
public PlayerData getSlotPlayerData(EntityPlayer player, Slot slot) {
|
2025-03-13 17:14:45 -04:00
|
|
|
if (slot == null)
|
2025-02-21 06:19:24 -05:00
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
PlayerData playerData = new PlayerData();
|
|
|
|
|
playerData.player = player;
|
2025-02-21 17:23:51 -05:00
|
|
|
|
|
|
|
|
NBTTagCompound compound = slot.getComponentData(new CNPCData().getTagName());
|
2025-03-13 17:14:45 -04:00
|
|
|
if (compound == null)
|
2025-02-21 17:23:51 -05:00
|
|
|
compound = new NBTTagCompound();
|
2025-06-30 21:57:29 -04:00
|
|
|
else
|
|
|
|
|
compound = (NBTTagCompound) compound.copy();
|
2025-02-21 17:23:51 -05:00
|
|
|
playerData.setNBT(compound);
|
2025-02-21 06:19:24 -05:00
|
|
|
return playerData;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void verifySlotQuests(EntityPlayer player) {
|
|
|
|
|
Profile profile = getProfile(player);
|
2025-02-21 16:40:44 -05:00
|
|
|
if (profile == null) {
|
2025-02-20 21:39:02 -05:00
|
|
|
return;
|
2025-02-21 16:40:44 -05:00
|
|
|
}
|
2025-02-20 21:39:02 -05:00
|
|
|
|
2025-02-21 16:40:44 -05:00
|
|
|
Map<Integer, Long> universalFinished = new HashMap<>();
|
|
|
|
|
for (Integer questId : QuestController.Instance.sharedQuests.keySet()) {
|
|
|
|
|
long maxTime = 0;
|
|
|
|
|
for (ISlot slot : profile.getSlots().values()) {
|
|
|
|
|
IPlayerData data = getSlotPlayerData(player, slot.getId());
|
|
|
|
|
if (data == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
PlayerQuestData questData = (PlayerQuestData) data.getQuestData();
|
|
|
|
|
Long t = questData.finishedQuests.get(questId);
|
|
|
|
|
if (t != null && t > maxTime) {
|
|
|
|
|
maxTime = t;
|
2025-02-21 06:19:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
2025-02-21 16:40:44 -05:00
|
|
|
if (maxTime > 0) {
|
|
|
|
|
universalFinished.put(questId, maxTime);
|
|
|
|
|
}
|
2025-02-21 06:19:24 -05:00
|
|
|
}
|
2025-02-21 16:40:44 -05:00
|
|
|
|
|
|
|
|
// Push the universal shared completion times into every slot.
|
|
|
|
|
for (ISlot slot : profile.getSlots().values()) {
|
|
|
|
|
IPlayerData data = getSlotPlayerData(player, slot.getId());
|
|
|
|
|
if (data != null) {
|
2025-02-21 17:23:51 -05:00
|
|
|
PlayerData playerData = (PlayerData) data;
|
2025-02-21 16:40:44 -05:00
|
|
|
PlayerQuestData questData = (PlayerQuestData) data.getQuestData();
|
|
|
|
|
questData.finishedQuests.putAll(universalFinished);
|
2025-02-21 17:23:51 -05:00
|
|
|
slot.setComponentData(new CNPCData().getTagName(), playerData.getNBT());
|
2025-02-21 06:19:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void shareQuestCompletion(EntityPlayer player, int questId, long completeTime) {
|
|
|
|
|
Profile profile = getProfile(player);
|
|
|
|
|
if (profile == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
for (ISlot slot : profile.getSlots().values()) {
|
|
|
|
|
IPlayerData playerData = getSlotPlayerData(player, slot.getId());
|
|
|
|
|
if (playerData != null) {
|
|
|
|
|
PlayerQuestData questData = (PlayerQuestData) playerData.getQuestData();
|
|
|
|
|
Long existing = questData.finishedQuests.get(questId);
|
|
|
|
|
if (existing == null || completeTime > existing) {
|
|
|
|
|
questData.finishedQuests.put(questId, completeTime);
|
|
|
|
|
}
|
2025-02-21 07:05:56 -05:00
|
|
|
playerData.save();
|
2025-02-21 06:19:24 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
save(player, profile);
|
2025-02-20 21:39:02 -05:00
|
|
|
}
|
2025-01-23 16:10:01 -05:00
|
|
|
}
|