9 Commits

Author SHA1 Message Date
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
27 changed files with 239 additions and 88 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

View File

@ -1,4 +1,4 @@
# <center>FeelingLucky Beta v1.0.2</center> # <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:blue">Plugin Description:</u></center>
@ -17,12 +17,13 @@ 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. 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, 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. <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> ## <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. 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, and support for Spigot will not be added in the future.</center></span> #### <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> ### <center>Note: If you are migrating from an Alpha build, the plugin configuration folder will need to be regenerated.</center>

View File

@ -3,7 +3,7 @@ plugins {
} }
group = 'io.github.simplex' group = 'io.github.simplex'
version = '1.2.0-RC01' version = '1.2.1'
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -3,56 +3,59 @@ package io.github.simplex.luck;
import io.github.simplex.luck.listener.AbstractListener; import io.github.simplex.luck.listener.AbstractListener;
import io.github.simplex.luck.util.SneakyWorker; import io.github.simplex.luck.util.SneakyWorker;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.nio.file.Files; import java.util.HashMap;
import java.nio.file.Path; import java.util.Map;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("ResultOfMethodCallIgnored") @SuppressWarnings("ResultOfMethodCallIgnored")
public class Config extends YamlConfiguration { public class Config extends YamlConfiguration {
private final FeelingLucky plugin; private final Map<String, Object> configEntries = new HashMap<>() {{
private final List<String> configEntries = new ArrayList<>() {{ put("high_rarity_chance", 512.0);
add("high_rarity_chance"); put("medium_rarity_chance", 128.0);
add("medium_rarity_chance"); put("low_rarity_chance", 64.0);
add("low_rarity_chance"); put("block_drops", "LOW");
add("block_drops"); put("bonemeal", "MED");
add("bonemeal"); put("cheat_death", "MED");
add("cheat_death"); put("enchanting", "HIGH");
add("enchanting"); put("experience", "HIGH");
add("experience"); put("give_damage", "LOW");
add("item_drops"); put("hide_check", "MED");
add("random_effect"); put("item_drops", "LOW");
add("restore_hunger"); put("jump_boost", "MED");
add("take_damage"); put("ore_vein", "HIGH");
add("unbreakable"); put("random_effect", "HIGH");
put("restore_hunger", "NONE");
put("take_damage", "MED");
put("unbreakable", "HIGH");
}}; }};
private File configFile; private File configFile;
public Config(FeelingLucky plugin) { public Config(FeelingLucky plugin) {
this.plugin = plugin;
File dataFolder = plugin.getDataFolder(); 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"); File configFile = new File(dataFolder, "config.yml");
if (!configFile.exists()) { if (!configFile.exists()) {
SneakyWorker.sneakyTry(configFile::createNewFile); plugin.getLogger().info("No configuration file exists. Creating a new one...");
plugin.saveResource("config.yml", true); plugin.saveResource("config.yml", true);
} }
this.configFile = configFile; this.configFile = configFile;
load();
if (validateIntegrity()) { if (validateIntegrity(this.configFile)) {
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;
load(); 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,14 +72,20 @@ public class Config extends YamlConfiguration {
load(); load();
} }
public boolean validateIntegrity() { public boolean validateIntegrity(@NotNull File fromDisk) {
for (String key : getKeys(false)) { YamlConfiguration disk = YamlConfiguration.loadConfiguration(fromDisk);
if (!configEntries.contains(key)) { if (disk.getKeys(true).size() <= 0) {
plugin.getLogger().severe("The contents of your configuration file is corrupted! Regenerating a new configuration file..."); return false;
return true; }
boolean result = true;
for (String key : configEntries.keySet()) {
if (!disk.getKeys(false).contains(key)) {
if (result) result = false;
} }
} }
return false; return result;
} }
public AbstractListener.Rarity getRarity(String name) { public AbstractListener.Rarity getRarity(String name) {

View File

@ -4,14 +4,14 @@ import io.github.simplex.luck.listener.*;
import io.github.simplex.luck.player.PlayerConfig; import io.github.simplex.luck.player.PlayerConfig;
import io.github.simplex.luck.player.PlayerHandler; import io.github.simplex.luck.player.PlayerHandler;
import io.github.simplex.luck.util.LuckCMD; 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.luck.util.SpecialFootItem;
import io.github.simplex.metrics.Metrics; import io.github.simplex.metrics.Metrics;
import org.bukkit.command.CommandMap;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -41,9 +41,10 @@ public final class FeelingLucky extends JavaPlugin {
loadPlayerConfigurations(); loadPlayerConfigurations();
getLogger().info("Attempting to load the main configuration..."); getLogger().info("Attempting to load the main configuration...");
config = new Config(this); config = new Config(this);
getLogger().info("Main Config loaded successfully! Attempting to load the Luck command..."); getLogger().info("Main Config loaded successfully! Loading commands...");
new LuckCMD(this); new LuckCMD(this);
getLogger().info("Successfully loaded the Luck command!"); new RegenerateConfigCMD(this);
getLogger().info("Successfully loaded all commands!");
getLogger().info("Successfully initialized!"); getLogger().info("Successfully initialized!");
} }
@ -79,18 +80,23 @@ public final class FeelingLucky extends JavaPlugin {
} }
private void registerListeners() { private void registerListeners() {
try { new BlockDrops(this);
Class<?>[] listeners = SneakyWorker.getClasses(AbstractListener.class.getPackage().getName()); new BonemealFullCrop(this);
Arrays.stream(listeners).forEach(l -> { new CheatDeath(this);
if (AbstractListener.class.isAssignableFrom(l)) { new EnchantmentBoost(this);
if (l.equals(AbstractListener.class)) return; new ExpBoost(this);
new GiveDamage(this);
SneakyWorker.sneakyTry(() -> l.getDeclaredConstructor(FeelingLucky.class).newInstance(this)); new HideCheck(this);
} new IllOmen(this);
}); new ItemDrops(this);
} catch (IOException | ClassNotFoundException ex) { new JumpBoost(this);
getLogger().severe(ex.getMessage()); new OreVein(this);
} new PlayerListener(this);
new RandomEffect(this);
new RestoreHunger(this);
new TakeDamage(this);
new UnbreakableTool(this);
new VillagerInventory(this);
} }
public PlayerHandler getHandler() { public PlayerHandler getHandler() {
@ -106,4 +112,8 @@ public final class FeelingLucky extends JavaPlugin {
public SpecialFootItem getFoot() { public SpecialFootItem getFoot() {
return specialFootItem; return specialFootItem;
} }
public CommandMap getCommandMap() {
return getServer().getCommandMap();
}
} }

View File

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

View File

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

View File

@ -17,6 +17,7 @@ import org.bukkit.inventory.ItemStack;
public final class BonemealFullCrop extends AbstractListener { public final class BonemealFullCrop extends AbstractListener {
public BonemealFullCrop(FeelingLucky plugin) { public BonemealFullCrop(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
@ -42,7 +43,6 @@ public final class BonemealFullCrop extends AbstractListener {
crop.setAge(crop.getMaximumAge()); crop.setAge(crop.getMaximumAge());
data.merge(crop); data.merge(crop);
block.setBlockData(data); block.setBlockData(data);
player.sendMessage(MiniComponent.info("You got lucky and your crops grew to maturity."));
} }
} }
} }

View File

@ -10,6 +10,7 @@ import org.bukkit.event.entity.PlayerDeathEvent;
public final class CheatDeath extends AbstractListener { public final class CheatDeath extends AbstractListener {
public CheatDeath(FeelingLucky plugin) { public CheatDeath(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

@ -13,6 +13,7 @@ import java.util.Map;
public final class EnchantmentBoost extends AbstractListener { public final class EnchantmentBoost extends AbstractListener {
public EnchantmentBoost(FeelingLucky plugin) { public EnchantmentBoost(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

@ -10,6 +10,7 @@ import org.bukkit.event.EventHandler;
public final class ExpBoost extends AbstractListener { public final class ExpBoost extends AbstractListener {
public ExpBoost(FeelingLucky plugin) { public ExpBoost(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

@ -11,6 +11,7 @@ import org.bukkit.event.entity.EntityDamageByEntityEvent;
public class GiveDamage extends AbstractListener { public class GiveDamage extends AbstractListener {
public GiveDamage(FeelingLucky plugin) { public GiveDamage(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
@ -19,9 +20,8 @@ public class GiveDamage extends AbstractListener {
&& (e.getEntity() instanceof LivingEntity)) { && (e.getEntity() instanceof LivingEntity)) {
double nextDmg = e.getDamage() + Luck.RNG().nextDouble(1.0, 5.0); double nextDmg = e.getDamage() + Luck.RNG().nextDouble(1.0, 5.0);
Luck luck = plugin.getHandler().getLuckContainer(player); Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue())) { if (luck.quickRNG(luck.getValue()) && doesQualify("give_damage", luck.getValue())) {
e.setDamage(nextDmg); e.setDamage(nextDmg);
player.sendMessage(MiniComponent.info("Your luck has increased your damage output!"));
} }
} }
} }

View File

@ -19,6 +19,7 @@ public class HideCheck extends AbstractListener {
public HideCheck(FeelingLucky plugin) { public HideCheck(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
@ -41,10 +42,10 @@ public class HideCheck extends AbstractListener {
@EventHandler @EventHandler
public void checkForSneak(PlayerToggleSneakEvent event) { public void checkForSneak(PlayerToggleSneakEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
if (!player.isSneaking()) return; if (player.isSneaking()) return;
Luck luck = plugin.getHandler().getLuckContainer(player); Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && !luck.isMarked(player)) { if (luck.quickRNG(luck.getValue()) && doesQualify("hide_check", luck.getValue())) {
entityMapList.get(player).forEach(e -> { entityMapList.get(player).forEach(e -> {
e.getTrackedPlayers().remove(player); e.getTrackedPlayers().remove(player);
}); });

View File

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

View File

@ -22,6 +22,7 @@ public class ItemDrops extends AbstractListener {
public ItemDrops(FeelingLucky plugin) { public ItemDrops(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

@ -11,16 +11,17 @@ import org.bukkit.util.Vector;
public class JumpBoost extends AbstractListener { public class JumpBoost extends AbstractListener {
public JumpBoost(FeelingLucky plugin) { public JumpBoost(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
public void detectJumping(PlayerJumpEvent event) { public void detectJumping(PlayerJumpEvent event) {
Player player = event.getPlayer(); // Player is never null; they're in game and jumping. Player player = event.getPlayer(); // Player is never null; they're in game and jumping.
Luck luck = plugin.getHandler().getLuckContainer(player); Luck luck = plugin.getHandler().getLuckContainer(player);
Vector velocity = player.getVelocity().clone();
if (luck.quickRNG(luck.getValue()) && !luck.isMarked(player)) { if (luck.quickRNG(luck.getValue()) && doesQualify("jump_boost", luck.getValue())) {
player.setVelocity(new Vector(0, 2, 0)); player.setVelocity(new Vector(velocity.getX(), velocity.getY() + 3, velocity.getZ()));
player.sendMessage(MiniComponent.info("Your luck has boosted your jump height!"));
} }
} }
} }

View File

@ -18,13 +18,14 @@ public class OreVein extends AbstractListener {
public OreVein(FeelingLucky plugin) { public OreVein(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
public void playerMine(BlockBreakEvent event) { public void playerMine(BlockBreakEvent event) {
Player player = event.getPlayer(); Player player = event.getPlayer();
Luck luck = plugin.getHandler().getLuckContainer(player); Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && event.getBlock().isValidTool(player.getInventory().getItemInMainHand())) { if (luck.quickRNG(luck.getValue()) && doesQualify("ore_vein", luck.getValue()) && event.getBlock().isValidTool(player.getInventory().getItemInMainHand())) {
getOresInArea(event.getBlock()).forEach(Block::breakNaturally); getOresInArea(event.getBlock()).forEach(Block::breakNaturally);
player.sendMessage(MiniComponent.info("Your luck has let you mine all the blocks with one swing.")); player.sendMessage(MiniComponent.info("Your luck has let you mine all the blocks with one swing."));
} }

View File

@ -25,6 +25,7 @@ public final class PlayerListener extends AbstractListener {
public PlayerListener(FeelingLucky plugin) { public PlayerListener(FeelingLucky plugin) {
super(plugin); super(plugin);
this.timer = new CooldownTimer(); this.timer = new CooldownTimer();
register(this);
} }
@EventHandler @EventHandler
@ -47,6 +48,7 @@ public final class PlayerListener extends AbstractListener {
player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 0.1!")); player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 0.1!"));
} }
double rng = Luck.RNG().nextDouble(2.0, 5.0); double rng = Luck.RNG().nextDouble(2.0, 5.0);
rng = Math.round(rng);
player.getInventory().remove(player.getInventory().getItemInMainHand()); player.getInventory().remove(player.getInventory().getItemInMainHand());
luck.addTo(rng); luck.addTo(rng);
plugin.getHandler().updatePlayer(player, luck); plugin.getHandler().updatePlayer(player, luck);

View File

@ -15,6 +15,7 @@ import java.util.List;
public class RandomEffect extends AbstractListener { public class RandomEffect extends AbstractListener {
public RandomEffect(FeelingLucky plugin) { public RandomEffect(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

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

View File

@ -1,5 +1,6 @@
package io.github.simplex.luck.listener; package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.lib.PotionEffectBuilder; import io.github.simplex.lib.PotionEffectBuilder;
import io.github.simplex.luck.FeelingLucky; import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck; import io.github.simplex.luck.player.Luck;
@ -13,6 +14,7 @@ import org.bukkit.event.entity.EntityDamageEvent;
public class TakeDamage extends AbstractListener { public class TakeDamage extends AbstractListener {
public TakeDamage(FeelingLucky plugin) { public TakeDamage(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler
@ -36,7 +38,7 @@ public class TakeDamage extends AbstractListener {
if (luck.quickRNG(percentage)) { if (luck.quickRNG(percentage)) {
event.setCancelled(true); event.setCancelled(true);
player.damage(event.getDamage() * 2); 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; return;
} }
@ -44,7 +46,6 @@ public class TakeDamage extends AbstractListener {
if (luck.quickRNG(percentage) && doesQualify("take_damage", percentage)) { if (luck.quickRNG(percentage) && doesQualify("take_damage", percentage)) {
event.setCancelled(true); event.setCancelled(true);
player.damage(event.getDamage() / 2); player.damage(event.getDamage() / 2);
player.sendMessage(Component.empty().content("You got lucky and took less damage."));
} }
} }
} }
@ -70,7 +71,7 @@ public class TakeDamage extends AbstractListener {
event.setCancelled(true); event.setCancelled(true);
player.getActivePotionEffects().removeIf(p -> ListBox.potionEffects.contains(p.getType())); player.getActivePotionEffects().removeIf(p -> ListBox.potionEffects.contains(p.getType()));
player.setFireTicks(0); 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 class UnbreakableTool extends AbstractListener {
public UnbreakableTool(FeelingLucky plugin) { public UnbreakableTool(FeelingLucky plugin) {
super(plugin); super(plugin);
register(this);
} }
@EventHandler @EventHandler

View File

@ -31,6 +31,8 @@ public class VillagerInventory extends AbstractListener {
recipe.setPriceMultiplier(1.25F); recipe.setPriceMultiplier(1.25F);
recipe.setVillagerExperience(25); recipe.setVillagerExperience(25);
recipe.setSpecialPrice(4); recipe.setSpecialPrice(4);
register(this);
} }
@EventHandler @EventHandler

View File

@ -4,10 +4,16 @@ import io.github.simplex.api.LuckContainer;
import io.github.simplex.luck.FeelingLucky; import io.github.simplex.luck.FeelingLucky;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; 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") @SuppressWarnings("all")
public class Luck implements LuckContainer { public class Luck implements LuckContainer {
@ -34,10 +40,16 @@ public class Luck implements LuckContainer {
event = new PlayerLuckChangeEvent(this); 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, @Contract(pure = true,
value = "-> new") value = "-> new")
public static @NotNull SplittableRandom RNG() { public static @NotNull SecureRandom RNG() {
return new SplittableRandom(); return new SecureRandom(SecureRandom.getSeed(20));
} }
public static boolean quickRNGnoMultiplier(double value) { public static boolean quickRNGnoMultiplier(double value) {
@ -53,6 +65,10 @@ public class Luck implements LuckContainer {
return (value >= actual); return (value >= actual);
} }
public boolean playerHasLuckPE() {
return player.hasPotionEffect(PotionEffectType.LUCK);
}
public FeelingLucky getPlugin() { public FeelingLucky getPlugin() {
return plugin; return plugin;
} }
@ -89,6 +105,12 @@ public class Luck implements LuckContainer {
return player; return player;
} }
/**
* 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) { public boolean quickRNG(double value) {
double rng; double rng;
if (value >= 1024.0) { if (value >= 1024.0) {
@ -97,13 +119,19 @@ public class Luck implements LuckContainer {
rng = RNG().nextDouble(0.0, 1024.0); rng = RNG().nextDouble(0.0, 1024.0);
} }
AtomicReference<Double> multiplier = new AtomicReference<>(multiplier());
double actual = Math.round((rng / 1024) * 100); double actual = Math.round((rng / 1024) * 100);
double newVal = Math.round((value / 1024) * 100);
if (multiplier() > 1.0) { if (playerHasLuckPE()) {
return ((value * multiplier()) >= actual); player.getActivePotionEffects()
.stream()
.filter(p -> p.getType().equals(PotionEffectType.LUCK))
.findFirst()
.ifPresent(p -> multiplier.updateAndGet(v -> (v + p.getAmplifier())));
} }
return (value >= actual); return ((newVal * multiplier.get()) >= actual);
} }
public void reset() { public void reset() {

View File

@ -22,12 +22,16 @@ public class LuckCMD extends Command implements TabCompleter, PluginIdentifiable
super("luck", "FeelingLucky main command.", "/<command> <info | set | reset | give | take> [player] [amount]", List.of()); super("luck", "FeelingLucky main command.", "/<command> <info | set | reset | give | take> [player] [amount]", List.of());
this.plugin = plugin; this.plugin = plugin;
setPermission("luck.default"); setPermission("luck.default");
register(plugin.getServer().getCommandMap()); plugin.getCommandMap().register("luck", "FeelingLucky", this);
plugin.getLogger().info("Successfully registered command: Luck");
} }
@Override @Override
public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { 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 (args.length == 3) {
if ((sender instanceof ConsoleCommandSender) || sender.hasPermission("luck.admin")) { if ((sender instanceof ConsoleCommandSender) || sender.hasPermission("luck.admin")) {
@ -65,21 +69,21 @@ public class LuckCMD extends Command implements TabCompleter, PluginIdentifiable
luck.setValue(amount); luck.setValue(amount);
plugin.getHandler().updatePlayer(player, luck); plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue()); 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; return true;
} }
case "give" -> { case "give" -> {
luck.addTo(amount); luck.addTo(amount);
plugin.getHandler().updatePlayer(player, luck); plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue()); 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; return true;
} }
case "take" -> { case "take" -> {
luck.takeFrom(amount); luck.takeFrom(amount);
plugin.getHandler().updatePlayer(player, luck); plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue()); 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; return true;
} }
} }

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

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