Skip to content

Commit e3d7e54

Browse files
committed
Refactor InventoryDataProvider and InventoryGUIHelper to improve readability
1 parent 131cd51 commit e3d7e54

2 files changed

Lines changed: 176 additions & 123 deletions

File tree

src/main/java/org/mvplugins/multiverse/inventories/profile/InventoryDataProvider.java

Lines changed: 144 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -95,66 +95,91 @@ public CompletableFuture<PlayerInventoryData> loadPlayerInventoryData(
9595
@NotNull String worldName
9696
) {
9797
// If the player is online, prioritize getting their live inventory
98-
if (targetPlayer.isOnline()) {
99-
Player onlineTarget = targetPlayer.getPlayer();
100-
// Ensure onlineTarget is not null and their current world matches the requested worldName
101-
if (onlineTarget != null && onlineTarget.getWorld().getName().equalsIgnoreCase(worldName)) {
102-
// Get the actual ProfileType for the online player
103-
ProfileType profileType = ProfileTypes.forPlayer(onlineTarget);
104-
// Return immediately with live data
105-
return CompletableFuture.completedFuture(new PlayerInventoryData(
106-
onlineTarget.getInventory().getContents(),
107-
onlineTarget.getInventory().getArmorContents(),
108-
onlineTarget.getInventory().getItemInOffHand(),
109-
"Displaying LIVE inventory for " + targetPlayer.getName() + " in world " + worldName + ".",
110-
profileType
111-
));
98+
if (!targetPlayer.isOnline()) {
99+
return loadInventoryDataFromProfileStorage(targetPlayer, worldName);
100+
}
101+
102+
Player onlineTarget = targetPlayer.getPlayer();
103+
// Ensure onlineTarget is not null and their current world matches the requested worldName
104+
if (onlineTarget != null && onlineTarget.getWorld().getName().equalsIgnoreCase(worldName)) {
105+
return loadInventoryDataFromPlayer(onlineTarget, worldName);
106+
}
107+
// If online but in a different world, or getPlayer() returned null, fall through to stored data logic
108+
if (onlineTarget != null) {
109+
inventories.getLogger().fine("Player " + targetPlayer.getName() + " is online but in world " + onlineTarget.getWorld().getName() + ". Loading stored data for " + worldName + ".");
110+
} else {
111+
inventories.getLogger().warning("Player " + targetPlayer.getName() + " is online but getPlayer() returned null. Falling back to stored data.");
112+
}
113+
// If the player is offline or online in a different world, or live data failed, load from Multiverse-Inventories' stored profiles
114+
return loadInventoryDataFromProfileStorage(targetPlayer, worldName);
115+
}
116+
117+
private CompletableFuture<PlayerInventoryData> loadInventoryDataFromPlayer(
118+
@NotNull Player onlineTarget,
119+
@NotNull String worldName
120+
) {
121+
// Get the actual ProfileType for the online player
122+
ProfileType profileType = ProfileTypes.forPlayer(onlineTarget);
123+
// Return immediately with live data
124+
return CompletableFuture.completedFuture(new PlayerInventoryData(
125+
onlineTarget.getInventory().getContents(),
126+
onlineTarget.getInventory().getArmorContents(),
127+
onlineTarget.getInventory().getItemInOffHand(),
128+
"Displaying LIVE inventory for " + onlineTarget.getName() + " in world " + worldName + ".",
129+
profileType
130+
));
131+
}
132+
133+
private CompletableFuture<PlayerInventoryData> loadInventoryDataFromProfileStorage(
134+
@NotNull OfflinePlayer targetPlayer,
135+
@NotNull String worldName
136+
) {
137+
return CompletableFuture.supplyAsync(() -> {
138+
ProfileContainer container = profileContainerStoreProvider.getStore(ContainerType.WORLD)
139+
.getContainer(worldName);
140+
if (container == null) {
141+
throw new IllegalStateException("Could not load profile container for world: " + worldName);
142+
}
143+
144+
PlayerProfile tempProfile = loadMVInvPlayerProfile(container, targetPlayer);
145+
if (tempProfile == null) {
146+
throw new IllegalStateException("No player data found for " + targetPlayer.getName() + " in world " + worldName + ". Try checking a different world or ensure the player has played in this world.");
112147
}
113-
// If online but in a different world, or getPlayer() returned null, fall through to stored data logic
114-
if (onlineTarget != null) {
115-
inventories.getLogger().fine("Player " + targetPlayer.getName() + " is online but in world " + onlineTarget.getWorld().getName() + ". Loading stored data for " + worldName + ".");
116-
} else {
117-
inventories.getLogger().warning("Player " + targetPlayer.getName() + " is online but getPlayer() returned null. Falling back to stored data.");
148+
ProfileType profileTypeToUse = tempProfile.getProfileType();
149+
try {
150+
ItemStack[] contents = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.INVENTORY).read().join();
151+
ItemStack[] armor = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.ARMOR).read().join();
152+
ItemStack offHand = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.OFF_HAND).read().join();
153+
154+
return new PlayerInventoryData(
155+
contents,
156+
armor,
157+
offHand,
158+
"Displaying STORED inventory for " + targetPlayer.getName() + " in world " + worldName + ".",
159+
profileTypeToUse
160+
);
161+
} catch (CompletionException e) {
162+
// Unwrap CompletionException to get the actual cause
163+
throw new IllegalStateException("Error loading inventory data: " + e.getCause().getMessage(), e.getCause());
118164
}
165+
});
166+
}
167+
168+
@Nullable
169+
private PlayerProfile loadMVInvPlayerProfile(ProfileContainer container, OfflinePlayer targetPlayer) {
170+
PlayerProfile survivalProfile = container.getPlayerProfileNow(ProfileTypes.SURVIVAL, targetPlayer);
171+
if (survivalProfile != null) {
172+
return survivalProfile;
119173
}
120-
// If the player is offline or online in a different world, or live data failed, load from Multiverse-Inventories' stored profiles
121-
return CompletableFuture.supplyAsync(() -> {
122-
ProfileContainer container = profileContainerStoreProvider.getStore(ContainerType.WORLD)
123-
.getContainer(worldName);
124-
if (container == null) {
125-
throw new IllegalStateException("Could not load profile container for world: " + worldName);
126-
}
127-
128-
PlayerProfile tempProfile = container.getPlayerProfileNow(ProfileTypes.SURVIVAL, targetPlayer);
129-
ProfileType profileTypeToUse = ProfileTypes.SURVIVAL;
130-
131-
if (tempProfile == null) {
132-
for (ProfileType type : ProfileTypes.getTypes()) {
133-
if (type.equals(ProfileTypes.SURVIVAL)) continue;
134-
tempProfile = container.getPlayerProfileNow(type, targetPlayer);
135-
if (tempProfile != null) {
136-
profileTypeToUse = type;
137-
break;
138-
}
139-
}
140-
}
141-
142-
if (tempProfile == null) {
143-
throw new IllegalStateException("No player data found for " + targetPlayer.getName() + " in world " + worldName + ". Try checking a different world or ensure the player has played in this world.");
144-
}
145-
146-
try {
147-
ItemStack[] contents = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.INVENTORY).read().join();
148-
ItemStack[] armor = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.ARMOR).read().join();
149-
ItemStack offHand = SingleShareReader.of(inventories, targetPlayer, worldName, profileTypeToUse, Sharables.OFF_HAND).read().join();
150-
151-
return new PlayerInventoryData(contents, armor, offHand, "Displaying STORED inventory for " + targetPlayer.getName() + " in world " + worldName + ".", profileTypeToUse);
152-
} catch (CompletionException e) {
153-
// Unwrap CompletionException to get the actual cause
154-
throw new IllegalStateException("Error loading inventory data: " + e.getCause().getMessage(), e.getCause());
155-
}
156-
});
174+
for (ProfileType type : ProfileTypes.getTypes()) {
175+
if (type.equals(ProfileTypes.SURVIVAL)) continue;
176+
PlayerProfile profile = container.getPlayerProfileNow(type, targetPlayer);
177+
if (profile != null) {
178+
return profile;
179+
}
157180
}
181+
return null;
182+
}
158183

