76 Commits
v1.1.1 ... main

Author SHA1 Message Date
Jack
f99eceb46f make time/weather command checks more strict (closes #19) 2025-06-22 23:30:50 -04:00
Jack
df9b8f1fcd Merge pull request #18 from Karotte128/main
fix SunriseSunsetRequest to use right config values
2025-05-29 00:51:17 -04:00
Karotte128
6f5f69ee9e fix SunriseSunsetRequest to use right config variables 2025-02-22 22:09:51 +01:00
Jack
333325c4e0 Clean up fixed calculateWorldTime method 2024-08-06 21:10:22 -04:00
Jack
c83fe91f4e Merge pull request #12 from hunter232/main
Closes #11
2024-08-06 21:03:21 -04:00
Hunter Richardson
6fb3745d64 fixted bug where time was only ever set to sunrise or sunset [result of integer(long) division was either 0 or 1] 2024-08-02 11:55:20 -04:00
Jack
23b64653a8 add ANOTHER missing URISyntaxException catch (they're hiding from me ig) 2024-07-23 23:38:53 -04:00
Jack
5ef5db1cd5 change line endings 2024-07-23 23:37:07 -04:00
Jack
bb14509fbd change line endings 2024-07-23 23:35:23 -04:00
Jack
92b92b5969 use new PluginMeta instead of getDescription 2024-07-23 23:26:43 -04:00
Jack
8280d9b78c use setGameRule instead of setGameRuleValue 2024-07-23 23:26:25 -04:00
Jack
cca328c5ee remove deprecated code and use modern methods/classes/code where applicable 2024-07-23 23:23:11 -04:00
Jack
d2796f7992 move project to Java 21 and the 1.21 Paper API 2024-07-23 23:04:32 -04:00
Jack
c4c5ca7558 updated current features in README 2024-07-23 18:23:00 -04:00
Jack
d51c5f531f version set to 1.4.0 2024-07-23 17:54:46 -04:00
Jack
dfbd81146f moved some debug statements around 2024-07-23 17:53:43 -04:00
Jack
e3e09f24ac renamed RealTimeWeather.getConfigurator to getConfigManager 2024-07-23 17:53:22 -04:00
Jack
1ffa9d81bb added support for enabling/disabling time and weather sync in specific worlds (closes #7) 2024-07-23 17:52:43 -04:00
Jack
549541c74a moved updateCheckInterval and Debug to top of config.yml part 3 2024-07-23 17:51:23 -04:00
Jack
27dc240597 moved updateCheckInterval and Debug to top of config.yml 2024-07-23 17:50:34 -04:00
Jack
334471b37b moved updateCheckInterval and Debug to top of config.yml 2024-07-23 17:49:46 -04:00
Jack
796097f3e2 shortened task scheduling line for update checks 2024-07-23 02:30:39 -04:00
Jack
97bd8df2de removed unnecessary if statements from WeatherRequestObject 2024-07-23 02:28:28 -04:00
Jack
6db07a376b cleaned up some code 2024-07-23 02:27:39 -04:00
Jack
20bf2d74fc add update checks 2024-07-23 02:26:56 -04:00
Jack
36ddb10fe2 add RequestFunctions class 2024-07-23 02:25:45 -04:00
Jack
a7b1f7c6e8 slight update to the README 2024-06-27 18:35:34 -04:00
Jack
e1154c59ca version set to v1.3.0 2024-06-27 18:29:54 -04:00
Jack
616b754afe change config version scheme (and update it to v1.3.0) 2024-06-27 18:27:34 -04:00
Jack
8d15534257 re-write some comments in config.yml 2024-06-27 18:27:11 -04:00
Jack
05dcde1b91 added bStats chart for SunriseSunset config value 2024-06-27 18:19:29 -04:00
Jack
1ec4d708f0 renamed EventHandler to EventHandlers 2024-06-27 18:17:11 -04:00
Jack
b616a71674 renamed Configurator to ConfigManager 2024-06-27 18:16:33 -04:00
Jack
4c4f861645 add support for real-world and custom sunrise/sunset times (closes #2) 2024-06-27 18:13:37 -04:00
Jack
c605b60903 renamed EventHandler command methods 2024-06-26 22:36:56 -04:00
Jack
4543087258 updated setAPIKey exception logging to a more "robust" method 2024-06-26 22:35:12 -04:00
Jack
cdb6d057e4 update bStats to 3.0.2 2024-06-24 21:39:16 -04:00
Jack
b816761511 update Gradle to 8.8 2024-06-24 21:32:32 -04:00
Jack
6eab85374d remove unnecessary spaces in the authors array 2024-06-23 18:23:33 -04:00
Jack
85a792228c explicitly set to load POSTWORLD 2024-06-23 18:22:33 -04:00
Jack
e623611301 add options to disable beds during night/thunder 2024-06-23 17:58:02 -04:00
Jack
b5a212d4ef change EventHandler priorities to LOWEST 2024-06-23 17:21:37 -04:00
Jack
79d1fc7b88 change message when commands are cancelled 2024-06-23 17:21:02 -04:00
Jack
b751b4ad3e fix "this.config is null" crash 2024-06-23 17:17:34 -04:00
Jack
1f303459cb grammar is hard 2023-11-02 08:57:19 -04:00
Jack Fitch
ef8ae1f6f4 add link to Wiki in config.yml 2023-04-24 20:04:59 -04:00
Jack Fitch
0f152ec892 Merge remote-tracking branch 'origin/master' 2023-04-24 20:02:40 -04:00
Jack Fitch
15c7532cad add Configurator and EventHandler classes (and some more debug output) 2023-04-24 20:02:23 -04:00
Jack
7573f46deb add commands to upcoming features 2023-04-24 12:31:46 -04:00
Jack Fitch
fb63f55ad3 clean up import statements 2023-04-22 20:53:39 -04:00
Jack Fitch
c782ee604a add option to enable /time set and /weather commands 2023-04-22 20:53:24 -04:00
Jack Fitch
f94cb36afe add RequestObject class and option to sync weather with coordinates 2023-04-22 20:44:34 -04:00
Jack
b086fa8143 update shadow plugin to 8.1.1 2023-04-19 13:01:46 -04:00
Jack
291261761c update Gradle to 8.1 2023-04-19 12:59:09 -04:00
Jack
ffa6474ba2 add Folia support to upcoming features 2023-04-17 08:42:47 -04:00
Jack Fitch
4ca9026f25 added 4SplitImage media 2023-03-08 16:47:38 -05:00
Jack Fitch
914249cc49 finally finally finish issue templates 2023-03-08 15:51:46 -05:00
Jack Fitch
dfb89d7e40 finally finish issue templates 2023-03-08 15:46:30 -05:00
Jack
9461db7d7e remove Wiki from upcoming features 2023-03-07 20:38:13 -05:00
Jack
454394e14c add multi-world support to the upcoming features 2023-03-07 20:31:05 -05:00
Jack Fitch
5d5867ed35 change README image 2023-03-07 19:02:11 -05:00
Jack Fitch
e16375557f add media images 2023-03-07 19:00:12 -05:00
Jack
fd449bf81a add title image 2023-03-07 18:06:18 -05:00
Jack
acc7acb4af add installation instructions 2023-02-28 16:30:33 -05:00
Jack
302e485640 tiny changes 2023-02-28 13:39:59 -05:00
Jack
175e9f7e67 add config.yml 2022-10-28 22:24:33 -04:00
Jack Fitch
380927d34d update issue templates 2022-10-28 22:22:17 -04:00
Jack Fitch
9724e20b85 update issue templates 2022-10-28 22:19:50 -04:00
Jack
5c46c34542 add issue templates 2022-10-28 16:37:36 -04:00
Jack Fitch
84f3050820 fix time one minute behind 2022-10-28 16:20:45 -04:00
Jack Fitch
829462243c update README 2022-10-28 16:20:28 -04:00
Jack Fitch
2858457303 suppress deprecation warnings 2022-10-28 16:07:11 -04:00
Jack Fitch
1d2513f8b7 add option to change sync intervals 2022-10-28 16:04:31 -04:00
Jack Fitch
6558d82f5c add support for Minecraft 1.7+ 2022-10-28 15:46:02 -04:00
Jack
8954e93310 bump to 1.1.2 2022-10-28 15:20:17 -04:00
Jack
123ed65d36 actually disable default weather cycle (oops) 2022-10-28 15:20:00 -04:00
24 changed files with 1083 additions and 285 deletions

71
.github/ISSUE_TEMPLATE/BUG-REPORT.yml vendored Normal file
View File

@@ -0,0 +1,71 @@
name: Bug report
description: Report problems/issues here
labels: [bug]
body:
- type: checkboxes
attributes:
label: Have you searched the wiki and looked for existing issues for this?
description: Check the wiki first in case this is a common issue. If it isn't make sure that [no one else has reported it](https://github.com/Jack1424/RealTimeWeather/issues?q=is%3Aissue+label%3Abug+).
options:
- label: This is not a common issue or cannot be fixed by the solutions provided
required: true
- label: This issue has not been reported yet
required: true
- type: textarea
attributes:
label: What's happening
description: Describe the issue that you're having. Make sure to be clear and concise.
validations:
required: true
- type: textarea
attributes:
label: What's supposed to happen
description: Describe what should be happening
validations:
required: true
- type: dropdown
attributes:
label: Server Software
description: What type of server are you running RealTimeWeather on?
options:
- Bukkit
- Paper
- Spigot
- Purpur
- Other
validations:
required: true
- type: input
attributes:
label: Minecraft version
description: What version of Minecraft is your server running?
placeholder: 'Example: 1.19.3'
validations:
required: true
- type: input
attributes:
label: Server log
description: If applicable, paste the link to your server log here
placeholder: Get a link at https://pastebin.com/
validations:
required: false
- type: input
attributes:
label: RTW configuration
description: If applicable, paste the link to your configuration file here **(REMEMBER TO REMOVE YOUR API KEY)**
placeholder: Get a link at https://pastebin.com/
validations:
required: false
- type: textarea
attributes:
label: Additional information
description: Put any more information (including screenshots and videos) that you might have here
validations:
required: false

View File

@@ -0,0 +1,18 @@
name: Feature request
description: Use this to request new features and/or changes
labels: [enhancement]
body:
- type: checkboxes
attributes:
label: Is there already a request similar to this?
description: Check the [other feature requests](https://github.com/Jack1424/RealTimeWeather/issues?q=label%3Aenhancement+) and ensure that this hasn't been requested yet
options:
- label: There are not and have never been any feature requests similar to this
required: true
- type: textarea
attributes:
label: What's your suggestion?
description: Use the space below to describe your suggestion. Feel free to attach any relevant files/links.
validations:
required: true

3
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,3 @@
#file: noinspection YAMLSchemaValidation
#IntelliJ IDEA interprets this as another issue template so the above line is required
blank_issues_enabled: false

View File

@@ -1,2 +1,2 @@
language: java language: java
jdk: openjdk17 jdk: openjdk21

View File

@@ -1,16 +1,27 @@
# RealTimeWeather [![Build Status](https://app.travis-ci.com/Jack1424/RealTimeWeather.svg?branch=master)](https://app.travis-ci.com/Jack1424/RealTimeWeather) ![4SplitSingleLineCloseColors](https://raw.githubusercontent.com/Jack1424/RealTimeWeather/master/media/4SplitColors.png)
A lightweight Minecraft Java server plugin that allows you to sync your server's time and weather with the real world [![Build Status](https://app.travis-ci.com/Jack1424/RealTimeWeather.svg?branch=master)](https://app.travis-ci.com/Jack1424/RealTimeWeather)
### A lightweight Minecraft server plugin that allows you to sync your server's time and weather with the real world
___
**Current Features:** **Current Features:**
- Lightweight - Lightweight
- Constant time syncing - Easy setup
- Weather syncing (rain and thunder) - Supports all Minecraft versions from 1.7+
- Constant time syncing (including custom or real-world sunrise/sunset times)
- Weather syncing (rain/snow and thunder)
- Enable/disable specific worlds
**Upcoming Features:** **Upcoming Features:**
- [ ] Use WeatherPlusAPI (more weather states) - [ ] Commands
- [ ] Support for more Minecraft verions - [ ] Multi-world support
- [ ] Folia support
## Contributions ## Installation
I'm open to any help/ideas that you have. Just open an issue or a pull request and I'll be sure to look at it as soon as I can. Builds with `gradlew shadowJar`. Just download the [latest version](https://github.com/Jack1424/RealTimeWeather/releases/latest) of RTW and put it in your `plugins` directory.
You'll need to run your server at least once to generate the configuration file.
After running (and then stopping) your server, simply change the values in the configuration file to what you'd like, and you're good to go.
## Contributions/Support
I'm open to any help/ideas that you have. Just open an issue or a pull request, and I'll be sure to look at it as soon as I can. Builds with `gradlew shadowJar`.
License: GPL-3.0 License: GPL-3.0

View File

@@ -1,33 +1,45 @@
plugins { plugins {
id 'java' id 'java'
id 'com.github.johnrengelman.shadow' version '7.1.2' id 'io.github.goooler.shadow' version '8.1.8' // TODO: Temporarily using fork
} }
group = 'io.github.Jack1424' group = 'io.github.jack1424'
version = '1.1.1' version = '2.0.0-DEV'
repositories { repositories {
mavenCentral() mavenCentral()
maven { maven {
name = 'papermc-repo' name = "papermc-repo"
url = 'https://repo.papermc.io/repository/maven-public/' url = "https://repo.papermc.io/repository/maven-public/"
} }
maven { maven {
name = 'sonatype' name = "sonatype"
url = 'https://oss.sonatype.org/content/groups/public/' url = "https://oss.sonatype.org/content/groups/public/"
} }
} }
dependencies { dependencies {
implementation("org.bstats:bstats-bukkit:3.0.0") compileOnly("io.papermc.paper:paper-api:1.21-R0.1-SNAPSHOT")
compileOnly 'io.papermc.paper:paper-api:1.19.2-R0.1-SNAPSHOT' implementation("org.bstats:bstats-bukkit:3.0.2")
} }
shadowJar { shadowJar {
relocate('org.bstats', 'io.github.jack1424.realtimeweather') relocate('org.bstats', 'io.github.jack1424.realTimeWeather')
} }
def targetJavaVersion = 17 tasks.jar {
manifest {
attributes["paperweight-mappings-namespace"] = "mojang"
}
}
tasks.shadowJar {
manifest {
attributes["paperweight-mappings-namespace"] = "mojang"
}
}
def targetJavaVersion = 21
java { java {
def javaVersion = JavaVersion.toVersion(targetJavaVersion) def javaVersion = JavaVersion.toVersion(targetJavaVersion)
sourceCompatibility = javaVersion sourceCompatibility = javaVersion
@@ -38,8 +50,10 @@ java {
} }
tasks.withType(JavaCompile).configureEach { tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) { if (targetJavaVersion >= 10 || JavaVersion.current().isJava10Compatible()) {
options.release = targetJavaVersion options.release.set(targetJavaVersion)
} }
} }

Binary file not shown.

View File

@@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

51
gradlew vendored Executable file → Normal file
View File

@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# #
# Copyright <EFBFBD> 2015-2021 the original authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@@ -32,10 +32,10 @@
# Busybox and similar reduced shells will NOT work, because this script # Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features: # requires all of these POSIX shell features:
# * functions; # * functions;
# * expansions <EFBFBD>$var<EFBFBD>, <EFBFBD>${var}<EFBFBD>, <EFBFBD>${var:-default}<EFBFBD>, <EFBFBD>${var+SET}<EFBFBD>, # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# <EFBFBD>${var#prefix}<EFBFBD>, <EFBFBD>${var%suffix}<EFBFBD>, and <EFBFBD>$( cmd )<EFBFBD>; # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially <EFBFBD>case<EFBFBD>; # * compound commands having a testable exit status, especially «case»;
# * various built-in commands including <EFBFBD>command<EFBFBD>, <EFBFBD>set<EFBFBD>, and <EFBFBD>ulimit<EFBFBD>. # * various built-in commands including «command», «set», and «ulimit».
# #
# Important for patching: # Important for patching:
# #
@@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -80,13 +80,11 @@ do
esac esac
done done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # This is normally unused
# shellcheck disable=SC2034
APP_NAME="Gradle"
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@@ -133,22 +131,29 @@ location of your Java installation."
fi fi
else else
JAVACMD=java JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 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 Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #( case $MAX_FD in #(
max*) 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 ) || MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit" warn "Could not query maximum file descriptor limit"
esac esac
case $MAX_FD in #( case $MAX_FD in #(
'' | soft) :;; #( '' | 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" || ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD" warn "Could not set maximum file descriptor limit to $MAX_FD"
esac esac
@@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then
done done
fi fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
# shell script including quotes and variable substitutions, so put them in DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded. # 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 -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
@@ -205,6 +214,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \ 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. # Use "xargs" to parse quoted args.
# #
# With -n1 it outputs one arg per line, with the quotes and backslashes removed. # With -n1 it outputs one arg per line, with the quotes and backslashes removed.

31
gradlew.bat vendored
View File

@@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%"=="" set DIRNAME=. if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@@ -40,13 +41,13 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@@ -56,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if %ERRORLEVEL% equ 0 goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 set EXIT_CODE=%ERRORLEVEL%
exit /b 1 if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal

BIN
media/4SplitCloseColors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 333 KiB

BIN
media/4SplitColors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 KiB

BIN
media/4SplitImage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1008 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

BIN
media/IconColors.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

View File

@@ -0,0 +1,392 @@
package io.github.jack1424.realTimeWeather;
import io.github.jack1424.realTimeWeather.requests.WeatherRequestObject;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.json.simple.parser.ParseException;
import javax.naming.ConfigurationException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.time.zone.ZoneRulesException;
import java.util.HashSet;
import java.util.Objects;
import java.util.TimeZone;
public class ConfigManager {
private final RealTimeWeather rtw;
private final FileConfiguration configFile;
private TimeZone timeZone;
private boolean debug, timeEnabled, weatherEnabled, timeSyncAllWorlds, weatherSyncAllWorlds, blockTimeSetCommand, blockWeatherCommand, disableBedsAtNight, disableBedsDuringThunder;
private long updateCheckInterval, timeSyncInterval, weatherSyncInterval;
private String sunriseSunset, sunriseSunsetLatitude, sunriseSunsetLongitude, apiKey, weatherLatitude, weatherLongitude, disableBedsAtNightMessage, disableBedsDuringThunderMessage, sunriseCustomTime, sunsetCustomTime;
private HashSet<World> timeSyncWorlds, weatherSyncWorlds;
public ConfigManager(RealTimeWeather rtw) {
this.rtw = rtw;
configFile = rtw.getConfig();
}
public void refreshValues() {
setDebugEnabled(configFile.getBoolean("Debug"));
setTimeEnabled(configFile.getBoolean("SyncTime"));
if (isTimeEnabled())
try {
timeSyncWorlds = new HashSet<>();
setTimeSyncAllWorlds(configFile.getBoolean("TimeSyncAllWorlds"));
if (getTimeSyncAllWorlds()) {
for (World world : rtw.getServer().getWorlds())
if (world.getEnvironment() == World.Environment.NORMAL)
addTimeSyncWorld(world.getName());
} else {
for (String worldName : configFile.getStringList("TimeSyncWorlds"))
addTimeSyncWorld(worldName);
}
setBlockTimeSetCommand(configFile.getBoolean("BlockTimeSetCommand"));
setDisableBedsAtNight(configFile.getBoolean("DisableBedsAtNight"));
setDisableBedsAtNightMessage(configFile.getString("DisableBedsAtNightMessage"));
setTimeSyncInterval(configFile.getLong("TimeSyncInterval"));
setTimeZone(configFile.getString("Timezone"));
setSunriseSunset(configFile.getString("SunriseSunset"));
if (getSunriseSunset().equals("real")) {
setSunriseSunsetLatitude(configFile.getString("SunriseSunsetLatitude"));
setSunriseSunsetLongitude(configFile.getString("SunriseSunsetLongitude"));
} else if (getSunriseSunset().equals("custom")) {
setSunriseCustomTime(configFile.getString("SunriseCustomTime"));
setSunsetCustomTime(configFile.getString("SunsetCustomTime"));
}
} catch (ConfigurationException e) {
rtw.getLogger().severe((e.getMessage()));
rtw.getLogger().severe("Error loading time configuration. Check that the values in your configuration file are valid.");
rtw.getLogger().severe("Disabling time sync...");
setTimeEnabled(false);
}
setWeatherEnabled(configFile.getBoolean("SyncWeather"));
if (isWeatherEnabled())
try {
weatherSyncWorlds = new HashSet<>();
setWeatherSyncAllWorlds(configFile.getBoolean("WeatherSyncAllWorlds"));
if (getWeatherSyncAllWorlds()) {
for (World world : rtw.getServer().getWorlds())
if (world.getEnvironment() == World.Environment.NORMAL)
addWeatherSyncWorld(world.getName());
} else {
for (String worldName : configFile.getStringList("WeatherSyncWorlds"))
addWeatherSyncWorld(worldName);
}
setBlockWeatherCommand(configFile.getBoolean("BlockWeatherCommand"));
setDisableBedsDuringThunder(configFile.getBoolean("DisableBedsDuringThunder"));
setDisableBedsDuringThunderMessage(configFile.getString("DisableBedsDuringThunderMessage"));
setWeatherSyncInterval(configFile.getLong("WeatherSyncInterval"));
setAPIKey(configFile.getString("APIKey"));
setWeatherLatitude(configFile.getString("WeatherLatitude"));
setWeatherLongitude(configFile.getString("WeatherLongitude"));
} catch (ConfigurationException e) {
rtw.getLogger().severe(e.getMessage());
rtw.getLogger().severe("Error loading weather configuration. Check that the values in your configuration file are valid.");
rtw.getLogger().severe("Disabling weather sync...");
setWeatherEnabled(false);
}
setUpdateCheckInterval(configFile.getLong("UpdateCheckInterval"));
}
public long getUpdateCheckInterval() {
return updateCheckInterval;
}
public void setUpdateCheckInterval(long value) {
updateCheckInterval = value;
rtw.debug("updateCheckInterval set to " + value);
}
public boolean debugEnabled() {
return debug;
}
public void setDebugEnabled(boolean value) {
debug = value;
rtw.getLogger().warning("Debug set to " + value);
}
public boolean isTimeEnabled() {
return timeEnabled;
}
public void setTimeEnabled(boolean value) {
timeEnabled = value;
rtw.debug("SyncTime set to " + value);
}
public boolean getTimeSyncAllWorlds() {
return timeSyncAllWorlds;
}
public void setTimeSyncAllWorlds(boolean value) {
timeSyncAllWorlds = value;
rtw.debug("TimeSyncAllWorlds set to " + value);
}
public HashSet<World> getTimeSyncWorlds() {
return timeSyncWorlds;
}
public void addTimeSyncWorld(String worldName) throws ConfigurationException {
World world = rtw.getServer().getWorld(worldName);
if (world == null)
throw new ConfigurationException("World \"" + worldName + "\" cannot be found");
timeSyncWorlds.add(world);
rtw.debug("World \"" + worldName + "\" added to TimeSyncWorlds");
}
public boolean getBlockTimeSetCommand() {
return blockTimeSetCommand;
}
public void setBlockTimeSetCommand(boolean value) {
blockTimeSetCommand = value;
rtw.debug("BlockTimeSetCommand set to " + value);
}
public boolean getDisableBedsAtNight() {
return disableBedsAtNight;
}
public void setDisableBedsAtNight(boolean value) {
disableBedsAtNight = value;
rtw.debug("DisableBedsAtNight set to " + value);
}
public String getDisableBedsAtNightMessage() {
return disableBedsAtNightMessage;
}
public void setDisableBedsAtNightMessage(String value) {
disableBedsAtNightMessage = value;
rtw.debug("NightDisabledBedMessage set to " + value);
}
public long getTimeSyncInterval() {
return timeSyncInterval;
}
public void setTimeSyncInterval(long value) throws ConfigurationException {
if (value < 0)
throw new ConfigurationException("Time sync interval cannot be less than 0");
timeSyncInterval = value;
rtw.debug("TimeSyncInterval set to " + value);
}
public TimeZone getTimeZone() {
return timeZone;
}
public void setTimeZone(String value) throws ConfigurationException {
try {
timeZone = TimeZone.getTimeZone(ZoneId.of(Objects.requireNonNull(value)));
} catch (ZoneRulesException | NullPointerException e) {
throw new ConfigurationException("Timezone not valid");
}
rtw.debug("TimeZone set to " + value);
}
public String getSunriseSunset() {
return sunriseSunset;
}
public void setSunriseSunset(String value) throws ConfigurationException {
value = value.toLowerCase();
if (value.equals("default") || value.equals("real") || value.equals("custom")) {
sunriseSunset = value;
rtw.debug("SunriseSunset set to " + value);
} else {
throw new ConfigurationException("SunriseSunset value invalid (must be default or real or custom)");
}
}
public String getSunriseSunsetLatitude() {
return sunriseSunsetLatitude;
}
public void setSunriseSunsetLatitude(String value) {
sunriseSunsetLatitude = value;
rtw.debug("SunriseSunsetLatitude set to " + value);
}
public String getSunriseSunsetLongitude() {
return sunriseSunsetLongitude;
}
public void setSunriseSunsetLongitude(String value) {
sunriseSunsetLongitude = value;
rtw.debug("SunriseSunsetLongitude set to " + value);
}
public String getSunriseCustomTime() {
return sunriseCustomTime;
}
public void setSunriseCustomTime(String value) throws ConfigurationException {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm:ss a");
sunriseCustomTime = LocalTime.parse(value, formatter).format(formatter);
rtw.debug("SunriseCustomTime set to " + value);
} catch (DateTimeParseException e) {
throw new ConfigurationException("SunriseCustomTime value invalid (check format)");
}
}
public String getSunsetCustomTime() {
return sunsetCustomTime;
}
public void setSunsetCustomTime(String value) throws ConfigurationException {
try {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("h:mm:ss a");
sunsetCustomTime = LocalTime.parse(value, formatter).format(formatter);
rtw.debug("SunsetCustomTime set to " + value);
} catch (DateTimeParseException e) {
throw new ConfigurationException("SunsetCustomTime value invalid (check format)");
}
}
public boolean isWeatherEnabled() {
return weatherEnabled;
}
public void setWeatherEnabled(boolean value) {
weatherEnabled = value;
rtw.debug("SyncWeather set to " + value);
}
public boolean getWeatherSyncAllWorlds() {
return weatherSyncAllWorlds;
}
public void setWeatherSyncAllWorlds(boolean value) {
weatherSyncAllWorlds = value;
rtw.debug("WeatherSyncAllWorlds set to " + value);
}
public HashSet<World> getWeatherSyncWorlds() {
return weatherSyncWorlds;
}
public void addWeatherSyncWorld(String worldName) throws ConfigurationException {
World world = rtw.getServer().getWorld(worldName);
if (world == null)
throw new ConfigurationException("World \"" + worldName + "\" cannot be found");
weatherSyncWorlds.add(world);
rtw.debug("World \"" + worldName + "\" added to WeatherSyncWorlds");
}
public boolean getBlockWeatherCommand() {
return blockWeatherCommand;
}
public void setBlockWeatherCommand(boolean value) {
blockWeatherCommand = value;
rtw.debug("BlockWeatherCommand set to " + value);
}
public boolean getDisableBedsDuringThunder() {
return disableBedsDuringThunder;
}
public void setDisableBedsDuringThunder(boolean value) {
disableBedsDuringThunder = value;
rtw.debug("DisableBedsDuringThunder set to " + value);
}
public String getDisableBedsDuringThunderMessage() {
return disableBedsDuringThunderMessage;
}
public void setDisableBedsDuringThunderMessage(String value) {
disableBedsDuringThunderMessage = value;
rtw.debug("ThunderDisabledBedMessage set to " + value);
}
public long getWeatherSyncInterval() {
return weatherSyncInterval;
}
public void setWeatherSyncInterval(long value) throws ConfigurationException {
if (value < 0)
throw new ConfigurationException("WeatherSyncInterval cannot be less than 0");
weatherSyncInterval = value;
rtw.debug("WeatherSyncInterval set to " + value);
}
public String getAPIKey() {
return apiKey;
}
public void setAPIKey(String value) throws ConfigurationException {
try {
new WeatherRequestObject(Objects.requireNonNull(value), "0", "0");
} catch (NullPointerException e) {
throw new ConfigurationException("The APIKey cannot be blank");
}
catch (IOException | ParseException | URISyntaxException e) {
rtw.getLogger().severe(e.getMessage());
throw new ConfigurationException("There was an error when validating this APIKey (this does not mean that the API key is invalid)");
}
apiKey = value;
rtw.debug("APIKey set to " + value);
}
public String getWeatherLatitude() {
return weatherLatitude;
}
public void setWeatherLatitude(String value) throws ConfigurationException {
try {
double doubleValue = Double.parseDouble(Objects.requireNonNull(value));
if (doubleValue < -90 || doubleValue > 90)
throw new ConfigurationException("The entered latitude cannot be less than -90 or greater than 90");
} catch (NullPointerException e) {
throw new ConfigurationException("The latitude cannot be blank");
} catch (NumberFormatException e) {
throw new ConfigurationException("The entered latitude might not be a number (or is too long)");
}
weatherLatitude = value;
rtw.debug("Latitude set to " + value);
}
public String getWeatherLongitude() {
return weatherLongitude;
}
public void setWeatherLongitude(String value) throws ConfigurationException {
try {
double doubleValue = Double.parseDouble(Objects.requireNonNull(value));
if (doubleValue < -180 || doubleValue > 180)
throw new ConfigurationException("The entered longitude cannot be less than -180 or greater than 180");
} catch (NullPointerException e) {
throw new ConfigurationException("The longitude cannot be blank");
} catch (NumberFormatException e) {
throw new ConfigurationException("The entered longitude might not be a number (or is too long)");
}
weatherLongitude = value;
rtw.debug("Longitude set to " + value);
}
}

View File

@@ -0,0 +1,54 @@
package io.github.jack1424.realTimeWeather;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerBedEnterEvent;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
public class EventHandlers implements Listener {
private final ConfigManager config;
public EventHandlers(RealTimeWeather rtw) {
config = rtw.getConfigManager();
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onCommandPreprocess(PlayerCommandPreprocessEvent event) {
if ((config.getBlockTimeSetCommand() && config.isTimeEnabled() && event.getMessage().toLowerCase().contains("time set "))
|| (config.getBlockWeatherCommand() && config.isWeatherEnabled() && event.getMessage().toLowerCase().contains("weather "))) {
event.setCancelled(true);
event.getPlayer().sendMessage("Command disabled by RealTimeWeather");
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onConsoleCommand(ServerCommandEvent event) {
if ((config.getBlockTimeSetCommand() && config.isTimeEnabled() && event.getCommand().toLowerCase().contains("time set "))
|| (config.getBlockWeatherCommand() && config.isWeatherEnabled() && event.getCommand().toLowerCase().contains("weather "))) {
event.setCancelled(true);
event.getSender().sendMessage("Command disabled by RealTimeWeather");
}
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onPlayerBedEnter(PlayerBedEnterEvent event) {
Player player = event.getPlayer();
World playerWorld = player.getWorld();
long worldTime = playerWorld.getTime();
if (config.isTimeEnabled() && config.getDisableBedsAtNight() && ((!playerWorld.hasStorm() && worldTime >= 12542 && worldTime <= 23459)
|| (playerWorld.hasStorm() && worldTime >= 12010 && worldTime <= 23991))) {
event.setCancelled(true);
player.sendMessage(config.getDisableBedsAtNightMessage());
}
if (config.isWeatherEnabled() && config.getDisableBedsDuringThunder() && playerWorld.isThundering()) {
event.setCancelled(true);
player.sendMessage(config.getDisableBedsDuringThunderMessage());
}
}
}

View File

@@ -0,0 +1,203 @@
package io.github.jack1424.realTimeWeather;
import io.github.jack1424.realTimeWeather.requests.*;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.plugin.java.JavaPlugin;
import javax.naming.ConfigurationException;
import java.time.LocalTime;
import java.util.Calendar;
import java.util.logging.Logger;
public final class RealTimeWeather extends JavaPlugin {
private Logger logger;
private ConfigManager config;
@Override
public void onEnable() {
logger = getLogger();
logger.info("Starting...");
logger.info("Loading configuration...");
saveDefaultConfig();
config = new ConfigManager(this);
config.refreshValues();
debug("TimeSync: " + config.isTimeEnabled());
if (config.isTimeEnabled())
setupTime();
debug("WeatherSync: " + config.isWeatherEnabled());
if (config.isWeatherEnabled())
setupWeather();
getServer().getPluginManager().registerEvents(new EventHandlers(this), this);
debug("Enabling metrics...");
Metrics metrics = new Metrics(this, 16709);
metrics.addCustomChart(new SimplePie("weather_sync_enabled", () -> String.valueOf(config.isWeatherEnabled())));
metrics.addCustomChart(new SimplePie("sunrise_sunset_source", () -> String.valueOf(config.getSunriseSunset())));
metrics.addCustomChart(new SimplePie("time_sync_enabled", () -> String.valueOf(config.isTimeEnabled())));
logger.info("Started!");
logger.info("Checking for updates...");
logger.info(getUpdateCheck());
long updateCheckInterval = config.getUpdateCheckInterval();
if (config.getUpdateCheckInterval() > 0)
getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> logger.info(getUpdateCheck()), updateCheckInterval, updateCheckInterval);
}
@Override
public void onDisable() {
for (World world : getServer().getWorlds())
if (world.getEnvironment().equals(World.Environment.NORMAL)) {
debug("Re-enabling normal daylight and weather cycles...");
if (config.isTimeEnabled())
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, true);
if (config.isWeatherEnabled())
world.setGameRule(GameRule.DO_WEATHER_CYCLE, true);
}
logger.info("Stopping...");
}
private void setupTime() {
debug("Enabling time zone sync...");
debug("Syncing time with " + config.getTimeZone().getDisplayName());
if (config.getSunriseSunset().equals("real"))
debug("Syncing sunrise/sunset with " + config.getSunriseSunsetLatitude() + " " + config.getSunriseSunsetLongitude());
if (config.getSunriseSunset().equals("custom"))
debug("Using custom sunrise/sunset times. Sunrise: " + config.getSunriseCustomTime() + ", Sunset: " + config.getSunsetCustomTime());
for (World world : config.getTimeSyncWorlds())
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
if (config.isTimeEnabled()) {
Calendar cal = Calendar.getInstance(config.getTimeZone());
for (World world : config.getTimeSyncWorlds())
if (config.getSunriseSunset().equals("real")) {
SunriseSunsetRequestObject sunriseSunset;
try {
sunriseSunset = new SunriseSunsetRequestObject(config.getTimeZone(), config.getSunriseSunsetLatitude(), config.getSunriseSunsetLongitude());
world.setTime(calculateWorldTime(cal, sunriseSunset.getSunriseTime(), sunriseSunset.getSunsetTime()));
} catch (Exception e) {
logger.severe(e.getMessage());
logger.severe("Error getting sunrise/sunset times, using default sunrise/sunset times");
try {
config.setSunriseSunset("default");
} catch (ConfigurationException ex) {
throw new RuntimeException(ex);
}
world.setTime(calculateWorldTime(cal, "5:02:27 AM", "6:36:36 PM"));
return;
}
} else if (config.getSunriseSunset().equals("custom")) {
world.setTime(calculateWorldTime(cal, config.getSunriseCustomTime(), config.getSunsetCustomTime()));
} else
world.setTime(calculateWorldTime(cal, "5:02:27 AM", "6:36:36 PM"));
}
}, 0L, config.getTimeSyncInterval());
debug("Weather sync enabled");
}
private void setupWeather() {
debug("Enabling weather sync...");
try {
new WeatherRequestObject(config.getAPIKey(), config.getWeatherLatitude(), config.getWeatherLongitude());
} catch (Exception e) {
logger.severe(e.getMessage());
logger.severe("Disabling weather sync...");
config.setWeatherEnabled(false);
return;
}
for (World world : config.getWeatherSyncWorlds())
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
debug("Syncing weather...");
try {
WeatherRequestObject request = new WeatherRequestObject(config.getAPIKey(), config.getWeatherLatitude(), config.getWeatherLongitude());
debug("Setting weather (Rain: " + request.isRaining() + ", Thunder: " + request.isThundering() + ")...");
for (World world : config.getWeatherSyncWorlds()) {
world.setStorm(request.isRaining());
world.setThundering(request.isThundering());
}
} catch (Exception e) {
logger.severe("There was an error when attempting to get weather information");
debug(e.getMessage());
}
}, 0L, config.getWeatherSyncInterval());
debug("Weather sync enabled");
}
private long calculateWorldTime(Calendar cal, String sunriseTime, String sunsetTime) {
String[] sunriseTimeSplit = sunriseTime.split(":");
String[] sunsetTimeSplit = sunsetTime.split(":");
long sunriseMinutes = Long.parseLong(sunriseTimeSplit[0]) * 60 + Long.parseLong(sunriseTimeSplit[1]) + Long.parseLong(sunriseTimeSplit[2].substring(0, 2)) / 60;
long sunsetMinutes = Long.parseLong(sunsetTimeSplit[0]) * 60 + Long.parseLong(sunsetTimeSplit[1]) + Long.parseLong(sunsetTimeSplit[2].substring(0, 2)) / 60;
if (sunriseTimeSplit[2].substring(3).equalsIgnoreCase("PM"))
sunriseMinutes += 720;
if (sunsetTimeSplit[2].substring(3).equalsIgnoreCase("PM"))
sunsetMinutes += 720;
LocalTime currentTime = LocalTime.of(cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE));
double currentMinutes = currentTime.getHour() * 60 + currentTime.getMinute();
if (currentMinutes >= sunriseMinutes && currentMinutes < sunsetMinutes) {
return (long) (((currentMinutes - sunriseMinutes) / (sunsetMinutes - sunriseMinutes)) * 13569) + 23041;
} else {
if (currentMinutes < sunriseMinutes)
currentMinutes += 1440;
return (long) (((currentMinutes - sunsetMinutes) / (1440 - sunsetMinutes + sunriseMinutes)) * 13569) + 12610;
}
}
@SuppressWarnings("UnstableApiUsage")
public String getUpdateCheck() {
String currentVersion = this.getPluginMeta().getVersion();
String latestVersion;
try {
debug("Getting latest version...");
latestVersion = RequestFunctions.getLatestVersion();
} catch (Exception exception) {
debug(exception.getMessage());
return "There was an error getting the latest version";
}
if (currentVersion.equals(latestVersion)) {
return String.format("RealTimeWeather (v%s) is up to date!", currentVersion);
} else
return String.format("RealTimeWeather (v%s) is outdated! v%s is the latest version.", currentVersion, latestVersion);
}
public ConfigManager getConfigManager() {
return config;
}
public void debug(String message) {
if (config.debugEnabled()) {
logger.info("[DEBUG] " + message);
}
}
}

View File

@@ -0,0 +1,47 @@
package io.github.jack1424.realTimeWeather.requests;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Scanner;
public class RequestFunctions {
public static Object makeRequest(String URLString) throws IOException, HTTPResponseException, ParseException, URISyntaxException {
int responseCode = getResponseCode(URLString);
if (responseCode > 399)
throw new HTTPResponseException(responseCode);
Scanner scanner = new Scanner(new URI(URLString).toURL().openStream());
StringBuilder response = new StringBuilder();
while (scanner.hasNextLine())
response.append(scanner.nextLine());
scanner.close();
return new JSONParser().parse(response.toString());
}
public static int getResponseCode(String URLString) throws IOException, URISyntaxException {
URL url = new URI(URLString).toURL();
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("GET");
con.connect();
return con.getResponseCode();
}
public static String getLatestVersion() throws Exception {
return ((JSONObject) ((JSONArray) makeRequest("https://api.modrinth.com/v2/project/WRA6ODcm/version")).getFirst()).get("version_number").toString();
}
public static class HTTPResponseException extends Exception {
public HTTPResponseException(int responseCode) {
super(String.valueOf(responseCode));
}
}
}

View File

@@ -0,0 +1,46 @@
package io.github.jack1424.realTimeWeather.requests;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import javax.naming.ConfigurationException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
public class SunriseSunsetRequestObject {
private String sunriseTime, sunsetTime;
public SunriseSunsetRequestObject(TimeZone timeZone, String lat, String lon) throws IOException, ParseException, ConfigurationException, URISyntaxException {
JSONObject response;
try {
response = (JSONObject) ((JSONObject) RequestFunctions.makeRequest(String.format("https://api.sunrisesunset.io/json?lat=%s&lng=%s&timezone=UTC", lat, lon))).get("results");
} catch (RequestFunctions.HTTPResponseException e) {
throw new IOException("Server/client error (HTTP error " + e.getMessage() + ")");
}
sunriseTime = response.get("sunrise").toString();
sunsetTime = response.get("sunset").toString();
if (sunriseTime.equalsIgnoreCase("null") || sunsetTime.equalsIgnoreCase("null"))
throw new ConfigurationException("Time(s) returned null. Check the sunrise/sunset longitude and latitude.");
DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("h:mm:ss a");
LocalDate currentDate = LocalDate.now(ZoneId.of("UTC"));
sunriseTime = ZonedDateTime.of(currentDate, LocalTime.parse(sunriseTime, timeFormatter), ZoneId.of("UTC")).withZoneSameInstant(timeZone.toZoneId()).format(timeFormatter);
sunsetTime = ZonedDateTime.of(currentDate, LocalTime.parse(sunsetTime, timeFormatter), ZoneId.of("UTC")).withZoneSameInstant(timeZone.toZoneId()).format(timeFormatter);
}
public String getSunriseTime() {
return sunriseTime;
}
public String getSunsetTime() {
return sunsetTime;
}
}

View File

@@ -0,0 +1,52 @@
package io.github.jack1424.realTimeWeather.requests;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.ParseException;
import javax.naming.ConfigurationException;
import java.io.IOException;
import java.net.ProtocolException;
import java.net.URISyntaxException;
public class WeatherRequestObject {
private boolean rain = false, thunder = false;
public WeatherRequestObject(String apiKey, String lat, String lon) throws IOException, ParseException, ConfigurationException, URISyntaxException {
JSONArray conditions;
try {
conditions = (JSONArray) ((JSONObject) RequestFunctions.makeRequest(String.format("https://api.openweathermap.org/data/2.5/weather?lat=%s&lon=%s&appid=%s", lat, lon, apiKey))).get("weather");
} catch (RequestFunctions.HTTPResponseException e) {
int responseCode = Integer.parseInt(e.getMessage());
if (responseCode > 499) {
throw new ProtocolException("Server/client error (HTTP error " + responseCode + ")");
} else if (responseCode > 399) {
String message = "Error when getting weather information: ";
if (responseCode == 401)
throw new ConfigurationException(message + "API key invalid. Check the Wiki for troubleshooting steps.");
else
throw new ProtocolException(message + "Unknown error");
} else {
throw new IOException("Server/client error (HTTP error " + e.getMessage() + ")");
}
}
for (Object rawCondition : conditions) {
int id = Integer.parseInt(String.valueOf(((JSONObject) rawCondition).get("id")));
while (id >= 10)
id /= 10;
rain = id == 2 || id == 3 || id == 5 || id == 6;
thunder = id == 2;
}
}
public boolean isRaining() {
return rain;
}
public boolean isThundering() {
return thunder;
}
}

View File

@@ -1,209 +0,0 @@
package io.github.jack1424.realtimeweather;
import org.bstats.bukkit.Metrics;
import org.bstats.charts.SimplePie;
import org.bukkit.GameRule;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandPreprocessEvent;
import org.bukkit.event.server.ServerCommandEvent;
import org.bukkit.plugin.java.JavaPlugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import javax.net.ssl.HttpsURLConnection;
import java.io.IOException;
import java.net.URL;
import java.time.ZoneId;
import java.time.zone.ZoneRulesException;
import java.util.*;
import java.util.logging.Logger;
public final class RealTimeWeather extends JavaPlugin implements Listener {
private Logger logger;
private ZoneId timezone;
private boolean timeEnabled, weatherEnabled, debug;
@Override
public void onEnable() {
logger = getLogger();
logger.info("Starting...");
saveDefaultConfig();
debug = getConfig().getBoolean("Debug");
timeEnabled = getConfig().getBoolean("SyncTime");
if (timeEnabled)
setupTime();
weatherEnabled = getConfig().getBoolean("SyncWeather");
if (weatherEnabled)
setupWeather();
getServer().getPluginManager().registerEvents(this, this);
debug("Enabling metrics...");
Metrics metrics = new Metrics(this, 16709);
metrics.addCustomChart(new SimplePie("weather_sync_enabled", () -> String.valueOf(weatherEnabled)));
metrics.addCustomChart(new SimplePie("time_sync_enabled", () -> String.valueOf(timeEnabled)));
logger.info("Started!");
}
@Override
public void onDisable() {
for (World world : getServer().getWorlds())
if (world.getEnvironment().equals(World.Environment.NORMAL)) {
debug("Re-enabling normal daylight and weather cycles...");
if (timeEnabled)
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, true);
if (weatherEnabled)
world.setGameRule(GameRule.DO_WEATHER_CYCLE, true);
}
logger.info("Stopping...");
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onOperatorSet(PlayerCommandPreprocessEvent event) {
if ((timeEnabled && event.getMessage().contains("time set")) || (weatherEnabled && event.getMessage().contains("weather"))) {
event.setCancelled(true);
event.getPlayer().sendMessage("Command cancelled (RealTimeWeather is controlling this)");
}
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onOperatorSetConsole(ServerCommandEvent event) {
if ((timeEnabled && event.getCommand().contains("time set")) || (weatherEnabled && event.getCommand().contains("weather"))) {
event.setCancelled(true);
event.getSender().sendMessage("Command cancelled (RealTimeWeather is controlling this)");
}
}
private void setupTime() {
try {
timezone = ZoneId.of(Objects.requireNonNull(getConfig().getString("Timezone")));
} catch (NullPointerException|ZoneRulesException e) {
logger.severe("Error loading timezone. Check that the values in your configuration file are valid.");
debug(e.getMessage());
logger.severe("Disabling time sync...");
timeEnabled = false;
return;
}
debug("Enabling time zone sync (every second)");
debug("Syncing time with " + timezone.toString());
for (World world : getServer().getWorlds())
if (world.getEnvironment().equals(World.Environment.NORMAL))
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
if (timeEnabled) {
Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(timezone));
for (World world : getServer().getWorlds())
if (world.getEnvironment().equals(World.Environment.NORMAL))
world.setTime((1000 * cal.get(Calendar.HOUR_OF_DAY)) + (16 * cal.get(Calendar.MINUTE)) - 6000); // TODO: Time is one minute behind
}
}, 0L, 20L); // TODO: Does this really need to update every second?
}
private void setupWeather() {
String apiKey = getConfig().getString("APIKey");
String zipCode = getConfig().getString("ZipCode");
String countryCode = getConfig().getString("CountryCode");
String lat, lon;
try {
HttpsURLConnection con = (HttpsURLConnection) new URL(String.format("https://api.openweathermap.org/geo/1.0/zip?zip=%s,%s&appid=%s", zipCode, countryCode, apiKey)).openConnection();
con.setRequestMethod("GET");
con.connect();
int response = con.getResponseCode();
if (response > 499) {
logger.severe("There was a server error when requesting weather information. Please try again later");
throw new Exception("Server error");
}
else if (response > 399) {
String message = "Error when getting weather information: ";
switch (response) {
case 401 -> logger.severe(message + "API key incorrect");
case 404 -> logger.severe(message + "Zip/Country code incorrect");
default -> logger.severe("Unknown error");
}
logger.severe("Please check that the values set in the config file are correct");
throw new Exception("Configuration error");
}
JSONObject obj = makeWeatherRequest(con.getURL());
lat = String.valueOf(obj.get("lat"));
lon = String.valueOf(obj.get("lon"));
} catch (Exception e) {
debug(e.getMessage());
logger.severe("Disabling weather sync...");
weatherEnabled = false;
return;
}
getServer().getScheduler().scheduleSyncRepeatingTask(this, () -> {
debug("Syncing weather...");
boolean rain = false, thunder = false;
try {
JSONObject obj = makeWeatherRequest(new URL(String.format("https://api.openweathermap.org/data/2.5/weather?lat=%s&lon=%s&appid=%s", lat, lon, apiKey)));
JSONArray conditions = (JSONArray) obj.get("weather");
for (Object rawCondition : conditions) {
JSONObject condition = (JSONObject) rawCondition;
int id = Integer.parseInt(String.valueOf(condition.get("id")));
debug("Weather ID: " + id);
while (id >= 10)
id /= 10;
if (!rain)
rain = id == 2 || id == 3 || id == 5 || id == 6;
if (!thunder)
thunder = id == 2;
}
} catch (Exception e) {
logger.severe("There was an error when attempting to get weather information");
debug(e.getMessage());
}
debug("Setting weather (Rain: " + rain + ", Thunder: " + thunder + ")...");
for (World world : getServer().getWorlds())
if (world.getEnvironment().equals(World.Environment.NORMAL)) {
world.setStorm(rain);
world.setThundering(thunder);
}
}, 0L, 6000L);
}
private JSONObject makeWeatherRequest(URL url) throws IOException, ParseException {
Scanner scanner = new Scanner(url.openStream());
StringBuilder data = new StringBuilder();
while (scanner.hasNext()) {
data.append(scanner.nextLine());
}
scanner.close();
JSONParser parser = new JSONParser();
return (JSONObject) parser.parse(data.toString());
}
private void debug(String message) {
if (debug) {
logger.info("[DEBUG] " + message);
}
}
}

View File

@@ -1,35 +1,110 @@
# RealTimeWeather Configuration File (v1) # RealTimeWeather Configuration File (v2.0.0)
# Configure RTM below BEFORE using it # You can find detailed instructions at: https://github.com/Jack1424/RealTimeWeather/wiki#editing-the-configuration-file
######################################## Real Time Weather Settings ##################################################
# By default, RealTimeWeather will check if an update is available every 24 hours (1734000 ticks) #
# You can change the interval here (or set to 0 to disable update checks) #
# If this is disabled, RealTimeWeather will still check for updates on startup #
# You can find a handy tick calculator here: https://mapmaking.fr/tick/ #
UpdateCheckInterval: 1734000
#
# Set to true for various console messages when time and weather sync are executed #
# This is useful if the plugin is not working, and you want to find out what's wrong #
# This will also provide error messages even when an error is caught and managed by RTM #
# Note: There will be no messages during a time sync because they happen very frequently #
# Note: Unhandled plugin errors will still be logged regardless of the debug value #
Debug: false
######################################################################################################################
################################# TIME SYNC SETTINGS ################################################################# ################################# TIME SYNC SETTINGS #################################################################
# Set to true to enable time syncing, or false to disable # # Set to true to enable time syncing, or false to disable #
# All time-related settings will be ignored if this is set to false #
SyncTime: false SyncTime: false
# # # #
# By default, RealTimeWeather will apply the time sync settings below to all worlds #
# End and nether worlds will not be synced #
# If you ony want to enable time syncing in some worlds on your server, set this to false #
TimeSyncAllWorlds: true
# #
# List the worlds that you want RealTimeWeather to sync the time in #
# End and nether worlds will not be synced #
# This only works if TimeSyncAllWorlds is set to false #
TimeSyncWorlds:
- world
# #
# Set to false to enable the /time set command (not recommended) #
BlockTimeSetCommand: true
# #
# Prevent players from sleeping in beds at night (they will still be able to set their spawn point) #
# If you disable this, strange things could happen #
DisableBedsAtNight: true
# The message sent to players when they try to sleep at night when beds are disabled #
DisableBedsAtNightMessage: ''
# #
# You can change the time between time syncs from the default (5 seconds) below #
TimeSyncInterval: 100
# #
# Enter the time zone that you want to sync your world(s) with # # Enter the time zone that you want to sync your world(s) with #
# This location CAN be different from your chosen weather location # # This location CAN be different from your chosen weather location #
# You can find a full list of timezones here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List # # You can find a full list of timezones here: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List #
Timezone: 'America/New_York' Timezone: 'Etc/UTC'
# # # #
# Set to default to use "default" Minecraft sunrise/sunset times (always 5:02 AM and 6:36 PM respectfully) #
# Set to real to sync the sunrise/sunset times with a real world location (configure below) #
# Set to custom to use custom sunrise/sunset times (configure below) #
SunriseSunset: default
# Enter the latitude and longitude of the location that you want to sync the sunrise and sunset with #
# If you set this to a place with no sunrise/sunset (like the North Pole), the default times will be used #
# NOTE: You can find the latitude and longitude of a location at https://www.latlong.net/ #
# This feature is provided for free by SunriseSunset.io #
SunriseSunsetLatitude: '0'
SunriseSunsetLongitude: '0'
# Enter the times that you would like to use for sunrise and sunset #
# You MUST include the seconds (even if they're just 00) #
# Sunrise is defined as 23041 ticks and sunset is 12610 ticks in-game #
SunriseCustomTime: '5:02:27 AM'
SunsetCustomTime: '6:36:36 PM'
###################################################################################################################### ######################################################################################################################
################################# WEATHER SYNC SETTINGS ############################################################## ################################# WEATHER SYNC SETTINGS ##############################################################
# Set to true to enable weather syncing, or false to disable # # Set to true to enable weather syncing, or false to disable #
# All weather-related settings will be ignored if this is set to false #
SyncWeather: false SyncWeather: false
# # # #
# By default, RealTimeWeather will apply the weather sync settings below to all worlds #
# End and nether worlds will not be synced #
# If you ony want to enable weather syncing in some worlds on your server, set this to false #
WeatherSyncAllWorlds: true
# #
# List the worlds that you want RealTimeWeather to sync the weather in #
# End and nether worlds will not be synced #
# This only works if WeatherSyncAllWorlds is set to false #
WeatherSyncWorlds:
- world
# #
# Set to false to enable the /weather command (not recommended) #
BlockWeatherCommand: true
# #
# Prevent players from sleeping in beds during a thunderstorm (they will still be able to set their spawn point) #
# If you disable this, it could break weather syncing #
DisableBedsDuringThunder: true
# The message sent to players when they try to sleep during a thunderstorm when beds are disabled #
DisableBedsDuringThunderMessage: ''
# #
# You can change the time between weather syncs from the default (5 minutes) below #
# Setting this value below 200 (10 seconds) is not recommended #
# The minimum safe value on a free API plan is 40 (2 seconds) #
# You can find a handy tick calculator here: https://mapmaking.fr/tick/ #
WeatherSyncInterval: 6000
# #
# In order to access the weather sync feature, create an account at https://openweathermap.org/ # # In order to access the weather sync feature, create an account at https://openweathermap.org/ #
# Then, create an API key at https://openweathermap.org/appid and copy it # # Then, create an API key at https://openweathermap.org/appid and copy it #
# Finally, paste the API key below and DO NOT SHARE IT WITH OTHERS # # Finally, paste the API key below and DO NOT SHARE IT WITH OTHERS #
APIKey: 'API_KEY' APIKey: 'API_KEY'
# Enter the zip code and country code of the location that you want to sync your world(s) weather with # # #
# NOTE: A list of country codes can be found at https://en.wikipedia.org/wiki/ISO_3166-1#Current_codes # # Enter the latitude and longitude of the location that you want to sync your world(s) weather with #
ZipCode: '10001' # NOTE: You can find the latitude and longitude of a location at https://www.latlong.net/ #
CountryCode: 'US' WeatherLatitude: '0'
WeatherLongitude: '0'
# # # #
###################################################################################################################### ######################################################################################################################
# Set to true for various console messages when time and weather sync are executed
# This is useful if the plugin is not working, and you want to find out what's wrong
# This will also provide java error messages when an error is caught and managed by RTM
# Note: There will be no messages during a time sync because they happen every second
# Note: Java exceptions and fatal plugin errors will still be logged regardless of the debug value
Debug: false

View File

@@ -1,7 +1,8 @@
main: io.github.jack1424.realTimeWeather.RealTimeWeather
name: RealTimeWeather name: RealTimeWeather
version: '${version}' version: '${version}'
description: Sync your server time and weather with the real world description: Sync your Minecraft server's time and weather with the real world
main: io.github.jack1424.realtimeweather.RealTimeWeather api-version: '1.21'
api-version: 1.19 load: POSTWORLD
authors: [ Jack1424 ] author: Jack1424
website: https://github.com/Jack1424/RealTimeWeather website: github.com/Jack1424/RealTimeWeather