forked from ChomeNS/chomens-bot-java
Compare commits
79 commits
Author | SHA1 | Date | |
---|---|---|---|
bb0bc090df | |||
36a138becc | |||
651db6c8ce | |||
ed4c171f11 | |||
65bae4ce7d | |||
dc023758f2 | |||
f7187e560f | |||
60a1d069c7 | |||
06522fadcc | |||
392120f28b | |||
975199bf4f | |||
d8c8a9750d | |||
832d6ee5fa | |||
a45477ed1b | |||
efd837db36 | |||
e4970cc56b | |||
d3845f7c8a | |||
6c507219f2 | |||
9f10ca8a3e | |||
b424f29972 | |||
71d9caa0db | |||
a942cfd557 | |||
2a6ef53c25 | |||
65aa230260 | |||
9b824e195a | |||
a44cae4d3e | |||
e51bd0b1e5 | |||
832a391ad0 | |||
ed15e9b023 | |||
a9fb768795 | |||
c738a37948 | |||
373736feed | |||
c0909d54aa | |||
159cb8ce11 | |||
627b18ebf9 | |||
66dc3b97ec | |||
f322e2dd14 | |||
5e9a1f0917 | |||
4ba78b843b | |||
357559ae6e | |||
7363252660 | |||
4b2b1e9e1a | |||
28012c1194 | |||
7b78ce7d06 | |||
11f478487d | |||
4f8d5bfff5 | |||
3811790c93 | |||
597a694727 | |||
f561a9c810 | |||
4b16f12623 | |||
783a7a937e | |||
cb86896223 | |||
e62de655ba | |||
0ddf042311 | |||
4764a8947e | |||
b3615770dc | |||
3ad8b11494 | |||
b118d50249 | |||
9e22cdfea5 | |||
c655b5d0cd | |||
71ef35598c | |||
c707309958 | |||
bf52424792 | |||
b1dc8dfc7c | |||
0d73ddd791 | |||
3740a9b45f | |||
2de709c127 | |||
feed688a89 | |||
8e188d9ec7 | |||
43d12f2471 | |||
bff3c2f58d | |||
4142875c06 | |||
32c3801acf | |||
9b214c7111 | |||
743072d8e3 | |||
a4f7b0e6a8 | |||
d0f0911f8c | |||
ef5ec8dc27 | |||
a948ef84e2 |
93 changed files with 2376 additions and 7552 deletions
62
.gitignore
vendored
62
.gitignore
vendored
|
@ -1,55 +1,17 @@
|
|||
.gradle
|
||||
**/build/
|
||||
!src/**/build/
|
||||
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
|
||||
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||
|
||||
# User-specific stuff
|
||||
.idea/**/workspace.xml
|
||||
.idea/**/tasks.xml
|
||||
.idea/**/dictionaries
|
||||
.idea/**/shelf
|
||||
|
||||
# Sensitive or high-churn files
|
||||
.idea/**/dataSources/
|
||||
.idea/**/dataSources.ids
|
||||
.idea/**/dataSources.local.xml
|
||||
.idea/**/sqlDataSources.xml
|
||||
.idea/**/dynamic.xml
|
||||
.idea/**/uiDesigner.xml
|
||||
|
||||
# Gradle
|
||||
.idea/**/gradle.xml
|
||||
.idea/**/libraries
|
||||
.gradle
|
||||
build/
|
||||
run/
|
||||
|
||||
.idea/misc.xml
|
||||
# IntelliJ IDEA
|
||||
.idea/
|
||||
*.iml
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
gradle
|
||||
|
||||
# Ignore Gradle GUI config
|
||||
gradle-app.setting
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
# Avoid ignore Gradle wrappper properties
|
||||
!gradle-wrapper.properties
|
||||
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
# Eclipse Gradle plugin generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
# JDT-specific (Eclipse Java Development Tools)
|
||||
.classpath
|
||||
|
||||
# Exploits plugin
|
||||
/src/main/java/land/chipmunk/chayapak/chomens_bot/plugins/ExploitsPlugin.java
|
||||
# Exploits stuff
|
||||
src/main/java/me/chayapak1/chomens_bot/plugins/ExploitsPlugin.java
|
||||
src/main/java/me/chayapak1/chomens_bot/data/exploitMethods/
|
||||
|
||||
# Testing plugins
|
||||
/src/main/java/land/chipmunk/chayapak/chomens_bot/plugins/testing
|
||||
/.idea/modules/
|
||||
/.idea/modules.xml
|
||||
src/main/java/me/chayapak1/chomens_bot/plugins/testing
|
||||
|
|
3
.idea/.gitignore
vendored
3
.idea/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/.idea/workspace.xml
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,12 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module version="4">
|
||||
<component name="FacetManager">
|
||||
<facet type="minecraft" name="Minecraft">
|
||||
<configuration>
|
||||
<autoDetectTypes>
|
||||
<platformType>ADVENTURE</platformType>
|
||||
</autoDetectTypes>
|
||||
</configuration>
|
||||
</facet>
|
||||
</component>
|
||||
</module>
|
|
@ -1,9 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
</annotationProcessing>
|
||||
<bytecodeTargetLevel target="17" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="DiscordProjectSettings">
|
||||
<option name="show" value="PROJECT_FILES" />
|
||||
<option name="description" value="" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
|
@ -1,65 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="minecraft-libraries" />
|
||||
<option name="name" value="Minecraft Libraries" />
|
||||
<option name="url" value="https://libraries.minecraft.net" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="dv8tion" />
|
||||
<option name="name" value="m2-dv8tion" />
|
||||
<option name="url" value="https://m2.dv8tion.net/releases" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven3" />
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven4" />
|
||||
<option name="name" value="maven4" />
|
||||
<option name="url" value="https://maven.maxhenkel.de/repository/public" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="opencollab" />
|
||||
<option name="name" value="opencollab" />
|
||||
<option name="url" value="https://repo.opencollab.dev/maven-snapshots/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenLocal" />
|
||||
<option name="name" value="MavenLocal" />
|
||||
<option name="url" value="file:$MAVEN_REPOSITORY$/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="opencollab" />
|
||||
<option name="name" value="opencollab" />
|
||||
<option name="url" value="https://repo.opencollab.dev/maven-releases/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://repo.opencollab.dev/main/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
|
@ -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>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
25
README.md
25
README.md
|
@ -1,27 +1,10 @@
|
|||
# ChomeNS Bot Java
|
||||
A Java verison of ChomeNS Bot.
|
||||
A Java version of ChomeNS Bot.
|
||||
|
||||
# Compiling
|
||||
You will see that the exploits plugin is missing because I gitignored it to prevent exploit leaks
|
||||
|
||||
To make this successfully compile just make `ExploitsPlugin.java` in the plugins folder and add this code:
|
||||
To make this successfully compile, you will have to fix the missing `ExploitsPlugin.java` in the `plugins` package, and also some enums related to it.
|
||||
|
||||
```java
|
||||
package me.chayapak1.chomens_bot.plugins;
|
||||
After that, you can now run `./gradlew build` to actually get the `.jar` file.
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ExploitsPlugin {
|
||||
public ExploitsPlugin (Bot bot) {}
|
||||
|
||||
public void kick (UUID uuid) {}
|
||||
|
||||
public void pcrash (UUID uuid) {}
|
||||
}
|
||||
```
|
||||
|
||||
Then at the root of the project run `./gradlew shadowJar` for Linux or `gradlew.bat shadowJar` for Windows
|
||||
|
||||
The .jar file will be at `build/libs`, to run the bot do `java -jar chomens_bot-rolling-all.jar`
|
||||
The .jar file will be at `build/libs`, to run the bot simply do `java -jar chomens_bot-rolling-all.jar`
|
||||
|
|
1
build-number.txt
Normal file
1
build-number.txt
Normal file
|
@ -0,0 +1 @@
|
|||
1137
|
58
build.gradle
58
build.gradle
|
@ -1,11 +1,8 @@
|
|||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
import java.text.SimpleDateFormat
|
||||
|
||||
plugins {
|
||||
id 'java'
|
||||
id 'java-library'
|
||||
id 'maven-publish'
|
||||
id 'application'
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1'
|
||||
}
|
||||
|
||||
|
@ -16,7 +13,6 @@ java.sourceCompatibility = JavaVersion.VERSION_17
|
|||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
|
@ -56,7 +52,6 @@ dependencies {
|
|||
implementation 'org.yaml:snakeyaml:2.0'
|
||||
implementation 'org.luaj:luaj-jse:3.0.1'
|
||||
implementation 'net.dv8tion:JDA:5.0.0-beta.12'
|
||||
implementation 'joda-time:joda-time:2.12.4'
|
||||
implementation 'net.kyori:adventure-text-serializer-legacy:4.15.0'
|
||||
implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.20.0'
|
||||
implementation 'io.socket:socket.io-client:2.1.0'
|
||||
|
@ -64,12 +59,55 @@ dependencies {
|
|||
implementation 'org.concentus:Concentus:1.0-SNAPSHOT'
|
||||
}
|
||||
|
||||
jar {
|
||||
manifest {
|
||||
attributes 'Main-Class': 'me.chayapak1.chomens_bot.Main'
|
||||
static def getGitCommitHash() {
|
||||
try {
|
||||
return 'git rev-parse --short HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
static def getGitCommitCount() {
|
||||
try {
|
||||
return 'git rev-list --count HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace()
|
||||
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
def buildNumberFile = file("build-number.txt")
|
||||
def buildNumber = 0
|
||||
|
||||
if (buildNumberFile.exists()) {
|
||||
buildNumber = buildNumberFile.text.trim().toInteger() + 1
|
||||
} else {
|
||||
buildNumber = 1
|
||||
}
|
||||
|
||||
buildNumberFile.text = buildNumber
|
||||
|
||||
ext.buildInfo = [
|
||||
gitCommitCount: getGitCommitCount(),
|
||||
compileDate: new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z").format(new Date()),
|
||||
gitCommitHash: getGitCommitHash(),
|
||||
buildNumber: buildNumber,
|
||||
]
|
||||
|
||||
processResources {
|
||||
inputs.property("buildInfo", buildInfo)
|
||||
filesMatching("application.properties") {
|
||||
expand(buildInfo)
|
||||
}
|
||||
}
|
||||
|
||||
application {
|
||||
mainClass = 'me.chayapak1.chomens_bot.Main'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
options.encoding = 'UTF-8'
|
||||
}
|
||||
|
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
7
gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
5
gradlew
vendored
5
gradlew
vendored
|
@ -15,6 +15,8 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
|
@ -84,7 +86,8 @@ done
|
|||
# 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 "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
|
186
gradlew.bat
vendored
186
gradlew.bat
vendored
|
@ -1,92 +1,94 @@
|
|||
@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
|
||||
|
||||
@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
|
||||
@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
|
||||
|
|
|
@ -1,5 +1 @@
|
|||
/*
|
||||
* This file was generated by the Gradle 'init' task.
|
||||
*/
|
||||
|
||||
rootProject.name = 'chomens_bot'
|
||||
|
|
|
@ -41,7 +41,10 @@ public class Bot {
|
|||
|
||||
public Session session;
|
||||
|
||||
public boolean printDisconnectedCause = false;
|
||||
|
||||
public boolean loggedIn = false;
|
||||
public long loginTime;
|
||||
|
||||
public final ExecutorService executorService = Main.executorService;
|
||||
public final ScheduledExecutorService executor = Main.executor;
|
||||
|
@ -96,16 +99,9 @@ public class Bot {
|
|||
this.bots = bots;
|
||||
|
||||
this.config = config;
|
||||
|
||||
ConsolePlugin.addListener(new ConsolePlugin.Listener() {
|
||||
@Override
|
||||
public void ready() {
|
||||
Bot.this.ready();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void ready () {
|
||||
public void connect () {
|
||||
this.tick = new TickPlugin(this);
|
||||
this.chat = new ChatPlugin(this);
|
||||
this.commandSpy = new CommandSpyPlugin(this);
|
||||
|
@ -177,8 +173,10 @@ public class Bot {
|
|||
}
|
||||
|
||||
if (packet instanceof ClientboundLoginPacket) {
|
||||
loggedIn = true;
|
||||
loginTime = System.currentTimeMillis();
|
||||
|
||||
for (SessionListener listener : listeners) {
|
||||
loggedIn = true;
|
||||
listener.connected(new ConnectedEvent(session));
|
||||
}
|
||||
|
||||
|
@ -251,6 +249,8 @@ public class Bot {
|
|||
|
||||
final Throwable cause = disconnectedEvent.getCause();
|
||||
|
||||
if (printDisconnectedCause && cause != null) cause.printStackTrace();
|
||||
|
||||
// lazy fix #69420
|
||||
if (cause instanceof OutOfMemoryError) System.exit(1);
|
||||
|
||||
|
|
|
@ -12,9 +12,6 @@ public class Configuration {
|
|||
public String consoleCommandPrefix;
|
||||
|
||||
public Keys keys = new Keys();
|
||||
|
||||
public InternetCheck internetCheck = new InternetCheck();
|
||||
|
||||
public Backup backup = new Backup();
|
||||
|
||||
public String weatherApiKey;
|
||||
|
@ -52,18 +49,16 @@ public class Configuration {
|
|||
public int timeout = 6000;
|
||||
}
|
||||
|
||||
public static class InternetCheck {
|
||||
public boolean enabled = true;
|
||||
public String address = "https://sus.red";
|
||||
}
|
||||
|
||||
public static class Backup {
|
||||
public boolean enabled = false;
|
||||
public String address = "http://fard.sex/check";
|
||||
public int interval = 1000;
|
||||
public int failTimes = 2;
|
||||
}
|
||||
|
||||
public static class Keys {
|
||||
public String normalKey;
|
||||
public String trustedKey;
|
||||
public String adminKey;
|
||||
public String ownerKey;
|
||||
}
|
||||
|
||||
|
@ -92,19 +87,20 @@ public class Configuration {
|
|||
}
|
||||
|
||||
public static class Discord {
|
||||
public boolean enabled = true;
|
||||
public boolean enabled = false;
|
||||
public String prefix = "default!";
|
||||
public String token;
|
||||
public Map<String, String> servers = new HashMap<>();
|
||||
public EmbedColors embedColors = new EmbedColors();
|
||||
public String trustedRoleName = "Trusted";
|
||||
public String adminRoleName = "Admin";
|
||||
public String ownerRoleName = "Owner";
|
||||
public String statusMessage = "Oh hi!";
|
||||
public String inviteLink = "https://discord.gg/xdgCkUyaA4";
|
||||
}
|
||||
|
||||
public static class IRC {
|
||||
public boolean enabled = true;
|
||||
public boolean enabled = false;
|
||||
public String prefix = "!";
|
||||
public String host;
|
||||
public int port;
|
||||
|
@ -169,6 +165,7 @@ public class Configuration {
|
|||
public boolean creayun = false;
|
||||
public String serverName;
|
||||
public boolean useCore = true;
|
||||
public boolean useCorePlaceBlock = false;
|
||||
public boolean useChat = false;
|
||||
public boolean coreCommandSpy = false;
|
||||
public boolean resolveSRV = true;
|
||||
|
|
|
@ -2,26 +2,21 @@ package me.chayapak1.chomens_bot;
|
|||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import me.chayapak1.chomens_bot.plugins.ConsolePlugin;
|
||||
import me.chayapak1.chomens_bot.util.HttpUtilities;
|
||||
import me.chayapak1.chomens_bot.util.LoggerUtilities;
|
||||
import me.chayapak1.chomens_bot.util.PersistentDataUtilities;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
import net.dv8tion.jda.api.entities.Activity;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import me.chayapak1.chomens_bot.plugins.DiscordPlugin;
|
||||
import me.chayapak1.chomens_bot.plugins.IRCPlugin;
|
||||
import me.chayapak1.chomens_bot.plugins.LoggerPlugin;
|
||||
import me.chayapak1.chomens_bot.util.*;
|
||||
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.Constructor;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
|
@ -43,9 +38,11 @@ public class Main {
|
|||
|
||||
private static boolean alreadyStarted = false;
|
||||
|
||||
private static final List<Thread> alreadyAddedThreads = new ArrayList<>();
|
||||
private static boolean stopping = false;
|
||||
|
||||
private static JDA jda = null;
|
||||
private static int backupFailTimes = 0;
|
||||
|
||||
private static DiscordPlugin discord;
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
final Path configPath = Path.of("config.yml");
|
||||
|
@ -72,7 +69,9 @@ public class Main {
|
|||
configWriter.write(defaultConfig);
|
||||
configWriter.close();
|
||||
|
||||
LoggerUtilities.info("config.yml file not found, so the default one was created");
|
||||
LoggerUtilities.info("config.yml file was not found, so the default one was created. Please modify it to your needs.");
|
||||
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
InputStream opt = Files.newInputStream(configPath);
|
||||
|
@ -80,82 +79,61 @@ public class Main {
|
|||
|
||||
config = yaml.load(reader);
|
||||
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
checkInternet();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 0, 1, TimeUnit.MINUTES);
|
||||
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
final Set<Thread> threads = Thread.getAllStackTraces().keySet();
|
||||
|
||||
for (Thread thread : threads) {
|
||||
final Thread.UncaughtExceptionHandler oldHandler = thread.getUncaughtExceptionHandler();
|
||||
|
||||
thread.setUncaughtExceptionHandler((_thread, throwable) -> {
|
||||
if (!alreadyAddedThreads.contains(thread) && throwable instanceof OutOfMemoryError) System.exit(1);
|
||||
|
||||
alreadyAddedThreads.add(thread);
|
||||
|
||||
oldHandler.uncaughtException(_thread, throwable);
|
||||
});
|
||||
}
|
||||
}, 0, 30, TimeUnit.SECONDS);
|
||||
|
||||
if (!config.backup.enabled) {
|
||||
initializeBots();
|
||||
return;
|
||||
} else {
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
boolean reachable;
|
||||
|
||||
try {
|
||||
HttpUtilities.getRequest(new URL(config.backup.address));
|
||||
|
||||
reachable = true;
|
||||
} catch (Exception e) {
|
||||
reachable = false;
|
||||
}
|
||||
|
||||
if (!reachable && !alreadyStarted) {
|
||||
backupFailTimes++;
|
||||
|
||||
if (backupFailTimes > config.backup.failTimes) {
|
||||
LoggerUtilities.info("Main instance is down! Starting backup instance");
|
||||
|
||||
initializeBots();
|
||||
}
|
||||
} else if (reachable && alreadyStarted) {
|
||||
LoggerUtilities.info("Main instance is back up! Now stopping");
|
||||
|
||||
// no need to reset backupFailTimes because we are stopping anyway
|
||||
|
||||
stop();
|
||||
}
|
||||
}, 0, config.backup.interval, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
executor.scheduleAtFixedRate(() -> {
|
||||
boolean reachable;
|
||||
|
||||
try {
|
||||
HttpUtilities.getRequest(new URL(config.backup.address));
|
||||
|
||||
reachable = true;
|
||||
} catch (Exception e) {
|
||||
reachable = false;
|
||||
}
|
||||
|
||||
if (!reachable && !alreadyStarted) {
|
||||
LoggerUtilities.info("Main instance is down! Starting backup instance");
|
||||
|
||||
initializeBots();
|
||||
} else if (reachable && alreadyStarted) {
|
||||
System.exit(1);
|
||||
}
|
||||
}, 0, 1, TimeUnit.MINUTES);
|
||||
}
|
||||
|
||||
public static void initializeBots() {
|
||||
alreadyStarted = true;
|
||||
|
||||
try {
|
||||
Configuration.BotOption[] botsOptions = config.bots;
|
||||
|
||||
// idk if these should be here lol, but it is just the discord stuff
|
||||
if (config.discord.enabled) {
|
||||
JDABuilder builder = JDABuilder.createDefault(config.discord.token);
|
||||
builder.enableIntents(GatewayIntent.MESSAGE_CONTENT);
|
||||
try {
|
||||
jda = builder.build();
|
||||
jda.awaitReady();
|
||||
} catch (InterruptedException ignored) {
|
||||
System.exit(1);
|
||||
}
|
||||
jda.getPresence().setPresence(Activity.playing(config.discord.statusMessage), false);
|
||||
}
|
||||
final Configuration.BotOption[] botsOptions = config.bots;
|
||||
|
||||
for (Configuration.BotOption botOption : botsOptions) {
|
||||
final Bot bot = new Bot(botOption, bots, config);
|
||||
bots.add(bot);
|
||||
}
|
||||
|
||||
// fard
|
||||
new ConsolePlugin(bots, config, jda);
|
||||
// initialize util classes and plugins
|
||||
PersistentDataUtilities.init();
|
||||
|
||||
new ConsolePlugin();
|
||||
LoggerPlugin.init();
|
||||
if (config.discord.enabled) discord = new DiscordPlugin(config);
|
||||
if (config.irc.enabled) new IRCPlugin(config);
|
||||
|
||||
LoggerUtilities.info("Initialized all bots. Now connecting");
|
||||
|
||||
for (Bot bot : bots) bot.connect();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
|
@ -163,30 +141,12 @@ public class Main {
|
|||
}
|
||||
}
|
||||
|
||||
private static void checkInternet () throws IOException {
|
||||
if (!config.internetCheck.enabled) return;
|
||||
|
||||
boolean reachable = false;
|
||||
|
||||
try {
|
||||
final URL url = new URL(config.internetCheck.address);
|
||||
|
||||
final URLConnection connection = url.openConnection();
|
||||
|
||||
connection.connect();
|
||||
|
||||
reachable = true;
|
||||
} catch (UnknownHostException ignored) {}
|
||||
|
||||
if (!reachable) {
|
||||
LoggerUtilities.error("No internet, exiting");
|
||||
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// most of these are stolen from HBot
|
||||
public static void stop () {
|
||||
if (stopping) return;
|
||||
|
||||
stopping = true;
|
||||
|
||||
executor.shutdown();
|
||||
|
||||
PersistentDataUtilities.stop();
|
||||
|
@ -194,11 +154,9 @@ public class Main {
|
|||
executorService.shutdown();
|
||||
|
||||
try {
|
||||
final boolean executorDone = executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
final boolean executorServiceDone = executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
final boolean ignoredExecutorDone = executor.awaitTermination(5, TimeUnit.SECONDS);
|
||||
final boolean ignoredExecutorServiceDone = executorService.awaitTermination(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException ignored) {}
|
||||
|
||||
ArrayList<Bot> copiedList;
|
||||
synchronized (bots) {
|
||||
|
@ -208,46 +166,42 @@ public class Main {
|
|||
final boolean ircEnabled = config.irc.enabled;
|
||||
final boolean discordEnabled = config.discord.enabled;
|
||||
|
||||
final boolean[] stoppedDiscord = new boolean[copiedList.size()];
|
||||
|
||||
int botIndex = 0;
|
||||
for (Bot bot : copiedList) {
|
||||
if (discordEnabled) {
|
||||
final String channelId = bot.discord.servers.get(bot.host + ":" + bot.port);
|
||||
try {
|
||||
if (discordEnabled) {
|
||||
final String channelId = bot.discord.servers.get(bot.host + ":" + bot.port);
|
||||
|
||||
bot.discord.sendMessageInstantly("Stopping..", channelId);
|
||||
}
|
||||
final MessageCreateAction messageAction = bot.discord.sendMessageInstantly("Stopping..", channelId, false);
|
||||
|
||||
if (ircEnabled) {
|
||||
bot.irc.quit("Stopping..");
|
||||
}
|
||||
final int finalBotIndex = botIndex;
|
||||
messageAction.queue(
|
||||
(message) -> stoppedDiscord[finalBotIndex] = true,
|
||||
(error) -> stoppedDiscord[finalBotIndex] = true // should i also set this to true on fail?
|
||||
);
|
||||
}
|
||||
|
||||
bot.stop();
|
||||
if (ircEnabled) bot.irc.quit("Stopping..");
|
||||
|
||||
bot.stop();
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
botIndex++;
|
||||
}
|
||||
|
||||
if (jda != null) jda.shutdown();
|
||||
|
||||
if (discordEnabled) {
|
||||
discord.jda.shutdown();
|
||||
|
||||
for (int i = 0; i < 150; i++) {
|
||||
boolean stoppedDiscord = true;
|
||||
|
||||
for (Bot bot : bots) {
|
||||
if (!bot.discord.shuttedDown) {
|
||||
stoppedDiscord = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!stoppedDiscord) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
try {
|
||||
if (!ArrayUtilities.isAllTrue(stoppedDiscord)) Thread.sleep(50);
|
||||
else break;
|
||||
} catch (InterruptedException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
System.exit(69); // nice
|
||||
System.exit(0);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package me.chayapak1.chomens_bot.chatParsers;
|
||||
|
||||
import me.chayapak1.chomens_bot.util.UUIDUtilities;
|
||||
import org.geysermc.mcprotocollib.auth.GameProfile;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
|
@ -38,7 +39,7 @@ public class CreayunChatParser implements ChatParser {
|
|||
final String contents = matcher.group(2);
|
||||
|
||||
PlayerEntry sender = bot.players.getEntry(displayName);
|
||||
if (sender == null) sender = new PlayerEntry(new GameProfile(new UUID(0L, 0L), displayName), GameMode.SURVIVAL, 0, Component.text(displayName), 0L, null, new byte[0], true);
|
||||
if (sender == null) sender = new PlayerEntry(new GameProfile(UUIDUtilities.getOfflineUUID(displayName), displayName), GameMode.SURVIVAL, 0, Component.text(displayName), 0L, null, new byte[0], true);
|
||||
|
||||
return new PlayerMessage(sender, Component.text(displayName), Component.text(contents));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package me.chayapak1.chomens_bot.chatParsers;
|
||||
|
||||
import me.chayapak1.chomens_bot.util.ComponentUtilities;
|
||||
import me.chayapak1.chomens_bot.util.UUIDUtilities;
|
||||
import org.geysermc.mcprotocollib.auth.GameProfile;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
|
@ -43,9 +45,12 @@ public class KaboomChatParser implements ChatParser {
|
|||
return null;
|
||||
}
|
||||
|
||||
// final String stringifiedDisplayName = ComponentUtilities.stringify(displayName);
|
||||
|
||||
PlayerEntry sender = bot.players.getEntry(Component.empty().append(prefix).append(displayName));
|
||||
if (sender == null) sender = bot.players.getEntry(prefix.append(displayName)); // old
|
||||
if (sender == null) sender = new PlayerEntry(new GameProfile(new UUID(0L, 0L), null), GameMode.SURVIVAL, 0, displayName, 0L, null, new byte[0], true); // new and currently using
|
||||
// if (sender == null) sender = new PlayerEntry(new GameProfile(UUIDUtilities.getOfflineUUID(stringifiedDisplayName), stringifiedDisplayName), GameMode.SURVIVAL, 0, displayName, 0L, null, new byte[0], true); // new and currently using
|
||||
if (sender == null) return null;
|
||||
|
||||
return new PlayerMessage(sender, displayName, contents);
|
||||
}
|
||||
|
|
|
@ -4,9 +4,9 @@ import net.kyori.adventure.text.Component;
|
|||
|
||||
public abstract class Command {
|
||||
public final String name;
|
||||
public final String description;
|
||||
public final String[] usages;
|
||||
public final String[] aliases;
|
||||
public String description;
|
||||
public String[] usages;
|
||||
public String[] aliases;
|
||||
public final TrustLevel trustLevel;
|
||||
public final boolean consoleOnly;
|
||||
|
||||
|
|
|
@ -3,5 +3,6 @@ package me.chayapak1.chomens_bot.command;
|
|||
public enum TrustLevel {
|
||||
PUBLIC,
|
||||
TRUSTED,
|
||||
ADMIN,
|
||||
OWNER
|
||||
}
|
||||
|
|
|
@ -52,11 +52,12 @@ public class CloopCommand extends Command {
|
|||
|
||||
try {
|
||||
final int index = context.getInteger(true);
|
||||
bot.cloop.remove(index);
|
||||
|
||||
final CommandLoop cloop = bot.cloop.remove(index);
|
||||
|
||||
return Component.translatable(
|
||||
"Removed cloop %s",
|
||||
Component.text(index).color(ColorUtilities.getColorByString(bot.config.colorPalette.number))
|
||||
Component.text(cloop.command()).color(ColorUtilities.getColorByString(bot.config.colorPalette.string))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
} catch (IndexOutOfBoundsException | IllegalArgumentException | NullPointerException ignored) {
|
||||
throw new CommandException(Component.text("Invalid index"));
|
||||
|
@ -96,9 +97,7 @@ public class CloopCommand extends Command {
|
|||
Component.join(JoinConfiguration.newlines(), cloopsComponent)
|
||||
);
|
||||
}
|
||||
default -> {
|
||||
throw new CommandException(Component.text("Invalid action"));
|
||||
}
|
||||
default -> throw new CommandException(Component.text("Invalid action"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public class CommandBlockCommand extends Command {
|
|||
|
||||
if (future == null) return;
|
||||
|
||||
future.thenApply(output -> {
|
||||
future.thenApplyAsync(output -> {
|
||||
context.sendOutput(output);
|
||||
|
||||
return output;
|
||||
|
|
|
@ -19,7 +19,8 @@ public class ConsoleCommand extends Command {
|
|||
"Controls stuff about console",
|
||||
new String[] {
|
||||
"server <server>",
|
||||
"logtoconsole <true|false>"
|
||||
"logtoconsole <true|false>",
|
||||
"printdisconnectedreason <true|false>"
|
||||
},
|
||||
new String[] {},
|
||||
TrustLevel.OWNER,
|
||||
|
@ -47,8 +48,6 @@ public class ConsoleCommand extends Command {
|
|||
if (server.equalsIgnoreCase("all")) {
|
||||
eachBot.console.consoleServer = "all";
|
||||
|
||||
context.sendOutput(Component.text("Set the console server to all servers").color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor)));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -56,9 +55,8 @@ public class ConsoleCommand extends Command {
|
|||
// servers.find(server => server.toLowerCase().includes(args.join(' '))) in js i guess
|
||||
eachBot.console.consoleServer = servers.stream()
|
||||
.filter(eachServer -> eachServer.toLowerCase().contains(server))
|
||||
.toArray(String[]::new)[0];
|
||||
|
||||
context.sendOutput(Component.text("Set the console server to " + bot.console.consoleServer).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor)));
|
||||
.findFirst()
|
||||
.orElse("all");
|
||||
} catch (ArrayIndexOutOfBoundsException e) {
|
||||
throw new CommandException(Component.text("Invalid server: " + server));
|
||||
}
|
||||
|
@ -76,6 +74,18 @@ public class ConsoleCommand extends Command {
|
|||
bool ? Component.text("enabled").color(NamedTextColor.GREEN) : Component.text("disabled").color(NamedTextColor.RED)
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
case "printdisconnectedreason" -> {
|
||||
context.checkOverloadArgs(2);
|
||||
|
||||
final boolean bool = context.getBoolean(true);
|
||||
|
||||
bot.printDisconnectedCause = bool;
|
||||
|
||||
return Component.translatable(
|
||||
"Printing the disconnected cause is now %s",
|
||||
bool ? Component.text("enabled").color(NamedTextColor.GREEN) : Component.text("disabled").color(NamedTextColor.RED)
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -38,7 +38,7 @@ public class EvalCommand extends Command {
|
|||
|
||||
final CompletableFuture<EvalOutput> future = bot.eval.run(command);
|
||||
|
||||
future.thenApply((output) -> {
|
||||
future.thenApplyAsync(output -> {
|
||||
if (output.isError()) context.sendOutput(Component.text(output.output()).color(NamedTextColor.RED));
|
||||
else context.sendOutput(Component.text(output.output()));
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ public class FilterCommand extends Command {
|
|||
"list"
|
||||
},
|
||||
new String[] { "filterplayer", "ban", "blacklist" },
|
||||
TrustLevel.OWNER,
|
||||
TrustLevel.ADMIN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -101,11 +101,25 @@ public class FilterCommand extends Command {
|
|||
for (JsonElement playerElement : FilterPlugin.filteredPlayers) {
|
||||
final FilteredPlayer player = gson.fromJson(playerElement, FilteredPlayer.class);
|
||||
|
||||
Component options = Component.empty().color(NamedTextColor.DARK_GRAY);
|
||||
|
||||
if (player.ignoreCase || player.regex) {
|
||||
final List<Component> args = new ArrayList<>();
|
||||
|
||||
if (player.ignoreCase) args.add(Component.text("ignore case"));
|
||||
if (player.regex) args.add(Component.text("regex"));
|
||||
|
||||
options = options.append(Component.text("("));
|
||||
options = options.append(Component.join(JoinConfiguration.commas(true), args).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)));
|
||||
options = options.append(Component.text(")"));
|
||||
}
|
||||
|
||||
filtersComponents.add(
|
||||
Component.translatable(
|
||||
"%s › %s",
|
||||
"%s › %s %s",
|
||||
Component.text(index).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)),
|
||||
Component.text(player.playerName).color(ColorUtilities.getColorByString(bot.config.colorPalette.username))
|
||||
Component.text(player.playerName).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)),
|
||||
options
|
||||
).color(NamedTextColor.DARK_GRAY)
|
||||
);
|
||||
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
package me.chayapak1.chomens_bot.commands;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.command.Command;
|
||||
import me.chayapak1.chomens_bot.command.CommandContext;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.plugins.PlayersPersistentDataPlugin;
|
||||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class FindAltsCommand extends Command {
|
||||
public FindAltsCommand() {
|
||||
super(
|
||||
"findalts",
|
||||
"Finds players with the same IP address",
|
||||
new String[] { "<player>", "<ip>" },
|
||||
new String[] { "alts", "sameip" },
|
||||
TrustLevel.PUBLIC,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws Exception {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final String player = context.getString(true, true);
|
||||
|
||||
final PlayerEntry playerEntry = bot.players.getEntry(player);
|
||||
|
||||
if (playerEntry == null) return handle(bot, player, true, player);
|
||||
else {
|
||||
final CompletableFuture<String> future = bot.players.getPlayerIP(playerEntry);
|
||||
|
||||
if (future == null) return null;
|
||||
|
||||
future.thenApplyAsync(targetIP -> {
|
||||
context.sendOutput(handle(bot, targetIP, false, player));
|
||||
|
||||
return targetIP;
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Component handle (Bot bot, String targetIP, boolean argumentIsIP, String player) {
|
||||
final Stream<String> matches = PlayersPersistentDataPlugin.playersObject.deepCopy().entrySet() // is calling deepCopy necessary?
|
||||
.stream()
|
||||
.filter(
|
||||
entry -> {
|
||||
final JsonObject ipsObject = entry
|
||||
.getValue().getAsJsonObject().getAsJsonObject("ips");
|
||||
|
||||
if (ipsObject == null) return false;
|
||||
|
||||
final JsonElement currentServerIP = ipsObject.get(bot.host + ":" + bot.port);
|
||||
|
||||
if (currentServerIP == null) return false;
|
||||
|
||||
return currentServerIP.getAsString().equals(targetIP);
|
||||
}
|
||||
)
|
||||
.map(Map.Entry::getKey);
|
||||
|
||||
Component component = Component
|
||||
.translatable("Possible alts for the %s %s:")
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor))
|
||||
.arguments(
|
||||
Component.text(argumentIsIP ? "IP" : "player"),
|
||||
Component.text(player).color(ColorUtilities.getColorByString(bot.config.colorPalette.username))
|
||||
)
|
||||
.appendNewline();
|
||||
|
||||
int i = 0;
|
||||
for (String name : matches.toList()) {
|
||||
component = component
|
||||
.append(
|
||||
Component
|
||||
.text(name)
|
||||
.color((i++ & 1) == 0 ? ColorUtilities.getColorByString(bot.config.colorPalette.primary) : ColorUtilities.getColorByString(bot.config.colorPalette.secondary))
|
||||
)
|
||||
.appendSpace();
|
||||
}
|
||||
|
||||
return component;
|
||||
}
|
||||
}
|
|
@ -50,6 +50,7 @@ public class HelpCommand extends Command {
|
|||
final List<Component> list = new ArrayList<>();
|
||||
list.addAll(getCommandListByTrustLevel(TrustLevel.PUBLIC));
|
||||
list.addAll(getCommandListByTrustLevel(TrustLevel.TRUSTED));
|
||||
list.addAll(getCommandListByTrustLevel(TrustLevel.ADMIN));
|
||||
list.addAll(getCommandListByTrustLevel(TrustLevel.OWNER));
|
||||
|
||||
return Component.empty()
|
||||
|
@ -60,7 +61,8 @@ public class HelpCommand extends Command {
|
|||
.append(Component.text("(").color(NamedTextColor.DARK_GRAY))
|
||||
.append(Component.text("Public ").color(NamedTextColor.GREEN))
|
||||
.append(Component.text("Trusted ").color(NamedTextColor.RED))
|
||||
.append(Component.text("Owner").color(NamedTextColor.DARK_RED))
|
||||
.append(Component.text("Admin ").color(NamedTextColor.DARK_RED))
|
||||
.append(Component.text("Owner").color(NamedTextColor.LIGHT_PURPLE))
|
||||
.append(Component.text(") - ").color(NamedTextColor.DARK_GRAY))
|
||||
.append(Component.join(JoinConfiguration.separator(Component.space()), list));
|
||||
}
|
||||
|
@ -98,7 +100,8 @@ public class HelpCommand extends Command {
|
|||
return switch (trustLevel) {
|
||||
case PUBLIC -> NamedTextColor.GREEN;
|
||||
case TRUSTED -> NamedTextColor.RED;
|
||||
case OWNER -> NamedTextColor.DARK_RED;
|
||||
case ADMIN -> NamedTextColor.DARK_RED;
|
||||
case OWNER -> NamedTextColor.LIGHT_PURPLE;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ public class IPFilterCommand extends Command {
|
|||
"list"
|
||||
},
|
||||
new String[] { "filterip", "banip", "ipban" },
|
||||
TrustLevel.OWNER,
|
||||
TrustLevel.ADMIN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,9 +10,12 @@ import net.kyori.adventure.text.Component;
|
|||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
import net.kyori.adventure.text.format.TextDecoration;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.MemoryUsage;
|
||||
|
@ -21,21 +24,38 @@ import java.net.InetAddress;
|
|||
import java.net.UnknownHostException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Instant;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class InfoCommand extends Command {
|
||||
public static final String ORIGINAL_REPOSITORY_URL = "https://code.chipmunk.land/ChomeNS/chomens-bot-java";
|
||||
|
||||
public static final Properties BUILD_INFO = new Properties();
|
||||
|
||||
static {
|
||||
try (final InputStream input = ClassLoader.getSystemClassLoader().getResourceAsStream("application.properties")) {
|
||||
BUILD_INFO.load(input);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
public InfoCommand () {
|
||||
super(
|
||||
"info",
|
||||
"Shows an info about various things",
|
||||
new String[] {
|
||||
"<creator>",
|
||||
"<discord>",
|
||||
"<server>",
|
||||
"<botuser>",
|
||||
"<uptime>"
|
||||
"",
|
||||
"creator",
|
||||
"discord",
|
||||
"server",
|
||||
"botuser",
|
||||
"botlogintime",
|
||||
"uptime"
|
||||
},
|
||||
new String[] {},
|
||||
TrustLevel.PUBLIC,
|
||||
|
@ -49,7 +69,7 @@ public class InfoCommand extends Command {
|
|||
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final String action = context.getString(false, true, true);
|
||||
final String action = context.getString(false, false, true);
|
||||
|
||||
switch (action) {
|
||||
case "creator" -> {
|
||||
|
@ -179,6 +199,30 @@ public class InfoCommand extends Command {
|
|||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.uuid))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
case "botlogintime" -> {
|
||||
final long loginTime = bot.loginTime;
|
||||
|
||||
final Instant instant = Instant.ofEpochMilli(loginTime);
|
||||
final ZoneId zoneId = ZoneId.of("UTC");
|
||||
final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId);
|
||||
|
||||
final DateTimeFormatter loginTimeFormatter = DateTimeFormatter.ofPattern("MMMM d, yyyy, hh:mm:ss a Z");
|
||||
final String formattedLoginTime = localDateTime.format(loginTimeFormatter);
|
||||
|
||||
final DateFormat timeSinceFormatter = new SimpleDateFormat("HH 'hours' mm 'minutes' ss 'seconds'");
|
||||
timeSinceFormatter.setTimeZone(TimeZone.getTimeZone(zoneId)); // very important
|
||||
final String formattedTimeSince = timeSinceFormatter.format(new Date(System.currentTimeMillis() - loginTime));
|
||||
|
||||
return Component.translatable(
|
||||
"The bots login time is %s and has been on the server for %s",
|
||||
Component
|
||||
.text(formattedLoginTime)
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.string)),
|
||||
Component
|
||||
.text(formattedTimeSince)
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.string))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
case "uptime" -> {
|
||||
final long uptime = ManagementFactory.getRuntimeMXBean().getUptime() / 1000;
|
||||
|
||||
|
@ -199,7 +243,60 @@ public class InfoCommand extends Command {
|
|||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
default -> {
|
||||
throw new CommandException(Component.text("Invalid action"));
|
||||
return Component.empty()
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor))
|
||||
.append(Component.text("ChomeNS Bot").color(NamedTextColor.YELLOW))
|
||||
.append(Component.space())
|
||||
.append(
|
||||
Component
|
||||
.translatable(
|
||||
"is an open-source utility bot and a moderation bot made for " +
|
||||
"the %s Minecraft server (and its clones) " +
|
||||
"but also works on vanilla Minecraft servers. " +
|
||||
"It was originally made for fun but " +
|
||||
"I got addicted and made it a full blown bot."
|
||||
)
|
||||
.arguments(Component.text("Kaboom").style(Style.style().color(NamedTextColor.GRAY).decorate(TextDecoration.BOLD)))
|
||||
)
|
||||
.append(Component.newline())
|
||||
.append(Component.text("Original repository: "))
|
||||
.append(
|
||||
Component
|
||||
.text(ORIGINAL_REPOSITORY_URL)
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.string))
|
||||
.clickEvent(
|
||||
ClickEvent.openUrl(ORIGINAL_REPOSITORY_URL)
|
||||
)
|
||||
)
|
||||
.append(Component.newline())
|
||||
.append(Component.text("Compiled at "))
|
||||
.append(
|
||||
Component
|
||||
.text(BUILD_INFO.getProperty("build.date", "unknown"))
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.string))
|
||||
)
|
||||
.append(
|
||||
Component
|
||||
.translatable(
|
||||
", Git commit %s (%s)",
|
||||
Component
|
||||
.text(BUILD_INFO.getProperty("build.git.commit.hash", "unknown"))
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.string)),
|
||||
Component
|
||||
.text(BUILD_INFO.getProperty("build.git.commit.count", "unknown"))
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.number))
|
||||
)
|
||||
)
|
||||
.append(Component.newline())
|
||||
.append(
|
||||
Component
|
||||
.translatable(
|
||||
"Build %s",
|
||||
Component
|
||||
.text(BUILD_INFO.getProperty("build.number", "unknown"))
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.number))
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,11 @@ import me.chayapak1.chomens_bot.command.CommandContext;
|
|||
import me.chayapak1.chomens_bot.command.CommandException;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.data.exploitMethods.Kick;
|
||||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
public class KickCommand extends Command {
|
||||
|
@ -16,17 +18,23 @@ public class KickCommand extends Command {
|
|||
super(
|
||||
"kick",
|
||||
"Kicks a player",
|
||||
new String[] { "<player>" },
|
||||
new String[] {},
|
||||
new String[] {},
|
||||
TrustLevel.TRUSTED,
|
||||
false
|
||||
);
|
||||
|
||||
final String allMethods = String.join("|", Arrays.stream(Kick.values()).map(Enum::name).toList());
|
||||
|
||||
this.usages = new String[] { "<" + allMethods + "> <player>" };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws CommandException {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final Kick method = context.getEnum(Kick.class);
|
||||
|
||||
final PlayerEntry entry = bot.players.getEntry(context.getString(true, true));
|
||||
|
||||
if (entry == null) throw new CommandException(Component.text("Invalid player name"));
|
||||
|
@ -34,11 +42,16 @@ public class KickCommand extends Command {
|
|||
final String name = entry.profile.getName();
|
||||
final UUID uuid = entry.profile.getId();
|
||||
|
||||
bot.exploits.kick(uuid);
|
||||
bot.exploits.kick(method, uuid);
|
||||
|
||||
return Component.empty()
|
||||
.append(Component.text("Kicking player "))
|
||||
.append(Component.text("Kicking player"))
|
||||
.append(Component.space())
|
||||
.append(Component.text(name).color(ColorUtilities.getColorByString(bot.config.colorPalette.username)))
|
||||
.append(Component.space())
|
||||
.append(Component.text("with method"))
|
||||
.append(Component.space())
|
||||
.append(Component.text(method.name()).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)))
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,14 +16,15 @@ import me.chayapak1.chomens_bot.util.PersistentDataUtilities;
|
|||
import me.chayapak1.chomens_bot.util.UUIDUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TextComponent;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import net.kyori.adventure.text.event.HoverEvent;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
@ -105,7 +106,7 @@ public class MailCommand extends Command {
|
|||
throw new CommandException(Component.text("There was an error while sending your mail"));
|
||||
}
|
||||
|
||||
future.thenApply(output -> {
|
||||
future.thenApplyAsync(output -> {
|
||||
try {
|
||||
final List<Component> children = output.children();
|
||||
|
||||
|
@ -174,8 +175,12 @@ public class MailCommand extends Command {
|
|||
|
||||
if (!mail.sentTo.equals(sender.profile.getName())) continue;
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern("MMMM d, YYYY, hh:mm:ss a Z");
|
||||
final String formattedTime = formatter.print(mail.timeSent);
|
||||
final Instant instant = Instant.ofEpochMilli(mail.timeSent);
|
||||
final ZoneId zoneId = ZoneId.systemDefault();
|
||||
final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId);
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MMMM d, yyyy, hh:mm:ss a Z");
|
||||
final String formattedTime = localDateTime.format(formatter);
|
||||
|
||||
mailsComponent.add(
|
||||
Component.translatable(
|
||||
|
|
|
@ -12,7 +12,6 @@ import me.chayapak1.chomens_bot.song.Loop;
|
|||
import me.chayapak1.chomens_bot.song.Note;
|
||||
import me.chayapak1.chomens_bot.song.Song;
|
||||
import me.chayapak1.chomens_bot.util.*;
|
||||
import me.chayapak1.chomens_bot.util.*;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
|
@ -36,8 +35,6 @@ import static me.chayapak1.chomens_bot.util.StringUtilities.isNotNullAndNotBlank
|
|||
public class MusicCommand extends Command {
|
||||
private Path root;
|
||||
|
||||
private int ratelimit = 0;
|
||||
|
||||
public MusicCommand () {
|
||||
super(
|
||||
"music",
|
||||
|
@ -63,15 +60,11 @@ public class MusicCommand extends Command {
|
|||
TrustLevel.PUBLIC,
|
||||
false
|
||||
);
|
||||
|
||||
Main.executor.scheduleAtFixedRate(() -> ratelimit = 0, 0, 5, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws CommandException {
|
||||
ratelimit++;
|
||||
|
||||
if (ratelimit > 10) return null;
|
||||
if (context.bot.music.locked) throw new CommandException(Component.text("Managing music is currently locked"));
|
||||
|
||||
final String action = context.getString(false, true, true);
|
||||
|
||||
|
@ -213,7 +206,7 @@ public class MusicCommand extends Command {
|
|||
throw new CommandException(Component.text("There was an error while getting your data"));
|
||||
}
|
||||
|
||||
future.thenApply(output -> {
|
||||
future.thenApplyAsync(output -> {
|
||||
final List<Component> children = output.children();
|
||||
|
||||
if (
|
||||
|
@ -264,14 +257,14 @@ public class MusicCommand extends Command {
|
|||
final CompletableFuture<Component> future = bot.core.runTracked(
|
||||
"minecraft:data get entity " +
|
||||
UUIDUtilities.selector(context.sender.profile.getId()) +
|
||||
" SelectedItem.tag.SongItemData.SongData"
|
||||
" SelectedItem.components.minecraft:custom_data.SongItemData.SongData"
|
||||
);
|
||||
|
||||
if (future == null) {
|
||||
throw new CommandException(Component.text("There was an error while getting your data"));
|
||||
}
|
||||
|
||||
future.thenApply(output -> {
|
||||
future.thenApplyAsync(output -> {
|
||||
final List<Component> children = output.children();
|
||||
|
||||
if (
|
||||
|
@ -281,7 +274,7 @@ public class MusicCommand extends Command {
|
|||
.key()
|
||||
.equals("arguments.nbtpath.nothing_found")
|
||||
) {
|
||||
context.sendOutput(Component.text("Player has no SongItemData -> SongData NBT tag in the selected item").color(NamedTextColor.RED));
|
||||
context.sendOutput(Component.text("Player has no SongItemData -> SongData NBT tag in their selected item's minecraft:custom_data").color(NamedTextColor.RED));
|
||||
return output;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
package me.chayapak1.chomens_bot.commands;
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.command.Command;
|
||||
import me.chayapak1.chomens_bot.command.CommandContext;
|
||||
import me.chayapak1.chomens_bot.command.CommandException;
|
||||
import me.chayapak1.chomens_bot.command.TrustLevel;
|
||||
import me.chayapak1.chomens_bot.data.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
||||
public class PCrashCommand extends Command {
|
||||
public PCrashCommand () {
|
||||
super(
|
||||
"pcrash",
|
||||
"Crashes a player using particle",
|
||||
new String[] { "<player>" },
|
||||
new String[] { "particlecrash" },
|
||||
TrustLevel.TRUSTED,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws CommandException {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final PlayerEntry player = bot.players.getEntry(context.getString(true, true));
|
||||
|
||||
if (player == null) throw new CommandException(Component.text("Invalid player name"));
|
||||
|
||||
bot.exploits.pcrash(player.profile.getId());
|
||||
|
||||
return Component.translatable(
|
||||
"Attempting to crash %s",
|
||||
Component.text(player.profile.getName()).color(ColorUtilities.getColorByString(bot.config.colorPalette.secondary))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
}
|
|
@ -10,11 +10,13 @@ import me.chayapak1.chomens_bot.command.TrustLevel;
|
|||
import me.chayapak1.chomens_bot.plugins.PlayersPersistentDataPlugin;
|
||||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SeenCommand extends Command {
|
||||
public SeenCommand () {
|
||||
|
@ -34,30 +36,44 @@ public class SeenCommand extends Command {
|
|||
|
||||
final String player = context.getString(true, true);
|
||||
|
||||
boolean online = false;
|
||||
|
||||
final List<Component> onlineComponents = new ArrayList<>();
|
||||
|
||||
for (Bot eachBot : bot.bots) {
|
||||
if (eachBot.players.getEntry(player) != null) return Component.empty()
|
||||
.append(Component.text(player))
|
||||
.append(Component.text(" is currently online on "))
|
||||
.append(Component.text(eachBot.host + ":" + eachBot.port))
|
||||
.color(NamedTextColor.RED);
|
||||
if (eachBot.players.getEntry(player) != null) {
|
||||
online = true;
|
||||
|
||||
onlineComponents.add(
|
||||
Component.empty()
|
||||
.append(Component.text(player))
|
||||
.append(Component.text(" is currently online on "))
|
||||
.append(Component.text(eachBot.host + ":" + eachBot.port))
|
||||
.color(NamedTextColor.RED)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (online) return Component.join(JoinConfiguration.newlines(), onlineComponents);
|
||||
|
||||
final JsonElement playerElement = PlayersPersistentDataPlugin.playersObject.get(player);
|
||||
if (playerElement == null) return Component.translatable(
|
||||
if (playerElement == null) throw new CommandException(Component.translatable(
|
||||
"%s was never seen",
|
||||
Component.text(player)
|
||||
).color(NamedTextColor.RED);
|
||||
));
|
||||
|
||||
final JsonObject lastSeen = playerElement.getAsJsonObject().get("lastSeen").getAsJsonObject();
|
||||
|
||||
final JsonElement time = lastSeen.get("time");
|
||||
|
||||
if (time == null) throw new CommandException(Component.text("time is null.. (possible invalid entry)"));
|
||||
if (time == null) throw new CommandException(Component.text("This player does not have the `lastSeen.time` entry in the database for some reason."));
|
||||
|
||||
final DateTime dateTime = new DateTime(time.getAsLong(), DateTimeZone.UTC);
|
||||
final Instant instant = Instant.ofEpochMilli(time.getAsLong());
|
||||
final ZoneId zoneId = ZoneId.of("UTC"); // should i be doing this?
|
||||
final OffsetDateTime localDateTime = OffsetDateTime.ofInstant(instant, zoneId);
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern("EEEE, MMMM d, YYYY, hh:mm:ss a z");
|
||||
final String formattedTime = formatter.print(dateTime);
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy, hh:mm:ss a Z");
|
||||
final String formattedTime = localDateTime.format(formatter);
|
||||
|
||||
final String server = lastSeen.get("server").getAsString();
|
||||
|
||||
|
|
|
@ -26,24 +26,28 @@ public class ServerEvalCommand extends Command {
|
|||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws CommandException {
|
||||
try {
|
||||
final Bot bot = context.bot;
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final Globals globals = JsePlatform.standardGlobals();
|
||||
bot.executorService.submit(() -> {
|
||||
try {
|
||||
final Globals globals = JsePlatform.standardGlobals();
|
||||
|
||||
globals.set("bot", CoerceJavaToLua.coerce(bot));
|
||||
globals.set("class", CoerceJavaToLua.coerce(Class.class));
|
||||
globals.set("context", CoerceJavaToLua.coerce(context));
|
||||
globals.set("bot", CoerceJavaToLua.coerce(bot));
|
||||
globals.set("class", CoerceJavaToLua.coerce(Class.class));
|
||||
globals.set("context", CoerceJavaToLua.coerce(context));
|
||||
|
||||
LuaValue chunk = globals.load(context.getString(true, true));
|
||||
LuaValue chunk = globals.load(context.getString(true, true));
|
||||
|
||||
final LuaValue output = chunk.call();
|
||||
final LuaValue output = chunk.call();
|
||||
|
||||
return Component.text(output.toString()).color(NamedTextColor.GREEN);
|
||||
} catch (CommandException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new CommandException(Component.text(e.toString()));
|
||||
}
|
||||
context.sendOutput(Component.text(output.toString()).color(NamedTextColor.GREEN));
|
||||
} catch (CommandException e) {
|
||||
context.sendOutput(e.message.color(NamedTextColor.RED));
|
||||
} catch (Exception e) {
|
||||
context.sendOutput(Component.text(e.toString()).color(NamedTextColor.RED));
|
||||
}
|
||||
});
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,10 +8,11 @@ import me.chayapak1.chomens_bot.command.TrustLevel;
|
|||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.time.DateTimeException;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class TimeCommand extends Command {
|
||||
public TimeCommand () {
|
||||
|
@ -27,26 +28,24 @@ public class TimeCommand extends Command {
|
|||
|
||||
@Override
|
||||
public Component execute(CommandContext context) throws CommandException {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final String timezone = context.getString(true, true);
|
||||
|
||||
DateTimeZone zone;
|
||||
try {
|
||||
zone = DateTimeZone.forID(timezone);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final String timezone = context.getString(true, true);
|
||||
|
||||
final ZoneId zoneId = ZoneId.of(timezone);
|
||||
final ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId);
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEEE, MMMM d, yyyy, hh:mm:ss a");
|
||||
final String formattedTime = zonedDateTime.format(formatter);
|
||||
|
||||
return Component.translatable(
|
||||
"The current time for %s is: %s",
|
||||
Component.text(timezone).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)),
|
||||
Component.text(formattedTime).color(NamedTextColor.GREEN)
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
} catch (DateTimeException e) {
|
||||
throw new CommandException(Component.text("Invalid timezone (case-sensitive)"));
|
||||
}
|
||||
|
||||
final DateTime dateTime = new DateTime(zone);
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern("EEEE, MMMM d, YYYY, hh:mm:ss a");
|
||||
final String formattedTime = formatter.print(dateTime);
|
||||
|
||||
return Component.translatable(
|
||||
"The current time for %s is: %s",
|
||||
Component.text(timezone).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)),
|
||||
Component.text(formattedTime).color(NamedTextColor.GREEN)
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,10 +24,15 @@ public class ValidateCommand extends Command {
|
|||
public Component execute(CommandContext context) throws CommandException {
|
||||
final Bot bot = context.bot;
|
||||
|
||||
final String hash = context.fullArgs[0];
|
||||
final String[] fullArgs = context.fullArgs;
|
||||
|
||||
if (bot.hashing.isCorrectHash(hash, context.userInputCommandName, context.sender)) return Component.text("Valid hash").color(NamedTextColor.GREEN);
|
||||
else if (bot.hashing.isCorrectOwnerHash(hash, context.userInputCommandName, context.sender)) return Component.text("Valid OwnerHash").color(NamedTextColor.GREEN);
|
||||
if (fullArgs.length == 0) return null;
|
||||
|
||||
final String hash = fullArgs[0];
|
||||
|
||||
if (bot.hashing.isCorrectHash(hash, context.userInputCommandName, context.sender)) return Component.text("Valid trusted hash").color(NamedTextColor.GREEN);
|
||||
else if (bot.hashing.isCorrectAdminHash(hash, context.userInputCommandName, context.sender)) return Component.text("Valid admin hash").color(NamedTextColor.GREEN);
|
||||
else if (bot.hashing.isCorrectOwnerHash(hash, context.userInputCommandName, context.sender)) return Component.text("Valid owner hash").color(NamedTextColor.GREEN);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -11,14 +11,13 @@ import me.chayapak1.chomens_bot.util.ColorUtilities;
|
|||
import me.chayapak1.chomens_bot.util.HttpUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.DateTimeZone;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.ZoneId;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class WeatherCommand extends Command {
|
||||
public WeatherCommand () {
|
||||
|
@ -53,13 +52,11 @@ public class WeatherCommand extends Command {
|
|||
|
||||
final JsonObject jsonObject = gson.fromJson(jsonOutput, JsonObject.class);
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern("hh:mm:ss a");
|
||||
final ZoneId zoneId = ZoneId.of(jsonObject.get("location").getAsJsonObject().get("tz_id").getAsString());
|
||||
final ZonedDateTime zonedDateTime = ZonedDateTime.now(zoneId);
|
||||
|
||||
final DateTimeZone zone = DateTimeZone.forID(jsonObject.get("location").getAsJsonObject().get("tz_id").getAsString());
|
||||
|
||||
final DateTime dateTime = new DateTime(zone);
|
||||
|
||||
final String time = formatter.print(dateTime);
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a");
|
||||
final String time = zonedDateTime.format(formatter);
|
||||
|
||||
return Component.translatable(
|
||||
"Weather forecast for %s, %s:\n%s (%s), feels like %s (%s)\nTime: %s",
|
||||
|
|
|
@ -20,7 +20,7 @@ public class WhitelistCommand extends Command {
|
|||
"Manages whitelist",
|
||||
new String[] { "enable", "disable", "add <player>", "remove <index>", "clear", "list" },
|
||||
new String[] {},
|
||||
TrustLevel.OWNER,
|
||||
TrustLevel.ADMIN,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
@ -57,18 +57,18 @@ public class WhitelistCommand extends Command {
|
|||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
}
|
||||
case "remove" -> {
|
||||
final String player = context.getString(true, true);
|
||||
try {
|
||||
final int index = context.getInteger(true);
|
||||
|
||||
if (!bot.whitelist.list.contains(player)) throw new CommandException(Component.text("Player doesn't exist in the list"));
|
||||
final String player = bot.whitelist.remove(index);
|
||||
|
||||
if (player.equals(bot.profile.getName())) throw new CommandException(Component.text("Cannot remove the bot"));
|
||||
|
||||
bot.whitelist.remove(player);
|
||||
|
||||
return Component.translatable(
|
||||
"Removed %s from the whitelist",
|
||||
Component.text(player).color(ColorUtilities.getColorByString(bot.config.colorPalette.username))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
return Component.translatable(
|
||||
"Removed %s from the whitelist",
|
||||
Component.text(player).color(ColorUtilities.getColorByString(bot.config.colorPalette.username))
|
||||
).color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor));
|
||||
} catch (IndexOutOfBoundsException | IllegalArgumentException | NullPointerException ignored) {
|
||||
throw new CommandException(Component.text("Invalid index"));
|
||||
}
|
||||
}
|
||||
case "clear" -> {
|
||||
context.checkOverloadArgs(1);
|
||||
|
|
|
@ -15,7 +15,7 @@ public class EvalFunction {
|
|||
this.bot = bot;
|
||||
}
|
||||
|
||||
public Output execute (Object ...args) { return null; }
|
||||
public Output execute (Object ...args) throws Exception { return null; }
|
||||
|
||||
public static class Output {
|
||||
public final String message;
|
||||
|
|
|
@ -10,6 +10,8 @@ public class ChatFunction extends EvalFunction {
|
|||
|
||||
@Override
|
||||
public Output execute(Object... args) {
|
||||
if (args.length == 0) return null;
|
||||
|
||||
final String message = (String) args[0];
|
||||
|
||||
bot.chat.send(message);
|
||||
|
|
|
@ -2,6 +2,11 @@ package me.chayapak1.chomens_bot.evalFunctions;
|
|||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.eval.EvalFunction;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CoreFunction extends EvalFunction {
|
||||
public CoreFunction (Bot bot) {
|
||||
|
@ -9,11 +14,13 @@ public class CoreFunction extends EvalFunction {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Output execute(Object... args) {
|
||||
public Output execute(Object... args) throws Exception {
|
||||
if (args.length == 0) return null;
|
||||
|
||||
final String command = (String) args[0];
|
||||
|
||||
bot.core.run(command);
|
||||
final CompletableFuture<Component> future = bot.core.runTracked(command);
|
||||
|
||||
return null;
|
||||
return new Output(GsonComponentSerializer.gson().serialize(future.get(1, TimeUnit.SECONDS)), true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ public class CorePlaceBlockFunction extends EvalFunction {
|
|||
|
||||
@Override
|
||||
public Output execute(Object... args) {
|
||||
if (args.length == 0) return null;
|
||||
|
||||
final String command = (String) args[0];
|
||||
|
||||
bot.core.runPlaceBlock(command);
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package me.chayapak1.chomens_bot.evalFunctions;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.eval.EvalFunction;
|
||||
|
||||
public class GetBotInfoFunction extends EvalFunction {
|
||||
public GetBotInfoFunction(Bot bot) {
|
||||
super("getBotInfo", bot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Output execute(Object... args) {
|
||||
final JsonObject object = new JsonObject();
|
||||
|
||||
object.addProperty("usernane", bot.username);
|
||||
object.addProperty("host", bot.host);
|
||||
object.addProperty("port", bot.port);
|
||||
object.addProperty("loggedIn", bot.loggedIn);
|
||||
|
||||
return new Output(object.toString(), true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package me.chayapak1.chomens_bot.evalFunctions;
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.eval.EvalFunction;
|
||||
import me.chayapak1.chomens_bot.plugins.ChatPlugin;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
|
||||
public class GetLatestChatMessageFunction extends EvalFunction {
|
||||
private String latestMessage = "";
|
||||
|
||||
public GetLatestChatMessageFunction (Bot bot) {
|
||||
super("getLatestChatMessage", bot);
|
||||
|
||||
bot.chat.addListener(new ChatPlugin.Listener() {
|
||||
@Override
|
||||
public boolean systemMessageReceived(Component component, String string, String ansi) {
|
||||
messageReceived(component);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void messageReceived (Component component) {
|
||||
latestMessage = GsonComponentSerializer.gson().serialize(component);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Output execute(Object... args) {
|
||||
return new Output(latestMessage, true);
|
||||
}
|
||||
}
|
|
@ -23,6 +23,8 @@ public class AuthPlugin extends PlayersPlugin.Listener {
|
|||
|
||||
private boolean hasCorrectHash;
|
||||
|
||||
private PlayerEntry targetPlayer;
|
||||
|
||||
private boolean started = false;
|
||||
|
||||
public AuthPlugin (Bot bot) {
|
||||
|
@ -39,7 +41,7 @@ public class AuthPlugin extends PlayersPlugin.Listener {
|
|||
return AuthPlugin.this.systemMessageReceived(component);
|
||||
}
|
||||
});
|
||||
bot.executor.scheduleAtFixedRate(this::check, 0, 1, TimeUnit.SECONDS);
|
||||
bot.executor.scheduleAtFixedRate(this::check, 1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private String getSanitizedOwnerName() {
|
||||
|
@ -50,6 +52,8 @@ public class AuthPlugin extends PlayersPlugin.Listener {
|
|||
public void playerJoined(PlayerEntry target) {
|
||||
if (!target.profile.getName().equals(getSanitizedOwnerName()) || !bot.options.useCore) return;
|
||||
|
||||
targetPlayer = target;
|
||||
|
||||
bot.executor.schedule(() -> sendVerificationMessage(target, true), 2, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
@ -110,6 +114,8 @@ public class AuthPlugin extends PlayersPlugin.Listener {
|
|||
|
||||
hasCorrectHash = inputHash.equals(hash);
|
||||
|
||||
if (hasCorrectHash && targetPlayer != null) bot.chat.tellraw(Component.text("You have been verified").color(NamedTextColor.GREEN), targetPlayer.profile.getId());
|
||||
|
||||
return false;
|
||||
} catch (Exception ignored) {}
|
||||
|
||||
|
@ -117,7 +123,7 @@ public class AuthPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
private void check() {
|
||||
if (!started) return;
|
||||
if (!started || !bot.config.ownerAuthentication.enabled) return;
|
||||
|
||||
final PlayerEntry entry = bot.players.getEntry(getSanitizedOwnerName());
|
||||
|
||||
|
|
|
@ -5,32 +5,37 @@ import me.chayapak1.chomens_bot.util.ColorUtilities;
|
|||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
public class BruhifyPlugin extends TickPlugin.Listener {
|
||||
private final Bot bot;
|
||||
|
||||
public class BruhifyPlugin {
|
||||
public String bruhifyText = "";
|
||||
|
||||
private int startHue = 0;
|
||||
|
||||
public BruhifyPlugin (Bot bot) {
|
||||
bot.executor.scheduleAtFixedRate(() -> {
|
||||
if (bruhifyText.isEmpty()) return;
|
||||
this.bot = bot;
|
||||
|
||||
int hue = startHue;
|
||||
String displayName = bruhifyText;
|
||||
int increment = 360 / Math.max(displayName.length(), 20);
|
||||
bot.tick.addListener(this);
|
||||
}
|
||||
|
||||
Component component = Component.empty();
|
||||
@Override
|
||||
public void onTick() {
|
||||
if (bruhifyText.isEmpty()) return;
|
||||
|
||||
for (char character : displayName.toCharArray()) {
|
||||
String color = String.format("#%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
|
||||
component = component.append(Component.text(character).color(TextColor.fromHexString(color)));
|
||||
hue = (hue + increment) % 360;
|
||||
}
|
||||
int hue = startHue;
|
||||
String displayName = bruhifyText;
|
||||
int increment = 360 / Math.max(displayName.length(), 20);
|
||||
|
||||
bot.chat.actionBar(component);
|
||||
Component component = Component.empty();
|
||||
|
||||
startHue = (startHue + increment) % 360;
|
||||
}, 0, 50, TimeUnit.MILLISECONDS);
|
||||
for (char character : displayName.toCharArray()) {
|
||||
String color = String.format("#%06x", ColorUtilities.hsvToRgb(hue, 100, 100));
|
||||
component = component.append(Component.text(character).color(TextColor.fromHexString(color)));
|
||||
hue = (hue + increment) % 360;
|
||||
}
|
||||
|
||||
bot.chat.actionBar(component);
|
||||
|
||||
startHue = (startHue + increment) % 360;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,11 +58,9 @@ public class ChatCommandHandlerPlugin extends ChatPlugin.Listener {
|
|||
|
||||
final PlayerCommandContext context = new PlayerCommandContext(bot, displayName, prefix, "@a", message.sender);
|
||||
|
||||
bot.executorService.submit(() -> {
|
||||
final Component output = bot.commandHandler.executeCommand(commandString, context, null);
|
||||
final Component output = bot.commandHandler.executeCommand(commandString, context, null);
|
||||
|
||||
if (output != null) context.sendOutput(output);
|
||||
});
|
||||
if (output != null) context.sendOutput(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -94,10 +92,8 @@ public class ChatCommandHandlerPlugin extends ChatPlugin.Listener {
|
|||
|
||||
final PlayerCommandContext context = new PlayerCommandContext(bot, displayName, prefix, selector, sender);
|
||||
|
||||
bot.executorService.submit(() -> {
|
||||
final Component output = bot.commandHandler.executeCommand(commandString, context, null);
|
||||
final Component output = bot.commandHandler.executeCommand(commandString, context, null);
|
||||
|
||||
if (output != null) context.sendOutput(output);
|
||||
});
|
||||
if (output != null) context.sendOutput(output);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,14 @@ public class CloopPlugin {
|
|||
loopTasks.add(bot.executor.scheduleAtFixedRate(loopTask, 0, interval, TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
public void remove (int index) {
|
||||
public CommandLoop remove (int index) {
|
||||
ScheduledFuture<?> loopTask = loopTasks.remove(index);
|
||||
|
||||
if (loopTask != null) {
|
||||
loopTask.cancel(true);
|
||||
}
|
||||
|
||||
loops.remove(index);
|
||||
return loops.remove(index);
|
||||
}
|
||||
|
||||
public void clear () {
|
||||
|
|
|
@ -51,13 +51,13 @@ public class CommandHandlerPlugin {
|
|||
registerCommand(new EvalCommand());
|
||||
registerCommand(new InfoCommand());
|
||||
registerCommand(new ConsoleCommand());
|
||||
registerCommand(new PCrashCommand());
|
||||
// registerCommand(new ScreenshareCommand());
|
||||
registerCommand(new WhitelistCommand());
|
||||
registerCommand(new SeenCommand());
|
||||
registerCommand(new IPFilterCommand());
|
||||
registerCommand(new StopCommand());
|
||||
registerCommand(new GrepLogCommand());
|
||||
registerCommand(new FindAltsCommand());
|
||||
}
|
||||
|
||||
public boolean disabled = false;
|
||||
|
@ -93,6 +93,8 @@ public class CommandHandlerPlugin {
|
|||
|
||||
final String[] splitInput = input.trim().split("\\s+");
|
||||
|
||||
if (splitInput.length == 0) return null;
|
||||
|
||||
final String commandName = splitInput[0];
|
||||
|
||||
final Command command = findCommand(commands, commandName);
|
||||
|
@ -123,28 +125,43 @@ public class CommandHandlerPlugin {
|
|||
|
||||
final String trustedRoleName = bot.config.discord.trustedRoleName;
|
||||
final String adminRoleName = bot.config.discord.adminRoleName;
|
||||
final String ownerRoleName = bot.config.discord.ownerRoleName;
|
||||
|
||||
if (
|
||||
command.trustLevel == TrustLevel.TRUSTED &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(trustedRoleName)) &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(adminRoleName))
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(adminRoleName)) &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(ownerRoleName))
|
||||
) return Component.text("You're not in the trusted role!").color(NamedTextColor.RED);
|
||||
|
||||
if (
|
||||
command.trustLevel == TrustLevel.OWNER &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(adminRoleName))
|
||||
command.trustLevel == TrustLevel.ADMIN &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(adminRoleName)) &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(ownerRoleName))
|
||||
) return Component.text("You're not in the admin role!").color(NamedTextColor.RED);
|
||||
|
||||
if (
|
||||
command.trustLevel == TrustLevel.OWNER &&
|
||||
roles.stream().noneMatch(role -> role.getName().equalsIgnoreCase(ownerRoleName))
|
||||
) return Component.text("You're not in the owner role!").color(NamedTextColor.RED);
|
||||
} else {
|
||||
if (
|
||||
command.trustLevel == TrustLevel.TRUSTED &&
|
||||
!bot.hashing.isCorrectHash(userHash, splitInput[0], context.sender) &&
|
||||
!bot.hashing.isCorrectAdminHash(userHash, splitInput[0], context.sender) &&
|
||||
!bot.hashing.isCorrectOwnerHash(userHash, splitInput[0], context.sender)
|
||||
) return Component.text("Invalid hash").color(NamedTextColor.RED);
|
||||
|
||||
if (
|
||||
command.trustLevel == TrustLevel.ADMIN &&
|
||||
!bot.hashing.isCorrectAdminHash(userHash, splitInput[0], context.sender) &&
|
||||
!bot.hashing.isCorrectOwnerHash(userHash, splitInput[0], context.sender)
|
||||
) return Component.text("Invalid admin hash").color(NamedTextColor.RED);
|
||||
|
||||
if (
|
||||
command.trustLevel == TrustLevel.OWNER &&
|
||||
!bot.hashing.isCorrectOwnerHash(userHash, splitInput[0], context.sender)
|
||||
) return Component.text("Invalid OwnerHash").color(NamedTextColor.RED);
|
||||
) return Component.text("Invalid owner hash").color(NamedTextColor.RED);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
package me.chayapak1.chomens_bot.plugins;
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.Configuration;
|
||||
import me.chayapak1.chomens_bot.Main;
|
||||
import me.chayapak1.chomens_bot.command.Command;
|
||||
import me.chayapak1.chomens_bot.command.ConsoleCommandContext;
|
||||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.jline.reader.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ConsolePlugin implements Completer {
|
||||
|
@ -21,12 +18,10 @@ public class ConsolePlugin implements Completer {
|
|||
|
||||
public String consoleServer = "all";
|
||||
|
||||
public String prefix;
|
||||
private String prefix;
|
||||
|
||||
private static final List<Listener> listeners = new ArrayList<>();
|
||||
|
||||
public ConsolePlugin (List<Bot> allBots, Configuration config, JDA jda) {
|
||||
this.allBots = allBots;
|
||||
public ConsolePlugin () {
|
||||
this.allBots = Main.bots;
|
||||
this.reader = LineReaderBuilder
|
||||
.builder()
|
||||
.completer(this)
|
||||
|
@ -38,13 +33,8 @@ public class ConsolePlugin implements Completer {
|
|||
prefix = bot.config.consoleCommandPrefix;
|
||||
|
||||
bot.console = this;
|
||||
|
||||
bot.logger = new LoggerPlugin(bot);
|
||||
}
|
||||
|
||||
new DiscordPlugin(config, jda);
|
||||
if (config.irc.enabled) new IRCPlugin(config);
|
||||
|
||||
final String prompt = "> ";
|
||||
|
||||
Main.executorService.submit(() -> {
|
||||
|
@ -59,8 +49,6 @@ public class ConsolePlugin implements Completer {
|
|||
handleLine(line);
|
||||
}
|
||||
});
|
||||
|
||||
for (Listener listener : listeners) { listener.ready(); }
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -82,7 +70,7 @@ public class ConsolePlugin implements Completer {
|
|||
candidates.addAll(filteredCommands);
|
||||
}
|
||||
|
||||
public void handleLine (String line) {
|
||||
private void handleLine (String line) {
|
||||
if (line == null) return;
|
||||
|
||||
for (Bot bot : allBots) {
|
||||
|
@ -112,10 +100,4 @@ public class ConsolePlugin implements Completer {
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addListener (Listener listener) { listeners.add(listener); }
|
||||
|
||||
public static class Listener {
|
||||
public void ready () {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,10 +30,7 @@ import net.kyori.adventure.text.TextComponent;
|
|||
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -55,6 +52,8 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
|
||||
public Vector3i block = null;
|
||||
|
||||
public final List<String> placeBlockQueue = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
private int nextTransactionId = 0;
|
||||
private final Map<Integer, CompletableFuture<Component>> transactions = new HashMap<>();
|
||||
|
||||
|
@ -120,6 +119,27 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
return CorePlugin.this.systemMessageReceived(component);
|
||||
}
|
||||
});
|
||||
|
||||
bot.tick.addListener(new TickPlugin.Listener() {
|
||||
@Override
|
||||
public void onTick() {
|
||||
try {
|
||||
final List<String> clonedQueue = new ArrayList<>(placeBlockQueue);
|
||||
|
||||
if (clonedQueue.isEmpty()) return;
|
||||
|
||||
if (clonedQueue.size() > 500) {
|
||||
placeBlockQueue.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
forceRunPlaceBlock(clonedQueue.get(0));
|
||||
placeBlockQueue.remove(0);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hasRateLimit () {
|
||||
|
@ -171,6 +191,11 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
if (!ready || command.length() > 32767) return;
|
||||
|
||||
if (bot.options.useCore) {
|
||||
if (bot.options.useCorePlaceBlock) {
|
||||
runPlaceBlock(command);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRateLimited() && hasRateLimit()) return;
|
||||
|
||||
forceRun(command);
|
||||
|
@ -183,8 +208,15 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
|
||||
// thanks chipmunk for this new tellraw method
|
||||
public CompletableFuture<Component> runTracked (String command) {
|
||||
if (!ready || command.length() > 32767) return null;
|
||||
|
||||
if (!bot.options.useCore) return null;
|
||||
|
||||
if (bot.options.useCorePlaceBlock) {
|
||||
runPlaceBlock(command);
|
||||
return null;
|
||||
}
|
||||
|
||||
final Vector3i coreBlock = block;
|
||||
|
||||
run(command);
|
||||
|
@ -239,7 +271,7 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
|
||||
final String stringLastOutput = ((TextComponent) children.get(1)).content();
|
||||
|
||||
future.complete(Component.join(JoinConfiguration.separator(Component.space()), GsonComponentSerializer.gson().deserialize(stringLastOutput).children()));
|
||||
future.complete(Component.join(JoinConfiguration.separator(Component.empty()), GsonComponentSerializer.gson().deserialize(stringLastOutput).children()));
|
||||
|
||||
return false;
|
||||
} catch (ClassCastException | NumberFormatException ignored) {}
|
||||
|
@ -248,6 +280,10 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
}
|
||||
|
||||
public void runPlaceBlock (String command) {
|
||||
bot.executorService.submit(() -> placeBlockQueue.add(command));
|
||||
}
|
||||
|
||||
private void forceRunPlaceBlock (String command) {
|
||||
if (!ready || !bot.options.useCore) return;
|
||||
|
||||
final NbtMapBuilder blockEntityTagBuilder = NbtMap.builder();
|
||||
|
@ -374,6 +410,8 @@ public class CorePlugin extends PositionPlugin.Listener {
|
|||
|
||||
@Override
|
||||
public void positionChange (Vector3i position) {
|
||||
if (bot.position.isGoingDownFromHeightLimit) return;
|
||||
|
||||
from = Vector3i.from(
|
||||
(int) (fromSize.getX() + Math.floor((double) bot.position.position.getX() / 16) * 16),
|
||||
MathUtilities.clamp(fromSize.getY(), bot.world.minY, bot.world.maxY),
|
||||
|
|
|
@ -9,14 +9,14 @@ import me.chayapak1.chomens_bot.util.ColorUtilities;
|
|||
import me.chayapak1.chomens_bot.util.ComponentUtilities;
|
||||
import me.chayapak1.chomens_bot.util.LoggerUtilities;
|
||||
import net.dv8tion.jda.api.JDA;
|
||||
import net.dv8tion.jda.api.entities.Member;
|
||||
import net.dv8tion.jda.api.entities.Message;
|
||||
import net.dv8tion.jda.api.entities.MessageEmbed;
|
||||
import net.dv8tion.jda.api.entities.Role;
|
||||
import net.dv8tion.jda.api.JDABuilder;
|
||||
import net.dv8tion.jda.api.entities.*;
|
||||
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
|
||||
import net.dv8tion.jda.api.events.message.MessageReceivedEvent;
|
||||
import net.dv8tion.jda.api.events.session.ShutdownEvent;
|
||||
import net.dv8tion.jda.api.hooks.ListenerAdapter;
|
||||
import net.dv8tion.jda.api.requests.GatewayIntent;
|
||||
import net.dv8tion.jda.api.requests.restaction.MessageCreateAction;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import net.kyori.adventure.text.event.ClickEvent;
|
||||
|
@ -35,7 +35,7 @@ import java.util.*;
|
|||
// please ignore my ohio code
|
||||
// also this is one of the classes which has >100 lines or actually >400 LMAO
|
||||
public class DiscordPlugin {
|
||||
public final JDA jda;
|
||||
public JDA jda;
|
||||
|
||||
public final Map<String, String> servers;
|
||||
|
||||
|
@ -49,11 +49,10 @@ public class DiscordPlugin {
|
|||
|
||||
public boolean shuttedDown = false;
|
||||
|
||||
public DiscordPlugin (Configuration config, JDA jda) {
|
||||
public DiscordPlugin (Configuration config) {
|
||||
final Configuration.Discord options = config.discord;
|
||||
this.prefix = options.prefix;
|
||||
this.servers = options.servers;
|
||||
this.jda = jda;
|
||||
this.discordUrl = config.discord.inviteLink;
|
||||
this.messagePrefix = Component.empty()
|
||||
.append(Component.text("ChomeNS ").color(NamedTextColor.YELLOW))
|
||||
|
@ -65,8 +64,17 @@ public class DiscordPlugin {
|
|||
)
|
||||
.clickEvent(ClickEvent.openUrl(discordUrl));
|
||||
|
||||
final JDABuilder builder = JDABuilder.createDefault(config.discord.token);
|
||||
builder.enableIntents(GatewayIntent.MESSAGE_CONTENT);
|
||||
try {
|
||||
jda = builder.build();
|
||||
jda.awaitReady();
|
||||
} catch (InterruptedException ignored) {}
|
||||
|
||||
if (jda == null) return;
|
||||
|
||||
jda.getPresence().setPresence(Activity.playing(config.discord.statusMessage), false);
|
||||
|
||||
for (Bot bot : Main.bots) {
|
||||
final String channelId = servers.get(bot.host + ":" + bot.port);
|
||||
|
||||
|
@ -78,7 +86,9 @@ public class DiscordPlugin {
|
|||
bot.tick.addListener(new TickPlugin.Listener() {
|
||||
@Override
|
||||
public void onAlwaysTick () {
|
||||
onDiscordTick(channelId);
|
||||
try {
|
||||
onDiscordTick(channelId);
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -353,24 +363,31 @@ public class DiscordPlugin {
|
|||
}
|
||||
}
|
||||
|
||||
public void sendMessageInstantly (String message, String channelId) {
|
||||
if (jda == null) return;
|
||||
public void sendMessageInstantly (String message, String channelId) { sendMessageInstantly(message, channelId, true); }
|
||||
public MessageCreateAction sendMessageInstantly (String message, String channelId, boolean queue) {
|
||||
if (jda == null) return null;
|
||||
|
||||
final TextChannel logChannel = jda.getTextChannelById(channelId);
|
||||
|
||||
if (logChannel == null) {
|
||||
LoggerUtilities.error("Log channel for " + channelId + " is null");
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
logChannel.sendMessage(message).queue(
|
||||
(msg) -> doneSendingInLogs.put(channelId, true),
|
||||
(err) -> {
|
||||
err.printStackTrace();
|
||||
if (queue) {
|
||||
logChannel.sendMessage(message).queue(
|
||||
(msg) -> doneSendingInLogs.put(channelId, true),
|
||||
(err) -> {
|
||||
err.printStackTrace();
|
||||
|
||||
doneSendingInLogs.put(channelId, false);
|
||||
}
|
||||
);
|
||||
doneSendingInLogs.put(channelId, false);
|
||||
}
|
||||
);
|
||||
|
||||
return null;
|
||||
} else {
|
||||
return logChannel.sendMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
public void onDiscordTick(String channelId) {
|
||||
|
@ -389,7 +406,7 @@ public class DiscordPlugin {
|
|||
String message;
|
||||
synchronized (logMessages) {
|
||||
StringBuilder logMessage = logMessages.get(channelId);
|
||||
message = logMessage.toString();
|
||||
message = logMessage.toString().replace(".", "\u200b.\u200b"); // the ZWSP fixes discord.gg showing invite
|
||||
final int maxLength = 2_000 - ("""
|
||||
```ansi
|
||||
|
||||
|
|
|
@ -7,10 +7,7 @@ import io.socket.client.Socket;
|
|||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.eval.EvalFunction;
|
||||
import me.chayapak1.chomens_bot.data.eval.EvalOutput;
|
||||
import me.chayapak1.chomens_bot.evalFunctions.ChatFunction;
|
||||
import me.chayapak1.chomens_bot.evalFunctions.CoreFunction;
|
||||
import me.chayapak1.chomens_bot.evalFunctions.CorePlaceBlockFunction;
|
||||
import me.chayapak1.chomens_bot.evalFunctions.GetPlayerListFunction;
|
||||
import me.chayapak1.chomens_bot.evalFunctions.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
@ -38,6 +35,8 @@ public class EvalPlugin {
|
|||
functions.add(new CorePlaceBlockFunction(bot));
|
||||
functions.add(new ChatFunction(bot));
|
||||
functions.add(new GetPlayerListFunction(bot));
|
||||
functions.add(new GetBotInfoFunction(bot));
|
||||
functions.add(new GetLatestChatMessageFunction(bot));
|
||||
|
||||
try {
|
||||
socket = IO.socket(bot.config.eval.address);
|
||||
|
@ -61,16 +60,20 @@ public class EvalPlugin {
|
|||
socket.on(Socket.EVENT_CONNECT_ERROR, (args) -> connected = false);
|
||||
|
||||
for (EvalFunction function : functions) {
|
||||
socket.on(BRIDGE_PREFIX + function.name, args -> {
|
||||
final EvalFunction.Output output = function.execute(args);
|
||||
socket.on(BRIDGE_PREFIX + function.name, args -> new Thread(() -> {
|
||||
try {
|
||||
final EvalFunction.Output output = function.execute(args);
|
||||
|
||||
if (output == null) return;
|
||||
if (output == null) return;
|
||||
|
||||
socket.emit("functionOutput:" + function.name, output.message, output.parseJSON);
|
||||
});
|
||||
socket.emit("functionOutput:" + function.name, output.message, output.parseJSON);
|
||||
} catch (Exception ignored) {}
|
||||
}).start());
|
||||
}
|
||||
|
||||
socket.on("codeOutput", (args) -> {
|
||||
if (args.length < 3) return;
|
||||
|
||||
final int id = (int) args[0];
|
||||
final boolean isError = (boolean) args[1];
|
||||
final String output = (String) args[2];
|
||||
|
|
|
@ -25,8 +25,8 @@ public class FilterPlugin extends PlayersPlugin.Listener {
|
|||
private final Gson gson = new Gson();
|
||||
|
||||
static {
|
||||
if (PersistentDataUtilities.jsonObject.has("filters")) {
|
||||
filteredPlayers = PersistentDataUtilities.jsonObject.get("filters").getAsJsonArray();
|
||||
if (PersistentDataUtilities.has("filters")) {
|
||||
filteredPlayers = PersistentDataUtilities.get("filters").getAsJsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -55,55 +55,54 @@ public class FilterPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
private FilteredPlayer getPlayer (String name) {
|
||||
// mess
|
||||
// also regex and ignorecase codes from greplog plugin
|
||||
FilteredPlayer filteredPlayer = null;
|
||||
for (JsonElement filteredPlayerElement : filteredPlayers) {
|
||||
final FilteredPlayer _filteredPlayer = gson.fromJson(filteredPlayerElement, FilteredPlayer.class);
|
||||
final FilteredPlayer filteredPlayer = gson.fromJson(filteredPlayerElement, FilteredPlayer.class);
|
||||
|
||||
if (_filteredPlayer.regex) {
|
||||
Pattern pattern = null;
|
||||
if (_filteredPlayer.ignoreCase) {
|
||||
pattern = Pattern.compile(_filteredPlayer.playerName, Pattern.CASE_INSENSITIVE);
|
||||
} else {
|
||||
try {
|
||||
pattern = Pattern.compile(_filteredPlayer.playerName);
|
||||
} catch (Exception e) {
|
||||
bot.chat.tellraw(Component.text(e.toString()).color(NamedTextColor.RED));
|
||||
}
|
||||
}
|
||||
|
||||
if (pattern == null) break;
|
||||
|
||||
if (pattern.matcher(name).find()) {
|
||||
filteredPlayer = _filteredPlayer;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (_filteredPlayer.ignoreCase) {
|
||||
if (_filteredPlayer.playerName.toLowerCase().equals(name)) {
|
||||
filteredPlayer = _filteredPlayer;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (_filteredPlayer.playerName.equals(name)) {
|
||||
filteredPlayer = _filteredPlayer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (matchesPlayer(name, filteredPlayer)) {
|
||||
return filteredPlayer;
|
||||
}
|
||||
}
|
||||
|
||||
return filteredPlayer;
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean matchesPlayer (String name, FilteredPlayer player) {
|
||||
if (player.regex) {
|
||||
final Pattern pattern = compilePattern(player);
|
||||
|
||||
return pattern != null && pattern.matcher(name).find();
|
||||
} else {
|
||||
return compareNames(name, player);
|
||||
}
|
||||
}
|
||||
|
||||
private Pattern compilePattern (FilteredPlayer player) {
|
||||
try {
|
||||
final int flags = player.ignoreCase ? Pattern.CASE_INSENSITIVE : 0;
|
||||
|
||||
return Pattern.compile(player.playerName, flags);
|
||||
} catch (Exception e) {
|
||||
bot.chat.tellraw(Component.text(e.toString()).color(NamedTextColor.RED));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean compareNames (String name, FilteredPlayer player) {
|
||||
final String playerName = player.ignoreCase ? player.playerName.toLowerCase() : player.playerName;
|
||||
final String targetName = player.ignoreCase ? name.toLowerCase() : name;
|
||||
|
||||
return playerName.equals(targetName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerJoined (PlayerEntry target) {
|
||||
final FilteredPlayer player = getPlayer(target.profile.getName());
|
||||
bot.executorService.submit(() -> {
|
||||
final FilteredPlayer player = getPlayer(target.profile.getName());
|
||||
|
||||
if (player == null) return;
|
||||
if (player == null) return;
|
||||
|
||||
doAll(target);
|
||||
doAll(target);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.nio.charset.StandardCharsets;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.NotDirectoryException;
|
||||
import java.nio.file.Path;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -104,10 +105,12 @@ public class GrepLogPlugin {
|
|||
.queue(message -> {
|
||||
final String url = message.getAttachments().get(0).getUrl();
|
||||
|
||||
final DecimalFormat formatter = new DecimalFormat("#,###");
|
||||
|
||||
final Component component = Component.translatable("Found %s matches for %s. You can see the results by clicking %s or in the Discord server.")
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor))
|
||||
.arguments(
|
||||
Component.text(matches).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)),
|
||||
Component.text(formatter.format(matches)).color(ColorUtilities.getColorByString(bot.config.colorPalette.number)),
|
||||
Component.text(input).color(ColorUtilities.getColorByString(bot.config.colorPalette.string)),
|
||||
Component
|
||||
.text("here")
|
||||
|
@ -126,6 +129,9 @@ public class GrepLogPlugin {
|
|||
|
||||
context.sendOutput(component);
|
||||
});
|
||||
} catch (CommandException e) {
|
||||
running = false;
|
||||
throw e;
|
||||
} catch (FileNotFoundException e) {
|
||||
running = false;
|
||||
throw new CommandException(Component.text("File not found"));
|
||||
|
|
|
@ -14,10 +14,13 @@ public class HashingPlugin {
|
|||
this.bot = bot;
|
||||
}
|
||||
|
||||
public String getHash (String prefix, PlayerEntry sender, boolean sectionSigns) {
|
||||
final long time = System.currentTimeMillis() / 5_000;
|
||||
public String getHash (String prefix, PlayerEntry sender, boolean sectionSigns) { return getGenericHash(bot.config.keys.trustedKey, prefix, sender, sectionSigns); }
|
||||
public String getAdminHash (String prefix, PlayerEntry sender, boolean sectionSigns) { return getGenericHash(bot.config.keys.adminKey, prefix, sender, sectionSigns); }
|
||||
public String getOwnerHash (String prefix, PlayerEntry sender, boolean sectionSigns) { return getGenericHash(bot.config.keys.ownerKey, prefix, sender, sectionSigns); }
|
||||
|
||||
final String key = bot.config.keys.normalKey;
|
||||
// should this be public?
|
||||
public String getGenericHash (String key, String prefix, PlayerEntry sender, boolean sectionSigns) {
|
||||
final long time = System.currentTimeMillis() / 5_000;
|
||||
|
||||
final String hashValue = sender.profile.getIdAsString() + prefix + time + key;
|
||||
|
||||
|
@ -35,40 +38,25 @@ public class HashingPlugin {
|
|||
hash;
|
||||
}
|
||||
|
||||
public String getOwnerHash (String prefix, PlayerEntry sender, boolean sectionSigns) {
|
||||
final long time = System.currentTimeMillis() / 5_000;
|
||||
private boolean checkHash (String hash, String input, String prefix, PlayerEntry sender) {
|
||||
// removes reset section sign
|
||||
if (input.length() == (16 * 2 /* <-- don't forget, we have the section signs */) + 2 && input.endsWith("§r")) input = input.substring(0, input.length() - 2);
|
||||
|
||||
final String key = bot.config.keys.ownerKey;
|
||||
|
||||
final String value = sender.profile.getIdAsString() + prefix + time + key;
|
||||
|
||||
final String hash = Hashing.sha256()
|
||||
.hashString(value, StandardCharsets.UTF_8)
|
||||
.toString()
|
||||
.substring(0, 16);
|
||||
|
||||
return sectionSigns ?
|
||||
String.join("",
|
||||
Arrays.stream(hash.split(""))
|
||||
.map((letter) -> "§" + letter)
|
||||
.toArray(String[]::new)
|
||||
) :
|
||||
hash;
|
||||
return input.equals(hash);
|
||||
}
|
||||
|
||||
public boolean isCorrectHash (String hash, String prefix, PlayerEntry sender) {
|
||||
// removes reset section sign
|
||||
if (hash.length() == (16 * 2 /* <-- don't forget, we have the section signs */) + 2 && hash.endsWith("§r")) hash = hash.substring(0, hash.length() - 2);
|
||||
|
||||
return hash.equals(getHash(prefix, sender, true)) ||
|
||||
hash.equals(getHash(prefix, sender, false));
|
||||
public boolean isCorrectHash (String input, String prefix, PlayerEntry sender) {
|
||||
return checkHash(getHash(prefix, sender, true), input, prefix, sender) ||
|
||||
checkHash(getHash(prefix, sender, false), input, prefix, sender);
|
||||
}
|
||||
|
||||
public boolean isCorrectOwnerHash (String hash, String prefix, PlayerEntry sender) {
|
||||
// removes reset section sign
|
||||
if (hash.length() == (16 * 2 /* <-- don't forget, we have the section signs */) + 2 && hash.endsWith("§r")) hash = hash.substring(0, hash.length() - 2);
|
||||
public boolean isCorrectAdminHash (String input, String prefix, PlayerEntry sender) {
|
||||
return checkHash(getAdminHash(prefix, sender, true), input, prefix, sender) ||
|
||||
checkHash(getAdminHash(prefix, sender, false), input, prefix, sender);
|
||||
}
|
||||
|
||||
return hash.equals(getOwnerHash(prefix, sender, true)) ||
|
||||
hash.equals(getOwnerHash(prefix, sender, false));
|
||||
public boolean isCorrectOwnerHash (String input, String prefix, PlayerEntry sender) {
|
||||
return checkHash(getOwnerHash(prefix, sender, true), input, prefix, sender) ||
|
||||
checkHash(getOwnerHash(prefix, sender, false), input, prefix, sender);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,8 @@ import com.google.gson.JsonArray;
|
|||
import com.google.gson.JsonElement;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.util.ComponentUtilities;
|
||||
import me.chayapak1.chomens_bot.util.PersistentDataUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -19,8 +15,8 @@ public class IPFilterPlugin extends PlayersPlugin.Listener {
|
|||
public static JsonArray filteredIPs = new JsonArray();
|
||||
|
||||
static {
|
||||
if (PersistentDataUtilities.jsonObject.has("ipFilters")) {
|
||||
filteredIPs = PersistentDataUtilities.jsonObject.get("ipFilters").getAsJsonArray();
|
||||
if (PersistentDataUtilities.has("ipFilters")) {
|
||||
filteredIPs = PersistentDataUtilities.get("ipFilters").getAsJsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +25,7 @@ public class IPFilterPlugin extends PlayersPlugin.Listener {
|
|||
|
||||
bot.players.addListener(this);
|
||||
|
||||
bot.executor.scheduleAtFixedRate(this::checkAllPlayers, 0, 2, TimeUnit.SECONDS);
|
||||
bot.executor.scheduleAtFixedRate(this::checkAllPlayers, 0, 10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,21 +36,14 @@ public class IPFilterPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
private void check (PlayerEntry target) {
|
||||
final CompletableFuture<Component> future = bot.core.runTracked("essentials:seen " + target.profile.getIdAsString());
|
||||
if (bot.options.useCorePlaceBlock) return; // it will spam the place block core so i ignored this
|
||||
|
||||
final CompletableFuture<String> future = bot.players.getPlayerIP(target);
|
||||
|
||||
if (future == null) return;
|
||||
|
||||
future.thenApply(output -> {
|
||||
final List<Component> children = output.children();
|
||||
|
||||
String stringified = ComponentUtilities.stringify(Component.join(JoinConfiguration.separator(Component.space()), children));
|
||||
|
||||
if (!stringified.startsWith(" - IP Address: ")) return output;
|
||||
|
||||
stringified = stringified.trim().substring(" - IP Address: ".length());
|
||||
if (stringified.startsWith("/")) stringified = stringified.substring(1);
|
||||
|
||||
handleIP(stringified, target);
|
||||
future.thenApplyAsync(output -> {
|
||||
handleIP(output, target);
|
||||
|
||||
return output;
|
||||
});
|
||||
|
@ -71,7 +60,9 @@ public class IPFilterPlugin extends PlayersPlugin.Listener {
|
|||
private void checkAllPlayers () {
|
||||
if (filteredIPs.isEmpty()) return;
|
||||
|
||||
for (PlayerEntry entry : bot.players.list) check(entry);
|
||||
bot.executorService.submit(() -> {
|
||||
for (PlayerEntry entry : bot.players.list) check(entry);
|
||||
});
|
||||
}
|
||||
|
||||
public String remove (int index) {
|
||||
|
|
|
@ -169,7 +169,7 @@ public class IRCPlugin extends ListenerAdapter {
|
|||
}
|
||||
|
||||
public void quit (String reason) {
|
||||
bot.sendIRC().quitServer(reason);
|
||||
if (bot.isConnected()) bot.sendIRC().quitServer(reason);
|
||||
}
|
||||
|
||||
private void connected (Bot bot) {
|
||||
|
@ -202,9 +202,7 @@ public class IRCPlugin extends ListenerAdapter {
|
|||
|
||||
bot.sendIRC().message(entry.getKey(), withIRCColors);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
private void addMessageToQueue (Bot bot, String message) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package me.chayapak1.chomens_bot.plugins;
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.Main;
|
||||
import me.chayapak1.chomens_bot.util.ComponentUtilities;
|
||||
import me.chayapak1.chomens_bot.util.LoggerUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
@ -8,6 +9,10 @@ import org.geysermc.mcprotocollib.network.event.session.ConnectedEvent;
|
|||
import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent;
|
||||
|
||||
public class LoggerPlugin extends ChatPlugin.Listener {
|
||||
public static void init () {
|
||||
for (Bot bot : Main.bots) new LoggerPlugin(bot);
|
||||
}
|
||||
|
||||
private final Bot bot;
|
||||
|
||||
private boolean addedListener = false;
|
||||
|
@ -16,7 +21,7 @@ public class LoggerPlugin extends ChatPlugin.Listener {
|
|||
|
||||
private int totalConnects = 0;
|
||||
|
||||
public LoggerPlugin(Bot bot) {
|
||||
public LoggerPlugin (Bot bot) {
|
||||
this.bot = bot;
|
||||
|
||||
bot.addListener(new Bot.Listener() {
|
||||
|
@ -75,6 +80,8 @@ public class LoggerPlugin extends ChatPlugin.Listener {
|
|||
log(message + string, true, false);
|
||||
}
|
||||
});
|
||||
|
||||
bot.logger = this;
|
||||
}
|
||||
|
||||
public void log (String message) {
|
||||
|
|
|
@ -19,8 +19,8 @@ public class MailPlugin extends PlayersPlugin.Listener {
|
|||
private final Gson gson = new Gson();
|
||||
|
||||
static {
|
||||
if (PersistentDataUtilities.jsonObject.has("mails")) {
|
||||
mails = PersistentDataUtilities.jsonObject.get("mails").getAsJsonArray();
|
||||
if (PersistentDataUtilities.has("mails")) {
|
||||
mails = PersistentDataUtilities.get("mails").getAsJsonArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ public class MusicPlayerPlugin extends Bot.Listener {
|
|||
|
||||
private int limit = 0;
|
||||
|
||||
public boolean locked = false; // this can be set through servereval
|
||||
|
||||
private final String bossbarName = "music";
|
||||
|
||||
public BossBarColor bossBarColor;
|
||||
|
@ -73,7 +75,7 @@ public class MusicPlayerPlugin extends Bot.Listener {
|
|||
}
|
||||
|
||||
public void loadSong (Path location, PlayerEntry sender) {
|
||||
if (songQueue.size() > 100) return;
|
||||
if (songQueue.size() > 500) return;
|
||||
|
||||
loaderThread = new SongLoaderThread(location, bot, sender.profile.getName());
|
||||
|
||||
|
@ -90,7 +92,7 @@ public class MusicPlayerPlugin extends Bot.Listener {
|
|||
}
|
||||
|
||||
public void loadSong (URL location, PlayerEntry sender) {
|
||||
if (songQueue.size() > 100) return;
|
||||
if (songQueue.size() > 500) return;
|
||||
|
||||
limit++;
|
||||
|
||||
|
@ -114,7 +116,7 @@ public class MusicPlayerPlugin extends Bot.Listener {
|
|||
}
|
||||
|
||||
public void loadSong (byte[] data, PlayerEntry sender) {
|
||||
if (songQueue.size() > 100) return;
|
||||
if (songQueue.size() > 500) return;
|
||||
|
||||
loaderThread = new SongLoaderThread(data, bot, sender.profile.getName());
|
||||
|
||||
|
@ -194,13 +196,9 @@ public class MusicPlayerPlugin extends Bot.Listener {
|
|||
if (songQueue.isEmpty()) {
|
||||
stopPlaying();
|
||||
removeBossBar();
|
||||
bot.chat.tellraw(
|
||||
Component
|
||||
.text("Finished playing every song in the queue")
|
||||
.color(ColorUtilities.getColorByString(bot.config.colorPalette.defaultColor))
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentSong.size() > 0) {
|
||||
currentSong = songQueue.get(0);
|
||||
currentSong.setTime(0);
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
package me.chayapak1.chomens_bot.plugins;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import me.chayapak1.chomens_bot.data.PlayerEntry;
|
||||
import me.chayapak1.chomens_bot.util.PersistentDataUtilities;
|
||||
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class PlayersPersistentDataPlugin extends PlayersPlugin.Listener {
|
||||
public static JsonObject playersObject = new JsonObject();
|
||||
|
||||
static {
|
||||
if (PersistentDataUtilities.jsonObject.has("players")) {
|
||||
playersObject = PersistentDataUtilities.jsonObject.get("players").getAsJsonObject();
|
||||
if (PersistentDataUtilities.has("players")) {
|
||||
playersObject = PersistentDataUtilities.get("players").getAsJsonObject();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,12 +29,40 @@ public class PlayersPersistentDataPlugin extends PlayersPlugin.Listener {
|
|||
|
||||
@Override
|
||||
public void playerJoined(PlayerEntry target) {
|
||||
if (playersObject.has(getName(target))) return;
|
||||
final JsonElement originalElement = playersObject.get(target.profile.getName());
|
||||
|
||||
final JsonObject object = new JsonObject();
|
||||
object.addProperty("uuid", target.profile.getIdAsString());
|
||||
object.add("lastSeen", new JsonObject());
|
||||
JsonObject object;
|
||||
|
||||
if (originalElement == null) {
|
||||
object = new JsonObject();
|
||||
object.addProperty("uuid", target.profile.getIdAsString());
|
||||
object.add("ips", new JsonObject());
|
||||
} else {
|
||||
object = originalElement.getAsJsonObject();
|
||||
}
|
||||
|
||||
final CompletableFuture<String> future = bot.players.getPlayerIP(target);
|
||||
|
||||
if (future == null) {
|
||||
setPersistentEntry(target, object);
|
||||
return;
|
||||
}
|
||||
|
||||
future.completeOnTimeout(null, 5, TimeUnit.SECONDS);
|
||||
|
||||
future.thenApplyAsync(output -> {
|
||||
if (output != null) {
|
||||
object.getAsJsonObject("ips").addProperty(bot.host + ":" + bot.port, output);
|
||||
}
|
||||
|
||||
setPersistentEntry(target, object);
|
||||
|
||||
return output;
|
||||
});
|
||||
}
|
||||
|
||||
// is this bad?
|
||||
private void setPersistentEntry (PlayerEntry target, JsonObject object) {
|
||||
playersObject.add(getName(target), object);
|
||||
|
||||
PersistentDataUtilities.put("players", playersObject);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package me.chayapak1.chomens_bot.plugins;
|
||||
|
||||
import me.chayapak1.chomens_bot.util.ComponentUtilities;
|
||||
import net.kyori.adventure.text.JoinConfiguration;
|
||||
import org.geysermc.mcprotocollib.network.Session;
|
||||
import org.geysermc.mcprotocollib.network.event.session.DisconnectedEvent;
|
||||
import org.geysermc.mcprotocollib.network.packet.Packet;
|
||||
|
@ -16,6 +18,7 @@ import java.util.ArrayList;
|
|||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class PlayersPlugin extends Bot.Listener {
|
||||
private final Bot bot;
|
||||
|
@ -58,6 +61,31 @@ public class PlayersPlugin extends Bot.Listener {
|
|||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<String> getPlayerIP (PlayerEntry target) {
|
||||
final CompletableFuture<String> outputFuture = new CompletableFuture<>();
|
||||
|
||||
final CompletableFuture<Component> trackedCoreFuture = bot.core.runTracked("essentials:seen " + target.profile.getIdAsString());
|
||||
|
||||
if (trackedCoreFuture == null) return null;
|
||||
|
||||
trackedCoreFuture.thenApplyAsync(output -> {
|
||||
final List<Component> children = output.children();
|
||||
|
||||
String stringified = ComponentUtilities.stringify(Component.join(JoinConfiguration.separator(Component.empty()), children));
|
||||
|
||||
if (!stringified.startsWith(" - IP Address: ")) return output;
|
||||
|
||||
stringified = stringified.trim().substring(" - IP Address: ".length());
|
||||
if (stringified.startsWith("/")) stringified = stringified.substring(1);
|
||||
|
||||
outputFuture.complete(stringified);
|
||||
|
||||
return output;
|
||||
});
|
||||
|
||||
return outputFuture;
|
||||
}
|
||||
|
||||
public final PlayerEntry getEntry (UUID uuid) {
|
||||
for (PlayerEntry candidate : list) {
|
||||
if (candidate.profile.getId().equals(uuid)) {
|
||||
|
@ -164,7 +192,7 @@ public class PlayersPlugin extends Bot.Listener {
|
|||
final PlayerEntry target = getEntry(uuid);
|
||||
if (target == null) return;
|
||||
|
||||
bot.tabComplete.tabComplete("/minecraft:scoreboard players add ").thenApply(packet -> {
|
||||
bot.tabComplete.tabComplete("/minecraft:scoreboard players add ").thenApplyAsync(packet -> {
|
||||
final String[] matches = packet.getMatches();
|
||||
final Component[] tooltips = packet.getTooltips();
|
||||
final String username = target.profile.getName();
|
||||
|
|
|
@ -30,6 +30,8 @@ public class PositionPlugin extends Bot.Listener {
|
|||
|
||||
public Vector3i position = Vector3i.from(0, 0, 0);
|
||||
|
||||
public boolean isGoingDownFromHeightLimit = false; // cool variable name
|
||||
|
||||
private final Map<Integer, PlayerEntry> entityIdMap = new HashMap<>();
|
||||
private final Map<Integer, Vector3f> positionMap = new HashMap<>();
|
||||
private final Map<Integer, Rotation> rotationMap = new HashMap<>();
|
||||
|
@ -40,12 +42,23 @@ public class PositionPlugin extends Bot.Listener {
|
|||
bot.addListener(this);
|
||||
|
||||
// notchian clients also does this, sends the position packet every second
|
||||
bot.executor.scheduleAtFixedRate(() -> bot.session.send(new ServerboundMovePlayerPosPacket(
|
||||
false,
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ()
|
||||
)), 0, 1, TimeUnit.SECONDS);
|
||||
bot.executor.scheduleAtFixedRate(() -> {
|
||||
if (isGoingDownFromHeightLimit) return;
|
||||
|
||||
bot.session.send(new ServerboundMovePlayerPosPacket(
|
||||
false,
|
||||
position.getX(),
|
||||
position.getY(),
|
||||
position.getZ()
|
||||
));
|
||||
}, 0, 1, TimeUnit.SECONDS);
|
||||
|
||||
bot.tick.addListener(new TickPlugin.Listener() {
|
||||
@Override
|
||||
public void onTick() {
|
||||
handleHeightLimit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -145,6 +158,52 @@ public class PositionPlugin extends Bot.Listener {
|
|||
for (Listener listener : listeners) listener.playerMoved(player, position, rotation);
|
||||
}
|
||||
|
||||
// for now this is used in CorePlugin when placing the command block
|
||||
private void handleHeightLimit () {
|
||||
final int y = position.getY();
|
||||
final int minY = bot.world.minY;
|
||||
final int maxY = bot.world.maxY;
|
||||
|
||||
if (y < maxY) {
|
||||
if (isGoingDownFromHeightLimit) {
|
||||
isGoingDownFromHeightLimit = false;
|
||||
|
||||
for (Listener listener : listeners) { listener.positionChange(position); }
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
isGoingDownFromHeightLimit = true;
|
||||
|
||||
final Vector3i newPosition = Vector3i.from(
|
||||
position.getX(),
|
||||
position.getY() - 2,
|
||||
position.getZ()
|
||||
);
|
||||
|
||||
position = newPosition;
|
||||
|
||||
if (position.getY() > maxY + 500 || position.getY() < minY) {
|
||||
String command = "/";
|
||||
|
||||
if (bot.serverPluginsManager.hasPlugin(ServerPluginsManagerPlugin.ESSENTIALS)) command += "essentials:";
|
||||
|
||||
command += String.format("tp ~ %s ~", maxY - 1);
|
||||
|
||||
bot.chat.send(command);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bot.session.send(new ServerboundMovePlayerPosPacket(
|
||||
false,
|
||||
newPosition.getX(),
|
||||
newPosition.getY(),
|
||||
newPosition.getZ()
|
||||
));
|
||||
}
|
||||
|
||||
public Vector3f getPlayerPosition (String playerName) {
|
||||
int entityId = -1;
|
||||
for (Map.Entry<Integer, PlayerEntry> entry : entityIdMap.entrySet()) {
|
||||
|
|
|
@ -27,7 +27,7 @@ public class ServerPluginsManagerPlugin extends Bot.Listener {
|
|||
public void connected(ConnectedEvent event) {
|
||||
final CompletableFuture<ClientboundCommandSuggestionsPacket> future = bot.tabComplete.tabComplete("/ver ");
|
||||
|
||||
future.thenApply((packet) -> {
|
||||
future.thenApplyAsync((packet) -> {
|
||||
final String[] matches = packet.getMatches();
|
||||
|
||||
// should i just use the plugins as the String array instead of a list?
|
||||
|
|
|
@ -13,7 +13,7 @@ public class TagPlugin extends CorePlugin.Listener {
|
|||
public TagPlugin (Bot bot) {
|
||||
this.bot = bot;
|
||||
|
||||
bot.executor.scheduleAtFixedRate(this::runCommand, 5, 20, TimeUnit.SECONDS);
|
||||
bot.executor.scheduleAtFixedRate(this::runCommand, 5, 30, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
private void runCommand () {
|
||||
|
|
|
@ -18,11 +18,25 @@ public class TickPlugin {
|
|||
}
|
||||
|
||||
private void tick () {
|
||||
for (Listener listener : listeners) listener.onAlwaysTick();
|
||||
for (Listener listener : listeners) {
|
||||
try {
|
||||
listener.onAlwaysTick();
|
||||
} catch (Exception e) {
|
||||
bot.logger.error("Caught exception in an always tick listener!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (!bot.loggedIn) return;
|
||||
|
||||
for (Listener listener : listeners) listener.onTick();
|
||||
for (Listener listener : listeners) {
|
||||
try {
|
||||
listener.onTick();
|
||||
} catch (Exception e) {
|
||||
bot.logger.error("Caught exception in a tick listener!");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addListener (Listener listener) {
|
||||
|
|
|
@ -5,10 +5,9 @@ import me.chayapak1.chomens_bot.data.PlayerEntry;
|
|||
import me.chayapak1.chomens_bot.util.ColorUtilities;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.format.DateTimeFormat;
|
||||
import org.joda.time.format.DateTimeFormatter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
|
@ -64,10 +63,10 @@ public class TrustedPlugin extends PlayersPlugin.Listener {
|
|||
Component.text(target.profile.getName()).color(ColorUtilities.getColorByString(bot.config.colorPalette.username))
|
||||
).color(NamedTextColor.GREEN);
|
||||
} else {
|
||||
final DateTime now = DateTime.now();
|
||||
final LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
final DateTimeFormatter formatter = DateTimeFormat.forPattern("hh:mm:ss a");
|
||||
final String formattedTime = formatter.print(now);
|
||||
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm:ss a");
|
||||
final String formattedTime = now.format(formatter);
|
||||
|
||||
component = Component.translatable(
|
||||
"""
|
||||
|
|
|
@ -58,7 +58,7 @@ public class VoiceChatPlugin extends Bot.Listener {
|
|||
|
||||
bot.session.send(new ServerboundCustomPayloadPacket(
|
||||
Key.key("voicechat:request_secret"),
|
||||
new FriendlyByteBuf(Unpooled.buffer()).writeInt(17).array()
|
||||
new FriendlyByteBuf(Unpooled.buffer()).writeInt(18).array()
|
||||
));
|
||||
|
||||
bot.session.send(new ServerboundCustomPayloadPacket(
|
||||
|
|
|
@ -51,13 +51,7 @@ public class WhitelistPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
public void add (String player) { list.add(player); }
|
||||
public void remove (String player) {
|
||||
list.removeIf(eachPlayer -> eachPlayer.equals(player));
|
||||
|
||||
final PlayerEntry entry = bot.players.getEntry(player);
|
||||
|
||||
if (entry != null) handle(entry);
|
||||
}
|
||||
public String remove (int index) { return list.remove(index); }
|
||||
public void clear () {
|
||||
list.removeIf(eachPlayer -> !eachPlayer.equals(bot.profile.getName()));
|
||||
}
|
||||
|
@ -72,7 +66,7 @@ public class WhitelistPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
public void commandReceived (PlayerEntry entry, String command) {
|
||||
if (!enabled || list.contains(entry.profile.getName())) return;
|
||||
if (!enabled || list.contains(entry.profile.getName()) || entry.profile.equals(bot.profile)) return;
|
||||
|
||||
if (
|
||||
command.startsWith("mute") ||
|
||||
|
@ -90,7 +84,7 @@ public class WhitelistPlugin extends PlayersPlugin.Listener {
|
|||
}
|
||||
|
||||
private void handle (PlayerEntry entry) {
|
||||
if (!enabled || list.contains(entry.profile.getName())) return;
|
||||
if (!enabled || list.contains(entry.profile.getName()) || entry.profile.equals(bot.profile)) return;
|
||||
|
||||
bot.filter.doAll(entry);
|
||||
}
|
||||
|
|
|
@ -34,14 +34,17 @@ public class WorldPlugin extends Bot.Listener {
|
|||
private void worldChanged (String dimension) {
|
||||
final RegistryEntry currentDimension = registry.stream()
|
||||
.filter(eachDimension -> eachDimension.getId().asString().equals(dimension))
|
||||
.toArray(RegistryEntry[]::new)[0];
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
if (currentDimension == null) return;
|
||||
|
||||
final NbtMap data = currentDimension.getData();
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
minY = data.getInt("min_y");
|
||||
maxY = data.getInt("height");
|
||||
maxY = data.getInt("height") + minY;
|
||||
|
||||
for (Listener listener : listeners) listener.worldChanged(dimension);
|
||||
}
|
||||
|
|
|
@ -215,7 +215,8 @@ public class MidiConverter implements Converter {
|
|||
|
||||
shiftedInstrument = Arrays.stream(instrumentList)
|
||||
.filter(ins -> ins.offset == closest)
|
||||
.toArray(Instrument[]::new)[0];
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -278,14 +278,14 @@ public class NBSConverter implements Converter {
|
|||
private static final Map<String, String> subtitles = new HashMap<>();
|
||||
|
||||
static {
|
||||
for (Map.Entry<String, String> entry : ComponentUtilities.englishLanguage.entrySet()) {
|
||||
for (Map.Entry<String, String> entry : ComponentUtilities.language.entrySet()) {
|
||||
if (!entry.getKey().startsWith("subtitles.")) continue;
|
||||
|
||||
subtitles.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> sounds = loadJsonStringArray("sounds.json");
|
||||
private static final List<String> sounds = loadJsonStringArray("sounds.json");
|
||||
|
||||
private static List<String> loadJsonStringArray (String name) {
|
||||
List<String> list = new ArrayList<>();
|
||||
|
|
|
@ -17,7 +17,7 @@ public class Song {
|
|||
public long startTime = 0; // Start time in millis since unix epoch
|
||||
public long length = 0; // Milliseconds in the song
|
||||
public long time = 0; // Time since start of song
|
||||
public long loopPosition = 200; // Milliseconds into the song to start looping
|
||||
public long loopPosition = 0; // Milliseconds into the song to start looping
|
||||
|
||||
public final Map<Long, String> lyrics = new HashMap<>();
|
||||
|
||||
|
@ -80,7 +80,7 @@ public class Song {
|
|||
*/
|
||||
public void play () {
|
||||
if (paused) {
|
||||
if (loopPosition != 200) bot.music.loop = Loop.CURRENT;
|
||||
if (loopPosition != 0) bot.music.loop = Loop.CURRENT;
|
||||
paused = false;
|
||||
startTime = System.currentTimeMillis() - time;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package me.chayapak1.chomens_bot.song;
|
||||
|
||||
import me.chayapak1.chomens_bot.Bot;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
@ -46,7 +47,7 @@ public class SongPlayerConverter implements Converter {
|
|||
song.length = songLength;
|
||||
// song.looping = loop > 0;
|
||||
// song.loopCount = loopCount;
|
||||
song.loopPosition = loopPosition == 0 ? 200 : loopPosition;
|
||||
song.loopPosition = loopPosition;
|
||||
|
||||
long time = 0;
|
||||
while (true) {
|
||||
|
@ -107,12 +108,12 @@ public class SongPlayerConverter implements Converter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[]) throws IOException {
|
||||
public int read(byte @NotNull [] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
public int read(byte @NotNull [] b, int off, int len) throws IOException {
|
||||
int i = original.read(b, off, len);
|
||||
if (i>=0) incrementCounter(i);
|
||||
return i;
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
package me.chayapak1.chomens_bot.util;
|
||||
|
||||
public class ArrayUtilities {
|
||||
public static boolean isAllTrue (boolean[] array) {
|
||||
for (boolean value : array) if (!value) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -26,7 +26,6 @@ public class ComponentUtilities {
|
|||
|
||||
// component parsing
|
||||
public static final Map<String, String> language = loadJsonStringMap("language.json");
|
||||
public static final Map<String, String> englishLanguage = loadJsonStringMap("englishLanguage.json");
|
||||
private static final Map<String, String> voiceChatLanguage = loadJsonStringMap("voiceChatLanguage.json");
|
||||
private static final Map<String, String> keybinds = loadJsonStringMap("keybinds.json");
|
||||
|
||||
|
@ -64,9 +63,6 @@ public class ComponentUtilities {
|
|||
String lastColor
|
||||
) {}
|
||||
|
||||
private ComponentUtilities () {
|
||||
}
|
||||
|
||||
private static Map<String, String> loadJsonStringMap (String name) {
|
||||
Map<String, String> map = new HashMap<>();
|
||||
|
||||
|
@ -81,13 +77,15 @@ public class ComponentUtilities {
|
|||
return map;
|
||||
}
|
||||
|
||||
private static String getOrReturnKey (String key) {
|
||||
private static String getOrReturnFallback (TranslatableComponent component) {
|
||||
final String key = component.key();
|
||||
|
||||
final String minecraftKey = language.get(key);
|
||||
final String voiceChatKey = voiceChatLanguage.get(key);
|
||||
|
||||
if (minecraftKey != null) return minecraftKey;
|
||||
else if (voiceChatKey != null) return voiceChatKey;
|
||||
else return key;
|
||||
else return component.fallback() != null ? component.fallback() : key;
|
||||
}
|
||||
|
||||
public static String stringify (Component message) { return stringify(message, null); }
|
||||
|
@ -264,7 +262,7 @@ public class ComponentUtilities {
|
|||
}
|
||||
|
||||
public static PartiallyStringified stringifyPartially (TranslatableComponent message, boolean motd, boolean ansi, String lastColor, boolean noHex) {
|
||||
String format = getOrReturnKey(message.key());
|
||||
String format = getOrReturnFallback(message);
|
||||
|
||||
// totallynotskidded™️ from HBot (and changed a bit)
|
||||
Matcher matcher = ARG_PATTERN.matcher(format);
|
||||
|
@ -278,6 +276,8 @@ public class ComponentUtilities {
|
|||
|
||||
int i = 0;
|
||||
while (matcher.find()) {
|
||||
if (i > 300) break;
|
||||
|
||||
if (matcher.group().equals("%%")) {
|
||||
matcher.appendReplacement(sb, "%");
|
||||
} else {
|
||||
|
@ -317,7 +317,7 @@ public class ComponentUtilities {
|
|||
|
||||
public static PartiallyStringified stringifyPartially (KeybindComponent message, boolean motd, boolean ansi, String lastColor, boolean noHex) {
|
||||
String keybind = message.keybind();
|
||||
Component component = keybinds.containsKey(keybind) ? Component.translatable(keybind) : Component.text(keybind); // TODO: Fix some keys like `key.keyboard.a`
|
||||
Component component = keybinds.containsKey(keybind) ? Component.translatable(keybinds.get(keybind)) : Component.text(keybind);
|
||||
return stringifyPartially(component, motd, ansi, lastColor, noHex);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,10 +2,8 @@ package me.chayapak1.chomens_bot.util;
|
|||
|
||||
import me.chayapak1.chomens_bot.Main;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
@ -17,12 +15,13 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
// totallynotskidded™ from HBot
|
||||
// original source code from hhhzzzsss, specifically HBot.
|
||||
// source: https://github.com/hhhzzzsss/HBot-Release/blob/main/src/main/java/com/github/hhhzzzsss/hbot/Logger.java
|
||||
public class FileLoggerUtilities {
|
||||
public static final Path logDirectory = Path.of("logs");
|
||||
public static final Path logPath = Paths.get(logDirectory.toString(), "log.txt");
|
||||
|
||||
public static BufferedWriter logWriter;
|
||||
public static OutputStreamWriter logWriter;
|
||||
|
||||
public static LocalDate currentLogDate;
|
||||
public static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("'['dd/MM/yyyy HH:mm:ss']' ");
|
||||
|
@ -78,56 +77,49 @@ public class FileLoggerUtilities {
|
|||
}
|
||||
}
|
||||
|
||||
public static void makeNewLogFile() throws IOException {
|
||||
public static synchronized void makeNewLogFile() throws IOException {
|
||||
currentLogDate = LocalDate.now();
|
||||
|
||||
if (!Files.exists(logPath)) Files.createFile(logPath);
|
||||
|
||||
logWriter = Files.newBufferedWriter(logPath, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
logWriter = new OutputStreamWriter(Files.newOutputStream(logPath, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING), StandardCharsets.UTF_8);
|
||||
logWriter.write(currentLogDate.toString() + '\n');
|
||||
logWriter.flush();
|
||||
}
|
||||
|
||||
public static void openLogFile() throws IOException {
|
||||
public static synchronized void openLogFile() throws IOException {
|
||||
currentLogDate = LocalDate.parse(getLogDate(logPath));
|
||||
logWriter = Files.newBufferedWriter(logPath, StandardOpenOption.APPEND);
|
||||
logWriter = new OutputStreamWriter(Files.newOutputStream(logPath, StandardOpenOption.CREATE, StandardOpenOption.APPEND), StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static void compressLogFile() throws IOException {
|
||||
public static synchronized void compressLogFile() throws IOException {
|
||||
if (Files.size(logPath) > 100 * 1024 * 1024) { // Will not save because log file is too big
|
||||
return;
|
||||
}
|
||||
|
||||
final Path path = Paths.get(logDirectory.toString(), getLogDate(logPath) + ".txt.gz");
|
||||
|
||||
Files.createFile(path);
|
||||
|
||||
InputStream in = Files.newInputStream(logPath);
|
||||
GZIPOutputStream out = new GZIPOutputStream(Files.newOutputStream(path));
|
||||
|
||||
byte[] buffer = new byte[1024];
|
||||
int size;
|
||||
while ((size = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, size);
|
||||
try (
|
||||
final InputStream in = Files.newInputStream(logPath, StandardOpenOption.READ);
|
||||
final GZIPOutputStream out = new GZIPOutputStream(Files.newOutputStream(path, StandardOpenOption.CREATE))
|
||||
) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int size;
|
||||
while ((size = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, size);
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
out.finish();
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static String getLogDate(Path path) throws IOException {
|
||||
BufferedReader reader = Files.newBufferedReader(path);
|
||||
String date = reader.readLine();
|
||||
reader.close();
|
||||
return date;
|
||||
public static synchronized String getLogDate (Path filePath) throws IOException {
|
||||
try (final BufferedReader reader = Files.newBufferedReader(filePath, StandardCharsets.UTF_8)) {
|
||||
return reader.readLine();
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean logIsCurrent(Path path) throws IOException {
|
||||
public static synchronized boolean logIsCurrent(Path path) throws IOException {
|
||||
LocalDate date = LocalDate.now();
|
||||
return getLogDate(path).equals(date.toString());
|
||||
}
|
||||
|
||||
public static void log(String str) {
|
||||
public static synchronized void log(String str) {
|
||||
if (freezeTime > System.currentTimeMillis()) {
|
||||
return;
|
||||
}
|
||||
|
@ -161,8 +153,7 @@ public class FileLoggerUtilities {
|
|||
logWriter.write("\n");
|
||||
}
|
||||
|
||||
if (str.length() > 32767) logWriter.write("Message too big, not logging this message"); // should these stuff be hardcoded?
|
||||
else logWriter.write(getTimePrefix() + str.replaceAll("\\[(\\d+?)x](?=$|[\r\n])", "[/$1x]")); // the replaceAll will prevent conflicts with the duplicate counter
|
||||
logWriter.write(getTimePrefix() + str.replaceAll("\\[(\\d+?)x](?=$|[\r\n])", "[/$1x]")); // the replaceAll will prevent conflicts with the duplicate counter
|
||||
logWriter.flush();
|
||||
|
||||
duplicateCounter = 1;
|
||||
|
|
|
@ -38,6 +38,8 @@ public class LoggerUtilities {
|
|||
}
|
||||
|
||||
public static void log (String message) { log(null, message, true, true); }
|
||||
public static void log (Component message) { log(null, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void log (Bot bot, Component message) { log(bot, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void log (Bot bot, String message) { log(bot, message, true, true); }
|
||||
public static void log (Bot bot, String message, boolean logToFile, boolean logToConsole) {
|
||||
final String component = prefix(bot, Component.text("Log").color(NamedTextColor.GOLD), message);
|
||||
|
@ -58,6 +60,8 @@ public class LoggerUtilities {
|
|||
}
|
||||
|
||||
public static void info (String message) { info(null, message); }
|
||||
public static void info (Component message) { info(null, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void info (Bot bot, Component message) { info(bot, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void info (Bot bot, String message) {
|
||||
final String component = prefix(bot, Component.text("Info").color(NamedTextColor.GREEN), message);
|
||||
|
||||
|
@ -66,6 +70,8 @@ public class LoggerUtilities {
|
|||
}
|
||||
|
||||
public static void error (String message) { error(null, message); }
|
||||
public static void error (Component message) { error(null, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void error (Bot bot, Component message) { error(bot, ComponentUtilities.stringifyAnsi(message)); }
|
||||
public static void error (Bot bot, String message) {
|
||||
final String component = prefix(bot, Component.text("Error").color(NamedTextColor.RED), message);
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.google.gson.Gson;
|
|||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import me.chayapak1.chomens_bot.Main;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
|
@ -12,101 +11,95 @@ import java.io.IOException;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class PersistentDataUtilities {
|
||||
public static final Path path = Path.of("persistent.json");
|
||||
private static final Path path = Path.of("persistent.json");
|
||||
|
||||
private static BufferedWriter writer;
|
||||
private static final Gson gson = new Gson();
|
||||
|
||||
public static JsonObject jsonObject = new JsonObject();
|
||||
private static JsonObject jsonObject = new JsonObject();
|
||||
|
||||
private static final Map<String, JsonElement> queue = new ConcurrentHashMap<>();
|
||||
private static final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final ScheduledFuture<?> future;
|
||||
private static volatile boolean stopping = false;
|
||||
|
||||
static {
|
||||
init();
|
||||
public static void init () {
|
||||
lock.lock();
|
||||
|
||||
future = Main.executor.scheduleAtFixedRate(() -> {
|
||||
try {
|
||||
if (queue.isEmpty()) return;
|
||||
|
||||
final Map.Entry<String, JsonElement> entry = queue.entrySet().iterator().next(); // is this the best way to get the first item of the map?
|
||||
|
||||
final String property = entry.getKey();
|
||||
final JsonElement value = entry.getValue();
|
||||
|
||||
Main.executorService.submit(() -> {
|
||||
jsonObject.add(property, value);
|
||||
|
||||
write(jsonObject.toString());
|
||||
|
||||
queue.remove(property);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}, 0, 100, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private static void init () {
|
||||
try {
|
||||
if (!Files.exists(path)) Files.createFile(path);
|
||||
|
||||
// loads the persistent data from the last session
|
||||
else {
|
||||
final BufferedReader reader = Files.newBufferedReader(path);
|
||||
|
||||
final Gson gson = new Gson();
|
||||
|
||||
jsonObject = gson.fromJson(reader, JsonObject.class);
|
||||
if (Files.exists(path)) {
|
||||
try (BufferedReader reader = Files.newBufferedReader(path)) {
|
||||
jsonObject = gson.fromJson(reader, JsonObject.class);
|
||||
}
|
||||
} else {
|
||||
Files.createFile(path);
|
||||
}
|
||||
|
||||
writer = Files.newBufferedWriter(path, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private static void write (String string) {
|
||||
private static synchronized void writeToFile() {
|
||||
if (stopping) return;
|
||||
|
||||
lock.lock();
|
||||
|
||||
try (BufferedWriter writer = Files.newBufferedWriter(path, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING)) {
|
||||
writer.write(gson.toJson(jsonObject));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void stop () {
|
||||
stopping = true;
|
||||
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
writer.close();
|
||||
|
||||
// ? how do i clear the file contents without making a completely new writer?
|
||||
// or is this the only way?
|
||||
writer = Files.newBufferedWriter(path, StandardOpenOption.TRUNCATE_EXISTING);
|
||||
|
||||
writer.write(string);
|
||||
writer.flush();
|
||||
} catch (IOException ignored) {}
|
||||
writeToFile();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void stop () {
|
||||
future.cancel(false);
|
||||
write(jsonObject.toString());
|
||||
public static synchronized boolean has (String property) {
|
||||
return jsonObject.has(property);
|
||||
}
|
||||
|
||||
public static void put (String property, JsonElement value) {
|
||||
Main.executorService.submit(() -> queue.put(property, value));
|
||||
public static synchronized JsonElement get (String property) {
|
||||
return jsonObject.get(property);
|
||||
}
|
||||
|
||||
public static void put (String property, String value) {
|
||||
Main.executorService.submit(() -> queue.put(property, new JsonPrimitive(value)));
|
||||
public static synchronized void put (String property, JsonElement value) {
|
||||
lock.lock();
|
||||
|
||||
try {
|
||||
jsonObject.add(property, value);
|
||||
writeToFile();
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public static void put (String property, boolean value) {
|
||||
Main.executorService.submit(() -> queue.put(property, new JsonPrimitive(value)));
|
||||
public static synchronized void put (String property, String value) {
|
||||
put(property, new JsonPrimitive(value));
|
||||
}
|
||||
|
||||
public static void put (String property, int value) {
|
||||
Main.executorService.submit(() -> queue.put(property, new JsonPrimitive(value)));
|
||||
public static synchronized void put (String property, boolean value) {
|
||||
put(property, new JsonPrimitive(value));
|
||||
}
|
||||
|
||||
public static void put (String property, char value) {
|
||||
Main.executorService.submit(() -> queue.put(property, new JsonPrimitive(value)));
|
||||
public static synchronized void put (String property, int value) {
|
||||
put(property, new JsonPrimitive(value));
|
||||
}
|
||||
|
||||
public static synchronized void put (String property, char value) {
|
||||
put(property, new JsonPrimitive(value));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@ public class JavaOpusEncoder {
|
|||
|
||||
public static OpusApplication getApplication(de.maxhenkel.opus4j.OpusEncoder.Application application) {
|
||||
return switch (application) {
|
||||
default -> OpusApplication.OPUS_APPLICATION_VOIP;
|
||||
case AUDIO -> OpusApplication.OPUS_APPLICATION_AUDIO;
|
||||
case LOW_DELAY -> OpusApplication.OPUS_APPLICATION_RESTRICTED_LOWDELAY;
|
||||
default -> OpusApplication.OPUS_APPLICATION_VOIP;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
4
src/main/resources/application.properties
Normal file
4
src/main/resources/application.properties
Normal file
|
@ -0,0 +1,4 @@
|
|||
build.date=${compileDate}
|
||||
build.git.commit.count=${gitCommitCount}
|
||||
build.git.commit.hash=${gitCommitHash}
|
||||
build.number=${buildNumber}
|
|
@ -9,33 +9,34 @@ commandSpyPrefixes:
|
|||
|
||||
consoleCommandPrefix: '.'
|
||||
|
||||
internetCheck:
|
||||
enabled: true
|
||||
address: 'https://sus.red'
|
||||
|
||||
# how backup works is that it checks for the address every 1 minute,
|
||||
# how backup works is that it makes a http request for the address
|
||||
# if the address is reachable it will not start the bot
|
||||
# if the address is not reachable then it will start the bot
|
||||
#
|
||||
|
||||
# *** it doesn't care about the status code
|
||||
|
||||
# if the bot has already been started and the address is back up it
|
||||
# will stop the bot (using System.exit(1))
|
||||
# will stop the bot
|
||||
backup:
|
||||
enabled: false
|
||||
address: 'https://fard.sex/check'
|
||||
interval: 1000 # in milliseconds
|
||||
failTimes: 2
|
||||
|
||||
discord:
|
||||
enabled: false
|
||||
prefix: 'default!'
|
||||
token: 'token here'
|
||||
trustedRoleName: 'Trusted'
|
||||
adminRoleName: 'Admin' # NOTE: admin will be able to access servereval..
|
||||
adminRoleName: 'Admin'
|
||||
ownerRoleName: 'Owner'
|
||||
statusMessage: 'Say Gex'
|
||||
inviteLink: 'https://discord.gg/xdgCkUyaA4'
|
||||
servers:
|
||||
localhost:25565: 'channel id'
|
||||
|
||||
irc:
|
||||
enabled: true
|
||||
enabled: false
|
||||
prefix: '!'
|
||||
host: 'irc.libera.chat'
|
||||
port: 6665
|
||||
|
@ -59,7 +60,8 @@ colorPalette:
|
|||
number: 'gold'
|
||||
ownerName: 'green'
|
||||
|
||||
ownerName: 'chayapak' # currently this is only used in the console
|
||||
# you HAVE TO CHANGE THIS if you are hosting another instance of my bot.
|
||||
ownerName: 'XxChange_mexX'
|
||||
|
||||
imposterFormatChecker:
|
||||
enabled: false
|
||||
|
@ -74,8 +76,9 @@ trusted:
|
|||
- 'player name'
|
||||
|
||||
keys:
|
||||
normalKey: 'normal hash key here'
|
||||
ownerKey: 'OwnerHash™ key here'
|
||||
trustedKey: 'trusted key here'
|
||||
adminKey: 'admin key here'
|
||||
ownerKey: 'owner key here'
|
||||
|
||||
weatherApiKey: 'key here' # weatherapi.com key
|
||||
|
||||
|
@ -130,7 +133,8 @@ bots:
|
|||
# username - optional, if not specified it will just use a random username
|
||||
# creayun - defaults to false
|
||||
# serverName - name it whatever you like, it will be used as server name in trusted broadcast and in console
|
||||
# useCore - if enabled it just sends the command using chat instead of using core. recommended to enable useChat too when this is enabled
|
||||
# useCore - if enabled it just sends the command using chat instead of using core. recommended to enable useChat too when this is disabled
|
||||
# useCorePlaceBlock - uses the place block core instead of the main core. only used if useCore is enabled
|
||||
# useChat - when the bot tellraws it will chat instead of using the core to run tellraw
|
||||
# coreCommandSpy - set to true if server supports enabling player's commandspy though command block
|
||||
# resolveSRV - whether to resolve SRV records on the server. the notchian minecraft doesn't resolve them
|
||||
|
@ -139,22 +143,23 @@ bots:
|
|||
|
||||
- host: 'localhost'
|
||||
port: 25565
|
||||
username: 'ChomeNS_Bot'
|
||||
creayun: false
|
||||
serverName: 'Localhost'
|
||||
useCore: true
|
||||
useChat: false
|
||||
coreCommandSpy: false
|
||||
resolveSRV: true
|
||||
reconnectDelay: 2000
|
||||
removeNamespaces: false
|
||||
chatQueueDelay: 125
|
||||
coreRateLimit:
|
||||
limit: 10
|
||||
reset: 1000 # in milliseconds
|
||||
# or without the optional ones:
|
||||
# or with the optional ones
|
||||
# - host: 'localhost'
|
||||
# port: 25565
|
||||
# username: 'ChomeNS_Bot'
|
||||
# creayun: false
|
||||
# serverName: 'Localhost'
|
||||
# useCore: true
|
||||
# useCorePlaceBlock: false
|
||||
# useChat: false
|
||||
# coreCommandSpy: false
|
||||
# resolveSRV: true
|
||||
# reconnectDelay: 2000
|
||||
# removeNamespaces: false
|
||||
# chatQueueDelay: 125
|
||||
# coreRateLimit:
|
||||
# limit: 10
|
||||
# reset: 1000 # in milliseconds
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -33,6 +33,7 @@
|
|||
"block.amethyst_block.fall",
|
||||
"block.amethyst_block.hit",
|
||||
"block.amethyst_block.place",
|
||||
"block.amethyst_block.resonate",
|
||||
"block.amethyst_block.step",
|
||||
"block.amethyst_cluster.break",
|
||||
"block.amethyst_cluster.fall",
|
||||
|
@ -52,6 +53,19 @@
|
|||
"block.anvil.place",
|
||||
"block.anvil.step",
|
||||
"block.anvil.use",
|
||||
"entity.armadillo.eat",
|
||||
"entity.armadillo.hurt",
|
||||
"entity.armadillo.hurt_reduced",
|
||||
"entity.armadillo.ambient",
|
||||
"entity.armadillo.step",
|
||||
"entity.armadillo.death",
|
||||
"entity.armadillo.roll",
|
||||
"entity.armadillo.land",
|
||||
"entity.armadillo.scute_drop",
|
||||
"entity.armadillo.unroll_finish",
|
||||
"entity.armadillo.peek",
|
||||
"entity.armadillo.unroll_start",
|
||||
"entity.armadillo.brush",
|
||||
"item.armor.equip_chain",
|
||||
"item.armor.equip_diamond",
|
||||
"item.armor.equip_elytra",
|
||||
|
@ -61,6 +75,8 @@
|
|||
"item.armor.equip_leather",
|
||||
"item.armor.equip_netherite",
|
||||
"item.armor.equip_turtle",
|
||||
"item.armor.equip_wolf",
|
||||
"item.armor.unequip_wolf",
|
||||
"entity.armor_stand.break",
|
||||
"entity.armor_stand.fall",
|
||||
"entity.armor_stand.hit",
|
||||
|
@ -152,6 +168,11 @@
|
|||
"entity.blaze.shoot",
|
||||
"entity.boat.paddle_land",
|
||||
"entity.boat.paddle_water",
|
||||
"entity.bogged.ambient",
|
||||
"entity.bogged.death",
|
||||
"entity.bogged.hurt",
|
||||
"entity.bogged.shear",
|
||||
"entity.bogged.step",
|
||||
"block.bone_block.break",
|
||||
"block.bone_block.fall",
|
||||
"block.bone_block.hit",
|
||||
|
@ -164,9 +185,25 @@
|
|||
"item.bottle.empty",
|
||||
"item.bottle.fill",
|
||||
"item.bottle.fill_dragonbreath",
|
||||
"entity.breeze.charge",
|
||||
"entity.breeze.deflect",
|
||||
"entity.breeze.inhale",
|
||||
"entity.breeze.idle_ground",
|
||||
"entity.breeze.idle_air",
|
||||
"entity.breeze.shoot",
|
||||
"entity.breeze.jump",
|
||||
"entity.breeze.land",
|
||||
"entity.breeze.slide",
|
||||
"entity.breeze.death",
|
||||
"entity.breeze.hurt",
|
||||
"entity.breeze.whirl",
|
||||
"entity.breeze.wind_burst",
|
||||
"block.brewing_stand.brew",
|
||||
"item.brush.brushing",
|
||||
"item.brush.brush_sand_completed",
|
||||
"item.brush.brushing.generic",
|
||||
"item.brush.brushing.sand",
|
||||
"item.brush.brushing.gravel",
|
||||
"item.brush.brushing.sand.complete",
|
||||
"item.brush.brushing.gravel.complete",
|
||||
"block.bubble_column.bubble_pop",
|
||||
"block.bubble_column.upwards_ambient",
|
||||
"block.bubble_column.upwards_inside",
|
||||
|
@ -282,6 +319,11 @@
|
|||
"block.chorus_flower.death",
|
||||
"block.chorus_flower.grow",
|
||||
"item.chorus_fruit.teleport",
|
||||
"block.cobweb.break",
|
||||
"block.cobweb.step",
|
||||
"block.cobweb.place",
|
||||
"block.cobweb.hit",
|
||||
"block.cobweb.fall",
|
||||
"entity.cod.ambient",
|
||||
"entity.cod.death",
|
||||
"entity.cod.flop",
|
||||
|
@ -296,11 +338,27 @@
|
|||
"block.conduit.ambient.short",
|
||||
"block.conduit.attack.target",
|
||||
"block.conduit.deactivate",
|
||||
"block.copper_bulb.break",
|
||||
"block.copper_bulb.step",
|
||||
"block.copper_bulb.place",
|
||||
"block.copper_bulb.hit",
|
||||
"block.copper_bulb.fall",
|
||||
"block.copper_bulb.turn_on",
|
||||
"block.copper_bulb.turn_off",
|
||||
"block.copper.break",
|
||||
"block.copper.step",
|
||||
"block.copper.place",
|
||||
"block.copper.hit",
|
||||
"block.copper.fall",
|
||||
"block.copper_door.close",
|
||||
"block.copper_door.open",
|
||||
"block.copper_grate.break",
|
||||
"block.copper_grate.step",
|
||||
"block.copper_grate.place",
|
||||
"block.copper_grate.hit",
|
||||
"block.copper_grate.fall",
|
||||
"block.copper_trapdoor.close",
|
||||
"block.copper_trapdoor.open",
|
||||
"block.coral_block.break",
|
||||
"block.coral_block.fall",
|
||||
"block.coral_block.hit",
|
||||
|
@ -311,6 +369,8 @@
|
|||
"entity.cow.hurt",
|
||||
"entity.cow.milk",
|
||||
"entity.cow.step",
|
||||
"block.crafter.craft",
|
||||
"block.crafter.fail",
|
||||
"entity.creeper.death",
|
||||
"entity.creeper.hurt",
|
||||
"entity.creeper.primed",
|
||||
|
@ -327,6 +387,8 @@
|
|||
"block.decorated_pot.break",
|
||||
"block.decorated_pot.fall",
|
||||
"block.decorated_pot.hit",
|
||||
"block.decorated_pot.insert",
|
||||
"block.decorated_pot.insert_fail",
|
||||
"block.decorated_pot.step",
|
||||
"block.decorated_pot.place",
|
||||
"block.decorated_pot.shatter",
|
||||
|
@ -364,6 +426,7 @@
|
|||
"entity.donkey.death",
|
||||
"entity.donkey.eat",
|
||||
"entity.donkey.hurt",
|
||||
"entity.donkey.jump",
|
||||
"block.dripstone_block.break",
|
||||
"block.dripstone_block.step",
|
||||
"block.dripstone_block.place",
|
||||
|
@ -477,6 +540,11 @@
|
|||
"block.suspicious_sand.place",
|
||||
"block.suspicious_sand.hit",
|
||||
"block.suspicious_sand.fall",
|
||||
"block.suspicious_gravel.break",
|
||||
"block.suspicious_gravel.step",
|
||||
"block.suspicious_gravel.place",
|
||||
"block.suspicious_gravel.hit",
|
||||
"block.suspicious_gravel.fall",
|
||||
"block.froglight.break",
|
||||
"block.froglight.fall",
|
||||
"block.froglight.hit",
|
||||
|
@ -589,6 +657,11 @@
|
|||
"block.hanging_sign.fall",
|
||||
"block.hanging_sign.hit",
|
||||
"block.hanging_sign.place",
|
||||
"block.heavy_core.break",
|
||||
"block.heavy_core.fall",
|
||||
"block.heavy_core.hit",
|
||||
"block.heavy_core.place",
|
||||
"block.heavy_core.step",
|
||||
"block.nether_wood_hanging_sign.step",
|
||||
"block.nether_wood_hanging_sign.break",
|
||||
"block.nether_wood_hanging_sign.fall",
|
||||
|
@ -599,6 +672,22 @@
|
|||
"block.bamboo_wood_hanging_sign.fall",
|
||||
"block.bamboo_wood_hanging_sign.hit",
|
||||
"block.bamboo_wood_hanging_sign.place",
|
||||
"block.trial_spawner.break",
|
||||
"block.trial_spawner.step",
|
||||
"block.trial_spawner.place",
|
||||
"block.trial_spawner.hit",
|
||||
"block.trial_spawner.fall",
|
||||
"block.trial_spawner.spawn_mob",
|
||||
"block.trial_spawner.about_to_spawn_item",
|
||||
"block.trial_spawner.spawn_item",
|
||||
"block.trial_spawner.spawn_item_begin",
|
||||
"block.trial_spawner.detect_player",
|
||||
"block.trial_spawner.ominous_activate",
|
||||
"block.trial_spawner.ambient",
|
||||
"block.trial_spawner.ambient_ominous",
|
||||
"block.trial_spawner.open_shutter",
|
||||
"block.trial_spawner.close_shutter",
|
||||
"block.trial_spawner.eject_item",
|
||||
"item.hoe.till",
|
||||
"entity.hoglin.ambient",
|
||||
"entity.hoglin.angry",
|
||||
|
@ -710,6 +799,9 @@
|
|||
"block.lodestone.hit",
|
||||
"block.lodestone.fall",
|
||||
"item.lodestone_compass.lock",
|
||||
"item.mace.smash_air",
|
||||
"item.mace.smash_ground",
|
||||
"item.mace.smash_ground_heavy",
|
||||
"entity.magma_cube.death",
|
||||
"entity.magma_cube.hurt",
|
||||
"entity.magma_cube.hurt_small",
|
||||
|
@ -774,6 +866,7 @@
|
|||
"entity.mule.death",
|
||||
"entity.mule.eat",
|
||||
"entity.mule.hurt",
|
||||
"entity.mule.jump",
|
||||
"music.creative",
|
||||
"music.credits",
|
||||
"music_disc.5",
|
||||
|
@ -791,6 +884,10 @@
|
|||
"music_disc.wait",
|
||||
"music_disc.ward",
|
||||
"music_disc.otherside",
|
||||
"music_disc.relic",
|
||||
"music_disc.creator",
|
||||
"music_disc.creator_music_box",
|
||||
"music_disc.precipice",
|
||||
"music.dragon",
|
||||
"music.end",
|
||||
"music.game",
|
||||
|
@ -803,7 +900,7 @@
|
|||
"music.overworld.jagged_peaks",
|
||||
"music.overworld.lush_caves",
|
||||
"music.overworld.swamp",
|
||||
"music.overworld.jungle_and_forest",
|
||||
"music.overworld.forest",
|
||||
"music.overworld.old_growth_taiga",
|
||||
"music.overworld.meadow",
|
||||
"music.overworld.cherry_grove",
|
||||
|
@ -813,6 +910,12 @@
|
|||
"music.nether.soul_sand_valley",
|
||||
"music.overworld.stony_peaks",
|
||||
"music.nether.warped_forest",
|
||||
"music.overworld.flower_forest",
|
||||
"music.overworld.desert",
|
||||
"music.overworld.badlands",
|
||||
"music.overworld.jungle",
|
||||
"music.overworld.sparse_jungle",
|
||||
"music.overworld.bamboo_jungle",
|
||||
"music.under_water",
|
||||
"block.nether_bricks.break",
|
||||
"block.nether_bricks.step",
|
||||
|
@ -836,7 +939,7 @@
|
|||
"block.nether_wood_pressure_plate.click_on",
|
||||
"block.nether_wood_fence_gate.close",
|
||||
"block.nether_wood_fence_gate.open",
|
||||
"minecraft:intentionally_empty",
|
||||
"intentionally_empty",
|
||||
"block.packed_mud.break",
|
||||
"block.packed_mud.fall",
|
||||
"block.packed_mud.hit",
|
||||
|
@ -907,6 +1010,7 @@
|
|||
"entity.ocelot.hurt",
|
||||
"entity.ocelot.ambient",
|
||||
"entity.ocelot.death",
|
||||
"item.ominous_bottle.dispose",
|
||||
"entity.painting.break",
|
||||
"entity.painting.place",
|
||||
"entity.panda.pre_sneeze",
|
||||
|
@ -926,6 +1030,8 @@
|
|||
"entity.parrot.fly",
|
||||
"entity.parrot.hurt",
|
||||
"entity.parrot.imitate.blaze",
|
||||
"entity.parrot.imitate.bogged",
|
||||
"entity.parrot.imitate.breeze",
|
||||
"entity.parrot.imitate.creeper",
|
||||
"entity.parrot.imitate.drowned",
|
||||
"entity.parrot.imitate.elder_guardian",
|
||||
|
@ -1012,6 +1118,7 @@
|
|||
"entity.player.splash",
|
||||
"entity.player.splash.high_speed",
|
||||
"entity.player.swim",
|
||||
"entity.player.teleport",
|
||||
"entity.polar_bear.ambient",
|
||||
"entity.polar_bear.ambient_baby",
|
||||
"entity.polar_bear.death",
|
||||
|
@ -1221,6 +1328,9 @@
|
|||
"entity.sniffer.digging",
|
||||
"entity.sniffer.digging_stop",
|
||||
"entity.sniffer.happy",
|
||||
"block.sniffer_egg.plop",
|
||||
"block.sniffer_egg.crack",
|
||||
"block.sniffer_egg.hatch",
|
||||
"entity.snowball.throw",
|
||||
"block.snow.break",
|
||||
"block.snow.fall",
|
||||
|
@ -1238,6 +1348,12 @@
|
|||
"entity.spider.step",
|
||||
"entity.splash_potion.break",
|
||||
"entity.splash_potion.throw",
|
||||
"block.sponge.break",
|
||||
"block.sponge.fall",
|
||||
"block.sponge.hit",
|
||||
"block.sponge.place",
|
||||
"block.sponge.step",
|
||||
"block.sponge.absorb",
|
||||
"item.spyglass.use",
|
||||
"item.spyglass.stop_using",
|
||||
"entity.squid.ambient",
|
||||
|
@ -1288,6 +1404,16 @@
|
|||
"block.tuff.place",
|
||||
"block.tuff.hit",
|
||||
"block.tuff.fall",
|
||||
"block.tuff_bricks.break",
|
||||
"block.tuff_bricks.fall",
|
||||
"block.tuff_bricks.hit",
|
||||
"block.tuff_bricks.place",
|
||||
"block.tuff_bricks.step",
|
||||
"block.polished_tuff.break",
|
||||
"block.polished_tuff.fall",
|
||||
"block.polished_tuff.hit",
|
||||
"block.polished_tuff.place",
|
||||
"block.polished_tuff.step",
|
||||
"entity.turtle.ambient_land",
|
||||
"entity.turtle.death",
|
||||
"entity.turtle.death_baby",
|
||||
|
@ -1309,6 +1435,20 @@
|
|||
"ui.toast.challenge_complete",
|
||||
"ui.toast.in",
|
||||
"ui.toast.out",
|
||||
"block.vault.activate",
|
||||
"block.vault.ambient",
|
||||
"block.vault.break",
|
||||
"block.vault.close_shutter",
|
||||
"block.vault.deactivate",
|
||||
"block.vault.eject_item",
|
||||
"block.vault.reject_rewarded_player",
|
||||
"block.vault.fall",
|
||||
"block.vault.hit",
|
||||
"block.vault.insert_item",
|
||||
"block.vault.insert_item_fail",
|
||||
"block.vault.open_shutter",
|
||||
"block.vault.place",
|
||||
"block.vault.step",
|
||||
"entity.vex.ambient",
|
||||
"entity.vex.charge",
|
||||
"entity.vex.death",
|
||||
|
@ -1373,6 +1513,8 @@
|
|||
"entity.warden.sonic_charge",
|
||||
"entity.warden.step",
|
||||
"entity.warden.tendril_clicks",
|
||||
"block.hanging_sign.waxed_interact_fail",
|
||||
"block.sign.waxed_interact_fail",
|
||||
"block.water.ambient",
|
||||
"weather.rain",
|
||||
"weather.rain.above",
|
||||
|
@ -1381,6 +1523,14 @@
|
|||
"block.wet_grass.hit",
|
||||
"block.wet_grass.place",
|
||||
"block.wet_grass.step",
|
||||
"block.wet_sponge.break",
|
||||
"block.wet_sponge.dries",
|
||||
"block.wet_sponge.fall",
|
||||
"block.wet_sponge.hit",
|
||||
"block.wet_sponge.place",
|
||||
"block.wet_sponge.step",
|
||||
"entity.wind_charge.wind_burst",
|
||||
"entity.wind_charge.throw",
|
||||
"entity.witch.ambient",
|
||||
"entity.witch.celebrate",
|
||||
"entity.witch.death",
|
||||
|
@ -1397,6 +1547,10 @@
|
|||
"entity.wither_skeleton.hurt",
|
||||
"entity.wither_skeleton.step",
|
||||
"entity.wither.spawn",
|
||||
"item.wolf_armor.break",
|
||||
"item.wolf_armor.crack",
|
||||
"item.wolf_armor.damage",
|
||||
"item.wolf_armor.repair",
|
||||
"entity.wolf.ambient",
|
||||
"entity.wolf.death",
|
||||
"entity.wolf.growl",
|
||||
|
@ -1452,5 +1606,8 @@
|
|||
"entity.zombie_villager.cure",
|
||||
"entity.zombie_villager.death",
|
||||
"entity.zombie_villager.hurt",
|
||||
"entity.zombie_villager.step"
|
||||
"entity.zombie_villager.step",
|
||||
"event.mob_effect.bad_omen",
|
||||
"event.mob_effect.trial_omen",
|
||||
"event.mob_effect.raid_omen"
|
||||
]
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"key.categories.voicechat": "Voice Chat",
|
||||
"key.push_to_talk": "Push To Talk",
|
||||
"key.push_to_talk": "Push to Talk",
|
||||
"key.whisper": "Whisper",
|
||||
"key.mute_microphone": "Mute Microphone",
|
||||
"key.disable_voice_chat": "Disable Voice Chat",
|
||||
"key.hide_icons": "Hide Voice Chat Icons",
|
||||
"key.voice_chat_settings": "Voice Chat Settings",
|
||||
"key.voice_chat": "Voice Chat GUI",
|
||||
"key.voice_chat_group": "Voice Chat Group",
|
||||
"key.voice_chat": "Voice Chat Menu",
|
||||
"key.voice_chat_group": "Group Management",
|
||||
"key.voice_chat_toggle_recording": "Toggle Recording",
|
||||
"key.voice_chat_adjust_volumes": "Adjust Volumes",
|
||||
"gui.voicechat.voice_chat.title": "Voice Chat",
|
||||
|
@ -15,151 +15,198 @@
|
|||
"gui.voicechat.adjust_volume.title": "Adjust Volumes",
|
||||
"gui.voicechat.select_microphone.title": "Select Microphone",
|
||||
"gui.voicechat.select_speaker.title": "Select Speaker",
|
||||
"gui.voicechat.group.title": "Group Chat",
|
||||
"gui.voicechat.group.title": "Group Management",
|
||||
"gui.voicechat.join_create_group.title": "Join or Create Group",
|
||||
"gui.voicechat.create_group.title": "Create a Group",
|
||||
"gui.voicechat.create_group.title": "Create Group",
|
||||
"gui.voicechat.enter_password.title": "Enter Group Password",
|
||||
"message.voicechat.settings": "Settings",
|
||||
"message.voicechat.group": "Group",
|
||||
"message.voicechat.voice_chat_volume": "Voice chat volume: %s",
|
||||
"message.voicechat.microphone_amplification": "Microphone amplification: %s",
|
||||
"message.voicechat.mic_test_on": "Disable microphone testing",
|
||||
"message.voicechat.mic_test_off": "Enable microphone testing",
|
||||
"message.voicechat.mic_test_unavailable": "Microphone testing unavailable",
|
||||
"message.voicechat.voice_chat_volume": "Voice Chat Volume: %s",
|
||||
"message.voicechat.microphone_amplification": "Microphone Amplification: %s",
|
||||
"message.voicechat.mic_test_unavailable": "Microphone testing unavailable!",
|
||||
"message.voicechat.mic_test.disabled": "Press to enable microphone testing.",
|
||||
"message.voicechat.mic_test.enabled": "Press to disable microphone testing.",
|
||||
"message.voicechat.voice_chat_unavailable": "Voice chat unavailable",
|
||||
"message.voicechat.voice_chat_not_connected": "Voice chat not connected",
|
||||
"message.voicechat.activation_type": "Activation type: %s",
|
||||
"message.voicechat.activation_type.ptt": "Push to talk",
|
||||
"message.voicechat.activation_type": "Activation Method: %s",
|
||||
"message.voicechat.activation_type.ptt": "Push to Talk",
|
||||
"message.voicechat.activation_type.voice": "Voice",
|
||||
"message.voicechat.voice_activation": "Voice activation threshold: %s dB",
|
||||
"message.voicechat.voice_activation": "Voice Activation Threshold: %s dB",
|
||||
"message.voicechat.voice_activation.disabled": "0 dB deactivates the microphone!",
|
||||
"message.voicechat.adjust_volumes": "Adjust volumes",
|
||||
"message.voicechat.adjust_volumes": "Adjust Volumes",
|
||||
"message.voicechat.volume_amplification": "Amplification: %s",
|
||||
"message.voicechat.muted": "Muted",
|
||||
"message.voicechat.adjust_volume_player": "Adjust volume of %s",
|
||||
"message.voicechat.no_microphone": "No microphone available",
|
||||
"message.voicechat.no_speaker": "No speaker available",
|
||||
"message.voicechat.select": "Select",
|
||||
"message.voicechat.select_microphone": "Select microphone",
|
||||
"message.voicechat.select_speaker": "Select speaker",
|
||||
"message.voicechat.no_microphone": "No microphones available",
|
||||
"message.voicechat.no_speaker": "No speakers available",
|
||||
"message.voicechat.select_microphone": "Select Microphone",
|
||||
"message.voicechat.select_speaker": "Select Speaker",
|
||||
"message.voicechat.back": "Back",
|
||||
"message.voicechat.client_not_connected": "Client not connected",
|
||||
"message.voicechat.failed_to_send_ping": "Failed to send ping: %s",
|
||||
"message.voicechat.sending_ping": "Sending ping...",
|
||||
"message.voicechat.ping_sent_waiting": "Ping sent. Waiting for response...",
|
||||
"message.voicechat.ping_received": "Got a response in %sms",
|
||||
"message.voicechat.ping_received_attempt": "Got a response after %s attempts in %sms",
|
||||
"message.voicechat.ping_received": "Got a response in %s ms",
|
||||
"message.voicechat.ping_received_attempt": "Got a response in %s ms after %s attempts",
|
||||
"message.voicechat.ping_retry": "No response. Retrying...",
|
||||
"message.voicechat.ping_timed_out": "Request timed out after %s attempts",
|
||||
"message.voicechat.icons_hidden": "Voice chat icons hidden",
|
||||
"message.voicechat.icons_visible": "Voice chat icons visible",
|
||||
"message.voicechat.incompatible_version": "Your voice chat version is not compatible with the servers version.\nPlease install version %s of %s.",
|
||||
"message.voicechat.incompatible": "Your voice chat version is not compatible with the servers version.",
|
||||
"message.voicechat.group_members": "Group members",
|
||||
"message.voicechat.no_group_members": "This group is empty",
|
||||
"message.voicechat.incompatible_version": "Your voice chat client version is not compatible with the server-side version.\nPlease install version %s of %s.",
|
||||
"message.voicechat.incompatible": "Your voice chat client version is not compatible with the server-side version.",
|
||||
"message.voicechat.group_members": "Group members:",
|
||||
"message.voicechat.no_group_members": "Empty group",
|
||||
"message.voicechat.join_create_group": "Join or Create Group",
|
||||
"message.voicechat.group_name": "Group name",
|
||||
"message.voicechat.leave_group": "Leave group",
|
||||
"message.voicechat.group_name": "Group Name",
|
||||
"message.voicechat.leave_group": "Press to leave the group.",
|
||||
"message.voicechat.not_in_group": "You are not in a group",
|
||||
"message.voicechat.invite": "%s invited you to the group %s. %s",
|
||||
"message.voicechat.accept_invite": "ACCEPT",
|
||||
"message.voicechat.accept_invite.hover": "Click to accept invitation",
|
||||
"message.voicechat.join_successful": "Successfully joined %s",
|
||||
"message.voicechat.accept_invite.hover": "Click to accept the invitation",
|
||||
"message.voicechat.join_successful": "Successfully joined the group %s",
|
||||
"message.voicechat.leave_successful": "Successfully left the group",
|
||||
"message.voicechat.groups_disabled": "Groups are disabled on this server",
|
||||
"message.voicechat.recording_disabled": "Recording is disabled on this server",
|
||||
"message.voicechat.invite_successful": "Successfully invited %s",
|
||||
"message.voicechat.processing_recording_session": "Processing recording session...",
|
||||
"message.voicechat.processing_progress": "Processing %s%%",
|
||||
"message.voicechat.save_session": "Saved session to '%s'",
|
||||
"message.voicechat.save_session": "Saved session to %s",
|
||||
"message.voicechat.save_session_failed": "Failed to save recording session: %s",
|
||||
"message.voicechat.recording_started": "Started Recording",
|
||||
"message.voicechat.recording_stopped": "Stopped Recording",
|
||||
"message.voicechat.open_folder": "Open Folder",
|
||||
"message.voicechat.storage_size": "Expected Storage Size %s",
|
||||
"message.voicechat.saved_debug_report": "Saved voice chat debug report to %s",
|
||||
"message.voicechat.open": "Open",
|
||||
"message.voicechat.saved_debug_report_failed": "Failed to save voice chat debug report: %s",
|
||||
"message.voicechat.open_folder": "Open folder",
|
||||
"message.voicechat.storage_size": "Estimated disk space usage: %s.",
|
||||
"message.voicechat.microphone_unavailable": "Microphone unavailable",
|
||||
"message.voicechat.speaker_unavailable": "Speaker unavailable",
|
||||
"message.voicechat.playback_unavailable": "Playback unavailable",
|
||||
"message.voicechat.denoiser": "Noise suppression: %s",
|
||||
"message.voicechat.enabled": "Enabled",
|
||||
"message.voicechat.disabled": "Disabled",
|
||||
"message.voicechat.denoiser": "Noise Suppression: %s",
|
||||
"message.voicechat.denoiser.on": "ON",
|
||||
"message.voicechat.denoiser.off": "OFF",
|
||||
"message.voicechat.group_type_title": "%s (%s)",
|
||||
"message.voicechat.group_title": "%s",
|
||||
"message.voicechat.group_does_not_exist": "This group does not exist",
|
||||
"message.voicechat.group_does_not_exist": "Such a group does not exist",
|
||||
"message.voicechat.group_name_not_unique": "Group name is ambiguous",
|
||||
"message.voicechat.create": "Create",
|
||||
"message.voicechat.create_group": "Create a Group",
|
||||
"message.voicechat.create_group_button": "Create a group",
|
||||
"message.voicechat.create_group": "Create Group",
|
||||
"message.voicechat.create_group_button": "Create Group",
|
||||
"message.voicechat.optional_password": "Password (Optional)",
|
||||
"message.voicechat.group_type": "Group type",
|
||||
"message.voicechat.group_type": "Group Type",
|
||||
"message.voicechat.group_type.normal": "Normal",
|
||||
"message.voicechat.group_type.normal.description": "Players that are not in your group can't hear you, but you can hear them",
|
||||
"message.voicechat.group_type.normal.description": "Players who are not in your group can't hear you, but you can hear them.",
|
||||
"message.voicechat.group_type.open": "Open",
|
||||
"message.voicechat.group_type.open.description": "Players that are not in your group can hear you and you can hear them",
|
||||
"message.voicechat.group_type.open.description": "Players who are not in your group can hear you, and you can hear them too.",
|
||||
"message.voicechat.group_type.isolated": "Isolated",
|
||||
"message.voicechat.group_type.isolated.description": "Players that are not in your group can't hear you and you can't hear them",
|
||||
"message.voicechat.join_group": "Join group",
|
||||
"message.voicechat.group_type.isolated.description": "Players who are not in your group can't hear you, and you can't hear them either.",
|
||||
"message.voicechat.join_group": "Join Group",
|
||||
"message.voicechat.enter_group_password": "Enter Group Password",
|
||||
"message.voicechat.password": "Password",
|
||||
"message.voicechat.wrong_password": "Wrong Password",
|
||||
"message.voicechat.wrong_password": "Incorrect Password",
|
||||
"message.voicechat.server_port": "Voice chat server hosted on port %s",
|
||||
"message.voicechat.macos_no_mic_permission": "No microphone permission. Please check Security & Privacy settings",
|
||||
"message.voicechat.macos_unsupported_launcher": "Your launcher does not support MacOS microphone permissions",
|
||||
"message.voicechat.macos_no_mic_permission": "No permission to access your microphone. Please open System Settings > Privacy & Security and check the access options there",
|
||||
"message.voicechat.macos_unsupported_launcher": "Your launcher does not support macOS microphone permissions",
|
||||
"message.voicechat.player_no_voicechat": "%s does not have %s installed",
|
||||
"message.voicechat.mute.enabled": "Press to unmute your microphone",
|
||||
"message.voicechat.mute.disabled": "Press to mute your microphone",
|
||||
"message.voicechat.mute.disabled_ptt": "You can't mute when using push to talk",
|
||||
"message.voicechat.disable.enabled": "Press to enable all voice chat sounds",
|
||||
"message.voicechat.disable.disabled": "Press to disable all voice chat sounds",
|
||||
"message.voicechat.disable.no_speaker": "No speaker available",
|
||||
"message.voicechat.hide_icons.enabled": "Press to show all voice chat icons",
|
||||
"message.voicechat.hide_icons.disabled": "Press to hide all voice chat icons",
|
||||
"message.voicechat.show_group_hud.enabled": "Press to hide the group chat HUD",
|
||||
"message.voicechat.show_group_hud.disabled": "Press to show the group chat HUD",
|
||||
"message.voicechat.recording.disabled": "Press to start recording",
|
||||
"message.voicechat.recording.enabled": "Press to stop recording",
|
||||
"message.voicechat.mute.enabled": "Press to unmute your microphone.",
|
||||
"message.voicechat.mute.disabled": "Press to mute your microphone.",
|
||||
"message.voicechat.mute.disabled_ptt": "You can't mute your microphone when using push to talk.",
|
||||
"message.voicechat.disable.enabled": "Press to enable all voice chat sounds.",
|
||||
"message.voicechat.disable.disabled": "Press to disable all voice chat sounds.",
|
||||
"message.voicechat.disable.no_speaker": "No speakers available.",
|
||||
"message.voicechat.hide_icons.enabled": "Press to show all voice chat icons.",
|
||||
"message.voicechat.hide_icons.disabled": "Press to hide all voice chat icons.",
|
||||
"message.voicechat.show_group_hud.enabled": "Press to hide the group chat HUD.",
|
||||
"message.voicechat.show_group_hud.disabled": "Press to show the group chat HUD.",
|
||||
"message.voicechat.recording.disabled": "Press to start recording.",
|
||||
"message.voicechat.recording.enabled": "Press to stop recording.",
|
||||
"message.voicechat.no_speak_permission": "You do not have permission to speak",
|
||||
"message.voicechat.no_listen_permission": "You do not have permission to hear the voice chat",
|
||||
"message.voicechat.no_group_permission": "You do not have permission to join groups",
|
||||
"message.voicechat.search_hint": "Search...",
|
||||
"message.voicechat.search_empty": "Couldn't find any players with that name",
|
||||
"message.voicechat.other_volume": "Other",
|
||||
"message.voicechat.other_volume.description": "The volume of any sound not listed below",
|
||||
"message.voicechat.other_volume.description": "The volume of any sound not listed below.",
|
||||
"message.voicechat.more_members": "and %s more...",
|
||||
"message.voicechat.no_groups": "No existing groups",
|
||||
"message.voicechat.audio_type": "3D audio: %s",
|
||||
"message.voicechat.audio_type": "3D Audio: %s",
|
||||
"message.voicechat.audio_type.normal": "Normal",
|
||||
"message.voicechat.audio_type.reduced": "Reduced",
|
||||
"message.voicechat.audio_type.off": "Off",
|
||||
"message.voicechat.invite_player": "Invite %s to your group",
|
||||
"message.voicechat.audio_type.off": "OFF",
|
||||
"message.voicechat.invite_player": "Press to invite %s to your group.",
|
||||
"message.voicechat.press_to_reassign_key": "Press to assign a key.",
|
||||
"message.voicechat.set_up": "Press %s to set up",
|
||||
"message.voicechat.onboarding.reset": "Onboarding status has been reset",
|
||||
"message.voicechat.onboarding.next": "Next",
|
||||
"message.voicechat.onboarding.confirm": "Confirm",
|
||||
"message.voicechat.onboarding.back": "Back",
|
||||
"message.voicechat.onboarding.cancel": "Cancel",
|
||||
"message.voicechat.onboarding.introduction.title": "Set Up %s",
|
||||
"message.voicechat.onboarding.introduction.description": "This setup guide will help you configure your voice chat.\n\nYou can skip it if you know what you are doing.",
|
||||
"message.voicechat.onboarding.introduction.skip": "I Know What I Am Doing - Skip",
|
||||
"message.voicechat.onboarding.skip.title": "Skip Setup",
|
||||
"message.voicechat.onboarding.skip.description": "Are you sure you want to skip this setup guide?\n\nIf you skip it, you will have to adjust all the settings manually!",
|
||||
"message.voicechat.onboarding.microphone": "Select Microphone",
|
||||
"message.voicechat.onboarding.speaker": "Select Speaker",
|
||||
"message.voicechat.onboarding.activation.title": "Select Activation Method",
|
||||
"message.voicechat.onboarding.activation": "Please choose the method to activate your microphone.",
|
||||
"message.voicechat.onboarding.activation.ptt": "When selecting %s, you need to press and hold a button to speak.",
|
||||
"message.voicechat.onboarding.activation.ptt.name": "Push to Talk",
|
||||
"message.voicechat.onboarding.activation.voice": "%s automatically activates your microphone when a certain volume threshold is reached.",
|
||||
"message.voicechat.onboarding.activation.voice.name": "Voice Activation",
|
||||
"message.voicechat.onboarding.ptt.title": "Choose Push to Talk Keybind",
|
||||
"message.voicechat.onboarding.ptt.description": "Please choose the key that should be used to activate your microphone.",
|
||||
"message.voicechat.onboarding.ptt.button_description": "Press to assign",
|
||||
"message.voicechat.onboarding.voice.title": "Adjust Microphone Activation Threshold",
|
||||
"message.voicechat.onboarding.voice.description": "Enable microphone testing and make sure the volume is below the slider when you are silent and above it when you are speaking.",
|
||||
"message.voicechat.onboarding.final": "Finish Setup",
|
||||
"message.voicechat.onboarding.final.description.success": "You have successfully configured your voice chat!\n\nOpen the voice chat menu with %s.",
|
||||
"message.voicechat.onboarding.final.description.ptt": "Hold %s while speaking to use the voice chat.",
|
||||
"message.voicechat.onboarding.final.description.voice": "You will be muted after exiting this screen. Press %s to unmute.",
|
||||
"message.voicechat.onboarding.final.description.configuration": "You can always change all the settings in the voice chat menu.\nKeybinds, however, can be changed just like any other keybind in the game.",
|
||||
"message.voicechat.onboarding.final.finish_setup": "Finish Setup",
|
||||
"resourcepack.voicechat.classic_icons": "Classic Icons",
|
||||
"resourcepack.voicechat.classic_icons.description": "Classic Voice Chat Icons",
|
||||
"resourcepack.voicechat.classic_icons.description": "Classic voice chat icons",
|
||||
"resourcepack.voicechat.white_icons": "White Icons",
|
||||
"resourcepack.voicechat.white_icons.description": "White Voice Chat Icons",
|
||||
"resourcepack.voicechat.white_icons.description": "White voice chat icons",
|
||||
"resourcepack.voicechat.black_icons": "Black Icons",
|
||||
"resourcepack.voicechat.black_icons.description": "Black Voice Chat Icons",
|
||||
"resourcepack.voicechat.black_icons.description": "Black voice chat icons",
|
||||
"cloth_config.voicechat.settings": "Voice Chat Settings",
|
||||
"cloth_config.voicechat.category.general": "General",
|
||||
"cloth_config.voicechat.category.other": "Other",
|
||||
"cloth_config.voicechat.category.audio": "Audio",
|
||||
"cloth_config.voicechat.category.hud_icons": "HUD Icons",
|
||||
"cloth_config.voicechat.category.group_chat_icons": "Group Chat Icons",
|
||||
"cloth_config.voicechat.category.hud_icons": "Voice Chat HUD",
|
||||
"cloth_config.voicechat.category.group_chat_icons": "Group Chat HUD",
|
||||
"cloth_config.voicechat.category.ingame_menu": "In-Game Menu",
|
||||
"cloth_config.voicechat.config.recording_destination": "Recording destination",
|
||||
"cloth_config.voicechat.config.run_local_server": "Run in singleplayer/LAN worlds",
|
||||
"cloth_config.voicechat.config.recording_destination.description": "The location where recordings should be saved.\nLeave blank to use the default location.",
|
||||
"cloth_config.voicechat.config.run_local_server": "Run in singleplayer or LAN worlds",
|
||||
"cloth_config.voicechat.config.run_local_server.description": "If the voice chat should work in singleplayer or in worlds shared over LAN.",
|
||||
"cloth_config.voicechat.config.offline_player_volume_adjustment": "Offline player volume adjustment",
|
||||
"cloth_config.voicechat.config.freecam_support": "Freecam support",
|
||||
"cloth_config.voicechat.config.offline_player_volume_adjustment.description": "If the volume adjustment interface should also display offline players.",
|
||||
"cloth_config.voicechat.config.freecam_mode": "Freecam mode",
|
||||
"cloth_config.voicechat.config.freecam_mode.description": "How listening to other players should work when using freecam mods.\nCAMERA: You will hear the voice chat around your camera. Whether you will still be able to hear the voice chat when the camera is far away from your character depends on the voice chat broadcast range of the server.\nPLAYER: You will hear the voice chat around your character no matter where your camera is.",
|
||||
"cloth_config.voicechat.config.freecam_mode.camera": "Camera",
|
||||
"cloth_config.voicechat.config.freecam_mode.player": "Player",
|
||||
"cloth_config.voicechat.config.mute_on_join": "Mute on join",
|
||||
"cloth_config.voicechat.config.mute_on_join.description": "If enabled, you will be automatically muted when joining a world.",
|
||||
"cloth_config.voicechat.config.audio_packet_threshold": "Audio packet threshold",
|
||||
"cloth_config.voicechat.config.deactivation_delay": "Deactivation delay",
|
||||
"cloth_config.voicechat.config.audio_packet_threshold.description": "The maximum number of audio packets that should be held back if a packet arrives out of order or is dropped.\nThis prevents audio packets that are only slightly out of order from being discarded.\nSet this to 0 to disable.",
|
||||
"cloth_config.voicechat.config.voice_deactivation_delay": "Microphone deactivation delay",
|
||||
"cloth_config.voicechat.config.voice_deactivation_delay.description": "The time it takes for the microphone to deactivate when using voice activation.\nA value of 1 means 20 milliseconds, 2=40 ms, 3=60 ms, and so on.",
|
||||
"cloth_config.voicechat.config.output_buffer_size": "Output buffer size",
|
||||
"cloth_config.voicechat.config.hud_icon_scale": "HUD icon scale",
|
||||
"cloth_config.voicechat.config.hud_icon_x": "HUD icon X pos",
|
||||
"cloth_config.voicechat.config.hud_icon_y": "HUD icon Y pos",
|
||||
"cloth_config.voicechat.config.group_player_icon_orientation": "Group HUD icon orientation",
|
||||
"cloth_config.voicechat.config.group_hud_icon_scale": "Group HUD icon scale",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_x": "Group icon X position",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_y": "Group icon Y position",
|
||||
"cloth_config.voicechat.config.show_own_group_icon": "Show own group HUD icon"
|
||||
"cloth_config.voicechat.config.output_buffer_size.description": "The size of the audio output buffer (in packets).\nHigher values mean a higher latency but less crackling.\nIncrease this value if you have an unstable internet connection.",
|
||||
"cloth_config.voicechat.config.hud_icon_scale": "Voice chat HUD icon scale",
|
||||
"cloth_config.voicechat.config.hud_icon_scale.description": "The scale of the icons in the voice chat HUD, such as microphone or connection status.",
|
||||
"cloth_config.voicechat.config.hud_icon_pos_x": "Voice chat HUD icon X position",
|
||||
"cloth_config.voicechat.config.hud_icon_pos_x.description": "The X position of the icons in the voice chat HUD.\nNegative values mean anchoring to the right instead.",
|
||||
"cloth_config.voicechat.config.hud_icon_pos_y": "Voice chat HUD icon Y position",
|
||||
"cloth_config.voicechat.config.hud_icon_pos_y.description": "The Y position of the icons in the voice chat HUD.\nNegative values mean anchoring to the bottom instead.",
|
||||
"cloth_config.voicechat.config.group_player_icon_orientation": "Group chat HUD icon orientation",
|
||||
"cloth_config.voicechat.config.group_player_icon_orientation.description": "The orientation of the player icons in the group chat HUD.",
|
||||
"cloth_config.voicechat.config.group_player_icon_orientation.vertical": "Vertical",
|
||||
"cloth_config.voicechat.config.group_player_icon_orientation.horizontal": "Horizontal",
|
||||
"cloth_config.voicechat.config.group_hud_icon_scale": "Group chat HUD icon scale",
|
||||
"cloth_config.voicechat.config.group_hud_icon_scale.description": "The scale of the player icons in the group chat HUD.",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_x": "Group chat HUD icon X position",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_x.description": "The X position of the player icons in the group chat HUD.\nNegative values mean anchoring to the right instead.",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_y": "Group chat HUD icon Y position",
|
||||
"cloth_config.voicechat.config.group_player_icon_pos_y.description": "The Y position of the player icons in the group chat HUD.\nNegative values mean anchoring to the bottom instead.",
|
||||
"cloth_config.voicechat.config.show_own_group_icon": "Show yourself in the group chat HUD",
|
||||
"cloth_config.voicechat.config.show_own_group_icon.description": "If your own player icon should be displayed in the group chat HUD when you are in a group."
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue