10 Commits

Author SHA1 Message Date
330fd278b7 Beta 20220422-SNAPSHOT
Changelog:
 - Added a configuration with editable rarity values and rarity types for the different events that can occur, to give the end user more control over how often players receive the effects.
- Modified listeners to use the respective Configuration values.
- Added the ability to reload a specific player configuration with /luck reload -p <player_name>
- Added the ability to reload the main configuration using /luck reload -m
- Added an integrity checker to validate the main configuration on boot.
2022-04-22 19:25:02 -05:00
6119180b0b Add VillagerInventory.java
Added the possibility to find a special rabbits foot on a villager when trading with a BUTCHER profession.
2022-04-21 09:54:36 -05:00
fe620952bc Add CooldownTimer
Added the Cooldown Timer for when a user uses a Rabbit's Foot. This restricts a user from using rabbit's feet consecutively by forcing a 30 second cooldown between uses.
2022-04-17 14:48:05 -05:00
5b1fb352bb Beta 20220417-SNAPSHOT
Changelog:
 - Reorganized the listener registration method to register the listeners in alphabetical order
 - Added the IllOmen effect, which will apply a -25% debuff to a user's luck stat when they have the Bad Omen status effect.
 - Added the ability for Guardian lasers to inflict negative damage to a users luck stat.
 - Added a cache to the Luck class to store user values in the event that they have the Ill Omen debuff applied.
2022-04-17 14:00:22 -05:00
b424a83062 Beta 20220416-SNAPSHOT
Changelog:
 - Changed the way classes interact with the PlayerHandler by using a getter instead of the actual field.
 - Added #isTool(Material) to ItemBuilder to check if an item is, in fact, a type of tool.
 - Created the UnbreakableTool listener which will grant the unbreakable status to a tool if a user is lucky enough.
  NOTE: This is a beta feature, and while it may remain included the way it works will most likely change.
2022-04-16 17:27:54 -05:00
077ed05d74 Remove Compiler Files 2022-04-16 16:25:07 -05:00
8e70e1de73 Beta 20220414-SNAPSHOT
Changelog:
 - Added the ability to fully mature crops when using bone meal
 - Added the ability to cheat death (Grants 1 half heart and between 2.5 and 5 points of absorption)
 - Added #info, #warn, and #err to MiniComponent, and utilized these across the board.
 - Switched the #color method to use org.bukkit.ChatColor instead of TextColor for accessibility.
 - Moved loading configurations and listener registration to separate methods.
2022-04-14 14:58:14 -05:00
899768819e Beta 20220411-SNAPSHOT
Changelog:
 - Added ExpBoost feature
 - Added Special Rabbit Foot, which increases a user's luck multiplier.
 - Added ItemBuilder and MiniComponent library classes
 - Removed Messages#builder in favor of MiniComponent
2022-04-11 10:29:18 -05:00
ea50032a89 Alpha 1.0 RELEASE - Patch 0003 2022-04-10 19:10:24 -05:00
057450c585 Alpha 1.0 RELEASE 2022-04-10 18:48:09 -05:00
61 changed files with 1175 additions and 572 deletions

6
.gitignore vendored
View File

@ -19,6 +19,12 @@
*.tar.gz
*.rar
# Compiler Files #
build/
.idea/
.gradle/
FeelingLucky.iml
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
replay_pid*

View File

@ -1,2 +0,0 @@
#Wed Feb 09 22:19:17 CST 2022
gradle.version=7.3.3

Binary file not shown.

3
.idea/.gitignore generated vendored
View File

@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml

1
.idea/.name generated
View File

@ -1 +0,0 @@
FeelingLucky

6
.idea/compiler.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="17" />
</component>
</project>

17
.idea/gradle.xml generated
View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@ -1,54 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoCipherInsecureAsymmetricCryptographicAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoKeyAgreementGuideonApprovedCryptographicAlgorithm" enabled="true" level="SENSEI MARKED INFO" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoKeyAgreementInsecureCryptographicAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoKeyPairGenerationApprovedStandardCryptographicAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoKeyPairGenerationInsecureCryptographicAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoKeyPairGenerationNonStandardCryptographicAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoSignatureApprovedHashingAlgorithm" enabled="true" level="SENSEI MARKED INFO" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoSignatureInsecureHashingAlgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_CryptoSignatureNonStandardHashingAlgorithm" enabled="true" level="SENSEI WARNING" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataInjectionParameterizeLDAPFiltersDirContextsearch" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidbruteforcingUsesufficientlylongkeysizeskeyGenerator" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatekeypairgenerationalgorithminsecure" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatekeypairgenerationalgorithmnotrecommended" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmDESfamily" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmHmacfamily" enabled="true" level="SENSEI WARNING" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmHmacfamily1" enabled="true" level="SENSEI WARNING" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmOtheralgorithms" enabled="true" level="SENSEI MARKED INFO" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithminsecureSecretKeyFactory" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmnotrecommendedSecretKeyFactory" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUseappropriatesecretkeygenerationalgorithmotherSecretKeyFactory" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUsestrongsymmetriccryptographicalgorithm" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUsesufficientlylongkeysizeskeyGeneratorbadvalue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUsesufficientlylongkeysizeskeyPairGenerator" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-CryptographyAvoidcryptographicweaknessUsesufficientlylongkeysizeskeyPairGeneratorbadvalue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_DataProtection-SecureDataStorageAvoiddataexposureUseCipherinsteadofNullCipher" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidCodeInjectionUseSafeConstructor1stargumentoftypeConstructor" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidCodeInjectionUseSafeConstructorargumentsbutnoConstructorargument" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidCodeInjectionUseSafeConstructornoarguments" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidSQLInjectionUseParameterizedQueriesPreparedStatement" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidSQLInjectionUseParameterizedQueriesStatement" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidXMLInjectionUsesetFeature" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidXMLInjectionUsesetSchema" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InjectionAvoidXMLInjectionsetFeaturewithbadvalue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InputValidationAvoidXXEDonotsetDocumentBuilderFactoryexternal-parameter-entitiestotrue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InputValidationAvoidXXEDonotsetDocumentBuilderFactoryload-external-dtdtotrue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InputValidationAvoidXXEDonotsetDocumentBuilderFactorysetExpandEntityReferencestotrue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InputValidationAvoidXXEDonotsetDocumentBuilderFactorysetXIncludeAwaretotrue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_InputValidationAvoidXXEDonotsetXMLInputFactoryPropertytotrue" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_PortabilityFlawAvoidlocaledependentcomparisonsequalsaftercaseconversion" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_TLSWeakEncryptionInsecureVersion" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_TLSWeakEncryptionOutdatedVersion" enabled="true" level="SENSEI WARNING" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetExpandEntityReferencestofalse" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetFeaturedissallow-doctype-decl" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetFeaturedissallow-doctype-declwrongboolean" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetFeatureexternal-parameter-entitiesshouldbesetfirst" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetFeatureload-external-dtd" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesDocumentBuilderFactorysetXIncludeAware" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesXMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
<inspection_tool class="fcd36335-ac86-4bef-8d30-062d8aae0364_XMLExternalEntitiesXMLInputFactory.SUPPORT_DTD" enabled="true" level="SENSEI ERROR" enabled_by_default="true" />
</profile>
</component>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="MavenRepo" />
<option name="name" value="MavenRepo" />
<option name="url" value="https://repo.maven.apache.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="papermc-repo" />
<option name="name" value="papermc-repo" />
<option name="url" value="https://papermc.io/repo/repository/maven-public/" />
</remote-repository>
<remote-repository>
<option name="id" value="sonatype" />
<option name="name" value="sonatype" />
<option name="url" value="https://oss.sonatype.org/content/groups/public/" />
</remote-repository>
<remote-repository>
<option name="id" value="sonatype" />
<option name="name" value="sonatype" />
<option name="url" value="file:/$PROJECT_DIR$/%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20url%20=%20uri(%22https:/s01.oss.sonatype.org/service/local/staging/deploy/maven2/%22)%0A" />
</remote-repository>
<remote-repository>
<option name="id" value="sonatype" />
<option name="name" value="sonatype" />
<option name="url" value="https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="sonatype" />
<option name="name" value="sonatype" />
<option name="url" value="https://s01.oss.sonatype.org/content/groups/public/" />
</remote-repository>
</component>
</project>

