Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.mvplugins.multiverse.core.module.MultiverseModule;
import org.mvplugins.multiverse.core.utils.StringFormatter;
import org.mvplugins.multiverse.inventories.command.MVInvCommandConditions;
import org.mvplugins.multiverse.inventories.command.MVInvCommandPermissions;
import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
import org.mvplugins.multiverse.inventories.command.MVInvCommandCompletion;
import org.mvplugins.multiverse.inventories.command.MVInvCommandContexts;
Expand Down Expand Up @@ -73,6 +74,8 @@ public class MultiverseInventories extends MultiverseModule {
private Provider<MVInvCommandContexts> mvInvCommandContexts;
@Inject
private Provider<MVInvCommandConditions> mvInvCommandConditions;
@Inject
private Provider<MVInvCommandPermissions> mvInvCommandPermissions;

private InventoriesDupingPatch dupingPatch;
private boolean usingSpawnChangeEvent = false;
Expand Down Expand Up @@ -167,6 +170,7 @@ private void registerCommands() {
mvInvCommandCompletion.get();
mvInvCommandContexts.get();
mvInvCommandConditions.get();
mvInvCommandPermissions.get();
}).onFailure(e -> {
Logging.warning("Failed to register command completers: %s", e.getMessage());
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
import org.mvplugins.multiverse.inventories.share.Sharables;

import java.util.Arrays;
Expand Down Expand Up @@ -53,6 +55,7 @@ private MVInvCommandCompletion(
commandCompletions.registerStaticCompletion("mvinvconfigs", inventoriesConfig.getStringPropertyHandle().getAllPropertyNames());
commandCompletions.registerAsyncCompletion("mvinvconfigvalues", this::suggestConfigValues);
commandCompletions.registerAsyncCompletion("mvinvplayernames", this::suggestPlayerNames);
commandCompletions.registerAsyncCompletion("mvinvprofiletypes", this::suggestProfileTypes);
commandCompletions.registerAsyncCompletion("sharables", this::suggestSharables);
commandCompletions.registerAsyncCompletion("shares", this::suggestShares);
commandCompletions.registerAsyncCompletion("worldGroups", this::suggestWorldGroups);
Expand Down Expand Up @@ -89,6 +92,29 @@ private List<String> getPlayerNames() {
.collect(Collectors.toList());
}

private Collection<String> suggestProfileTypes(BukkitCommandCompletionContext context) {
if (!context.hasConfig("multiple")) {
return ProfileTypes.getTypes().stream()
.map(ProfileType::getName)
.map(String::toLowerCase)
.toList();
}

if (Objects.equals(context.getInput(), "@all")) {
return Collections.emptyList();
}
List<String> profileTypes = ProfileTypes.getTypes()
.stream()
.map(ProfileType::getName)
.map(String::toLowerCase)
.collect(Collectors.toList());
if (context.getInput().indexOf(',') == -1) {
profileTypes.add("@all");
return profileTypes;
}
return StringFormatter.addonToCommaSeperated(context.getInput(), profileTypes);
}

private Collection<String> suggestSharables(BukkitCommandCompletionContext context) {
String scope = context.getConfig("scope", "enabled");

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.mvplugins.multiverse.inventories.command;

import com.google.common.base.Strings;
import org.bukkit.Bukkit;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.command.MVCommandManager;
import org.mvplugins.multiverse.core.utils.REPatterns;
Expand All @@ -11,54 +10,122 @@
import org.mvplugins.multiverse.external.jakarta.inject.Inject;
import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
import org.mvplugins.multiverse.external.vavr.control.Option;
import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
import org.mvplugins.multiverse.inventories.profile.PlayerNamesMapper;
import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;
import org.mvplugins.multiverse.inventories.profile.key.ContainerKey;
import org.mvplugins.multiverse.inventories.profile.key.ContainerType;
import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
import org.mvplugins.multiverse.inventories.share.Sharable;
import org.mvplugins.multiverse.inventories.share.Sharables;
import org.mvplugins.multiverse.inventories.share.Shares;
import org.mvplugins.multiverse.inventories.util.MVInvi18n;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
import java.util.Collections;
import java.util.List;

@Service
public final class MVInvCommandContexts {

private final WorldGroupManager worldGroupManager;
private final PlayerNamesMapper playerNamesMapper;
private final InventoriesConfig config;
private final ProfileDataSource profileDataSource;

@Inject
private MVInvCommandContexts(
@NotNull MVCommandManager commandManager,
@NotNull WorldGroupManager worldGroupManager,
@NotNull PlayerNamesMapper playerNamesMapper
@NotNull PlayerNamesMapper playerNamesMapper,
@NotNull InventoriesConfig config,
@NotNull ProfileDataSource profileDataSource
) {
this.worldGroupManager = worldGroupManager;
this.playerNamesMapper = playerNamesMapper;
this.config = config;
this.profileDataSource = profileDataSource;

CommandContexts<BukkitCommandExecutionContext> commandContexts = commandManager.getCommandContexts();
commandContexts.registerContext(GlobalProfileKey[].class, this::parseGlobalProfileKeys);
commandContexts.registerContext(ContainerKey[].class, this::parseContainerKeyArray);
commandContexts.registerContext(GlobalProfileKey[].class, this::parseGlobalProfileKeyArray);
commandContexts.registerIssuerAwareContext(ProfileType.class, this::parseProfileType);
commandContexts.registerIssuerAwareContext(ProfileType[].class, this::parseProfileTypeArray);
commandContexts.registerContext(Sharable.class, this::parseSharable);
commandContexts.registerContext(Shares.class, this::parseShares);
commandContexts.registerContext(WorldGroup.class, this::parseWorldGroup);
}

private GlobalProfileKey[] parseGlobalProfileKeys(BukkitCommandExecutionContext context) {
String profileStrings = context.popFirstArg();
if (profileStrings.equals("@all")) {
return playerNamesMapper.getKeys().toArray(GlobalProfileKey[]::new);
private ProfileType parseProfileType(BukkitCommandExecutionContext context) {
if (!config.getEnableGamemodeShareHandling()) {
return ProfileTypes.getDefault();
}
String profileType = context.popFirstArg();
return ProfileTypes.forName(profileType)
.getOrElseThrow(() -> new InvalidCommandArgument("Invalid profile type: " + profileType));
}

private ContainerKey[] parseContainerKeyArray(BukkitCommandExecutionContext context) {
String keyStrings = context.popFirstArg();
if (keyStrings.equals("@all")) {
return Arrays.stream(ContainerType.values()).flatMap(containerType ->
profileDataSource.listContainerDataNames(containerType)
.stream()
.map(containerName -> ContainerKey.create(containerType, containerName)))
.toArray(ContainerKey[]::new);
}
List<ContainerKey> containerKeys = new ArrayList<>();
String[] typesSplit = REPatterns.SEMICOLON.split(keyStrings);
for (String typeSplit : typesSplit) {
String[] keyValueSplit = REPatterns.EQUALS.split(typeSplit, 2);
if (keyValueSplit.length != 2) {
// todo: Probably error invalid format
continue;
}
ContainerType containerType = ContainerType.valueOf(keyValueSplit[0].toUpperCase());
String[] dataNameSplit = REPatterns.COMMA.split(keyValueSplit[1]);
List<String> availableDataNames = profileDataSource.listContainerDataNames(containerType);
for (String dataName : dataNameSplit) {
if (availableDataNames.contains(dataName)) {
containerKeys.add(ContainerKey.create(containerType, dataName));
}
}
}
return containerKeys.toArray(new ContainerKey[0]);
}

String[] profileNames = REPatterns.COMMA.split(profileStrings);
private GlobalProfileKey[] parseGlobalProfileKeyArray(BukkitCommandExecutionContext context) {
String keyStrings = context.popFirstArg();
if (keyStrings.equals("@all")) {
return playerNamesMapper.getKeys().toArray(GlobalProfileKey[]::new);
}
// todo: UUID parsing
String[] profileNames = REPatterns.COMMA.split(keyStrings);
return Arrays.stream(profileNames)
.map(playerNamesMapper::getKey)
.filter(Option::isDefined)
.map(Option::get)
.toArray(GlobalProfileKey[]::new);
}

private ProfileType[] parseProfileTypeArray(BukkitCommandExecutionContext context) {
String keyStrings = context.popFirstArg();
if (keyStrings.equals("@all")) {
return ProfileTypes.getTypes().toArray(ProfileType[]::new);
}
String[] profileNames = REPatterns.COMMA.split(keyStrings);
return Arrays.stream(profileNames)
.map(ProfileTypes::forName)
.filter(Option::isDefined)
.map(Option::get)
.toArray(ProfileType[]::new);
}

private Sharable<?> parseSharable(BukkitCommandExecutionContext context) {
String sharableName = context.popFirstArg();
Sharable<?> targetSharable = Sharables.all().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.mvplugins.multiverse.inventories.command;

import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.command.MVCommandManager;
import org.mvplugins.multiverse.core.command.MVCommandPermissions;
import org.mvplugins.multiverse.external.jakarta.inject.Inject;
import org.mvplugins.multiverse.external.jetbrains.annotations.NotNull;
import org.mvplugins.multiverse.inventories.config.InventoriesConfig;

@Service
public class MVInvCommandPermissions {

@Inject
MVInvCommandPermissions(@NotNull MVCommandManager commandManager, @NotNull InventoriesConfig config) {

MVCommandPermissions commandPermissions = commandManager.getCommandPermissions();
commandPermissions.registerPermissionChecker("mvinv-gamemode-profile-true", commandIssuer -> config.getEnableGamemodeShareHandling());
commandPermissions.registerPermissionChecker("mvinv-gamemode-profile-false", commandIssuer -> !config.getEnableGamemodeShareHandling());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@

import com.dumptruckman.minecraft.util.Logging;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
import org.mvplugins.multiverse.core.command.MVCommandManager;
import org.mvplugins.multiverse.core.utils.REPatterns;
import org.mvplugins.multiverse.core.world.MultiverseWorld;
import org.mvplugins.multiverse.external.acf.commands.annotation.CommandAlias;
import org.mvplugins.multiverse.external.acf.commands.annotation.CommandCompletion;
import org.mvplugins.multiverse.external.acf.commands.annotation.CommandPermission;
import org.mvplugins.multiverse.external.acf.commands.annotation.Description;
Expand All @@ -22,14 +20,14 @@
import org.mvplugins.multiverse.external.jakarta.inject.Inject;
import org.mvplugins.multiverse.external.vavr.control.Try;
import org.mvplugins.multiverse.inventories.MultiverseInventories;
import org.mvplugins.multiverse.inventories.config.InventoriesConfig;
import org.mvplugins.multiverse.inventories.handleshare.SingleShareReader;
import org.mvplugins.multiverse.inventories.handleshare.SingleShareWriter;
import org.mvplugins.multiverse.inventories.profile.ProfileDataSource;
import org.mvplugins.multiverse.inventories.profile.key.GlobalProfileKey;
import org.mvplugins.multiverse.inventories.profile.key.ProfileType;
import org.mvplugins.multiverse.inventories.profile.key.ProfileTypes;
import org.mvplugins.multiverse.inventories.share.Sharables;
import org.mvplugins.multiverse.inventories.util.PlayerStats;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicBoolean;
Expand All @@ -49,17 +47,30 @@ final class GiveCommand extends InventoriesCommand {
this.profileDataSource = profileDataSource;
}

// TODO Support custom gamemode when gamemode profile is enabled
// TODO Better offline player parsing
@Subcommand("give")
@CommandPermission("multiverse.inventories.give")
@CommandCompletion("@players @mvworlds:scope=both @materials @range:64")
@Syntax("<player> <world> <item> [amount]")
@CommandCompletion("@players " +
"@mvworlds:scope=both " +
"@mvinvprofiletypes:checkPermissions=@mvinv-gamemode-profile-true|@materials:checkPermissions=@mvinv-gamemode-profile-false " +
"@materials:checkPermissions=@mvinv-gamemode-profile-true|@range:64,checkPermissions=@mvinv-gamemode-profile-false " +
"@range:64,checkPermissions=@mvinv-gamemode-profile-true|@empty " +
"@empty")
@Syntax("<player> <world> [gamemode] <item> [amount]")
@Description("World and Group Information")
void onGiveCommand(
MVCommandIssuer issuer,

@Syntax("<player>")
OfflinePlayer player,

@Syntax("<world>")
MultiverseWorld world,

@Syntax("[gamemode]")
ProfileType profileType,

@Syntax("<item> [amount]")
String item
) {
ItemStack itemStack = parseItemFromString(issuer, item);
Expand All @@ -69,16 +80,16 @@ void onGiveCommand(
Logging.finer("Giving player " + player.getName() + " item: " + itemStack);

// Giving online player in same world
// TODO check for gamemode as well if gamemode-profile is enabled.
Player onlinePlayer = player.getPlayer();
if (onlinePlayer != null && world.getName().equals(onlinePlayer.getWorld().getName())) {
if (onlinePlayer != null
&& world.getName().equals(onlinePlayer.getWorld().getName())
&& ProfileTypes.forPlayer(onlinePlayer).equals(profileType)) {
onlinePlayer.getInventory().addItem(itemStack);
issuer.sendInfo("Gave player %s %s %s in world %s."
.formatted(player.getName(), itemStack.getAmount(), itemStack, world.getName()));
return;
}

ProfileType profileType = ProfileTypes.getDefault();
SingleShareReader.of(inventories, player, world.getName(), profileType, Sharables.INVENTORY)
.read()
.thenCompose(inventory -> updatePlayerInventory(issuer, player, world, profileType, inventory, itemStack))
Expand All @@ -88,7 +99,7 @@ void onGiveCommand(
});
}

private ItemStack parseItemFromString(MVCommandIssuer issuer, String item) {
private @Nullable ItemStack parseItemFromString(MVCommandIssuer issuer, String item) {
// Get amount
int amount = 1;
AtomicBoolean endIsAmount = new AtomicBoolean(false);
Expand Down Expand Up @@ -137,8 +148,8 @@ private CompletableFuture<Void> updatePlayerInventory(
OfflinePlayer player,
MultiverseWorld world,
ProfileType profileType,
ItemStack[] inventory,
ItemStack itemStack
@Nullable ItemStack[] inventory,
@NotNull ItemStack itemStack
) {
putItemInInventory(inventory, itemStack);
return SingleShareWriter.of(inventories, player, world.getName(), profileType, Sharables.INVENTORY)
Expand All @@ -150,7 +161,10 @@ private CompletableFuture<Void> updatePlayerInventory(
.formatted(player.getName(), itemStack.getAmount(), itemStack.getI18NDisplayName(), world.getName())));
}

private void putItemInInventory(ItemStack[] inventory, ItemStack itemStack) {
private void putItemInInventory(@Nullable ItemStack[] inventory, @NotNull ItemStack itemStack) {
if (inventory == null) {
inventory = new ItemStack[PlayerStats.INVENTORY_SIZE];
}
int amountLeft = itemStack.getAmount();
for (int i = 0; i < inventory.length; i++) {
if (inventory[i] == null || inventory[i].getType() == Material.AIR) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.mvplugins.multiverse.inventories.commands.bulkedit;

import org.jetbrains.annotations.ApiStatus;
import org.mvplugins.multiverse.core.command.MVCommandIssuer;
import org.mvplugins.multiverse.core.utils.StringFormatter;
import org.mvplugins.multiverse.inventories.commands.InventoriesCommand;
import org.mvplugins.multiverse.inventories.profile.bulkedit.action.BulkEditAction;
import org.mvplugins.multiverse.inventories.profile.bulkedit.action.BulkEditResult;

@ApiStatus.Internal
public abstract class BulkEditCommand extends InventoriesCommand {

protected void outputActionSummary(MVCommandIssuer issuer, BulkEditAction<?> bulkEditAction) {
issuer.sendMessage("Summary of affected profiles:");
bulkEditAction.getActionSummary().forEach((key, value) ->
issuer.sendMessage(" %s: %s".formatted(key, value.size() > 10
? value.size()
: StringFormatter.join(value, ", "))));

}

protected void runBulkEditAction(MVCommandIssuer issuer, BulkEditAction<?> bulkEditAction) {
issuer.sendMessage("Starting bulk edit action...");
bulkEditAction.execute()
.thenAccept(result -> outputResult(issuer, result));
}

protected void outputResult(MVCommandIssuer issuer, BulkEditResult bulkEditResult) {
issuer.sendMessage("Successfully processed %d profiles!".formatted(bulkEditResult.getSuccessCount()));
if (bulkEditResult.getFailureCount() > 0) {
issuer.sendError("Failed to process %d profiles! See log for details.".formatted(bulkEditResult.getFailureCount()));
}
issuer.sendMessage("Bulk edit action completed in %.4f ms.".formatted(bulkEditResult.getTimeTaken()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ void onCommand(
}

private void doClear(MVCommandIssuer issuer, GlobalProfileKey[] globalProfileKeys, boolean clearPlayerProfile) {
//TODO: Check lastWorld and online
CompletableFuture[] futures = Arrays.stream(globalProfileKeys)
.map(globalProfileKey -> profileDataSource.deleteGlobalProfile(globalProfileKey, clearPlayerProfile))
.toArray(CompletableFuture[]::new);
Expand Down
Loading