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
8 changes: 8 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ repositories {
url = uri('https://repo.codemc.org/repository/maven-releases')
}

maven {
name = "helpchatRepoReleases"
url = uri("https://repo.helpch.at/releases/")
}

maven {
name = 'benwoo1110'
url = uri('https://repo.c0ding.party/multiverse-beta')
Expand Down Expand Up @@ -45,6 +50,9 @@ dependencies {
// Caching
shadowed("com.github.ben-manes.caffeine:caffeine:3.2.0")

// PlaceholderAPI
externalPlugin 'me.clip:placeholderapi:2.11.6'

// Luckperms for group context
compileOnly 'net.luckperms:api:5.4'

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,14 @@ public final void onEnable() {
this.setUpLocales();
this.registerCommands();
this.registerDestinations();
this.setupMetrics();

// Hook plugins that can be imported from
this.hookImportables();

// Init other extensions
this.hookLuckPerms();
this.loadPlaceholderApiIntegration();
this.setupMetrics();
this.dupingPatch = InventoriesDupingPatch.enableDupingPatch(this);
this.playerNamesMapperProvider.get().loadMap();

Expand Down Expand Up @@ -185,6 +186,22 @@ private void hookLuckPerms() {
});
}

/**
* Setup placeholder api hook
*/
private void loadPlaceholderApiIntegration() {
if (!inventoriesConfig.get().getRegisterPapiHook()) {
return;
}
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
Try.run(() -> serviceLocator.getService(PlaceholderExpansionHook.class))
.onFailure(e -> {
Logging.severe("Failed to load PlaceholderAPI integration.");
e.printStackTrace();
});
}
}

/**
* Setup bstats Metrics.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package org.mvplugins.multiverse.inventories;

import com.google.common.collect.Lists;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.utils.REPatterns;
import org.mvplugins.multiverse.core.utils.StringFormatter;
import org.mvplugins.multiverse.external.jakarta.annotation.PostConstruct;
import org.mvplugins.multiverse.external.jakarta.inject.Inject;
import org.mvplugins.multiverse.inventories.profile.group.WorldGroup;
import org.mvplugins.multiverse.inventories.profile.group.WorldGroupManager;

import java.util.List;
import java.util.Objects;

@Service
final class PlaceholderExpansionHook extends PlaceholderExpansion {

private final MultiverseInventories plugin;
private final WorldGroupManager worldGroupManager;

@Inject
PlaceholderExpansionHook(@NotNull MultiverseInventories plugin, @NotNull WorldGroupManager worldGroupManager) {
this.plugin = plugin;
this.worldGroupManager = worldGroupManager;
}

@PostConstruct
@Override
public boolean register() {
return super.register();
}

@NotNull
@Override
public String getIdentifier() {
return "multiverse-inventories";
}

@NotNull
@Override
public String getAuthor() {
return StringFormatter.joinAnd(plugin.getDescription().getAuthors());
}

@NotNull
@Override
public String getVersion() {
return plugin.getDescription().getVersion();
}

@Override
public @Nullable String onRequest(OfflinePlayer offlinePlayer, @NotNull String params) {
List<String> paramsArray = Lists.newArrayList(REPatterns.UNDERSCORE.split(params));
if (paramsArray.isEmpty() || paramsArray.size() < 2) {
warning("Placeholder has too little parameters: " + params);
return null;
}

return switch (paramsArray.get(0)) {
case "world" -> worldPlaceholders(offlinePlayer, paramsArray);
case "group" -> groupPlaceholders(offlinePlayer, paramsArray);
default -> {
warning("Unknown placeholder: " + paramsArray.get(0));
yield null;
}
};
}

private String worldPlaceholders(OfflinePlayer offlinePlayer, List<String> paramsArray) {
String world = null;
if (paramsArray.size() > 2) {
world = paramsArray.get(paramsArray.size() - 1);
}
if (offlinePlayer instanceof Player player) {
world = player.getWorld().getName();
}

if (world == null) {
warning("Please specify a world name to use with this placeholder.");
return null;
}

return switch (paramsArray.get(1)) {
case "groups" -> StringFormatter.join(worldGroupManager.getGroupsForWorld(world).stream()
.map(WorldGroup::getName)
.toList(), ", ");
case "groupcount" -> String.valueOf(worldGroupManager.getGroupsForWorld(world).size());
default -> {
warning("Unknown world placeholder arg: " + paramsArray.get(1));
yield null;
}
};
}

private String groupPlaceholders(OfflinePlayer offlinePlayer, List<String> paramsArray) {
WorldGroup group = null;
if (paramsArray.size() > 2) {
group = worldGroupManager.getGroup(paramsArray.get(paramsArray.size() - 1));
if (group == null) {
warning("Group not found: " + paramsArray.get(paramsArray.size() - 1));
return null;
}
} else if (offlinePlayer instanceof Player player) {
group = worldGroupManager.getGroupsForWorld(player.getWorld().getName())
.stream()
.findFirst()
.orElse(null);
if (group == null) {
return "ungrouped world";
}
}

if (group == null) {
warning("Please specify a group name to use with this placeholder.");
return null;
}

return getGroupPlaceholderValue(group, paramsArray.get(1));
}

private String getGroupPlaceholderValue(WorldGroup worldGroup, String placeholder) {
return switch (placeholder) {
case "name" -> worldGroup.getName();
case "worlds" -> StringFormatter.join(worldGroup.getWorlds(), ", ");
case "shares" -> StringFormatter.join(worldGroup.getShares().toStringList(), ", ");
case "players" -> StringFormatter.join(worldGroup.getWorlds().stream()
.map(Bukkit::getWorld)
.filter(Objects::nonNull)
.flatMap(world -> world.getPlayers().stream().map(Player::getName))
.toList(), ", ");
case "playercount" -> worldGroup.getWorlds().stream()
.map(Bukkit::getWorld)
.filter(Objects::nonNull)
.map(World::getPlayers)
.map(List::size)
.reduce(Integer::sum)
.orElse(0)
.toString();
default -> {
warning("Unknown group placeholder arg: " + placeholder);
yield null;
}
};
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.mvplugins.multiverse.inventories.config;

import com.dumptruckman.minecraft.util.Logging;
import org.jetbrains.annotations.ApiStatus;
import org.jvnet.hk2.annotations.Service;
import org.mvplugins.multiverse.core.config.handle.CommentedConfigurationHandle;
import org.mvplugins.multiverse.core.config.handle.StringPropertyHandle;
Expand Down Expand Up @@ -255,6 +256,31 @@ public Try<Void> setGlobalProfileCacheExpiry(int globalProfileCacheExpiry) {
return this.configHandle.set(configNodes.globalProfileCacheExpiry, globalProfileCacheExpiry);
}

/**
* Get the value of registerPapiHook
*
* @return The value of registerPapiHook
*
* @since 5.1
*/
@ApiStatus.AvailableSince("5.1")
public boolean getRegisterPapiHook() {
return this.configHandle.get(configNodes.registerPapiHook);
}

