2 Commits

Author SHA1 Message Date
henrique fe66b8aa8f Port to Paper 26.3 (2.1.0)
Built against paper-api 26.3.build.140-beta on Java 25, api-version 26.3,
version 2.1.0 so the jar reports the number Modrinth shows. Release notes
are in the 2.1.0 section of the Modrinth changelog.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-01 16:41:55 +01:00
henrique cfc2efc9a5 Port to Paper 26.2 (2.0.0)
Snapshot of the 26.2 port published on Modrinth as 2.0.0 on 2026-08-06.
Built against paper-api 26.2.build.100-stable on Java 25. The changes had
only lived in the working tree on HPDebian (/root/mc-26.2/repos); this
commit records them as they were shipped. Details are in the 2.0.0 section
of the Modrinth changelog.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-30 16:35:33 +01:00
92 changed files with 406 additions and 1295 deletions
+26
View File
@@ -5,6 +5,32 @@ All notable changes to CommunityMarket will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.1.0] - 2026-10-01
Requires Minecraft 26.3 and Java 25. On 26.2 use 2.0.0; on 1.21.x use the 1.x release.
### Changed
- Built against Paper 26.3 on Java 25 and tested on Paper 26.3 build 140, which Paper still marks as beta: there was no stable 26.3 build when this was released. `api-version` is now `26.3`.
- The plugin now reports version 2.1.0. The 2.0.0 jar reported `1.0.0`.
- Checked against 26.3: no new item holds other items, so the container checks from 2.0.0 cover the new content unchanged.
## [2.0.0] - 2026-08-06
Requires Minecraft 26.2 and Java 25. This release does not run on 1.21.x; upgrade the server before installing it.
### Fixed
- Listing more than one stack could hand the buyer nothing. The quantity selector let a player list everything they held, so five stacks of dirt became a single count of 320, and from 26.1 a stack larger than its own maximum is read as empty. The purchase, the refund on a failed listing, the return on cancel or expiry, and claim storage were each a place where the player received an empty slot. Items are split into legal stacks before they are given or taken now, and every leftover is delivered instead of only the first.
- The same count rendered as a blank slot in Browse Market, My Listings and the quantity selector. Icon counts are clamped, and against the item's real maximum: items that stack to 16 or to 1 were treated as stacking to 64.
- Blacklisted materials and blacklisted name or lore keywords could be listed or auctioned inside a shulker box, a bundle or a loaded sulfur cube bucket, because only the outer item was checked. Every rule now applies to the container and to everything inside it, three levels deep, and listing and auction creation both run the same check before anything is written, so no path can skip it. A container holding ordinary items is still tradeable.
### Changed
- Built against Paper 26.2 on Java 25.
- Listings already stored with an oversized count keep it and are split when they are handed out, so no database migration is needed.
- Unchanged, and worth knowing before installing: CommunityMarket reads only Vault and EssentialsX economies. It has no MultiBank provider and disables itself when neither is present.
## [1.0.0] - 2026-01-15 ## [1.0.0] - 2026-01-15
### Added ### Added
+8 -8
View File
@@ -4,7 +4,7 @@
<groupId>pt.henrique</groupId> <groupId>pt.henrique</groupId>
<artifactId>communitymarket</artifactId> <artifactId>communitymarket</artifactId>
<name>CommunityMarket</name> <name>CommunityMarket</name>
<version>1.0.0</version> <version>2.1.0</version>
<description>A comprehensive player-to-player marketplace plugin with sales, auctions, and negotiations</description> <description>A comprehensive player-to-player marketplace plugin with sales, auctions, and negotiations</description>
<build> <build>
<resources> <resources>
@@ -18,13 +18,13 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version> <version>3.12.1</version>
<configuration> <configuration>
<source>21</source> <source>25</source>
<target>21</target> <target>25</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version> <version>3.6.2</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -72,7 +72,7 @@
<dependency> <dependency>
<groupId>io.papermc.paper</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId> <artifactId>paper-api</artifactId>
<version>1.21.1-R0.1-SNAPSHOT</version> <version>26.3.build.140-beta</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@@ -83,9 +83,9 @@
</dependency> </dependency>
</dependencies> </dependencies>
<properties> <properties>
<maven.compiler.target>21</maven.compiler.target>
<maven.compiler.source>21</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<paper.version>1.21.1-R0.1-SNAPSHOT</paper.version> <paper.version>26.3.build.140-beta</paper.version>
<maven.compiler.target>25</maven.compiler.target>
<maven.compiler.source>25</maven.compiler.source>
</properties> </properties>
</project> </project>
+8 -8
View File
@@ -6,17 +6,17 @@
<groupId>pt.henrique</groupId> <groupId>pt.henrique</groupId>
<artifactId>communitymarket</artifactId> <artifactId>communitymarket</artifactId>
<version>1.0.0</version> <version>2.1.0</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>CommunityMarket</name> <name>CommunityMarket</name>
<description>A comprehensive player-to-player marketplace plugin with sales, auctions, and negotiations</description> <description>A comprehensive player-to-player marketplace plugin with sales, auctions, and negotiations</description>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>25</maven.compiler.source>
<maven.compiler.target>21</maven.compiler.target> <maven.compiler.target>25</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<paper.version>1.21.1-R0.1-SNAPSHOT</paper.version> <paper.version>26.3.build.140-beta</paper.version>
</properties> </properties>
<repositories> <repositories>
@@ -37,7 +37,7 @@
<dependency> <dependency>
<groupId>io.papermc.paper</groupId> <groupId>io.papermc.paper</groupId>
<artifactId>paper-api</artifactId> <artifactId>paper-api</artifactId>
<version>${paper.version}</version> <version>26.3.build.140-beta</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
@@ -72,15 +72,15 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.12.1</version> <version>3.12.1</version>
<configuration> <configuration>
<source>21</source> <source>25</source>
<target>21</target> <target>25</target>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.5.1</version> <version>3.6.2</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <phase>package</phase>
@@ -120,7 +120,10 @@ public class BrowseMarketGui implements MarketGui {
var msgManager = plugin.getMessageManager(); var msgManager = plugin.getMessageManager();
ItemStack display = listing.getItem().clone(); ItemStack display = listing.getItem().clone();
display.setAmount(listing.getAmount()); // Display only: a count above the max stack size makes the stack resolve to
// empty since 26.1, so the icon would render as nothing. The real amount is
// in the lore.
display.setAmount(Math.min(listing.getAmount(), Math.max(1, display.getMaxStackSize())));
// Calculate time remaining // Calculate time remaining
String expires; String expires;
@@ -382,8 +382,7 @@ public class CreateAuctionGui implements MarketGui {
// Creation failed AFTER we removed the items - give them back so nothing is lost. // Creation failed AFTER we removed the items - give them back so nothing is lost.
ItemStack refund = auctionItem.clone(); ItemStack refund = auctionItem.clone();
refund.setAmount(amount); refund.setAmount(amount);
ItemStack leftover = InventoryUtil.giveItem(player, refund); for (ItemStack leftover : InventoryUtil.giveItemSplit(player, refund)) {
if (leftover != null) {
plugin.getClaimService().addClaimItem(player.getUniqueId(), leftover, plugin.getClaimService().addClaimItem(player.getUniqueId(), leftover,
pt.henrique.communityMarket.model.ClaimItem.ClaimReason.ADMIN_RETURN, pt.henrique.communityMarket.model.ClaimItem.ClaimReason.ADMIN_RETURN,
"Auction creation failed"); "Auction creation failed");
@@ -327,8 +327,7 @@ public class CreateListingGui implements MarketGui {
// Creation failed AFTER we removed the items - give them back so nothing is lost. // Creation failed AFTER we removed the items - give them back so nothing is lost.
ItemStack refund = listItem.clone(); ItemStack refund = listItem.clone();
refund.setAmount(amount); refund.setAmount(amount);
ItemStack leftover = InventoryUtil.giveItem(player, refund); for (ItemStack leftover : InventoryUtil.giveItemSplit(player, refund)) {
if (leftover != null) {
plugin.getClaimService().addClaimItem(player.getUniqueId(), leftover, plugin.getClaimService().addClaimItem(player.getUniqueId(), leftover,
pt.henrique.communityMarket.model.ClaimItem.ClaimReason.ADMIN_RETURN, pt.henrique.communityMarket.model.ClaimItem.ClaimReason.ADMIN_RETURN,
"Listing creation failed"); "Listing creation failed");
@@ -80,7 +80,10 @@ public class MyListingsGui implements MarketGui {
var msgManager = plugin.getMessageManager(); var msgManager = plugin.getMessageManager();
ItemStack display = listing.getItem().clone(); ItemStack display = listing.getItem().clone();
display.setAmount(listing.getAmount()); // Display only: a count above the max stack size makes the stack resolve to
// empty since 26.1, so the icon would render as nothing. The real amount is
// in the lore.
display.setAmount(Math.min(listing.getAmount(), Math.max(1, display.getMaxStackSize())));
String expires; String expires;
if (listing.getExpiresAt() != null) { if (listing.getExpiresAt() != null) {
@@ -112,9 +112,10 @@ public class QuantitySelectGui implements MarketGui {
) )
.build()); .build());
// Item preview // Item preview. Clamped: a count above the max stack size renders as an
// empty slot since 26.1. The chosen quantity is shown in the lore.
ItemStack displayItem = selectedItem.clone(); ItemStack displayItem = selectedItem.clone();
displayItem.setAmount(currentQuantity); displayItem.setAmount(Math.min(currentQuantity, Math.max(1, displayItem.getMaxStackSize())));
inventory.setItem(ITEM_DISPLAY_SLOT, new ItemBuilder(displayItem) inventory.setItem(ITEM_DISPLAY_SLOT, new ItemBuilder(displayItem)
.addLore(java.util.List.of( .addLore(java.util.List.of(
"", "",
@@ -211,7 +212,7 @@ public class QuantitySelectGui implements MarketGui {
// Update item display amount // Update item display amount
ItemStack displayItem = selectedItem.clone(); ItemStack displayItem = selectedItem.clone();
displayItem.setAmount(Math.min(currentQuantity, 64)); displayItem.setAmount(Math.min(currentQuantity, Math.max(1, displayItem.getMaxStackSize())));
inventory.setItem(ITEM_DISPLAY_SLOT, new ItemBuilder(displayItem) inventory.setItem(ITEM_DISPLAY_SLOT, new ItemBuilder(displayItem)
.addLore(java.util.List.of( .addLore(java.util.List.of(
"", "",
@@ -53,7 +53,9 @@ public class AuctionService {
return CompletableFuture.completedFuture(-1); return CompletableFuture.completedFuture(-1);
} }
if (plugin.getConfigManager().isMaterialBlacklisted(item.getType())) { // Last gate before persistence: applies the blacklist to the payload too,
// so a banned material cannot enter the market inside a container.
if (!plugin.getTransactionService().validateItem(item).isValid()) {
return CompletableFuture.completedFuture(-1); return CompletableFuture.completedFuture(-1);
} }
@@ -77,9 +77,10 @@ public class ClaimService {
// Give item to player on main thread // Give item to player on main thread
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
ItemStack leftover = InventoryUtil.giveItem(player, claimItem.getItem()); // Every leftover stack is re-stored, not just the first:
if (leftover != null) { // an item stored before the split fix can be several
// This shouldn't happen since we checked space, but just in case // stacks wide and must not lose the tail.
for (ItemStack leftover : InventoryUtil.giveItemSplit(player, claimItem.getItem())) {
plugin.getDatabaseManager().addClaimItem(new ClaimItem( plugin.getDatabaseManager().addClaimItem(new ClaimItem(
player.getUniqueId(), player.getUniqueId(),
leftover, leftover,
@@ -118,8 +119,7 @@ public class ClaimService {
ItemStack itemToGive = item.getItem(); ItemStack itemToGive = item.getItem();
ClaimItem source = item; ClaimItem source = item;
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
ItemStack leftover = InventoryUtil.giveItem(player, itemToGive); for (ItemStack leftover : InventoryUtil.giveItemSplit(player, itemToGive)) {
if (leftover != null) {
// Inventory filled up mid-claim: put the remainder back into // Inventory filled up mid-claim: put the remainder back into
// claim storage instead of silently destroying the items. // claim storage instead of silently destroying the items.
plugin.getDatabaseManager().addClaimItem(new ClaimItem( plugin.getDatabaseManager().addClaimItem(new ClaimItem(
@@ -52,7 +52,9 @@ public class ListingService {
return CompletableFuture.completedFuture(-1); return CompletableFuture.completedFuture(-1);
} }
if (plugin.getConfigManager().isMaterialBlacklisted(item.getType())) { // Last gate before persistence: applies the blacklist to the payload too,
// so a banned material cannot enter the market inside a container.
if (!plugin.getTransactionService().validateItem(item).isValid()) {
return CompletableFuture.completedFuture(-1); return CompletableFuture.completedFuture(-1);
} }
@@ -229,17 +231,19 @@ public class ListingService {
Bukkit.getScheduler().runTask(plugin, () -> { Bukkit.getScheduler().runTask(plugin, () -> {
ItemStack item = listing.getItem().clone(); ItemStack item = listing.getItem().clone();
item.setAmount(listing.getAmount()); item.setAmount(listing.getAmount());
ItemStack leftover = InventoryUtil.giveItem(buyer, item); java.util.List<ItemStack> leftovers = InventoryUtil.giveItemSplit(buyer, item);
if (leftover != null) { if (!leftovers.isEmpty()) {
// Couldn't fit in inventory, add to claim storage // Couldn't fit in inventory, add to claim storage.
ClaimItem claimItem = new ClaimItem( // Every leftover stack is stored, not just the first.
buyer.getUniqueId(), for (ItemStack leftover : leftovers) {
leftover, plugin.getDatabaseManager().addClaimItem(new ClaimItem(
ClaimItem.ClaimReason.PURCHASE_FULL_INVENTORY, buyer.getUniqueId(),
"Listing #" + listingId leftover,
); ClaimItem.ClaimReason.PURCHASE_FULL_INVENTORY,
plugin.getDatabaseManager().addClaimItem(claimItem); "Listing #" + listingId
));
}
buyer.sendMessage(plugin.getMessageManager().getPrefixed("messages.claim-inventory-full")); buyer.sendMessage(plugin.getMessageManager().getPrefixed("messages.claim-inventory-full"));
} }
}); });
@@ -3,6 +3,7 @@ package pt.henrique.communityMarket.service;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import pt.henrique.communityMarket.CommunityMarket; import pt.henrique.communityMarket.CommunityMarket;
import pt.henrique.communityMarket.util.ContainerItemUtil;
import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletableFuture;
@@ -22,6 +23,11 @@ public class TransactionService {
/** /**
* Validates an item before it can be listed or auctioned. * Validates an item before it can be listed or auctioned.
* Checks material blacklist, keywords in name/lore, and other restrictions. * Checks material blacklist, keywords in name/lore, and other restrictions.
* <p>
* Prices here are set by the seller and the item is transferred intact, so a
* loaded container is not refused. What is refused is a banned material or a
* banned lore keyword hidden inside a shulker box, a bundle, a sulfur cube
* bucket or a crossbow, so every rule is applied to the payload as well.
* *
* @param item The item to validate * @param item The item to validate
* @return ValidationResult with success status and error message if applicable * @return ValidationResult with success status and error message if applicable
@@ -31,6 +37,23 @@ public class TransactionService {
return new ValidationResult(false, "invalid-item"); return new ValidationResult(false, "invalid-item");
} }
ValidationResult own = validateSingleStack(item);
if (!own.isValid()) return own;
for (ItemStack nested : ContainerItemUtil.flattenPayload(item)) {
ValidationResult inner = validateSingleStack(nested);
if (!inner.isValid()) return inner;
}
return new ValidationResult(true, null);
}
/** Applies the blacklist rules to one stack, ignoring anything it contains. */
private ValidationResult validateSingleStack(ItemStack item) {
if (item == null || item.getType().isAir()) {
return new ValidationResult(true, null);
}
// Check material blacklist // Check material blacklist
if (plugin.getConfigManager().isMaterialBlacklisted(item.getType())) { if (plugin.getConfigManager().isMaterialBlacklisted(item.getType())) {
return new ValidationResult(false, "blacklisted-item"); return new ValidationResult(false, "blacklisted-item");
@@ -0,0 +1,227 @@
package pt.henrique.communityMarket.util;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.BundleContents;
import io.papermc.paper.datacomponent.item.ChargedProjectiles;
import io.papermc.paper.datacomponent.item.ItemContainerContents;
import io.papermc.paper.datacomponent.item.SulfurCubeContent;
import org.bukkit.block.ShulkerBox;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.BlockStateMeta;
import org.bukkit.inventory.meta.BundleMeta;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
/**
* Single answer to "does this stack contain other stacks, and if so which ones".
* <p>
* As of 26.2 an {@link ItemStack} can carry other stacks in four distinct ways,
* none of which share an API:
* <ol>
* <li>Shulker boxes and other block-entity items: {@link BlockStateMeta} whose
* block state is a container, or the {@code minecraft:container} component.</li>
* <li>Bundles: {@link BundleMeta#getItems()} / {@code minecraft:bundle_contents}.</li>
* <li>{@code SULFUR_CUBE_BUCKET}: {@code minecraft:sulfur_cube_content}, reached
* through {@link SulfurCubeContent#absorbedItem()}. Neither a
* {@link BlockStateMeta} nor a {@link BundleMeta}.</li>
* <li>Crossbows: {@code minecraft:charged_projectiles}.</li>
* </ol>
* The server's own {@code ItemStack.validateComponents} recurses into
* {@code CONTAINER}, {@code BUNDLE_CONTENTS} and {@code CHARGED_PROJECTILES} but
* <b>not</b> {@code SULFUR_CUBE_CONTENT}, so a sulfur cube bucket payload is never
* sanitised by the server. Every pricing, selling, listing and anti-dupe check must
* go through {@link #payloadOf(ItemStack)} rather than testing for a shulker box.
* <p>
* The shulker-box read/rewrite helpers below stay shulker-specific: they back the
* three-option shulker sell flow, which needs the 27-slot inventory shape. Buckets,
* bundles and crossbows have no such shape and are never opened, only refused.
*/
public final class ContainerItemUtil {
/** Number of slots inside a shulker box. */
public static final int SHULKER_SIZE = 27;
/**
* Levels of nesting inspected by {@link #flattenPayload(ItemStack)}.
* Vanilla forbids shulker-in-shulker, so one level is enough today; the cap
* exists so a datapack or plugin that deepens the nesting cannot walk past
* the guard, and so a malformed cyclic payload cannot loop forever.
*/
public static final int MAX_NESTING_DEPTH = 3;
private ContainerItemUtil() {}
// ══════════════════════════════════════════════════════════════
// General nesting
// ══════════════════════════════════════════════════════════════
/**
* Returns the stacks held directly inside this one, across all four nesting
* classes. Empty when the stack holds nothing or is not a container.
* The returned stacks are the live snapshots handed back by the API; callers
* that keep them should clone.
*/
public static List<ItemStack> payloadOf(ItemStack stack) {
if (stack == null || stack.getType().isAir()) return List.of();
List<ItemStack> out = new ArrayList<>();
// getItemMeta() clones, and this runs once per inventory slot in the sell
// scans, so the meta routes are gated on the type name first. The component
// checks below are cheap map lookups and cover everything the gate misses,
// including block-entity items that are not shulker boxes.
String typeName = stack.getType().name();
if (typeName.endsWith("SHULKER_BOX")) {
if (stack.getItemMeta() instanceof BlockStateMeta bsm
&& bsm.getBlockState() instanceof ShulkerBox box) {
addNonEmpty(out, box.getInventory().getContents());
}
} else if (typeName.endsWith("BUNDLE")) {
if (stack.getItemMeta() instanceof BundleMeta bundle) {
addNonEmpty(out, bundle.getItems());
}
}
if (out.isEmpty() && stack.hasData(DataComponentTypes.CONTAINER)) {
ItemContainerContents container = stack.getData(DataComponentTypes.CONTAINER);
if (container != null) addNonEmpty(out, container.contents());
}
if (out.isEmpty() && stack.hasData(DataComponentTypes.BUNDLE_CONTENTS)) {
BundleContents bundle = stack.getData(DataComponentTypes.BUNDLE_CONTENTS);
if (bundle != null) addNonEmpty(out, bundle.contents());
}
if (stack.hasData(DataComponentTypes.SULFUR_CUBE_CONTENT)) {
SulfurCubeContent cube = stack.getData(DataComponentTypes.SULFUR_CUBE_CONTENT);
if (cube != null) addNonEmpty(out, List.of(cube.absorbedItem()));
}
if (stack.hasData(DataComponentTypes.CHARGED_PROJECTILES)) {
ChargedProjectiles charged = stack.getData(DataComponentTypes.CHARGED_PROJECTILES);
if (charged != null) addNonEmpty(out, charged.projectiles());
}
return out;
}
/**
* True when this stack carries other stacks. Such items are refused by every
* server-shop path: their payload has no price and would be destroyed with the
* container, and a container priced as empty is a value-laundering route.
*/
public static boolean isNestingItemWithContents(ItemStack stack) {
return !payloadOf(stack).isEmpty();
}
/**
* Every stack reachable from this one, breadth-first, down to
* {@link #MAX_NESTING_DEPTH} levels. The stack itself is not included.
* Used by the blacklist checks, which must see a banned material or a banned
* lore keyword wherever it is hidden.
*/
public static List<ItemStack> flattenPayload(ItemStack stack) {
List<ItemStack> out = new ArrayList<>();
Deque<ItemStack> frontier = new ArrayDeque<>(payloadOf(stack));
int depth = 0;
while (!frontier.isEmpty() && depth < MAX_NESTING_DEPTH) {
int levelSize = frontier.size();
for (int i = 0; i < levelSize; i++) {
ItemStack current = frontier.poll();
if (current == null) continue;
out.add(current);
if (depth + 1 < MAX_NESTING_DEPTH) frontier.addAll(payloadOf(current));
}
depth++;
}
return out;
}
/** Total number of items (summed amounts) held inside this stack, one level deep. */
public static int countTotalItems(ItemStack stack) {
int total = 0;
for (ItemStack c : payloadOf(stack)) total += c.getAmount();
return total;
}
/** Number of occupied slots inside this stack, one level deep. */
public static int countNonEmptySlots(ItemStack stack) {
return payloadOf(stack).size();
}
// ══════════════════════════════════════════════════════════════
// Shulker boxes: read and rewrite
// ══════════════════════════════════════════════════════════════
/** @return true if the stack is any shulker box (all 16 colors + uncolored). */
public static boolean isShulkerBox(ItemStack stack) {
return stack != null && !stack.getType().isAir()
&& stack.getType().name().endsWith("SHULKER_BOX");
}
/**
* Returns the shulker's internal contents as a detached snapshot array.
* {@code getBlockState()} returns a copy, so reading never mutates the original
* item. Returns an empty array if the stack is not a shulker box.
*/
public static ItemStack[] getContents(ItemStack shulker) {
if (!isShulkerBox(shulker)) return new ItemStack[0];
if (!(shulker.getItemMeta() instanceof BlockStateMeta bsm)) return new ItemStack[0];
if (!(bsm.getBlockState() instanceof ShulkerBox box)) return new ItemStack[0];
return box.getInventory().getContents();
}
/** @return true if the shulker box contains at least one item. */
public static boolean hasContents(ItemStack shulker) {
for (ItemStack c : getContents(shulker)) {
if (c != null && !c.getType().isAir()) return true;
}
return false;
}
/** Returns a clone of the shulker with its internal inventory emptied. */
public static ItemStack emptiedClone(ItemStack shulker) {
ItemStack clone = shulker.clone();
if (clone.getItemMeta() instanceof BlockStateMeta bsm
&& bsm.getBlockState() instanceof ShulkerBox box) {
box.getInventory().clear();
bsm.setBlockState(box);
clone.setItemMeta(bsm);
}
return clone;
}
/**
* Returns a clone of the shulker whose internal contents are replaced by the
* given array (length must be at most {@link #SHULKER_SIZE}; shorter arrays
* clear the remaining slots).
*/
public static ItemStack withContents(ItemStack shulker, ItemStack[] newContents) {
ItemStack clone = shulker.clone();
if (clone.getItemMeta() instanceof BlockStateMeta bsm
&& bsm.getBlockState() instanceof ShulkerBox box) {
box.getInventory().setContents(newContents);
bsm.setBlockState(box);
clone.setItemMeta(bsm);
}
return clone;
}
// ══════════════════════════════════════════════════════════════
// Helpers
// ══════════════════════════════════════════════════════════════
private static void addNonEmpty(List<ItemStack> out, ItemStack[] items) {
if (items == null) return;
for (ItemStack i : items) {
if (i != null && !i.getType().isAir()) out.add(i);
}
}
private static void addNonEmpty(List<ItemStack> out, List<ItemStack> items) {
if (items == null) return;
for (ItemStack i : items) {
if (i != null && !i.getType().isAir()) out.add(i);
}
}
}
@@ -6,6 +6,7 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import pt.henrique.communityMarket.CommunityMarket; import pt.henrique.communityMarket.CommunityMarket;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -51,24 +52,73 @@ public class InventoryUtil {
} }
/** /**
* Gives an item to a player, returning any items that couldn't fit * Splits a stack into legally-sized stacks.
* <p>
* Since 26.1 an {@link ItemStack} whose count exceeds its max stack size is
* treated as empty by the server, so a "give 320 dirt" shortcut built as one
* stack hands the player nothing. Anything that multiplies a quantity into a
* single stack must route through this first. The input amount is used as the
* total; the returned stacks are clones.
*
* @return one or more stacks, each within its max stack size; empty for air
*/
public static List<ItemStack> splitIntoLegalStacks(ItemStack item) {
if (item == null || item.getType().isAir() || item.getAmount() <= 0) {
return List.of();
}
int maxStack = Math.max(1, item.getMaxStackSize());
if (item.getAmount() <= maxStack) {
return List.of(item.clone());
}
List<ItemStack> out = new ArrayList<>();
for (int left = item.getAmount(); left > 0; left -= maxStack) {
ItemStack part = item.clone();
part.setAmount(Math.min(left, maxStack));
out.add(part);
}
return out;
}
/** @return true when the stack's count is within its max stack size. */
public static boolean isLegalStack(ItemStack item) {
return item == null || item.getType().isAir()
|| item.getAmount() <= Math.max(1, item.getMaxStackSize());
}
/**
* Gives an item to a player, returning any items that couldn't fit.
* The item is split into legal stacks first, so an oversized input is handed
* over in full instead of resolving to nothing.
* *
* @param player The player * @param player The player
* @param item The item to give * @param item The item to give
* @return Items that couldn't fit, or null if all items were added * @return Items that couldn't fit, or null if all items were added
*/ */
public static ItemStack giveItem(Player player, ItemStack item) { public static ItemStack giveItem(Player player, ItemStack item) {
if (item == null || item.getType().isAir()) { List<ItemStack> leftovers = giveItemSplit(player, item);
return null; return leftovers.isEmpty() ? null : leftovers.get(0);
}
/**
* Gives an item to a player as legal stacks.
*
* @return every stack that did not fit, each within its max stack size
*/
public static List<ItemStack> giveItemSplit(Player player, ItemStack item) {
List<ItemStack> parts = splitIntoLegalStacks(item);
if (parts.isEmpty()) {
return List.of();
} }
HashMap<Integer, ItemStack> leftover = player.getInventory().addItem(item.clone()); HashMap<Integer, ItemStack> leftover =
player.getInventory().addItem(parts.toArray(new ItemStack[0]));
if (leftover.isEmpty()) { if (leftover.isEmpty()) {
return null; return List.of();
} }
return new ArrayList<>(leftover.values());
return leftover.values().iterator().next();
} }
/** /**
@@ -87,7 +137,12 @@ public class InventoryUtil {
ItemStack toRemove = item.clone(); ItemStack toRemove = item.clone();
toRemove.setAmount(amount); toRemove.setAmount(amount);
HashMap<Integer, ItemStack> notRemoved = player.getInventory().removeItem(toRemove); // Split first: an over-full stack is treated as empty since 26.1, so a
// single oversized removal request could take nothing while reporting
// success.
List<ItemStack> parts = splitIntoLegalStacks(toRemove);
HashMap<Integer, ItemStack> notRemoved =
player.getInventory().removeItem(parts.toArray(new ItemStack[0]));
return notRemoved.isEmpty(); return notRemoved.isEmpty();
} }
@@ -38,8 +38,20 @@ public class ItemBuilder {
/** /**
* Creates a new ItemBuilder from an existing ItemStack * Creates a new ItemBuilder from an existing ItemStack
*/ */
/**
* Wraps an existing stack as a GUI icon.
* <p>
* The count is clamped to the item's max stack size. Builder output only ever
* goes into plugin GUI inventories, never to a player, and since 26.1 an
* over-full stack resolves to empty, which would render the icon as a blank
* slot. Real quantities are shown in the lore.
*/
public ItemBuilder(ItemStack item) { public ItemBuilder(ItemStack item) {
this.item = item.clone(); this.item = item.clone();
int maxStack = Math.max(1, this.item.getMaxStackSize());
if (this.item.getAmount() > maxStack) {
this.item.setAmount(maxStack);
}
this.meta = this.item.getItemMeta(); this.meta = this.item.getItemMeta();
} }
@@ -115,7 +127,7 @@ public class ItemBuilder {
* Sets the item amount * Sets the item amount
*/ */
public ItemBuilder amount(int amount) { public ItemBuilder amount(int amount) {
item.setAmount(Math.min(64, Math.max(1, amount))); item.setAmount(Math.min(Math.max(1, item.getMaxStackSize()), Math.max(1, amount)));
return this; return this;
} }
+1 -1
View File
@@ -1,7 +1,7 @@
name: CommunityMarket name: CommunityMarket
version: '${project.version}' version: '${project.version}'
main: pt.henrique.communityMarket.CommunityMarket main: pt.henrique.communityMarket.CommunityMarket
api-version: '1.21' api-version: "26.3"
description: A GUI-only marketplace plugin for fixed-price listings and auctions description: A GUI-only marketplace plugin for fixed-price listings and auctions
author: Henrique author: Henrique
website: https://github.com/henriquescrrrr/carrageis-communitymarket website: https://github.com/henriquescrrrr/carrageis-communitymarket
-152
View File
@@ -1,152 +0,0 @@
# ============================================
# CommunityMarket Configuration
# A GUI-only marketplace plugin
# ============================================
# Language setting (available: en_US, pt_PT)
language: en_US
# Database Configuration
database:
# Type: sqlite or mysql
type: sqlite
sqlite:
file: database.db
mysql:
host: localhost
port: 3306
database: communitymarket
username: root
password: ""
pool:
maximum-pool-size: 10
minimum-idle: 2
connection-timeout: 30000
idle-timeout: 600000
max-lifetime: 1800000
# Economy Settings
economy:
# Currency display format (uses Java DecimalFormat)
currency-format: "$#,##0.00"
currency-symbol: "$"
taxes:
# Tax percentage for fixed-price market sales (seller pays)
market-tax: 5.0
# Tax percentage for auction sales (seller pays)
auction-tax: 7.5
# Fixed-Price Market Settings
market:
# Maximum active listings per player
max-listings-per-player: 20
# Cooldown between creating listings (seconds, 0 = disabled)
listing-cooldown: 0
# Default listing duration in hours
default-duration-hours: 168
# Available durations for players to choose (in hours)
available-durations:
- 24
- 72
- 168
- 336
# Price limits
min-price: 1.0
max-price: 1000000000.0
# Auction Settings
auction:
# Maximum active auctions per player
max-auctions-per-player: 10
# Duration limits (hours)
min-duration-hours: 1
max-duration-hours: 168
default-duration-hours: 24
# Available durations for players to choose (in hours)
available-durations:
- 1
- 6
- 12
- 24
- 48
- 72
- 168
# Price limits for starting bid
min-start-price: 1.0
max-start-price: 1000000000.0
# Minimum bid increment (percentage of current bid)
min-bid-increment-percent: 5.0
# Minimum absolute bid increment
min-bid-increment-absolute: 1.0
# Anti-snipe protection
anti-snipe:
enabled: true
# If bid placed within this many seconds of end, extend auction
trigger-seconds: 30
# How many seconds to extend
extension-seconds: 30
# Maximum number of extensions (0 = unlimited)
max-extensions: 10
# Item Blacklist
blacklist:
# Materials that cannot be listed/auctioned
materials:
- BARRIER
- COMMAND_BLOCK
- CHAIN_COMMAND_BLOCK
- REPEATING_COMMAND_BLOCK
- COMMAND_BLOCK_MINECART
- STRUCTURE_BLOCK
- STRUCTURE_VOID
- JIGSAW
- DEBUG_STICK
- KNOWLEDGE_BOOK
- SPAWNER
- BEDROCK
# Items with these keywords in their name/lore are blocked
keywords:
- "admin"
- "illegal"
- "exploit"
# GUI Settings
gui:
# Items displayed per page in browse views
items-per-page: 45
# Whether to show the Help button in the main menu
# Set to false to hide it (slot will be filled with glass)
show-help-button: true
# Sound effects (use Bukkit Sound enum names)
sounds:
click: UI_BUTTON_CLICK
success: ENTITY_PLAYER_LEVELUP
error: ENTITY_VILLAGER_NO
purchase: ENTITY_EXPERIENCE_ORB_PICKUP
# Notification Settings
notifications:
# Notify seller when their item sells
notify-on-sale: true
# Notify bidder when they are outbid
notify-on-outbid: true
# Notify winner when they win an auction
notify-on-win: true
# Notify seller when their listing expires
notify-on-expire: true
# Performance Settings
performance:
# How often to cache listings/auctions (seconds)
cache-duration: 30
# How often to check for ended auctions (seconds)
auction-check-interval: 5
# How often to check for expired listings (minutes)
expired-check-interval: 5
-448
View File
@@ -1,448 +0,0 @@
# ============================================
# CommunityMarket Language File - English (US)
# ============================================
# General
prefix: "&8[&6Market&8] &r"
# General Messages
messages:
no-permission: "&cYou don't have permission to do that."
player-only: "&cThis command can only be used by players."
reload-success: "&aConfiguration reloaded successfully!"
economy-not-found: "&cNo economy plugin found! Market disabled."
# Listing Messages
listing-created: "&aListing created successfully! ID: #{id}"
listing-cancelled: "&aListing cancelled. Item returned to claim storage."
listing-expired: "&eYour listing #{id} has expired. Item moved to claim storage."
listing-purchased: "&aYou purchased {item} x{amount} for {price}!"
listing-sold: "&aYour {item} x{amount} was sold to {buyer} for {price}!"
listing-limit-reached: "&cYou've reached the maximum number of listings ({max})."
listing-cooldown: "&cPlease wait {time} before creating another listing."
listing-not-found: "&cListing not found or no longer available."
listing-own-item: "&cYou cannot buy your own listing."
listing-insufficient-funds: "&cYou don't have enough money. Required: {price}"
# Auction Messages
auction-created: "&aAuction created successfully! ID: #{id}"
auction-cancelled: "&aAuction cancelled. Item returned to claim storage."
auction-ended-winner: "&aCongratulations! You won the auction for {item}! Paid: {price}"
auction-ended-seller: "&aYour auction for {item} ended! Winner: {winner}, Earned: {price}"
auction-ended-no-bids: "&eYour auction for {item} ended with no bids. Item moved to claim storage."
auction-limit-reached: "&cYou've reached the maximum number of auctions ({max})."
auction-not-found: "&cAuction not found or no longer available."
auction-own-item: "&cYou cannot bid on your own auction."
auction-bid-placed: "&aYou placed a bid of {amount} on {item}!"
auction-outbid: "&eYou've been outbid on {item}! New bid: {amount} by {bidder}"
auction-bid-too-low: "&cBid too low! Minimum bid: {min}"
auction-insufficient-funds: "&cYou don't have enough money. Required: {price}"
auction-buyout: "&aYou bought out the auction for {item} for {price}!"
auction-extended: "&eAuction extended by {seconds}s due to anti-snipe protection."
# Claim Messages
claim-success: "&aItem claimed successfully!"
claim-empty: "&eYou have no items to claim."
claim-inventory-full: "&cYour inventory is full! Please make space."
claim-all-success: "&aClaimed {count} items!"
# Earnings Messages
earnings-withdrawn: "&aWithdrew {amount}! New balance: {balance}"
earnings-empty: "&eYou have no pending earnings."
earnings-balance: "&aYour pending earnings: {amount}"
# Item Validation
invalid-item: "&cPlease select a valid item."
item-no-longer-available: "&cThe selected item is no longer in your inventory."
item-changed: "&cThe selected item has changed. Please select again."
quantity-changed: "&cThe available quantity has changed. Please verify and try again."
blacklisted-item: "&cThis item type is not allowed on the market."
blacklisted-content: "&cThis item contains blacklisted content."
invalid-price: "&cInvalid price. Range: {min} - {max}"
invalid-amount: "&cInvalid amount."
invalid-duration: "&cInvalid duration."
# Admin Messages
admin-listing-removed: "&aListing #{id} removed by admin."
admin-auction-cancelled: "&aAuction #{id} cancelled by admin."
admin-reload: "&aConfiguration reloaded."
# GUI Titles (support color codes)
gui-titles:
main-menu: "&8&lCommunity Market"
browse-market: "&8&lBrowse Market &7(Page {page})"
browse-auctions: "&8&lBrowse Auctions &7(Page {page})"
create-listing: "&8&lCreate Listing"
create-auction: "&8&lCreate Auction"
select-item-listing: "&8&lSelect Item to Sell"
select-item-auction: "&8&lSelect Item to Auction"
quantity-select: "&8&lSelect Quantity"
my-listings: "&8&lMy Listings"
my-auctions: "&8&lMy Auctions"
claim-items: "&8&lClaim Items"
earnings: "&8&lEarnings"
confirm-purchase: "&8&lConfirm Purchase"
confirm-bid: "&8&lConfirm Bid"
confirm-cancel: "&8&lConfirm Cancellation"
number-input: "&8&lEnter Amount"
admin-panel: "&8&lAdmin Panel"
admin-listings: "&8&lAll Listings"
admin-auctions: "&8&lAll Auctions"
listing-details: "&8&lListing Details"
auction-details: "&8&lAuction Details"
filter-menu: "&8&lFilter Options"
sort-menu: "&8&lSort Options"
duration-select: "&8&lSelect Duration"
help: "&8&lHelp"
# Button Names
buttons:
# Main Menu
browse-market: "&aBrowse Market"
browse-auctions: "&6Browse Auctions"
create-listing: "&eCreate Listing"
create-auction: "&eCreate Auction"
my-listings: "&bMy Listings"
my-auctions: "&bMy Auctions"
claim-items: "&dClaim Items"
earnings: "&aEarnings"
help: "&fHelp"
admin: "&cAdmin Panel"
# Navigation
next-page: "&aNext Page →"
previous-page: "&a← Previous Page"
back: "&cBack"
close: "&cClose"
# Actions
confirm: "&aConfirm"
cancel: "&cCancel"
buy: "&aBuy Now"
bid: "&6Place Bid"
buyout: "&eBuyout"
claim: "&aClaim"
claim-all: "&aClaim All"
withdraw: "&aWithdraw All"
remove: "&cRemove Listing"
cancel-auction: "&cCancel Auction"
# Number Input
add-1: "&a+1"
add-10: "&a+10"
add-100: "&a+100"
add-1000: "&a+1,000"
subtract-1: "&c-1"
subtract-10: "&c-10"
subtract-100: "&c-100"
subtract-1000: "&c-1,000"
set-min: "&eSet Min"
set-max: "&eSet Max"
custom-amount: "&bCustom Amount"
# Filters & Sort
filter: "&eFilter"
sort: "&eSort"
search: "&eSearch"
clear-filter: "&cClear Filters"
# Duration
duration-1h: "&e1 Hour"
duration-6h: "&e6 Hours"
duration-12h: "&e12 Hours"
duration-24h: "&e24 Hours"
duration-48h: "&e48 Hours"
duration-72h: "&e3 Days"
duration-168h: "&e7 Days"
duration-336h: "&e14 Days"
# Admin
admin-view-listings: "&aView All Listings"
admin-view-auctions: "&6View All Auctions"
admin-reload: "&eReload Config"
# Button Lore (descriptions)
lore:
browse-market:
- "&7Browse all fixed-price"
- "&7listings from players."
- ""
- "&eClick to browse!"
browse-auctions:
- "&7Browse all active auctions"
- "&7and place bids."
- ""
- "&eClick to browse!"
create-listing:
- "&7Sell items at a fixed price."
- "&7Tax: &f{tax}%"
- ""
- "&eClick to create!"
create-auction:
- "&7Auction items to the"
- "&7highest bidder."
- "&7Tax: &f{tax}%"
- ""
- "&eClick to create!"
my-listings:
- "&7View and manage your"
- "&7active listings."
- ""
- "&7Active: &f{count}/{max}"
- ""
- "&eClick to view!"
my-auctions:
- "&7View and manage your"
- "&7active auctions."
- ""
- "&7Active: &f{count}/{max}"
- ""
- "&eClick to view!"
claim-items:
- "&7Claim items from expired"
- "&7listings or won auctions."
- ""
- "&7Pending: &f{count}"
- ""
- "&eClick to claim!"
earnings:
- "&7View and withdraw your"
- "&7pending earnings from sales."
- ""
- "&7Pending: &a{amount}"
- ""
- "&eClick to view!"
help:
- "&7Learn how to use the"
- "&7Community Market."
- ""
- "&eClick for help!"
admin:
- "&cAdmin Panel"
- "&7Manage listings and auctions."
- ""
- "&eClick to open!"
# Listing Info
listing-info:
- "&7Seller: &f{seller}"
- "&7Price: &a{price}"
- "&7Amount: &f{amount}"
- "&7Expires: &f{expires}"
- ""
- "&eLeft-click to buy!"
# Auction Info
auction-info:
- "&7Seller: &f{seller}"
- "&7Starting bid: &a{start_price}"
- "&7Current bid: &a{current_bid}"
- "&7Bidder: &f{bidder}"
- "&7Bids: &f{bid_count}"
- "&7Ends: &f{ends}"
- ""
- "&eLeft-click to bid!"
- "&eRight-click to buyout!"
# My Listing Info
my-listing-info:
- "&7Price: &a{price}"
- "&7Amount: &f{amount}"
- "&7Created: &f{created}"
- "&7Expires: &f{expires}"
- ""
- "&cClick to cancel"
# My Auction Info
my-auction-info:
- "&7Starting bid: &a{start_price}"
- "&7Current bid: &a{current_bid}"
- "&7Bidder: &f{bidder}"
- "&7Bids: &f{bid_count}"
- "&7Ends: &f{ends}"
- ""
- "&cClick to cancel (if no bids)"
# Confirm Purchase
confirm-purchase-info:
- "&7You are purchasing:"
- "&f{item} x{amount}"
- ""
- "&7Price: &a{price}"
- "&7Tax: &e{tax}"
- "&7Total: &a{total}"
- ""
- "&aClick to confirm!"
# Confirm Bid
confirm-bid-info:
- "&7You are bidding on:"
- "&f{item}"
- ""
- "&7Your bid: &a{bid}"
- "&7Current high: &e{current}"
- ""
- "&aClick to confirm!"
# Claim Item
claim-item-info:
- "&7Reason: &f{reason}"
- "&7From: &f{source}"
- "&7Date: &f{date}"
- ""
- "&eClick to claim!"
# Earnings Info
earnings-info:
- "&7Your pending earnings"
- "&7from market sales."
- ""
- "&7Total: &a{amount}"
- ""
- "&aClick to withdraw!"
# Number Input Info
current-value:
- "&7Current: &a{value}"
# Filter Options
filters:
all: "&fAll Items"
weapons: "&cWeapons"
armor: "&bArmor"
tools: "&eTools"
blocks: "&7Blocks"
food: "&6Food"
potions: "&dPotions"
materials: "&aMaterials"
enchanted: "&5Enchanted Items"
misc: "&8Miscellaneous"
# Sort Options
sort:
newest: "&aNewest First"
oldest: "&eOldest First"
price-low: "&aPrice: Low to High"
price-high: "&cPrice: High to Low"
ending-soon: "&6Ending Soon"
most-bids: "&bMost Bids"
# Time Formats
time:
expired: "&cExpired"
days: "{d}d"
hours: "{h}h"
minutes: "{m}m"
seconds: "{s}s"
# Quantity Selector GUI
quantity-select:
title: "&6&lSelect Quantity"
info-line-1: "&7Choose how many items"
info-line-2: "&7you want to sell."
available: "&7Available: &f{amount}"
selected: "&7Selected: &f{amount}"
quantity-label: "Quantity"
minimum: "&7Minimum: &f{amount}"
maximum: "&7Maximum: &f{amount}"
use-buttons: "&eUse buttons to adjust"
click-adjust: "&7Click: &e{amount}"
set-minimum: "&6Set Minimum"
set-maximum: "&6Set Maximum"
set-to: "&7Set to: &f{amount}"
back-lore: "&7Return to item selection"
confirm-lore: "&7Quantity: &a{amount}"
# Item Selection GUI
item-selection:
info-title: "&fSelect an Item"
info-lore-listing: "&7Click on an item from your|&7inventory to create a &eListing&7."
info-lore-auction: "&7Click on an item from your|&7inventory to create a &6Auction&7."
blacklisted-note: "&7Blacklisted items are shown in red."
click-to-select: "&a► Click to select"
blocked-title: "&c{material}"
blocked-lore-1: "&7This item cannot be listed."
blocked-lore-2: "&cBlacklisted or invalid."
back-lore: "&7Return to main menu"
# Create Listing GUI
create-listing:
info-title: "&6&lCreate Listing"
info-lore-1: "&7Set a price and duration"
info-lore-2: "&7for your listing."
tax-info: "&7Tax: &f{tax}%"
item-lore: "&7Quantity: &f{amount}|&eThis item will be listed"
price-title: "&6Price: {price}"
price-tax: "&7Tax ({percent}%): &c{amount}"
price-earnings: "&7You receive: &a{amount}"
price-click: "&eClick to change price"
duration-title: "&eDuration: {duration}"
duration-lore: "&7Listing expires after this time"
duration-click: "&eClick to change duration"
back-lore: "&7Return to item selection"
confirm-item: "&7Item: &f{item} x{amount}"
confirm-price: "&7Price: &a{price}"
confirm-earnings: "&7You receive: &a{amount}"
confirm-duration: "&7Duration: &e{duration}"
confirm-click: "&aClick to create listing!"
# Create Auction GUI
create-auction:
info-title: "&6&lCreate Auction"
info-lore-1: "&7Set starting price, optional buyout,"
info-lore-2: "&7and duration for your auction."
tax-info: "&7Tax on sale: &f{tax}%"
item-lore: "&7Quantity: &f{amount}|&eThis item will be auctioned"
start-price-title: "&6Starting Price: {price}"
start-price-lore-1: "&7Minimum bid to start"
start-price-lore-2: "&7the auction."
start-price-click: "&eClick to change"
buyout-title-set: "&bBuyout: {price}"
buyout-title-unset: "&bBuyout: &7Not set"
buyout-lore-set-1: "&7Instant purchase price."
buyout-lore-set-2: "&eLeft-click to change"
buyout-lore-set-3: "&cRight-click to remove"
buyout-lore-unset-1: "&7Optional instant purchase"
buyout-lore-unset-2: "&7price for your auction."
buyout-lore-unset-click: "&eClick to set buyout price"
duration-title: "&eDuration: {duration}"
duration-lore: "&7Auction ends after this time."
duration-click: "&eClick to change duration"
back-lore: "&7Return to item selection"
confirm-item: "&7Item: &f{item} x{amount}"
confirm-start: "&7Start: &a{price}"
confirm-buyout: "&7Buyout: &b{price}"
confirm-buyout-none: "&7Buyout: &7None"
confirm-duration: "&7Duration: &e{duration}"
confirm-click: "&aClick to create auction!"
# Number Input GUI
number-input:
display-title: "&6&l{value}"
minimum: "&7Minimum: &f{value}"
maximum: "&7Maximum: &f{value}"
use-buttons: "&eUse buttons to adjust"
click-adjust: "&7Click: &e{amount}"
shift-click: "&7Shift-click: &e{amount}"
set-minimum: "&6Set Minimum"
set-maximum: "&6Set Maximum"
set-to: "&7Set to: &f{value}"
cancel-lore: "&7Cancel and go back"
confirm-lore: "&7Confirm: &a{value}"
# Help Content
help:
title: "&6&lCommunity Market Help"
content:
- "&eBrowse Market &7- View and buy fixed-price listings"
- "&eBrowse Auctions &7- View and bid on auctions"
- "&eCreate Listing &7- Sell items at a fixed price"
- "&eCreate Auction &7- Auction items to highest bidder"
- "&eMy Listings &7- Manage your active listings"
- "&eMy Auctions &7- Manage your active auctions"
- "&eClaim Items &7- Collect unsold/won items"
- "&eEarnings &7- Withdraw money from sales"
- ""
- "&7&oTip: All actions are done through GUIs!"
- "&7&oJust click on buttons to navigate."
-448
View File
@@ -1,448 +0,0 @@
# ============================================
# CommunityMarket Ficheiro de Idioma - Português (Portugal)
# ============================================
# Geral
prefix: "&8[&6Mercado&8] &r"
# Mensagens Gerais
messages:
no-permission: "&cNão tens permissão para fazer isso."
player-only: "&cEste comando só pode ser usado por jogadores."
reload-success: "&aConfiguração recarregada com sucesso!"
economy-not-found: "&cNenhum plugin de economia encontrado! Mercado desativado."
# Mensagens de Anúncios
listing-created: "&aAnúncio criado com sucesso! ID: #{id}"
listing-cancelled: "&aAnúncio cancelado. Item devolvido ao armazém."
listing-expired: "&eO teu anúncio #{id} expirou. Item movido para o armazém."
listing-purchased: "&aCompraste {item} x{amount} por {price}!"
listing-sold: "&aO teu {item} x{amount} foi vendido a {buyer} por {price}!"
listing-limit-reached: "&cAtingiste o número máximo de anúncios ({max})."
listing-cooldown: "&cPor favor aguarda {time} antes de criar outro anúncio."
listing-not-found: "&cAnúncio não encontrado ou já não está disponível."
listing-own-item: "&cNão podes comprar o teu próprio anúncio."
listing-insufficient-funds: "&cNão tens dinheiro suficiente. Necessário: {price}"
# Mensagens de Leilões
auction-created: "&aLeilão criado com sucesso! ID: #{id}"
auction-cancelled: "&aLeilão cancelado. Item devolvido ao armazém."
auction-ended-winner: "&aParabéns! Ganhaste o leilão por {item}! Pagaste: {price}"
auction-ended-seller: "&aO teu leilão por {item} terminou! Vencedor: {winner}, Ganhaste: {price}"
auction-ended-no-bids: "&eO teu leilão por {item} terminou sem licitações. Item movido para o armazém."
auction-limit-reached: "&cAtingiste o número máximo de leilões ({max})."
auction-not-found: "&cLeilão não encontrado ou já não está disponível."
auction-own-item: "&cNão podes licitar no teu próprio leilão."
auction-bid-placed: "&aFizeste uma licitação de {amount} em {item}!"
auction-outbid: "&eForam feitas licitações superiores à tua em {item}! Nova licitação: {amount} por {bidder}"
auction-bid-too-low: "&cLicitação muito baixa! Mínimo: {min}"
auction-insufficient-funds: "&cNão tens dinheiro suficiente. Necessário: {price}"
auction-buyout: "&aCompraste o leilão de {item} por {price}!"
auction-extended: "&eLeilão prolongado por {seconds}s devido à proteção anti-snipe."
# Mensagens de Reclamação
claim-success: "&aItem reclamado com sucesso!"
claim-empty: "&eNão tens itens para reclamar."
claim-inventory-full: "&cO teu inventário está cheio! Por favor liberta espaço."
claim-all-success: "&aReclamaste {count} itens!"
# Mensagens de Ganhos
earnings-withdrawn: "&aLevantaste {amount}! Novo saldo: {balance}"
earnings-empty: "&eNão tens ganhos pendentes."
earnings-balance: "&aOs teus ganhos pendentes: {amount}"
# Validação de Itens
invalid-item: "&cPor favor seleciona um item válido."
item-no-longer-available: "&cO item selecionado já não está no teu inventário."
item-changed: "&cO item selecionado foi alterado. Por favor seleciona novamente."
quantity-changed: "&cA quantidade disponível foi alterada. Por favor verifica e tenta novamente."
blacklisted-item: "&cEste tipo de item não é permitido no mercado."
blacklisted-content: "&cEste item contém conteúdo bloqueado."
invalid-price: "&cPreço inválido. Intervalo: {min} - {max}"
invalid-amount: "&cQuantidade inválida."
invalid-duration: "&cDuração inválida."
# Mensagens de Admin
admin-listing-removed: "&aAnúncio #{id} removido pelo admin."
admin-auction-cancelled: "&aLeilão #{id} cancelado pelo admin."
admin-reload: "&aConfiguração recarregada."
# Títulos GUI (suportam códigos de cor)
gui-titles:
main-menu: "&8&lMercado Comunitário"
browse-market: "&8&lExplorar Mercado &7(Página {page})"
browse-auctions: "&8&lExplorar Leilões &7(Página {page})"
create-listing: "&8&lCriar Anúncio"
create-auction: "&8&lCriar Leilão"
select-item-listing: "&8&lSelecionar Item para Vender"
select-item-auction: "&8&lSelecionar Item para Leilão"
quantity-select: "&8&lSelecionar Quantidade"
my-listings: "&8&lOs Meus Anúncios"
my-auctions: "&8&lOs Meus Leilões"
claim-items: "&8&lReclamar Itens"
earnings: "&8&lGanhos"
confirm-purchase: "&8&lConfirmar Compra"
confirm-bid: "&8&lConfirmar Licitação"
confirm-cancel: "&8&lConfirmar Cancelamento"
number-input: "&8&lIntroduzir Valor"
admin-panel: "&8&lPainel de Admin"
admin-listings: "&8&lTodos os Anúncios"
admin-auctions: "&8&lTodos os Leilões"
listing-details: "&8&lDetalhes do Anúncio"
auction-details: "&8&lDetalhes do Leilão"
filter-menu: "&8&lOpções de Filtro"
sort-menu: "&8&lOpções de Ordenação"
duration-select: "&8&lSelecionar Duração"
help: "&8&lAjuda"
# Nomes dos Botões
buttons:
# Menu Principal
browse-market: "&aExplorar Mercado"
browse-auctions: "&6Explorar Leilões"
create-listing: "&eCriar Anúncio"
create-auction: "&eCriar Leilão"
my-listings: "&bOs Meus Anúncios"
my-auctions: "&bOs Meus Leilões"
claim-items: "&dReclamar Itens"
earnings: "&aGanhos"
help: "&fAjuda"
admin: "&cPainel de Admin"
# Navegação
next-page: "&aPágina Seguinte →"
previous-page: "&a← Página Anterior"
back: "&cVoltar"
close: "&cFechar"
# Ações
confirm: "&aConfirmar"
cancel: "&cCancelar"
buy: "&aComprar Agora"
bid: "&6Fazer Licitação"
buyout: "&eCompra Imediata"
claim: "&aReclamar"
claim-all: "&aReclamar Tudo"
withdraw: "&aLevantar Tudo"
remove: "&cRemover Anúncio"
cancel-auction: "&cCancelar Leilão"
# Entrada Numérica
add-1: "&a+1"
add-10: "&a+10"
add-100: "&a+100"
add-1000: "&a+1.000"
subtract-1: "&c-1"
subtract-10: "&c-10"
subtract-100: "&c-100"
subtract-1000: "&c-1.000"
set-min: "&eDefinir Mín"
set-max: "&eDefinir Máx"
custom-amount: "&bValor Personalizado"
# Filtros e Ordenação
filter: "&eFiltro"
sort: "&eOrdenar"
search: "&ePesquisar"
clear-filter: "&cLimpar Filtros"
# Duração
duration-1h: "&e1 Hora"
duration-6h: "&e6 Horas"
duration-12h: "&e12 Horas"
duration-24h: "&e24 Horas"
duration-48h: "&e48 Horas"
duration-72h: "&e3 Dias"
duration-168h: "&e7 Dias"
duration-336h: "&e14 Dias"
# Admin
admin-view-listings: "&aVer Todos os Anúncios"
admin-view-auctions: "&6Ver Todos os Leilões"
admin-reload: "&eRecarregar Config"
# Lore dos Botões (descrições)
lore:
browse-market:
- "&7Explora todos os anúncios"
- "&7de preço fixo dos jogadores."
- ""
- "&eClica para explorar!"
browse-auctions:
- "&7Explora todos os leilões ativos"
- "&7e faz licitações."
- ""
- "&eClica para explorar!"
create-listing:
- "&7Vende itens a um preço fixo."
- "&7Taxa: &f{tax}%"
- ""
- "&eClica para criar!"
create-auction:
- "&7Leiloa itens ao"
- "&7maior licitador."
- "&7Taxa: &f{tax}%"
- ""
- "&eClica para criar!"
my-listings:
- "&7Vê e gere os teus"
- "&7anúncios ativos."
- ""
- "&7Ativos: &f{count}/{max}"
- ""
- "&eClica para ver!"
my-auctions:
- "&7Vê e gere os teus"
- "&7leilões ativos."
- ""
- "&7Ativos: &f{count}/{max}"
- ""
- "&eClica para ver!"
claim-items:
- "&7Reclama itens de anúncios"
- "&7expirados ou leilões ganhos."
- ""
- "&7Pendentes: &f{count}"
- ""
- "&eClica para reclamar!"
earnings:
- "&7Vê e levanta os teus"
- "&7ganhos pendentes das vendas."
- ""
- "&7Pendente: &a{amount}"
- ""
- "&eClica para ver!"
help:
- "&7Aprende a usar o"
- "&7Mercado Comunitário."
- ""
- "&eClica para ajuda!"
admin:
- "&cPainel de Admin"
- "&7Gere anúncios e leilões."
- ""
- "&eClica para abrir!"
# Info do Anúncio
listing-info:
- "&7Vendedor: &f{seller}"
- "&7Preço: &a{price}"
- "&7Quantidade: &f{amount}"
- "&7Expira: &f{expires}"
- ""
- "&eClique esquerdo para comprar!"
# Info do Leilão
auction-info:
- "&7Vendedor: &f{seller}"
- "&7Licitação inicial: &a{start_price}"
- "&7Licitação atual: &a{current_bid}"
- "&7Licitador: &f{bidder}"
- "&7Licitações: &f{bid_count}"
- "&7Termina: &f{ends}"
- ""
- "&eClique esquerdo para licitar!"
- "&eClique direito para compra imediata!"
# Info do Meu Anúncio
my-listing-info:
- "&7Preço: &a{price}"
- "&7Quantidade: &f{amount}"
- "&7Criado: &f{created}"
- "&7Expira: &f{expires}"
- ""
- "&cClica para cancelar"
# Info do Meu Leilão
my-auction-info:
- "&7Licitação inicial: &a{start_price}"
- "&7Licitação atual: &a{current_bid}"
- "&7Licitador: &f{bidder}"
- "&7Licitações: &f{bid_count}"
- "&7Termina: &f{ends}"
- ""
- "&cClica para cancelar (sem licitações)"
# Confirmar Compra
confirm-purchase-info:
- "&7Estás a comprar:"
- "&f{item} x{amount}"
- ""
- "&7Preço: &a{price}"
- "&7Taxa: &e{tax}"
- "&7Total: &a{total}"
- ""
- "&aClica para confirmar!"
# Confirmar Licitação
confirm-bid-info:
- "&7Estás a licitar em:"
- "&f{item}"
- ""
- "&7A tua licitação: &a{bid}"
- "&7Atual mais alta: &e{current}"
- ""
- "&aClica para confirmar!"
# Reclamar Item
claim-item-info:
- "&7Razão: &f{reason}"
- "&7De: &f{source}"
- "&7Data: &f{date}"
- ""
- "&eClica para reclamar!"
# Info de Ganhos
earnings-info:
- "&7Os teus ganhos pendentes"
- "&7das vendas no mercado."
- ""
- "&7Total: &a{amount}"
- ""
- "&aClica para levantar!"
# Info de Entrada Numérica
current-value:
- "&7Atual: &a{value}"
# Opções de Filtro
filters:
all: "&fTodos os Itens"
weapons: "&cArmas"
armor: "&bArmadura"
tools: "&eFerramentas"
blocks: "&7Blocos"
food: "&6Comida"
potions: "&dPoções"
materials: "&aMateriais"
enchanted: "&5Itens Encantados"
misc: "&8Diversos"
# Opções de Ordenação
sort:
newest: "&aMais Recente"
oldest: "&eMais Antigo"
price-low: "&aPreço: Menor para Maior"
price-high: "&cPreço: Maior para Menor"
ending-soon: "&6A Terminar Em Breve"
most-bids: "&bMais Licitações"
# Formatos de Tempo
time:
expired: "&cExpirado"
days: "{d}d"
hours: "{h}h"
minutes: "{m}m"
seconds: "{s}s"
# GUI de Seleção de Quantidade
quantity-select:
title: "&6&lSelecionar Quantidade"
info-line-1: "&7Escolhe quantos itens"
info-line-2: "&7queres vender."
available: "&7Disponível: &f{amount}"
selected: "&7Selecionado: &f{amount}"
quantity-label: "Quantidade"
minimum: "&7Mínimo: &f{amount}"
maximum: "&7Máximo: &f{amount}"
use-buttons: "&eUsa os botões para ajustar"
click-adjust: "&7Clica: &e{amount}"
set-minimum: "&6Definir Mínimo"
set-maximum: "&6Definir Máximo"
set-to: "&7Definir para: &f{amount}"
back-lore: "&7Voltar à seleção de item"
confirm-lore: "&7Quantidade: &a{amount}"
# GUI de Seleção de Item
item-selection:
info-title: "&fSelecionar um Item"
info-lore-listing: "&7Clica num item do teu|&7inventário para criar um &eAnúncio&7."
info-lore-auction: "&7Clica num item do teu|&7inventário para criar um &6Leilão&7."
blacklisted-note: "&7Itens bloqueados aparecem a vermelho."
click-to-select: "&a► Clica para selecionar"
blocked-title: "&c{material}"
blocked-lore-1: "&7Este item não pode ser listado."
blocked-lore-2: "&cBloqueado ou inválido."
back-lore: "&7Voltar ao menu principal"
# GUI de Criar Anúncio
create-listing:
info-title: "&6&lCriar Anúncio"
info-lore-1: "&7Define um preço e duração"
info-lore-2: "&7para o teu anúncio."
tax-info: "&7Taxa: &f{tax}%"
item-lore: "&7Quantidade: &f{amount}|&eEste item será listado"
price-title: "&6Preço: {price}"
price-tax: "&7Taxa ({percent}%): &c{amount}"
price-earnings: "&7Recebes: &a{amount}"
price-click: "&eClica para alterar preço"
duration-title: "&eDuração: {duration}"
duration-lore: "&7O anúncio expira após este tempo"
duration-click: "&eClica para alterar duração"
back-lore: "&7Voltar à seleção de item"
confirm-item: "&7Item: &f{item} x{amount}"
confirm-price: "&7Preço: &a{price}"
confirm-earnings: "&7Recebes: &a{amount}"
confirm-duration: "&7Duração: &e{duration}"
confirm-click: "&aClica para criar anúncio!"
# GUI de Criar Leilão
create-auction:
info-title: "&6&lCriar Leilão"
info-lore-1: "&7Define preço inicial, compra imediata opcional,"
info-lore-2: "&7e duração para o teu leilão."
tax-info: "&7Taxa na venda: &f{tax}%"
item-lore: "&7Quantidade: &f{amount}|&eEste item será leiloado"
start-price-title: "&6Preço Inicial: {price}"
start-price-lore-1: "&7Licitação mínima para iniciar"
start-price-lore-2: "&7o leilão."
start-price-click: "&eClica para alterar"
buyout-title-set: "&bCompra Imediata: {price}"
buyout-title-unset: "&bCompra Imediata: &7Não definido"
buyout-lore-set-1: "&7Preço de compra instantânea."
buyout-lore-set-2: "&eClique esquerdo para alterar"
buyout-lore-set-3: "&cClique direito para remover"
buyout-lore-unset-1: "&7Preço opcional de compra"
buyout-lore-unset-2: "&7instantânea para o teu leilão."
buyout-lore-unset-click: "&eClica para definir preço de compra imediata"
duration-title: "&eDuração: {duration}"
duration-lore: "&7O leilão termina após este tempo."
duration-click: "&eClica para alterar duração"
back-lore: "&7Voltar à seleção de item"
confirm-item: "&7Item: &f{item} x{amount}"
confirm-start: "&7Início: &a{price}"
confirm-buyout: "&7Compra Imediata: &b{price}"
confirm-buyout-none: "&7Compra Imediata: &7Nenhum"
confirm-duration: "&7Duração: &e{duration}"
confirm-click: "&aClica para criar leilão!"
# GUI de Entrada Numérica
number-input:
display-title: "&6&l{value}"
minimum: "&7Mínimo: &f{value}"
maximum: "&7Máximo: &f{value}"
use-buttons: "&eUsa os botões para ajustar"
click-adjust: "&7Clica: &e{amount}"
shift-click: "&7Shift-clica: &e{amount}"
set-minimum: "&6Definir Mínimo"
set-maximum: "&6Definir Máximo"
set-to: "&7Definir para: &f{value}"
cancel-lore: "&7Cancelar e voltar"
confirm-lore: "&7Confirmar: &a{value}"
# Conteúdo de Ajuda
help:
title: "&6&lAjuda do Mercado Comunitário"
content:
- "&eExplorar Mercado &7- Ver e comprar anúncios de preço fixo"
- "&eExplorar Leilões &7- Ver e licitar em leilões"
- "&eCriar Anúncio &7- Vender itens a um preço fixo"
- "&eCriar Leilão &7- Leiloar itens ao maior licitador"
- "&eOs Meus Anúncios &7- Gerir os teus anúncios ativos"
- "&eOs Meus Leilões &7- Gerir os teus leilões ativos"
- "&eReclamar Itens &7- Recolher itens não vendidos/ganhos"
- "&eGanhos &7- Levantar dinheiro das vendas"
- ""
- "&7&oDica: Todas as ações são feitas através de GUIs!"
- "&7&oBasta clicar nos botões para navegar."
-83
View File
@@ -1,83 +0,0 @@
name: CommunityMarket
version: '1.0.0'
main: pt.henrique.communityMarket.CommunityMarket
api-version: '1.21'
description: A GUI-only marketplace plugin for fixed-price listings and auctions
author: Henrique
website: https://github.com/henrique/CommunityMarket
# Soft dependencies - plugin will detect and use these if available
softdepend:
- Vault
- Essentials
load: POSTWORLD
commands:
market:
description: Opens the Community Market main menu
usage: /<command>
aliases: [cmarket]
permission: communitymarket.use
permissions:
communitymarket.*:
description: Grants all CommunityMarket permissions
default: op
children:
communitymarket.use: true
communitymarket.sell: true
communitymarket.auction: true
communitymarket.buy: true
communitymarket.bid: true
communitymarket.claim: true
communitymarket.withdraw: true
communitymarket.admin: true
communitymarket.use:
description: Allows access to the market GUI
default: true
communitymarket.sell:
description: Allows creating fixed-price listings
default: true
communitymarket.auction:
description: Allows creating auctions
default: true
communitymarket.buy:
description: Allows purchasing from the market
default: true
communitymarket.bid:
description: Allows bidding on auctions
default: true
communitymarket.claim:
description: Allows claiming items from storage
default: true
communitymarket.withdraw:
description: Allows withdrawing earnings
default: true
communitymarket.admin:
description: Allows access to admin functions
default: op
children:
communitymarket.admin.viewall: true
communitymarket.admin.remove: true
communitymarket.admin.reload: true
communitymarket.admin.viewall:
description: Allows viewing all listings/auctions
default: op
communitymarket.admin.remove:
description: Allows removing any listing or auction
default: op
communitymarket.admin.reload:
description: Allows reloading configuration
default: op
Binary file not shown.
-3
View File
@@ -1,3 +0,0 @@
artifactId=communitymarket
groupId=pt.henrique
version=1.0.0
@@ -1,67 +0,0 @@
pt/henrique/communityMarket/economy/EconomyManager.class
pt/henrique/communityMarket/util/TextUtil.class
pt/henrique/communityMarket/config/MessageManager.class
pt/henrique/communityMarket/model/PendingEarnings.class
pt/henrique/communityMarket/gui/AdminGui$AdminListingsGui.class
pt/henrique/communityMarket/model/Auction.class
pt/henrique/communityMarket/listener/PlayerListener.class
pt/henrique/communityMarket/economy/EconomyManager$EconomyAdapter.class
pt/henrique/communityMarket/gui/MarketGui.class
pt/henrique/communityMarket/service/AuctionService.class
pt/henrique/communityMarket/util/ItemSerializer.class
pt/henrique/communityMarket/service/EarningsService$WithdrawResult.class
pt/henrique/communityMarket/gui/MainMenuGui.class
pt/henrique/communityMarket/service/ListingService.class
pt/henrique/communityMarket/gui/ConfirmationGui.class
pt/henrique/communityMarket/gui/HelpGui.class
pt/henrique/communityMarket/db/DatabaseManager.class
pt/henrique/communityMarket/gui/QuantitySelectGui$QuantityCallback.class
pt/henrique/communityMarket/service/TransactionService.class
pt/henrique/communityMarket/task/AuctionTask.class
pt/henrique/communityMarket/model/Bid.class
pt/henrique/communityMarket/service/ClaimService.class
pt/henrique/communityMarket/task/ExpiredListingTask.class
pt/henrique/communityMarket/gui/NumberInputGui$NumberInputCallback.class
pt/henrique/communityMarket/service/ClaimService$ClaimResult.class
pt/henrique/communityMarket/gui/MyAuctionsGui.class
pt/henrique/communityMarket/CommunityMarket.class
pt/henrique/communityMarket/gui/ConfirmationGui$ConfirmCallback.class
pt/henrique/communityMarket/model/ClaimItem$ClaimReason.class
pt/henrique/communityMarket/gui/BrowseMarketGui.class
pt/henrique/communityMarket/model/Auction$AuctionStatus.class
pt/henrique/communityMarket/util/SoundUtil.class
pt/henrique/communityMarket/gui/BrowseMarketGui$1.class
pt/henrique/communityMarket/gui/CreateAuctionGui.class
pt/henrique/communityMarket/gui/QuantitySelectGui.class
pt/henrique/communityMarket/util/InventoryUtil.class
pt/henrique/communityMarket/gui/AdminGui$AdminAuctionsGui.class
pt/henrique/communityMarket/command/MarketCommand.class
pt/henrique/communityMarket/listener/GuiListener$1.class
pt/henrique/communityMarket/service/AuctionService$BidResult.class
pt/henrique/communityMarket/gui/CreateListingGui.class
pt/henrique/communityMarket/model/ClaimItem.class
pt/henrique/communityMarket/gui/ClaimGui$1.class
pt/henrique/communityMarket/util/ItemBuilder.class
pt/henrique/communityMarket/gui/NumberInputGui.class
pt/henrique/communityMarket/gui/AdminGui.class
pt/henrique/communityMarket/gui/BrowseAuctionsGui.class
pt/henrique/communityMarket/gui/ItemSelectionGui$SelectionMode.class
pt/henrique/communityMarket/service/TransactionService$TransactionResult.class
pt/henrique/communityMarket/service/EarningsService.class
pt/henrique/communityMarket/service/TransactionService$ValidationResult.class
pt/henrique/communityMarket/gui/BrowseAuctionsGui$1.class
pt/henrique/communityMarket/model/Listing.class
pt/henrique/communityMarket/service/AuctionService$CancelResult.class
pt/henrique/communityMarket/gui/GuiManager.class
pt/henrique/communityMarket/economy/EconomyManager$VaultAdapter.class
pt/henrique/communityMarket/gui/ClaimGui.class
pt/henrique/communityMarket/economy/EconomyManager$EssentialsAdapter.class
pt/henrique/communityMarket/service/ListingService$PurchaseResult.class
pt/henrique/communityMarket/gui/EarningsGui.class
pt/henrique/communityMarket/config/ConfigManager.class
pt/henrique/communityMarket/gui/MarketGui$GuiType.class
pt/henrique/communityMarket/util/InventoryUtil$ItemCategory.class
pt/henrique/communityMarket/gui/MyListingsGui.class
pt/henrique/communityMarket/gui/ItemSelectionGui.class
pt/henrique/communityMarket/model/Listing$ListingStatus.class
pt/henrique/communityMarket/listener/GuiListener.class
@@ -1,42 +0,0 @@
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/CommunityMarket.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/command/MarketCommand.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/config/ConfigManager.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/config/MessageManager.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/db/DatabaseManager.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/economy/EconomyManager.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/AdminGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/BrowseAuctionsGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/BrowseMarketGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/ClaimGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/ConfirmationGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/CreateAuctionGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/CreateListingGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/EarningsGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/GuiManager.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/HelpGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/ItemSelectionGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/MainMenuGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/MarketGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/MyAuctionsGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/MyListingsGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/NumberInputGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/gui/QuantitySelectGui.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/listener/GuiListener.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/listener/PlayerListener.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/model/Auction.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/model/Bid.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/model/ClaimItem.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/model/Listing.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/model/PendingEarnings.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/service/AuctionService.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/service/ClaimService.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/service/EarningsService.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/service/ListingService.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/service/TransactionService.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/task/AuctionTask.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/task/ExpiredListingTask.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/util/InventoryUtil.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/util/ItemBuilder.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/util/ItemSerializer.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/util/SoundUtil.java
/root/mc-plugins-audit/repos/communitymarket/src/main/java/pt/henrique/communityMarket/util/TextUtil.java
Binary file not shown.