159184
/**
160185
* Asynchronously saves a player's inventory data to their Multiverse-Inventories profile.
@@ -180,7 +205,69 @@ public CompletableFuture<Void> savePlayerInventoryData(
180205
@Nullable ItemStack newOffHand
181206
) {
182207
// Save the updated inventory, armor, and off-hand contents asynchronously
183-
CompletableFuture<Void> saveFuture = CompletableFuture.allOf(
208+
CompletableFuture<Void> saveFuture = writeInventoryDataToProfile(
209+
targetPlayer,
210+
worldName,
211+
profileType,
212+
newContents,
213+
newArmor,
214+
newOffHand
215+
);
216+
217+
return saveFuture.thenRun(() -> {
218+
inventories.getLogger().info("Inventory for player " + targetPlayer.getName() + " in world " + worldName + " has been modified and saved.");
219+
updateOnlinePlayerInventoryData(targetPlayer, worldName, newContents, newArmor, newOffHand);
220+
}).exceptionally(throwable -> {
221+
inventories.getLogger().severe("Failed to save inventory for " + targetPlayer.getName() + " in world " + worldName + ": " + throwable.getMessage());
222+
throwable.printStackTrace();
223+
return null;
224+
});
225+
}
226+
227+
private void updateOnlinePlayerInventoryData(
228+
OfflinePlayer targetPlayer,
229+
String worldName,
230+
@NotNull ItemStack[] newContents,
231+
@NotNull ItemStack[] newArmor,
232+
ItemStack newOffHand
233+
) {
234+
// If the target player is online, update their live inventory
235+
if (!targetPlayer.isOnline()) {
236+
return;
237+
}
238+
239+
Player onlinePlayer = targetPlayer.getPlayer();
240+
if (onlinePlayer == null) {
241+
return;
242+
}
243+
244+
// Check if the online player is in the world whose inventory was modified
245+
// This is important to avoid overwriting their current inventory if they are in a different world
246+
if (!onlinePlayer.getWorld().getName().equalsIgnoreCase(worldName)) {
247+
inventories.getLogger().info("Player " + onlinePlayer.getName() + " is online but in a different world (" + onlinePlayer.getWorld().getName() + "), not updating live inventory.");
248+
return;
249+
}
250+
251+
// Run Bukkit API calls on the main thread
252+
Bukkit.getScheduler().runTask(inventories, () -> {
253+
onlinePlayer.getInventory().setContents(newContents);
254+
onlinePlayer.getInventory().setArmorContents(newArmor);
255+
onlinePlayer.getInventory().setItemInOffHand(newOffHand);
256+
onlinePlayer.updateInventory(); // Ensure client sees changes
257+
inventories.getLogger().info("Updated live inventory for online player " + onlinePlayer.getName() + " in world " + worldName);
258+
});
259+
}
260+
261+
private CompletableFuture<Void> writeInventoryDataToProfile(
262+
@NotNull OfflinePlayer targetPlayer,
263+
@NotNull String worldName,
264+
@NotNull ProfileType profileType,
265+
@NotNull ItemStack[] newContents,
266+
@NotNull ItemStack[] newArmor,
267+
@Nullable ItemStack newOffHand
268+
) {
269+
// Save the updated inventory, armor, and off-hand contents asynchronously
270+
return CompletableFuture.allOf(
184271
SingleShareWriter.of(inventories, targetPlayer, worldName, profileType, Sharables.INVENTORY)
185272
.write(newContents, true) // true to update if player is online
186273
.thenRun(() -> inventories.getLogger().fine("Saved inventory for " + targetPlayer.getName() + " in " + worldName)),
@@ -191,34 +278,5 @@ public CompletableFuture<Void> savePlayerInventoryData(
191278
.write(newOffHand, true)
192279
.thenRun(() -> inventories.getLogger().fine("Saved off-hand for " + targetPlayer.getName() + " in " + worldName))
193280
);
194-
195-
return saveFuture.thenRun(() -> {
196-
inventories.getLogger().info("Inventory for player " + targetPlayer.getName() + " in world " + worldName + " has been modified and saved.");
197-
198-
// If the target player is online, update their live inventory
199-
if (targetPlayer.isOnline()) {
200-
Player onlinePlayer = targetPlayer.getPlayer();
201-
if (onlinePlayer != null) {
202-
// Check if the online player is in the world whose inventory was modified
203-
// This is important to avoid overwriting their current inventory if they are in a different world
204-
if (onlinePlayer.getWorld().getName().equalsIgnoreCase(worldName)) {
205-
// Run Bukkit API calls on the main thread
206-
Bukkit.getScheduler().runTask(inventories, () -> {
207-
onlinePlayer.getInventory().setContents(newContents);
208-
onlinePlayer.getInventory().setArmorContents(newArmor);
209-
onlinePlayer.getInventory().setItemInOffHand(newOffHand);
210-
onlinePlayer.updateInventory(); // Ensure client sees changes
211-
inventories.getLogger().info("Updated live inventory for online player " + onlinePlayer.getName() + " in world " + worldName);
212-
});
213-
} else {
214-
inventories.getLogger().info("Player " + onlinePlayer.getName() + " is online but in a different world (" + onlinePlayer.getWorld().getName() + "), not updating live inventory.");
215-
}
216-
}
217-
}
218-
}).exceptionally(throwable -> {
219-
inventories.getLogger().severe("Failed to save inventory for " + targetPlayer.getName() + " in world " + worldName + ": " + throwable.getMessage());
220-
throwable.printStackTrace();
221-
return null;
222-
});
223281
}
224282
}

src/main/java/org/mvplugins/multiverse/inventories/view/InventoryGUIHelper.java

Lines changed: 32 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import org.bukkit.NamespacedKey;
77
import org.bukkit.inventory.ItemStack;
88
import org.bukkit.inventory.meta.ItemMeta;
9+
import org.bukkit.persistence.PersistentDataContainer;
910
import org.bukkit.persistence.PersistentDataType;
1011
import org.jetbrains.annotations.ApiStatus;
1112
import org.jetbrains.annotations.NotNull;
@@ -68,8 +69,9 @@ public boolean isFillerItem(@NotNull ItemStack item) {
6869
if (!item.hasItemMeta()) {
6970
return false;
7071
}
71-
return item.getItemMeta().getPersistentDataContainer().has(IS_FILLER_KEY, PersistentDataType.BYTE) &&
72-
item.getItemMeta().getPersistentDataContainer().get(IS_FILLER_KEY, PersistentDataType.BYTE) == (byte) 1;
72+
PersistentDataContainer persistentDataContainer = item.getItemMeta().getPersistentDataContainer();
73+
return persistentDataContainer.has(IS_FILLER_KEY, PersistentDataType.BYTE) &&
74+
persistentDataContainer.getOrDefault(IS_FILLER_KEY, PersistentDataType.BYTE, (byte) 0) == (byte) 1;
7375
}
7476

7577
/**
@@ -92,28 +94,24 @@ public boolean isValidItemForSlot(@NotNull ItemStack item, int slot) {
9294
return true;
9395
}
9496

95-
switch (slot) {
96-
case 36: // Helmet slot
97-
return item.getType().name().endsWith("_HELMET");
98-
case 37: // Chestplate slot
99-
return item.getType().name().endsWith("_CHESTPLATE");
100-
case 38: // Leggings slot
101-
return item.getType().name().endsWith("_LEGGINGS");
102-
case 39: // Boots slot
103-
return item.getType().name().endsWith("_BOOTS");
104-
case 40: // Off-hand slot
105-
// Off-hand is very permissive in vanilla. Allow any non-air item.
106-
// If you want to restrict this further (e.g., only shields/totems),
107-
// add more specific Material checks here.
108-
return true;
109-
case 41: // Padding slot
110-
case 42: // Padding slot
111-
case 43: // Padding slot
112-
case 44: // Padding slot
113-
return false; // Cannot place items in padding slots
114-
default:
115-
return true; // For non-special slots (main inventory), any item is generally allowed.
116-
}
97+
return switch (slot) {
98+
case 36 -> item.getType().name().endsWith("_HELMET");
99+
case 37 -> item.getType().name().endsWith("_CHESTPLATE");
100+
case 38 -> item.getType().name().endsWith("_LEGGINGS");
101+
case 39 -> item.getType().name().endsWith("_BOOTS");
102+
103+
// Off-hand is very permissive in vanilla. Allow any non-air item.
104+
// If you want to restrict this further (e.g., only shields/totems),
105+
// add more specific Material checks here.
106+
case 40 -> true;
107+
108+
// Padding slot
109+
// Cannot place items in padding slots
110+
case 41, 42, 43, 44 -> false;
111+
112+
// For non-special slots (main inventory), any item is generally allowed.
113+
default -> true;
114+
};
117115
}
118116

119117
/**
@@ -126,17 +124,14 @@ public boolean isValidItemForSlot(@NotNull ItemStack item, int slot) {
126124
*/
127125
@ApiStatus.AvailableSince("5.2")
128126
public ItemStack createFillerItemForSlot(int slot) {
129-
switch (slot) {
130-
case 36: return createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Helmet Slot", "Place Helmet Here");
131-
case 37: return createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Chestplate Slot", "Place Chestplate Here");
132-
case 38: return createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Leggings Slot", "Place Leggings Here");
133-
case 39: return createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Boots Slot", "Place Boots Here");
134-
case 40: return createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Off-Hand Slot", "Place Off-Hand Item Here");
135-
case 41:
136-
case 42:
137-
case 43:
138-
case 44: return createFillerItem(Material.BARRIER, " ", " "); // Padding slots
139-
default: return new ItemStack(Material.AIR); // Should not happen for these slots
140-
}
127+
return switch (slot) {
128+
case 36 -> createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Helmet Slot", "Place Helmet Here");
129+
case 37 -> createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Chestplate Slot", "Place Chestplate Here");
130+
case 38 -> createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Leggings Slot", "Place Leggings Here");
131+
case 39 -> createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Boots Slot", "Place Boots Here");
132+
case 40 -> createFillerItem(Material.GRAY_STAINED_GLASS_PANE, "Off-Hand Slot", "Place Off-Hand Item Here");
133+
case 41, 42, 43, 44 -> createFillerItem(Material.BARRIER, " ", " "); // Padding slots
134+
default -> new ItemStack(Material.AIR); // Should not happen for these slots
135+
};
141136
}
142-
}
137+
}

0 commit comments

Comments
 (0)