/**
* Sets the value of registerPapiHook
*
* @param registerPapiHook The value of registerPapiHook
* @return The result of the operation
*
* @since 5.1
*/
@ApiStatus.AvailableSince("5.1")
public Try<Void> setRegisterPapiHook(boolean registerPapiHook) {
return this.configHandle.set(configNodes.registerPapiHook, registerPapiHook);
}

/**
* Tells whether this is the first time the plugin has run as set by a config flag.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ public Object serialize(Shares sharables, Class<Shares> aClass) {
.name("global-profile-cache-expiry")
.build());

private final ConfigHeaderNode miscHeader = node(ConfigHeaderNode.builder("misc")
.comment("")
.comment("")
.build());

final ConfigNode<Boolean> registerPapiHook = node(ConfigNode.builder("misc.register-papi-hook", Boolean.class)
.comment("This config option defines whether or not Multiverse should register the PlaceholderAPI hook.")
.comment("This only applies if PlaceholderAPI is installed.")
.defaultValue(true)
.name("register-papi-hook")
.build());

final ConfigNode<Boolean> firstRun = node(ConfigNode.builder("first-run", Boolean.class)
.comment("")
.comment("")
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ api-version: 1.13
authors: ['dumptruckman', 'benwoo1110']
website: 'https://dev.bukkit.org/projects/multiverse-inventories'
depend: ['Multiverse-Core']
softdepend: [LuckPerms, MultiInv, WorldInventories, PerWorldInventory]
softdepend: [LuckPerms, PlaceholderAPI, MultiInv, WorldInventories, PerWorldInventory]
3 changes: 3 additions & 0 deletions src/test/resources/config/fresh_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,8 @@ performance:
global-profile-cache-size: 500
global-profile-cache-expiry: 60

misc:
register-papi-hook: true

first-run: true
version: 5.0
3 changes: 3 additions & 0 deletions src/test/resources/config/migrated_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,8 @@ performance:
global-profile-cache-size: 500
global-profile-cache-expiry: 60

misc:
register-papi-hook: true

first-run: true
version: 5.0