Skip to content
Closed
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
30 changes: 16 additions & 14 deletions .github/workflows/build-and-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,14 @@ jobs:

- name: Check if release commit
id: check_release
shell: bash
run: |
if [[ "${{ steps.commit_message.outputs.message }}" =~ ^release:\ [0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "is_release=true" >> $GITHUB_OUTPUT
echo "version=$(echo '${{ steps.commit_message.outputs.message }}' | sed 's/release: //')" >> $GITHUB_OUTPUT
echo "is_release=true" >> "$GITHUB_OUTPUT"
echo "version=$(echo '${{ steps.commit_message.outputs.message }}' | sed 's/release: //')" >> "$GITHUB_OUTPUT"
else
echo "is_release=false" >> $GITHUB_OUTPUT
echo "version=beta-${{ github.run_number }}" >> $GITHUB_OUTPUT
echo "is_release=false" >> "$GITHUB_OUTPUT"
echo "version=beta-${{ github.run_number }}" >> "$GITHUB_OUTPUT"
fi

- name: Update version in pom.xml
Expand All @@ -59,11 +60,12 @@ jobs:
uses: actions/upload-artifact@v4
with:
name: skyeblock-${{ steps.check_release.outputs.version }}
path: target/*.jar
path: target/SkyeBlock-${{ steps.check_release.outputs.version }}.jar
retention-days: 90

- name: Create Beta Release
if: steps.check_release.outputs.is_release == 'false'
if: github.event_name == 'push' && steps.check_release.outputs.is_release == 'false'
id: create_beta_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -83,18 +85,18 @@ jobs:
prerelease: true

- name: Upload Beta Release Asset
if: steps.check_release.outputs.is_release == 'false'
if: github.event_name == 'push' && steps.check_release.outputs.is_release == 'false'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_beta_release.outputs.upload_url }}
asset_path: target/skyeblock-${{ steps.check_release.outputs.version }}.jar
asset_name: skyeblock-beta-${{ github.run_number }}.jar
asset_path: target/SkyeBlock-${{ steps.check_release.outputs.version }}.jar
asset_name: SkyeBlock-${{ steps.check_release.outputs.version }}.jar
asset_content_type: application/java-archive

- name: Generate Changelog
if: steps.check_release.outputs.is_release == 'true'
if: github.event_name == 'push' && steps.check_release.outputs.is_release == 'true'
id: changelog
run: |
# Get the previous release tag
Expand All @@ -121,7 +123,7 @@ jobs:
echo "EOF" >> $GITHUB_OUTPUT

- name: Create Release
if: steps.check_release.outputs.is_release == 'true'
if: github.event_name == 'push' && steps.check_release.outputs.is_release == 'true'
id: create_release
uses: actions/create-release@v1
env:
Expand All @@ -134,14 +136,14 @@ jobs:
prerelease: false

- name: Upload Release Asset
if: steps.check_release.outputs.is_release == 'true'
if: github.event_name == 'push' && steps.check_release.outputs.is_release == 'true'
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: target/skyeblock-${{ steps.check_release.outputs.version }}.jar
asset_name: skyeblock-${{ steps.check_release.outputs.version }}.jar
asset_path: target/SkyeBlock-${{ steps.check_release.outputs.version }}.jar
asset_name: SkyeBlock-${{ steps.check_release.outputs.version }}.jar
asset_content_type: application/java-archive

code-quality:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ target/maven-status/
target/generated-sources/
target/classes/
target/original-*.jar
target/*
target/classes/*

# META-INF directory in target
target/META-INF/
70 changes: 70 additions & 0 deletions permissions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# SkyeBlock Permissions

This document lists all permissions defined in the plugin and the defaults shipped in `plugin.yml`.

## Roles / Bundles

| Role / Node | Includes | Default |
| --- | --- | --- |
| `skyeblock.*` | Everything in this file | `op` |
| `skyeblock.player` | All player commands and warps (no gamerule admin bypass) | `true` |
| `skyeblock.admin` | Admin commands (/sba), high-level management | `op` |
| `skyeblock.gamerule.*` | All gamerule nodes (must be explicitly granted) | `false` |

## Core Commands

| Command | Permission | Default |
| --- | --- | --- |
| `/sb`, `/island`, `/is` | `skyeblock.island` | `true` |
| `/visit` | `skyeblock.island.visit` | `true` |
| `/island vote` | `skyeblock.island.vote` | `true` |
| `/island edit` (title/desc/icon) | `skyeblock.island.edit` | `true` |
| `/island coop` | `skyeblock.island.coop` | `true` |
| `/island lock` / `unlock` | `skyeblock.island.lock` | `true` |
| `/island set home|visit` | `skyeblock.island.set` | `true` |
| `/delete` (self delete) | `skyeblock.island.delete` | `true` |
| `/islandpermissions` | `skyeblock.island.permissions` | `true` |
| `/hub` | `skyeblock.hub` | `true` |
| `/spawn` | `skyeblock.spawn` | `true` |
| `/warp` | `skyeblock.warp` | `true` |
| `/createisland` | `skyeblock.island.create` | `true` |

## Warp Permissions

| Permission | Use | Default |
| --- | --- | --- |
| `skyeblock.warp.spawn` | Spawn warp | `true` |
| `skyeblock.warp.nether` | Nether resource world warp | `true` |
| `skyeblock.warp.end` | End resource world warp | `true` |
| `skyeblock.warp.pvp` | PvP arena warp | `true` |
| `skyeblock.warp.shop` | Shop/market warp | `true` |
| `skyeblock.admin.warp` | Admin warp management (/warpadmin) | `op` |

## Admin / Staff

| Command | Permission | Default |
| --- | --- | --- |
| `/sba ...` (admin suite) | `skyeblock.admin` | `op` |
| `/convertislands` | `skyeblock.admin.convert` | `op` |
| `/warpadmin ...` | `skyeblock.admin.warp` | `op` |
| `/mobspawning ...` | `skyeblock.admin.mobspawning` | `op` |

## Gamerule Access

- Global bypass: `skyeblock.gamerules.adminbypass` (see all gamerules) — default `op`.
- Common bundle: `skyeblock.settings.gamerules` — default `false`, grants the listed gamerules below.
- Full bundle: `skyeblock.gamerule.*` — default `false` (must be explicitly granted).

### Individual Gamerule Nodes (all default `false`)
`skyeblock.gamerule.dodaylightcycle`, `skyeblock.gamerule.doweathercycle`, `skyeblock.gamerule.keepinventory`, `skyeblock.gamerule.mobgriefing`, `skyeblock.gamerule.domobspawning`, `skyeblock.gamerule.dofiretick`, `skyeblock.gamerule.falldamage`, `skyeblock.gamerule.firedamage`, `skyeblock.gamerule.drowningdamage`, `skyeblock.gamerule.doinsomnia`, `skyeblock.gamerule.doimmediaterespawn`, `skyeblock.gamerule.announceadvancements`, `skyeblock.gamerule.disableelytraMovementcheck`, `skyeblock.gamerule.dolimitedcrafting`, `skyeblock.gamerule.naturalregeneration`, `skyeblock.gamerule.reduceddebuginfo`, `skyeblock.gamerule.sendcommandfeedback`, `skyeblock.gamerule.showdeathmessages`, `skyeblock.gamerule.doentitydrops`, `skyeblock.gamerule.dotiledrops`, `skyeblock.gamerule.domobloot`, `skyeblock.gamerule.dopatrolspawning`, `skyeblock.gamerule.dotraderSpawning`, `skyeblock.gamerule.forgivedeadplayers`, `skyeblock.gamerule.universalanger`, `skyeblock.gamerule.randomtickspeed`, `skyeblock.gamerule.spawnradius`, `skyeblock.gamerule.maxentitycramming`, `skyeblock.gamerule.maxcommandchainlength`, `skyeblock.gamerule.playerssleepingpercentage`.

## Quick Assignment Examples

- **Default players**: grant `skyeblock.player` (already default `true`).
- **Trusted players with gamerules**: grant `skyeblock.settings.gamerules` or specific `skyeblock.gamerule.*` entries.
- **Admins**: grant `skyeblock.admin` (includes /sba) plus `skyeblock.admin.warp` and `skyeblock.admin.mobspawning` as needed.
- **Everything**: grant `skyeblock.*` (OPs have this by default).

## Source of Truth

All permission definitions are declared in [src/main/resources/plugin.yml](src/main/resources/plugin.yml).
20 changes: 17 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,12 @@
<url>https://repo.codemc.org/repository/maven-public/</url>
</repository>
<repository>
<id>dmulloy2-repo</id>
<url>https://repo.dmulloy2.net/repository/public/</url>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/public/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io/</url>
</repository>
</repositories>

Expand Down Expand Up @@ -68,7 +72,7 @@

<!-- ProtocolLib -->
<dependency>
<groupId>com.comphenix.protocol</groupId>
<groupId>com.github.dmulloy2</groupId>
<artifactId>ProtocolLib</artifactId>
<version>5.3.0</version>
<scope>provided</scope>
Expand All @@ -90,6 +94,16 @@
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/*.schem</exclude>
</excludes>
</resource>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
<includes>
<include>**/*.schem</include>
</includes>
</resource>
</resources>
<plugins>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ public void onEnable() {
// Save default config
saveDefaultConfig();

// Perform config migration if needed
migrateConfig();

// Initialize warp configuration
loadWarpConfig();

Expand Down Expand Up @@ -393,6 +396,30 @@ public void reloadWarpConfig() {
}
}

/**
* Migrate configuration from older versions to current version
*/
private void migrateConfig() {
String currentVersion = "2.0.0";
String configVersion = getConfig().getString("version", "1.0.0");

if (!configVersion.equals(currentVersion)) {
getLogger().info("Migrating configuration from version " + configVersion + " to " + currentVersion);

// Ensure visiting is disabled by default (safety feature)
if (!getConfig().contains("island.visiting.enabled")) {
getConfig().set("island.visiting.enabled", false);
getLogger().info("Set island.visiting.enabled to false (default)");
}

// Update version
getConfig().set("version", currentVersion);
saveConfig();

getLogger().info("Configuration migration completed successfully!");
}
}

/**
* Override reloadConfig to ensure config exists but not overwrite existing config
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package skyeblock.nobleskye.dev.skyeblock.commands;

import skyeblock.nobleskye.dev.skyeblock.SkyeBlockPlugin;
import skyeblock.nobleskye.dev.skyeblock.models.Island;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
Expand Down Expand Up @@ -82,8 +83,43 @@ public boolean onCommand(CommandSender sender, Command command, String label, St
}
}

/**
* Get the island the admin is currently on by checking their world
*/
private Island getIslandFromAdminLocation(Player admin) {
String worldName = admin.getWorld().getName();

// Check if the world is an island world
Island island = plugin.getIslandManager().getIslandById(worldName);

// If direct match fails, check if it's a nether island world (ends with _nether)
if (island == null && worldName.endsWith("_nether")) {
String mainIslandId = worldName.substring(0, worldName.length() - "_nether".length());
island = plugin.getIslandManager().getIslandById(mainIslandId);
}

return island;
}

private boolean handleAdminIslandCommand(CommandSender sender, String[] args) {
// Admin island management - bypasses all restrictions
if (sender instanceof Player) {
Player admin = (Player) sender;
Island currentIsland = getIslandFromAdminLocation(admin);

if (currentIsland != null) {
sender.sendMessage(Component.text("Executing island command for the island you're on ("
+ currentIsland.getIslandId() + ") with admin privileges...", NamedTextColor.YELLOW));

// Temporarily set the admin's UUID to the island owner's UUID for the command context
// Note: This approach maintains the admin's actual identity but operates on the current island
return islandCommand.onCommand(sender, null, "sba", args);
} else {
sender.sendMessage(Component.text("You are not currently on an island! Go to an island first, then use /sba island.", NamedTextColor.RED));
return true;
}
}

sender.sendMessage(Component.text("Executing island command with admin privileges...", NamedTextColor.YELLOW));
return islandCommand.onCommand(sender, null, "sba", args);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ public class VisitorPacketListener extends PacketAdapter {
new java.util.concurrent.ConcurrentHashMap<UUID, Boolean>());

public VisitorPacketListener(SkyeBlockPlugin plugin) {
super(plugin, ListenerPriority.LOWEST, // Use LOWEST to ensure we get packets first
super(plugin, ListenerPriority.HIGHEST,
// Container interaction
PacketType.Play.Client.WINDOW_CLICK,
PacketType.Play.Client.CLOSE_WINDOW,
PacketType.Play.Client.HELD_ITEM_SLOT,
// Block interaction
PacketType.Play.Client.USE_ENTITY,
PacketType.Play.Client.BLOCK_PLACE,
PacketType.Play.Client.USE_ITEM_ON,
PacketType.Play.Client.BLOCK_DIG,
// Item interaction
PacketType.Play.Client.SET_CREATIVE_SLOT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -612,8 +612,10 @@ public World getIslandWorld(String islandId) {
}

// Apply island settings to the world if found and it's not the main world
// This ensures gamerules are always correct when getting an island world
if (world != null && !world.equals(skyBlockWorld)) {
plugin.getIslandSettingsManager().applySettingsToWorld(islandId, world);
plugin.getLogger().fine("Reapplied gamerules to island world: " + islandId);
}

return world != null ? world : skyBlockWorld;
Expand All @@ -637,13 +639,18 @@ public World getOrLoadIslandWorld(String islandId) {
plugin.getLogger().info("Successfully loaded island world for " + islandId + ": " + loadedWorld.getName());
// Apply current mob spawning settings to the newly loaded world
applyMobSpawningSettings(loadedWorld);
// Apply island-specific gamerules from settings
plugin.getIslandSettingsManager().applySettingsToWorld(islandId, loadedWorld);
plugin.getLogger().info("Applied gamerules to newly loaded world: " + islandId);
return loadedWorld;
} else {
plugin.getLogger().warning("Failed to load island world for " + islandId + " - using default world");
}
} else if (world != null && !world.equals(skyBlockWorld)) {
// Apply current mob spawning settings to existing loaded world
applyMobSpawningSettings(world);
// Reapply island-specific gamerules to ensure they're correct
plugin.getIslandSettingsManager().applySettingsToWorld(islandId, world);
}

return world;
Expand Down
2 changes: 1 addition & 1 deletion src/main/resources/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ island:

# Island visiting settings
visiting:
# Whether island visiting is enabled globally
# Whether island visiting is enabled globally (auto-disabled for security)
enabled: false

# Messages (using MiniMessage format)
Expand Down
Loading
Loading