Compare commits
No commits in common. "master" and "feat-transfer" have entirely different histories.
master
...
feat-trans
196 changed files with 4925 additions and 6615 deletions
71
.gitignore
vendored
71
.gitignore
vendored
|
@ -1,29 +1,50 @@
|
|||
.gradle
|
||||
build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/
|
||||
*.iws
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# Idea files
|
||||
*.iml
|
||||
*.ipr
|
||||
out/
|
||||
!**/src/main/**/out/
|
||||
!**/src/test/**/out/
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
bin/
|
||||
!**/src/main/**/bin/
|
||||
!**/src/test/**/bin/
|
||||
# Nicko first pass build files
|
||||
core/target
|
||||
v1_14_R1/target
|
||||
v1_15_R1/target
|
||||
v1_16_R1/target
|
||||
v1_16_R2/target
|
||||
v1_16_R3/target
|
||||
v1_17_R1/target
|
||||
v1_18_R1/target
|
||||
v1_18_R2/target
|
||||
v1_19_R1/target
|
||||
|
||||
### Server ###
|
||||
run/
|
||||
# Idea Folder
|
||||
.idea
|
||||
|
||||
# Build folder
|
||||
target
|
||||
|
||||
# Maven Dependency Reduced Pom
|
||||
dist/dependency-reduced-pom.xml
|
||||
core/dependency-reduced-pom.xml
|
8
.idea/.gitignore
generated
vendored
8
.idea/.gitignore
generated
vendored
|
@ -1,8 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
18
.idea/gradle.xml
generated
18
.idea/gradle.xml
generated
|
@ -1,18 +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="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
</set>
|
||||
</option>
|
||||
<option name="resolveExternalAnnotations" value="true" />
|
||||
</GradleProjectSettings>
|
||||
</option>
|
||||
<option name="parallelModelFetch" value="true" />
|
||||
</component>
|
||||
</project>
|
7
.idea/inspectionProfiles/Project_Default.xml
generated
7
.idea/inspectionProfiles/Project_Default.xml
generated
|
@ -1,7 +0,0 @@
|
|||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="UnusedReceiverParameter" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
<inspection_tool class="UnusedSymbol" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||
</profile>
|
||||
</component>
|
10
.idea/misc.xml
generated
10
.idea/misc.xml
generated
|
@ -1,10 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="PWA">
|
||||
<option name="wasEnabledAtLeastOnce" value="true" />
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_22" project-jdk-name="graal-22" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
124
.idea/uiDesigner.xml
generated
124
.idea/uiDesigner.xml
generated
|
@ -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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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.svg" 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>
|
129
CHANGELOG.log
129
CHANGELOG.log
|
@ -1,129 +0,0 @@
|
|||
1.3.0-RC1: Update n°13 (XX/XX/25)
|
||||
[FEATURES]
|
||||
- Players are now able to mark disguises as favorites.
|
||||
|
||||
[FIXES]
|
||||
- Fixed a bug where a player was improperly named when inspecting it in the admin panel.
|
||||
- Added a missing sound when players undisguised.
|
||||
|
||||
1.2.0-RC1: Update n°12 (XX/XX/25)
|
||||
[FEATURES]
|
||||
- Updated to support Minecraft 1.21.5.
|
||||
- Added a sub-command (/nicko about) to get information about Nicko.
|
||||
- Modernized the messages and added various sound effects upon interacting with the plugin.
|
||||
- Cleaned up GUI titles.
|
||||
|
||||
[FIXES]
|
||||
- Fixed an oversight preventing the configuration from properly being migrated.
|
||||
- Fixed a rare bug that could prevent data from being saved.
|
||||
- Fixed the placeholder item in the skin cache invalidation not being translated.
|
||||
- Fixed a oversight about a column name using SQL storage.
|
||||
|
||||
[LANGUAGE]
|
||||
- Moved the prefix to the language file.
|
||||
|
||||
[OTHER]
|
||||
- Cleaned up the codebase to prepare for future updates.
|
||||
|
||||
1.1.7-RC1: Hotfix n°5 (04/05/24)
|
||||
[OTHER]
|
||||
- Restored download link again on spigotmc.org
|
||||
|
||||
1.1.6-RC1: Update n°11 (04/05/24)
|
||||
[FEATURES]
|
||||
- Update dependencies in preparation to the 1.20.5 update
|
||||
|
||||
[OTHER]
|
||||
- Restored download link on spigotmc.org
|
||||
|
||||
1.1.5-RC1: Update n°10 (25/12/23)
|
||||
[FEATURES]
|
||||
- Various improvements to performance.
|
||||
[FIXES]
|
||||
- Fixed a bug related to configuration migration.
|
||||
|
||||
1.1.4-RC1: Update n°9 (07/02/23)
|
||||
[OTHER]
|
||||
- The repository hosting the previous version of Nicko had expired, this is now fixed.
|
||||
|
||||
1.1.3-RC1: Hotfix n°4 (28/12/23)
|
||||
[FIXES]
|
||||
- Fixed the English Locale version being late.
|
||||
|
||||
1.1.2-RC1: Update n°8 (28/12/23)
|
||||
[FEATURES]
|
||||
- Players now default back to their original appearance upon failure.
|
||||
|
||||
[FIXES]
|
||||
- Fixed an invalid placeholder parameter (%nicko_random_skin% now gets if the player has random skin on login set or not).
|
||||
- Fixed the error reason not appearing upon failure.
|
||||
- Fixed player profiles (name and skin associated) not being reset gracefully upon failure.
|
||||
- Fixed error messages not being precise enough.
|
||||
- Various optimizations and improvements.
|
||||
|
||||
1.1.1-RC1: Update n°7 (27/12/23)
|
||||
[FEATURES]
|
||||
- Made Nicko compatible with 1.20.3 and 1.20.4.
|
||||
|
||||
|
||||
1.1.0-RC1: Update n°6 (23/12/23)
|
||||
[BREAKING]
|
||||
- The language system has been updated to use the Adventure library (https://docs.advntr.dev/index.html). This results in the custom locale breaking
|
||||
Nicko upon usage of legacy color codes (e.g., "§6Nicko"). Your custom locale will be backed up upon starting this version and you will be able to
|
||||
use the new default English locale to help you make your locale compatible with the new formatting.
|
||||
|
||||
[FEATURES]
|
||||
- Players can now choose to get a random appearance via a list of more than 400 usernames and skins associated.
|
||||
- Players can now toggle a setting to automatically get a random appearance upon joining.
|
||||
- Introduced a version string inside Nicko's language files to plan future updates to the file. (see [BREAKING])
|
||||
|
||||
(Note: the random skin functionality is still work-in-progress and might break or not work at all because of
|
||||
the lack of time that I have to test all the usernames and skins associated.)
|
||||
|
||||
[FIXES]
|
||||
- Various optimizations and improvements.
|
||||
- Internal refactoring
|
||||
- bStats metrics are not minified anymore.
|
||||
|
||||
1.0.8-RC1: Update n°5 (19/12/23)
|
||||
[FEATURES]
|
||||
- Introduced a version string inside Nicko's configuration to plan future updates to the file. Your previous configuration file will automatically be migrated to this current version (with the backup of your old one included!)
|
||||
- Persistence and cache will now fallback to local alternatives when unreachable.
|
||||
- Player check GUI has been updated to better reflect the current state of player's disguises.
|
||||
- Developers can now listen to the PlayerDisguiseEvent and cancel the disguise process.
|
||||
|
||||
[OTHER]
|
||||
- Various optimizations and improvements.
|
||||
- Internal refactoring
|
||||
|
||||
1.0.7-RC1: Update n°4 (13/12/23)
|
||||
[OTHER]
|
||||
- In line with my thinking that Minecraft servers should always be in one of the latest versions to give developers more freedom and less maintenance hassle, Nicko will now only be supporting the current major version and the one before it. This results in this version of Nicko now needing at minimum Java version 17 and a server running 1.19. If you can't upgrade, consider myself sorry.
|
||||
- Various optimizations and improvements following the upgrade to Java 17.
|
||||
|
||||
1.0.6-RC1: Update n°3 (11/12/23)
|
||||
[OTHER]
|
||||
- Added telemetry via bStats to gather useful informations about Nicko. This feature is optional and can be disabled inside the "bStats" folder found in plugins folder. Informations gathered are public record and can be found at: https://bstats.org/plugin/bukkit/Nicko/20483.
|
||||
|
||||
1.0.5-RC1: Update n°2 (11/12/23)
|
||||
[OTHER]
|
||||
- Moved plugin to the Gradle build chain, resulting in faster builds and smaller Jar. This has no consequences for players.
|
||||
|
||||
1.0.4-RC1:
|
||||
[FEATURES]
|
||||
- The players check GUI is now updated upon player's joining and leaving
|
||||
- Administrators are now able to remove a player's disguise through the player check GUI
|
||||
|
||||
1.0.3-RC1: Hotfix n°3 (07/12/23)
|
||||
[FIXES]
|
||||
- Fixed a visual bug where players in survival mode were seeing themselves as having full health and hunger after disguising.
|
||||
|
||||
1.0.2-RC1: Hotfix n°2 (06/12/23)
|
||||
[OTHER]
|
||||
- Internal refactoring
|
||||
|
||||
1.0.1-RC1: Hotfix n°1 (06/12/23)
|
||||
[FIXES]
|
||||
- Fixed an issue when joining and players being disguised were not for the player joining.
|
||||
|
||||
|
31
README.md
31
README.md
|
@ -1,29 +1,14 @@
|
|||
# *Nicko* <img style="vertical-align:middle" src="./img/LOGO.png" alt="" width="65"/>
|
||||
# _Nicko_ <img style="vertical-align:middle" src="./img/LOGO.png" alt="" width="50"/>
|
||||
|
||||
## The feature packed, next generation disguise plugin for Minecraft.
|
||||
## The next-generation, most feature-packed disguise plugin for Minecraft.
|
||||
|
||||
---
|
||||
### Download:
|
||||
|
||||
## Download:
|
||||
|
||||
https://www.spigotmc.org/resources/nicko.113868/
|
||||
|
||||
---
|
||||
|
||||
## Known bugs:
|
||||
|
||||
- Players who have operator (OP) status lose access to the Operator Items tab in creative mode
|
||||
after disguising **(1.20 and up)**.
|
||||
- When disguising and only changing their display name, players will have the new default
|
||||
skins **(1.20 and up)**.
|
||||
|
||||
---
|
||||
Coming soon! ⏳
|
||||
|
||||
#### Version compatibility table
|
||||
|
||||
| Version | Plugin |
|
||||
|---------------|----------------------------------------------------------------------------|
|
||||
| 1.7 and lower | Unsupported |
|
||||
| 1.8 - 1.12.2 | Use [NickReloaded](https://www.spigotmc.org/resources/nickreloaded.46335/) |
|
||||
| 1.13 to 1.19 | Unsupported |
|
||||
| 1.20 - 1.21 | Use Nicko |
|
||||
| Version | Supported |
|
||||
|-----------|----------------------------------------------------------------------------|
|
||||
| < 1.12.2 | Use [NickReloaded](https://www.spigotmc.org/resources/nickreloaded.46335/) |
|
||||
| \> 1.12.2 | Supported |
|
106
build.gradle.kts
106
build.gradle.kts
|
@ -1,106 +0,0 @@
|
|||
plugins {
|
||||
id("java")
|
||||
id("com.gradleup.shadow") version "8.3.2"
|
||||
id("xyz.jpenilla.run-paper") version "2.3.0"
|
||||
id("io.papermc.paperweight.userdev") version "2.0.0-beta.17"
|
||||
}
|
||||
|
||||
group = "xyz.ineanto"
|
||||
version = "1.2.0"
|
||||
|
||||
val invuiVersion: String = "1.44"
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_22
|
||||
targetCompatibility = JavaVersion.VERSION_22
|
||||
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(22)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
mavenLocal()
|
||||
|
||||
maven("https://repo.xenondevs.xyz/releases")
|
||||
maven("https://repo.papermc.io/repository/maven-public/")
|
||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
||||
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
paperweight.paperDevBundle("1.21.5-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly("me.clip:placeholderapi:2.11.5")
|
||||
compileOnly("net.kyori:adventure-api:4.21.0")
|
||||
compileOnly("xyz.xenondevs.invui:invui-core:$invuiVersion")
|
||||
compileOnly("net.wesjd:anvilgui:1.10.4-SNAPSHOT")
|
||||
compileOnly("com.comphenix.protocol:ProtocolLib:5.4.0-SNAPSHOT")
|
||||
|
||||
implementation("de.rapha149.signgui:signgui:2.5.0")
|
||||
implementation("com.github.jsixface:yamlconfig:1.2")
|
||||
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.18.1")
|
||||
implementation("com.fasterxml.jackson.core:jackson-core:2.18.1")
|
||||
implementation("com.mysql:mysql-connector-j:9.2.0")
|
||||
implementation("org.mariadb.jdbc:mariadb-java-client:3.5.2")
|
||||
implementation("redis.clients:jedis:5.2.0")
|
||||
implementation("com.google.code.gson:gson:2.13.1")
|
||||
}
|
||||
|
||||
tasks {
|
||||
|
||||
processResources {
|
||||
from("src/main/resources")
|
||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||
filesMatching("*.yml") {
|
||||
expand("version" to version)
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
// RELOCATIONS
|
||||
relocate("net.wesjd", "xyz.ineanto.nicko.libs.anvilgui")
|
||||
relocate("com.github.jsixface", "xyz.ineanto.nicko.libs.yaml")
|
||||
relocate("me.clip", "xyz.ineanto.nicko.libs.placeholderapi")
|
||||
relocate("com.fasterxml.jackson", "xyz.ineanto.nicko.libs.jackson")
|
||||
relocate("com.mysql", "xyz.ineanto.nicko.libs.mysql")
|
||||
relocate("org.mariadb.jdbc", "xyz.ineanto.nicko.libs.mariadb")
|
||||
relocate("redis.clients", "xyz.ineanto.nicko.libs.redis")
|
||||
relocate("com.google.gson", "xyz.ineanto.nicko.libs.gson")
|
||||
relocate("org.apache.commons.pool2", "xyz.ineanto.nicko.libs.pool2")
|
||||
|
||||
// EXCLUSIONS
|
||||
exclude("colors.bin")
|
||||
exclude("waffle/**")
|
||||
exclude("com/sun/**")
|
||||
exclude("com/google/protobuf/**")
|
||||
exclude("com/google/errorprone/**")
|
||||
exclude("org/apache/commons/logging/**")
|
||||
exclude("org/jetbrains/**")
|
||||
exclude("org/intellij/**")
|
||||
exclude("org/checkerframework/**")
|
||||
exclude("org/json/**")
|
||||
exclude("org/slf4j/**")
|
||||
exclude("org/yaml/**")
|
||||
exclude("google/protobuf/**")
|
||||
exclude("net/kyori/**")
|
||||
|
||||
// MINIFY
|
||||
minimize {
|
||||
exclude(dependency("xyz.xenondevs.invui:.*"))
|
||||
exclude(dependency("de.rapha149.signgui:.*"))
|
||||
}
|
||||
}
|
||||
|
||||
runServer {
|
||||
downloadPlugins {
|
||||
url("https://download.luckperms.net/1593/bukkit/loader/LuckPerms-Bukkit-5.5.8.jar")
|
||||
|
||||
// 1.20.5 - latest testing
|
||||
url("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar")
|
||||
}
|
||||
|
||||
minecraftVersion("1.21.5")
|
||||
}
|
||||
}
|
178
core/pom.xml
Normal file
178
core/pom.xml
Normal file
|
@ -0,0 +1,178 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>core</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<parent>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>nicko-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>papermc</id>
|
||||
<url>https://repo.papermc.io/repository/maven-public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>spigot-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/groups/public/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>codemc-snapshots</id>
|
||||
<url>https://repo.codemc.io/repository/maven-snapshots/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<id>placeholderapi</id>
|
||||
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<!-- PlaceHolder API -->
|
||||
<dependency>
|
||||
<groupId>me.clip</groupId>
|
||||
<artifactId>placeholderapi</artifactId>
|
||||
<version>2.11.2</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Spigot API -->
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.19.4-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- Inventory Lib -->
|
||||
<dependency>
|
||||
<groupId>xyz.xenondevs.invui</groupId>
|
||||
<artifactId>invui</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- AnvilGUI -->
|
||||
<dependency>
|
||||
<groupId>net.wesjd</groupId>
|
||||
<artifactId>anvilgui</artifactId>
|
||||
<version>1.6.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<!-- Google Guava (GSON) -->
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>31.1-jre</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- MockBukkit 1.19 (Bukkit Unit Tests) -->
|
||||
<dependency>
|
||||
<groupId>com.github.seeseemelk</groupId>
|
||||
<artifactId>MockBukkit-v1.19</artifactId>
|
||||
<version>2.29.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- MariaDB JDBC Driver -->
|
||||
<dependency>
|
||||
<groupId>org.mariadb.jdbc</groupId>
|
||||
<artifactId>mariadb-java-client</artifactId>
|
||||
<version>3.1.2</version>
|
||||
</dependency>
|
||||
<!-- YAML Reader -->
|
||||
<dependency>
|
||||
<groupId>com.github.jsixface</groupId>
|
||||
<artifactId>yamlconfig</artifactId>
|
||||
<version>1.1.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-core</artifactId>
|
||||
<version>2.14.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.dataformat</groupId>
|
||||
<artifactId>jackson-dataformat-yaml</artifactId>
|
||||
<version>2.14.2</version>
|
||||
</dependency>
|
||||
<!-- Redis -->
|
||||
<dependency>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
<version>4.3.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>3.0.0-M7</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.3.1-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>net.wesjd:anvilgui</include>
|
||||
<include>xyz.xenondevs.invui:*</include>
|
||||
<include>com.github.jsixface:*</include>
|
||||
<include>com.fasterxml.jackson.dataformat</include>
|
||||
<include>com.fasterxml.jackson.core</include>
|
||||
<include>org.mariadb.jdbc</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
<relocations>
|
||||
<relocation>
|
||||
<pattern>net.wesjd.anvilgui</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.anvilgui</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>xyz.xenondevs.invui</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.invui</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.github.jsixface</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.yaml</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.fasterxml.jackson.dataformat</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.jackson.yaml</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>com.fasterxml.jackson.core</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.jackson.core</shadedPattern>
|
||||
</relocation>
|
||||
<relocation>
|
||||
<pattern>org.mariadb.jdbc</pattern>
|
||||
<shadedPattern>net.artelnatif.libs.mariadb</shadedPattern>
|
||||
</relocation>
|
||||
</relocations>
|
||||
<!-- Prevents breaking AnvilGUI's VersionWrapper. -->
|
||||
<minimizeJar>false</minimizeJar>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<filtering>true</filtering>
|
||||
<directory>${basedir}/src/main/resources/</directory>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
</project>
|
167
core/src/main/java/net/artelnatif/nicko/NickoBukkit.java
Normal file
167
core/src/main/java/net/artelnatif/nicko/NickoBukkit.java
Normal file
|
@ -0,0 +1,167 @@
|
|||
package net.artelnatif.nicko;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.common.OptionUnavailable;
|
||||
import xyz.xenondevs.invui.gui.structure.Structure;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
import net.artelnatif.nicko.command.NickoCommand;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.ConfigurationManager;
|
||||
import net.artelnatif.nicko.event.PlayerJoinListener;
|
||||
import net.artelnatif.nicko.event.PlayerQuitListener;
|
||||
import net.artelnatif.nicko.gui.items.main.ExitGUI;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import net.artelnatif.nicko.i18n.LocaleFileManager;
|
||||
import net.artelnatif.nicko.impl.Internals;
|
||||
import net.artelnatif.nicko.impl.InternalsProvider;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.placeholder.PlaceHolderHook;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.plugin.java.JavaPluginLoader;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class NickoBukkit extends JavaPlugin {
|
||||
private static NickoBukkit plugin;
|
||||
|
||||
private final boolean unitTesting;
|
||||
|
||||
private MojangAPI mojangAPI;
|
||||
private PlayerDataStore dataStore;
|
||||
private ConfigurationManager configurationManager;
|
||||
private Configuration configuration;
|
||||
private LocaleFileManager localeFileManager;
|
||||
private PlayerNameStore nameStore;
|
||||
|
||||
public NickoBukkit() { this.unitTesting = false; }
|
||||
|
||||
/**
|
||||
* Used by MockBukkit
|
||||
*/
|
||||
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file) {
|
||||
this(loader, description, dataFolder, file, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used by MockBukkit
|
||||
*/
|
||||
protected NickoBukkit(JavaPluginLoader loader, PluginDescriptionFile description, File dataFolder, File file, Configuration configuration) {
|
||||
super(loader, description, dataFolder, file);
|
||||
unitTesting = true;
|
||||
this.configuration = configuration;
|
||||
getLogger().info("Unit Testing Mode enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin = this;
|
||||
configurationManager = new ConfigurationManager(getDataFolder());
|
||||
configurationManager.saveDefaultConfig();
|
||||
|
||||
mojangAPI = new MojangAPI();
|
||||
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
|
||||
nameStore = new PlayerNameStore();
|
||||
|
||||
if (!dataStore.getStorage().isError()) {
|
||||
getLogger().info("Loading persistence...");
|
||||
if (!dataStore.getStorage().getProvider().init()) {
|
||||
dataStore.getStorage().setError(true);
|
||||
getLogger().severe("Failed to open persistence, data will NOT be saved!");
|
||||
}
|
||||
}
|
||||
|
||||
if (!unitTesting) {
|
||||
getLogger().info("Loading internals...");
|
||||
if (getInternals() == null) {
|
||||
getLogger().severe("Nicko could not find a valid implementation for this server version. Is your server supported?");
|
||||
dataStore.getStorage().setError(true);
|
||||
getServer().getPluginManager().disablePlugin(this);
|
||||
}
|
||||
|
||||
|
||||
localeFileManager = new LocaleFileManager();
|
||||
if (configuration.isCustomLocale()) {
|
||||
if (localeFileManager.dumpFromLocale(Locale.ENGLISH)) {
|
||||
getLogger().info("Successfully loaded custom language file.");
|
||||
} else {
|
||||
getLogger().severe("Failed to load custom language file!");
|
||||
}
|
||||
}
|
||||
|
||||
final PluginCommand command = getCommand("nicko");
|
||||
if (command != null) {
|
||||
command.setExecutor(new NickoCommand());
|
||||
}
|
||||
|
||||
Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
|
||||
Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.ORANGE_STAINED_GLASS_PANE).setDisplayName(" ")));
|
||||
Structure.addGlobalIngredient('U', new OptionUnavailable());
|
||||
Structure.addGlobalIngredient('E', new ExitGUI());
|
||||
|
||||
new PlaceHolderHook(this).hook();
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this);
|
||||
|
||||
getLogger().info("Nicko (Bukkit) has been enabled.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (!getDataStore().getStorage().isError()) {
|
||||
getLogger().info("Closing persistence...");
|
||||
nameStore.clearStoredNames();
|
||||
Bukkit.getOnlinePlayers().forEach(player -> dataStore.saveData(player));
|
||||
if (!dataStore.getStorage().getProvider().close()) {
|
||||
getLogger().severe("Failed to close persistence!");
|
||||
}
|
||||
}
|
||||
|
||||
getLogger().info("Nicko (Bukkit) has been disabled.");
|
||||
}
|
||||
|
||||
public static NickoBukkit getInstance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public Configuration getNickoConfig() {
|
||||
try {
|
||||
if (configuration == null) { return configuration = configurationManager.load(); }
|
||||
return configuration;
|
||||
} catch (IOException e) {
|
||||
getLogger().severe("Failed to load the configuration file!");
|
||||
getLogger().severe("It may be have been generated with an older version of Nicko.");
|
||||
getLogger().severe("Delete the configuration and restart the server please :)");
|
||||
getLogger().severe("(" + e.getMessage() + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerDataStore getDataStore() {
|
||||
return dataStore;
|
||||
}
|
||||
|
||||
public PlayerNameStore getNameStore() {
|
||||
return nameStore;
|
||||
}
|
||||
|
||||
public MojangAPI getMojangAPI() {
|
||||
return mojangAPI;
|
||||
}
|
||||
|
||||
public LocaleFileManager getLocaleFileManager() {
|
||||
return localeFileManager;
|
||||
}
|
||||
|
||||
public Internals getInternals() {
|
||||
return InternalsProvider.getInternals();
|
||||
}
|
||||
}
|
106
core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java
Normal file
106
core/src/main/java/net/artelnatif/nicko/anvil/AnvilManager.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
package net.artelnatif.nicko.anvil;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import net.wesjd.anvilgui.AnvilGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class AnvilManager {
|
||||
private final Player player;
|
||||
private final AppearanceManager appearanceManager;
|
||||
|
||||
public AnvilManager(Player player) {
|
||||
this.player = player;
|
||||
this.appearanceManager = AppearanceManager.get(player);
|
||||
}
|
||||
|
||||
public void openNameThenSkinAnvil() {
|
||||
getNameThenSkinAnvil().open(player);
|
||||
}
|
||||
|
||||
public void openSkinAnvil() {
|
||||
getSkinAnvil().open(player);
|
||||
}
|
||||
|
||||
public void openNameAnvil() {
|
||||
getNameAnvil().open(player);
|
||||
}
|
||||
|
||||
public AnvilGUI.Builder getNameThenSkinAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(false))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setName(completion.getText());
|
||||
openSkinAnvil();
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.close());
|
||||
}
|
||||
})
|
||||
.text("New name...");
|
||||
}
|
||||
|
||||
public AnvilGUI.Builder getNameAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(false))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setName(completion.getText());
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(false);
|
||||
return sendResultAndClose(actionResult);
|
||||
}
|
||||
})
|
||||
.text("New name...");
|
||||
}
|
||||
|
||||
private AnvilGUI.Builder getSkinAnvil() {
|
||||
return new AnvilGUI.Builder()
|
||||
.plugin(NickoBukkit.getInstance())
|
||||
.itemLeft(getLeftItem(true))
|
||||
.interactableSlots(AnvilGUI.Slot.OUTPUT)
|
||||
.onComplete((completion) -> {
|
||||
if (MojangUtils.isUsernameInvalid(completion.getText())) {
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.replaceInputText("Invalid username!"));
|
||||
} else {
|
||||
appearanceManager.setSkin(completion.getText());
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(true);
|
||||
return sendResultAndClose(actionResult);
|
||||
}
|
||||
})
|
||||
.text("New skin...");
|
||||
}
|
||||
|
||||
private List<AnvilGUI.ResponseAction> sendResultAndClose(ActionResult<Void> actionResult) {
|
||||
if (!actionResult.isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.SUCCESS));
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Disguise.FAIL, I18N.translateWithoutPrefix(player, actionResult.getErrorMessage())));
|
||||
}
|
||||
return Collections.singletonList(AnvilGUI.ResponseAction.close());
|
||||
}
|
||||
|
||||
private ItemStack getLeftItem(boolean skin) {
|
||||
final ItemStack item = new ItemStack(Material.PAPER);
|
||||
final ItemMeta meta = item.getItemMeta();
|
||||
meta.setDisplayName("§0New " + (skin ? "skin" : "name") + "...");
|
||||
item.setItemMeta(meta);
|
||||
return item;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package net.artelnatif.nicko.appearance;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class AppearanceManager {
|
||||
private final NickoProfile profile;
|
||||
private final Player player;
|
||||
private final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
private final PlayerDataStore dataStore = instance.getDataStore();
|
||||
private final PlayerNameStore nameStore = instance.getNameStore();
|
||||
|
||||
private AppearanceManager(UUID uuid) {
|
||||
this.player = Bukkit.getPlayer(uuid);
|
||||
this.profile = dataStore.getData(uuid).orElse(NickoProfile.EMPTY_PROFILE.clone());
|
||||
}
|
||||
|
||||
private AppearanceManager(String name) {
|
||||
this.player = null;
|
||||
this.profile = dataStore.getOfflineData(name).orElse(NickoProfile.EMPTY_PROFILE.clone());
|
||||
}
|
||||
|
||||
public static AppearanceManager get(Player player) {
|
||||
return new AppearanceManager(player.getUniqueId());
|
||||
}
|
||||
|
||||
public static AppearanceManager get(String name) {
|
||||
return new AppearanceManager(name);
|
||||
}
|
||||
|
||||
public boolean hasData() {
|
||||
return !profile.isEmpty();
|
||||
}
|
||||
|
||||
public void setSkin(String skin) {
|
||||
profile.setSkin(skin);
|
||||
}
|
||||
|
||||
public String getSkin() {
|
||||
return profile.getSkin();
|
||||
}
|
||||
|
||||
public boolean needsASkinChange() {
|
||||
return profile.getSkin() != null && !profile.getSkin().equals(player.getName());
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
profile.setName(name);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return profile.getName();
|
||||
}
|
||||
|
||||
public NickoProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setNameAndSkin(String name, String skin) {
|
||||
this.profile.setName(name);
|
||||
this.profile.setSkin(skin);
|
||||
updatePlayer(true);
|
||||
}
|
||||
|
||||
public ActionResult<Void> reset() {
|
||||
final String defaultName = nameStore.getStoredName(player);
|
||||
this.profile.setName(defaultName);
|
||||
this.profile.setSkin(defaultName);
|
||||
final ActionResult<Void> actionResult = resetPlayer();
|
||||
this.profile.setSkin(null);
|
||||
this.profile.setName(null);
|
||||
return actionResult;
|
||||
}
|
||||
|
||||
public ActionResult<Void> resetPlayer() {
|
||||
return NickoBukkit.getInstance().getInternals().updateProfile(player, profile, true, true);
|
||||
}
|
||||
|
||||
public ActionResult<Void> updatePlayer(boolean skinChange) {
|
||||
return NickoBukkit.getInstance().getInternals().updateProfile(player, profile, skinChange, false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package net.artelnatif.nicko.command;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.command.sub.NickoCheckSubCmd;
|
||||
import net.artelnatif.nicko.command.sub.NickoDebugSubCmd;
|
||||
import net.artelnatif.nicko.gui.MainGUI;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NickoCommand implements CommandExecutor {
|
||||
private String helpMessage = "§cNicko §8§o[{version}] §f- §2Help:\n" +
|
||||
"§6/nicko §f- §7Open the GUI.\n" +
|
||||
"§6/nicko help §f- §7Print this help message.\n";
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
if (args.length >= 1) {
|
||||
switch (args[0]) {
|
||||
case "debug":
|
||||
new NickoDebugSubCmd().execute(player, args);
|
||||
break;
|
||||
case "check":
|
||||
new NickoCheckSubCmd().execute(player, args);
|
||||
break;
|
||||
default:
|
||||
sendHelpMessage(sender);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
new MainGUI(player).open();
|
||||
return false;
|
||||
}
|
||||
|
||||
sender.sendMessage("This plugin can only be used in-game. Sorry!");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void sendHelpMessage(CommandSender sender) {
|
||||
helpMessage = helpMessage.replace("{version}", NickoBukkit.getInstance().getDescription().getVersion());
|
||||
sender.sendMessage(helpMessage);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.command.sub;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.StringJoiner;
|
||||
|
||||
public class NickoCheckSubCmd {
|
||||
public void execute(Player player, String[] args) {
|
||||
final String targetName = args[1];
|
||||
final Player target = Bukkit.getPlayerExact(targetName);
|
||||
|
||||
AppearanceManager appearanceManager;
|
||||
if (MojangUtils.isUsernameInvalid(targetName)) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Error.INVALID_USERNAME));
|
||||
return;
|
||||
}
|
||||
|
||||
if (target == null) {
|
||||
appearanceManager = AppearanceManager.get(targetName);
|
||||
} else {
|
||||
appearanceManager = AppearanceManager.get(target);
|
||||
}
|
||||
|
||||
final StringJoiner builder = new StringJoiner("\n");
|
||||
builder.add("§c" + NickoBukkit.getInstance().getNickoConfig().getPrefix() + "§6Check for: §f§o" + targetName);
|
||||
if (!appearanceManager.hasData()) {
|
||||
builder.add("§cThis player has not data.");
|
||||
} else {
|
||||
builder.add("§7- §fNicked: §a✔");
|
||||
builder.add("§7- §fName: §6" + appearanceManager.getName());
|
||||
builder.add("§7- §fSkin: §6" + appearanceManager.getSkin());
|
||||
}
|
||||
|
||||
player.sendMessage(builder.toString());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package net.artelnatif.nicko.command.sub;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class NickoDebugSubCmd {
|
||||
public void execute(CommandSender sender, String[] args) {
|
||||
final String prefix = NickoBukkit.getInstance().getNickoConfig().getPrefix();
|
||||
|
||||
Player target;
|
||||
String name, skin;
|
||||
if (args.length == 3) {
|
||||
target = (Player) sender;
|
||||
name = args[1];
|
||||
skin = args[2];
|
||||
} else {
|
||||
if (args.length < 3) {
|
||||
sender.sendMessage(prefix + "§cMissing argument.");
|
||||
return;
|
||||
}
|
||||
|
||||
final String playerName = args[1];
|
||||
name = args[2];
|
||||
skin = args[3];
|
||||
|
||||
target = Bukkit.getPlayer(playerName);
|
||||
if (target == null) {
|
||||
sender.sendMessage(prefix + "§cSpecified player is offline.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(target.getPlayer());
|
||||
|
||||
if (MojangUtils.isUsernameInvalid(name) || MojangUtils.isUsernameInvalid(skin)) {
|
||||
sender.sendMessage(prefix + "§cSpecified username is invalid.");
|
||||
}
|
||||
|
||||
appearanceManager.setNameAndSkin(name, skin);
|
||||
target.sendMessage(prefix + "§aWhoosh!");
|
||||
target.playSound(target.getLocation(), Sound.ENTITY_ITEM_FRAME_PLACE, 1, 1);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package net.artelnatif.nicko.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
public class Configuration {
|
||||
@JsonProperty("sql")
|
||||
private final DataSourceConfiguration sqlConfiguration;
|
||||
@JsonProperty("redis")
|
||||
private final DataSourceConfiguration redisConfiguration;
|
||||
private final String prefix;
|
||||
private final Boolean local;
|
||||
private final Boolean customLocale;
|
||||
|
||||
public Configuration(DataSourceConfiguration sqlConfiguration, DataSourceConfiguration redisConfiguration, String prefix, Boolean local, Boolean customLocale) {
|
||||
this.sqlConfiguration = sqlConfiguration;
|
||||
this.redisConfiguration = redisConfiguration;
|
||||
this.prefix = prefix;
|
||||
this.local = local;
|
||||
this.customLocale = customLocale;
|
||||
}
|
||||
|
||||
public Configuration() {
|
||||
this(
|
||||
new DataSourceConfiguration("", 3306, "", ""),
|
||||
new DataSourceConfiguration("", 6379, "", ""),
|
||||
"",
|
||||
false,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
public DataSourceConfiguration getSqlConfiguration() {
|
||||
return sqlConfiguration;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration getRedisConfiguration() {
|
||||
return redisConfiguration;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public Boolean isLocal() {
|
||||
return local;
|
||||
}
|
||||
|
||||
public Boolean isCustomLocale() {
|
||||
return customLocale;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package xyz.ineanto.nicko.config;
|
||||
package net.artelnatif.nicko.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
@ -7,23 +7,16 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
|||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ConfigurationManager {
|
||||
private final Logger logger = Logger.getLogger("ConfigurationManager");
|
||||
private final ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
|
||||
private final File file;
|
||||
private final File backupFile;
|
||||
|
||||
public ConfigurationManager(File directory) {
|
||||
final String date = Instant.now()
|
||||
.atZone(ZoneId.systemDefault())
|
||||
.format(DateTimeFormatter.ofPattern("dd-MM-yyyy"));
|
||||
this.file = new File(directory, "config.yml");
|
||||
this.backupFile = new File(directory, "config.old-" + date + ".yml");
|
||||
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
|
||||
}
|
||||
|
||||
public void save(Configuration configuration) throws IOException {
|
||||
|
@ -38,6 +31,7 @@ public class ConfigurationManager {
|
|||
try {
|
||||
final InputStream input = getClass().getResourceAsStream("/config.yml");
|
||||
if (input != null) {
|
||||
logger.info("Saved default configuration as config.yml");
|
||||
Files.createDirectories(file.getParentFile().toPath());
|
||||
Files.createFile(file.toPath());
|
||||
Files.copy(input, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
|
@ -53,12 +47,4 @@ public class ConfigurationManager {
|
|||
return mapper.readValue(reader, Configuration.class);
|
||||
}
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public File getBackupFile() {
|
||||
return backupFile;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.config;
|
||||
|
||||
public class DataSourceConfiguration {
|
||||
public static final DataSourceConfiguration SQL_EMPTY = new DataSourceConfiguration("127.0.0.1", 3306, "root", "");
|
||||
public static final DataSourceConfiguration REDIS_EMPTY = new DataSourceConfiguration("127.0.0.1", 6379, "", "");
|
||||
|
||||
private final String address;
|
||||
private final Integer port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public DataSourceConfiguration(String address, Integer port, String username, String password) {
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration() { this("", 0, "", ""); }
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.disguise;
|
||||
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
|
||||
public class ActionResult<R> {
|
||||
private final I18NDict errorMessage;
|
||||
private boolean error = false;
|
||||
private R result;
|
||||
|
||||
public ActionResult() {
|
||||
this.errorMessage = null;
|
||||
}
|
||||
|
||||
public ActionResult(I18NDict errorMessage) {
|
||||
this.errorMessage = errorMessage;
|
||||
this.error = true;
|
||||
this.result = null;
|
||||
}
|
||||
|
||||
public ActionResult(R result) {
|
||||
this.errorMessage = null;
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public R getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public I18NDict getErrorMessage() {
|
||||
return errorMessage;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
package net.artelnatif.nicko.disguise;
|
||||
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
|
||||
public class NickoProfile implements Cloneable {
|
||||
public static final NickoProfile EMPTY_PROFILE = new NickoProfile(null, null, Locale.ENGLISH, true);
|
||||
|
||||
private String name;
|
||||
private String skin;
|
||||
private Locale locale;
|
||||
private boolean bungeecordTransfer;
|
||||
|
||||
public NickoProfile(String name, String skin, Locale locale, boolean bungeecordTransfer) {
|
||||
this.name = name;
|
||||
this.skin = skin;
|
||||
this.locale = locale;
|
||||
this.bungeecordTransfer = bungeecordTransfer;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return name == null && skin == null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
public void setSkin(String skin) {
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
public Locale getLocale() { return locale; }
|
||||
|
||||
public void setLocale(Locale locale) { this.locale = locale; }
|
||||
|
||||
public boolean isBungeecordTransfer() {
|
||||
return bungeecordTransfer;
|
||||
}
|
||||
|
||||
public void setBungeecordTransfer(boolean bungeecordTransfer) {
|
||||
this.bungeecordTransfer = bungeecordTransfer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NickoProfile{" +
|
||||
"name='" + name + '\'' +
|
||||
", skin='" + skin + '\'' +
|
||||
", locale=" + locale +
|
||||
", bungeecordTransfer=" + bungeecordTransfer +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public NickoProfile clone() {
|
||||
Object o;
|
||||
try {
|
||||
o = super.clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
return (NickoProfile) o;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.event;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.storage.PlayerDataStore;
|
||||
import net.artelnatif.nicko.storage.name.PlayerNameStore;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
|
||||
public class PlayerJoinListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
|
||||
final PlayerDataStore dataStore = instance.getDataStore();
|
||||
final PlayerNameStore nameStore = instance.getNameStore();
|
||||
nameStore.storeName(player);
|
||||
|
||||
// TODO: 2/20/23 BungeeCord transfer
|
||||
|
||||
dataStore.performProfileUpdate(player.getUniqueId(), NickoProfile.EMPTY_PROFILE);
|
||||
Bukkit.getScheduler().runTaskLater(instance, () -> {
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(player);
|
||||
if (appearanceManager.hasData()) {
|
||||
final ActionResult<Void> actionResult = appearanceManager.updatePlayer(appearanceManager.needsASkinChange());
|
||||
if (!actionResult.isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.SUCCESS));
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.PreviousSkin.FAIL, I18N.translate(player, actionResult.getErrorMessage())));
|
||||
}
|
||||
}
|
||||
}, 20L);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.artelnatif.nicko.event;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
|
||||
public class PlayerQuitListener implements Listener {
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ActionResult<Void> result = NickoBukkit.getInstance().getDataStore().saveData(player);
|
||||
if (result.isError()) {
|
||||
NickoBukkit.getInstance().getLogger().warning("Failed to save data for " + player.getName());
|
||||
}
|
||||
}
|
||||
}
|
35
core/src/main/java/net/artelnatif/nicko/gui/AdminGUI.java
Normal file
35
core/src/main/java/net/artelnatif/nicko/gui/AdminGUI.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.admin.ManageCache;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class AdminGUI {
|
||||
public static final String TITLE = "Nicko > Administration";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public AdminGUI(Player player) {
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(
|
||||
"# # # # # # # # #",
|
||||
"# # # S U U # # #",
|
||||
"B # # # # # # # #"
|
||||
)
|
||||
.addIngredient('S', new ManageCache())
|
||||
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
46
core/src/main/java/net/artelnatif/nicko/gui/MainGUI.java
Normal file
46
core/src/main/java/net/artelnatif/nicko/gui/MainGUI.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.main.AdminSubGUI;
|
||||
import net.artelnatif.nicko.gui.items.main.ResetAppearance;
|
||||
import net.artelnatif.nicko.gui.items.main.SettingsSubGUI;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeName;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeNameAndSkin;
|
||||
import net.artelnatif.nicko.gui.items.skin.ChangeSkin;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class MainGUI {
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public MainGUI(Player player) {
|
||||
final String[] dynamicStructure = new String[]{
|
||||
"# # # # # # # # #",
|
||||
"# # # N B S # # #",
|
||||
"E P A # # # # # R"};
|
||||
|
||||
if (!player.hasPermission("nicko.admin") || !player.isOp()) {
|
||||
dynamicStructure[2] = dynamicStructure[2].replace("A", "#");
|
||||
}
|
||||
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(dynamicStructure)
|
||||
.addIngredient('R', new ResetAppearance())
|
||||
.addIngredient('N', new ChangeName())
|
||||
.addIngredient('B', new ChangeNameAndSkin())
|
||||
.addIngredient('S', new ChangeSkin(player))
|
||||
.addIngredient('P', new SettingsSubGUI())
|
||||
.addIngredient('A', new AdminSubGUI())
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle("Nicko - Home").open(player);
|
||||
}
|
||||
}
|
38
core/src/main/java/net/artelnatif/nicko/gui/SettingsGUI.java
Normal file
38
core/src/main/java/net/artelnatif/nicko/gui/SettingsGUI.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package net.artelnatif.nicko.gui;
|
||||
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import net.artelnatif.nicko.gui.items.settings.BungeeCordCycling;
|
||||
import net.artelnatif.nicko.gui.items.settings.LanguageCycling;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class SettingsGUI {
|
||||
public static final String TITLE = "Nicko > Settings";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public SettingsGUI(Player player) {
|
||||
final String[] dynamicStructure = new String[]{
|
||||
"# # # # # # # # #",
|
||||
"# # # L T U # # #",
|
||||
"B # # # # # # # #"
|
||||
};
|
||||
|
||||
// TODO: 3/6/23 Replace when Redis is not enabled
|
||||
dynamicStructure[1] = dynamicStructure[1].replace("T", "U");
|
||||
|
||||
this.gui = Gui.normal()
|
||||
.setStructure(dynamicStructure)
|
||||
.addIngredient('B', new GoBack(new MainGUI(player).getGUI()))
|
||||
.addIngredient('L', new LanguageCycling().get(player))
|
||||
.addIngredient('T', new BungeeCordCycling().get(player))
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.gui.admin;
|
||||
|
||||
import net.artelnatif.nicko.gui.AdminGUI;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheDetailed;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheInvalidate;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.CacheOverview;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class CacheManagementGUI {
|
||||
public static final String TITLE = "Nicko > Admin... > Cache";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public CacheManagementGUI(Player player) {
|
||||
this.gui = Gui.normal()
|
||||
.setStructure("B # S A D")
|
||||
.addIngredient('B', new GoBack(new AdminGUI(player).getGUI()))
|
||||
.addIngredient('S', new CacheOverview())
|
||||
.addIngredient('A', new CacheInvalidate())
|
||||
.addIngredient('D', new CacheDetailed())
|
||||
.build();
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public Gui getGUI() {
|
||||
return gui;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
61
core/src/main/java/net/artelnatif/nicko/gui/admin/cache/CacheDetailedGUI.java
vendored
Normal file
61
core/src/main/java/net/artelnatif/nicko/gui/admin/cache/CacheDetailedGUI.java
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
package net.artelnatif.nicko.gui.admin.cache;
|
||||
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.gui.structure.Markers;
|
||||
import xyz.xenondevs.invui.item.Item;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.gui.items.admin.cache.SkinPlaceholder;
|
||||
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
|
||||
import net.artelnatif.nicko.gui.items.common.GoBack;
|
||||
import net.artelnatif.nicko.gui.items.common.ScrollDown;
|
||||
import net.artelnatif.nicko.gui.items.common.ScrollUp;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CacheDetailedGUI {
|
||||
public static final String TITLE = "... > Cache > Invalidate";
|
||||
|
||||
private final Player player;
|
||||
private final Gui gui;
|
||||
|
||||
public CacheDetailedGUI(Player player) {
|
||||
final ConcurrentMap<String, Optional<MojangSkin>> skins = NickoBukkit.getInstance().getMojangAPI().getCache().asMap();
|
||||
final List<String> loadedSkins = skins.entrySet().stream()
|
||||
.filter(entry -> entry.getValue().isPresent())
|
||||
.map(Map.Entry::getKey)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
final List<Item> items = loadedSkins.stream()
|
||||
.map(SkinPlaceholder::new)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
gui = ScrollGui.items(guiItemBuilder -> {
|
||||
guiItemBuilder.setStructure(
|
||||
"# # # # # # # # #",
|
||||
"# x x x x x x U #",
|
||||
"# x x x x x x # #",
|
||||
"# x x x x x x # #",
|
||||
"# x x x x x x D #",
|
||||
"B # # # # # # # #");
|
||||
guiItemBuilder.addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL);
|
||||
guiItemBuilder.addIngredient('U', new ScrollUp());
|
||||
guiItemBuilder.addIngredient('D', new ScrollDown());
|
||||
guiItemBuilder.addIngredient('B', new GoBack(new CacheManagementGUI(player).getGUI()));
|
||||
guiItemBuilder.setContent(items);
|
||||
});
|
||||
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
public void open() {
|
||||
Window.single().setGui(gui).setTitle(TITLE).open(player);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.artelnatif.nicko.gui.items.admin;
|
||||
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AsyncItem;
|
||||
import net.artelnatif.nicko.gui.admin.CacheManagementGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ManageCache extends AsyncItem {
|
||||
public ManageCache() {
|
||||
super(new ItemBuilder(Material.PAINTING)
|
||||
.setDisplayName("§fManage §6skin §fcache...")
|
||||
.addLoreLines("§7Access the skin cache management panel."),
|
||||
() -> {
|
||||
final SkullBuilder builder = new SkullBuilder("Notch");
|
||||
builder.setDisplayName("§fManage §6skin §fcache...");
|
||||
builder.addLoreLines("§7Access the skin cache management panel.");
|
||||
return builder;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull InventoryClickEvent event) {
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
event.getView().close();
|
||||
new CacheManagementGUI(player).open();
|
||||
}
|
||||
}
|
||||
}
|
26
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheDetailed.java
vendored
Normal file
26
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheDetailed.java
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import net.artelnatif.nicko.gui.admin.cache.CacheDetailedGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class CacheDetailed extends SuppliedItem {
|
||||
public CacheDetailed() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.PAPER);
|
||||
builder.setDisplayName("§6Invalidate specific skin...");
|
||||
builder.addLoreLines("§7Select a specific skin to invalidate.");
|
||||
return builder;
|
||||
}, (click) -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
new CacheDetailedGUI(click.getPlayer()).open();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
36
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheInvalidate.java
vendored
Normal file
36
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheInvalidate.java
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class CacheInvalidate extends SuppliedItem {
|
||||
public CacheInvalidate() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.TNT);
|
||||
builder.setDisplayName("§fInvalidate §6skin cache");
|
||||
builder.addLoreLines(
|
||||
"§c§oNOT RECOMMENDED",
|
||||
"§7Invalidates every skin entry present in the cache.",
|
||||
"§7Does not reset player disguises.",
|
||||
"§7Could be useful if a skin has been updated",
|
||||
"§7recently and the cache is now outdated.");
|
||||
return builder;
|
||||
}, (click) -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
final Player player = click.getPlayer();
|
||||
click.getEvent().getView().close();
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Admin.CACHE_CLEAN));
|
||||
NickoBukkit.getInstance().getMojangAPI().getCache().invalidateAll();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
28
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheOverview.java
vendored
Normal file
28
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/CacheOverview.java
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import com.google.common.cache.CacheStats;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class CacheOverview extends SuppliedItem {
|
||||
public CacheOverview() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
|
||||
final LoadingCache<String, Optional<MojangSkin>> cache = NickoBukkit.getInstance().getMojangAPI().getCache();
|
||||
final CacheStats stats = cache.stats();
|
||||
builder.setDisplayName("§6Skin cache §foverview:");
|
||||
builder.addLoreLines(
|
||||
"Request Count: §2" + stats.requestCount(),
|
||||
"Skin Cached: §2" + Math.round(cache.size()),
|
||||
"§7§oCache is cleared every 24 hours.",
|
||||
"§7§o(Click to refresh)");
|
||||
return builder;
|
||||
}, (event) -> true);
|
||||
}
|
||||
}
|
21
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/SkinPlaceholder.java
vendored
Normal file
21
core/src/main/java/net/artelnatif/nicko/gui/items/admin/cache/SkinPlaceholder.java
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
package net.artelnatif.nicko.gui.items.admin.cache;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AsyncItem;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class SkinPlaceholder extends AsyncItem {
|
||||
public SkinPlaceholder(String name) {
|
||||
super(new ItemBuilder(Material.PAINTING).setDisplayName("§7§oLoading..."), () -> {
|
||||
final String stringUUID = name.replaceAll("(.{8})(.{4})(.{4})(.{4})(.+)", "$1-$2-$3-$4-$5");
|
||||
final UUID uuid = UUID.fromString(stringUUID);
|
||||
final SkullBuilder skull = new SkullBuilder(uuid);
|
||||
skull.setDisplayName("§6Skin Entry");
|
||||
skull.addLoreLines("§7Click to invalidate skin");
|
||||
return skull;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.Gui;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
|
||||
public class GoBack extends SuppliedItem {
|
||||
public GoBack(Gui gui) {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.ARROW);
|
||||
builder.setDisplayName("Go back");
|
||||
builder.addLoreLines("§7Return to the previous window.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
click.getEvent().getView().close();
|
||||
// TODO: 4/1/23 Get title of parent GUI
|
||||
Window.single().setGui(gui).setTitle("Nicko").open(click.getPlayer());
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class OptionUnavailable extends SuppliedItem {
|
||||
public OptionUnavailable() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.RED_TERRACOTTA);
|
||||
builder.setDisplayName("§cFeature unavailable :(");
|
||||
builder.addLoreLines("§7This button is disabled.");
|
||||
return builder;
|
||||
}, click -> true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
|
||||
|
||||
public class ScrollDown extends ScrollItem {
|
||||
|
||||
public ScrollDown() {
|
||||
super(1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemProvider getItemProvider(ScrollGui gui) {
|
||||
ItemBuilder builder = new ItemBuilder(Material.GREEN_STAINED_GLASS_PANE);
|
||||
builder.setDisplayName("§7Scroll down");
|
||||
if (!gui.canScroll(1))
|
||||
builder.addLoreLines("§cYou can't scroll further down");
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.common;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import xyz.xenondevs.invui.gui.ScrollGui;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.controlitem.ScrollItem;
|
||||
|
||||
public class ScrollUp extends ScrollItem {
|
||||
|
||||
public ScrollUp() {
|
||||
super(-1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemProvider getItemProvider(ScrollGui gui) {
|
||||
ItemBuilder builder = new ItemBuilder(Material.RED_STAINED_GLASS_PANE);
|
||||
builder.setDisplayName("§7Scroll up");
|
||||
if (!gui.canScroll(-1))
|
||||
builder.addLoreLines("§cYou've reached the top");
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,25 +1,22 @@
|
|||
package xyz.ineanto.nicko.gui.items.home;
|
||||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.gui.AdminGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.ineanto.nicko.gui.AdminGUI;
|
||||
import xyz.ineanto.nicko.language.PlayerLanguage;
|
||||
import xyz.ineanto.nicko.language.LanguageKey;
|
||||
import org.bukkit.inventory.ItemFlag;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class AdminAccessItem {
|
||||
private final PlayerLanguage playerLanguage;
|
||||
|
||||
public AdminAccessItem(Player player) {
|
||||
this.playerLanguage = new PlayerLanguage(player);
|
||||
}
|
||||
|
||||
public SuppliedItem get() {
|
||||
return new SuppliedItem(() -> {
|
||||
public class AdminSubGUI extends SuppliedItem {
|
||||
public AdminSubGUI() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMMAND_BLOCK);
|
||||
return playerLanguage.translateItem(builder, LanguageKey.GUI.Home.ADMIN);
|
||||
builder.addEnchantment(Enchantment.DAMAGE_ALL, 1, false);
|
||||
builder.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||
builder.setDisplayName("§cAdministration panel...");
|
||||
builder.addLoreLines("§7Access the administration panel.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
|
@ -0,0 +1,17 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
public class ExitGUI extends SimpleItem {
|
||||
public ExitGUI() {
|
||||
super(new ItemBuilder(Material.OAK_DOOR).setDisplayName("§fExit"), click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.appearance.AppearanceManager;
|
||||
import net.artelnatif.nicko.i18n.I18N;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ResetAppearance extends SuppliedItem {
|
||||
public ResetAppearance() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.TNT);
|
||||
builder.setDisplayName("§fReset");
|
||||
builder.addLoreLines("§7Get rid of your disguise.");
|
||||
return builder;
|
||||
}, (event) -> {
|
||||
final Player player = event.getPlayer();
|
||||
final ClickType clickType = event.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
final AppearanceManager appearanceManager = AppearanceManager.get(player);
|
||||
|
||||
if (!appearanceManager.hasData()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.NONE));
|
||||
event.getEvent().getView().close();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!appearanceManager.reset().isError()) {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.SUCCESS));
|
||||
return true;
|
||||
} else {
|
||||
player.sendMessage(I18N.translate(player, I18NDict.Event.Undisguise.FAIL));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,25 +1,18 @@
|
|||
package xyz.ineanto.nicko.gui.items.home;
|
||||
package net.artelnatif.nicko.gui.items.main;
|
||||
|
||||
import net.artelnatif.nicko.gui.SettingsGUI;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.ineanto.nicko.gui.SettingsGUI;
|
||||
import xyz.ineanto.nicko.language.PlayerLanguage;
|
||||
import xyz.ineanto.nicko.language.LanguageKey;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class SettingsAccessItem {
|
||||
private final PlayerLanguage playerLanguage;
|
||||
|
||||
public SettingsAccessItem(Player player) {
|
||||
this.playerLanguage = new PlayerLanguage(player);
|
||||
}
|
||||
|
||||
public SuppliedItem get() {
|
||||
return new SuppliedItem(() -> {
|
||||
public class SettingsSubGUI extends SuppliedItem {
|
||||
public SettingsSubGUI() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMPARATOR);
|
||||
return playerLanguage.translateItem(builder, LanguageKey.GUI.Home.SETTINGS);
|
||||
builder.setDisplayName("§fSettings...");
|
||||
builder.addLoreLines("§7Adjust your preferences.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
|
@ -0,0 +1,49 @@
|
|||
package net.artelnatif.nicko.gui.items.settings;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AbstractItem;
|
||||
import xyz.xenondevs.invui.item.impl.CycleItem;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class BungeeCordCycling {
|
||||
private final ItemProvider[] providers = new ItemProvider[]{
|
||||
getItemProviderForValue(true),
|
||||
getItemProviderForValue(false)
|
||||
};
|
||||
|
||||
public AbstractItem get(Player player) {
|
||||
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
|
||||
if (profile.isPresent()) {
|
||||
final NickoProfile nickoProfile = profile.get();
|
||||
int startingState = nickoProfile.isBungeecordTransfer() ? 0 : 1;
|
||||
return CycleItem.withStateChangeHandler((observer, integer) -> {
|
||||
nickoProfile.setBungeecordTransfer(integer != 1);
|
||||
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
|
||||
}, startingState, providers);
|
||||
}
|
||||
|
||||
return new SimpleItem(ItemProvider.EMPTY);
|
||||
}
|
||||
|
||||
private ItemProvider getItemProviderForValue(boolean enabled) {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.COMPASS);
|
||||
builder.setDisplayName("§6BungeeCord transfer:");
|
||||
if (enabled) {
|
||||
builder.addLoreLines("§7> §cDisabled");
|
||||
builder.addLoreLines("§6§l> §a§lEnabled");
|
||||
} else {
|
||||
builder.addLoreLines("§6§l> §c§lDisabled");
|
||||
builder.addLoreLines("§7> §aEnabled");
|
||||
}
|
||||
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
|
||||
return builder;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package net.artelnatif.nicko.gui.items.settings;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.xenondevs.invui.item.ItemProvider;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.AbstractItem;
|
||||
import xyz.xenondevs.invui.item.impl.CycleItem;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class LanguageCycling {
|
||||
private final ItemProvider[] providers = getItems();
|
||||
|
||||
public AbstractItem get(Player player) {
|
||||
final Optional<NickoProfile> profile = NickoBukkit.getInstance().getDataStore().getData(player.getUniqueId());
|
||||
if (profile.isPresent()) {
|
||||
final NickoProfile nickoProfile = profile.get();
|
||||
int localeOrdinal = nickoProfile.getLocale().ordinal();
|
||||
return CycleItem.withStateChangeHandler((observer, integer) -> {
|
||||
nickoProfile.setLocale(Locale.values()[integer]);
|
||||
observer.playSound(player, Sound.UI_BUTTON_CLICK, 1f, 0.707107f); // 0.707107 ~= C
|
||||
}, localeOrdinal, providers);
|
||||
}
|
||||
|
||||
return new SimpleItem(ItemProvider.EMPTY);
|
||||
}
|
||||
|
||||
private ItemProvider generateItem(Locale locale, List<Locale> locales) {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.OAK_SIGN);
|
||||
builder.setDisplayName("§6Select your language:");
|
||||
for (Locale value : locales) {
|
||||
if (locale != value) {
|
||||
builder.addLoreLines("§7> " + value.getName());
|
||||
} else {
|
||||
builder.addLoreLines("§6§l> §f" + value.getName());
|
||||
}
|
||||
}
|
||||
builder.addLoreLines("§7§oCycle through the values by", "§7§oleft and right clicking.");
|
||||
return builder;
|
||||
}
|
||||
|
||||
private ItemProvider[] getItems() {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final ArrayList<ItemProvider> items = new ArrayList<>();
|
||||
|
||||
final ArrayList<Locale> localesToGenerate = new ArrayList<>();
|
||||
Collections.addAll(localesToGenerate, Locale.values());
|
||||
if (!instance.getNickoConfig().isCustomLocale()) {
|
||||
localesToGenerate.remove(Locale.CUSTOM);
|
||||
}
|
||||
localesToGenerate.forEach(locale -> items.add(generateItem(locale, localesToGenerate)));
|
||||
return items.toArray(new ItemProvider[]{});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeName extends SuppliedItem {
|
||||
public ChangeName() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.NAME_TAG);
|
||||
builder.setDisplayName("§fChange §6name");
|
||||
builder.addLoreLines("§7Only change your name.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openNameAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeNameAndSkin extends SuppliedItem {
|
||||
public ChangeNameAndSkin() {
|
||||
super(() -> {
|
||||
final ItemBuilder builder = new ItemBuilder(Material.END_PORTAL_FRAME);
|
||||
builder.setDisplayName("§6Skin §fand §6name §fchange");
|
||||
builder.addLoreLines("§7Change both your skin and name.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openNameThenSkinAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.gui.items.skin;
|
||||
|
||||
import net.artelnatif.nicko.anvil.AnvilManager;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import xyz.xenondevs.invui.item.builder.SkullBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SuppliedItem;
|
||||
|
||||
public class ChangeSkin extends SuppliedItem {
|
||||
public ChangeSkin(Player player) {
|
||||
super(() -> {
|
||||
final SkullBuilder builder = new SkullBuilder(player.getName());
|
||||
builder.setDisplayName("§fChange §6skin");
|
||||
builder.addLoreLines("§7Only change your skin.");
|
||||
return builder;
|
||||
}, click -> {
|
||||
final ClickType clickType = click.getClickType();
|
||||
if (clickType.isLeftClick() || clickType.isRightClick()) {
|
||||
click.getEvent().getView().close();
|
||||
final AnvilManager manager = new AnvilManager(click.getPlayer());
|
||||
manager.openSkinAnvil();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
62
core/src/main/java/net/artelnatif/nicko/i18n/I18N.java
Normal file
62
core/src/main/java/net/artelnatif/nicko/i18n/I18N.java
Normal file
|
@ -0,0 +1,62 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import com.github.jsixface.YamlConfig;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Optional;
|
||||
|
||||
public class I18N {
|
||||
private final static MessageFormat formatter = new MessageFormat("");
|
||||
|
||||
private static Locale getLocale(Player player) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
try {
|
||||
final Optional<NickoProfile> profile = instance.getDataStore().getData(player.getUniqueId());
|
||||
return !profile.isPresent() ? Locale.FALLBACK_LOCALE : profile.get().getLocale();
|
||||
} catch (IllegalArgumentException exception) {
|
||||
instance.getLogger().severe("Invalid locale provided by " + player.getName() + ", defaulting to " + Locale.FALLBACK_LOCALE.getCode() + ".");
|
||||
return Locale.FALLBACK_LOCALE;
|
||||
}
|
||||
}
|
||||
|
||||
public static String translate(Player player, I18NDict key, Object... arguments) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final String translation = findTranslation(player, key);
|
||||
|
||||
try {
|
||||
formatter.applyPattern(translation);
|
||||
return instance.getNickoConfig().getPrefix() + formatter.format(arguments);
|
||||
} catch (Exception e) {
|
||||
return instance.getNickoConfig().getPrefix() + key.key();
|
||||
}
|
||||
}
|
||||
|
||||
public static String translateWithoutPrefix(Player player, I18NDict key, Object... arguments) {
|
||||
final String translation = findTranslation(player, key);
|
||||
try {
|
||||
formatter.applyPattern(translation);
|
||||
return formatter.format(arguments);
|
||||
} catch (Exception e) {
|
||||
return key.key();
|
||||
}
|
||||
}
|
||||
|
||||
private static String findTranslation(Player player, I18NDict key) {
|
||||
final NickoBukkit instance = NickoBukkit.getInstance();
|
||||
final Locale locale = getLocale(player);
|
||||
String translation;
|
||||
if (locale == Locale.CUSTOM) {
|
||||
translation = instance.getLocaleFileManager().get(key.key());
|
||||
} else {
|
||||
final InputStream resource = instance.getResource(locale.getCode() + ".yml");
|
||||
final YamlConfig yamlConfig = YamlConfig.load(resource);
|
||||
translation = yamlConfig.getString(key.key());
|
||||
}
|
||||
|
||||
return translation;
|
||||
}
|
||||
}
|
44
core/src/main/java/net/artelnatif/nicko/i18n/I18NDict.java
Normal file
44
core/src/main/java/net/artelnatif/nicko/i18n/I18NDict.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
public class I18NDict {
|
||||
private final String key;
|
||||
|
||||
public I18NDict(String key) { this.key = key; }
|
||||
|
||||
public static class Event {
|
||||
public static class Admin {
|
||||
public static final I18NDict CACHE_CLEAN = new I18NDict("event.admin.cache_clear");
|
||||
}
|
||||
|
||||
public static class Disguise {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.disguise.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.disguise.fail");
|
||||
}
|
||||
|
||||
public static class Undisguise {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.undisguise.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.undisguise.fail");
|
||||
public static final I18NDict NONE = new I18NDict("event.undisguise.none");
|
||||
}
|
||||
|
||||
public static class PreviousSkin {
|
||||
public static final I18NDict SUCCESS = new I18NDict("event.previous_skin_applied.success");
|
||||
public static final I18NDict FAIL = new I18NDict("event.previous_skin_applied.fail");
|
||||
}
|
||||
}
|
||||
|
||||
public static class Error {
|
||||
public static final I18NDict PLAYER_OFFLINE = new I18NDict("error.player_offline");
|
||||
public static final I18NDict SKIN_FAIL_MOJANG = new I18NDict("error.couldnt_get_skin_from_mojang");
|
||||
public static final I18NDict SKIN_FAIL_CACHE = new I18NDict("error.couldnt_get_skin_from_cache");
|
||||
public static final I18NDict NAME_FAIL_MOJANG = new I18NDict("error.couldnt_get_name_from_mojang");
|
||||
public static final I18NDict INVALID_USERNAME = new I18NDict("error.invalid_username");
|
||||
public static final I18NDict UNEXPECTED_ERROR = new I18NDict("error.generic");
|
||||
public static final I18NDict SQL_ERROR = new I18NDict("error.sql");
|
||||
public static final I18NDict JSON_ERROR = new I18NDict("error.json");
|
||||
}
|
||||
|
||||
public String key() {
|
||||
return key;
|
||||
}
|
||||
}
|
|
@ -1,26 +1,24 @@
|
|||
package xyz.ineanto.nicko.language;
|
||||
|
||||
import xyz.ineanto.nicko.version.Version;
|
||||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public enum Language implements Serializable {
|
||||
public enum Locale implements Serializable {
|
||||
ENGLISH("en", "English"),
|
||||
FRENCH("fr", "Français"),
|
||||
CUSTOM("cm", "Server Custom");
|
||||
|
||||
public static final Version VERSION = new Version(1, 4, 0);
|
||||
public static final Locale FALLBACK_LOCALE = ENGLISH;
|
||||
|
||||
private final String code;
|
||||
private transient final String name;
|
||||
|
||||
Language(String code, String name) {
|
||||
Locale(String code, String name) {
|
||||
this.code = code;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static Language fromCode(String code) {
|
||||
for (Language value : values()) {
|
||||
public static Locale fromCode(String code) {
|
||||
for (Locale value : values()) {
|
||||
if (code.equals(value.code)) return value;
|
||||
}
|
||||
return ENGLISH;
|
|
@ -0,0 +1,42 @@
|
|||
package net.artelnatif.nicko.i18n;
|
||||
|
||||
import com.github.jsixface.YamlConfig;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import xyz.xenondevs.invui.util.IOUtils;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
|
||||
public class LocaleFileManager {
|
||||
private final File folder = new File(NickoBukkit.getInstance().getDataFolder() + "/lang/");
|
||||
private final File file = new File(folder, "lang.yml");
|
||||
|
||||
public String get(String key) {
|
||||
if (!file.exists()) return key;
|
||||
try (BufferedInputStream inputStream = new BufferedInputStream(Files.newInputStream(file.toPath()))) {
|
||||
final YamlConfig yamlConfig = YamlConfig.load(inputStream);
|
||||
return yamlConfig.getString(key);
|
||||
} catch (IOException e) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean dumpFromLocale(Locale locale) {
|
||||
if (locale == Locale.CUSTOM) return true;
|
||||
if (file.exists()) return true;
|
||||
final InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(locale.getCode() + ".yml");
|
||||
try {
|
||||
if (folder.mkdirs()) {
|
||||
if (file.createNewFile()) {
|
||||
try (FileOutputStream outputStream = new FileOutputStream(file)) {
|
||||
IOUtils.copy(inputStream, outputStream, 8192);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
38
core/src/main/java/net/artelnatif/nicko/impl/Internals.java
Normal file
38
core/src/main/java/net/artelnatif/nicko/impl/Internals.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package net.artelnatif.nicko.impl;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangSkin;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
|
||||
public interface Internals {
|
||||
void updateSelf(Player player);
|
||||
|
||||
void updateOthers(Player player);
|
||||
|
||||
ActionResult<Void> updateProfile(Player player, NickoProfile profile, boolean skinChange, boolean reset);
|
||||
|
||||
default ActionResult<MojangSkin> fetchSkinTextures(NickoProfile profile, boolean reset) {
|
||||
Optional<MojangSkin> skin;
|
||||
try {
|
||||
final MojangAPI mojang = NickoBukkit.getInstance().getMojangAPI();
|
||||
final Optional<String> uuid = mojang.getUUID(profile.getSkin());
|
||||
if (uuid.isPresent()) {
|
||||
skin = (reset ? mojang.getSkinWithoutCaching(uuid.get()) : mojang.getSkin(uuid.get()));
|
||||
return skin.map(ActionResult::new).orElseGet(() -> new ActionResult<>(I18NDict.Error.SKIN_FAIL_MOJANG));
|
||||
}
|
||||
return new ActionResult<>(I18NDict.Error.NAME_FAIL_MOJANG);
|
||||
} catch (ExecutionException e) {
|
||||
return new ActionResult<>(I18NDict.Error.SKIN_FAIL_CACHE);
|
||||
} catch (IOException e) {
|
||||
return new ActionResult<>(I18NDict.Error.NAME_FAIL_MOJANG);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package net.artelnatif.nicko.impl;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class InternalsProvider {
|
||||
private static final Logger logger = Logger.getLogger("Internals");
|
||||
private static Internals internals;
|
||||
|
||||
static {
|
||||
try {
|
||||
final String packageName = Internals.class.getPackage().getName();
|
||||
final String bukkitVersion = Bukkit.getServer().getClass().getPackage().getName().split("\\.")[3];
|
||||
final String fullClassName = packageName + "." + bukkitVersion;
|
||||
final Class<?> clazz = Class.forName(fullClassName);
|
||||
internals = (Internals) clazz.getConstructors()[0].newInstance();
|
||||
logger.info("Loaded support for " + bukkitVersion);
|
||||
} catch (InvocationTargetException | ClassNotFoundException | InstantiationException | IllegalAccessException |
|
||||
ClassCastException exception) {
|
||||
internals = null;
|
||||
}
|
||||
}
|
||||
|
||||
public static Internals getInternals() {
|
||||
return internals;
|
||||
}
|
||||
}
|
116
core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java
Normal file
116
core/src/main/java/net/artelnatif/nicko/mojang/MojangAPI.java
Normal file
|
@ -0,0 +1,116 @@
|
|||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParseException;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.URL;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MojangAPI {
|
||||
public static final String URL_NAME = "https://api.mojang.com/users/profiles/minecraft/{name}";
|
||||
public static final String URL_SKIN = "https://sessionserver.mojang.com/session/minecraft/profile/{uuid}?unsigned=false";
|
||||
|
||||
private final Logger logger = Logger.getLogger("MojangAPI");
|
||||
|
||||
private final CacheLoader<String, Optional<MojangSkin>> loader = new CacheLoader<String, Optional<MojangSkin>>() {
|
||||
@Nonnull
|
||||
public Optional<MojangSkin> load(@Nonnull String uuid) throws Exception {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
};
|
||||
|
||||
private final LoadingCache<String, Optional<MojangSkin>> cache = CacheBuilder
|
||||
.newBuilder()
|
||||
.recordStats()
|
||||
.expireAfterWrite(24, TimeUnit.HOURS)
|
||||
.build(loader);
|
||||
|
||||
public Optional<MojangSkin> getSkin(String uuid) throws IOException, ExecutionException {
|
||||
return cache.get(uuid);
|
||||
}
|
||||
|
||||
public Optional<MojangSkin> getSkinWithoutCaching(String uuid) throws IOException {
|
||||
return getSkinFromMojang(uuid);
|
||||
}
|
||||
|
||||
public Optional<String> getUUID(String name) throws IOException {
|
||||
final String parametrizedUrl = URL_NAME.replace("{name}", name);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
return Optional.of(object.get("id").getAsString());
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<MojangSkin> getSkinFromMojang(String uuid) throws IOException {
|
||||
final String parametrizedUrl = URL_SKIN.replace("{uuid}", uuid);
|
||||
final JsonObject object = getRequestToUrl(parametrizedUrl);
|
||||
if (hasNoError(object)) {
|
||||
final MojangSkin skin = MojangSkin.buildFromJson(object);
|
||||
return Optional.of(skin);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private JsonObject getRequestToUrl(String parametrizedUrl) throws IOException {
|
||||
final URL url = new URL(parametrizedUrl);
|
||||
final HttpsURLConnection con = (HttpsURLConnection) url.openConnection();
|
||||
con.setDoInput(true);
|
||||
con.setRequestMethod("GET");
|
||||
|
||||
switch (con.getResponseCode()) {
|
||||
case 400:
|
||||
logger.warning("Failed to parse request: Invalid Name");
|
||||
return getErrorObject();
|
||||
case 429:
|
||||
logger.warning("Failed to parse request: The connection is throttled.");
|
||||
return getErrorObject();
|
||||
case 200:
|
||||
final BufferedReader input = new BufferedReader(new InputStreamReader(con.getInputStream()));
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
String line;
|
||||
while ((line = input.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
|
||||
try {
|
||||
final JsonElement jsonElt = JsonParser.parseString(builder.toString());
|
||||
return jsonElt.getAsJsonObject();
|
||||
} catch (JsonParseException | IllegalStateException exception) {
|
||||
logger.warning("Failed to parse request (" + parametrizedUrl + ")!");
|
||||
return getErrorObject();
|
||||
}
|
||||
default:
|
||||
logger.warning("Unhandled response code from Mojang: " + con.getResponseCode());
|
||||
return getErrorObject();
|
||||
}
|
||||
}
|
||||
|
||||
private JsonObject getErrorObject() {
|
||||
final JsonObject errorObject = new JsonObject();
|
||||
errorObject.addProperty("error", "An error occurred.");
|
||||
return errorObject;
|
||||
}
|
||||
|
||||
private boolean hasNoError(JsonObject object) {
|
||||
return object.get("error") == null;
|
||||
}
|
||||
|
||||
public LoadingCache<String, Optional<MojangSkin>> getCache() {
|
||||
return cache;
|
||||
}
|
||||
}
|
|
@ -1,12 +1,16 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import com.destroystokyo.paper.profile.ProfileProperty;
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
public class MojangSkin {
|
||||
private final String value;
|
||||
private final String signature;
|
||||
|
||||
public MojangSkin(String value, String signature) {
|
||||
this.value = value;
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
public record MojangSkin(String value, String signature) {
|
||||
public static MojangSkin buildFromJson(JsonObject object) {
|
||||
final JsonObject properties = object.get("properties").getAsJsonArray().get(0).getAsJsonObject();
|
||||
final String value = properties.get("value").getAsString();
|
||||
|
@ -14,7 +18,11 @@ public record MojangSkin(String value, String signature) {
|
|||
return new MojangSkin(value, signature);
|
||||
}
|
||||
|
||||
public Collection<ProfileProperty> asProfileProperties() {
|
||||
return Collections.singleton(new ProfileProperty("textures", value, signature));
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String getSignature() {
|
||||
return signature;
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package xyz.ineanto.nicko.mojang;
|
||||
package net.artelnatif.nicko.mojang;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.regex.Pattern;
|
|
@ -1,19 +1,19 @@
|
|||
package xyz.ineanto.nicko.placeholder;
|
||||
package net.artelnatif.nicko.placeholder;
|
||||
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class NickoExpansion extends PlaceholderExpansion {
|
||||
|
||||
private final Nicko instance;
|
||||
private final NickoBukkit instance;
|
||||
|
||||
public NickoExpansion(Nicko instance) {
|
||||
public NickoExpansion(NickoBukkit instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
|
@ -24,12 +24,12 @@ public class NickoExpansion extends PlaceholderExpansion {
|
|||
|
||||
@Override
|
||||
public @NotNull String getAuthor() {
|
||||
return "Ineanto";
|
||||
return "Aro";
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getVersion() {
|
||||
return "1.0.1";
|
||||
return "1.0.0";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -42,27 +42,29 @@ public class NickoExpansion extends PlaceholderExpansion {
|
|||
if (player == null) return null;
|
||||
|
||||
String name, skin, locale;
|
||||
boolean randomSkin;
|
||||
boolean bungeecord;
|
||||
|
||||
name = skin = player.getName();
|
||||
locale = "N/A";
|
||||
randomSkin = false;
|
||||
bungeecord = true;
|
||||
|
||||
final Optional<NickoProfile> optionalProfile = instance.getDataStore().getData(player.getUniqueId());
|
||||
if (optionalProfile.isPresent()) {
|
||||
final NickoProfile profile = optionalProfile.get();
|
||||
name = profile.getName() == null ? player.getName() : profile.getName();
|
||||
skin = profile.getSkin() == null ? player.getName() : profile.getSkin();
|
||||
if (!profile.isEmpty()) {
|
||||
name = profile.getName();
|
||||
skin = profile.getSkin();
|
||||
}
|
||||
locale = profile.getLocale().getName();
|
||||
randomSkin = profile.isRandomSkin();
|
||||
bungeecord = profile.isBungeecordTransfer();
|
||||
}
|
||||
|
||||
return switch (params) {
|
||||
case "name" -> name;
|
||||
case "skin" -> skin;
|
||||
case "locale" -> locale;
|
||||
case "random_skin" -> String.valueOf(randomSkin);
|
||||
default -> null;
|
||||
};
|
||||
switch (params) {
|
||||
case "name": return name;
|
||||
case "skin": return skin;
|
||||
case "locale": return locale;
|
||||
case "bungeecord": return String.valueOf(bungeecord);
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package net.artelnatif.nicko.placeholder;
|
||||
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class PlaceHolderHook {
|
||||
private final NickoBukkit instance;
|
||||
|
||||
public PlaceHolderHook(NickoBukkit instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public void hook() {
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
instance.getLogger().info("Enabling PlaceHolderAPI support...");
|
||||
new NickoExpansion(instance).register();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package net.artelnatif.nicko.storage;
|
||||
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.mojang.MojangAPI;
|
||||
import net.artelnatif.nicko.mojang.MojangUtils;
|
||||
import net.artelnatif.nicko.storage.cache.Cache;
|
||||
import net.artelnatif.nicko.storage.cache.redis.RedisCache;
|
||||
import net.artelnatif.nicko.storage.json.JSONStorage;
|
||||
import net.artelnatif.nicko.storage.sql.SQLStorage;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerDataStore {
|
||||
private final Storage storage;
|
||||
private final Cache cache;
|
||||
private final MojangAPI mojangAPI;
|
||||
private final HashMap<UUID, NickoProfile> profiles = new HashMap<>();
|
||||
|
||||
public PlayerDataStore(MojangAPI mojangAPI, Configuration configuration) {
|
||||
this.mojangAPI = mojangAPI;
|
||||
this.storage = configuration.isLocal() ? new JSONStorage() : new SQLStorage(configuration);
|
||||
this.cache = new RedisCache(); // The only option for now!
|
||||
}
|
||||
|
||||
public void performProfileUpdate(UUID uuid, NickoProfile profile) {
|
||||
if (!profiles.containsKey(uuid)) {
|
||||
profiles.put(uuid, profile);
|
||||
return;
|
||||
}
|
||||
|
||||
profiles.replace(uuid, profile);
|
||||
}
|
||||
|
||||
public Optional<NickoProfile> getData(UUID uuid) {
|
||||
if (storage.isError()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (profiles.containsKey(uuid)) {
|
||||
return Optional.of(profiles.get(uuid));
|
||||
} else if (storage.isStored(uuid)) {
|
||||
final Optional<NickoProfile> retrievedProfile = storage.retrieve(uuid);
|
||||
retrievedProfile.ifPresent(profile -> profiles.put(uuid, profile));
|
||||
return retrievedProfile;
|
||||
} else {
|
||||
final NickoProfile newProfile = NickoProfile.EMPTY_PROFILE.clone();
|
||||
profiles.put(uuid, newProfile);
|
||||
return Optional.of(newProfile);
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<NickoProfile> getOfflineData(String name) {
|
||||
if (storage.isError()) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
try {
|
||||
final Optional<String> uuidTrimmed = mojangAPI.getUUID(name);
|
||||
if (uuidTrimmed.isPresent()) {
|
||||
final UUID uuid = MojangUtils.fromTrimmed(uuidTrimmed.get());
|
||||
return getData(uuid);
|
||||
}
|
||||
return Optional.empty();
|
||||
} catch (IOException e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public ActionResult<Void> saveData(Player player) {
|
||||
if (storage.isError()) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
|
||||
if (!profiles.containsKey(player.getUniqueId())) { return new ActionResult<>(I18NDict.Error.UNEXPECTED_ERROR); }
|
||||
|
||||
final ActionResult<Void> store = storage.store(player.getUniqueId(), profiles.get(player.getUniqueId()));
|
||||
profiles.remove(player.getUniqueId());
|
||||
return store;
|
||||
}
|
||||
|
||||
public Storage getStorage() {
|
||||
return storage;
|
||||
}
|
||||
|
||||
public Cache getCache() {
|
||||
return cache;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package xyz.ineanto.nicko.storage;
|
||||
package net.artelnatif.nicko.storage;
|
||||
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
@ -11,14 +11,12 @@ public abstract class Storage {
|
|||
|
||||
public abstract StorageProvider getProvider();
|
||||
|
||||
public abstract ActionResult store(UUID uuid, NickoProfile profile);
|
||||
public abstract ActionResult<Void> store(UUID uuid, NickoProfile profile);
|
||||
|
||||
public abstract boolean isStored(UUID uuid);
|
||||
|
||||
public abstract Optional<NickoProfile> retrieve(UUID uuid);
|
||||
|
||||
public abstract ActionResult delete(UUID uuid);
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package xyz.ineanto.nicko.storage;
|
||||
package net.artelnatif.nicko.storage;
|
||||
|
||||
public interface StorageProvider {
|
||||
boolean init();
|
|
@ -1,7 +1,7 @@
|
|||
package xyz.ineanto.nicko.storage;
|
||||
package net.artelnatif.nicko.storage.cache;
|
||||
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
@ -11,14 +11,12 @@ public abstract class Cache {
|
|||
|
||||
public abstract CacheProvider getProvider();
|
||||
|
||||
public abstract ActionResult cache(UUID uuid, NickoProfile profile);
|
||||
public abstract ActionResult<Void> cache(UUID uuid, NickoProfile profile);
|
||||
|
||||
public abstract boolean isCached(UUID uuid);
|
||||
|
||||
public abstract Optional<NickoProfile> retrieve(UUID uuid);
|
||||
|
||||
public abstract ActionResult delete(UUID uuid);
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package xyz.ineanto.nicko.storage;
|
||||
package net.artelnatif.nicko.storage.cache;
|
||||
|
||||
public interface CacheProvider {
|
||||
boolean init();
|
31
core/src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCache.java
vendored
Normal file
31
core/src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCache.java
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
package net.artelnatif.nicko.storage.cache.redis;
|
||||
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.storage.cache.Cache;
|
||||
import net.artelnatif.nicko.storage.cache.CacheProvider;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class RedisCache extends Cache {
|
||||
@Override
|
||||
public CacheProvider getProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult<Void> cache(UUID uuid, NickoProfile profile) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCached(UUID uuid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
26
core/src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCacheProvider.java
vendored
Normal file
26
core/src/main/java/net/artelnatif/nicko/storage/cache/redis/RedisCacheProvider.java
vendored
Normal file
|
@ -0,0 +1,26 @@
|
|||
package net.artelnatif.nicko.storage.cache.redis;
|
||||
|
||||
import net.artelnatif.nicko.storage.cache.CacheProvider;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
public class RedisCacheProvider implements CacheProvider {
|
||||
private JedisPool pool;
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
// TODO: 3/12/23 Get port from configuration
|
||||
pool = new JedisPool("localhost", 6379);
|
||||
return !pool.isClosed() && pool.getResource() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
pool.close();
|
||||
return pool.isClosed();
|
||||
}
|
||||
|
||||
public Jedis getJedis() {
|
||||
return pool.getResource();
|
||||
}
|
||||
}
|
|
@ -1,12 +1,13 @@
|
|||
package xyz.ineanto.nicko.storage.json;
|
||||
package net.artelnatif.nicko.storage.json;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import xyz.ineanto.nicko.storage.Storage;
|
||||
import xyz.ineanto.nicko.storage.StorageProvider;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.storage.Storage;
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.Optional;
|
||||
|
@ -16,7 +17,7 @@ import java.util.logging.Logger;
|
|||
public class JSONStorage extends Storage {
|
||||
private final Logger logger = Logger.getLogger("JSONStorage");
|
||||
private final Gson gson = new GsonBuilder().serializeNulls().setPrettyPrinting().create();
|
||||
private final File directory = new File(Nicko.getInstance().getDataFolder() + "/players/");
|
||||
private final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
|
||||
private JSONStorageProvider provider;
|
||||
|
||||
|
@ -29,7 +30,7 @@ public class JSONStorage extends Storage {
|
|||
}
|
||||
|
||||
@Override
|
||||
public ActionResult store(UUID uuid, NickoProfile profile) {
|
||||
public ActionResult<Void> store(UUID uuid, NickoProfile profile) {
|
||||
final String profileToJson = gson.toJson(profile);
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
|
||||
|
@ -41,26 +42,27 @@ public class JSONStorage extends Storage {
|
|||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("Could not write to file.");
|
||||
return ActionResult.error();
|
||||
return new ActionResult<>(I18NDict.Error.JSON_ERROR);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.warning("Could not create file.");
|
||||
e.printStackTrace();
|
||||
return ActionResult.error();
|
||||
return new ActionResult<>(I18NDict.Error.JSON_ERROR);
|
||||
}
|
||||
|
||||
return ActionResult.ok();
|
||||
return new ActionResult<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStored(UUID uuid) {
|
||||
final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
return file.exists();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
final File directory = new File(NickoBukkit.getInstance().getDataFolder() + "/players/");
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
try (FileReader fileReader = new FileReader(file)) {
|
||||
try (BufferedReader reader = new BufferedReader(fileReader)) {
|
||||
|
@ -72,21 +74,7 @@ public class JSONStorage extends Storage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult delete(UUID uuid) {
|
||||
final File file = new File(directory, uuid.toString() + ".json");
|
||||
if (file.delete() || !file.exists()) {
|
||||
return ActionResult.ok();
|
||||
}
|
||||
return ActionResult.error();
|
||||
}
|
||||
|
||||
private boolean checkFileExists(File file) throws IOException {
|
||||
// Additional check if the folder gets deleted while the plugin is running.
|
||||
if (!file.getParentFile().exists()) {
|
||||
file.getParentFile().mkdirs();
|
||||
}
|
||||
|
||||
if (!file.exists()) {
|
||||
return file.createNewFile();
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
package xyz.ineanto.nicko.storage.json;
|
||||
package net.artelnatif.nicko.storage.json;
|
||||
|
||||
import xyz.ineanto.nicko.storage.StorageProvider;
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
|
@ -12,12 +12,11 @@ public class JSONStorageProvider implements StorageProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean init() {
|
||||
public boolean init()
|
||||
{
|
||||
return directory.exists() || directory.mkdirs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean close() {
|
||||
return true;
|
||||
}
|
||||
public boolean close() { return true; }
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package xyz.ineanto.nicko.storage.name;
|
||||
package net.artelnatif.nicko.storage.name;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
|
@ -1,57 +1,53 @@
|
|||
package xyz.ineanto.nicko.storage.mariadb;
|
||||
package net.artelnatif.nicko.storage.sql;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.appearance.Appearance;
|
||||
import xyz.ineanto.nicko.config.Configuration;
|
||||
import xyz.ineanto.nicko.language.Language;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import xyz.ineanto.nicko.storage.Storage;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import net.artelnatif.nicko.i18n.I18NDict;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import net.artelnatif.nicko.storage.Storage;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MariaDBStorage extends Storage {
|
||||
public class SQLStorage extends Storage {
|
||||
private final Logger logger = Logger.getLogger("SQLStorage");
|
||||
private final Configuration configuration;
|
||||
private final Gson gson = new GsonBuilder().serializeNulls().create();
|
||||
|
||||
private MariaDBStorageProvider provider;
|
||||
private SQLStorageProvider provider;
|
||||
|
||||
public MariaDBStorage(Configuration configuration) {
|
||||
public SQLStorage(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MariaDBStorageProvider getProvider() {
|
||||
public SQLStorageProvider getProvider() {
|
||||
if (provider == null) {
|
||||
provider = new MariaDBStorageProvider(configuration);
|
||||
provider = new SQLStorageProvider(configuration);
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult store(UUID uuid, NickoProfile profile) {
|
||||
public ActionResult<Void> store(UUID uuid, NickoProfile profile) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return ActionResult.error();
|
||||
if (connection == null) return new ActionResult<>(I18NDict.Error.SQL_ERROR);
|
||||
|
||||
try {
|
||||
final PreparedStatement statement = isStored(uuid) ?
|
||||
getUpdateStatement(connection, uuid, profile) : getInsertStatement(connection, uuid, profile);
|
||||
statement.executeUpdate();
|
||||
return ActionResult.ok();
|
||||
return new ActionResult<>();
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't send SQL Request: " + e.getMessage());
|
||||
return ActionResult.error();
|
||||
return new ActionResult<>(I18NDict.Error.SQL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -61,10 +57,10 @@ public class MariaDBStorage extends Storage {
|
|||
if (connection == null) return false;
|
||||
|
||||
try {
|
||||
final String sql = "SELECT uuid FROM nicko.DATA WHERE uuid = ?";
|
||||
final String sql = "SELECT * FROM nicko.DATA WHERE uuid = ?";
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
return resultSet.next();
|
||||
|
@ -78,29 +74,26 @@ public class MariaDBStorage extends Storage {
|
|||
public Optional<NickoProfile> retrieve(UUID uuid) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return Optional.empty();
|
||||
if (!isStored(uuid)) return Optional.empty();
|
||||
|
||||
try {
|
||||
final String sql = "SELECT * FROM nicko.DATA WHERE uuid = ?";
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
|
||||
final ResultSet resultSet = statement.executeQuery();
|
||||
String name = "";
|
||||
String skin = "";
|
||||
String locale = "";
|
||||
boolean randomSkin = false;
|
||||
List<Appearance> favorites = Collections.emptyList();
|
||||
boolean bungeecord = false;
|
||||
while (resultSet.next()) {
|
||||
name = resultSet.getString("name");
|
||||
skin = resultSet.getString("skin");
|
||||
locale = resultSet.getString("locale");
|
||||
randomSkin = resultSet.getBoolean("randomskin");
|
||||
favorites = gson.fromJson(resultSet.getString("favorites"), new TypeToken<List<Appearance>>() { }.getType());
|
||||
bungeecord = resultSet.getBoolean("bungeecord");
|
||||
}
|
||||
|
||||
final NickoProfile profile = new NickoProfile(new Appearance(name, skin), Language.fromCode(locale), randomSkin, favorites);
|
||||
final NickoProfile profile = new NickoProfile(name, skin, Locale.fromCode(locale), bungeecord);
|
||||
return Optional.of(profile);
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't fetch profile: " + e.getMessage());
|
||||
|
@ -108,43 +101,33 @@ public class MariaDBStorage extends Storage {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionResult delete(UUID uuid) {
|
||||
final Connection connection = getProvider().getConnection();
|
||||
if (connection == null) return ActionResult.error();
|
||||
|
||||
try {
|
||||
final String sql = "DELETE FROM nicko.DATA WHERE uuid = ?";
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, uuid.toString());
|
||||
int rows = statement.executeUpdate();
|
||||
return (rows == 1 ? ActionResult.ok() : ActionResult.error());
|
||||
} catch (SQLException e) {
|
||||
logger.warning("Couldn't delete profile: " + e.getMessage());
|
||||
return ActionResult.error();
|
||||
}
|
||||
}
|
||||
|
||||
private PreparedStatement getInsertStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
|
||||
final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `randomskin`, `favorites`) VALUES (?, ?, ?, ?, ?, ?)";
|
||||
final String sql = "INSERT IGNORE INTO nicko.DATA (`uuid`, `name`, `skin`, `locale`, `bungeecord`) VALUES (?, ?, ?, ?, ?)";
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, uuid.toString());
|
||||
statement.setBinaryStream(1, uuidToBin(uuid));
|
||||
statement.setString(2, profile.getName() == null ? null : profile.getName());
|
||||
statement.setString(3, profile.getSkin() == null ? null : profile.getSkin());
|
||||
statement.setString(4, profile.getLocale().getCode());
|
||||
statement.setBoolean(5, profile.isRandomSkin());
|
||||
statement.setString(6, gson.toJson(profile.getFavorites(), new TypeToken<List<Appearance>>() { }.getRawType()));
|
||||
statement.setBoolean(5, profile.isBungeecordTransfer());
|
||||
return statement;
|
||||
}
|
||||
|
||||
private PreparedStatement getUpdateStatement(Connection connection, UUID uuid, NickoProfile profile) throws SQLException {
|
||||
final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, randomskin = ? WHERE uuid = ?";
|
||||
final String sql = "UPDATE nicko.DATA SET name = ?, skin = ?, locale = ?, bungeecord = ? WHERE uuid = ?";
|
||||
final PreparedStatement statement = connection.prepareStatement(sql);
|
||||
statement.setString(1, profile.getName() == null ? null : profile.getName());
|
||||
statement.setString(2, profile.getSkin() == null ? null : profile.getSkin());
|
||||
statement.setString(3, profile.getLocale().getCode());
|
||||
statement.setBoolean(4, profile.isRandomSkin());
|
||||
statement.setString(5, uuid.toString());
|
||||
statement.setBoolean(4, profile.isBungeecordTransfer());
|
||||
statement.setBinaryStream(5, uuidToBin(uuid));
|
||||
return statement;
|
||||
}
|
||||
|
||||
private ByteArrayInputStream uuidToBin(UUID uuid) {
|
||||
byte[] bytes = new byte[16];
|
||||
ByteBuffer.wrap(bytes)
|
||||
.putLong(uuid.getMostSignificantBits())
|
||||
.putLong(uuid.getLeastSignificantBits());
|
||||
return new ByteArrayInputStream(bytes);
|
||||
}
|
||||
}
|
|
@ -1,24 +1,24 @@
|
|||
package xyz.ineanto.nicko.storage.mariadb;
|
||||
package net.artelnatif.nicko.storage.sql;
|
||||
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import net.artelnatif.nicko.storage.StorageProvider;
|
||||
import org.mariadb.jdbc.MariaDbDataSource;
|
||||
import xyz.ineanto.nicko.config.Configuration;
|
||||
import xyz.ineanto.nicko.config.DataSourceConfiguration;
|
||||
import xyz.ineanto.nicko.storage.StorageProvider;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class MariaDBStorageProvider implements StorageProvider {
|
||||
private final Logger logger = Logger.getLogger("MariaDBStorageProvider");
|
||||
public class SQLStorageProvider implements StorageProvider {
|
||||
private final Logger logger = Logger.getLogger("SQLStorageProvider");
|
||||
private final Configuration configuration;
|
||||
|
||||
private Connection connection;
|
||||
|
||||
private final String schemaName = "nicko";
|
||||
|
||||
public MariaDBStorageProvider(Configuration configuration) {
|
||||
public SQLStorageProvider(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
}
|
||||
|
||||
|
@ -26,12 +26,11 @@ public class MariaDBStorageProvider implements StorageProvider {
|
|||
public boolean init() {
|
||||
try {
|
||||
final MariaDbDataSource dataSource = new MariaDbDataSource();
|
||||
final DataSourceConfiguration sqlConfiguration = configuration.getSqlConfiguration();
|
||||
dataSource.setUrl("jdbc:mariadb://" + sqlConfiguration.getAddress() + ":" + sqlConfiguration.getPort());
|
||||
dataSource.setUser(sqlConfiguration.getUsername());
|
||||
dataSource.setPassword(sqlConfiguration.getPassword());
|
||||
final DataSourceConfiguration dataSourceConfiguration = configuration.getSqlConfiguration();
|
||||
dataSource.setUrl("jdbc:mariadb://" + dataSourceConfiguration.getAddress() + ":" + dataSourceConfiguration.getPort());
|
||||
dataSource.setUser(dataSourceConfiguration.getUsername());
|
||||
dataSource.setPassword(dataSourceConfiguration.getPassword());
|
||||
connection = dataSource.getConnection();
|
||||
connection.setAutoCommit(true);
|
||||
final boolean initialized = connection != null && !connection.isClosed();
|
||||
|
||||
if (!initialized) return false;
|
||||
|
@ -40,7 +39,7 @@ public class MariaDBStorageProvider implements StorageProvider {
|
|||
createTable();
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
logger.severe("Couldn't establish a connection to the MariaDB database: " + e.getMessage());
|
||||
logger.severe("Couldn't establish a connection to the MySQL database: " + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -58,24 +57,30 @@ public class MariaDBStorageProvider implements StorageProvider {
|
|||
|
||||
private void createTable() throws SQLException {
|
||||
final Connection connection = getConnection();
|
||||
final String query = "CREATE TABLE IF NOT EXISTS %s.DATA ".replace("%s", schemaName) +
|
||||
"(uuid varchar(36) NOT NULL," +
|
||||
"name varchar(16)," +
|
||||
"skin varchar(16)," +
|
||||
"locale char(2) NOT NULL," +
|
||||
"bungeecord boolean NOT NULL," +
|
||||
"PRIMARY KEY (uuid))";
|
||||
|
||||
String query = "CREATE TABLE IF NOT EXISTS %s.DATA " +
|
||||
"(uuid binary(16) NOT NULL," +
|
||||
"name varchar(16)," +
|
||||
"skin varchar(16)," +
|
||||
"locale char(2) NOT NULL," +
|
||||
"bungeecord boolean NOT NULL," +
|
||||
"PRIMARY KEY (UUID))";
|
||||
query = query.replace("%s", schemaName);
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(query);
|
||||
statement.executeUpdate();
|
||||
statement.close();
|
||||
}
|
||||
|
||||
private void createDatabase() throws SQLException {
|
||||
final Connection connection = getConnection();
|
||||
final String query = "CREATE DATABASE IF NOT EXISTS %s".replace("%s", schemaName);
|
||||
|
||||
String query = "CREATE DATABASE IF NOT EXISTS %s";
|
||||
query = query.replace("%s", schemaName);
|
||||
|
||||
final PreparedStatement statement = connection.prepareStatement(query);
|
||||
statement.executeUpdate();
|
||||
statement.close();
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
|
@ -1,23 +1,16 @@
|
|||
# Nicko ${version} - Config:
|
||||
# Nicko ${project.version} - Config:
|
||||
|
||||
# Specifies the configuration version, don't change.
|
||||
version: "1.2.0"
|
||||
###########
|
||||
# STORAGE #
|
||||
###########
|
||||
|
||||
# Nicko will copy the English locale as "lang.yml"
|
||||
# and will use the translations in that file when "Server Custom"
|
||||
# is selected as the player's locale.
|
||||
# Indicates wherever the data will be stored
|
||||
# locally through a .json file or a (My)SQL database.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
customLocale: false
|
||||
local: true
|
||||
|
||||
# This configuration section manages SQL.
|
||||
sql:
|
||||
# Indicates wherever the data will be stored locally
|
||||
# inside a .json file or in an SQL database.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
enabled: false
|
||||
# Toggles between the MariaDB and MySQL drivers.
|
||||
# If you use the MySQL database engine, switch this to off.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
mariadb: true
|
||||
# SQL database's address
|
||||
# Accepted values: valid IP address (e.g. localhost, 127.0.0.1)
|
||||
address: "localhost"
|
||||
|
@ -31,13 +24,15 @@ sql:
|
|||
# Accepted values: any string
|
||||
password: "password"
|
||||
|
||||
# This configuration section manages Redis (BungeeCord support).
|
||||
# It is used to transfer data between multiple servers.
|
||||
redis:
|
||||
# Indicates wherever the data will be stored through
|
||||
# Redis to transfer whenever a player switches server.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
enabled: false
|
||||
# Redis server's address
|
||||
# Accepted values: valid IP address (e.g.: localhost, 127.0.0.1)
|
||||
# Accepted values: valid IP address (e.g. localhost, 127.0.0.1)
|
||||
address: "localhost"
|
||||
# Redis server's port
|
||||
# Accepted values: valid integer (e.g. 3306, 25565)
|
||||
|
@ -47,4 +42,18 @@ redis:
|
|||
username: "username"
|
||||
# Redis server's password
|
||||
# Accepted values: any string
|
||||
password: "password"
|
||||
password: "password"
|
||||
|
||||
###########
|
||||
# DISPLAY #
|
||||
###########
|
||||
|
||||
# Nicko's messages prefix.
|
||||
# Accepted values: any string
|
||||
prefix: "§6Nicko §8§l| §r"
|
||||
|
||||
# Nicko will copy the English locale as "lang.yml"
|
||||
# and will use the translations in that file when "Server Custom"
|
||||
# is selected as the player's locale.
|
||||
# Accepted values: false (Disabled), true (Enabled)
|
||||
customLocale: false
|
22
core/src/main/resources/en.yml
Normal file
22
core/src/main/resources/en.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
error:
|
||||
couldnt_get_name_from_mojang: "Failed to get username from Mojang"
|
||||
couldnt_get_skin_from_cache: "Failed to get skin from cache"
|
||||
couldnt_get_skin_from_mojang: "Failed to get skin from Mojang"
|
||||
generic: "Unknown error"
|
||||
invalid_username: "§cThe specified username is not a valid Minecraft username."
|
||||
player_offline: "§c{0} §fis offline, please try again."
|
||||
sql: "SQL Error"
|
||||
json: "JSON Error"
|
||||
event:
|
||||
admin:
|
||||
cache_clear: "§aSkin cache cleaned."
|
||||
disguise:
|
||||
fail: "§cUnable to apply your disguise. §7§o({0})"
|
||||
success: "§aDisguise applied!"
|
||||
previous_skin_applied:
|
||||
fail: "§cFailed to apply your previous disguise back. §7§o({0})"
|
||||
success: "§aYour previous active disguise has been applied back."
|
||||
undisguise:
|
||||
fail: "§cUnable to remove your disguise. It will be set back to default on your next login. Sorry!"
|
||||
none: "§cYou do not have an active disguise."
|
||||
success: "§aDisguise removed."
|
22
core/src/main/resources/fr.yml
Normal file
22
core/src/main/resources/fr.yml
Normal file
|
@ -0,0 +1,22 @@
|
|||
error:
|
||||
couldnt_get_name_from_mojang: "Impossible de récupérer le nom d''utilisateur depuis Mojang"
|
||||
couldnt_get_skin_from_cache: "Impossible de récupérer le skin depuis le cache"
|
||||
couldnt_get_skin_from_mojang: "Impossible de récupérer le skin depuis Mojang"
|
||||
generic: "Erreur inconnue"
|
||||
invalid_username: "§cLe pseudo spécifié n''est pas un pseudo Minecraft valide."
|
||||
player_offline: "§c{0} §fest hors-ligne, veuillez réessayer."
|
||||
sql: "Erreur SQL"
|
||||
json: "Erreur JSON"
|
||||
event:
|
||||
admin:
|
||||
cache_clear: "§aCache des skins nettoyé."
|
||||
disguise:
|
||||
fail: "§cImpossible d''appliquer votre déguisement. §7§o({0})"
|
||||
success: "§aDéguisement appliqué !"
|
||||
previous_skin_applied:
|
||||
fail: "§cImpossible d''appliquer votre déguisement précédent. §7§o({0})"
|
||||
success: "§aVotre précédent déguisement a été réappliqué."
|
||||
undisguise:
|
||||
fail: "§cImpossible de retier votre déguisement. Il sera remis par défaut à votre prochaine reconnexion. Désolé !"
|
||||
none: "§cVous n''avez pas de déguisement."
|
||||
success: "§aDéguisement retiré."
|
17
core/src/main/resources/plugin.yml
Normal file
17
core/src/main/resources/plugin.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
name: Nicko
|
||||
main: net.artelnatif.nicko.NickoBukkit
|
||||
version: 1.0-SNAPSHOT
|
||||
author: Aro
|
||||
api-version: 1.13
|
||||
softdepend: [ PlaceholderAPI ]
|
||||
commands:
|
||||
nicko:
|
||||
description: "Opens Nicko's GUI."
|
||||
permission: nicko.admin
|
||||
permissions:
|
||||
nicko.*:
|
||||
default: op
|
||||
children:
|
||||
- nicko.use
|
||||
nicko.use:
|
||||
default: op
|
|
@ -0,0 +1,36 @@
|
|||
package net.artelnatif.nicko.test;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
|
||||
public class NickoPluginTest {
|
||||
private static NickoBukkit plugin;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
final Configuration config = new Configuration(
|
||||
DataSourceConfiguration.SQL_EMPTY,
|
||||
DataSourceConfiguration.REDIS_EMPTY,
|
||||
"",
|
||||
true,
|
||||
false);
|
||||
MockBukkit.mock();
|
||||
plugin = MockBukkit.load(NickoBukkit.class, config);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Plugin Initialization")
|
||||
public void initializePlugin() {
|
||||
assertNotNull(plugin);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdown() {
|
||||
MockBukkit.unmock();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package net.artelnatif.nicko.test.config;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class ConfigurationTest {
|
||||
private static NickoBukkit plugin;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
MockBukkit.mock();
|
||||
plugin = MockBukkit.load(NickoBukkit.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Read configuration")
|
||||
public void readConfiguration() {
|
||||
final Configuration configuration = plugin.getNickoConfig();
|
||||
assertTrue(configuration.isLocal());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdown() {
|
||||
MockBukkit.unmock();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package net.artelnatif.nicko.test.storage;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import be.seeseemelk.mockbukkit.ServerMock;
|
||||
import be.seeseemelk.mockbukkit.entity.PlayerMock;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class BrokenSQLTest {
|
||||
private static ServerMock server;
|
||||
private static NickoBukkit plugin;
|
||||
private static PlayerMock player;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
final Configuration config = new Configuration(
|
||||
DataSourceConfiguration.SQL_EMPTY,
|
||||
DataSourceConfiguration.REDIS_EMPTY,
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
server = MockBukkit.mock();
|
||||
plugin = MockBukkit.load(NickoBukkit.class, config);
|
||||
player = server.addPlayer();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Fail to create Tables")
|
||||
public void createSQLTables() {
|
||||
assertTrue(plugin.getDataStore().getStorage().isError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Fail to Store Player Via SQL")
|
||||
public void storePlayer() {
|
||||
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertFalse(optionalProfile.isPresent());
|
||||
ActionResult<Void> result = plugin.getDataStore().saveData(player);
|
||||
assertTrue(result.isError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Fail to Retrieve Player Via SQL")
|
||||
public void retrievePlayer() {
|
||||
final Optional<NickoProfile> storeAction = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertFalse(storeAction.isPresent());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdown() {
|
||||
MockBukkit.unmock();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package net.artelnatif.nicko.test.storage;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import be.seeseemelk.mockbukkit.ServerMock;
|
||||
import be.seeseemelk.mockbukkit.entity.PlayerMock;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import net.artelnatif.nicko.i18n.Locale;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.disguise.ActionResult;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.junit.jupiter.api.*;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class SQLStorageTest {
|
||||
private static ServerMock server;
|
||||
private static NickoBukkit plugin;
|
||||
private static PlayerMock player;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
final Configuration config = new Configuration(
|
||||
new DataSourceConfiguration("127.0.0.1", 3306, "root", "12345"),
|
||||
DataSourceConfiguration.REDIS_EMPTY,
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
server = MockBukkit.mock();
|
||||
plugin = MockBukkit.load(NickoBukkit.class, config);
|
||||
player = server.addPlayer();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Create SQL Tables")
|
||||
@Order(1)
|
||||
public void createSQLTables() {
|
||||
assertFalse(plugin.getDataStore().getStorage().isError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Store Player Via SQL")
|
||||
@Order(2)
|
||||
public void storePlayer() {
|
||||
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalProfile.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Retrieve Player Via SQL")
|
||||
@Order(3)
|
||||
public void retrievePlayer() {
|
||||
final Optional<NickoProfile> storeAction = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(storeAction.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Update Player Via SQL")
|
||||
@Order(4)
|
||||
public void updatePlayer() {
|
||||
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalProfile.isPresent());
|
||||
|
||||
final NickoProfile profile = optionalProfile.get();
|
||||
Assertions.assertNull(profile.getName());
|
||||
Assertions.assertNull(profile.getSkin());
|
||||
Assertions.assertEquals(profile.getLocale(), Locale.ENGLISH);
|
||||
assertTrue(profile.isBungeecordTransfer());
|
||||
|
||||
profile.setName("Notch");
|
||||
profile.setSkin("Notch");
|
||||
profile.setLocale(Locale.FRENCH);
|
||||
profile.setBungeecordTransfer(false);
|
||||
|
||||
final ActionResult<Void> result = plugin.getDataStore().saveData(player);
|
||||
assertFalse(result.isError());
|
||||
|
||||
final Optional<NickoProfile> optionalUpdatedProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalUpdatedProfile.isPresent());
|
||||
final NickoProfile updatedProfile = optionalProfile.get();
|
||||
Assertions.assertEquals(updatedProfile.getName(), "Notch");
|
||||
Assertions.assertEquals(updatedProfile.getSkin(), "Notch");
|
||||
Assertions.assertEquals(updatedProfile.getLocale(), Locale.FRENCH);
|
||||
assertFalse(updatedProfile.isBungeecordTransfer());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Remove Player Disguise Via SQL")
|
||||
@Order(5)
|
||||
public void removePlayerDisguise() {
|
||||
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalProfile.isPresent());
|
||||
|
||||
final NickoProfile profile = optionalProfile.get();
|
||||
|
||||
profile.setName(null);
|
||||
profile.setSkin(null);
|
||||
|
||||
final ActionResult<Void> result = plugin.getDataStore().saveData(player);
|
||||
assertFalse(result.isError());
|
||||
|
||||
final Optional<NickoProfile> optionalUpdatedProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalUpdatedProfile.isPresent());
|
||||
final NickoProfile updatedProfile = optionalProfile.get();
|
||||
Assertions.assertNull(updatedProfile.getName());
|
||||
Assertions.assertNull(updatedProfile.getSkin());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdown() {
|
||||
MockBukkit.unmock();
|
||||
}
|
||||
}
|
49
core/src/test/java/net/artelnatif/nicko/test/storage/cache/CacheStorageTest.java
vendored
Normal file
49
core/src/test/java/net/artelnatif/nicko/test/storage/cache/CacheStorageTest.java
vendored
Normal file
|
@ -0,0 +1,49 @@
|
|||
package net.artelnatif.nicko.test.storage.cache;
|
||||
|
||||
import be.seeseemelk.mockbukkit.MockBukkit;
|
||||
import be.seeseemelk.mockbukkit.ServerMock;
|
||||
import be.seeseemelk.mockbukkit.entity.PlayerMock;
|
||||
import net.artelnatif.nicko.NickoBukkit;
|
||||
import net.artelnatif.nicko.config.Configuration;
|
||||
import net.artelnatif.nicko.config.DataSourceConfiguration;
|
||||
import net.artelnatif.nicko.disguise.NickoProfile;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class CacheStorageTest {
|
||||
private static ServerMock server;
|
||||
private static NickoBukkit plugin;
|
||||
private static PlayerMock player;
|
||||
|
||||
@BeforeAll
|
||||
public static void setup() {
|
||||
final Configuration config = new Configuration(
|
||||
new DataSourceConfiguration("127.0.0.1", 3306, "root", "12345"),
|
||||
DataSourceConfiguration.REDIS_EMPTY,
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
server = MockBukkit.mock();
|
||||
plugin = MockBukkit.load(NickoBukkit.class, config);
|
||||
player = server.addPlayer();
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Cache Player Data")
|
||||
public void cachePlayerData() {
|
||||
final Optional<NickoProfile> optionalProfile = plugin.getDataStore().getData(player.getUniqueId());
|
||||
assertTrue(optionalProfile.isPresent());
|
||||
//assertTrue(plugin.getDataStore().isCached(player.getUniqueId()));
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void shutdown() {
|
||||
MockBukkit.unmock();
|
||||
}
|
||||
}
|
115
dist/pom.xml
vendored
Normal file
115
dist/pom.xml
vendored
Normal file
|
@ -0,0 +1,115 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>nicko-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>dist</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
|
||||
<build>
|
||||
<directory>../target</directory>
|
||||
<finalName>nicko-${project.version}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>3.3.1-SNAPSHOT</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactSet>
|
||||
<includes>
|
||||
<include>net.artelnatif:*</include>
|
||||
</includes>
|
||||
</artifactSet>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_13_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_13_R2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_14_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_15_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_16_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_16_R2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_16_R3</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_17_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_18_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_18_R2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_19_R1</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_19_R2</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>v1_19_R3</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
7
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,7 +0,0 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
251
gradlew
vendored
251
gradlew
vendored
|
@ -1,251 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
94
gradlew.bat
vendored
94
gradlew.bat
vendored
|
@ -1,94 +0,0 @@
|
|||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
@rem SPDX-License-Identifier: Apache-2.0
|
||||
@rem
|
||||
|
||||
@if "%DEBUG%"=="" @echo off
|
||||
@rem ##########################################################################
|
||||
@rem
|
||||
@rem Gradle startup script for Windows
|
||||
@rem
|
||||
@rem ##########################################################################
|
||||
|
||||
@rem Set local scope for the variables with windows NT shell
|
||||
if "%OS%"=="Windows_NT" setlocal
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
@rem This is normally unused
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:findJavaFromJavaHome
|
||||
set JAVA_HOME=%JAVA_HOME:"=%
|
||||
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||
|
||||
if exist "%JAVA_EXE%" goto execute
|
||||
|
||||
echo. 1>&2
|
||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||
echo. 1>&2
|
||||
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||
echo location of your Java installation. 1>&2
|
||||
|
||||
goto fail
|
||||
|
||||
:execute
|
||||
@rem Setup the command line
|
||||
|
||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||
|
||||
|
||||
@rem Execute Gradle
|
||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||
|
||||
:fail
|
||||
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||
rem the _cmd.exe /c_ return code!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
BIN
img/LOGO.png
Normal file
BIN
img/LOGO.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
35
pom.xml
Normal file
35
pom.xml
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>net.artelnatif</groupId>
|
||||
<artifactId>nicko-parent</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<name>Nicko</name>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>core</module>
|
||||
<module>dist</module>
|
||||
<module>v1_13_R1</module>
|
||||
<module>v1_13_R2</module>
|
||||
<module>v1_14_R1</module>
|
||||
<module>v1_15_R1</module>
|
||||
<module>v1_16_R1</module>
|
||||
<module>v1_16_R2</module>
|
||||
<module>v1_16_R3</module>
|
||||
<module>v1_17_R1</module>
|
||||
<module>v1_18_R1</module>
|
||||
<module>v1_18_R2</module>
|
||||
<module>v1_19_R1</module>
|
||||
<module>v1_19_R2</module>
|
||||
<module>v1_19_R3</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
<maven.compiler.source>11</maven.compiler.source>
|
||||
<maven.compiler.target>11</maven.compiler.target>
|
||||
</properties>
|
||||
</project>
|
|
@ -1,2 +0,0 @@
|
|||
rootProject.name = "nicko"
|
||||
|
|
@ -1,176 +0,0 @@
|
|||
package xyz.ineanto.nicko;
|
||||
|
||||
import com.comphenix.protocol.utility.MinecraftVersion;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import xyz.ineanto.nicko.appearance.random.RandomNameFetcher;
|
||||
import xyz.ineanto.nicko.command.NickoCommand;
|
||||
import xyz.ineanto.nicko.config.Configuration;
|
||||
import xyz.ineanto.nicko.config.ConfigurationManager;
|
||||
import xyz.ineanto.nicko.event.PlayerJoinListener;
|
||||
import xyz.ineanto.nicko.event.PlayerQuitListener;
|
||||
import xyz.ineanto.nicko.language.CustomLanguage;
|
||||
import xyz.ineanto.nicko.language.Language;
|
||||
import xyz.ineanto.nicko.migration.ConfigurationMigrator;
|
||||
import xyz.ineanto.nicko.migration.CustomLocaleMigrator;
|
||||
import xyz.ineanto.nicko.mojang.MojangAPI;
|
||||
import xyz.ineanto.nicko.placeholder.NickoExpansion;
|
||||
import xyz.ineanto.nicko.storage.PlayerDataStore;
|
||||
import xyz.ineanto.nicko.storage.json.JSONStorage;
|
||||
import xyz.ineanto.nicko.storage.map.MapCache;
|
||||
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
|
||||
import xyz.xenondevs.invui.InvUI;
|
||||
import xyz.xenondevs.invui.gui.structure.Structure;
|
||||
import xyz.xenondevs.invui.item.builder.ItemBuilder;
|
||||
import xyz.xenondevs.invui.item.impl.SimpleItem;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class Nicko extends JavaPlugin {
|
||||
private static Nicko plugin;
|
||||
|
||||
private MojangAPI mojangAPI;
|
||||
private PlayerDataStore dataStore;
|
||||
private ConfigurationManager configurationManager;
|
||||
private Configuration configuration;
|
||||
private CustomLanguage customLanguage;
|
||||
private PlayerNameStore nameStore;
|
||||
private RandomNameFetcher nameFetcher;
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
plugin = this;
|
||||
|
||||
configurationManager = new ConfigurationManager(getDataFolder());
|
||||
configurationManager.saveDefaultConfig();
|
||||
|
||||
dataStore = new PlayerDataStore(mojangAPI, getNickoConfig());
|
||||
|
||||
if (!MinecraftVersion.v1_21_5.atOrAbove()) {
|
||||
getLogger().severe("This version (" + MinecraftVersion.getCurrentVersion().getVersion() + ") is not supported by Nicko!");
|
||||
getLogger().severe("As of version 1.2.0, Nicko only supports the latest Minecraft version. (Currently 1.21.5)");
|
||||
dataStore.getStorage().setError(true);
|
||||
Bukkit.getPluginManager().disablePlugin(this);
|
||||
}
|
||||
|
||||
if (!Bukkit.getOnlineMode()) {
|
||||
getLogger().warning("Nicko has not been tested using offline mode!");
|
||||
getLogger().warning("Issues regarding Nicko being used in offline mode will be ignored for now.");
|
||||
}
|
||||
|
||||
try {
|
||||
Class.forName("io.papermc.paper.threadedregions.RegionizedServerInitEvent");
|
||||
getLogger().warning("Nicko has not been tested against Folia and might not work at all!");
|
||||
getLogger().warning("Issues regarding Nicko on Folia will be ignored for now.");
|
||||
} catch (ClassNotFoundException ignored) { }
|
||||
|
||||
getLogger().info("Loading persistence...");
|
||||
if (!dataStore.getStorage().getProvider().init()) {
|
||||
getLogger().severe("Couldn't connect to distant persistence, falling back on local persistence.");
|
||||
final JSONStorage storage = new JSONStorage();
|
||||
storage.getProvider().init();
|
||||
dataStore.setStorage(storage);
|
||||
}
|
||||
|
||||
getLogger().info("Loading cache...");
|
||||
if (!dataStore.getCache().getProvider().init()) {
|
||||
getLogger().severe("Couldn't connect to distant cache, falling back on local cache.");
|
||||
final MapCache cache = new MapCache();
|
||||
cache.getProvider().init();
|
||||
dataStore.setCache(cache);
|
||||
}
|
||||
|
||||
nameStore = new PlayerNameStore();
|
||||
mojangAPI = new MojangAPI();
|
||||
nameFetcher = new RandomNameFetcher(this);
|
||||
|
||||
new ConfigurationMigrator(this).migrate();
|
||||
InvUI.getInstance().setPlugin(this);
|
||||
|
||||
if (configuration.isCustomLocale()) {
|
||||
try {
|
||||
CustomLanguage.dumpIntoFile(Language.ENGLISH);
|
||||
customLanguage = new CustomLanguage();
|
||||
new CustomLocaleMigrator(this, customLanguage).migrate();
|
||||
getLogger().info("Successfully loaded the custom locale.");
|
||||
} catch (IOException e) {
|
||||
getLogger().severe("Failed to load the custom locale!");
|
||||
}
|
||||
}
|
||||
|
||||
registerCommand("nicko", new NickoCommand());
|
||||
|
||||
Structure.addGlobalIngredient('#', new SimpleItem(new ItemBuilder(Material.AIR)));
|
||||
Structure.addGlobalIngredient('%', new SimpleItem(new ItemBuilder(Material.BLACK_STAINED_GLASS_PANE).setDisplayName(" ")));
|
||||
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) {
|
||||
getLogger().info("Enabling PlaceHolderAPI support...");
|
||||
new NickoExpansion(this).register();
|
||||
}
|
||||
|
||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(), this);
|
||||
getServer().getPluginManager().registerEvents(new PlayerQuitListener(), this);
|
||||
|
||||
getLogger().info("Nicko has been enabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
if (!getDataStore().getStorage().isError()) {
|
||||
Bukkit.getOnlinePlayers().forEach(player -> dataStore.saveData(player));
|
||||
if (!dataStore.getStorage().getProvider().close()) {
|
||||
getLogger().severe("Failed to close persistence!");
|
||||
} else {
|
||||
getLogger().info("Persistence closed.");
|
||||
}
|
||||
}
|
||||
|
||||
nameStore.clearStoredNames();
|
||||
getLogger().info("Nicko (Bukkit) has been disabled.");
|
||||
}
|
||||
|
||||
public static Nicko getInstance() {
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public Configuration getNickoConfig() {
|
||||
try {
|
||||
if (configuration == null) {
|
||||
configuration = configurationManager.load();
|
||||
getLogger().info("Configuration file loaded.");
|
||||
}
|
||||
return configuration;
|
||||
} catch (IOException e) {
|
||||
getLogger().severe("Failed to load the configuration file!");
|
||||
getLogger().severe("It may be have been generated with an older version of Nicko.");
|
||||
getLogger().severe("Delete the configuration and restart the server please :)");
|
||||
getLogger().severe("(" + e.getMessage() + ")");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public RandomNameFetcher getNameFetcher() {
|
||||
return nameFetcher;
|
||||
}
|
||||
|
||||
public PlayerDataStore getDataStore() {
|
||||
return dataStore;
|
||||
}
|
||||
|
||||
public ConfigurationManager getConfigurationManager() {
|
||||
return configurationManager;
|
||||
}
|
||||
|
||||
public PlayerNameStore getNameStore() {
|
||||
return nameStore;
|
||||
}
|
||||
|
||||
public MojangAPI getMojangAPI() {
|
||||
return mojangAPI;
|
||||
}
|
||||
|
||||
public CustomLanguage getCustomLocale() {
|
||||
return customLanguage;
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
package xyz.ineanto.nicko.appearance;
|
||||
|
||||
public class ActionResult {
|
||||
private final String errorKey;
|
||||
private boolean error = false;
|
||||
|
||||
public static ActionResult ok() {
|
||||
return new ActionResult();
|
||||
}
|
||||
|
||||
public static ActionResult error() {
|
||||
return new ActionResult(null);
|
||||
}
|
||||
|
||||
public static ActionResult error(String errorMessage) {
|
||||
return new ActionResult(errorMessage);
|
||||
}
|
||||
|
||||
private ActionResult() {
|
||||
this.errorKey = null;
|
||||
}
|
||||
|
||||
private ActionResult(String errorMessage) {
|
||||
this.errorKey = errorMessage;
|
||||
this.error = true;
|
||||
}
|
||||
|
||||
public boolean isError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public String getErrorKey() {
|
||||
return errorKey;
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package xyz.ineanto.nicko.appearance;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public record Appearance(
|
||||
@Nullable String name,
|
||||
@Nullable String skin
|
||||
) {}
|
|
@ -1,70 +0,0 @@
|
|||
package xyz.ineanto.nicko.appearance;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.event.custom.PlayerDisguiseEvent;
|
||||
import xyz.ineanto.nicko.event.custom.PlayerResetDisguiseEvent;
|
||||
import xyz.ineanto.nicko.packet.PacketSender;
|
||||
import xyz.ineanto.nicko.packet.PaperPacketSender;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import xyz.ineanto.nicko.storage.PlayerDataStore;
|
||||
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class AppearanceManager {
|
||||
private final Nicko instance = Nicko.getInstance();
|
||||
private final PlayerDataStore dataStore = instance.getDataStore();
|
||||
private final PlayerNameStore nameStore = instance.getNameStore();
|
||||
private final PacketSender packetSender;
|
||||
|
||||
private final Player player;
|
||||
|
||||
public AppearanceManager(Player player) {
|
||||
this.player = player;
|
||||
this.packetSender = new PaperPacketSender(player, getNickoProfile());
|
||||
}
|
||||
|
||||
public ActionResult reset() {
|
||||
final NickoProfile profile = getNickoProfile();
|
||||
|
||||
// Call the event.
|
||||
final PlayerResetDisguiseEvent event = new PlayerResetDisguiseEvent(player);
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
profile.setName(null);
|
||||
profile.setSkin(null);
|
||||
dataStore.getCache().cache(player.getUniqueId(), profile);
|
||||
|
||||
return ActionResult.error();
|
||||
}
|
||||
|
||||
public ActionResult update(boolean skinChange) {
|
||||
final NickoProfile profile = getNickoProfile();
|
||||
final String displayName = profile.getName() == null ? player.getName() : profile.getName();
|
||||
|
||||
final ActionResult result = packetSender.updatePlayerProfile(displayName);
|
||||
|
||||
if (skinChange) {
|
||||
final ActionResult propertiesUpdateResult = packetSender.updatePlayerProfileProperties();
|
||||
|
||||
if (propertiesUpdateResult.isError()) {
|
||||
return reset();
|
||||
}
|
||||
}
|
||||
|
||||
// Call the event.
|
||||
final PlayerDisguiseEvent event = new PlayerDisguiseEvent(player, profile.getSkin(), profile.getName());
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
packetSender.sendEntityMetadataUpdate();
|
||||
packetSender.sendTabListUpdate(displayName);
|
||||
return result;
|
||||
}
|
||||
|
||||
private NickoProfile getNickoProfile() {
|
||||
final Optional<NickoProfile> optionalProfile = dataStore.getData(player.getUniqueId());
|
||||
return optionalProfile.orElse(NickoProfile.EMPTY_PROFILE.clone());
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package xyz.ineanto.nicko.appearance.random;
|
||||
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class RandomNameFetcher {
|
||||
private final Nicko instance;
|
||||
|
||||
public RandomNameFetcher(Nicko instance) {
|
||||
this.instance = instance;
|
||||
}
|
||||
|
||||
public String getRandomUsername() {
|
||||
final InputStream resource = instance.getResource("names.txt");
|
||||
final List<List<String>> records = new ArrayList<>();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
final String[] values = line.split("\n");
|
||||
records.add(Arrays.asList(values));
|
||||
}
|
||||
return records.get(new Random().nextInt(records.size() - 1)).getFirst();
|
||||
} catch (IOException e) {
|
||||
instance.getLogger().severe("Unable to fetch random names.");
|
||||
return "Ineanto";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
package xyz.ineanto.nicko.command;
|
||||
|
||||
import io.papermc.paper.command.brigadier.BasicCommand;
|
||||
import io.papermc.paper.command.brigadier.CommandSourceStack;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.config.Configuration;
|
||||
import xyz.ineanto.nicko.gui.HomeGUI;
|
||||
import xyz.ineanto.nicko.language.Language;
|
||||
import xyz.ineanto.nicko.language.PlayerLanguage;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressWarnings("UnstableApiUsage")
|
||||
public class NickoCommand implements BasicCommand {
|
||||
@Override
|
||||
public void execute(CommandSourceStack stack, String[] args) {
|
||||
final Entity executor = stack.getExecutor();
|
||||
final Player player = (Player) executor;
|
||||
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
|
||||
|
||||
if (player == null) { return; }
|
||||
|
||||
if (args.length >= 1 && args[0].equalsIgnoreCase("about")) {
|
||||
final Component firstAboutMessage = MiniMessage.miniMessage().deserialize(
|
||||
"<prefix> <dark_gray>(© Ineanto 2023-2025) </dark_gray><gray>v<version></gray> ",
|
||||
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
|
||||
Placeholder.unparsed("version", Nicko.getInstance().getPluginMeta().getVersion())
|
||||
);
|
||||
|
||||
final Component secondAboutMessage = MiniMessage.miniMessage().deserialize(
|
||||
"<gradient:#01a97c:#8ffd54>Configuration</gradient> <gray>v<configversion></gray>, <gradient:#01a97c:#8ffd54>I18N</gradient> <gray><i18nversion></gray>",
|
||||
Placeholder.component("prefix", playerLanguage.getPrefixComponent()),
|
||||
Placeholder.unparsed("configversion", Configuration.VERSION.toString()),
|
||||
Placeholder.unparsed("i18nversion", Language.VERSION.toString())
|
||||
|
||||
);
|
||||
|
||||
player.sendMessage(firstAboutMessage);
|
||||
player.sendMessage(secondAboutMessage);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
new HomeGUI(player).open();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(CommandSender sender) {
|
||||
return sender instanceof Player && sender.isOp() || sender.hasPermission(permission());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> suggest(CommandSourceStack commandSourceStack, String[] args) {
|
||||
return List.of("about");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable String permission() {
|
||||
return "nicko.use";
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
package xyz.ineanto.nicko.config;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import xyz.ineanto.nicko.version.Version;
|
||||
|
||||
public class Configuration {
|
||||
public static final Version VERSION = new Version(1, 2, 0);
|
||||
public static final Configuration DEFAULT = new Configuration(VERSION.toString(),
|
||||
DefaultDataSources.SQL_EMPTY,
|
||||
DefaultDataSources.REDIS_EMPTY,
|
||||
false);
|
||||
|
||||
private final transient Version versionObject;
|
||||
|
||||
@JsonProperty("version")
|
||||
private final String version;
|
||||
@JsonProperty("sql")
|
||||
private final SQLDataSourceConfiguration sqlConfiguration;
|
||||
@JsonProperty("redis")
|
||||
private final DataSourceConfiguration redisConfiguration;
|
||||
@JsonProperty("customLocale")
|
||||
private final Boolean customLocale;
|
||||
|
||||
public Configuration(@JsonProperty("version") String version,
|
||||
@JsonProperty("sql") SQLDataSourceConfiguration sqlConfiguration,
|
||||
@JsonProperty("redis") DataSourceConfiguration redisConfiguration,
|
||||
@JsonProperty("customLocale") Boolean customLocale) {
|
||||
this.version = version;
|
||||
this.versionObject = Version.fromString(version);
|
||||
this.sqlConfiguration = sqlConfiguration;
|
||||
this.redisConfiguration = redisConfiguration;
|
||||
this.customLocale = customLocale;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public Version getVersionObject() {
|
||||
return versionObject;
|
||||
}
|
||||
|
||||
public SQLDataSourceConfiguration getSqlConfiguration() {
|
||||
return sqlConfiguration;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration getRedisConfiguration() {
|
||||
return redisConfiguration;
|
||||
}
|
||||
|
||||
public Boolean isCustomLocale() {
|
||||
return customLocale;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package xyz.ineanto.nicko.config;
|
||||
|
||||
public class DataSourceConfiguration {
|
||||
private final boolean enabled;
|
||||
private final String address;
|
||||
private final Integer port;
|
||||
private final String username;
|
||||
private final String password;
|
||||
|
||||
public DataSourceConfiguration(boolean enabled, String address, Integer port, String username, String password) {
|
||||
this.enabled = enabled;
|
||||
this.address = address;
|
||||
this.port = port;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public DataSourceConfiguration() { this(false, "", 0, "", ""); }
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DataSourceConfiguration{" +
|
||||
"enabled=" + enabled +
|
||||
", address='" + address + '\'' +
|
||||
", port=" + port +
|
||||
", username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package xyz.ineanto.nicko.config;
|
||||
|
||||
public class DefaultDataSources {
|
||||
public static final DataSourceConfiguration REDIS_EMPTY = new DataSourceConfiguration(false, "127.0.0.1", 6379, "", "");
|
||||
public static final SQLDataSourceConfiguration MARIADB_EMPTY = new SQLDataSourceConfiguration(false, "127.0.0.1", 3306, "root", "", true);
|
||||
public static final SQLDataSourceConfiguration SQL_EMPTY = new SQLDataSourceConfiguration(false, "127.0.0.1", 3306, "root", "", false);
|
||||
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package xyz.ineanto.nicko.config;
|
||||
|
||||
public class SQLDataSourceConfiguration extends DataSourceConfiguration {
|
||||
private final boolean mariadb;
|
||||
|
||||
public SQLDataSourceConfiguration() { this(false, "", 0, "", "", true); }
|
||||
|
||||
public SQLDataSourceConfiguration(boolean enabled, String address, Integer port, String username, String password, boolean mariadb) {
|
||||
super(enabled, address, port, username, password);
|
||||
this.mariadb = mariadb;
|
||||
}
|
||||
|
||||
public boolean isMariadb() {
|
||||
return mariadb;
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package xyz.ineanto.nicko.event;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.appearance.AppearanceManager;
|
||||
import xyz.ineanto.nicko.gui.PlayerCheckGUI;
|
||||
import xyz.ineanto.nicko.gui.PlayerCheckGUIData;
|
||||
import xyz.ineanto.nicko.language.LanguageKey;
|
||||
import xyz.ineanto.nicko.language.PlayerLanguage;
|
||||
import xyz.ineanto.nicko.profile.NickoProfile;
|
||||
import xyz.ineanto.nicko.storage.PlayerDataStore;
|
||||
import xyz.ineanto.nicko.storage.name.PlayerNameStore;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
import xyz.xenondevs.invui.window.WindowManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public class PlayerJoinListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final Nicko instance = Nicko.getInstance();
|
||||
final PlayerLanguage playerLanguage = new PlayerLanguage(player);
|
||||
final PlayerNameStore nameStore = instance.getNameStore();
|
||||
final PlayerDataStore dataStore = instance.getDataStore();
|
||||
nameStore.storeName(player);
|
||||
|
||||
final Optional<NickoProfile> optionalProfile = dataStore.getData(player.getUniqueId());
|
||||
optionalProfile.ifPresentOrElse(profile -> {
|
||||
// Random Skin on connection feature
|
||||
if (profile.isRandomSkin()) {
|
||||
final String name = instance.getNameFetcher().getRandomUsername();
|
||||
final String skin = instance.getNameFetcher().getRandomUsername();
|
||||
profile.setName(name);
|
||||
profile.setSkin(skin);
|
||||
dataStore.updateCache(player.getUniqueId(), profile);
|
||||
}
|
||||
|
||||
if (profile.hasData()) {
|
||||
final AppearanceManager appearanceManager = new AppearanceManager(player);
|
||||
final boolean needsASkinChange = profile.getSkin() != null && !profile.getSkin().equals(player.getName());
|
||||
final ActionResult actionResult = appearanceManager.update(needsASkinChange);
|
||||
if (!actionResult.isError()) {
|
||||
player.sendMessage(playerLanguage.translateWithWhoosh(LanguageKey.Event.Appearance.Restore.OK));
|
||||
} else {
|
||||
player.sendMessage(
|
||||
playerLanguage.translateWithOops(LanguageKey.Event.Appearance.Restore.ERROR,
|
||||
playerLanguage.translate(actionResult.getErrorKey(), false)
|
||||
));
|
||||
}
|
||||
}
|
||||
}, () -> instance.getLogger().warning("Failed to load data for " + player.getName()));
|
||||
|
||||
@SuppressWarnings("unchecked") final ArrayList<UUID> viewers = (ArrayList<UUID>) PlayerCheckGUIData.VIEWERS.clone();
|
||||
viewers.forEach(uuid -> {
|
||||
final Player windowWatcher = Bukkit.getPlayer(uuid);
|
||||
final Window openWindow = WindowManager.getInstance().getOpenWindow(windowWatcher);
|
||||
if (openWindow != null) {
|
||||
final PlayerCheckGUI gui = new PlayerCheckGUI(windowWatcher, Bukkit.getOnlinePlayers());
|
||||
openWindow.close();
|
||||
gui.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
package xyz.ineanto.nicko.event;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import xyz.ineanto.nicko.Nicko;
|
||||
import xyz.ineanto.nicko.appearance.ActionResult;
|
||||
import xyz.ineanto.nicko.gui.PlayerCheckGUI;
|
||||
import xyz.ineanto.nicko.gui.PlayerCheckGUIData;
|
||||
import xyz.xenondevs.invui.window.Window;
|
||||
import xyz.xenondevs.invui.window.WindowManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class PlayerQuitListener implements Listener {
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
final Player player = event.getPlayer();
|
||||
final ActionResult result = Nicko.getInstance().getDataStore().saveData(player);
|
||||
if (result.isError()) {
|
||||
Nicko.getInstance().getLogger().warning("Failed to save data for " + player.getName());
|
||||
}
|
||||
|
||||
// This is a dirty way to do it but could be worse tbh
|
||||
@SuppressWarnings("unchecked") final ArrayList<UUID> viewers = (ArrayList<UUID>) PlayerCheckGUIData.VIEWERS.clone();
|
||||
viewers.forEach(uuid -> {
|
||||
final Player windowWatcher = Bukkit.getPlayer(uuid);
|
||||
final Window openWindow = WindowManager.getInstance().getOpenWindow(windowWatcher);
|
||||
if (openWindow != null) {
|
||||
final List<? extends Player> playersWithoutOffline = Bukkit.getOnlinePlayers()
|
||||
.stream()
|
||||
.filter(online -> online.getUniqueId() != player.getUniqueId()).collect(Collectors.toList());
|
||||
final PlayerCheckGUI gui = new PlayerCheckGUI(windowWatcher, playersWithoutOffline);
|
||||
openWindow.close();
|
||||
gui.open();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
package xyz.ineanto.nicko.event.custom;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlayerDisguiseEvent extends Event implements Cancellable {
|
||||
private static final HandlerList HANDLERS_LIST = new HandlerList();
|
||||
private boolean isCancelled;
|
||||
private final Player player;
|
||||
private final String skin, name;
|
||||
|
||||
public PlayerDisguiseEvent(Player player, String skin, String name) {
|
||||
this.player = player;
|
||||
this.skin = skin;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean isCancelled) {
|
||||
this.isCancelled = isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS_LIST;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public String getSkin() {
|
||||
return skin;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package xyz.ineanto.nicko.event.custom;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class PlayerResetDisguiseEvent extends Event implements Cancellable {
|
||||
private static final HandlerList HANDLERS_LIST = new HandlerList();
|
||||
private boolean isCancelled;
|
||||
private final Player player;
|
||||
|
||||
public PlayerResetDisguiseEvent(Player player) {
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCancelled(boolean isCancelled) {
|
||||
this.isCancelled = isCancelled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull HandlerList getHandlers() {
|
||||
return HANDLERS_LIST;
|
||||
}
|
||||
|
||||
public Player getPlayer() {
|
||||
return player;
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue