Celeste-OG Initial Release
This commit is contained in:
1 parent
a7e0bb9b5d
commit
2214c80c2a
34 files changed
+1056
-1538
No files matched your search
+36
-20
@@ -1,21 +1,37 @@
|
||||
# IntelliJ project files
|
||||
.idea
|
||||
*.iml
|
||||
out
|
||||
gen
|
||||
*.lnk
|
||||
target/
|
||||
.classpath
|
||||
.project
|
||||
# Compiled class file
|
||||
*.class
|
||||
|
||||
# Log file
|
||||
*.log
|
||||
|
||||
# BlueJ files
|
||||
*.ctxt
|
||||
|
||||
# Mobile Tools for Java (J2ME)
|
||||
.mtj.tmp/
|
||||
|
||||
# Package Files #
|
||||
*.jar
|
||||
*.war
|
||||
*.nar
|
||||
*.ear
|
||||
*.zip
|
||||
*.tar.gz
|
||||
*.rar
|
||||
|
||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||
hs_err_pid*
|
||||
replay_pid*
|
||||
|
||||
# macOS system files
|
||||
.DS_Store
|
||||
|
||||
# gradle build output files
|
||||
build/
|
||||
.gradle/
|
||||
|
||||
# eclipse project files
|
||||
.settings/
|
||||
.gitignore
|
||||
pom.xml.tag
|
||||
pom.xml.releaseBackup
|
||||
pom.xml.versionsBackup
|
||||
pom.xml.next
|
||||
release.properties
|
||||
dependency-reduced-pom.xml
|
||||
buildNumber.properties
|
||||
.mvn/timing.properties
|
||||
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
|
||||
.mvn/wrapper/maven-wrapper.jar
|
||||
.project
|
||||
.classpath
|
||||
bin/
|
||||
@@ -1,11 +1,12 @@
|
||||
# Celeste - Add shooting stars to your Minecraft server
|
||||
Celeste is a simple plugin that adds shooting stars to your Minecraft server. Inspired by the shooting stars from Animal Crossing and the falling stars from Breath of the Wild, this plugin brings some celestial ambience to your Minecraft world.
|
||||
# Celeste-OG - Add shooting stars to your Minecraft server
|
||||
Celeste-OG is a 1.19 fork of Celeste maintained for [TrueOG Network](https://true-og.net). Celeste plugin that adds shooting stars to your Minecraft server. Inspired by the shooting stars from Animal Crossing and the falling stars from Breath of the Wild, this plugin brings some celestial ambience to your Minecraft world.
|
||||
|
||||
[Check out the overview video](https://www.youtube.com/watch?v=TXdrECjVTiU)
|
||||
|
||||
[Download the server plugin on Spigot](https://www.spigotmc.org/resources/celeste.81862/)
|
||||
|
||||
[Learn more about Celeste (the plugin, not the owl)](https://idreesinc.com/about-celeste.html?utm_source=github&utm_medium=readme&utm_campaign=celeste)
|
||||
## Changes over Celeste
|
||||
- Maven -> Gradle.
|
||||
- Removed bStats Metrics.
|
||||
- Removed update checker.
|
||||
- Resolved 1 deprecation warning in CommandCeleste.java.
|
||||
- Built with Purpur API 1.19.4.
|
||||
|
||||
## Features
|
||||
- Add shooting stars to the night sky, with configurable frequency
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
plugins {
|
||||
java // Tell gradle this is a java project.
|
||||
id("io.github.goooler.shadow") version "8.1.8"
|
||||
eclipse // Import eclipse plugin for IDE integration.
|
||||
kotlin("jvm") version "1.9.23" // Import kotlin jvm plugin for kotlin/java integration.
|
||||
}
|
||||
|
||||
java {
|
||||
// Declare java version.
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
group = "net.trueog.celeste-og" // Declare bundle identifier.
|
||||
version = "1.0" // Declare plugin version (will be in .jar).
|
||||
val apiVersion = "1.19" // Declare minecraft server target version.
|
||||
|
||||
tasks.named<ProcessResources>("processResources") {
|
||||
val props = mapOf(
|
||||
"version" to version,
|
||||
"apiVersion" to apiVersion
|
||||
)
|
||||
|
||||
inputs.properties(props) // Indicates to rerun if version changes.
|
||||
|
||||
filesMatching("plugin.yml") {
|
||||
expand(props)
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
||||
maven {
|
||||
url = uri("https://repo.purpurmc.org/snapshots")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly("org.purpurmc.purpur:purpur-api:1.19.4-R0.1-SNAPSHOT") // Declare purpur API version to be packaged.
|
||||
compileOnly("io.github.miniplaceholders:miniplaceholders-api:2.2.3") // Import MiniPlaceholders API.
|
||||
}
|
||||
|
||||
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||
isPreserveFileTimestamps = false
|
||||
isReproducibleFileOrder = true
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
exclude("io.github.miniplaceholders.*") // Exclude the MiniPlaceholders package from being shadowed.
|
||||
minimize()
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
dependsOn(tasks.shadowJar)
|
||||
archiveClassifier.set("part")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
archiveClassifier.set("") // Use empty string instead of null
|
||||
from("LICENSE") {
|
||||
into("/")
|
||||
}
|
||||
}
|
||||
|
||||
tasks.jar {
|
||||
dependsOn("shadowJar")
|
||||
}
|
||||
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
options.compilerArgs.add("-parameters")
|
||||
options.encoding = "UTF-8"
|
||||
options.isFork = true
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvmToolchain(17)
|
||||
}
|
||||
|
||||
java {
|
||||
toolchain {
|
||||
languageVersion = JavaLanguageVersion.of(17)
|
||||
vendor = JvmVendorSpec.GRAAL_VM
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
@@ -0,0 +1,249 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# https://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# This is normally unused
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
||||
# Determine the Java command to use to start the JVM.
|
||||
if [ -n "$JAVA_HOME" ] ; then
|
||||
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||
# IBM's JDK on AIX uses strange locations for the executables
|
||||
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||
else
|
||||
JAVACMD=$JAVA_HOME/bin/java
|
||||
fi
|
||||
if [ ! -x "$JAVACMD" ] ; then
|
||||
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
else
|
||||
JAVACMD=java
|
||||
if ! command -v java >/dev/null 2>&1
|
||||
then
|
||||
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||
|
||||
Please set the JAVA_HOME variable in your environment to match the
|
||||
location of your Java installation."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Increase the maximum file descriptors if we can.
|
||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||
# shellcheck disable=SC2039,SC3045
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Collect all arguments for the java command:
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||
# and any embedded shellness will be escaped.
|
||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||
# treated as '${Hostname}' itself on the command line.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
Vendored
+92
@@ -0,0 +1,92 @@
|
||||
@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
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.idreesinc</groupId>
|
||||
<artifactId>Celeste</artifactId>
|
||||
<version>2.0</version>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<version>3.2.0</version>
|
||||
<configuration>
|
||||
<outputDirectory>dist</outputDirectory>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spigotmc-repo</id>
|
||||
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.spigotmc</groupId>
|
||||
<artifactId>spigot-api</artifactId>
|
||||
<version>1.18-R0.1-SNAPSHOT</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1 @@
|
||||
rootProject.name = "Celeste-OG"
|
||||
@@ -1,60 +0,0 @@
|
||||
package com.idreesinc.celeste;
|
||||
|
||||
import com.idreesinc.celeste.config.CelesteConfig;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class Astronomer extends BukkitRunnable {
|
||||
|
||||
private final Celeste celeste;
|
||||
|
||||
public Astronomer(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (celeste.getServer().getOnlinePlayers().size() == 0) {
|
||||
return;
|
||||
}
|
||||
List<World> worlds = celeste.getServer().getWorlds();
|
||||
for (World world : worlds) {
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(world.getName());
|
||||
if (!celeste.configManager.doesWorldHaveOverrides(world.getName())
|
||||
&& !world.getEnvironment().equals(World.Environment.NORMAL)) {
|
||||
// Ensure that Celeste only runs on normal worlds unless override is specified in config
|
||||
continue;
|
||||
}
|
||||
if (world.getPlayers().size() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!(world.getTime() >= config.beginSpawningStarsTime && world.getTime() <= config.endSpawningStarsTime)) {
|
||||
continue;
|
||||
}
|
||||
if (world.hasStorm()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double shootingStarChance;
|
||||
double fallingStarChance;
|
||||
if (config.newMoonMeteorShower && (world.getFullTime() / 24000) % 8 == 4) {
|
||||
shootingStarChance = config.shootingStarsPerMinuteMeteorShower / 120d;
|
||||
fallingStarChance = config.fallingStarsPerMinuteMeteorShower / 120d;
|
||||
} else {
|
||||
shootingStarChance = config.shootingStarsPerMinute / 120d;
|
||||
fallingStarChance = config.fallingStarsPerMinute / 120d;
|
||||
}
|
||||
|
||||
if (config.shootingStarsEnabled && new Random().nextDouble() <= shootingStarChance) {
|
||||
CelestialSphere.createShootingStar(celeste,
|
||||
world.getPlayers().get(new Random().nextInt(world.getPlayers().size())));
|
||||
}
|
||||
if (config.fallingStarsEnabled && new Random().nextDouble() <= fallingStarChance) {
|
||||
CelestialSphere.createFallingStar(celeste,
|
||||
world.getPlayers().get(new Random().nextInt(world.getPlayers().size())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package com.idreesinc.celeste;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import com.idreesinc.celeste.commands.CommandCeleste;
|
||||
import com.idreesinc.celeste.commands.CommandFallingStar;
|
||||
import com.idreesinc.celeste.commands.CommandShootingStar;
|
||||
import com.idreesinc.celeste.utilities.Metrics;
|
||||
import com.idreesinc.celeste.utilities.UpdateChecker;
|
||||
import com.idreesinc.celeste.config.CelesteConfigManager;
|
||||
|
||||
public class Celeste extends JavaPlugin {
|
||||
|
||||
public CelesteConfigManager configManager = new CelesteConfigManager(this);
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.saveDefaultConfig();
|
||||
// bStats metrics
|
||||
Metrics metrics = new Metrics(this, 8292);
|
||||
|
||||
this.getCommand("celeste").setExecutor(new CommandCeleste(this));
|
||||
this.getCommand("shootingstar").setExecutor(new CommandShootingStar(this));
|
||||
this.getCommand("fallingstar").setExecutor(new CommandFallingStar(this));
|
||||
configManager.processConfigs();
|
||||
|
||||
BukkitRunnable stargazingTask = new Astronomer(this);
|
||||
stargazingTask.runTaskTimer(this, 0, 10);
|
||||
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
reloadConfig();
|
||||
configManager.processConfigs();
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
public void checkForUpdates() {
|
||||
if (this.getConfig().getBoolean("check-for-updates")) {
|
||||
new UpdateChecker(this, 81862).getVersion(version -> {
|
||||
try {
|
||||
double current = Double.parseDouble(this.getDescription().getVersion());
|
||||
double api = Double.parseDouble(version);
|
||||
if (current < api) {
|
||||
this.getLogger().info("There is an update available for Celeste (" + current + " -> " + api + ")");
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
if (this.getConfig().getBoolean("debug")) {
|
||||
this.getLogger().severe("Unable to process remote plugin version number '" + version + "'");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
package com.idreesinc.celeste;
|
||||
|
||||
import com.idreesinc.celeste.config.CelesteConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Random;
|
||||
|
||||
public class CelestialSphere {
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Player player) {
|
||||
createShootingStar(celeste, player, true);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Player player, boolean approximate) {
|
||||
createShootingStar(celeste, player.getLocation(), approximate);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Location location) {
|
||||
createShootingStar(celeste, location, true);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Location location, boolean approximate) {
|
||||
Location starLocation;
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
double w = 100 * Math.sqrt(new Random().nextDouble());
|
||||
double t = 2d * Math.PI * new Random().nextDouble();
|
||||
double x = w * Math.cos(t);
|
||||
double range = Math.max(0, config.shootingStarsMaxHeight - config.shootingStarsMinHeight);
|
||||
double y = Math.max(new Random().nextDouble() * range + config.shootingStarsMinHeight, location.getY() + 50);
|
||||
double z = w * Math.sin(t);
|
||||
if (approximate) {
|
||||
starLocation = new Location(location.getWorld(), location.getX() + x, y, location.getZ() + z);
|
||||
} else {
|
||||
starLocation = new Location(location.getWorld(), location.getX(), y, location.getZ());
|
||||
}
|
||||
Vector direction = new Vector(new Random().nextDouble() * 2 - 1, new Random().nextDouble() * -0.75d, new Random().nextDouble() * 2 - 1);
|
||||
direction.normalize();
|
||||
double speed = new Random().nextDouble() * 2 + 0.75;
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, starLocation, 0, direction.getX(),
|
||||
direction.getY(), direction.getZ(), speed, null, true);
|
||||
if (new Random().nextDouble() >= 0.5) {
|
||||
location.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, starLocation, 0, direction.getX(),
|
||||
direction.getY(), direction.getZ(), speed, null, true);
|
||||
}
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Shooting star at " + stringifyLocation(starLocation) + " in world " + starLocation.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, Player player) {
|
||||
createFallingStar(celeste, player, true);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, Player player, boolean approximate) {
|
||||
createFallingStar(celeste, player.getLocation(), approximate);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, final Location location) {
|
||||
createFallingStar(celeste, location, true);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, final Location location, boolean approximate) {
|
||||
Location target = location;
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
if (approximate) {
|
||||
double fallingStarRadius = config.fallingStarsRadius;
|
||||
double w = fallingStarRadius * Math.sqrt(new Random().nextDouble());
|
||||
double t = 2d * Math.PI * new Random().nextDouble();
|
||||
double x = w * Math.cos(t);
|
||||
double z = w * Math.sin(t);
|
||||
target = new Location(location.getWorld(), location.getX() + x, location.getY(), location.getZ() + z);
|
||||
}
|
||||
BukkitRunnable fallingStarTask = new FallingStar(celeste, target);
|
||||
fallingStarTask.runTaskTimer(celeste, 0, 1);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Falling star at " + stringifyLocation(target) + " in world " + target.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static String stringifyLocation(Location location) {
|
||||
DecimalFormat format = new DecimalFormat("##.00");
|
||||
format.setRoundingMode(RoundingMode.HALF_UP);
|
||||
return "x: " + format.format(location.getX()) + " y: " + format.format(location.getY()) + " z: " + format.format(location.getZ());
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package com.idreesinc.celeste;
|
||||
|
||||
import com.idreesinc.celeste.config.CelesteConfig;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class FallingStar extends BukkitRunnable {
|
||||
|
||||
private final Celeste celeste;
|
||||
private final Location location;
|
||||
private final Location dropLoc;
|
||||
private final CelesteConfig config;
|
||||
private double y = 256;
|
||||
private boolean soundPlayed = false;
|
||||
private boolean lootDropped = false;
|
||||
private int sparkTimer;
|
||||
|
||||
public FallingStar(Celeste celeste, Location location) {
|
||||
this.celeste = celeste;
|
||||
this.location = location;
|
||||
config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
sparkTimer = config.fallingStarsSparkTime;
|
||||
dropLoc = new Location(location.getWorld(), location.getX(),
|
||||
location.getWorld().getHighestBlockAt(location).getY() + 1, location.getZ());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
double step = 1;
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, location.getX(), y, location.getZ(),
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
0.2, null, true);
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, location.getX(),
|
||||
y + new Random().nextDouble() * step,
|
||||
location.getZ(),
|
||||
0, 0, -1, 0,
|
||||
1, null, true);
|
||||
if (y % (step * 2) == 0) {
|
||||
location.getWorld().spawnParticle(Particle.LAVA, location.getX(), y + new Random().nextDouble(),
|
||||
location.getZ(),
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
0.2, null, true);
|
||||
}
|
||||
if (config.fallingStarsSoundEnabled && !soundPlayed && y <= dropLoc.getY() + 75) {
|
||||
location.getWorld().playSound(dropLoc, Sound.BLOCK_BELL_RESONATE, (float) config.fallingStarsVolume, 0.5f);
|
||||
soundPlayed = true;
|
||||
}
|
||||
if (y <= dropLoc.getY()) {
|
||||
if (!lootDropped) {
|
||||
// Note that both simple loot and loot tables will drop if both are configured because why not
|
||||
if (config.fallingStarSimpleLoot != null && config.fallingStarSimpleLoot.entries.size() > 0) {
|
||||
ItemStack drop = new ItemStack(Material.valueOf(config.fallingStarSimpleLoot.getRandom()), 1);
|
||||
location.getWorld().dropItem(dropLoc, drop);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Spawned simple falling star loot");
|
||||
}
|
||||
}
|
||||
if (config.fallingStarLootTable != null) {
|
||||
// Armor stands are used as markers are not compatible with 1.14
|
||||
Entity marker = dropLoc.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);
|
||||
String command = String.format("execute at %s run loot spawn %s %s %s loot %s",
|
||||
marker.getUniqueId(),
|
||||
dropLoc.getX(),
|
||||
dropLoc.getY(),
|
||||
dropLoc.getZ(),
|
||||
config.fallingStarLootTable);
|
||||
celeste.getServer().dispatchCommand(celeste.getServer().getConsoleSender(), command);
|
||||
marker.remove();
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Spawned falling star loot from loot table '" + config.fallingStarLootTable + "'");
|
||||
}
|
||||
}
|
||||
if (config.fallingStarsExperience > 0) {
|
||||
ExperienceOrb orb = (ExperienceOrb) dropLoc.getWorld().spawnEntity(dropLoc, EntityType.EXPERIENCE_ORB);
|
||||
orb.setExperience(config.fallingStarsExperience);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Dropping experience orbs with value " + config.fallingStarsExperience);
|
||||
}
|
||||
}
|
||||
lootDropped = true;
|
||||
}
|
||||
if (y % (step * 5) == 0) {
|
||||
location.getWorld().spawnParticle(Particle.LAVA, dropLoc,
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
1, null, true);
|
||||
}
|
||||
sparkTimer--;
|
||||
if (sparkTimer <= 0) {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
y -= step;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.idreesinc.celeste.commands;
|
||||
|
||||
import com.idreesinc.celeste.Celeste;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
public class CommandCeleste implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandCeleste(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
|
||||
if (sender.hasPermission("celeste.reload")) {
|
||||
celeste.reload();
|
||||
sender.sendMessage("Celeste has been reloaded");
|
||||
} else {
|
||||
sender.sendMessage("You do not have permission to use this command");
|
||||
}
|
||||
return true;
|
||||
} else if (args.length == 1 && args[0].equalsIgnoreCase("info")) {
|
||||
if (sender.hasPermission("celeste.info")) {
|
||||
sender.sendMessage("Celeste v" + celeste.getDescription().getVersion());
|
||||
sender.sendMessage("Shooting stars: " + (celeste.getConfig().getBoolean("shooting-stars-enabled") ? "Enabled" : "Disabled"));
|
||||
sender.sendMessage("Falling stars: " + (celeste.getConfig().getBoolean("falling-stars-enabled") ? "Enabled" : "Disabled"));
|
||||
sender.sendMessage("Meteor showers: " + (celeste.getConfig().getBoolean("new-moon-meteor-shower") ? "Enabled" : "Disabled"));
|
||||
} else {
|
||||
sender.sendMessage("You do not have permission to use this command");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.idreesinc.celeste.commands;
|
||||
|
||||
import com.idreesinc.celeste.Celeste;
|
||||
import com.idreesinc.celeste.CelestialSphere;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandFallingStar implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandFallingStar(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0) {
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
sender.sendMessage("\u00a7cError: Player not found.");
|
||||
return true;
|
||||
}
|
||||
CelestialSphere.createFallingStar(celeste, Bukkit.getPlayer(args[0]), false);
|
||||
} else {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
CelestialSphere.createFallingStar(celeste, player, false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String message = this.celeste.getConfig().getString("falling-stars-summon-text");
|
||||
if (message != null) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.idreesinc.celeste.commands;
|
||||
|
||||
import com.idreesinc.celeste.Celeste;
|
||||
import com.idreesinc.celeste.CelestialSphere;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class CommandShootingStar implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandShootingStar(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0) {
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
sender.sendMessage("\u00a7cError: Player not found.");
|
||||
return true;
|
||||
}
|
||||
CelestialSphere.createShootingStar(celeste, Bukkit.getPlayer(args[0]), false);
|
||||
} else {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
CelestialSphere.createShootingStar(celeste, player, false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String message = this.celeste.getConfig().getString("shooting-stars-summon-text");
|
||||
if (message != null) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
package com.idreesinc.celeste.config;
|
||||
|
||||
import com.idreesinc.celeste.utilities.WeightedRandomBag;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
public class CelesteConfig {
|
||||
public boolean newMoonMeteorShower;
|
||||
public int beginSpawningStarsTime;
|
||||
public int endSpawningStarsTime;
|
||||
|
||||
public boolean shootingStarsEnabled;
|
||||
public double shootingStarsPerMinute;
|
||||
public double shootingStarsPerMinuteMeteorShower;
|
||||
public int shootingStarsMinHeight;
|
||||
public int shootingStarsMaxHeight;
|
||||
|
||||
public boolean fallingStarsEnabled;
|
||||
public double fallingStarsPerMinute;
|
||||
public double fallingStarsPerMinuteMeteorShower;
|
||||
public int fallingStarsRadius;
|
||||
public boolean fallingStarsSoundEnabled;
|
||||
public double fallingStarsVolume;
|
||||
public int fallingStarsSparkTime;
|
||||
public int fallingStarsExperience;
|
||||
public WeightedRandomBag<String> fallingStarSimpleLoot;
|
||||
public String fallingStarLootTable;
|
||||
|
||||
public CelesteConfig(ConfigurationSection section) {
|
||||
// Used to build the global config
|
||||
buildFromConfigurationSection(section);
|
||||
}
|
||||
|
||||
public CelesteConfig(ConfigurationSection section, CelesteConfig globalConfig) {
|
||||
// Used to build per-world configs
|
||||
buildFromConfigurationSectionWithGlobal(section, globalConfig);
|
||||
}
|
||||
|
||||
private void buildFromConfigurationSection(ConfigurationSection section) {
|
||||
newMoonMeteorShower = section.getBoolean("new-moon-meteor-shower");
|
||||
beginSpawningStarsTime = section.getInt("begin-spawning-stars-time");
|
||||
endSpawningStarsTime = section.getInt("end-spawning-stars-time");
|
||||
|
||||
shootingStarsEnabled = section.getBoolean("shooting-stars-enabled");
|
||||
shootingStarsPerMinute = section.getDouble("shooting-stars-per-minute");
|
||||
shootingStarsPerMinuteMeteorShower = section.getDouble("shooting-stars-per-minute-during-meteor-showers");
|
||||
shootingStarsMinHeight = section.getInt("shooting-stars-min-height");
|
||||
shootingStarsMaxHeight = section.getInt("shooting-stars-max-height");
|
||||
|
||||
fallingStarsEnabled = section.getBoolean("falling-stars-enabled");
|
||||
fallingStarsPerMinute = section.getDouble("falling-stars-per-minute");
|
||||
fallingStarsPerMinuteMeteorShower = section.getDouble("falling-stars-per-minute-during-meteor-showers");
|
||||
fallingStarsRadius = section.getInt("falling-stars-radius");
|
||||
fallingStarsSoundEnabled = section.getBoolean("falling-stars-sound-enabled");
|
||||
fallingStarsVolume = section.getDouble("falling-stars-volume");
|
||||
fallingStarsSparkTime = section.getInt("falling-stars-spark-time");
|
||||
fallingStarsExperience = section.getInt("falling-stars-experience");
|
||||
|
||||
fallingStarLootTable = section.getString("falling-stars-loot-table");
|
||||
if (section.isSet("falling-stars-loot")) {
|
||||
fallingStarSimpleLoot = calculateSimpleLoot(section.getConfigurationSection("falling-stars-loot"));
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFromConfigurationSectionWithGlobal(ConfigurationSection section, CelesteConfig globalConfig) {
|
||||
newMoonMeteorShower = section.getBoolean("new-moon-meteor-shower", globalConfig.newMoonMeteorShower);
|
||||
beginSpawningStarsTime = section.getInt("begin-spawning-stars-time", globalConfig.beginSpawningStarsTime);
|
||||
endSpawningStarsTime = section.getInt("end-spawning-stars-time", globalConfig.endSpawningStarsTime);
|
||||
|
||||
shootingStarsEnabled = section.getBoolean("shooting-stars-enabled", globalConfig.shootingStarsEnabled);
|
||||
shootingStarsPerMinute = section.getDouble("shooting-stars-per-minute", globalConfig.shootingStarsPerMinute);
|
||||
shootingStarsPerMinuteMeteorShower = section.getDouble("shooting-stars-per-minute-during-meteor-showers", globalConfig.shootingStarsPerMinuteMeteorShower);
|
||||
shootingStarsMinHeight = section.getInt("shooting-stars-min-height", globalConfig.shootingStarsMinHeight);
|
||||
shootingStarsMaxHeight = section.getInt("shooting-stars-max-height", globalConfig.shootingStarsMaxHeight);
|
||||
|
||||
fallingStarsEnabled = section.getBoolean("falling-stars-enabled", globalConfig.fallingStarsEnabled);
|
||||
fallingStarsPerMinute = section.getDouble("falling-stars-per-minute", globalConfig.fallingStarsPerMinute);
|
||||
fallingStarsPerMinuteMeteorShower = section.getDouble("falling-stars-per-minute-during-meteor-showers", globalConfig.fallingStarsPerMinuteMeteorShower);
|
||||
fallingStarsRadius = section.getInt("falling-stars-radius", globalConfig.fallingStarsRadius);
|
||||
fallingStarsSoundEnabled = section.getBoolean("falling-stars-sound-enabled", globalConfig.fallingStarsSoundEnabled);
|
||||
fallingStarsVolume = section.getDouble("falling-stars-volume", globalConfig.fallingStarsVolume);
|
||||
fallingStarsSparkTime = section.getInt("falling-stars-spark-time", globalConfig.fallingStarsSparkTime);
|
||||
fallingStarsExperience = section.getInt("falling-stars-experience", globalConfig.fallingStarsExperience);
|
||||
|
||||
if (section.isSet("falling-stars-loot") || section.isSet("falling-stars-loot-table")) {
|
||||
// Ensure that neither type of loot is inherited from the global config if any overrides are used
|
||||
// This means that even if the global config sets simple loot and the world config overrides just loot
|
||||
// table, the end result will be a config with the loot table set and the simple table empty
|
||||
fallingStarLootTable = section.getString("falling-stars-loot-table");
|
||||
if (section.isSet("falling-stars-loot")) {
|
||||
fallingStarSimpleLoot = calculateSimpleLoot(section.getConfigurationSection("falling-stars-loot"));
|
||||
}
|
||||
} else {
|
||||
fallingStarLootTable = globalConfig.fallingStarLootTable;
|
||||
fallingStarSimpleLoot = globalConfig.fallingStarSimpleLoot;
|
||||
}
|
||||
}
|
||||
|
||||
public WeightedRandomBag<String> calculateSimpleLoot(ConfigurationSection loot) {
|
||||
WeightedRandomBag<String> fallingStarDrops = new WeightedRandomBag<>();
|
||||
for (String key : loot.getKeys(false)) {
|
||||
try {
|
||||
Material.valueOf(key.toUpperCase());
|
||||
fallingStarDrops.addEntry(key.toUpperCase(), loot.getDouble(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Error: Item with name " + key.toUpperCase() + " does not exist, skipping");
|
||||
}
|
||||
}
|
||||
return fallingStarDrops;
|
||||
}
|
||||
}
|
||||
@@ -1,838 +0,0 @@
|
||||
package com.idreesinc.celeste.utilities;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
public class Metrics {
|
||||
|
||||
private final Plugin plugin;
|
||||
|
||||
private final MetricsBase metricsBase;
|
||||
|
||||
/**
|
||||
* Creates a new Metrics instance.
|
||||
*
|
||||
* @param plugin Your plugin instance.
|
||||
* @param serviceId The id of the service. It can be found at <a
|
||||
* href="https://bstats.org/what-is-my-plugin-id">What is my plugin id?</a>
|
||||
*/
|
||||
public Metrics(JavaPlugin plugin, int serviceId) {
|
||||
this.plugin = plugin;
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
YamlConfiguration config = YamlConfiguration.loadConfiguration(configFile);
|
||||
if (!config.isSet("serverUuid")) {
|
||||
config.addDefault("enabled", true);
|
||||
config.addDefault("serverUuid", UUID.randomUUID().toString());
|
||||
config.addDefault("logFailedRequests", false);
|
||||
config.addDefault("logSentData", false);
|
||||
config.addDefault("logResponseStatusText", false);
|
||||
// Inform the server owners about bStats
|
||||
config
|
||||
.options()
|
||||
.header(
|
||||
"bStats (https://bStats.org) collects some basic information for plugin authors, like how\n"
|
||||
+ "many people use their plugin and their total player count. It's recommended to keep bStats\n"
|
||||
+ "enabled, but if you're not comfortable with this, you can turn this setting off. There is no\n"
|
||||
+ "performance penalty associated with having metrics enabled, and data sent to bStats is fully\n"
|
||||
+ "anonymous.")
|
||||
.copyDefaults(true);
|
||||
try {
|
||||
config.save(configFile);
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
// Load the data
|
||||
boolean enabled = config.getBoolean("enabled", true);
|
||||
String serverUUID = config.getString("serverUuid");
|
||||
boolean logErrors = config.getBoolean("logFailedRequests", false);
|
||||
boolean logSentData = config.getBoolean("logSentData", false);
|
||||
boolean logResponseStatusText = config.getBoolean("logResponseStatusText", false);
|
||||
metricsBase =
|
||||
new MetricsBase(
|
||||
"bukkit",
|
||||
serverUUID,
|
||||
serviceId,
|
||||
enabled,
|
||||
this::appendPlatformData,
|
||||
this::appendServiceData,
|
||||
submitDataTask -> Bukkit.getScheduler().runTask(plugin, submitDataTask),
|
||||
plugin::isEnabled,
|
||||
(message, error) -> this.plugin.getLogger().log(Level.WARNING, message, error),
|
||||
(message) -> this.plugin.getLogger().log(Level.INFO, message),
|
||||
logErrors,
|
||||
logSentData,
|
||||
logResponseStatusText);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom chart.
|
||||
*
|
||||
* @param chart The chart to add.
|
||||
*/
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
metricsBase.addCustomChart(chart);
|
||||
}
|
||||
|
||||
private void appendPlatformData(JsonObjectBuilder builder) {
|
||||
builder.appendField("playerAmount", getPlayerAmount());
|
||||
builder.appendField("onlineMode", Bukkit.getOnlineMode() ? 1 : 0);
|
||||
builder.appendField("bukkitVersion", Bukkit.getVersion());
|
||||
builder.appendField("bukkitName", Bukkit.getName());
|
||||
builder.appendField("javaVersion", System.getProperty("java.version"));
|
||||
builder.appendField("osName", System.getProperty("os.name"));
|
||||
builder.appendField("osArch", System.getProperty("os.arch"));
|
||||
builder.appendField("osVersion", System.getProperty("os.version"));
|
||||
builder.appendField("coreCount", Runtime.getRuntime().availableProcessors());
|
||||
}
|
||||
|
||||
private void appendServiceData(JsonObjectBuilder builder) {
|
||||
builder.appendField("pluginVersion", plugin.getDescription().getVersion());
|
||||
}
|
||||
|
||||
private int getPlayerAmount() {
|
||||
try {
|
||||
// Around MC 1.8 the return type was changed from an array to a collection,
|
||||
// This fixes java.lang.NoSuchMethodError:
|
||||
// org.bukkit.Bukkit.getOnlinePlayers()Ljava/util/Collection;
|
||||
Method onlinePlayersMethod = Class.forName("org.bukkit.Server").getMethod("getOnlinePlayers");
|
||||
return onlinePlayersMethod.getReturnType().equals(Collection.class)
|
||||
? ((Collection<?>) onlinePlayersMethod.invoke(Bukkit.getServer())).size()
|
||||
: ((Player[]) onlinePlayersMethod.invoke(Bukkit.getServer())).length;
|
||||
} catch (Exception e) {
|
||||
// Just use the new method if the reflection failed
|
||||
return Bukkit.getOnlinePlayers().size();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MetricsBase {
|
||||
|
||||
/** The version of the Metrics class. */
|
||||
public static final String METRICS_VERSION = "2.2.1";
|
||||
|
||||
private static final ScheduledExecutorService scheduler =
|
||||
Executors.newScheduledThreadPool(1, task -> new Thread(task, "bStats-Metrics"));
|
||||
|
||||
private static final String REPORT_URL = "https://bStats.org/api/v2/data/%s";
|
||||
|
||||
private final String platform;
|
||||
|
||||
private final String serverUuid;
|
||||
|
||||
private final int serviceId;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendPlatformDataConsumer;
|
||||
|
||||
private final Consumer<JsonObjectBuilder> appendServiceDataConsumer;
|
||||
|
||||
private final Consumer<Runnable> submitTaskConsumer;
|
||||
|
||||
private final Supplier<Boolean> checkServiceEnabledSupplier;
|
||||
|
||||
private final BiConsumer<String, Throwable> errorLogger;
|
||||
|
||||
private final Consumer<String> infoLogger;
|
||||
|
||||
private final boolean logErrors;
|
||||
|
||||
private final boolean logSentData;
|
||||
|
||||
private final boolean logResponseStatusText;
|
||||
|
||||
private final Set<CustomChart> customCharts = new HashSet<>();
|
||||
|
||||
private final boolean enabled;
|
||||
|
||||
/**
|
||||
* Creates a new MetricsBase class instance.
|
||||
*
|
||||
* @param platform The platform of the service.
|
||||
* @param serviceId The id of the service.
|
||||
* @param serverUuid The server uuid.
|
||||
* @param enabled Whether or not data sending is enabled.
|
||||
* @param appendPlatformDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all platform-specific data.
|
||||
* @param appendServiceDataConsumer A consumer that receives a {@code JsonObjectBuilder} and
|
||||
* appends all service-specific data.
|
||||
* @param submitTaskConsumer A consumer that takes a runnable with the submit task. This can be
|
||||
* used to delegate the data collection to a another thread to prevent errors caused by
|
||||
* concurrency. Can be {@code null}.
|
||||
* @param checkServiceEnabledSupplier A supplier to check if the service is still enabled.
|
||||
* @param errorLogger A consumer that accepts log message and an error.
|
||||
* @param infoLogger A consumer that accepts info log messages.
|
||||
* @param logErrors Whether or not errors should be logged.
|
||||
* @param logSentData Whether or not the sent data should be logged.
|
||||
* @param logResponseStatusText Whether or not the response status text should be logged.
|
||||
*/
|
||||
public MetricsBase(
|
||||
String platform,
|
||||
String serverUuid,
|
||||
int serviceId,
|
||||
boolean enabled,
|
||||
Consumer<JsonObjectBuilder> appendPlatformDataConsumer,
|
||||
Consumer<JsonObjectBuilder> appendServiceDataConsumer,
|
||||
Consumer<Runnable> submitTaskConsumer,
|
||||
Supplier<Boolean> checkServiceEnabledSupplier,
|
||||
BiConsumer<String, Throwable> errorLogger,
|
||||
Consumer<String> infoLogger,
|
||||
boolean logErrors,
|
||||
boolean logSentData,
|
||||
boolean logResponseStatusText) {
|
||||
this.platform = platform;
|
||||
this.serverUuid = serverUuid;
|
||||
this.serviceId = serviceId;
|
||||
this.enabled = enabled;
|
||||
this.appendPlatformDataConsumer = appendPlatformDataConsumer;
|
||||
this.appendServiceDataConsumer = appendServiceDataConsumer;
|
||||
this.submitTaskConsumer = submitTaskConsumer;
|
||||
this.checkServiceEnabledSupplier = checkServiceEnabledSupplier;
|
||||
this.errorLogger = errorLogger;
|
||||
this.infoLogger = infoLogger;
|
||||
this.logErrors = logErrors;
|
||||
this.logSentData = logSentData;
|
||||
this.logResponseStatusText = logResponseStatusText;
|
||||
checkRelocation();
|
||||
if (enabled) {
|
||||
startSubmitting();
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomChart(CustomChart chart) {
|
||||
this.customCharts.add(chart);
|
||||
}
|
||||
|
||||
private void startSubmitting() {
|
||||
final Runnable submitTask =
|
||||
() -> {
|
||||
if (!enabled || !checkServiceEnabledSupplier.get()) {
|
||||
// Submitting data or service is disabled
|
||||
scheduler.shutdown();
|
||||
return;
|
||||
}
|
||||
if (submitTaskConsumer != null) {
|
||||
submitTaskConsumer.accept(this::submitData);
|
||||
} else {
|
||||
this.submitData();
|
||||
}
|
||||
};
|
||||
// Many servers tend to restart at a fixed time at xx:00 which causes an uneven distribution
|
||||
// of requests on the
|
||||
// bStats backend. To circumvent this problem, we introduce some randomness into the initial
|
||||
// and second delay.
|
||||
// WARNING: You must not modify and part of this Metrics class, including the submit delay or
|
||||
// frequency!
|
||||
// WARNING: Modifying this code will get your plugin banned on bStats. Just don't do it!
|
||||
long initialDelay = (long) (1000 * 60 * (3 + Math.random() * 3));
|
||||
long secondDelay = (long) (1000 * 60 * (Math.random() * 30));
|
||||
scheduler.schedule(submitTask, initialDelay, TimeUnit.MILLISECONDS);
|
||||
scheduler.scheduleAtFixedRate(
|
||||
submitTask, initialDelay + secondDelay, 1000 * 60 * 30, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void submitData() {
|
||||
final JsonObjectBuilder baseJsonBuilder = new JsonObjectBuilder();
|
||||
appendPlatformDataConsumer.accept(baseJsonBuilder);
|
||||
final JsonObjectBuilder serviceJsonBuilder = new JsonObjectBuilder();
|
||||
appendServiceDataConsumer.accept(serviceJsonBuilder);
|
||||
JsonObjectBuilder.JsonObject[] chartData =
|
||||
customCharts.stream()
|
||||
.map(customChart -> customChart.getRequestJsonObject(errorLogger, logErrors))
|
||||
.filter(Objects::nonNull)
|
||||
.toArray(JsonObjectBuilder.JsonObject[]::new);
|
||||
serviceJsonBuilder.appendField("id", serviceId);
|
||||
serviceJsonBuilder.appendField("customCharts", chartData);
|
||||
baseJsonBuilder.appendField("service", serviceJsonBuilder.build());
|
||||
baseJsonBuilder.appendField("serverUUID", serverUuid);
|
||||
baseJsonBuilder.appendField("metricsVersion", METRICS_VERSION);
|
||||
JsonObjectBuilder.JsonObject data = baseJsonBuilder.build();
|
||||
scheduler.execute(
|
||||
() -> {
|
||||
try {
|
||||
// Send the data
|
||||
sendData(data);
|
||||
} catch (Exception e) {
|
||||
// Something went wrong! :(
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Could not submit bStats metrics data", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sendData(JsonObjectBuilder.JsonObject data) throws Exception {
|
||||
if (logSentData) {
|
||||
infoLogger.accept("Sent bStats metrics data: " + data.toString());
|
||||
}
|
||||
String url = String.format(REPORT_URL, platform);
|
||||
HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
|
||||
// Compress the data to save bandwidth
|
||||
byte[] compressedData = compress(data.toString());
|
||||
connection.setRequestMethod("POST");
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(compressedData.length));
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setRequestProperty("User-Agent", "Metrics-Service/1");
|
||||
connection.setDoOutput(true);
|
||||
try (DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream())) {
|
||||
outputStream.write(compressedData);
|
||||
}
|
||||
StringBuilder builder = new StringBuilder();
|
||||
try (BufferedReader bufferedReader =
|
||||
new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
builder.append(line);
|
||||
}
|
||||
}
|
||||
if (logResponseStatusText) {
|
||||
infoLogger.accept("Sent data to bStats and received response: " + builder);
|
||||
}
|
||||
}
|
||||
|
||||
/** Checks that the class was properly relocated. */
|
||||
private void checkRelocation() {
|
||||
// You can use the property to disable the check in your test environment
|
||||
if (System.getProperty("bstats.relocatecheck") == null
|
||||
|| !System.getProperty("bstats.relocatecheck").equals("false")) {
|
||||
// Maven's Relocate is clever and changes strings, too. So we have to use this little
|
||||
// "trick" ... :D
|
||||
final String defaultPackage =
|
||||
new String(new byte[] {'o', 'r', 'g', '.', 'b', 's', 't', 'a', 't', 's'});
|
||||
final String examplePackage =
|
||||
new String(new byte[] {'y', 'o', 'u', 'r', '.', 'p', 'a', 'c', 'k', 'a', 'g', 'e'});
|
||||
// We want to make sure no one just copy & pastes the example and uses the wrong package
|
||||
// names
|
||||
if (MetricsBase.class.getPackage().getName().startsWith(defaultPackage)
|
||||
|| MetricsBase.class.getPackage().getName().startsWith(examplePackage)) {
|
||||
throw new IllegalStateException("bStats Metrics class has not been relocated correctly!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given string.
|
||||
*
|
||||
* @param str The string to gzip.
|
||||
* @return The gzipped string.
|
||||
*/
|
||||
private static byte[] compress(final String str) throws IOException {
|
||||
if (str == null) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(outputStream)) {
|
||||
gzip.write(str.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return outputStream.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, int[]>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedBarChart(String chartId, Callable<Map<String, int[]>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, int[]> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, int[]> entry : map.entrySet()) {
|
||||
if (entry.getValue().length == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimpleBarChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimpleBarChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
valuesBuilder.appendField(entry.getKey(), new int[] {entry.getValue()});
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultiLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public MultiLineChart(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class AdvancedPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Integer>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public AdvancedPie(String chartId, Callable<Map<String, Integer>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Integer> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> entry : map.entrySet()) {
|
||||
if (entry.getValue() == 0) {
|
||||
// Skip this invalid
|
||||
continue;
|
||||
}
|
||||
allSkipped = false;
|
||||
valuesBuilder.appendField(entry.getKey(), entry.getValue());
|
||||
}
|
||||
if (allSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class CustomChart {
|
||||
|
||||
private final String chartId;
|
||||
|
||||
protected CustomChart(String chartId) {
|
||||
if (chartId == null) {
|
||||
throw new IllegalArgumentException("chartId must not be null");
|
||||
}
|
||||
this.chartId = chartId;
|
||||
}
|
||||
|
||||
public JsonObjectBuilder.JsonObject getRequestJsonObject(
|
||||
BiConsumer<String, Throwable> errorLogger, boolean logErrors) {
|
||||
JsonObjectBuilder builder = new JsonObjectBuilder();
|
||||
builder.appendField("chartId", chartId);
|
||||
try {
|
||||
JsonObjectBuilder.JsonObject data = getChartData();
|
||||
if (data == null) {
|
||||
// If the data is null we don't send the chart.
|
||||
return null;
|
||||
}
|
||||
builder.appendField("data", data);
|
||||
} catch (Throwable t) {
|
||||
if (logErrors) {
|
||||
errorLogger.accept("Failed to get data for custom chart with id " + chartId, t);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
protected abstract JsonObjectBuilder.JsonObject getChartData() throws Exception;
|
||||
}
|
||||
|
||||
public static class SingleLineChart extends CustomChart {
|
||||
|
||||
private final Callable<Integer> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SingleLineChart(String chartId, Callable<Integer> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
int value = callable.call();
|
||||
if (value == 0) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SimplePie extends CustomChart {
|
||||
|
||||
private final Callable<String> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public SimplePie(String chartId, Callable<String> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
String value = callable.call();
|
||||
if (value == null || value.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("value", value).build();
|
||||
}
|
||||
}
|
||||
|
||||
public static class DrilldownPie extends CustomChart {
|
||||
|
||||
private final Callable<Map<String, Map<String, Integer>>> callable;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* @param chartId The id of the chart.
|
||||
* @param callable The callable which is used to request the chart data.
|
||||
*/
|
||||
public DrilldownPie(String chartId, Callable<Map<String, Map<String, Integer>>> callable) {
|
||||
super(chartId);
|
||||
this.callable = callable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JsonObjectBuilder.JsonObject getChartData() throws Exception {
|
||||
JsonObjectBuilder valuesBuilder = new JsonObjectBuilder();
|
||||
Map<String, Map<String, Integer>> map = callable.call();
|
||||
if (map == null || map.isEmpty()) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
boolean reallyAllSkipped = true;
|
||||
for (Map.Entry<String, Map<String, Integer>> entryValues : map.entrySet()) {
|
||||
JsonObjectBuilder valueBuilder = new JsonObjectBuilder();
|
||||
boolean allSkipped = true;
|
||||
for (Map.Entry<String, Integer> valueEntry : map.get(entryValues.getKey()).entrySet()) {
|
||||
valueBuilder.appendField(valueEntry.getKey(), valueEntry.getValue());
|
||||
allSkipped = false;
|
||||
}
|
||||
if (!allSkipped) {
|
||||
reallyAllSkipped = false;
|
||||
valuesBuilder.appendField(entryValues.getKey(), valueBuilder.build());
|
||||
}
|
||||
}
|
||||
if (reallyAllSkipped) {
|
||||
// Null = skip the chart
|
||||
return null;
|
||||
}
|
||||
return new JsonObjectBuilder().appendField("values", valuesBuilder.build()).build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An extremely simple JSON builder.
|
||||
*
|
||||
* <p>While this class is neither feature-rich nor the most performant one, it's sufficient enough
|
||||
* for its use-case.
|
||||
*/
|
||||
public static class JsonObjectBuilder {
|
||||
|
||||
private StringBuilder builder = new StringBuilder();
|
||||
|
||||
private boolean hasAtLeastOneField = false;
|
||||
|
||||
public JsonObjectBuilder() {
|
||||
builder.append("{");
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a null field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendNull(String key) {
|
||||
appendFieldUnescaped(key, "null");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String value) {
|
||||
if (value == null) {
|
||||
throw new IllegalArgumentException("JSON value must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, "\"" + escape(value) + "\"");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer field to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param value The value of the field.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int value) {
|
||||
appendFieldUnescaped(key, String.valueOf(value));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param object The object.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject object) {
|
||||
if (object == null) {
|
||||
throw new IllegalArgumentException("JSON object must not be null");
|
||||
}
|
||||
appendFieldUnescaped(key, object.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a string array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The string array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, String[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values)
|
||||
.map(value -> "\"" + escape(value) + "\"")
|
||||
.collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an integer array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, int[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).mapToObj(String::valueOf).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an object array to the JSON.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param values The integer array.
|
||||
* @return A reference to this object.
|
||||
*/
|
||||
public JsonObjectBuilder appendField(String key, JsonObject[] values) {
|
||||
if (values == null) {
|
||||
throw new IllegalArgumentException("JSON values must not be null");
|
||||
}
|
||||
String escapedValues =
|
||||
Arrays.stream(values).map(JsonObject::toString).collect(Collectors.joining(","));
|
||||
appendFieldUnescaped(key, "[" + escapedValues + "]");
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a field to the object.
|
||||
*
|
||||
* @param key The key of the field.
|
||||
* @param escapedValue The escaped value of the field.
|
||||
*/
|
||||
private void appendFieldUnescaped(String key, String escapedValue) {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
if (key == null) {
|
||||
throw new IllegalArgumentException("JSON key must not be null");
|
||||
}
|
||||
if (hasAtLeastOneField) {
|
||||
builder.append(",");
|
||||
}
|
||||
builder.append("\"").append(escape(key)).append("\":").append(escapedValue);
|
||||
hasAtLeastOneField = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the JSON string and invalidates this builder.
|
||||
*
|
||||
* @return The built JSON string.
|
||||
*/
|
||||
public JsonObject build() {
|
||||
if (builder == null) {
|
||||
throw new IllegalStateException("JSON has already been built");
|
||||
}
|
||||
JsonObject object = new JsonObject(builder.append("}").toString());
|
||||
builder = null;
|
||||
return object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes the given string like stated in https://www.ietf.org/rfc/rfc4627.txt.
|
||||
*
|
||||
* <p>This method escapes only the necessary characters '"', '\'. and '\u0000' - '\u001F'.
|
||||
* Compact escapes are not used (e.g., '\n' is escaped as "\u000a" and not as "\n").
|
||||
*
|
||||
* @param value The value to escape.
|
||||
* @return The escaped value.
|
||||
*/
|
||||
private static String escape(String value) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
char c = value.charAt(i);
|
||||
if (c == '"') {
|
||||
builder.append("\\\"");
|
||||
} else if (c == '\\') {
|
||||
builder.append("\\\\");
|
||||
} else if (c <= '\u000F') {
|
||||
builder.append("\\u000").append(Integer.toHexString(c));
|
||||
} else if (c <= '\u001F') {
|
||||
builder.append("\\u00").append(Integer.toHexString(c));
|
||||
} else {
|
||||
builder.append(c);
|
||||
}
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A super simple representation of a JSON object.
|
||||
*
|
||||
* <p>This class only exists to make methods of the {@link JsonObjectBuilder} type-safe and not
|
||||
* allow a raw string inputs for methods like {@link JsonObjectBuilder#appendField(String,
|
||||
* JsonObject)}.
|
||||
*/
|
||||
public static class JsonObject {
|
||||
|
||||
private final String value;
|
||||
|
||||
private JsonObject(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
package com.idreesinc.celeste.utilities;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.util.Consumer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Scanner;
|
||||
|
||||
public class UpdateChecker {
|
||||
|
||||
private Plugin plugin;
|
||||
private int resourceId;
|
||||
|
||||
public UpdateChecker(Plugin plugin, int resourceId) {
|
||||
this.plugin = plugin;
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
public void getVersion(final Consumer<String> consumer) {
|
||||
Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> {
|
||||
try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream(); Scanner scanner = new Scanner(inputStream)) {
|
||||
if (scanner.hasNext()) {
|
||||
consumer.accept(scanner.next());
|
||||
}
|
||||
} catch (IOException exception) {
|
||||
this.plugin.getLogger().info("Cannot look for updates: " + exception.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
package com.idreesinc.celeste.utilities;
|
||||
//From https://gamedev.stackexchange.com/a/162987
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class WeightedRandomBag<T extends Object> {
|
||||
|
||||
private class Entry {
|
||||
double accumulatedWeight;
|
||||
T object;
|
||||
}
|
||||
|
||||
public List<Entry> entries = new ArrayList<Entry>();
|
||||
private double accumulatedWeight;
|
||||
private Random rand = new Random();
|
||||
|
||||
public void addEntry(T object, double weight) {
|
||||
accumulatedWeight += weight;
|
||||
Entry e = new Entry();
|
||||
e.object = object;
|
||||
e.accumulatedWeight = accumulatedWeight;
|
||||
entries.add(e);
|
||||
}
|
||||
|
||||
public T getRandom() {
|
||||
double r = rand.nextDouble() * accumulatedWeight;
|
||||
for (Entry entry: entries) {
|
||||
if (entry.accumulatedWeight >= r) {
|
||||
return entry.object;
|
||||
}
|
||||
}
|
||||
// Should only happen when there are no entries
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package net.trueog.celeste;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import net.trueog.celeste.config.CelesteConfig;
|
||||
|
||||
public class Astronomer extends BukkitRunnable {
|
||||
|
||||
private final Celeste celeste;
|
||||
|
||||
public Astronomer(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
if (celeste.getServer().getOnlinePlayers().size() == 0) {
|
||||
return;
|
||||
}
|
||||
List<World> worlds = celeste.getServer().getWorlds();
|
||||
for (World world : worlds) {
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(world.getName());
|
||||
if (!celeste.configManager.doesWorldHaveOverrides(world.getName())
|
||||
&& !world.getEnvironment().equals(World.Environment.NORMAL)) {
|
||||
// Ensure that Celeste only runs on normal worlds unless override is specified in config
|
||||
continue;
|
||||
}
|
||||
if (world.getPlayers().size() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!(world.getTime() >= config.beginSpawningStarsTime && world.getTime() <= config.endSpawningStarsTime)) {
|
||||
continue;
|
||||
}
|
||||
if (world.hasStorm()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double shootingStarChance;
|
||||
double fallingStarChance;
|
||||
if (config.newMoonMeteorShower && (world.getFullTime() / 24000) % 8 == 4) {
|
||||
shootingStarChance = config.shootingStarsPerMinuteMeteorShower / 120d;
|
||||
fallingStarChance = config.fallingStarsPerMinuteMeteorShower / 120d;
|
||||
} else {
|
||||
shootingStarChance = config.shootingStarsPerMinute / 120d;
|
||||
fallingStarChance = config.fallingStarsPerMinute / 120d;
|
||||
}
|
||||
|
||||
if (config.shootingStarsEnabled && new Random().nextDouble() <= shootingStarChance) {
|
||||
CelestialSphere.createShootingStar(celeste,
|
||||
world.getPlayers().get(new Random().nextInt(world.getPlayers().size())));
|
||||
}
|
||||
if (config.fallingStarsEnabled && new Random().nextDouble() <= fallingStarChance) {
|
||||
CelestialSphere.createFallingStar(celeste,
|
||||
world.getPlayers().get(new Random().nextInt(world.getPlayers().size())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package net.trueog.celeste;
|
||||
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import net.trueog.celeste.commands.CommandCeleste;
|
||||
import net.trueog.celeste.commands.CommandFallingStar;
|
||||
import net.trueog.celeste.commands.CommandShootingStar;
|
||||
import net.trueog.celeste.config.CelesteConfigManager;
|
||||
|
||||
public class Celeste extends JavaPlugin {
|
||||
|
||||
public CelesteConfigManager configManager = new CelesteConfigManager(this);
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
this.saveDefaultConfig();
|
||||
|
||||
this.getCommand("celeste").setExecutor(new CommandCeleste(this));
|
||||
this.getCommand("shootingstar").setExecutor(new CommandShootingStar(this));
|
||||
this.getCommand("fallingstar").setExecutor(new CommandFallingStar(this));
|
||||
configManager.processConfigs();
|
||||
|
||||
BukkitRunnable stargazingTask = new Astronomer(this);
|
||||
stargazingTask.runTaskTimer(this, 0, 10);
|
||||
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
reloadConfig();
|
||||
configManager.processConfigs();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
package net.trueog.celeste;
|
||||
|
||||
import java.math.RoundingMode;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import net.trueog.celeste.config.CelesteConfig;
|
||||
|
||||
public class CelestialSphere {
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Player player) {
|
||||
createShootingStar(celeste, player, true);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Player player, boolean approximate) {
|
||||
createShootingStar(celeste, player.getLocation(), approximate);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Location location) {
|
||||
createShootingStar(celeste, location, true);
|
||||
}
|
||||
|
||||
public static void createShootingStar(Celeste celeste, Location location, boolean approximate) {
|
||||
Location starLocation;
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
double w = 100 * Math.sqrt(new Random().nextDouble());
|
||||
double t = 2d * Math.PI * new Random().nextDouble();
|
||||
double x = w * Math.cos(t);
|
||||
double range = Math.max(0, config.shootingStarsMaxHeight - config.shootingStarsMinHeight);
|
||||
double y = Math.max(new Random().nextDouble() * range + config.shootingStarsMinHeight, location.getY() + 50);
|
||||
double z = w * Math.sin(t);
|
||||
if (approximate) {
|
||||
starLocation = new Location(location.getWorld(), location.getX() + x, y, location.getZ() + z);
|
||||
} else {
|
||||
starLocation = new Location(location.getWorld(), location.getX(), y, location.getZ());
|
||||
}
|
||||
Vector direction = new Vector(new Random().nextDouble() * 2 - 1, new Random().nextDouble() * -0.75d, new Random().nextDouble() * 2 - 1);
|
||||
direction.normalize();
|
||||
double speed = new Random().nextDouble() * 2 + 0.75;
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, starLocation, 0, direction.getX(),
|
||||
direction.getY(), direction.getZ(), speed, null, true);
|
||||
if (new Random().nextDouble() >= 0.5) {
|
||||
location.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, starLocation, 0, direction.getX(),
|
||||
direction.getY(), direction.getZ(), speed, null, true);
|
||||
}
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Shooting star at " + stringifyLocation(starLocation) + " in world " + starLocation.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, Player player) {
|
||||
createFallingStar(celeste, player, true);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, Player player, boolean approximate) {
|
||||
createFallingStar(celeste, player.getLocation(), approximate);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, final Location location) {
|
||||
createFallingStar(celeste, location, true);
|
||||
}
|
||||
|
||||
public static void createFallingStar(Celeste celeste, final Location location, boolean approximate) {
|
||||
Location target = location;
|
||||
CelesteConfig config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
if (approximate) {
|
||||
double fallingStarRadius = config.fallingStarsRadius;
|
||||
double w = fallingStarRadius * Math.sqrt(new Random().nextDouble());
|
||||
double t = 2d * Math.PI * new Random().nextDouble();
|
||||
double x = w * Math.cos(t);
|
||||
double z = w * Math.sin(t);
|
||||
target = new Location(location.getWorld(), location.getX() + x, location.getY(), location.getZ() + z);
|
||||
}
|
||||
BukkitRunnable fallingStarTask = new FallingStar(celeste, target);
|
||||
fallingStarTask.runTaskTimer(celeste, 0, 1);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Falling star at " + stringifyLocation(target) + " in world " + target.getWorld().getName());
|
||||
}
|
||||
}
|
||||
|
||||
private static String stringifyLocation(Location location) {
|
||||
DecimalFormat format = new DecimalFormat("##.00");
|
||||
format.setRoundingMode(RoundingMode.HALF_UP);
|
||||
return "x: " + format.format(location.getX()) + " y: " + format.format(location.getY()) + " z: " + format.format(location.getZ());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package net.trueog.celeste;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.ExperienceOrb;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
|
||||
import net.trueog.celeste.config.CelesteConfig;
|
||||
|
||||
public class FallingStar extends BukkitRunnable {
|
||||
|
||||
private final Celeste celeste;
|
||||
private final Location location;
|
||||
private final Location dropLoc;
|
||||
private final CelesteConfig config;
|
||||
private double y = 256;
|
||||
private boolean soundPlayed = false;
|
||||
private boolean lootDropped = false;
|
||||
private int sparkTimer;
|
||||
|
||||
public FallingStar(Celeste celeste, Location location) {
|
||||
this.celeste = celeste;
|
||||
this.location = location;
|
||||
config = celeste.configManager.getConfigForWorld(location.getWorld().getName());
|
||||
sparkTimer = config.fallingStarsSparkTime;
|
||||
dropLoc = new Location(location.getWorld(), location.getX(),
|
||||
location.getWorld().getHighestBlockAt(location).getY() + 1, location.getZ());
|
||||
}
|
||||
|
||||
public void run() {
|
||||
double step = 1;
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, location.getX(), y, location.getZ(),
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
0.2, null, true);
|
||||
location.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, location.getX(),
|
||||
y + new Random().nextDouble() * step,
|
||||
location.getZ(),
|
||||
0, 0, -1, 0,
|
||||
1, null, true);
|
||||
if (y % (step * 2) == 0) {
|
||||
location.getWorld().spawnParticle(Particle.LAVA, location.getX(), y + new Random().nextDouble(),
|
||||
location.getZ(),
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
0.2, null, true);
|
||||
}
|
||||
if (config.fallingStarsSoundEnabled && !soundPlayed && y <= dropLoc.getY() + 75) {
|
||||
location.getWorld().playSound(dropLoc, Sound.BLOCK_BELL_RESONATE, (float) config.fallingStarsVolume, 0.5f);
|
||||
soundPlayed = true;
|
||||
}
|
||||
if (y <= dropLoc.getY()) {
|
||||
if (!lootDropped) {
|
||||
// Note that both simple loot and loot tables will drop if both are configured because why not
|
||||
if (config.fallingStarSimpleLoot != null && config.fallingStarSimpleLoot.entries.size() > 0) {
|
||||
ItemStack drop = new ItemStack(Material.valueOf(config.fallingStarSimpleLoot.getRandom()), 1);
|
||||
location.getWorld().dropItem(dropLoc, drop);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Spawned simple falling star loot");
|
||||
}
|
||||
}
|
||||
if (config.fallingStarLootTable != null) {
|
||||
// Armor stands are used as markers are not compatible with 1.14
|
||||
Entity marker = dropLoc.getWorld().spawnEntity(location, EntityType.ARMOR_STAND);
|
||||
String command = String.format("execute at %s run loot spawn %s %s %s loot %s",
|
||||
marker.getUniqueId(),
|
||||
dropLoc.getX(),
|
||||
dropLoc.getY(),
|
||||
dropLoc.getZ(),
|
||||
config.fallingStarLootTable);
|
||||
celeste.getServer().dispatchCommand(celeste.getServer().getConsoleSender(), command);
|
||||
marker.remove();
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Spawned falling star loot from loot table '" + config.fallingStarLootTable + "'");
|
||||
}
|
||||
}
|
||||
if (config.fallingStarsExperience > 0) {
|
||||
ExperienceOrb orb = (ExperienceOrb) dropLoc.getWorld().spawnEntity(dropLoc, EntityType.EXPERIENCE_ORB);
|
||||
orb.setExperience(config.fallingStarsExperience);
|
||||
if (celeste.getConfig().getBoolean("debug")) {
|
||||
celeste.getLogger().info("Dropping experience orbs with value " + config.fallingStarsExperience);
|
||||
}
|
||||
}
|
||||
lootDropped = true;
|
||||
}
|
||||
if (y % (step * 5) == 0) {
|
||||
location.getWorld().spawnParticle(Particle.LAVA, dropLoc,
|
||||
0, 0, new Random().nextDouble(), 0,
|
||||
1, null, true);
|
||||
}
|
||||
sparkTimer--;
|
||||
if (sparkTimer <= 0) {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
y -= step;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package net.trueog.celeste.commands;
|
||||
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import net.trueog.celeste.Celeste;
|
||||
|
||||
public class CommandCeleste implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandCeleste(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length == 1 && args[0].equalsIgnoreCase("reload")) {
|
||||
if (sender.hasPermission("celeste.reload")) {
|
||||
celeste.reload();
|
||||
sender.sendMessage("Celeste has been reloaded");
|
||||
} else {
|
||||
sender.sendMessage("You do not have permission to use this command");
|
||||
}
|
||||
return true;
|
||||
} else if (args.length == 1 && args[0].equalsIgnoreCase("info")) {
|
||||
String version = "1.0";
|
||||
if (sender.hasPermission("celeste.info")) {
|
||||
sender.sendMessage("Celeste-OG" + version);
|
||||
sender.sendMessage("Shooting stars: " + (celeste.getConfig().getBoolean("shooting-stars-enabled") ? "Enabled" : "Disabled"));
|
||||
sender.sendMessage("Falling stars: " + (celeste.getConfig().getBoolean("falling-stars-enabled") ? "Enabled" : "Disabled"));
|
||||
sender.sendMessage("Meteor showers: " + (celeste.getConfig().getBoolean("new-moon-meteor-shower") ? "Enabled" : "Disabled"));
|
||||
} else {
|
||||
sender.sendMessage("You do not have permission to use this command");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.trueog.celeste.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import net.trueog.celeste.Celeste;
|
||||
import net.trueog.celeste.CelestialSphere;
|
||||
|
||||
public class CommandFallingStar implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandFallingStar(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0) {
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
sender.sendMessage("\u00a7cError: Player not found.");
|
||||
return true;
|
||||
}
|
||||
CelestialSphere.createFallingStar(celeste, Bukkit.getPlayer(args[0]), false);
|
||||
} else {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
CelestialSphere.createFallingStar(celeste, player, false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String message = this.celeste.getConfig().getString("falling-stars-summon-text");
|
||||
if (message != null) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package net.trueog.celeste.commands;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import net.trueog.celeste.Celeste;
|
||||
import net.trueog.celeste.CelestialSphere;
|
||||
|
||||
public class CommandShootingStar implements CommandExecutor {
|
||||
|
||||
Celeste celeste;
|
||||
|
||||
public CommandShootingStar(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (args.length > 0) {
|
||||
if (Bukkit.getPlayer(args[0]) == null) {
|
||||
sender.sendMessage("\u00a7cError: Player not found.");
|
||||
return true;
|
||||
}
|
||||
CelestialSphere.createShootingStar(celeste, Bukkit.getPlayer(args[0]), false);
|
||||
} else {
|
||||
if (sender instanceof Player) {
|
||||
Player player = (Player) sender;
|
||||
CelestialSphere.createShootingStar(celeste, player, false);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
String message = this.celeste.getConfig().getString("shooting-stars-summon-text");
|
||||
if (message != null) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package net.trueog.celeste.config;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import net.trueog.celeste.utilities.WeightedRandomBag;
|
||||
|
||||
public class CelesteConfig {
|
||||
public boolean newMoonMeteorShower;
|
||||
public int beginSpawningStarsTime;
|
||||
public int endSpawningStarsTime;
|
||||
|
||||
public boolean shootingStarsEnabled;
|
||||
public double shootingStarsPerMinute;
|
||||
public double shootingStarsPerMinuteMeteorShower;
|
||||
public int shootingStarsMinHeight;
|
||||
public int shootingStarsMaxHeight;
|
||||
|
||||
public boolean fallingStarsEnabled;
|
||||
public double fallingStarsPerMinute;
|
||||
public double fallingStarsPerMinuteMeteorShower;
|
||||
public int fallingStarsRadius;
|
||||
public boolean fallingStarsSoundEnabled;
|
||||
public double fallingStarsVolume;
|
||||
public int fallingStarsSparkTime;
|
||||
public int fallingStarsExperience;
|
||||
public WeightedRandomBag<String> fallingStarSimpleLoot;
|
||||
public String fallingStarLootTable;
|
||||
|
||||
public CelesteConfig(ConfigurationSection section) {
|
||||
// Used to build the global config
|
||||
buildFromConfigurationSection(section);
|
||||
}
|
||||
|
||||
public CelesteConfig(ConfigurationSection section, CelesteConfig globalConfig) {
|
||||
// Used to build per-world configs
|
||||
buildFromConfigurationSectionWithGlobal(section, globalConfig);
|
||||
}
|
||||
|
||||
private void buildFromConfigurationSection(ConfigurationSection section) {
|
||||
newMoonMeteorShower = section.getBoolean("new-moon-meteor-shower");
|
||||
beginSpawningStarsTime = section.getInt("begin-spawning-stars-time");
|
||||
endSpawningStarsTime = section.getInt("end-spawning-stars-time");
|
||||
|
||||
shootingStarsEnabled = section.getBoolean("shooting-stars-enabled");
|
||||
shootingStarsPerMinute = section.getDouble("shooting-stars-per-minute");
|
||||
shootingStarsPerMinuteMeteorShower = section.getDouble("shooting-stars-per-minute-during-meteor-showers");
|
||||
shootingStarsMinHeight = section.getInt("shooting-stars-min-height");
|
||||
shootingStarsMaxHeight = section.getInt("shooting-stars-max-height");
|
||||
|
||||
fallingStarsEnabled = section.getBoolean("falling-stars-enabled");
|
||||
fallingStarsPerMinute = section.getDouble("falling-stars-per-minute");
|
||||
fallingStarsPerMinuteMeteorShower = section.getDouble("falling-stars-per-minute-during-meteor-showers");
|
||||
fallingStarsRadius = section.getInt("falling-stars-radius");
|
||||
fallingStarsSoundEnabled = section.getBoolean("falling-stars-sound-enabled");
|
||||
fallingStarsVolume = section.getDouble("falling-stars-volume");
|
||||
fallingStarsSparkTime = section.getInt("falling-stars-spark-time");
|
||||
fallingStarsExperience = section.getInt("falling-stars-experience");
|
||||
|
||||
fallingStarLootTable = section.getString("falling-stars-loot-table");
|
||||
if (section.isSet("falling-stars-loot")) {
|
||||
fallingStarSimpleLoot = calculateSimpleLoot(section.getConfigurationSection("falling-stars-loot"));
|
||||
}
|
||||
}
|
||||
|
||||
private void buildFromConfigurationSectionWithGlobal(ConfigurationSection section, CelesteConfig globalConfig) {
|
||||
newMoonMeteorShower = section.getBoolean("new-moon-meteor-shower", globalConfig.newMoonMeteorShower);
|
||||
beginSpawningStarsTime = section.getInt("begin-spawning-stars-time", globalConfig.beginSpawningStarsTime);
|
||||
endSpawningStarsTime = section.getInt("end-spawning-stars-time", globalConfig.endSpawningStarsTime);
|
||||
|
||||
shootingStarsEnabled = section.getBoolean("shooting-stars-enabled", globalConfig.shootingStarsEnabled);
|
||||
shootingStarsPerMinute = section.getDouble("shooting-stars-per-minute", globalConfig.shootingStarsPerMinute);
|
||||
shootingStarsPerMinuteMeteorShower = section.getDouble("shooting-stars-per-minute-during-meteor-showers", globalConfig.shootingStarsPerMinuteMeteorShower);
|
||||
shootingStarsMinHeight = section.getInt("shooting-stars-min-height", globalConfig.shootingStarsMinHeight);
|
||||
shootingStarsMaxHeight = section.getInt("shooting-stars-max-height", globalConfig.shootingStarsMaxHeight);
|
||||
|
||||
fallingStarsEnabled = section.getBoolean("falling-stars-enabled", globalConfig.fallingStarsEnabled);
|
||||
fallingStarsPerMinute = section.getDouble("falling-stars-per-minute", globalConfig.fallingStarsPerMinute);
|
||||
fallingStarsPerMinuteMeteorShower = section.getDouble("falling-stars-per-minute-during-meteor-showers", globalConfig.fallingStarsPerMinuteMeteorShower);
|
||||
fallingStarsRadius = section.getInt("falling-stars-radius", globalConfig.fallingStarsRadius);
|
||||
fallingStarsSoundEnabled = section.getBoolean("falling-stars-sound-enabled", globalConfig.fallingStarsSoundEnabled);
|
||||
fallingStarsVolume = section.getDouble("falling-stars-volume", globalConfig.fallingStarsVolume);
|
||||
fallingStarsSparkTime = section.getInt("falling-stars-spark-time", globalConfig.fallingStarsSparkTime);
|
||||
fallingStarsExperience = section.getInt("falling-stars-experience", globalConfig.fallingStarsExperience);
|
||||
|
||||
if (section.isSet("falling-stars-loot") || section.isSet("falling-stars-loot-table")) {
|
||||
// Ensure that neither type of loot is inherited from the global config if any overrides are used
|
||||
// This means that even if the global config sets simple loot and the world config overrides just loot
|
||||
// table, the end result will be a config with the loot table set and the simple table empty
|
||||
fallingStarLootTable = section.getString("falling-stars-loot-table");
|
||||
if (section.isSet("falling-stars-loot")) {
|
||||
fallingStarSimpleLoot = calculateSimpleLoot(section.getConfigurationSection("falling-stars-loot"));
|
||||
}
|
||||
} else {
|
||||
fallingStarLootTable = globalConfig.fallingStarLootTable;
|
||||
fallingStarSimpleLoot = globalConfig.fallingStarSimpleLoot;
|
||||
}
|
||||
}
|
||||
|
||||
public WeightedRandomBag<String> calculateSimpleLoot(ConfigurationSection loot) {
|
||||
WeightedRandomBag<String> fallingStarDrops = new WeightedRandomBag<>();
|
||||
for (String key : loot.getKeys(false)) {
|
||||
try {
|
||||
Material.valueOf(key.toUpperCase());
|
||||
fallingStarDrops.addEntry(key.toUpperCase(), loot.getDouble(key));
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Error: Item with name " + key.toUpperCase() + " does not exist, skipping");
|
||||
}
|
||||
}
|
||||
return fallingStarDrops;
|
||||
}
|
||||
}
|
||||
+8
-7
@@ -1,14 +1,15 @@
|
||||
package com.idreesinc.celeste.config;
|
||||
|
||||
import com.idreesinc.celeste.Celeste;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
package net.trueog.celeste.config;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
|
||||
import net.trueog.celeste.Celeste;
|
||||
|
||||
public class CelesteConfigManager {
|
||||
|
||||
|
||||
private final Celeste celeste;
|
||||
private final Map<String, CelesteConfig> worldConfigs = new HashMap<>();
|
||||
private CelesteConfig globalConfig;
|
||||
@@ -16,7 +17,7 @@ public class CelesteConfigManager {
|
||||
public CelesteConfigManager(Celeste celeste) {
|
||||
this.celeste = celeste;
|
||||
}
|
||||
|
||||
|
||||
public void processConfigs() {
|
||||
this.worldConfigs.clear();
|
||||
FileConfiguration config = this.celeste.getConfig();
|
||||
@@ -0,0 +1,37 @@
|
||||
package net.trueog.celeste.utilities;
|
||||
//From https://gamedev.stackexchange.com/a/162987
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
public class WeightedRandomBag<T extends Object> {
|
||||
|
||||
private class Entry {
|
||||
double accumulatedWeight;
|
||||
T object;
|
||||
}
|
||||
|
||||
public List<Entry> entries = new ArrayList<Entry>();
|
||||
private double accumulatedWeight;
|
||||
private Random rand = new Random();
|
||||
|
||||
public void addEntry(T object, double weight) {
|
||||
accumulatedWeight += weight;
|
||||
Entry e = new Entry();
|
||||
e.object = object;
|
||||
e.accumulatedWeight = accumulatedWeight;
|
||||
entries.add(e);
|
||||
}
|
||||
|
||||
public T getRandom() {
|
||||
double r = rand.nextDouble() * accumulatedWeight;
|
||||
for (Entry entry: entries) {
|
||||
if (entry.accumulatedWeight >= r) {
|
||||
return entry.object;
|
||||
}
|
||||
}
|
||||
// Should only happen when there are no entries
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
check-for-updates: true
|
||||
shooting-stars-enabled: true
|
||||
falling-stars-enabled: true
|
||||
begin-spawning-stars-time: 13000
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
name: Celeste
|
||||
version: 2.0
|
||||
api-version: 1.14
|
||||
author: Idrees
|
||||
main: com.idreesinc.celeste.Celeste
|
||||
name: Celeste-OG
|
||||
version: 1.0
|
||||
api-version: 1.19
|
||||
authors: [NotAlexNoyle, Idrees]
|
||||
main: net.trueog.celeste.Celeste
|
||||
|
||||
commands:
|
||||
celeste:
|
||||
@@ -19,7 +19,7 @@ commands:
|
||||
|
||||
permissions:
|
||||
celeste.*:
|
||||
description: Gives access to all Celeste commands
|
||||
description: Gives access to all Celeste-OG commands
|
||||
children:
|
||||
celeste.reload: true
|
||||
celeste.info: true
|
||||
|
||||
Reference in new issue
Block a user