12
.idea/misc.xml generated
View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EntryPointsManager">
<list size="1">
<item index="0" class="java.lang.String" itemvalue="org.bukkit.event.EventHandler" />
</list>
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

View File

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="minecraft" name="Minecraft">
<configuration>
<autoDetectTypes>
<platformType>PAPER</platformType>
<platformType>ADVENTURE</platformType>
</autoDetectTypes>
</configuration>
</facet>
</component>
</module>

124
.idea/uiDesigner.xml generated
View File

@ -1,124 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

6
.idea/vcs.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -3,7 +3,7 @@ plugins {
}
group = 'io.github.simplex'
version = 'Alpha-1.0-RC03'
version = 'Alpha-1.0'
repositories {
mavenCentral()

View File

@ -1,5 +0,0 @@
name: FeelingLucky
version: 'Alpha-1.0-RC03'
author: SimplexDevelopment
main: io.github.simplex.luck.FeelingLucky
api-version: 1.18

View File

@ -1,2 +0,0 @@
Manifest-Version: 1.0

View File

@ -6,6 +6,7 @@ import org.bukkit.entity.Player;
import java.io.Serializable;
public interface LuckContainer extends Serializable {
Attribute asAttribute();
double getNumber();

View File

@ -0,0 +1,75 @@
package io.github.simplex.lib;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.Contract;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public final class ItemBuilder {
private final ItemStack stack;
private final ItemMeta meta;
public ItemBuilder(Material material) {
this.stack = new ItemStack(material);
this.meta = stack.getItemMeta();
}
@Contract("_ -> new")
public static ItemBuilder of(Material material) {
return new ItemBuilder(material);
}
@Contract(pure = true)
public static boolean isTool(Material m) {
String name = m.getKey().getKey();
return m.equals(Material.SHEARS)
|| name.endsWith("bow")
|| name.endsWith("pickaxe")
|| name.endsWith("axe")
|| name.endsWith("sword")
|| name.endsWith("shovel")
|| name.endsWith("hoe");
}
public ItemBuilder setName(String name) {
meta.displayName(MiniComponent.of(name).send());
return this;
}
public ItemBuilder setAmount(int amount) {
stack.setAmount(amount);
return this;
}
public ItemBuilder setLore(String... lore) {
List<Component> components = new ArrayList<>();
Arrays.stream(lore).forEach(entry -> components.add(MiniComponent.of(entry).send()));
meta.lore(components);
return this;
}
public ItemStack build() {
stack.setItemMeta(meta);
return stack;
}
private Component component(String content, TextColor color, TextDecoration decoration) {
return Component.empty().content(content).decorate(decoration).color(color);
}
private Component component(String content, TextColor color) {
return Component.empty().content(content).color(color);
}
private Component component(String content) {
return Component.empty().content(content);
}
}

View File

@ -1,15 +1,13 @@
package io.github.simplex.lib;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public enum Messages {
NOT_FROM_CONSOLE(builder("This command may only be used in game.", null, null)),
NO_PERMISSION(builder("You do not have permission to use this command.", TextColor.color(255, 0, 0), TextDecoration.ITALIC));
NOT_FROM_CONSOLE(MiniComponent.err("This command may only be used in game.")),
NO_PERMISSION(MiniComponent.err("You do not have permission to use this command.")),
NO_PLAYER(MiniComponent.warn("That player cannot be found.")),
OUT_OF_BOUNDS(MiniComponent.err("Number must be between -1024.0 and 1024.0"));
private final Component message;
@ -20,16 +18,4 @@ public enum Messages {
public Component get() {
return message;
}
private static Component builder(@NotNull String message, @Nullable TextColor color, @Nullable TextDecoration decoration) {
if (color == null) {
if (decoration == null) return Component.empty().content(message);
return Component.empty().content(message).decoration(decoration, TextDecoration.State.TRUE);
}
if (decoration == null) return Component.empty().content(message).color(color);
return Component.empty().content(message).color(color).decoration(decoration, TextDecoration.State.TRUE);
}
}

View File

@ -0,0 +1,59 @@
package io.github.simplex.lib;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import net.kyori.adventure.text.format.TextDecoration;
import org.bukkit.ChatColor;
import org.jetbrains.annotations.Contract;
public class MiniComponent {
private final String content;
private TextDecoration decoration = null;
private TextColor color = null;
public MiniComponent(String content) {
this.content = content;
}
@Contract("_ -> new")
public static MiniComponent of(String content) {
return new MiniComponent(content);
}
@Contract("_ -> new")
public static Component info(String content) {
return new MiniComponent(content).color(ChatColor.GREEN).send();
}
@Contract("_ -> new")
public static Component warn(String content) {
return new MiniComponent(content).color(ChatColor.YELLOW).decorate(TextDecoration.ITALIC).send();
}
@Contract("_ -> new")
public static Component err(String content) {
return new MiniComponent(content).color(ChatColor.RED).decorate(TextDecoration.BOLD).send();
}
public MiniComponent decorate(TextDecoration decoration) {
this.decoration = decoration;
return this;
}
public MiniComponent color(ChatColor color) {
this.color = TextColor.color(color.asBungee().getColor().getRGB());
return this;
}
public Component send() {
if (color == null) {
if (decoration == null) return Component.empty().content(content);
return Component.empty().content(content).decoration(decoration, TextDecoration.State.TRUE);
}
if (decoration == null) return Component.empty().content(content).color(color);
return Component.empty().content(content).decorate(decoration).color(color);
}
}

View File

@ -0,0 +1,91 @@
package io.github.simplex.luck;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.listener.AbstractListener;
import io.github.simplex.luck.util.SneakyWorker;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Config extends YamlConfiguration {
private final FeelingLucky plugin;
private File configFile;
public Config(FeelingLucky plugin) {
this.plugin = plugin;
File dataFolder = plugin.getDataFolder();
if (!dataFolder.exists()) dataFolder.mkdirs();
File configFile = new File(dataFolder, "config.yml");
if (!configFile.exists()) {
SneakyWorker.sneakyTry(configFile::createNewFile);
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(plugin.getDataFolder().getPath()));
newFile.createNewFile();
plugin.saveResource("config.yml", true);
});
this.configFile = newFile;
load();
}
}
public void save() {
SneakyWorker.sneakyTry(() -> save(configFile));
}
public void load() {
SneakyWorker.sneakyTry(() -> load(configFile));
}
public void reload() {
save();
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;
}
}
return false;
}
public AbstractListener.Rarity getRarity(String name) {
return AbstractListener.Rarity.valueOf(getString(name));
}
public double getChance(String path) {
return getDouble(path);
}
private 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");
}};
}

View File

@ -1,10 +1,11 @@
package io.github.simplex.luck;
import io.github.simplex.luck.listener.PlayerListener;
import io.github.simplex.luck.listener.*;
import io.github.simplex.luck.player.PlayerConfig;
import io.github.simplex.luck.player.PlayerHandler;
import org.bukkit.Bukkit;
import io.github.simplex.luck.util.LuckCMD;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Arrays;
@ -13,23 +14,42 @@ import java.util.Map;
import java.util.UUID;
public final class FeelingLucky extends JavaPlugin {
private static final Map<UUID, PlayerConfig> configMap = new HashMap<>();
public LuckCMD cmd;
public PlayerHandler handler;
public PlayerListener playerListener;
private final Map<UUID, PlayerConfig> configMap = new HashMap<>();
public static Map<UUID, PlayerConfig> getConfigMap() {
private PlayerHandler handler;
private Config config;
public Map<UUID, PlayerConfig> getConfigMap() {
return configMap;
}
@Override
public void onEnable() {
Bukkit.getLogger().info("Initializing the PlayerHandler...");
getLogger().info("Initializing the PlayerHandler...");
handler = new PlayerHandler(this);
Bukkit.getLogger().info("Initialization complete! Attempting to register the Listeners...");
playerListener = new PlayerListener(this);
Bukkit.getLogger().info("Registration complete! Attempting to load all player configuration files...");
getLogger().info("Initialization complete! Attempting to register the Listeners...");
registerListeners();
getLogger().info("Registration complete! Attempting to load all player configuration files...");
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...");
new LuckCMD(this);
getLogger().info("Successfully loaded the Luck command!");
getLogger().info("Successfully initialized!");
}
@Override
public void onDisable() {
getLogger().info("Saving all player configurations...");
configMap.values().forEach(PlayerConfig::save);
getLogger().info("Complete! Saving the main config...");
config.save();
getLogger().info("Complete! Goodbye! :)");
}
private void loadPlayerConfigurations() {
File[] files = getDataFolder().listFiles();
if (files != null) {
Arrays.stream(files).forEach(file -> {
@ -41,17 +61,30 @@ public final class FeelingLucky extends JavaPlugin {
} else {
getLogger().info("There are no player configurations to load.");
}
}
Bukkit.getLogger().info("Attempting to load the Luck command...");
cmd = new LuckCMD(this);
Bukkit.getLogger().info("Successfully loaded the Luck command!");
private void registerListeners() {
new BlockDrops(this);
new BonemealFullCrop(this);
new CheatDeath(this);
new EnchantmentBoost(this);
new ExpBoost(this);
new IllOmen(this);
new ItemDrops(this);
new PlayerListener(this);
new RestoreHunger(this);
new TakeDamage(this);
new UnbreakableTool(this);
new VillagerInventory(this);
}
Bukkit.getLogger().info("Successfully initialized!");
public PlayerHandler getHandler() {
return handler;
}
@Override
public void onDisable() {
Bukkit.getLogger().info("Saving all player configurations...");
configMap.values().forEach(PlayerConfig::save);
@NotNull
public Config getConfig() {
return config;
}
}

View File

@ -0,0 +1,46 @@
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;
import java.util.HashMap;
import java.util.Map;
public abstract class AbstractListener implements Listener {
protected final FeelingLucky plugin;
protected final Map<AbstractListener, Rarity> listenerRarityMap = new HashMap<>();
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 enum Rarity {
HIGH,
MED,
LOW,
NONE
}
public boolean doesQualify(String name, double luck) {
switch (config.getRarity(name)) {
case HIGH:
if (luck < config.getChance("high_rarity_chance")) return false;
case MED:
if (luck < config.getChance("medium_rarity_chance")) return false;
case LOW:
if (luck < config.getChance("low_rarity_chance")) return false;
case NONE:
return true;
}
throw new IllegalArgumentException("The value for the listener rarity is not a recognized rarity value.");
}
}

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 io.github.simplex.luck.util.SneakyWorker;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.BlockDropItemEvent;
import java.util.List;
public final class BlockDrops extends AbstractListener {
public BlockDrops(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void extraBlockDrops(BlockDropItemEvent event) {
Player player = event.getPlayer();
Luck luck = getHandler().getLuckContainer(player);
List<Item> items = event.getItems();
if (luck.quickRNG(luck.getPercentage()) && doesQualify("block_drops", luck.getPercentage())) {
items.forEach(SneakyWorker::move);
}
}
}

View File

@ -0,0 +1,48 @@
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;
import org.bukkit.block.Block;
import org.bukkit.block.data.Ageable;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
public final class BonemealFullCrop extends AbstractListener {
public BonemealFullCrop(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void bonemealFullCrop(PlayerInteractEvent event) {
Player player = event.getPlayer();
Action action = event.getAction();
ItemStack bonemeal = ItemBuilder.of(Material.BONE_MEAL).build();
Luck luck = getHandler().getLuckContainer(player);
ItemStack handItem = event.getItem();
if (handItem == null) return;
Block block = event.getClickedBlock();
if (block == null) return;
BlockData data = block.getBlockData();
if (action.isRightClick()
&& handItem.isSimilar(bonemeal)
&& (data instanceof Ageable crop)
&& luck.quickRNG(luck.getPercentage())
&& doesQualify("bonemeal", luck.getPercentage())) {
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

@ -0,0 +1,27 @@
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.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.PlayerDeathEvent;
public final class CheatDeath extends AbstractListener {
public CheatDeath(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void cheatDeath(PlayerDeathEvent event) {
Player player = event.getPlayer();
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())) {
event.setCancelled(true);
player.setHealth(1.0);
player.setAbsorptionAmount(absorption);
player.sendMessage(MiniComponent.of("You got lucky and cheated death!").send());
}
}
}

View File

@ -0,0 +1,39 @@
package io.github.simplex.luck.listener;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.enchantment.EnchantItemEvent;
import java.util.List;
import java.util.Map;
public final class EnchantmentBoost extends AbstractListener {
public EnchantmentBoost(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void enchantItem(EnchantItemEvent event) {
Map<Enchantment, Integer> enchMap = event.getEnchantsToAdd();
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())) {
Enchantment particular = enchList.get(Luck.RNG().nextInt(enchList.size()));
int rng = Luck.RNG().nextInt(1, 5);
if ((enchMap.get(particular) + rng) > particular.getMaxLevel()) {
enchMap.replace(particular, particular.getMaxLevel());
}
enchMap.replace(particular, enchMap.get(particular) + rng);
}
}
public FeelingLucky plugin() {
return plugin;
}
}

View File

@ -0,0 +1,27 @@
package io.github.simplex.luck.listener;
import com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.entity.ExperienceOrb;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
public final class ExpBoost extends AbstractListener {
public ExpBoost(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void boostExperienceGain(PlayerPickupExperienceEvent event) {
ExperienceOrb orb = event.getExperienceOrb();
int n = orb.getExperience();
int math = (5 * n ^ 2) / (2 * n + 4);
int rounded = Math.round(math);
Player player = event.getPlayer();
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.quickRNG(luck.getPercentage()) && doesQualify("experience", luck.getPercentage())) {
orb.setExperience(rounded);
}
}
}

View File

@ -0,0 +1,81 @@
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.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityPotionEffectEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class IllOmen extends AbstractListener {
public IllOmen(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void reconnectCheck(PlayerJoinEvent event) {
Player player = event.getPlayer();
PotionEffectType type = PotionEffectType.BAD_OMEN;
Luck luck = getHandler().getLuckContainer(player);
if (player.hasPotionEffect(type)) {
luck.cache();
double maths = luck.getValue() - (luck.getValue() * 0.25);
luck.setValue(maths);
player.sendMessage(MiniComponent.info("A -25% debuff has been applied to your luck from the Bad Omen status effect."));
} else if (luck.cached(player) && !player.hasPotionEffect(type)) {
luck.restore();
player.sendMessage("The -25% debuff to your luck has been removed.");
}
}
@EventHandler
public void effectApplyCheck(EntityPotionEffectEvent event) {
EntityPotionEffectEvent.Cause cause = EntityPotionEffectEvent.Cause.PATROL_CAPTAIN;
EntityPotionEffectEvent.Action added = EntityPotionEffectEvent.Action.ADDED;
EntityPotionEffectEvent.Action changed = EntityPotionEffectEvent.Action.CHANGED;
if (event.getCause().equals(cause) && (event.getAction().equals(added) || event.getAction().equals(changed))) {
if (event.getEntity() instanceof Player player) {
Luck luck = plugin.getHandler().getLuckContainer(player);
luck.cache();
double maths = luck.getValue() - (luck.getValue() * 0.25);
luck.setValue(maths);
player.sendMessage(MiniComponent.warn("A -25% debuff has been applied to your luck from the Bad Omen status effect."));
}
}
}
@EventHandler
public void effectRemoveCheck(EntityPotionEffectEvent event) {
PotionEffect old = event.getOldEffect();
EntityPotionEffectEvent.Action cleared = EntityPotionEffectEvent.Action.CLEARED;
EntityPotionEffectEvent.Action removed = EntityPotionEffectEvent.Action.REMOVED;
if (old == null) return;
if (old.getType().equals(PotionEffectType.BAD_OMEN) && (event.getAction().equals(cleared) || event.getAction().equals(removed))) {
if ((event.getEntity() instanceof Player player)) {
Luck luck = plugin.getHandler().getLuckContainer(player);
if (luck.cached(player)) {
luck.restore();
player.sendMessage("The -25% debuff to your luck has been removed.");
}
}
}
}
@EventHandler
public void disconnectCheck(PlayerQuitEvent event) {
if (event.getPlayer().hasPotionEffect(PotionEffectType.BAD_OMEN)) {
Luck luck = plugin.getHandler().getLuckContainer(event.getPlayer());
if (luck.cached(event.getPlayer())) {
luck.restore();
}
}
}
}

View File

@ -0,0 +1,74 @@
package io.github.simplex.luck.listener;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityDropItemEvent;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class ItemDrops extends AbstractListener {
private final Map<UUID, Player> entityPlayerMap = new HashMap<>();
private boolean canAffect = false;
public ItemDrops(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void checkForPreItemDrop(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof LivingEntity entity)) {
return;
}
if (!(event.getDamager() instanceof Player player)) {
return;
}
if (!(entity.getHealth() <= 0.0)) {
return;
}
entityPlayerMap.put(entity.getUniqueId(), player);
}
@EventHandler
public void checkForDroppedItems(EntityDeathEvent event) {
if (event.getEntity() instanceof Player) {
canAffect = false;
return;
}
canAffect = event.getDrops().isEmpty();
}
@EventHandler
public void itemDrops(EntityDropItemEvent event) {
Entity entity = event.getEntity();
if (entityPlayerMap.get(entity.getUniqueId()) == null) return;
if (!canAffect) return;
Player player = entityPlayerMap.get(entity.getUniqueId());
Luck luck = getHandler().getLuckContainer(player);
Item item = event.getItemDrop();
ItemStack stack = item.getItemStack();
int amount = stack.getAmount();
if (luck.quickRNG(luck.getPercentage()) && doesQualify("item_drops", luck.getPercentage())) {
int rng = Luck.RNG().nextInt(2, 5);
amount += rng;
stack.setAmount(amount);
event.getItemDrop().setItemStack(stack);
}
}
}

View File

@ -1,194 +1,65 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.PotionEffectBuilder;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.ListBox;
import io.github.simplex.luck.SneakyWorker;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.util.CooldownTimer;
import io.github.simplex.luck.util.SpecialFootItem;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.entity.*;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Guardian;
import org.bukkit.entity.Player;
import org.bukkit.entity.Witch;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockDropItemEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.Objects;
public class PlayerListener implements Listener {
private final Map<UUID, Player> entityPlayerMap = new HashMap<>();
private final FeelingLucky plugin;
public final class PlayerListener extends AbstractListener {
private final CooldownTimer timer;
public PlayerListener(FeelingLucky plugin) {
this.plugin = plugin;
Bukkit.getServer().getPluginManager().registerEvents(this, plugin);
}
@EventHandler
public void takeDamage(EntityDamageEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof Player)) {
return;
}
Player player = (Player) event.getEntity();
Luck luck = plugin.handler.getLuckContainer(player);
if (ListBox.acceptedCauses.contains(event.getCause())) {
if (luck.notDefault()) {
double percentage = luck.getPercentage();
/*
* If a player's luck stat is a negative number, or they are "marked",
* this will trigger instead of the regular luck spin.
*/
if (percentage < 0 || luck.isMarked(player)) {
percentage = Math.abs(percentage);
if (luck.quickRNG(percentage)) {
event.setCancelled(true);
player.damage(event.getDamage() * 2);
player.sendMessage(Component.empty().content("You were unlucky and took double damage."));
}
return;
}
if (luck.quickRNG(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();
/*
* If a player's luck stat is a negative number, or they are "marked",
* this will trigger instead of the regular luck spin.
*/
if (percentage < 0 || luck.isMarked(player)) {
percentage = Math.abs(percentage);
if (luck.quickRNG(percentage)) {
event.setCancelled(true);
player.addPotionEffect(PotionEffectBuilder.newEffect().type(ListBox.potionEffects.get(Luck.RNG().nextInt(ListBox.potionEffects.size() - 1))).amplifier(Luck.RNG().nextInt(1, 5)).duration(Luck.RNG().nextInt(1, 120)).create());
}
return;
}
if (luck.quickRNG(percentage)) {
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."));
}
}
}
}
@EventHandler
public void extraBlockDrops(BlockDropItemEvent event) {
Player player = event.getPlayer();
Luck luck = plugin.handler.getLuckContainer(player);
List<Item> items = event.getItems();
if (luck.quickRNG(luck.getPercentage())) {
items.forEach(SneakyWorker::move);
}
}
@EventHandler
public void checkForPreItemDrop(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof LivingEntity entity)) {
return;
}
if (!(event.getDamager() instanceof Player player)) {
return;
}
if (!(entity.getHealth() <= 0.0)) {
return;
}
if (entity instanceof Witch witch) {
if (Luck.quickRNG2(33.0)) {
Location location = witch.getLocation();
World world = location.getWorld();
Item item = world.dropItemNaturally(location, new ItemStack(Material.RABBIT_FOOT, 1));
new EntityDropItemEvent(witch, item).callEvent();
}
}
entityPlayerMap.put(entity.getUniqueId(), player);
}
@EventHandler
public void itemDrops(EntityDropItemEvent event) {
Entity entity = event.getEntity();
if (entityPlayerMap.get(entity.getUniqueId()) == null) return;
Player player = entityPlayerMap.get(entity.getUniqueId());
Luck luck = plugin.handler.getLuckContainer(player);
Item item = event.getItemDrop();
ItemStack stack = item.getItemStack();
int amount = stack.getAmount();
if (luck.quickRNG(luck.getPercentage())) {
int rng = Luck.RNG().nextInt(2, 5);
amount += rng;
stack.setAmount(amount);
event.getItemDrop().setItemStack(stack);
}
}
@EventHandler
public void restoreHunger(PlayerItemConsumeEvent event) {
ItemStack item = event.getItem();
Luck luck = plugin.handler.getLuckContainer(event.getPlayer());
PotionEffect effect = PotionEffectBuilder.newEffect().type(PotionEffectType.SATURATION).amplifier(2).duration(10).particles(false).create();
if (luck.notDefault()) {
double percentage = luck.getPercentage();
ListBox.foods.forEach(food -> {
if (item.isSimilar(food)) {
if (luck.quickRNG(percentage)) {
event.getPlayer().setExhaustion(event.getPlayer().getExhaustion() + 2);
event.getPlayer().addPotionEffect(effect);
}
}
});
}
super(plugin);
this.timer = new CooldownTimer();
}
@EventHandler
public void rabbitFoot(PlayerInteractEvent event) {
Action action = event.getAction();
ItemStack foot = new ItemStack(Material.RABBIT_FOOT);
SpecialFootItem special = new SpecialFootItem();
Player player = event.getPlayer();
Luck luck = plugin.handler.getLuckContainer(player);
Luck luck = getHandler().getLuckContainer(player);
if (timer.onCooldown(player)) {
player.sendMessage(MiniComponent.err("That feature can only be used once every 30 seconds."));
player.sendMessage(MiniComponent.info("You have " + timer.remaining(player) + " seconds remaining."));
return;
}
if (action.isRightClick() && player.getInventory().getItemInMainHand().isSimilar(foot)) {
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!"));
}
double rng = Luck.RNG().nextDouble(2.0, 5.0);
player.getInventory().remove(player.getInventory().getItemInMainHand());
luck.addTo(rng);
plugin.handler.updatePlayer(player, luck);
player.sendMessage(Component.empty().content("Your luck has been increased by " + rng + " points."));
plugin.getHandler().updatePlayer(player, luck);
timer.setCooldown(player.getUniqueId(), System.currentTimeMillis());
player.sendMessage(MiniComponent.info("Your luck has been increased by " + rng + " points."));
}
}
@EventHandler
public void witchesBrew(EntityDamageByEntityEvent event) {
public void luckDecrease(EntityDamageByEntityEvent event) {
Entity eTEMP = event.getDamager();
Entity pTEMP = event.getEntity();
EntityDamageEvent.DamageCause cause = event.getCause();
@ -197,16 +68,37 @@ public class PlayerListener implements Listener {
return;
}
if (!(eTEMP instanceof Witch)) {
if (!(eTEMP instanceof Witch) || !(eTEMP instanceof Guardian)) {
return;
}
Luck luck = plugin.handler.getLuckContainer(player);
Luck luck = plugin.getHandler().getLuckContainer(player);
if (cause.equals(EntityDamageEvent.DamageCause.MAGIC) || cause.equals(EntityDamageEvent.DamageCause.POISON)) {
if (luck.quickRNG(33.0)) {
luck.takeFrom(5.0);
plugin.handler.updatePlayer(player, luck);
plugin.getHandler().updatePlayer(player, luck);
player.sendMessage(MiniComponent.warn("Your luck has been decreased by 5 points!"));
}
}
}
@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

@ -0,0 +1,35 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.PotionEffectBuilder;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.util.ListBox;
import org.bukkit.event.EventHandler;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class RestoreHunger extends AbstractListener {
public RestoreHunger(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void restoreHunger(PlayerItemConsumeEvent event) {
ItemStack item = event.getItem();
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();
ListBox.foods.forEach(food -> {
if (item.isSimilar(food)) {
if (luck.quickRNG(percentage) && doesQualify("restore_hunger", percentage)) {
event.getPlayer().setExhaustion(event.getPlayer().getExhaustion() + 2);
event.getPlayer().addPotionEffect(effect);
}
}
});
}
}
}

View File

@ -0,0 +1,78 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.PotionEffectBuilder;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.util.ListBox;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.entity.EntityDamageEvent;
public class TakeDamage extends AbstractListener {
public TakeDamage(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void takeDamage(EntityDamageEvent event) {
Entity entity = event.getEntity();
if (!(entity instanceof Player)) {
return;
}
Player player = (Player) event.getEntity();
Luck luck = getHandler().getLuckContainer(player);
if (ListBox.acceptedCauses.contains(event.getCause())) {
if (luck.notDefault()) {
double percentage = luck.getPercentage();
/*
* If a player's luck stat is a negative number, or they are "marked",
* this will trigger instead of the regular luck spin.
*/
if (percentage < 0 || luck.isMarked(player)) {
percentage = Math.abs(percentage);
if (luck.quickRNG(percentage)) {
event.setCancelled(true);
player.damage(event.getDamage() * 2);
player.sendMessage(Component.empty().content("You were unlucky and took double damage."));
}
return;
}
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();
/*
* If a player's luck stat is a negative number, or they are "marked",
* this will trigger instead of the regular luck spin.
*/
if (percentage < 0 || luck.isMarked(player)) {
percentage = Math.abs(percentage);
if (luck.quickRNG(percentage)) {
event.setCancelled(true);
player.addPotionEffect(PotionEffectBuilder.newEffect().type(ListBox.potionEffects.get(Luck.RNG().nextInt(ListBox.potionEffects.size() - 1))).amplifier(Luck.RNG().nextInt(1, 5)).duration(Luck.RNG().nextInt(1, 120)).create());
}
return;
}
if (luck.quickRNG(percentage) && doesQualify("take_damage", percentage)) {
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."));
}
}
}
}
}

View File

@ -0,0 +1,39 @@
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.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.inventory.CraftingInventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class UnbreakableTool extends AbstractListener {
public UnbreakableTool(FeelingLucky plugin) {
super(plugin);
}
@EventHandler
public void unbreakableTool(CraftItemEvent event) {
CraftingInventory inventory = event.getInventory();
ItemStack stack = inventory.getResult();
if (stack == null) return;
ItemMeta meta = stack.getItemMeta();
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())) {
meta.setUnbreakable(true);
stack.setItemMeta(meta);
inventory.setResult(stack);
player.sendMessage(MiniComponent.info("By the grace of Luck you have crafted an unbreakable tool!"));
}
}
}
}
}

View File

@ -0,0 +1,52 @@
package io.github.simplex.luck.listener;
import io.github.simplex.lib.ItemBuilder;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.util.SpecialFootItem;
import org.bukkit.Material;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerInteractAtEntityEvent;
import org.bukkit.inventory.MerchantRecipe;
import java.util.ArrayList;
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);
public VillagerInventory(FeelingLucky plugin) {
super(plugin);
recipe.setIngredients(Arrays.asList(
ItemBuilder.of(Material.EMERALD).build(),
ItemBuilder.of(Material.RABBIT_HIDE).build()
));
recipe.setDemand(8);
recipe.setPriceMultiplier(1.25F);
recipe.setVillagerExperience(25);
recipe.setSpecialPrice(4);
}
@EventHandler
public void addRabbitFootToVillagerInventory(PlayerInteractAtEntityEvent event) {
if (event.getRightClicked() instanceof Villager vil) {
if (!vil.getProfession().equals(Villager.Profession.BUTCHER)) return;
List<MerchantRecipe> recipeList = new ArrayList<>(vil.getRecipes());
if (recipeList.contains(recipe)) return;
Luck luck = plugin.getHandler().getLuckContainer(event.getPlayer());
if (luck == null) return;
if (luck.quickRNG(luck.getPercentage())) {
recipeList.add(recipe);
vil.setRecipes(recipeList);
}
}
}
}

View File

@ -8,29 +8,55 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
import java.util.SplittableRandom;
import java.util.*;
@SuppressWarnings("all")
public class Luck implements LuckContainer {
private final Player player;
private final double multiplier;
private final double BASE_VALUE;
private final PlayerLuckChangeEvent event;
private final FeelingLucky plugin;
private final List<Player> markedPlayers = new ArrayList<>();
private final Map<Player, Double> cache = new HashMap<>();
private double BASE_VALUE;
private double multiplier;
private double tempSave;
public Luck(Player player) {
this(player, 1.0);
public Luck(FeelingLucky plugin, Player player) {
this(plugin, player, 1.0);
}
public Luck(Player player, double multiplier) {
public Luck(FeelingLucky plugin, Player player, double multiplier) {
this.player = player;
this.multiplier = multiplier;
BASE_VALUE = player.getAttribute(Attribute.GENERIC_LUCK).getDefaultValue();
this.plugin = plugin;
BASE_VALUE = plugin.getConfigMap().get(player.getUniqueId()).getConfig().getDouble("luck");
tempSave = BASE_VALUE;
event = new PlayerLuckChangeEvent(this);
}
private final List<Player> markedPlayers = new ArrayList<>();
@Contract(pure = true,
value = "-> new")
public static @NotNull SplittableRandom RNG() {
return new SplittableRandom();
}
public static boolean quickRNGnoMultiplier(double percentage) {
double rng;
if (percentage >= 100.0) {
rng = 1024.0; // 100% chance to trigger, obviously;
} else {
rng = RNG().nextDouble(0.0, 1024.0);
}
double actual = Math.round((rng / 1024.0) * 100);
return (percentage >= actual);
}
public FeelingLucky getPlugin() {
return plugin;
}
public void markPlayer(Player player) {
markedPlayers.add(player);
@ -44,25 +70,6 @@ public class Luck implements LuckContainer {
return markedPlayers.contains(player);
}
@Contract(pure = true,
value = "-> new")
public static @NotNull SplittableRandom RNG() {
return new SplittableRandom();
}
public static boolean quickRNG2(double percentage) {
double rng;
if (percentage >= 100.0) {
rng = 1024.0; // 100% chance to trigger, obviously;
} else {
rng = RNG().nextDouble(0.0, 1024.0);
}
double actual = Math.round((rng / 1024.0) * 100);
return (percentage >= actual);
}
@Override
public Attribute asAttribute() {
return Attribute.GENERIC_LUCK;
@ -119,14 +126,43 @@ public class Luck implements LuckContainer {
return BASE_VALUE;
}
public double getDefaultValue() {
return player.getAttribute(Attribute.GENERIC_LUCK).getDefaultValue();
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);
}
public void setValue(double value) {
player.getAttribute(Attribute.GENERIC_LUCK).setBaseValue(value);
FeelingLucky.getConfigMap().get(associatedPlayer().getUniqueId()).setLuck(value);
Bukkit.getPluginManager().callEvent(event);
public void setMultiplier(double multiplier) {
this.multiplier = multiplier;
plugin.getConfigMap().get(associatedPlayer().getUniqueId()).setMultiplier(multiplier);
}
public void cache() {
if (cache.containsKey(player)) {
cache.replace(player, getValue());
return;
}
cache.put(player, getValue());
}
public boolean cached(Player player) {
return cache.containsKey(player);
}
public void restore() {
if (!cache.containsKey(player)) {
plugin.getLogger().info("Nothing to restore!");
return;
}
setValue(cache.get(player));
cache.remove(player);
}
public double getDefaultValue() {
return player.getAttribute(Attribute.GENERIC_LUCK).getDefaultValue();
}
public void addTo(double value) {

View File

@ -1,7 +1,9 @@
package io.github.simplex.luck.player;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.SneakyWorker;
import io.github.simplex.luck.util.SneakyWorker;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.attribute.Attribute;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
@ -11,16 +13,18 @@ import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.util.UUID;
public class PlayerConfig {
private final File configFile;
private final FeelingLucky plugin;
private final OfflinePlayer player;
private volatile YamlConfiguration config;
@SuppressWarnings("ResultOfMethodCallIgnored")
public PlayerConfig(FeelingLucky plugin, Player player) {
this.plugin = plugin;
File dataFolder = plugin.getDataFolder();
this.player = player;
if (!plugin.getDataFolder().exists()) plugin.getDataFolder().mkdirs();
File dataFolder = new File(plugin.getDataFolder(), "players");
if (!dataFolder.exists()) dataFolder.mkdirs();
File file = new File(dataFolder, player.getUniqueId() + ".yml");
if (!file.exists()) {
@ -45,17 +49,17 @@ public class PlayerConfig {
String tempUsername = config.getString("username");
if (tempUsername != null && !tempUsername.equalsIgnoreCase(player.getName())) {
if (tempUsername == null) {
config.set("username", player.getName());
config.set("luck", plugin.handler.getLuckContainer(player).getDefaultValue());
config.set("luck", plugin.getHandler().getLuckContainer(player).getDefaultValue());
config.set("multiplier", "1.0");
save();
}
}
protected PlayerConfig(FeelingLucky plugin, File file) {
this.plugin = plugin;
this.configFile = file;
this.player = Bukkit.getOfflinePlayer(UUID.fromString(file.getName().split("\\.")[0]));
config = YamlConfiguration.loadConfiguration(configFile);
}
@ -72,11 +76,30 @@ public class PlayerConfig {
SneakyWorker.sneakyTry(() -> config = YamlConfiguration.loadConfiguration(configFile));
}
public void reload() {
save();
load();
}
public OfflinePlayer getPlayer() {
return player;
}
public void setUsername(String name) {
config.set("username", name);
save();
}
public void setLuck(double luck) {
config.set("luck", luck);
save();
}
public void setMultiplier(double multiplier) {
config.set("multiplier", multiplier);
save();
}
public YamlConfiguration getConfig() {
return config;
}

View File

@ -6,6 +6,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import java.util.HashMap;
import java.util.Map;
@ -30,11 +31,11 @@ public class PlayerHandler implements Listener {
@EventHandler
public void initializePlayer(PlayerLoginEvent event) {
Player player = event.getPlayer();
PlayerConfig playerConfig = FeelingLucky.getConfigMap().get(player.getUniqueId());
PlayerConfig playerConfig = plugin.getConfigMap().get(player.getUniqueId());
if (playerConfig == null) {
playerConfig = new PlayerConfig(plugin, player);
FeelingLucky.getConfigMap().put(player.getUniqueId(), playerConfig);
plugin.getConfigMap().put(player.getUniqueId(), playerConfig);
}
String username = playerConfig.getConfig().getString("username");
@ -47,9 +48,14 @@ public class PlayerHandler implements Listener {
playerConfig.load();
}
Luck container = new Luck(player, multiplier);
Luck container = new Luck(plugin, player, multiplier);
container.setValue(luck);
playerLuckMap.put(player, container);
}
@EventHandler
public void clearContainer(PlayerQuitEvent event) {
playerLuckMap.remove(event.getPlayer());
}
}

View File

@ -0,0 +1,38 @@
package io.github.simplex.luck.util;
import io.github.simplex.lib.MiniComponent;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
public class CooldownTimer {
private final Map<UUID, Long> cooldowns = new HashMap<>();
public static final long DEFAULT_COOLDOWN = 30L;
public void setCooldown(UUID playerUUID, long time) {
if (time < 1) {
cooldowns.remove(playerUUID);
} else {
cooldowns.put(playerUUID, time);
}
}
public long getCooldown(UUID uuid) {
return cooldowns.getOrDefault(uuid, 0L);
}
public long remaining(Player player) {
long timeLeft = System.currentTimeMillis() - getCooldown(player.getUniqueId());
return TimeUnit.MILLISECONDS.toSeconds(timeLeft) - DEFAULT_COOLDOWN;
}
public boolean onCooldown(Player player) {
long remaining = System.currentTimeMillis() - getCooldown(player.getUniqueId());
return (!(TimeUnit.MILLISECONDS.toSeconds(remaining) >= DEFAULT_COOLDOWN));
}
}

View File

@ -1,4 +1,4 @@
package io.github.simplex.luck;
package io.github.simplex.luck.util;
import org.bukkit.Material;
import org.bukkit.event.entity.EntityDamageEvent;

View File

@ -1,19 +1,22 @@
package io.github.simplex.luck;
package io.github.simplex.luck.util;
import io.github.simplex.lib.Messages;
import io.github.simplex.lib.MiniComponent;
import io.github.simplex.luck.FeelingLucky;
import io.github.simplex.luck.player.Luck;
import io.github.simplex.luck.player.PlayerConfig;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.TextColor;
import org.bukkit.Bukkit;
import org.bukkit.command.*;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.command.TabCompleter;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class LuckCMD extends Command implements TabCompleter {
private final FeelingLucky plugin;
@ -31,37 +34,55 @@ public class LuckCMD extends Command implements TabCompleter {
if (args.length == 3) {
if ((sender instanceof ConsoleCommandSender) || sender.hasPermission("luck.admin")) {
if (args[0].equalsIgnoreCase("reload") && args[1].equalsIgnoreCase("-p")) {
Player player = Bukkit.getPlayer(args[2]);
if (player == null) {
sender.sendMessage(Messages.NO_PLAYER.get());
return true;
}
UUID uuid = player.getUniqueId();
PlayerConfig config = plugin.getConfigMap().get(uuid);
config.reload();
sender.sendMessage(MiniComponent.info("Successfully reloaded " + player.getName() + "'s configuration file."));
return true;
}
Player player = Bukkit.getPlayer(args[1]);
double amount = Double.parseDouble(args[2]);
if (player == null) {
sender.sendMessage(Component.empty().content("That player cannot be found."));
sender.sendMessage(Messages.NO_PLAYER.get());
return true;
}
Luck luck = plugin.handler.getLuckContainer(player);
PlayerConfig config = FeelingLucky.getConfigMap().get(player.getUniqueId());
if (amount > 1024.0 || amount < -1024.0) {
sender.sendMessage(Messages.OUT_OF_BOUNDS.get());
return true;
}
Luck luck = plugin.getHandler().getLuckContainer(player);
PlayerConfig config = plugin.getConfigMap().get(player.getUniqueId());
switch (args[0]) {
case "set" -> {
luck.setValue(amount);
plugin.handler.updatePlayer(player, luck);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(Component.empty().content("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
return true;
}
case "give" -> {
luck.addTo(amount);
plugin.handler.updatePlayer(player, luck);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(Component.empty().content("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
return true;
}
case "take" -> {
luck.takeFrom(amount);
plugin.handler.updatePlayer(player, luck);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(Component.empty().content("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
return true;
}
}
@ -73,16 +94,20 @@ public class LuckCMD extends Command implements TabCompleter {
if (args.length == 2) {
if ((sender instanceof ConsoleCommandSender) || sender.hasPermission("luck.admin")) {
if (args[0].equalsIgnoreCase("reload") && args[1].equalsIgnoreCase("-m")) {
}
if (args[0].equalsIgnoreCase("info")) {
Player player = Bukkit.getPlayer(args[1]);
if (player == null) {
sender.sendMessage("That player cannot be found.");
sender.sendMessage(Messages.NO_PLAYER.get());
return true;
}
Luck luck = plugin.handler.getLuckContainer(player);
sender.sendMessage(Component.empty().content("Luck stat for " + args[1] + ": " + luck.getValue()));
Luck luck = plugin.getHandler().getLuckContainer(player);
sender.sendMessage(MiniComponent.info("Luck stat for " + args[1] + ": " + luck.getValue()));
return true;
}
@ -90,16 +115,16 @@ public class LuckCMD extends Command implements TabCompleter {
Player player = Bukkit.getPlayer(args[1]);
if (player == null) {
sender.sendMessage(Component.empty().content("That player cannot be found."));
sender.sendMessage(Messages.NO_PLAYER.get());
return true;
}
Luck luck = plugin.handler.getLuckContainer(player);
PlayerConfig config = FeelingLucky.getConfigMap().get(player.getUniqueId());
Luck luck = plugin.getHandler().getLuckContainer(player);
PlayerConfig config = plugin.getConfigMap().get(player.getUniqueId());
luck.reset();
plugin.handler.updatePlayer(player, luck);
plugin.getHandler().updatePlayer(player, luck);
config.setLuck(luck.getValue());
sender.sendMessage(Component.empty().content("Successfully reset " + args[1] + "'s Luck stat."));
sender.sendMessage(MiniComponent.info("Successfully reset " + args[1] + "'s Luck stat."));
return true;
}
} else {
@ -109,11 +134,16 @@ public class LuckCMD extends Command implements TabCompleter {
}
if (args.length == 1) {
if (args[0].equalsIgnoreCase("reload") && sender.hasPermission("luck.admin")) {
plugin.getConfigMap().values().forEach(PlayerConfig::reload);
sender.sendMessage(MiniComponent.info("Player configurations reloaded."));
return true;
}
if ((sender instanceof Player player) && player.hasPermission("luck.default")) {
if (args[0].equalsIgnoreCase("info")) {
Luck luck = plugin.handler.getLuckContainer(player);
TextComponent c = Component.text("Your Luck: " + luck.getPercentage());
player.sendMessage(c.color(TextColor.color(0, 255, 0)));
Luck luck = plugin.getHandler().getLuckContainer(player);
player.sendMessage(MiniComponent.info("Your Luck: " + luck.getPercentage()));
return true;
}
} else if (sender instanceof ConsoleCommandSender) {
@ -122,7 +152,7 @@ public class LuckCMD extends Command implements TabCompleter {
}
}
return true;
return false;
}
@Override
@ -148,6 +178,7 @@ public class LuckCMD extends Command implements TabCompleter {
switch (args[0]) {
case "info":
case "reset":
case "reload":
return new ArrayList<>();
case "give":
case "take":

View File

@ -1,4 +1,4 @@
package io.github.simplex.luck;
package io.github.simplex.luck.util;
import io.github.simplex.luck.player.Luck;
import org.bukkit.Bukkit;

View File

@ -0,0 +1,26 @@
package io.github.simplex.luck.util;
import io.github.simplex.lib.ItemBuilder;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
public class SpecialFootItem {
public final ItemStack stack;
public 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.")
.build();
}
public ItemStack get() {
return stack;
}
public ItemMeta meta() {
return stack.getItemMeta();
}
}

View File

@ -0,0 +1,26 @@
# These entries are for the minimum amount of luck required for the event to actually trigger.
# These work in addition to the RNG generator,
# meaning both the RNG and this condition must be met for the event to trigger.
# These values must be in the form of doubles, as listed below.
# The maximum amount of luck that can be attributed is 1024.0, and the minimum is -1024.0
high_rarity_chance: 512
medium_rarity_chance: 128
low_rarity_chance: 64
# The following entries are for the rarity level of each event trigger.
# This will determine which rarity chance to use which ensures players
# The following values are accepted: NONE, LOW, MED, HIGH
# - None implies that there is no rarity chance attributed to that feature.
# These entries are case-sensitive.
block_drops: LOW
bonemeal: LOW
cheat_death: MED
enchanting: HIGH
experience: HIGH
item_drops: LOW
random_effect: HIGH
restore_hunger: MED
take_damage: MED
unbreakable: HIGH