Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
dd5cd3d
feat: Added increment-block-statistics
awdrgyj8 Apr 4, 2026
f169ca6
perf: Batch incrementStatistic calls by material type
awdrgyj8 Apr 4, 2026
2a7d818
Merge branch 'master' into master
MagicTeaMC Apr 9, 2026
6ebc68c
[feat] auto pickup chopped drops into the player inventory
claude Aug 26, 2026
41bb576
Fix leaf/vine removal missing canopy on tall trees, add VINE to leaf-…
claude Jul 1, 2026
69880d1
Merge pull request #1 from OriginCraft-Team/claude/plugin-tree-auto-c…
awdrgyj8 Aug 26, 2026
e1b0a32
Fix 2x2 sapling replant landing offset from the chopped trunk
claude Aug 31, 2026
0512752
Merge pull request #2 from OriginCraft-Team/claude/auto-tree-planting…
awdrgyj8 Aug 31, 2026
62a0daa
Add a per-player auto pickup toggle command
claude Aug 31, 2026
0716b23
Merge pull request #3 from OriginCraft-Team/claude/auto-collect-toggl…
awdrgyj8 Aug 31, 2026
00dacc5
Show a refusal instead of hiding /atc autopickup without permission
claude Aug 31, 2026
0bc6077
Check the server-wide auto pickup flag before the player's permission
claude Aug 31, 2026
626e181
Stop granting autotreechop.autopickup to every player by default
claude Aug 31, 2026
aeed5b7
Route every message through the prefix style system again
claude Aug 31, 2026
7b965d2
Merge pull request #4 from OriginCraft-Team/claude/auto-collect-toggl…
awdrgyj8 Aug 31, 2026
9ba61ad
Honour the player's tool when drops fall on the ground
claude Aug 31, 2026
5f9aa89
Drop leaf blocks for Silk Touch tools independently of leaf-removal-d…
claude Aug 31, 2026
0c74b09
Record the leaf mining statistic before the leaf is broken
claude Aug 31, 2026
8b2d079
Merge pull request #5 from OriginCraft-Team/claude/silk-touch-axe-lea…
awdrgyj8 Aug 31, 2026
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
22 changes: 21 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ It's async-friendly, lightweight, and fully customizable — with built-in suppo
- Toggle on/off with `/atc` command or by sneaking (pressing SHIFT)
- Async support for smooth performance on Modern servers
- Customizable leaves cleaner
- Optional auto pickup: send drops straight to the player's inventory, respecting Fortune and Silk Touch

### ⚡ Lightweight & Easy to Configure

Expand Down Expand Up @@ -70,6 +71,7 @@ It's async-friendly, lightweight, and fully customizable — with built-in suppo
|--------|-------------|
| `/atc` | Toggle AutoTreeChop |
| `/atc confirm` | Confirm a pending chop (idle / no-leaves warning) |
| `/atc autopickup` | Toggle auto pickup of chopped drops for yourself |
| `/atc usage` | Show daily usage |
| `/atc reload` | Reload plugin config |
| `/atc toggle <player>` | Toggle for another player |
Expand All @@ -85,13 +87,14 @@ It's async-friendly, lightweight, and fully customizable — with built-in suppo

| Permission | Description | Default |
|------------|-------------|-------------|
| `autotreechop.use` | Use `/atc`, `/atc confirm`, and `/atc usage` commands | Everyone |
| `autotreechop.use` | Use `/atc`, `/atc confirm`, `/atc usage`, and `/atc autopickup` commands | Everyone |
| `autotreechop.vip` | Ignore usage limits | OP |
| `autotreechop.other` | Toggle others' ATC status | OP |
| `autotreechop.reload` | Reload config file | OP |
| `autotreechop.updatechecker` | Receive update notifications | OP |
| `autotreechop.replant` | Enable auto replanting | Everyone |
| `autotreechop.leaves` | Enable leaves removal | Everyone |
| `autotreechop.autopickup` | Collect chopped drops straight into the inventory | OP |

---

Expand All @@ -107,6 +110,23 @@ It's async-friendly, lightweight, and fully customizable — with built-in suppo

---

## Message styling

Every chat message in `plugins/AutoTreeChop/lang/*.properties` is wrapped in one of two tags:
`<prefix>` for success and information, `<prefix_negative>` for refusals, limits and warnings.
Both are defined in `lang/styles.properties`, so a server prefix or a different colour scheme is
a one-file change instead of an edit to every translation:

```properties
prefix=<dark_gray>[</dark_gray><green>MyServer</green><dark_gray>]</dark_gray> <text>{slot}</text>
prefix_negative=<dark_gray>[</dark_gray><green>MyServer</green><dark_gray>]</dark_gray> <negative>{slot}</negative>
```

`{slot}` is the message text, and the values are [MiniMessage](https://docs.advntr.dev/minimessage/format.html).
Run `/atc reload` to apply changes.

---

## Support & Contribute

- Need help? Join our [Matrix](https://matrix.to/#/#maoyue-dev:matrix.org)
Expand Down
9 changes: 7 additions & 2 deletions src/main/java/org/milkteamc/autotreechop/AutoTreeChop.java
Original file line number Diff line number Diff line change
Expand Up @@ -302,15 +302,20 @@ public PlayerConfig getPlayerConfig(UUID playerUUID) {
getLogger().warning("PlayerConfig not found for " + playerUUID + ", loading synchronously");
try {
DatabaseManager.PlayerData data = databaseManager
.loadPlayerDataAsync(playerUUID, config.getDefaultTreeChop())
.loadPlayerDataAsync(playerUUID, config.getDefaultTreeChop(), config.getDefaultAutoPickup())
.get();

playerConfig = new PlayerConfig(playerUUID, data);
playerConfigs.put(playerUUID, playerConfig);
} catch (Exception e) {
getLogger().warning("Failed to load player data: " + e.getMessage());
DatabaseManager.PlayerData defaultData = new DatabaseManager.PlayerData(
playerUUID, config.getDefaultTreeChop(), 0, 0, java.time.LocalDate.now());
playerUUID,
config.getDefaultTreeChop(),
config.getDefaultAutoPickup(),
0,
0,
java.time.LocalDate.now());
playerConfig = new PlayerConfig(playerUUID, defaultData);
playerConfigs.put(playerUUID, playerConfig);
}
Expand Down
24 changes: 24 additions & 0 deletions src/main/java/org/milkteamc/autotreechop/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ public class Config {
private long leafRemovalDelayTicks;
private int leafRemovalRadius;
private boolean leafRemovalDropItems;
private boolean leafRemovalSilkTouchDrops;
private boolean leafRemovalVisualEffects;
private boolean leafRemovalAsync;
private int leafRemovalBatchSize;
Expand All @@ -104,6 +105,9 @@ public class Config {
private int maxTreeSize;
private int maxDiscoveryBlocks;
private boolean callBlockBreakEvent;
private boolean incrementBlockStatistics;
private boolean autoPickupEnabled;
private boolean defaultAutoPickup;

public Config(AutoTreeChop plugin) {
this.plugin = plugin;
Expand Down Expand Up @@ -227,6 +231,9 @@ private void loadValues() {
maxTreeSize = config.getInt("max-tree-size", 500);
maxDiscoveryBlocks = config.getInt("max-discovery-blocks", 1000);
callBlockBreakEvent = config.getBoolean("call-block-break-event", true);
incrementBlockStatistics = config.getBoolean("increment-block-statistics", false);
autoPickupEnabled = config.getBoolean("enable-auto-pickup", false);
defaultAutoPickup = config.getBoolean("defaultAutoPickup", true);

autoReplantEnabled = config.getBoolean("enable-auto-replant", true);
replantDelayTicks = config.getLong("replant-delay-ticks", 15L);
Expand All @@ -237,6 +244,7 @@ private void loadValues() {
leafRemovalDelayTicks = config.getLong("leaf-removal-delay-ticks", 5L);
leafRemovalRadius = config.getInt("leaf-removal-radius", 10);
leafRemovalDropItems = config.getBoolean("leaf-removal-drop-items", false);
leafRemovalSilkTouchDrops = config.getBoolean("leaf-removal-silk-touch-drops", true);
leafRemovalVisualEffects = config.getBoolean("leaf-removal-visual-effects", true);
leafRemovalAsync = config.getBoolean("leaf-removal-async", true);
leafRemovalBatchSize = config.getInt("leaf-removal-batch-size", 20);
Expand Down Expand Up @@ -497,6 +505,10 @@ public boolean getLeafRemovalDropItems() {
return leafRemovalDropItems;
}

public boolean getLeafRemovalSilkTouchDrops() {
return leafRemovalSilkTouchDrops;
}

public boolean getLeafRemovalVisualEffects() {
return leafRemovalVisualEffects;
}
Expand Down Expand Up @@ -537,6 +549,18 @@ public boolean isCallBlockBreakEvent() {
return callBlockBreakEvent;
}

public boolean isIncrementBlockStatistics() {
return incrementBlockStatistics;
}

public boolean isAutoPickupEnabled() {
return autoPickupEnabled;
}

public boolean getDefaultAutoPickup() {
return defaultAutoPickup;
}

public int getIdleTimeoutSeconds() {
return idleTimeoutSeconds;
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/java/org/milkteamc/autotreechop/MessageKeys.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,13 @@ private MessageKeys() {}
public static final String CONFIRMATION_REQUIRED_BOTH = "confirmationRequiredBoth";
public static final String CONFIRMATION_SUCCESS = "confirmationSuccess";
public static final String NO_PENDING_CONFIRMATION = "noPendingConfirmation";
public static final String AUTO_PICKUP_ENABLED = "autoPickupEnabled";
public static final String AUTO_PICKUP_DISABLED = "autoPickupDisabled";
public static final String AUTO_PICKUP_UNAVAILABLE = "autoPickupUnavailable";

public static final String ALREADY_ENABLED = "alreadyEnabled";
public static final String ALREADY_DISABLED = "alreadyDisabled";
public static final String INVENTORY_FULL = "inventoryFull";
public static final String ABOUT_HEADER = "aboutHeader";
public static final String ABOUT_LICENSE = "aboutLicense";
public static final String ABOUT_GITHUB = "aboutGithub";
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/org/milkteamc/autotreechop/PlayerConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,17 @@ public void setAutoTreeChopEnabled(boolean enabled) {
}
}

public boolean isAutoPickupEnabled() {
return data.isAutoPickupEnabled();
}

public void setAutoPickupEnabled(boolean enabled) {
if (data.isAutoPickupEnabled() != enabled) {
data.setAutoPickupEnabled(enabled);
markDirty();
}
}

public int getDailyUses() {
checkAndUpdateDate();
return data.getDailyUses();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,46 @@ public void disable(BukkitCommandActor actor, EntitySelector<Player> targetPlaye
}
}

/**
* Flips the player's own auto pickup preference. The preference is stored per player and
* persists across sessions, exactly like the AutoTreeChop toggle above.
*
* <p>Gated on {@code autotreechop.use} rather than {@code autotreechop.autopickup} on purpose:
* a player without the auto pickup permission should be told they may not use the feature,
* not have the subcommand disappear from tab completion and answer "unknown command".
* The real permission is checked in the body so the refusal is an explicit message.
*
* <p>Toggling is also refused when auto pickup cannot take effect anyway — the server
* disabled it in config.yml — so a player never ends up with a stored "on" that silently
* does nothing. That server-wide state is checked first: when the feature is off for
* everyone, "auto pickup is disabled on this server" is the honest answer, and telling a
* player they lack the permission would point them at the wrong thing.
*/
@Subcommand({"autopickup", "pickup"})
@CommandPermission("autotreechop.use")
public void autoPickup(BukkitCommandActor actor) {
if (!plugin.getPluginConfig().isAutoPickupEnabled()) {
AutoTreeChop.sendMessage(actor.sender(), MessageKeys.AUTO_PICKUP_UNAVAILABLE);
return;
}

if (!(actor.sender() instanceof Player player)) {
AutoTreeChop.sendMessage(actor.sender(), MessageKeys.ONLY_PLAYERS);
return;
}

if (!player.hasPermission("autotreechop.autopickup")) {
AutoTreeChop.sendMessage(player, MessageKeys.NO_PERMISSION);
return;
}

PlayerConfig playerConfig = plugin.getPlayerConfig(player.getUniqueId());
boolean enabled = !playerConfig.isAutoPickupEnabled();
playerConfig.setAutoPickupEnabled(enabled);

AutoTreeChop.sendMessage(player, enabled ? MessageKeys.AUTO_PICKUP_ENABLED : MessageKeys.AUTO_PICKUP_DISABLED);
}

private void performSelfToggle(BukkitCommandActor actor) {
if (!(actor.sender() instanceof Player player)) {
AutoTreeChop.sendMessage(actor.sender(), MessageKeys.ONLY_PLAYERS);
Expand Down
Loading