24 Commits

Author SHA1 Message Date
0ad60075da FeelingLucky v1.3.0
This update will entail providing spigot support.
This is currently incomplete.
2022-06-15 09:35:35 -05:00
661b7bd6a7 Removed deprecated "new Double" call. 2022-06-15 08:38:42 -05:00
639bf09e48 Merge branch 'main' of https://github.com/SimplexDevelopment/FeelingLucky 2022-06-15 08:34:22 -05:00
8b3486a269 Update v1.2.1
Changed version to 1.2.1
Added codacy analysis workflow.
2022-06-15 08:34:15 -05:00
94b6067f97 Update README.md 2022-06-15 08:30:09 -05:00
0b07bd9da2 Minor Update 1.2.1
Adjusted the Luck class to reflect:
- SplittableRandom has been replaced with SecureRandom in favor of entropy-based pseudorandom calculations compared to pseudorandom calculations based off the system time.
- Adjusted the quickRNG to factor in whether the user has the luck potion effect, and to just apply the multiplier regardless of whether it is the default value.
- Also adjusted the values, as the original value still remained at 1024, whereas the randomized number criteria was a percentage of 100. Both the input value and the randomized number criteria now are percentages of 100, based off a total of 1024 possible points.
2022-06-15 08:28:53 -05:00
400687733f Update README.md 2022-06-14 12:30:43 -05:00
c7a168ede1 Update README.md 2022-06-14 12:25:33 -05:00
fda004a3c8 Update README.md 2022-06-14 01:52:21 -05:00
0c82515f43 Update Release 1.2.0
Added a command to regenerate the configuration file.

This command can only be used from console.
2022-06-14 01:51:45 -05:00
c3d781f5b6 FeelingLucky v1.2.0 RC01 2022-06-12 00:12:06 -05:00
e6fe9e904e FeelingLucky v1.0 RC01
Added some more features, this will be now the full official release; this commit is release candidate 1.

Changelog:
- Added HideCheck, which will break the tracking of any mobs targeting the player.
- Added JumpBoost, which adds a little extra height to your jumps.
- Modified OreVein as it previously scanned for all ore types rather than the relative mined ore type.
2022-06-12 00:10:56 -05:00
c383b2c546 Merge pull request #2 from allinkdev/ver/1.19
Update version from "1.18.2" to "1.19"
2022-06-11 20:06:26 -05:00
94b9e12f45 Change version from "1.18.2" to "1.19" 2022-06-10 14:13:48 +01:00
eb80523edc Update README.md 2022-06-08 00:39:45 -05:00
355b612732 Moved README up to Parent Directory 2022-06-08 00:39:13 -05:00
67734f3f89 Added README.md 2022-06-08 00:34:09 -05:00
4232842749 Merge branch 'main' of https://github.com/SimplexDevelopment/FeelingLucky 2022-05-20 16:54:37 -05:00
010fd76031 FeelingLucky v1.0.0 Release Clean Up
Cleaned up a bunch of stuff and made the luck stat unique to the plugin rather than using the values provided by minecraft.
2022-05-20 16:54:28 -05:00
c50b222586 Create codeql-analysis.yml 2022-05-20 16:20:24 -05:00
17f83bd9f2 FeelingLucky v1.0 RELEASE 2022-05-20 15:41:34 -05:00
10d7a4ed98 Minor Functionality Changes
- Modified SpecialRabbitsFoot
- Improved functionality of some code interactions
2022-05-17 13:34:25 -05:00
73e5be91eb Critical Bugfix
Fixed an issue where plugin was loading player configurations from ./plugins/FeelingLucky instead of ./plugins/FeelingLucky/players
2022-05-16 20:59:49 -05:00
07c4e5d50c Update LuckCMD.java
- Implemented PluginIdentifiableCommand
- Changed the way the command is registered in the command map.
2022-05-10 12:50:59 -05:00
34 changed files with 638 additions and 178 deletions

32
.github/workflows/codacy-analysis.yml vendored Normal file
View File

@ -0,0 +1,32 @@
name: Codacy Security Scan
on:
push:
branches: [ "master", "main" ]
pull_request:
branches: [ "master", "main" ]
jobs:
codacy-security-scan:
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@main
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@master
with:
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@main
with:
sarif_file: results.sarif

77
.github/workflows/codeql-analysis.yml vendored Normal file
View File

@ -0,0 +1,77 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '25 16 * * 4'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'java' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
steps:
- name: Checkout repository
uses: actions/checkout@v3
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v2
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
# If the Autobuild fails above, remove it and uncomment the following three lines.
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
# - run: |
# echo "Run, Build Application using script"
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
- name: Codacy Coverage Reporter
uses: codacy/codacy-coverage-reporter-action@v1.3.0

29
README.md Normal file
View File

@ -0,0 +1,29 @@
# <center>FeelingLucky v1.2.0 - A luck driven mechanics plugin.</center>
## <center><u><span style="color:blue">Plugin Description:</u></center>
### <center><u><span style="color:cyan">For All Users:</u></center>
<b>FeelingLucky</b> is a mechanics plugin designed to expand upon the Luck attribute which Minecraft provides.
Each user is assigned a tangible Luck stat, which can be viewed by using <b><span style="color:violet">/luck info</color></b>.
Users can <i>increase</i> their luck stat by using a rabbit's foot,
or increase their luck and their luck multiplier by consuming a special rabbits foot purchased from a Butcher villager.
<b><span style="color:red">Beware</b> though, if you take damage from guardian lasers or a witch's potion,
there's a chance your luck will <i>decrease</i> instead.
### <center><u><span style="color:pink">For Administrators:</u></center>
Admins can modify values in the configuration file, as well as modify individual user's luck stat.
Admins can set, reset, add to, and take from player's luck stat.
Admins can also reload the main configuration, as well as individual and all player configurations.
For this, the command is <b><span style="color:violet">/luck reload -m</color></b> for the main config,
<b><span style="color:violet">/luck reload</color></b> to reload all player configurations, and <b><span style="color:violet">/luck reload -p <i>PLAYER_NAME</i></span></b> to reload individual player configuration files.
Server owners and/or individuals with console access can run /rgc to regenerate the main configuration file in the case that there are values missing, corrupted, or invalid.
## <center><u><span style="color:blue">Server Requirements:</u></center>
In order to run <b>FeelingLucky</b> v<b>1.1.0</b>, the latest version of Paper or Spigot is required.
#### <center><span style="color:red">Note: Paper is REQUIRED for this plugin to run. Spigot is not supported, however Spigot support is currently in progress.</center></span>
### <center>Note: If you are migrating from an Alpha build, the plugin configuration folder will need to be regenerated.</center>

View File

@ -1,24 +1,28 @@
plugins {
id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.0'
}
group = 'io.github.simplex'
version = 'Beta-1.0'
version = '1.2.1'
repositories {
mavenCentral()
maven {
name = 'papermc-repo'
url = 'https://papermc.io/repo/repository/maven-public/'
}
maven {
name = 'sonatype'
url = 'https://s01.oss.sonatype.org/content/groups/public/'
}
maven { url = uri("https://s01.oss.sonatype.org/content/groups/public/") }
maven { url = uri("https://papermc.io/repo/repository/maven-public/")}
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")}
}
dependencies {
compileOnly 'io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT'
compileOnly("org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-api:1.19-R0.1-SNAPSHOT")
shadow("org.jetbrains:annotations:16.0.2")
shadow("net.kyori:adventure-api:4.11.0")
shadow("io.papermc:paperlib:1.0.7")
}
shadowJar {
relocate("io.papermc.lib", "io.github.simplex.paperlib")
}
def targetJavaVersion = 17

View File

@ -1,16 +1,11 @@
package io.github.simplex.api;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Player;
import java.io.Serializable;
public interface LuckContainer extends Serializable {
Attribute asAttribute();
double getNumber();
boolean isMatch(double number);
boolean isClose(double number, int range);

View File

@ -21,17 +21,17 @@ public class MiniComponent {
}
@Contract("_ -> new")
public static Component info(String content) {
public static String info(String content) {
return new MiniComponent(content).color(ChatColor.GREEN).send();
}
@Contract("_ -> new")
public static Component warn(String content) {
public static String warn(String content) {
return new MiniComponent(content).color(ChatColor.YELLOW).decorate(TextDecoration.ITALIC).send();
}
@Contract("_ -> new")
public static Component err(String content) {
public static String err(String content) {
return new MiniComponent(content).color(ChatColor.RED).decorate(TextDecoration.BOLD).send();
}
@ -45,7 +45,7 @@ public class MiniComponent {
return this;
}
public Component send() {
public String send() {
if (color == null) {
if (decoration == null) return Component.empty().content(content);

View File

@ -3,56 +3,59 @@ package io.github.simplex.luck;
import io.github.simplex.luck.listener.AbstractListener;
import io.github.simplex.luck.util.SneakyWorker;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.HashMap;
import java.util.Map;
@SuppressWarnings("ResultOfMethodCallIgnored")
public class Config extends YamlConfiguration {
private final FeelingLucky plugin;
private final List<String> configEntries = new ArrayList<>() {{
add("high_rarity_chance");
add("medium_rarity_chance");
add("low_rarity_chance");
add("block_drops");
add("bonemeal");
add("cheat_death");
add("enchanting");
add("experience");
add("item_drops");
add("random_effect");
add("restore_hunger");
add("take_damage");
add("unbreakable");
private final Map<String, Object> configEntries = new HashMap<>() {{
put("high_rarity_chance", 512.0);
put("medium_rarity_chance", 128.0);
put("low_rarity_chance", 64.0);
put("block_drops", "LOW");
put("bonemeal", "MED");
put("cheat_death", "MED");
put("enchanting", "HIGH");
put("experience", "HIGH");
put("give_damage", "LOW");
put("hide_check", "MED");
put("item_drops", "LOW");
put("jump_boost", "MED");
put("ore_vein", "HIGH");
put("random_effect", "HIGH");
put("restore_hunger", "NONE");
put("take_damage", "MED");
put("unbreakable", "HIGH");
}};
private File configFile;
public Config(FeelingLucky plugin) {
this.plugin = plugin;
File dataFolder = plugin.getDataFolder();
if (!dataFolder.exists()) dataFolder.mkdirs();
if (dataFolder.mkdirs()) {
plugin.getLogger().info("Created new data folder. Writing new configuration file...");
plugin.saveResource("config.yml", true);
}
File configFile = new File(dataFolder, "config.yml");
if (!configFile.exists()) {
SneakyWorker.sneakyTry(configFile::createNewFile);
plugin.getLogger().info("No configuration file exists. Creating a new one...");
plugin.saveResource("config.yml", true);
}
this.configFile = configFile;
load();
if (validateIntegrity()) {
File newFile = new File(plugin.getDataFolder(), "config.yml");
SneakyWorker.sneakyTry(() -> {
Files.delete(Path.of(this.configFile.getPath()));
newFile.createNewFile();
plugin.saveResource("config.yml", true);
});
this.configFile = newFile;
if (validateIntegrity(this.configFile)) {
load();
} else {
configEntries.forEach(super::set);
plugin.getLogger().warning("Your configuration file is missing keys. " +
"\nPlease use /rgc in the console to regenerate the config file. " +
"\nAlternatively, delete the config.yml and restart your server. " +
"\nIt is safe to ignore this, as default values will be used." +
"\nHowever, it is highly recommended to regenerate the configuration.");
}
}
@ -69,16 +72,22 @@ public class Config extends YamlConfiguration {
load();
}
public boolean validateIntegrity() {
for (String key : getKeys(false)) {
if (!configEntries.contains(key)) {
plugin.getLogger().severe("The contents of your configuration file is corrupted! Regenerating a new configuration file...");
return true;
}
}
public boolean validateIntegrity(@NotNull File fromDisk) {
YamlConfiguration disk = YamlConfiguration.loadConfiguration(fromDisk);
if (disk.getKeys(true).size() <= 0) {
return false;
}
boolean result = true;
for (String key : configEntries.keySet()) {
if (!disk.getKeys(false).contains(key)) {
if (result) result = false;
}
}
return result;
}
public AbstractListener.Rarity getRarity(String name) {
return AbstractListener.Rarity.valueOf(getString(name));
}

View File

@ -4,13 +4,17 @@ import io.github.simplex.luck.listener.*;
import io.github.simplex.luck.player.PlayerConfig;
import io.github.simplex.luck.player.PlayerHandler;
import io.github.simplex.luck.util.LuckCMD;
import io.github.simplex.luck.util.SneakyWorker;
import io.github.simplex.luck.util.RegenerateConfigCMD;
import io.github.simplex.luck.util.SpecialFootItem;
import io.github.simplex.metrics.Metrics;
import io.papermc.lib.PaperLib;
import org.bukkit.command.CommandMap;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
@ -18,14 +22,22 @@ import java.util.UUID;
public final class FeelingLucky extends JavaPlugin {
private final Map<UUID, PlayerConfig> configMap = new HashMap<>();
private final File playerDirectory = new File(getDataFolder(), "players");
private final SpecialFootItem specialFootItem = new SpecialFootItem();
private PlayerHandler handler;
private Config config;
private CommandMap commandMap = null;
public Map<UUID, PlayerConfig> getConfigMap() {
return configMap;
}
@Override
public void onLoad() {
if (!PaperLib.isPaper()) PaperLib.suggestPaper(this);
}
@Override
public void onEnable() {
getLogger().info("Initializing metrics...");
@ -38,9 +50,12 @@ public final class FeelingLucky extends JavaPlugin {
loadPlayerConfigurations();
getLogger().info("Attempting to load the main configuration...");
config = new Config(this);
getLogger().info("Main Config loaded successfully! Attempting to load the Luck command...");
getLogger().info("Main Config loaded successfully! Attempting to open the CommandMap...");
initCommandMap();
getLogger().info("Command Map successfully initialized! Attempting to register the commands...");
new LuckCMD(this);
getLogger().info("Successfully loaded the Luck command!");
new RegenerateConfigCMD(this);
getLogger().info("Successfully loaded all commands!");
getLogger().info("Successfully initialized!");
}
@ -54,12 +69,29 @@ public final class FeelingLucky extends JavaPlugin {
getLogger().info("Complete! Goodbye! :)");
}
private void initCommandMap() {
try {
Field f = getServer().getClass().getDeclaredField("commandMap");
f.setAccessible(true);
commandMap = (CommandMap) f.get(getServer());
} catch (NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
private void loadPlayerConfigurations() {
File[] files = getDataFolder().listFiles();
if (!playerDirectory.exists()) {
getLogger().info("No directory exists. Creating...");
playerDirectory.mkdirs();
getLogger().info("Created new directory \"FeelingLucky/players\".");
return;
}
File[] files = playerDirectory.listFiles();
if (files != null) {
Arrays.stream(files).forEach(file -> {
UUID uuid = UUID.fromString(file.getName().split("\\.")[0]);
configMap.put(uuid, PlayerConfig.loadFrom(this, file));
configMap.put(uuid, PlayerConfig.initFrom(this, file));
});
configMap.forEach((u, pc) -> pc.load());
getLogger().info("Successfully loaded all configurations!");
@ -69,17 +101,25 @@ public final class FeelingLucky extends JavaPlugin {
}
private void registerListeners() {
try {
Class<?>[] listeners = SneakyWorker.getClasses(AbstractListener.class.getPackage().getName());
Arrays.stream(listeners).forEach(l -> {
if (AbstractListener.class.isAssignableFrom(l)) {
if (l.equals(AbstractListener.class)) return;
new BlockDrops(this);
new BonemealFullCrop(this);
new CheatDeath(this);
new EnchantmentBoost(this);
new GiveDamage(this);
new HideCheck(this);
new IllOmen(this);
new ItemDrops(this);
new JumpBoost(this);
new OreVein(this);
new PlayerListener(this);
new RandomEffect(this);
new RestoreHunger(this);
new TakeDamage(this);
new UnbreakableTool(this);
new VillagerInventory(this);
SneakyWorker.sneakyTry(() -> l.getDeclaredConstructor(FeelingLucky.class).newInstance(this));
}
});
} catch (IOException | ClassNotFoundException ex) {
getLogger().severe(ex.getMessage());
if (PaperLib.isPaper()) {
new ExpBoost(this);
}
}
@ -92,4 +132,13 @@ public final class FeelingLucky extends JavaPlugin {
public Config getConfig() {
return config;
}
public SpecialFootItem getFoot() {
return specialFootItem;
}
@Nullable
public CommandMap getCommandMap() {
return commandMap;
}
}

View File

@ -1,29 +1,29 @@
package io.github.simplex.luck.listener;
import io.github.simplex.luck.Config;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.PlayerHandler;
import org.bukkit.event.Listener;
public abstract class AbstractListener implements Listener {
protected final FeelingLucky plugin;
protected final Config config;
public AbstractListener(FeelingLucky plugin) {
this.plugin = plugin;
this.config = plugin.getConfig();
plugin.getServer().getPluginManager().registerEvents(this, plugin);
}
protected PlayerHandler getHandler() {
return plugin.getHandler();
}
public void register(AbstractListener listener) {
plugin.getServer().getPluginManager().registerEvents(listener, plugin);
}
public boolean doesQualify(String name, double luck) {
return switch (config.getRarity(name)) {
case HIGH -> luck > config.getChance("high_rarity_chance");
case MED -> luck > config.getChance("medium_rarity_chance");
case LOW -> luck > config.getChance("low_rarity_chance");
return switch (plugin.getConfig().getRarity(name)) {
case HIGH -> luck > plugin.getConfig().getChance("high_rarity_chance");
case MED -> luck > plugin.getConfig().getChance("medium_rarity_chance");
case LOW -> luck > plugin.getConfig().getChance("low_rarity_chance");
case NONE -> true;
};
}

View File

@ -13,6 +13,7 @@ import java.util.List;
public final class BlockDrops extends AbstractListener {
public BlockDrops(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -20,8 +21,7 @@ public final class BlockDrops extends AbstractListener {
Player player = event.getPlayer();
Luck luck = getHandler().getLuckContainer(player);
List<Item> items = event.getItems();
if (luck.quickRNG(luck.getPercentage()) && doesQualify("block_drops", luck.getPercentage())) {
event.getItems().clear();
if (luck.quickRNG(luck.getValue()) && doesQualify("block_drops", luck.getValue())) {
event.getItems().addAll(items.stream().map(SneakyWorker::move).toList());
}
}

View File

@ -1,7 +1,6 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.ItemBuilder;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.Material;
@ -17,6 +16,7 @@ import org.bukkit.inventory.ItemStack;
public final class BonemealFullCrop extends AbstractListener {
public BonemealFullCrop(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -34,15 +34,14 @@ public final class BonemealFullCrop extends AbstractListener {
BlockData data = block.getBlockData();
if (action.isRightClick()
if ((action.equals(Action.RIGHT_CLICK_AIR) || action.equals(Action.RIGHT_CLICK_BLOCK))
&& handItem.isSimilar(bonemeal)
&& (data instanceof Ageable crop)
&& luck.quickRNG(luck.getPercentage())
&& doesQualify("bonemeal", luck.getPercentage())) {
&& luck.quickRNG(luck.getValue())
&& doesQualify("bonemeal", luck.getValue())) {
crop.setAge(crop.getMaximumAge());
data.merge(crop);
block.setBlockData(data);
player.sendMessage(MiniComponent.info("You got lucky and your crops grew to maturity."));
}
}
}

View File

@ -2,22 +2,25 @@ package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.CancellablePlayerDeathEvent;
import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent;
public final class CheatDeath extends AbstractListener {
public CheatDeath(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
public void cheatDeath(PlayerDeathEvent event) {
Player player = event.getPlayer();
public void cheatDeath(CancellablePlayerDeathEvent event) {
Player player = event.getEntity();
Luck luck = getHandler().getLuckContainer(player);
double absorption = Math.round(Luck.RNG().nextDouble(5.0, 10.0));
if (luck.quickRNG(luck.getPercentage()) && doesQualify("cheat_death", luck.getPercentage())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("cheat_death", luck.getValue())) {
event.setCancelled(true);
player.setHealth(1.0);
player.setAbsorptionAmount(absorption);

View File

@ -13,6 +13,7 @@ import java.util.Map;
public final class EnchantmentBoost extends AbstractListener {
public EnchantmentBoost(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -21,7 +22,7 @@ public final class EnchantmentBoost extends AbstractListener {
List<Enchantment> enchList = enchMap.keySet().stream().toList();
Player player = event.getEnchanter();
Luck luck = getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getPercentage()) && doesQualify("enchanting", luck.getPercentage())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("enchanting", luck.getValue())) {
Enchantment particular = enchList.get(Luck.RNG().nextInt(enchList.size()));
int rng = Luck.RNG().nextInt(1, 5);

View File

@ -10,6 +10,7 @@ import org.bukkit.event.EventHandler;
public final class ExpBoost extends AbstractListener {
public ExpBoost(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -20,7 +21,7 @@ public final class ExpBoost extends AbstractListener {
int rounded = Math.round(math);
Player player = event.getPlayer();
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getPercentage()) && doesQualify("experience", luck.getPercentage())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("experience", luck.getValue())) {
orb.setExperience(rounded);
}
}

View File

@ -0,0 +1,27 @@
package io.github.simplex.luck.listener;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class GiveDamage extends AbstractListener {
public GiveDamage(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
public void playerAttack(EntityDamageByEntityEvent e) {
if ((e.getDamager() instanceof Player player)
&& (e.getEntity() instanceof LivingEntity)) {
double nextDmg = e.getDamage() + Luck.RNG().nextDouble(1.0, 5.0);
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && doesQualify("give_damage", luck.getValue())) {
e.setDamage(nextDmg);
}
}
}
}

View File

@ -0,0 +1,59 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import java.util.*;
public class HideCheck extends AbstractListener {
public Map<Player, List<Mob>> entityMapList = new HashMap<>();
public HideCheck(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
public void initPlayerMaps(PlayerJoinEvent event) {
entityMapList.put(event.getPlayer(), List.of());
}
@EventHandler
public void checkTargeting(EntityTargetLivingEntityEvent event) {
if (event.getTarget() instanceof Player player) {
if (event.getEntity() instanceof Mob entity) {
List<Mob> buffer = entityMapList.get(player).isEmpty() ?
new ArrayList<>() : entityMapList.get(player);
buffer.add(entity);
entityMapList.replace(player, buffer);
}
}
}
@EventHandler
public void checkForSneak(PlayerToggleSneakEvent event) {
Player player = event.getPlayer();
if (player.isSneaking()) return;
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && doesQualify("hide_check", luck.getValue())) {
entityMapList.get(player).forEach(e -> e.getTarget().remove());
player.sendMessage(MiniComponent.info("Your luck has hidden you from sight."));
}
}
@EventHandler
public void removePlayerOnLeave(PlayerQuitEvent event) {
entityMapList.remove(event.getPlayer());
}
}

View File

@ -14,6 +14,7 @@ import org.bukkit.potion.PotionEffectType;
public class IllOmen extends AbstractListener {
public IllOmen(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler

View File

@ -22,6 +22,7 @@ public class ItemDrops extends AbstractListener {
public ItemDrops(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -64,7 +65,7 @@ public class ItemDrops extends AbstractListener {
Item item = event.getItemDrop();
ItemStack stack = item.getItemStack();
int amount = stack.getAmount();
if (luck.quickRNG(luck.getPercentage()) && doesQualify("item_drops", luck.getPercentage())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("item_drops", luck.getValue())) {
int rng = Luck.RNG().nextInt(2, 5);
amount += rng;
stack.setAmount(amount);

View File

@ -0,0 +1,27 @@
package io.github.simplex.luck.listener;
import com.destroystokyo.paper.event.player.PlayerJumpEvent;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.util.Vector;
public class JumpBoost extends AbstractListener {
public JumpBoost(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
public void detectJumping(PlayerJumpEvent event) {
Player player = event.getPlayer(); // Player is never null; they're in game and jumping.
Luck luck = plugin.getHandler().getLuckContainer(player);
Vector velocity = player.getVelocity().clone();
if (luck.quickRNG(luck.getValue()) && doesQualify("jump_boost", luck.getValue())) {
player.setVelocity(new Vector(velocity.getX(), velocity.getY() + 3, velocity.getZ()));
}
}
}

View File

@ -0,0 +1,52 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockBreakEvent;
import java.util.stream.Stream;
public class OreVein extends AbstractListener {
public OreVein(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
public void playerMine(BlockBreakEvent event) {
Player player = event.getPlayer();
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && doesQualify("ore_vein", luck.getValue()) && event.getBlock().isPreferredTool(player.getInventory().getItemInMainHand())) {
getOresInArea(event.getBlock()).forEach(Block::breakNaturally);
player.sendMessage(MiniComponent.info("Your luck has let you mine all the blocks with one swing."));
}
}
public Stream<Block> getOresInArea(Block block) {
Stream.Builder<Block> streamBuilder = Stream.builder();
Location start = block.getLocation();
World world = block.getWorld();
Stream<Tag<Material>> materialStream = Stream.of(Tag.COAL_ORES, Tag.COPPER_ORES, Tag.DIAMOND_ORES, Tag.GOLD_ORES, Tag.IRON_ORES, Tag.EMERALD_ORES, Tag.LAPIS_ORES, Tag.REDSTONE_ORES);
for (int x = start.getBlockX() - 15; x <= start.getBlockX() + 15; x++) {
for (int y = start.getBlockY() - 15; y <= start.getBlockY() + 15; y++) {
for (int z = start.getBlockZ() - 15; z <= start.getBlockZ() + 15; z++) {
Location location = new Location(world, x, y, z);
Material blockType = location.getBlock().getType();
if (materialStream.anyMatch(o -> o.isTagged(blockType))) {
streamBuilder.add(location.getBlock());
}
}
}
}
return streamBuilder.build().filter(b -> b.getType().equals(block.getType()));
}
}

View File

@ -25,13 +25,14 @@ public final class PlayerListener extends AbstractListener {
public PlayerListener(FeelingLucky plugin) {
super(plugin);
this.timer = new CooldownTimer();
register(this);
}
@EventHandler
public void rabbitFoot(PlayerInteractEvent event) {
Action action = event.getAction();
ItemStack foot = new ItemStack(Material.RABBIT_FOOT);
SpecialFootItem special = new SpecialFootItem();
SpecialFootItem special = plugin.getFoot();
Player player = event.getPlayer();
Luck luck = getHandler().getLuckContainer(player);
@ -41,12 +42,14 @@ public final class PlayerListener extends AbstractListener {
return;
}
if (action.isRightClick() && player.getInventory().getItemInMainHand().isSimilar(foot)) {
if ((action.equals(Action.RIGHT_CLICK_AIR) || action.equals(Action.RIGHT_CLICK_BLOCK))
&& player.getInventory().getItemInMainHand().getType().equals(foot.getType())) {
if (foot.getItemMeta().equals(special.meta()) || foot.equals(special.get())) {
luck.setMultiplier(luck.multiplier() + 1);
player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 1!"));
luck.setMultiplier(luck.multiplier() + 0.1);
player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 0.1!"));
}
double rng = Luck.RNG().nextDouble(2.0, 5.0);
rng = Math.round(rng);
player.getInventory().remove(player.getInventory().getItemInMainHand());
luck.addTo(rng);
plugin.getHandler().updatePlayer(player, luck);
@ -78,24 +81,4 @@ public final class PlayerListener extends AbstractListener {
}
}
}
@Override
public boolean equals(Object obj) {
if (obj == this) return true;
if (obj == null || obj.getClass() != this.getClass()) return false;
var that = (PlayerListener) obj;
return Objects.equals(this.plugin, that.plugin);
}
@Override
public int hashCode() {
return Objects.hash(plugin);
}
@Override
public String toString() {
return "PlayerListener[" +
"plugin=" + plugin + ']';
}
}

View File

@ -15,6 +15,7 @@ import java.util.List;
public class RandomEffect extends AbstractListener {
public RandomEffect(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -26,7 +27,7 @@ public class RandomEffect extends AbstractListener {
int size = effectList.size();
PotionEffect random = effectList.get(Luck.RNG().nextInt(size - 1));
if (luck.quickRNG(luck.getPercentage()) && doesQualify("random_effect", luck.getValue())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("random_effect", luck.getValue())) {
player.addPotionEffect(random);
player.sendMessage(MiniComponent.info("Thanks to luck, a random positive potion effect has been applied to you."));
}
@ -41,7 +42,7 @@ public class RandomEffect extends AbstractListener {
int size = effectList.size();
PotionEffect random = effectList.get(Luck.RNG().nextInt(size - 1));
if (luck.quickRNG(luck.getPercentage()) && doesQualify("random_effect", luck.getValue())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("random_effect", luck.getValue())) {
player.addPotionEffect(random);
player.sendMessage(MiniComponent.info("Thanks to luck, a random positive potion effect has been applied to you."));
}

View File

@ -13,6 +13,7 @@ import org.bukkit.potion.PotionEffectType;
public class RestoreHunger extends AbstractListener {
public RestoreHunger(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -21,7 +22,7 @@ public class RestoreHunger extends AbstractListener {
Luck luck = getHandler().getLuckContainer(event.getPlayer());
PotionEffect effect = PotionEffectBuilder.newEffect().type(PotionEffectType.SATURATION).amplifier(2).duration(10).particles(false).create();
if (luck.notDefault()) {
double percentage = luck.getPercentage();
double percentage = luck.getValue();
ListBox.foods.forEach(food -> {
if (item.isSimilar(food)) {
if (luck.quickRNG(percentage) && doesQualify("restore_hunger", percentage)) {

View File

@ -1,5 +1,6 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.lib.PotionEffectBuilder;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
@ -13,6 +14,7 @@ import org.bukkit.event.entity.EntityDamageEvent;
public class TakeDamage extends AbstractListener {
public TakeDamage(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -25,7 +27,7 @@ public class TakeDamage extends AbstractListener {
Luck luck = getHandler().getLuckContainer(player);
if (ListBox.acceptedCauses.contains(event.getCause())) {
if (luck.notDefault()) {
double percentage = luck.getPercentage();
double percentage = luck.getValue();
/*
* If a player's luck stat is a negative number, or they are "marked",
@ -36,7 +38,7 @@ public class TakeDamage extends AbstractListener {
if (luck.quickRNG(percentage)) {
event.setCancelled(true);
player.damage(event.getDamage() * 2);
player.sendMessage(Component.empty().content("You were unlucky and took double damage."));
player.sendMessage(MiniComponent.warn("You were unlucky and took double damage!"));
}
return;
}
@ -44,14 +46,13 @@ public class TakeDamage extends AbstractListener {
if (luck.quickRNG(percentage) && doesQualify("take_damage", percentage)) {
event.setCancelled(true);
player.damage(event.getDamage() / 2);
player.sendMessage(Component.empty().content("You got lucky and took less damage."));
}
}
}
if (ListBox.sideCauses.contains(event.getCause())) {
if (luck.notDefault()) {
double percentage = luck.getPercentage();
double percentage = luck.getValue();
/*
* If a player's luck stat is a negative number, or they are "marked",
@ -70,7 +71,7 @@ public class TakeDamage extends AbstractListener {
event.setCancelled(true);
player.getActivePotionEffects().removeIf(p -> ListBox.potionEffects.contains(p.getType()));
player.setFireTicks(0);
player.sendMessage(Component.empty().content("You got lucky and your afflictions were cured."));
player.sendMessage(MiniComponent.info("You got lucky and your afflictions were cured."));
}
}
}

View File

@ -14,6 +14,7 @@ import org.bukkit.inventory.meta.ItemMeta;
public class UnbreakableTool extends AbstractListener {
public UnbreakableTool(FeelingLucky plugin) {
super(plugin);
register(this);
}
@EventHandler
@ -27,7 +28,7 @@ public class UnbreakableTool extends AbstractListener {
if (ItemBuilder.isTool(stack.getType())) {
if (event.getWhoClicked() instanceof Player player) {
Luck luck = getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getPercentage()) && doesQualify("unbreakable", luck.getPercentage())) {
if (luck.quickRNG(luck.getValue()) && doesQualify("unbreakable", luck.getValue())) {
meta.setUnbreakable(true);
stack.setItemMeta(meta);
inventory.setResult(stack);

View File

@ -15,12 +15,14 @@ import java.util.Arrays;
import java.util.List;
public class VillagerInventory extends AbstractListener {
private final SpecialFootItem foot = new SpecialFootItem();
private final MerchantRecipe recipe = new MerchantRecipe(foot.get(), 0, 2, true);
private final MerchantRecipe recipe;
public VillagerInventory(FeelingLucky plugin) {
super(plugin);
SpecialFootItem foot = plugin.getFoot();
this.recipe = new MerchantRecipe(foot.get(), 0, 2, true);
recipe.setIngredients(Arrays.asList(
ItemBuilder.of(Material.EMERALD).build(),
ItemBuilder.of(Material.RABBIT_HIDE).build()
@ -29,6 +31,8 @@ public class VillagerInventory extends AbstractListener {
recipe.setPriceMultiplier(1.25F);
recipe.setVillagerExperience(25);
recipe.setSpecialPrice(4);
register(this);
}
@EventHandler
@ -42,7 +46,7 @@ public class VillagerInventory extends AbstractListener {
Luck luck = plugin.getHandler().getLuckContainer(event.getPlayer());
if (luck == null) return;
if (luck.quickRNG(luck.getPercentage())) {
if (luck.quickRNG(luck.getValue())) {
recipeList.add(recipe);
vil.setRecipes(recipeList);
}

View File

@ -0,0 +1,36 @@
package io.github.simplex.luck.player;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class CancellablePlayerDeathEvent extends PlayerDeathEvent implements Cancellable {
private boolean cancelled = false;
public CancellablePlayerDeathEvent(@NotNull Player player, @NotNull List<ItemStack> drops, int droppedExp, @Nullable String deathMessage) {
super(player, drops, droppedExp, deathMessage);
}
public CancellablePlayerDeathEvent(@NotNull Player player, @NotNull List<ItemStack> drops, int droppedExp, int newExp, @Nullable String deathMessage) {
super(player, drops, droppedExp, newExp, deathMessage);
}
public CancellablePlayerDeathEvent(@NotNull Player player, @NotNull List<ItemStack> drops, int droppedExp, int newExp, int newTotalExp, int newLevel, @Nullable String deathMessage) {
super(player, drops, droppedExp, newExp, newTotalExp, newLevel, deathMessage);
}
@Override
public boolean isCancelled() {
return cancelled;
}
@Override
public void setCancelled(boolean cancel) {
cancelled = cancel;
}
}

View File

@ -3,12 +3,17 @@ package io.github.simplex.luck.player;
import io.github.simplex.api.LuckContainer;
import io.github.simplex.luck.FeelingLucky;
import org.bukkit.Bukkit;
import org.bukkit.attribute.Attribute;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
@SuppressWarnings("all")
public class Luck implements LuckContainer {
@ -35,15 +40,21 @@ public class Luck implements LuckContainer {
event = new PlayerLuckChangeEvent(this);
}
/**
* This creates a new instance of a pseudorandom number generator based off entropy provided by the operating system.
* This will allow for a much purer randomization, due to entropy being different for each call.
*
* @return A new instance of SecureRandom. Each time this method is called a new instance is created to provide maximum variation with entropic calculations.
*/
@Contract(pure = true,
value = "-> new")
public static @NotNull SplittableRandom RNG() {
return new SplittableRandom();
public static @NotNull SecureRandom RNG() {
return new SecureRandom(SecureRandom.getSeed(20));
}
public static boolean quickRNGnoMultiplier(double percentage) {
public static boolean quickRNGnoMultiplier(double value) {
double rng;
if (percentage >= 100.0) {
if (value >= 1024.0) {
rng = 1024.0; // 100% chance to trigger, obviously;
} else {
rng = RNG().nextDouble(0.0, 1024.0);
@ -51,7 +62,11 @@ public class Luck implements LuckContainer {
double actual = Math.round((rng / 1024.0) * 100);
return (percentage >= actual);
return (value >= actual);
}
public boolean playerHasLuckPE() {
return player.hasPotionEffect(PotionEffectType.LUCK);
}
public FeelingLucky getPlugin() {
@ -70,24 +85,14 @@ public class Luck implements LuckContainer {
return markedPlayers.contains(player);
}
@Override
public Attribute asAttribute() {
return Attribute.GENERIC_LUCK;
}
@Override
public double getNumber() {
return associatedPlayer().getAttribute(asAttribute()).getValue();
}
@Override
public boolean isMatch(double number) {
return getNumber() == number;
return getValue() == number;
}
@Override
public boolean isClose(double number, int range) {
return ((getNumber() - range <= number) && (number <= getNumber() + range));
return ((getValue() - range <= number) && (number <= getValue() + range));
}
@Override
@ -100,21 +105,33 @@ public class Luck implements LuckContainer {
return player;
}
public boolean quickRNG(double percentage) {
/**
* Quickly calculate whether or not the player has enough luck to trigger the condition.
*
* @param value The players luck value.
* @return True if the player meets the criteria, false if they do not.
*/
public boolean quickRNG(double value) {
double rng;
if (percentage >= 100.0) {
if (value >= 1024.0) {
rng = 1024.0; // 100% chance to trigger, obviously;
} else {
rng = RNG().nextDouble(0.0, 1024.0);
}
AtomicReference<Double> multiplier = new AtomicReference<>(multiplier());
double actual = Math.round((rng / 1024) * 100);
double newVal = Math.round((value / 1024) * 100);
if (multiplier() > 1.0) {
return ((percentage * multiplier()) >= actual);
if (playerHasLuckPE()) {
player.getActivePotionEffects()
.stream()
.filter(p -> p.getType().equals(PotionEffectType.LUCK))
.findFirst()
.ifPresent(p -> multiplier.updateAndGet(v -> (v + p.getAmplifier())));
}
return (percentage >= actual);
return ((newVal * multiplier.get()) >= actual);
}
public void reset() {
@ -128,7 +145,6 @@ public class Luck implements LuckContainer {
public void setValue(double value) {
BASE_VALUE = value;
player.getAttribute(Attribute.GENERIC_LUCK).setBaseValue(value);
plugin.getConfigMap().get(associatedPlayer().getUniqueId()).setLuck(value);
Bukkit.getPluginManager().callEvent(event);
}
@ -162,7 +178,7 @@ public class Luck implements LuckContainer {
}
public double getDefaultValue() {
return player.getAttribute(Attribute.GENERIC_LUCK).getDefaultValue();
return 0;
}
public void addTo(double value) {
@ -181,10 +197,6 @@ public class Luck implements LuckContainer {
setValue(getValue() + value);
}
public double getPercentage() {
return getValue() - getDefaultValue();
}
public boolean notDefault() {
return getValue() != getDefaultValue();
}

View File

@ -29,7 +29,7 @@ public class PlayerConfig {
File file = new File(dataFolder, player.getUniqueId() + ".yml");
if (!file.exists()) {
String name = "username: " + player.getName();
String luck = "luck: " + player.getAttribute(Attribute.GENERIC_LUCK).getDefaultValue();
String luck = "luck: " + 0;
String multiplier = "multiplier: " + 1.0;
SneakyWorker.sneakyTry(() -> {
@ -64,7 +64,7 @@ public class PlayerConfig {
}
@Contract("_, _ -> new")
public static PlayerConfig loadFrom(FeelingLucky plugin, File file) {
public static PlayerConfig initFrom(FeelingLucky plugin, File file) {
return new PlayerConfig(plugin, file);
}

View File

@ -6,10 +6,7 @@ import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.player.PlayerConfig;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.command.*;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -18,19 +15,23 @@ import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class LuckCMD extends Command implements TabCompleter {
public class LuckCMD extends Command implements TabCompleter, PluginIdentifiableCommand {
private final FeelingLucky plugin;
public LuckCMD(FeelingLucky plugin) {
super("luck", "FeelingLucky main command.", "/<command> <info | set | reset | give | take> [player] [amount]", List.of());
this.plugin = plugin;
setPermission("luck.default");
plugin.getServer().getCommandMap().register("luck", "FeelingLucky", this);
plugin.getCommandMap().register("luck", "FeelingLucky", this);
plugin.getLogger().info("Successfully registered command: Luck");
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
if (args.length < 1 || args.length > 3) return false;
if (args.length < 1 || args.length > 3) {
sender.sendMessage(this.getUsage());
return false;
}
if (args.length == 3) {
if ((sender instanceof ConsoleCommandSender) || sender.hasPermission("luck.admin")) {
@ -68,21 +69,21 @@ public class LuckCMD extends Command implements TabCompleter {
luck.setValue(amount);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully set " + args[1] + "'s Luck stat to " + amount + "."));
return true;
}
case "give" -> {
luck.addTo(amount);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully gave " + args[1] + " " + amount + " points of luck!"));
return true;
}
case "take" -> {
luck.takeFrom(amount);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully took " + amount + " points of luck from " + args[1]));
return true;
}
}
@ -145,7 +146,7 @@ public class LuckCMD extends Command implements TabCompleter {
if ((sender instanceof Player player) && player.hasPermission("luck.default")) {
if (args[0].equalsIgnoreCase("info")) {
Luck luck = plugin.getHandler().getLuckContainer(player);
player.sendMessage(MiniComponent.info("Your Luck: " + luck.getPercentage()));
player.sendMessage(MiniComponent.info("Your Luck: " + luck.getValue()));
return true;
}
} else if (sender instanceof ConsoleCommandSender) {
@ -200,4 +201,9 @@ public class LuckCMD extends Command implements TabCompleter {
return completions.stream().filter(n -> n.startsWith(args[0])).toList();
}
@Override
public @NotNull FeelingLucky getPlugin() {
return plugin;
}
}

View File

@ -0,0 +1,46 @@
package io.github.simplex.luck.util;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import org.bukkit.command.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class RegenerateConfigCMD extends Command implements TabCompleter, PluginIdentifiableCommand {
private final FeelingLucky plugin;
public RegenerateConfigCMD(FeelingLucky plugin) {
super("rgc", "Regenerate this plugin's config file.", "/<command>", List.of());
this.plugin = plugin;
setPermission("luck.rgc");
plugin.getCommandMap().register("rgc", "FeelingLucky", this);
plugin.getLogger().info("Successfully registered command: RGC.");
}
@Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) {
if (!(sender instanceof ConsoleCommandSender)) {
sender.sendMessage(MiniComponent.err("This command can only be used through console access."));
return true;
}
plugin.saveResource("config.yml", true);
plugin.getConfig().load();
plugin.getLogger().info("Configuration regenerated.");
return true;
}
@Override
public @NotNull FeelingLucky getPlugin() {
return plugin;
}
@Override
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
return new ArrayList<>();
}
}

View File

@ -1,6 +1,5 @@
package io.github.simplex.luck.util;
import io.github.simplex.luck.listener.AbstractListener;
import io.github.simplex.luck.player.Luck;
import org.bukkit.Bukkit;
import org.bukkit.entity.Item;
@ -33,7 +32,7 @@ public class SneakyWorker {
}
}
public static Class[] getClasses(String packageName) throws ClassNotFoundException, IOException {
public static Class<?>[] getClasses(String packageName) throws ClassNotFoundException, IOException {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
assert classLoader != null;
String path = packageName.replace(".", "/");
@ -43,11 +42,11 @@ public class SneakyWorker {
URL resource = resources.nextElement();
dirs.add(new File(resource.getFile()));
}
ArrayList<Class> classes = new ArrayList<>();
ArrayList<Class<?>> classes = new ArrayList<>();
for (File directory : dirs) {
classes.addAll(findClasses(directory, packageName));
}
return classes.toArray(new Class[classes.size()]);
return classes.toArray(new Class<?>[0]);
}
private static List<Class<?>> findClasses(File directory, String packageName) throws ClassNotFoundException {

View File

@ -12,7 +12,7 @@ public class SpecialFootItem {
stack = ItemBuilder.of(Material.RABBIT_FOOT)
.setName("Enhanced Rabbit Foot")
.setAmount(1).setLore("A strange energy radiates from within.",
"This item will increase your luck multiplier by one.")
"This item will increase your luck multiplier by 0.1.")
.build();
}

View File

@ -19,7 +19,11 @@ bonemeal: MED
cheat_death: MED
enchanting: HIGH
experience: HIGH
give_damage: LOW
hide_check: MED
item_drops: LOW
jump_boost: MED
ore_vein: HIGH
random_effect: HIGH
restore_hunger: NONE
take_damage: MED