8 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
14 changed files with 161 additions and 30 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 v1.2.0</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

@ -1,18 +1,28 @@
plugins { plugins {
id 'java' id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.0'
} }
group = 'io.github.simplex' group = 'io.github.simplex'
version = '1.2.0' version = '1.2.1'
repositories { repositories {
mavenCentral() mavenCentral()
maven { url = uri("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://papermc.io/repo/repository/maven-public/")}
maven { url = uri("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")}
} }
dependencies { dependencies {
compileOnly("org.spigotmc:spigot-api:1.19-R0.1-SNAPSHOT")
compileOnly("io.papermc.paper:paper-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 def targetJavaVersion = 17

View File

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

View File

@ -7,11 +7,14 @@ import io.github.simplex.luck.util.LuckCMD;
import io.github.simplex.luck.util.RegenerateConfigCMD; 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 io.papermc.lib.PaperLib;
import org.bukkit.command.CommandMap; 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 org.jetbrains.annotations.Nullable;
import java.io.File; import java.io.File;
import java.lang.reflect.Field;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -24,11 +27,17 @@ public final class FeelingLucky extends JavaPlugin {
private PlayerHandler handler; private PlayerHandler handler;
private Config config; private Config config;
private CommandMap commandMap = null;
public Map<UUID, PlayerConfig> getConfigMap() { public Map<UUID, PlayerConfig> getConfigMap() {
return configMap; return configMap;
} }
@Override
public void onLoad() {
if (!PaperLib.isPaper()) PaperLib.suggestPaper(this);
}
@Override @Override
public void onEnable() { public void onEnable() {
getLogger().info("Initializing metrics..."); getLogger().info("Initializing metrics...");
@ -41,7 +50,9 @@ 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! Loading commands..."); 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); new LuckCMD(this);
new RegenerateConfigCMD(this); new RegenerateConfigCMD(this);
getLogger().info("Successfully loaded all commands!"); getLogger().info("Successfully loaded all commands!");
@ -58,6 +69,16 @@ public final class FeelingLucky extends JavaPlugin {
getLogger().info("Complete! Goodbye! :)"); 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() { private void loadPlayerConfigurations() {
if (!playerDirectory.exists()) { if (!playerDirectory.exists()) {
getLogger().info("No directory exists. Creating..."); getLogger().info("No directory exists. Creating...");
@ -84,7 +105,6 @@ public final class FeelingLucky extends JavaPlugin {
new BonemealFullCrop(this); new BonemealFullCrop(this);
new CheatDeath(this); new CheatDeath(this);
new EnchantmentBoost(this); new EnchantmentBoost(this);
new ExpBoost(this);
new GiveDamage(this); new GiveDamage(this);
new HideCheck(this); new HideCheck(this);
new IllOmen(this); new IllOmen(this);
@ -97,6 +117,10 @@ public final class FeelingLucky extends JavaPlugin {
new TakeDamage(this); new TakeDamage(this);
new UnbreakableTool(this); new UnbreakableTool(this);
new VillagerInventory(this); new VillagerInventory(this);
if (PaperLib.isPaper()) {
new ExpBoost(this);
}
} }
public PlayerHandler getHandler() { public PlayerHandler getHandler() {
@ -113,7 +137,8 @@ public final class FeelingLucky extends JavaPlugin {
return specialFootItem; return specialFootItem;
} }
@Nullable
public CommandMap getCommandMap() { public CommandMap getCommandMap() {
return getServer().getCommandMap(); return commandMap;
} }
} }

View File

@ -1,6 +1,5 @@
package io.github.simplex.luck.listener; package io.github.simplex.luck.listener;
import io.github.simplex.luck.Config;
import io.github.simplex.luck.FeelingLucky; import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.PlayerHandler; import io.github.simplex.luck.player.PlayerHandler;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;

View File

@ -1,7 +1,6 @@
package io.github.simplex.luck.listener; package io.github.simplex.luck.listener;
import io.github.simplex.lib.ItemBuilder; import io.github.simplex.lib.ItemBuilder;
import io.github.simplex.lib.MiniComponent;
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;
import org.bukkit.Material; import org.bukkit.Material;
@ -35,7 +34,7 @@ public final class BonemealFullCrop extends AbstractListener {
BlockData data = block.getBlockData(); BlockData data = block.getBlockData();
if (action.isRightClick() if ((action.equals(Action.RIGHT_CLICK_AIR) || action.equals(Action.RIGHT_CLICK_BLOCK))
&& handItem.isSimilar(bonemeal) && handItem.isSimilar(bonemeal)
&& (data instanceof Ageable crop) && (data instanceof Ageable crop)
&& luck.quickRNG(luck.getValue()) && luck.quickRNG(luck.getValue())

View File

@ -2,8 +2,10 @@ package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent; import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky; import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.CancellablePlayerDeathEvent;
import io.github.simplex.luck.player.Luck; import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.entity.PlayerDeathEvent;
@ -14,8 +16,8 @@ public final class CheatDeath extends AbstractListener {
} }
@EventHandler @EventHandler
public void cheatDeath(PlayerDeathEvent event) { public void cheatDeath(CancellablePlayerDeathEvent event) {
Player player = event.getPlayer(); Player player = event.getEntity();
Luck luck = getHandler().getLuckContainer(player); Luck luck = getHandler().getLuckContainer(player);
double absorption = Math.round(Luck.RNG().nextDouble(5.0, 10.0)); double absorption = Math.round(Luck.RNG().nextDouble(5.0, 10.0));
if (luck.quickRNG(luck.getValue()) && doesQualify("cheat_death", luck.getValue())) { if (luck.quickRNG(luck.getValue()) && doesQualify("cheat_death", luck.getValue())) {

View File

@ -1,6 +1,5 @@
package io.github.simplex.luck.listener; package io.github.simplex.luck.listener;
import io.github.simplex.lib.MiniComponent;
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;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;

View File

@ -5,6 +5,7 @@ import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck; import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Mob;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityTargetLivingEntityEvent; import org.bukkit.event.entity.EntityTargetLivingEntityEvent;
@ -15,7 +16,7 @@ import org.bukkit.event.player.PlayerToggleSneakEvent;
import java.util.*; import java.util.*;
public class HideCheck extends AbstractListener { public class HideCheck extends AbstractListener {
public Map<Player, List<Entity>> entityMapList = new HashMap<>(); public Map<Player, List<Mob>> entityMapList = new HashMap<>();
public HideCheck(FeelingLucky plugin) { public HideCheck(FeelingLucky plugin) {
super(plugin); super(plugin);
@ -30,8 +31,8 @@ public class HideCheck extends AbstractListener {
@EventHandler @EventHandler
public void checkTargeting(EntityTargetLivingEntityEvent event) { public void checkTargeting(EntityTargetLivingEntityEvent event) {
if (event.getTarget() instanceof Player player) { if (event.getTarget() instanceof Player player) {
if (event.getEntity() instanceof LivingEntity entity) { if (event.getEntity() instanceof Mob entity) {
List<Entity> buffer = entityMapList.get(player).isEmpty() ? List<Mob> buffer = entityMapList.get(player).isEmpty() ?
new ArrayList<>() : entityMapList.get(player); new ArrayList<>() : entityMapList.get(player);
buffer.add(entity); buffer.add(entity);
entityMapList.replace(player, buffer); entityMapList.replace(player, buffer);
@ -46,9 +47,7 @@ public class HideCheck extends AbstractListener {
Luck luck = plugin.getHandler().getLuckContainer(player); Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getValue()) && doesQualify("hide_check", luck.getValue())) { if (luck.quickRNG(luck.getValue()) && doesQualify("hide_check", luck.getValue())) {
entityMapList.get(player).forEach(e -> { entityMapList.get(player).forEach(e -> e.getTarget().remove());
e.getTrackedPlayers().remove(player);
});
player.sendMessage(MiniComponent.info("Your luck has hidden you from sight.")); player.sendMessage(MiniComponent.info("Your luck has hidden you from sight."));
} }
} }

View File

@ -25,7 +25,7 @@ public class OreVein extends AbstractListener {
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()) && doesQualify("ore_vein", luck.getValue()) && event.getBlock().isValidTool(player.getInventory().getItemInMainHand())) { if (luck.quickRNG(luck.getValue()) && doesQualify("ore_vein", luck.getValue()) && event.getBlock().isPreferredTool(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

@ -42,7 +42,8 @@ public final class PlayerListener extends AbstractListener {
return; return;
} }
if (action.isRightClick() && player.getInventory().getItemInMainHand().getType().equals(foot.getType())) { 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())) { if (foot.getItemMeta().equals(special.meta()) || foot.equals(special.get())) {
luck.setMultiplier(luck.multiplier() + 0.1); luck.setMultiplier(luck.multiplier() + 0.1);
player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 0.1!")); player.sendMessage(MiniComponent.info("Your luck multiplier has increased by 0.1!"));

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

@ -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() {