Compare commits
No commits in common. "master" and "universal" have entirely different histories.
64 changed files with 643 additions and 1882 deletions
23
README.md
23
README.md
|
@ -63,11 +63,9 @@ Hardcore hearts by chance
|
||||||
### Sleep
|
### Sleep
|
||||||
Sleeping doesn't skip night, but speeds it up. The more players, the faster it goes.
|
Sleeping doesn't skip night, but speeds it up. The more players, the faster it goes.
|
||||||
- Instant sleep \
|
- Instant sleep \
|
||||||
One can instantly skip, but only a part of the night. \
|
One can instantly skip, but only a part of the night. \
|
||||||
There's 5 players on the server. A night is 10 minutes long. \
|
There's 5 players on the server. A night is 10 minutes long. \
|
||||||
Each player can instantly skip 2 minutes of the night at any time, even if others aren't sleeping
|
Each player can instantly skip 2 minutes of the night at any time, even if others aren't sleeping
|
||||||
- Heal \
|
|
||||||
Sleeping heals
|
|
||||||
|
|
||||||
### Authentication
|
### Authentication
|
||||||
Players are given a unique subdomain like "\<key>.example.com" and they must use it to join \
|
Players are given a unique subdomain like "\<key>.example.com" and they must use it to join \
|
||||||
|
@ -83,21 +81,6 @@ Issue messages that the player needs to read to keep playing, and that make an a
|
||||||
|
|
||||||
`/emergencyalerts` (`tweaks724.emergencyalerts`)
|
`/emergencyalerts` (`tweaks724.emergencyalerts`)
|
||||||
|
|
||||||
### Remote redstone
|
|
||||||
Adds a "gateway" item that are controlled over internet. \
|
|
||||||
[RETSTONE.md for more info](/Minecon724/tweaks724/src/branch/master/docs/RETSTONE.md)
|
|
||||||
|
|
||||||
### Knockback
|
|
||||||
Control knockback dealt by entities
|
|
||||||
|
|
||||||
### Kill switch
|
|
||||||
Quickly kills (terminates) the server on trigger, via command or HTTP request.
|
|
||||||
[KILLSWITCH.md for more info](/Minecon724/tweaks724/src/branch/master/docs/KILLSWITCH.md)
|
|
||||||
|
|
||||||
### Swing through grass
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Utility commands
|
### Utility commands
|
||||||
|
|
||||||
- `/ping` - displays player ping \
|
- `/ping` - displays player ping \
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
Killswitch immediately stops the server.
|
|
||||||
|
|
||||||
### Warning
|
|
||||||
This terminates the server process, meaning it's like you'd pull the power. \
|
|
||||||
So you will lose some progress (since the last auto save), or worst case your world (or other data) gets corrupted.
|
|
||||||
|
|
||||||
Terminal froze after kill? `reset`
|
|
||||||
|
|
||||||
### Over a command
|
|
||||||
No key is required. \
|
|
||||||
`/servkill` is the command. Permission: `tweaks724.servkill`. \
|
|
||||||
You must grant the permission manually, like with a permission plugin - it's not automatically assigned even to OPs.
|
|
||||||
|
|
||||||
### Over HTTP
|
|
||||||
HTTP is insecure, meaning others *could* intercept your request to the server and get your key. \
|
|
||||||
To encrypt, put this behind a proxy to get HTTPS or a VPN (directly to the server, not a commercial VPN) \
|
|
||||||
Or regenerate the key after every usage.
|
|
||||||
|
|
||||||
Make a GET request to `/key/<base64 encoded key>`
|
|
||||||
|
|
||||||
Example:
|
|
||||||
```
|
|
||||||
https://127.0.0.1:57932/key/lNwANMSZhLiTWhNxSoqQ5Q==
|
|
||||||
|_ server address _| |_ base64 encoded key _|
|
|
||||||
```
|
|
||||||
|
|
||||||
The response is a 404 no matter what. Either way, you will notice that the server has stopped.
|
|
||||||
|
|
||||||
The key is generated to `plugins/Tweaks724/storage/killswitch key` \
|
|
||||||
To use it with HTTP server, encode it to base64.
|
|
||||||
|
|
||||||
Rate limit is 1 request / 5 minutes
|
|
|
@ -1,3 +0,0 @@
|
||||||
Here's the documentation.
|
|
||||||
|
|
||||||
Click above on a file to read more about a topic.
|
|
|
@ -1,48 +0,0 @@
|
||||||
## Remote redstone
|
|
||||||
|
|
||||||
See [retstone.py](retstone.py) for usage example
|
|
||||||
|
|
||||||
### Glossary
|
|
||||||
gateways - the blocks (daylight detector) that read or emit redstone with a specified power, controlled with UDP packets \
|
|
||||||
packet - a bunch of bytes sent over the internet, that do something with a specified gateway
|
|
||||||
|
|
||||||
### Crafting
|
|
||||||
|
|
||||||
To craft a gateway, combine:
|
|
||||||
- nether star
|
|
||||||
- ender chest
|
|
||||||
- chorus flower
|
|
||||||
- daylight detector
|
|
||||||
|
|
||||||
### Usage
|
|
||||||
Each gateway has an ID assigned. To view it, shift right-click a gateway.
|
|
||||||
|
|
||||||
To destroy a gateway, use silk touch.
|
|
||||||
|
|
||||||
### How it works
|
|
||||||
A packet is int / 4 bytes / 32 bits
|
|
||||||
|
|
||||||
Packet format:
|
|
||||||
```
|
|
||||||
[ 01 ] [ 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ] [ 29 30 31 32 ]
|
|
||||||
action bits 2-28 of repeater id payload
|
|
||||||
```
|
|
||||||
|
|
||||||
- action: `1` to write, `0` to read
|
|
||||||
- payload: power level if writing
|
|
||||||
|
|
||||||
If writing, no response \
|
|
||||||
If reading, response is the power level, or 0 if not powered or no repeater with that ID (or not loaded)
|
|
||||||
|
|
||||||
Reading powers the block down of course \
|
|
||||||
BUT you should power it down (or read), wait some, and then read again
|
|
||||||
|
|
||||||
**WARNING** the socket is not ratelimited or protected in any way. \
|
|
||||||
Though it should be hard to bruteforce, because there's no feedback
|
|
||||||
|
|
||||||
### Retstone
|
|
||||||
|
|
||||||
**Network** translates to **reto** in Esperanto \
|
|
||||||
So retsomething means networked something (posto - mail, retposto - email, ejo - place (site), retejo - website, etc.) \
|
|
||||||
And sometimes we use network instead of internet, same is in that language \
|
|
||||||
Hence retstone
|
|
|
@ -1,44 +0,0 @@
|
||||||
# Copyright (C) 2024 Minecon724
|
|
||||||
# Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
# in the project root for the full license text.
|
|
||||||
|
|
||||||
import socket, struct
|
|
||||||
|
|
||||||
ENDPOINT = ("127.0.0.1", 57931)
|
|
||||||
|
|
||||||
def get_power(repeater_id: int) -> int | None:
|
|
||||||
message = repeater_id & 0x7FFFFFF0
|
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
sock.sendto(message.to_bytes(4), ENDPOINT)
|
|
||||||
|
|
||||||
return struct.unpack(">b", sock.recvfrom(1)[0])[0]
|
|
||||||
|
|
||||||
def set_power(repeater_id: int, power: int):
|
|
||||||
message = repeater_id & 0x7FFFFFF0
|
|
||||||
message |= 0x80000000
|
|
||||||
message |= power & 0xF
|
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
sock.sendto(message.to_bytes(4), ENDPOINT)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
|
|
||||||
parser = ArgumentParser()
|
|
||||||
parser.add_argument("repeater_id", help="The repeater ID", type=int)
|
|
||||||
parser.add_argument("-p", "--power", help="Power the repeater with specified power. Leave to read.", type=int)
|
|
||||||
parser.add_argument("-c", "--copy", help="Copy input of one repeater to another. If combined with power, power is added.", type=int)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
if args.copy is None:
|
|
||||||
if args.power is None:
|
|
||||||
power = get_power(args.repeater_id)
|
|
||||||
print(power)
|
|
||||||
else:
|
|
||||||
set_power(args.repeater_id, args.power)
|
|
||||||
else:
|
|
||||||
while True:
|
|
||||||
power = get_power(args.repeater_id)
|
|
||||||
set_power(args.copy, power)
|
|
6
pom.xml
6
pom.xml
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<!--
|
<!--
|
||||||
~ Copyright (C) 2025 Minecon724
|
~ Copyright (C) 2024 Minecon724
|
||||||
~ Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
~ Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
~ in the project root for the full license text.
|
~ in the project root for the full license text.
|
||||||
-->
|
-->
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
<groupId>eu.m724</groupId>
|
<groupId>eu.m724</groupId>
|
||||||
<artifactId>tweaks</artifactId>
|
<artifactId>tweaks</artifactId>
|
||||||
<version>0.1.12-SNAPSHOT</version>
|
<version>0.1.10-SNAPSHOT</version>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<maven.compiler.source>21</maven.compiler.source>
|
<maven.compiler.source>21</maven.compiler.source>
|
||||||
|
@ -167,7 +167,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.spigotmc</groupId>
|
<groupId>org.spigotmc</groupId>
|
||||||
<artifactId>spigot-api</artifactId>
|
<artifactId>spigot-api</artifactId>
|
||||||
<version>1.21.1-R0.1-SNAPSHOT</version>
|
<version>${project.spigot.version}</version>
|
||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks;
|
|
||||||
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
public class DebugLogger {
|
|
||||||
static Logger logger;
|
|
||||||
|
|
||||||
public static void info(String message, Object... format) {
|
|
||||||
log(Level.INFO, message, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void warning(String message, Object... format) {
|
|
||||||
log(Level.WARNING, message, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void severe(String message, Object... format) {
|
|
||||||
log(Level.SEVERE, message, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void fine(String message, Object... format) {
|
|
||||||
log(Level.FINE, message, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void finer(String message, Object... format) {
|
|
||||||
log(Level.FINER, message, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void log(Level level, String message, Object... format) {
|
|
||||||
if (logger.getLevel().intValue() > level.intValue()) return;
|
|
||||||
|
|
||||||
var caller = Thread.currentThread().getStackTrace()[3].getClassName();
|
|
||||||
|
|
||||||
if (caller.equals(TweaksModule.class.getName())) {
|
|
||||||
var pcaller = Thread.currentThread().getStackTrace()[4].getClassName();
|
|
||||||
if (pcaller.endsWith("Module"))
|
|
||||||
caller = pcaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (caller.startsWith("eu.m724.tweaks."))
|
|
||||||
caller = caller.substring(15);
|
|
||||||
|
|
||||||
message = "[" + caller + "] " + message.formatted(format);
|
|
||||||
|
|
||||||
if (level.intValue() < Level.INFO.intValue()) { // levels below info are never logged even if set for some reason
|
|
||||||
// colors text gray (cyan is close to gray)
|
|
||||||
if (level == Level.FINE) {
|
|
||||||
message = "\033[38;5;250m" + message + "\033[39m";
|
|
||||||
} else {
|
|
||||||
message = "\033[38;5;245m" + message + "\033[39m";
|
|
||||||
}
|
|
||||||
level = Level.INFO;
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.log(level, message);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -28,15 +28,11 @@ public class Language {
|
||||||
return INSTANCE.resourceBundle.getString(key);
|
return INSTANCE.resourceBundle.getString(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getString(String key, Object... format) {
|
|
||||||
return INSTANCE.resourceBundle.getString(key).formatted(format);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BaseComponent getComponent(String key, ChatColor color) {
|
public static BaseComponent getComponent(String key, ChatColor color) {
|
||||||
return new ComponentBuilder(getString(key)).color(color).build();
|
return new ComponentBuilder(getString(key)).color(color).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BaseComponent getComponent(String key, ChatColor color, Object... format) {
|
public static BaseComponent getComponent(String key, ChatColor color, Object... format) {
|
||||||
return new ComponentBuilder(getString(key, format)).color(color).build();
|
return new ComponentBuilder(getString(key).formatted(format)).color(color).build();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -9,12 +9,8 @@ package eu.m724.tweaks;
|
||||||
import org.bukkit.configuration.file.FileConfiguration;
|
import org.bukkit.configuration.file.FileConfiguration;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public record TweaksConfig(
|
public record TweaksConfig(
|
||||||
boolean metrics,
|
boolean metrics,
|
||||||
boolean debug,
|
|
||||||
String locale,
|
|
||||||
|
|
||||||
boolean worldborderExpand,
|
boolean worldborderExpand,
|
||||||
boolean worldborderHide,
|
boolean worldborderHide,
|
||||||
|
@ -24,6 +20,7 @@ public record TweaksConfig(
|
||||||
boolean brandShowPing,
|
boolean brandShowPing,
|
||||||
boolean brandShowMspt,
|
boolean brandShowMspt,
|
||||||
|
|
||||||
|
boolean doorEnabled,
|
||||||
boolean doorDoubleOpen,
|
boolean doorDoubleOpen,
|
||||||
boolean doorKnocking,
|
boolean doorKnocking,
|
||||||
|
|
||||||
|
@ -45,27 +42,16 @@ public record TweaksConfig(
|
||||||
boolean updaterEnabled,
|
boolean updaterEnabled,
|
||||||
|
|
||||||
boolean hardcoreEnabled,
|
boolean hardcoreEnabled,
|
||||||
double hardcoreChance,
|
float hardcoreChance,
|
||||||
|
|
||||||
boolean sleepEnabled,
|
boolean sleepEnabled,
|
||||||
boolean sleepInstant,
|
boolean sleepInstant,
|
||||||
double sleepHeal,
|
|
||||||
|
|
||||||
boolean authEnabled,
|
boolean authEnabled,
|
||||||
boolean authForce,
|
boolean authForce,
|
||||||
String authDomain,
|
String authDomain
|
||||||
|
|
||||||
boolean redstoneEnabled,
|
|
||||||
String redstoneListen,
|
|
||||||
|
|
||||||
Map<String, Object> knockbackModifiers,
|
|
||||||
|
|
||||||
boolean killswitchEnabled,
|
|
||||||
String killswitchListen,
|
|
||||||
|
|
||||||
boolean swingEnabled
|
|
||||||
) {
|
) {
|
||||||
public static final int CONFIG_VERSION = 2;
|
public static final int CONFIG_VERSION = 1;
|
||||||
private static TweaksConfig config;
|
private static TweaksConfig config;
|
||||||
|
|
||||||
public static TweaksConfig getConfig() {
|
public static TweaksConfig getConfig() {
|
||||||
|
@ -78,18 +64,15 @@ public record TweaksConfig(
|
||||||
|
|
||||||
int configVersion = config.getInt("magic number don't modify this", 0);
|
int configVersion = config.getInt("magic number don't modify this", 0);
|
||||||
RuntimeException exception = new RuntimeException("Config version is %d, expected %d".formatted(configVersion, CONFIG_VERSION));
|
RuntimeException exception = new RuntimeException("Config version is %d, expected %d".formatted(configVersion, CONFIG_VERSION));
|
||||||
|
|
||||||
if (configVersion == 0) {
|
if (configVersion == 0) {
|
||||||
throw exception;
|
throw exception;
|
||||||
} else if (configVersion < CONFIG_VERSION) {
|
|
||||||
throw new RuntimeException("Please follow update instructions https://www.spigotmc.org/resources/tweaks724.121057/updates", exception);
|
|
||||||
} else if (configVersion > CONFIG_VERSION) {
|
} else if (configVersion > CONFIG_VERSION) {
|
||||||
|
throw new RuntimeException("Please follow update instructions", exception);
|
||||||
|
} else if (configVersion < CONFIG_VERSION) {
|
||||||
throw new RuntimeException("Did you downgrade the plugin? Remove config.yml and let the plugin re-create it", exception);
|
throw new RuntimeException("Did you downgrade the plugin? Remove config.yml and let the plugin re-create it", exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean metrics = config.getBoolean("metrics");
|
boolean metrics = config.getBoolean("metrics");
|
||||||
boolean debug = config.getBoolean("debug", false);
|
|
||||||
String locale = config.getString("locale", "US");
|
|
||||||
|
|
||||||
boolean worldborderExpand = config.getBoolean("worldborder.expand");
|
boolean worldborderExpand = config.getBoolean("worldborder.expand");
|
||||||
boolean worldborderHide = config.getBoolean("worldborder.hide");
|
boolean worldborderHide = config.getBoolean("worldborder.hide");
|
||||||
|
@ -101,6 +84,7 @@ public record TweaksConfig(
|
||||||
|
|
||||||
boolean doorDoubleOpen = config.getBoolean("doors.doubleOpen");
|
boolean doorDoubleOpen = config.getBoolean("doors.doubleOpen");
|
||||||
boolean doorKnocking = config.getBoolean("doors.knocking");
|
boolean doorKnocking = config.getBoolean("doors.knocking");
|
||||||
|
boolean doorEnabled = doorDoubleOpen || doorKnocking;
|
||||||
|
|
||||||
String motdSet = config.getString("motd.set");
|
String motdSet = config.getString("motd.set");
|
||||||
boolean motdEnabled = !(motdSet.equals("false") || motdSet.isBlank());
|
boolean motdEnabled = !(motdSet.equals("false") || motdSet.isBlank());
|
||||||
|
@ -120,44 +104,28 @@ public record TweaksConfig(
|
||||||
boolean updaterEnabled = config.getBoolean("updater.enabled");
|
boolean updaterEnabled = config.getBoolean("updater.enabled");
|
||||||
|
|
||||||
boolean hardcoreEnabled = config.getBoolean("hardcore.enabled");
|
boolean hardcoreEnabled = config.getBoolean("hardcore.enabled");
|
||||||
double hardcoreChance = config.getDouble("hardcore.chance");
|
float hardcoreChance = (float) config.getDouble("hardcore.chance");
|
||||||
|
|
||||||
boolean sleepEnabled = config.getBoolean("sleep.enabled");
|
boolean sleepEnabled = config.getBoolean("sleep.enabled");
|
||||||
boolean sleepInstant = config.getBoolean("sleep.instant");
|
boolean sleepInstant = config.getBoolean("sleep.instant");
|
||||||
double sleepHeal = config.getDouble("sleep.heal");
|
|
||||||
|
|
||||||
boolean authEnabled = config.getBoolean("auth.enabled");
|
boolean authEnabled = config.getBoolean("auth.enabled");
|
||||||
boolean authForce = config.getBoolean("auth.force");
|
boolean authForce = config.getBoolean("auth.force");
|
||||||
String authHostname = config.getString("auth.domain");
|
String authHostname = config.getString("auth.domain");
|
||||||
|
|
||||||
boolean redstoneEnabled = config.getBoolean("retstone.enabled");
|
|
||||||
String redstoneListen = config.getString("retstone.listen");
|
|
||||||
|
|
||||||
// this is processed when initing
|
|
||||||
Map<String, Object> knockbackModifiers = config.getConfigurationSection("knockback").getValues(false);
|
|
||||||
|
|
||||||
boolean killswitchEnabled = config.getBoolean("killswitch.enabled");
|
|
||||||
String killswitchListen = config.getString("killswitch.listen");
|
|
||||||
|
|
||||||
boolean swingEnabled = config.getBoolean("swing.enabled");
|
|
||||||
|
|
||||||
TweaksConfig.config = new TweaksConfig(
|
TweaksConfig.config = new TweaksConfig(
|
||||||
metrics, debug, locale,
|
metrics,
|
||||||
worldborderExpand, worldborderHide,
|
worldborderExpand, worldborderHide,
|
||||||
brandEnabled, brandText, brandShowPing, brandShowMspt,
|
brandEnabled, brandText, brandShowPing, brandShowMspt,
|
||||||
doorDoubleOpen, doorKnocking,
|
doorEnabled, doorDoubleOpen, doorKnocking,
|
||||||
motdEnabled, motdSet,
|
motdEnabled, motdSet,
|
||||||
chatEnabled, chatLocalEvents, chatDefaultName, chatRadius,
|
chatEnabled, chatLocalEvents, chatDefaultName, chatRadius,
|
||||||
compassEnabled, compassWidth, compassPrecision,
|
compassEnabled, compassWidth, compassPrecision,
|
||||||
pomodoroEnabled, pomodoroForce,
|
pomodoroEnabled, pomodoroForce,
|
||||||
updaterEnabled,
|
updaterEnabled,
|
||||||
hardcoreEnabled, hardcoreChance,
|
hardcoreEnabled, hardcoreChance,
|
||||||
sleepEnabled, sleepInstant, sleepHeal,
|
sleepEnabled, sleepInstant,
|
||||||
authEnabled, authForce, authHostname,
|
authEnabled, authForce, authHostname
|
||||||
redstoneEnabled, redstoneListen,
|
|
||||||
knockbackModifiers,
|
|
||||||
killswitchEnabled, killswitchListen,
|
|
||||||
swingEnabled
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return TweaksConfig.config;
|
return TweaksConfig.config;
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.ListenerPriority;
|
|
||||||
import com.comphenix.protocol.events.PacketAdapter;
|
|
||||||
import com.comphenix.protocol.events.PacketEvent;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public abstract class TweaksModule {
|
|
||||||
protected abstract void onInit();
|
|
||||||
|
|
||||||
void init() {
|
|
||||||
var name = getClass().getSimpleName();
|
|
||||||
DebugLogger.finer("Initializing " + name);
|
|
||||||
long start = System.nanoTime();
|
|
||||||
|
|
||||||
this.onInit();
|
|
||||||
|
|
||||||
long end = System.nanoTime();
|
|
||||||
DebugLogger.fine("Initialized %s in %d µs", name, (end - start) / 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO not static maybe?
|
|
||||||
protected TweaksPlugin getPlugin() {
|
|
||||||
return TweaksPlugin.getInstance();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TweaksConfig getConfig() {
|
|
||||||
return TweaksConfig.getConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void registerEvents(Listener listener) {
|
|
||||||
DebugLogger.finer("Registered listener: " + listener.getClass().getName());
|
|
||||||
getPlugin().getServer().getPluginManager().registerEvents(listener, getPlugin());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPacketSend(PacketType packetType, Consumer<PacketEvent> consumer) {
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(getPlugin(), ListenerPriority.NORMAL, packetType) {
|
|
||||||
@Override
|
|
||||||
public void onPacketSending(PacketEvent event) {
|
|
||||||
consumer.accept(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DebugLogger.finer("Registered packet send: " + packetType.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void onPacketReceive(PacketType packetType, Consumer<PacketEvent> consumer) {
|
|
||||||
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(getPlugin(), ListenerPriority.NORMAL, packetType) {
|
|
||||||
@Override
|
|
||||||
public void onPacketReceiving(PacketEvent event) {
|
|
||||||
consumer.accept(event);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DebugLogger.finer("Registered packet receive: " + packetType.name());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void registerCommand(String command, CommandExecutor executor) {
|
|
||||||
getPlugin().getCommand(command).setExecutor(executor);
|
|
||||||
DebugLogger.finer("Registered command: " + command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T extends TweaksModule> T init(Class<T> clazz) {
|
|
||||||
T module;
|
|
||||||
try {
|
|
||||||
module = clazz.getDeclaredConstructor().newInstance();
|
|
||||||
} catch (InstantiationException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.init();
|
|
||||||
|
|
||||||
return module;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -7,36 +7,32 @@
|
||||||
package eu.m724.tweaks;
|
package eu.m724.tweaks;
|
||||||
|
|
||||||
import eu.m724.mstats.MStatsPlugin;
|
import eu.m724.mstats.MStatsPlugin;
|
||||||
import eu.m724.tweaks.alert.AlertModule;
|
import eu.m724.tweaks.alert.AlertManager;
|
||||||
import eu.m724.tweaks.auth.AuthModule;
|
import eu.m724.tweaks.auth.AuthManager;
|
||||||
import eu.m724.tweaks.chat.ChatModule;
|
import eu.m724.tweaks.chat.ChatCommands;
|
||||||
import eu.m724.tweaks.door.DoorKnockModule;
|
import eu.m724.tweaks.chat.ChatManager;
|
||||||
import eu.m724.tweaks.door.DoorOpenModule;
|
import eu.m724.tweaks.door.DoorManager;
|
||||||
import eu.m724.tweaks.full.FullModule;
|
import eu.m724.tweaks.full.FullListener;
|
||||||
import eu.m724.tweaks.hardcore.HardcoreModule;
|
import eu.m724.tweaks.hardcore.HardcoreManager;
|
||||||
import eu.m724.tweaks.killswitch.KillswitchModule;
|
import eu.m724.tweaks.motd.MotdManager;
|
||||||
import eu.m724.tweaks.knockback.KnockbackModule;
|
|
||||||
import eu.m724.tweaks.motd.MotdModule;
|
|
||||||
import eu.m724.tweaks.ping.F3NameListener;
|
import eu.m724.tweaks.ping.F3NameListener;
|
||||||
import eu.m724.tweaks.ping.PingChecker;
|
import eu.m724.tweaks.ping.PingChecker;
|
||||||
import eu.m724.tweaks.pomodoro.PomodoroModule;
|
import eu.m724.tweaks.ping.PingCommands;
|
||||||
import eu.m724.tweaks.redstone.RedstoneModule;
|
import eu.m724.tweaks.pomodoro.PomodoroCommands;
|
||||||
import eu.m724.tweaks.sleep.SleepModule;
|
import eu.m724.tweaks.pomodoro.PomodoroManager;
|
||||||
import eu.m724.tweaks.swing.SwingModule;
|
import eu.m724.tweaks.sleep.SleepManager;
|
||||||
import eu.m724.tweaks.updater.UpdaterModule;
|
import eu.m724.tweaks.updater.UpdaterCommands;
|
||||||
import eu.m724.tweaks.worldborder.WorldBorderExpandModule;
|
import eu.m724.tweaks.updater.UpdaterManager;
|
||||||
import eu.m724.tweaks.worldborder.WorldBorderHideModule;
|
import eu.m724.tweaks.worldborder.WorldBorderManager;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.logging.Level;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class TweaksPlugin extends MStatsPlugin {
|
public class TweaksPlugin extends MStatsPlugin {
|
||||||
private static TweaksPlugin INSTANCE;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
long start = System.nanoTime();
|
long start = System.nanoTime();
|
||||||
INSTANCE = this;
|
|
||||||
|
|
||||||
if (getServer().getPluginManager().getPlugin("ProtocolLib") == null) {
|
if (getServer().getPluginManager().getPlugin("ProtocolLib") == null) {
|
||||||
getLogger().severe("ProtocolLib is required for this plugin.");
|
getLogger().severe("ProtocolLib is required for this plugin.");
|
||||||
|
@ -46,106 +42,83 @@ public class TweaksPlugin extends MStatsPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
TweaksConfig config = TweaksConfig.load(this);
|
TweaksConfig config = TweaksConfig.load(this);
|
||||||
|
new Language(Locale.US); // TODO
|
||||||
|
|
||||||
getLogger().setLevel(config.debug() ? Level.FINEST : Level.INFO);
|
// whether enabled is handled inside
|
||||||
DebugLogger.logger = getLogger();
|
new WorldBorderManager().init(this);
|
||||||
|
|
||||||
if (config.debug()) {
|
|
||||||
DebugLogger.warning("Debug harms performance");
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugLogger.fine("Language");
|
|
||||||
new Language(Locale.of(config.locale())); // TODO
|
|
||||||
DebugLogger.fine(Language.getString("languageNotice", Language.getString("language"), Language.getString("languageEnglish")));
|
|
||||||
|
|
||||||
/* start modules */
|
|
||||||
|
|
||||||
if (config.worldborderHide()) {
|
|
||||||
TweaksModule.init(WorldBorderHideModule.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.worldborderExpand()) {
|
|
||||||
TweaksModule.init(WorldBorderExpandModule.class);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.chatEnabled()) {
|
if (config.chatEnabled()) {
|
||||||
TweaksModule.init(ChatModule.class);
|
ChatManager chatManager = new ChatManager(this);
|
||||||
|
chatManager.init();
|
||||||
|
|
||||||
|
ChatCommands chatCommands = new ChatCommands(chatManager);
|
||||||
|
Objects.requireNonNull(getCommand("chat")).setExecutor(chatCommands);
|
||||||
|
Objects.requireNonNull(getCommand("chatmanage")).setExecutor(chatCommands);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.doorKnocking()) {
|
if (config.doorEnabled()) {
|
||||||
TweaksModule.init(DoorKnockModule.class);
|
new DoorManager().init(this);
|
||||||
}
|
|
||||||
|
|
||||||
if (config.doorDoubleOpen()) {
|
|
||||||
TweaksModule.init(DoorOpenModule.class);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.brandEnabled()) {
|
if (config.brandEnabled()) {
|
||||||
DebugLogger.fine("Enabling Brand");
|
|
||||||
new F3NameListener(this).init();
|
new F3NameListener(this).init();
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugLogger.fine("Enabling Ping");
|
new PingChecker(this).init();
|
||||||
new PingChecker(this).init(getCommand("ping"));
|
Objects.requireNonNull(getCommand("ping")).setExecutor(new PingCommands());
|
||||||
|
|
||||||
|
/*if (getServer().getPluginManager().getPlugin("voicechat") != null) {
|
||||||
|
new MusicPlayer(this).init();
|
||||||
|
} else {
|
||||||
|
getLogger().warning("To use voice extensions, install \"Simple Voice Chat\"");
|
||||||
|
}*/
|
||||||
|
|
||||||
if (config.motdEnabled()) {
|
if (config.motdEnabled()) {
|
||||||
TweaksModule.init(MotdModule.class);
|
try {
|
||||||
|
new MotdManager(this).init();
|
||||||
|
} catch (IOException e) {
|
||||||
|
getLogger().severe("Failed to initialize MOTD extension");
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.pomodoroEnabled()) {
|
if (config.pomodoroEnabled()) {
|
||||||
TweaksModule.init(PomodoroModule.class);
|
new PomodoroManager(this).init();
|
||||||
|
getCommand("pomodoro").setExecutor(new PomodoroCommands());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.updaterEnabled()) {
|
if (config.updaterEnabled()) {
|
||||||
TweaksModule.init(UpdaterModule.class);
|
try {
|
||||||
|
new UpdaterManager(this).init();
|
||||||
|
getCommand("updates").setExecutor(new UpdaterCommands());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.hardcoreEnabled()) {
|
if (config.hardcoreEnabled()) {
|
||||||
TweaksModule.init(HardcoreModule.class);
|
new HardcoreManager().init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.sleepEnabled()) {
|
if (config.sleepEnabled()) {
|
||||||
TweaksModule.init(SleepModule.class);
|
new SleepManager().init(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.authEnabled()) {
|
if (config.authEnabled()) {
|
||||||
TweaksModule.init(AuthModule.class);
|
new AuthManager(this).init(getCommand("tauth"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TweaksModule.init(AlertModule.class);
|
new AlertManager(this).init(getCommand("emergencyalert"));
|
||||||
|
|
||||||
TweaksModule.init(FullModule.class);
|
this.getServer().getPluginManager().registerEvents(new FullListener(), this);
|
||||||
|
|
||||||
if (config.redstoneEnabled()) {
|
if (config.metrics())
|
||||||
TweaksModule.init(RedstoneModule.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
TweaksModule.init(KnockbackModule.class);
|
|
||||||
|
|
||||||
if (config.killswitchEnabled()) {
|
|
||||||
TweaksModule.init(KillswitchModule.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.swingEnabled()) {
|
|
||||||
TweaksModule.init(SwingModule.class);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* end modules */
|
|
||||||
|
|
||||||
if (config.metrics()) {
|
|
||||||
DebugLogger.fine("Enabling Metrics");
|
|
||||||
mStats(1);
|
mStats(1);
|
||||||
}
|
|
||||||
|
|
||||||
DebugLogger.fine("Took %.3f milliseconds".formatted((System.nanoTime() - start) / 1000000.0));
|
getLogger().info("Took %.3f milliseconds".formatted((System.nanoTime() - start) / 1000000.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasResource(String resource) {
|
public boolean hasResource(String resource) {
|
||||||
return this.getClassLoader().getResource(resource) != null;
|
return this.getClassLoader().getResource(resource) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TweaksPlugin getInstance() {
|
|
||||||
return INSTANCE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -20,9 +20,9 @@ public class AlertCommand implements CommandExecutor {
|
||||||
private List<String> pending;
|
private List<String> pending;
|
||||||
private long when;
|
private long when;
|
||||||
|
|
||||||
private final AlertModule manager;
|
private final AlertManager manager;
|
||||||
|
|
||||||
public AlertCommand(AlertModule manager) {
|
public AlertCommand(AlertManager manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class AlertCommand implements CommandExecutor {
|
||||||
} else if (args[0].equalsIgnoreCase("confirm")) {
|
} else if (args[0].equalsIgnoreCase("confirm")) {
|
||||||
sender.sendMessage("CONFIRM must be in all caps");
|
sender.sendMessage("CONFIRM must be in all caps");
|
||||||
} else if (args[0].equalsIgnoreCase("cancel")) {
|
} else if (args[0].equalsIgnoreCase("cancel")) {
|
||||||
if (AlertModule.current != null) {
|
if (AlertManager.current != null) {
|
||||||
manager.stop();
|
manager.stop();
|
||||||
sender.sendMessage("Cancelled alert");
|
sender.sendMessage("Cancelled alert");
|
||||||
} else if (pending != null) {
|
} else if (pending != null) {
|
||||||
|
@ -86,7 +86,7 @@ public class AlertCommand implements CommandExecutor {
|
||||||
|
|
||||||
if (pending != null) {
|
if (pending != null) {
|
||||||
when = System.currentTimeMillis();
|
when = System.currentTimeMillis();
|
||||||
if (AlertModule.current != null) {
|
if (AlertManager.current != null) {
|
||||||
sender.sendMessage("Broadcasting a new alert will cancel the currently active one");
|
sender.sendMessage("Broadcasting a new alert will cancel the currently active one");
|
||||||
}
|
}
|
||||||
sender.sendMessage("Please confirm broadcast with /emergencyalert CONFIRM within 15 seconds");
|
sender.sendMessage("Please confirm broadcast with /emergencyalert CONFIRM within 15 seconds");
|
||||||
|
|
90
src/main/java/eu/m724/tweaks/alert/AlertManager.java
Normal file
90
src/main/java/eu/m724/tweaks/alert/AlertManager.java
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.alert;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.ListenerPriority;
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import eu.m724.tweaks.TweaksPlugin;
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scheduler.BukkitTask;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class AlertManager {
|
||||||
|
private final TweaksPlugin plugin;
|
||||||
|
|
||||||
|
private BukkitTask notifyTask;
|
||||||
|
static Alert current;
|
||||||
|
static Map<Player, Integer> pages = new HashMap<>();
|
||||||
|
|
||||||
|
public AlertManager(TweaksPlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(PluginCommand command) {
|
||||||
|
command.setExecutor(new AlertCommand(this));
|
||||||
|
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Play.Client.ENCHANT_ITEM
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketReceiving(PacketEvent event) {
|
||||||
|
if (current == null) return;
|
||||||
|
if (!current.isOpen(event.getPlayer())) return;
|
||||||
|
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
|
||||||
|
int windowId, buttonId;
|
||||||
|
windowId = packet.getIntegers().read(0);
|
||||||
|
buttonId = packet.getIntegers().read(1);
|
||||||
|
|
||||||
|
var page = pages.getOrDefault(event.getPlayer(),1);
|
||||||
|
|
||||||
|
if (buttonId == 1) { // prev page
|
||||||
|
page--;
|
||||||
|
} else if (buttonId == 2) { // nextc page
|
||||||
|
page++;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pages.put(event.getPlayer(), page);
|
||||||
|
var npacket = new PacketContainer(PacketType.Play.Server.WINDOW_DATA);
|
||||||
|
npacket.getIntegers().write(0, windowId);
|
||||||
|
npacket.getIntegers().write(1, 0);
|
||||||
|
npacket.getIntegers().write(2, page);
|
||||||
|
ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), npacket);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public Alert start(String... content) {
|
||||||
|
stop();
|
||||||
|
current = new Alert(content);
|
||||||
|
notifyTask = new AlertRunnable(current, v -> this.stop()).runTaskTimer(plugin, 0, 10);
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (current == null) return;
|
||||||
|
for (Player player : plugin.getServer().getOnlinePlayers()) {
|
||||||
|
if (current.isOpen(player))
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
pages.clear();
|
||||||
|
notifyTask.cancel();
|
||||||
|
current = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,74 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.alert;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.ProtocolLibrary;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class AlertModule extends TweaksModule {
|
|
||||||
private BukkitTask notifyTask;
|
|
||||||
static Alert current;
|
|
||||||
static Map<Player, Integer> pages = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerCommand("emergencyalert", new AlertCommand(this));
|
|
||||||
|
|
||||||
onPacketReceive(PacketType.Play.Client.ENCHANT_ITEM, (event) -> {
|
|
||||||
if (current == null) return;
|
|
||||||
if (!current.isOpen(event.getPlayer())) return;
|
|
||||||
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
int windowId, buttonId;
|
|
||||||
windowId = packet.getIntegers().read(0);
|
|
||||||
buttonId = packet.getIntegers().read(1);
|
|
||||||
|
|
||||||
var page = pages.getOrDefault(event.getPlayer(),1);
|
|
||||||
|
|
||||||
if (buttonId == 1) { // prev page
|
|
||||||
page--;
|
|
||||||
} else if (buttonId == 2) { // nextc page
|
|
||||||
page++;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pages.put(event.getPlayer(), page);
|
|
||||||
var npacket = new PacketContainer(PacketType.Play.Server.WINDOW_DATA);
|
|
||||||
npacket.getIntegers().write(0, windowId);
|
|
||||||
npacket.getIntegers().write(1, 0);
|
|
||||||
npacket.getIntegers().write(2, page);
|
|
||||||
ProtocolLibrary.getProtocolManager().sendServerPacket(event.getPlayer(), npacket);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public Alert start(String... content) {
|
|
||||||
stop();
|
|
||||||
current = new Alert(content);
|
|
||||||
notifyTask = new AlertRunnable(current, v -> this.stop()).runTaskTimer(getPlugin(), 0, 10);
|
|
||||||
return current;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void stop() {
|
|
||||||
if (current == null) return;
|
|
||||||
for (Player player : getPlugin().getServer().getOnlinePlayers()) {
|
|
||||||
if (current.isOpen(player))
|
|
||||||
player.closeInventory();
|
|
||||||
}
|
|
||||||
pages.clear();
|
|
||||||
notifyTask.cancel();
|
|
||||||
current = null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
package eu.m724.tweaks.auth;
|
||||||
|
|
||||||
import eu.m724.tweaks.Language;
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.BaseComponent;
|
import net.md_5.bungee.api.chat.BaseComponent;
|
||||||
|
@ -51,7 +50,7 @@ public class AuthCommands implements CommandExecutor {
|
||||||
.underlined(true)
|
.underlined(true)
|
||||||
.color(ChatColor.GRAY)
|
.color(ChatColor.GRAY)
|
||||||
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, hostname))
|
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, hostname))
|
||||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToCopy"))))
|
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text("Click to copy")))
|
||||||
.build();
|
.build();
|
||||||
sender.spigot().sendMessage(component);
|
sender.spigot().sendMessage(component);
|
||||||
} else {
|
} else {
|
||||||
|
|
25
src/main/java/eu/m724/tweaks/auth/AuthManager.java
Normal file
25
src/main/java/eu/m724/tweaks/auth/AuthManager.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.auth;
|
||||||
|
|
||||||
|
import org.bukkit.command.PluginCommand;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class AuthManager {
|
||||||
|
private final AuthStorage authStorage;
|
||||||
|
private final Plugin plugin;
|
||||||
|
|
||||||
|
public AuthManager(Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.authStorage = new AuthStorage(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init(PluginCommand command) {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new AuthListener(authStorage), plugin);
|
||||||
|
command.setExecutor(new AuthCommands(authStorage));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.auth;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
|
|
||||||
public class AuthModule extends TweaksModule {
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
var authStorage = new AuthStorage(getPlugin());
|
|
||||||
|
|
||||||
registerEvents(new AuthListener(authStorage));
|
|
||||||
registerCommand("tauth", new AuthCommands(authStorage));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -19,11 +19,12 @@ public class AuthStorage {
|
||||||
private final File keysDirectory;
|
private final File keysDirectory;
|
||||||
|
|
||||||
AuthStorage(Plugin plugin) {
|
AuthStorage(Plugin plugin) {
|
||||||
File directory = new File(plugin.getDataFolder(), "storage/auth");
|
File directory = new File(plugin.getDataFolder(), "auth storage");
|
||||||
this.playersDirectory = new File(directory, "players");
|
this.playersDirectory = new File(directory, "players");
|
||||||
this.keysDirectory = new File(directory, "keys");
|
this.keysDirectory = new File(directory, "keys");
|
||||||
|
|
||||||
keysDirectory.mkdirs();
|
directory.mkdir();
|
||||||
|
keysDirectory.mkdir();
|
||||||
playersDirectory.mkdir();
|
playersDirectory.mkdir();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -21,9 +21,9 @@ import java.util.Arrays;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class ChatCommands implements CommandExecutor {
|
public class ChatCommands implements CommandExecutor {
|
||||||
private final ChatModule manager;
|
private final ChatManager manager;
|
||||||
|
|
||||||
public ChatCommands(ChatModule manager) {
|
public ChatCommands(ChatManager manager) {
|
||||||
this.manager = manager;
|
this.manager = manager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,9 +94,9 @@ public class ChatCommands implements CommandExecutor {
|
||||||
ChatRoom newRoom = manager.createChatRoom(argument, null, player);
|
ChatRoom newRoom = manager.createChatRoom(argument, null, player);
|
||||||
sender.sendMessage("Created a chat room. Join it: /c " + newRoom.id);
|
sender.sendMessage("Created a chat room. Join it: /c " + newRoom.id);
|
||||||
sender.sendMessage("You might also want to protect it with a password: /cm setpassword");
|
sender.sendMessage("You might also want to protect it with a password: /cm setpassword");
|
||||||
} catch (ChatModule.InvalidIdException e) {
|
} catch (ChatManager.InvalidIdException e) {
|
||||||
sender.sendMessage("ID is invalid: " + e.getMessage());
|
sender.sendMessage("ID is invalid: " + e.getMessage());
|
||||||
} catch (ChatModule.ChatRoomExistsException e) {
|
} catch (ChatManager.ChatRoomExistsException e) {
|
||||||
sender.sendMessage("Room %s already exists".formatted(argument));
|
sender.sendMessage("Room %s already exists".formatted(argument));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
sender.sendMessage("Failed to create room");
|
sender.sendMessage("Failed to create room");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -25,14 +25,13 @@ import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
|
||||||
public class ChatListener implements Listener {
|
public class ChatListener implements Listener {
|
||||||
private final ChatModule chatModule;
|
private final ChatManager chatManager;
|
||||||
private final String defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
private final String defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
||||||
private final boolean localEvents = TweaksConfig.getConfig().chatLocalEvents();
|
private final boolean localEvents = TweaksConfig.getConfig().chatLocalEvents();
|
||||||
private final int radius;
|
private final int radius;
|
||||||
|
|
||||||
public ChatListener(ChatModule chatModule) {
|
public ChatListener(ChatManager chatManager) {
|
||||||
this.chatModule = chatModule;
|
this.chatManager = chatManager;
|
||||||
|
|
||||||
if (TweaksConfig.getConfig().chatRadius() < 0) {
|
if (TweaksConfig.getConfig().chatRadius() < 0) {
|
||||||
radius = 0;
|
radius = 0;
|
||||||
} else {
|
} else {
|
||||||
|
@ -53,7 +52,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
||||||
|
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
var cb = new ComponentBuilder()
|
var cb = new ComponentBuilder()
|
||||||
|
@ -78,7 +77,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatModule.removePlayer(player);
|
ChatRoom chatRoom = chatManager.removePlayer(player);
|
||||||
|
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
var cb = new ComponentBuilder()
|
var cb = new ComponentBuilder()
|
||||||
|
@ -104,7 +103,7 @@ public class ChatListener implements Listener {
|
||||||
public void onPlayerDeath(PlayerDeathEvent event) {
|
public void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
if (localEvents) {
|
if (localEvents) {
|
||||||
Player player = event.getEntity();
|
Player player = event.getEntity();
|
||||||
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
||||||
|
|
||||||
// would be easier on Paper but this is not Paper
|
// would be easier on Paper but this is not Paper
|
||||||
BaseComponent deathMessage = ComponentSerializer.deserialize(Component.Serializer.toJson(((CraftPlayer)player).getHandle().getCombatTracker().getDeathMessage(), CraftRegistry.getMinecraftRegistry()));
|
BaseComponent deathMessage = ComponentSerializer.deserialize(Component.Serializer.toJson(((CraftPlayer)player).getHandle().getCombatTracker().getDeathMessage(), CraftRegistry.getMinecraftRegistry()));
|
||||||
|
@ -125,7 +124,7 @@ public class ChatListener implements Listener {
|
||||||
|
|
||||||
// broadcast to killer if available
|
// broadcast to killer if available
|
||||||
if (player.getLastDamageCause().getDamageSource().getCausingEntity() instanceof Player killer) {
|
if (player.getLastDamageCause().getDamageSource().getCausingEntity() instanceof Player killer) {
|
||||||
ChatRoom chatRoom2 = chatModule.getPlayerChatRoom(killer);
|
ChatRoom chatRoom2 = chatManager.getPlayerChatRoom(killer);
|
||||||
if (chatRoom != chatRoom2) {
|
if (chatRoom != chatRoom2) {
|
||||||
if (proximityFor(chatRoom)) {
|
if (proximityFor(chatRoom)) {
|
||||||
chatRoom2.broadcastNear(killer.getLocation(), radius, component);
|
chatRoom2.broadcastNear(killer.getLocation(), radius, component);
|
||||||
|
@ -143,7 +142,7 @@ public class ChatListener implements Listener {
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
|
public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
ChatRoom chatRoom = chatModule.getPlayerChatRoom(player);
|
ChatRoom chatRoom = chatManager.getPlayerChatRoom(player);
|
||||||
String message = event.getMessage();
|
String message = event.getMessage();
|
||||||
|
|
||||||
var component = new ComponentBuilder()
|
var component = new ComponentBuilder()
|
||||||
|
|
|
@ -1,43 +1,45 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.chat;
|
package eu.m724.tweaks.chat;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
import org.bukkit.OfflinePlayer;
|
import org.bukkit.OfflinePlayer;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class ChatModule extends TweaksModule {
|
public class ChatManager {
|
||||||
private final NamespacedKey chatRoomKey = new NamespacedKey(getPlugin(), "chatRoom");
|
private final Plugin plugin;
|
||||||
private final String defaultRoom = getConfig().chatDefaultName();
|
private final NamespacedKey chatRoomKey;
|
||||||
|
private final String defaultRoom;
|
||||||
|
|
||||||
private final Map<Player, ChatRoom> playerMap = new HashMap<>();
|
private final Map<Player, ChatRoom> playerMap = new HashMap<>();
|
||||||
private final Map<String, ChatRoom> roomIdMap = new HashMap<>();
|
private final Map<String, ChatRoom> roomIdMap = new HashMap<>();
|
||||||
|
|
||||||
|
public ChatManager(Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.chatRoomKey = new NamespacedKey(plugin, "chatRoom");
|
||||||
|
this.defaultRoom = TweaksConfig.getConfig().chatDefaultName();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
public void init() {
|
||||||
protected void onInit() {
|
if (plugin.getServer().isEnforcingSecureProfiles()) {
|
||||||
if (getPlugin().getServer().isEnforcingSecureProfiles()) {
|
|
||||||
throw new RuntimeException("Please disable enforce-secure-profile in server.properties to use chatrooms");
|
throw new RuntimeException("Please disable enforce-secure-profile in server.properties to use chatrooms");
|
||||||
}
|
}
|
||||||
|
|
||||||
getById(defaultRoom);
|
getById(defaultRoom);
|
||||||
registerEvents(new ChatListener(this));
|
plugin.getServer().getPluginManager().registerEvents(new ChatListener(this), plugin);
|
||||||
|
|
||||||
var chatCommands = new ChatCommands(this);
|
|
||||||
registerCommand("chat", chatCommands);
|
|
||||||
registerCommand("chatmanage", chatCommands);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,7 +69,7 @@ public class ChatModule extends TweaksModule {
|
||||||
if (id.equals(defaultRoom)) {
|
if (id.equals(defaultRoom)) {
|
||||||
chatRoom = new ChatRoom(defaultRoom, null, null);
|
chatRoom = new ChatRoom(defaultRoom, null, null);
|
||||||
} else {
|
} else {
|
||||||
chatRoom = ChatRoomLoader.load(id);
|
chatRoom = ChatRoomLoader.load(plugin, id);
|
||||||
}
|
}
|
||||||
roomIdMap.put(id, chatRoom);
|
roomIdMap.put(id, chatRoom);
|
||||||
}
|
}
|
||||||
|
@ -164,17 +166,17 @@ public class ChatModule extends TweaksModule {
|
||||||
throw new ChatRoomExistsException();
|
throw new ChatRoomExistsException();
|
||||||
|
|
||||||
ChatRoom chatRoom = new ChatRoom(id, password, owner);
|
ChatRoom chatRoom = new ChatRoom(id, password, owner);
|
||||||
ChatRoomLoader.save(chatRoom);
|
ChatRoomLoader.save(plugin, chatRoom);
|
||||||
return chatRoom;
|
return chatRoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
void saveChatRoom(ChatRoom chatRoom) throws IOException {
|
void saveChatRoom(ChatRoom chatRoom) throws IOException {
|
||||||
ChatRoomLoader.save(chatRoom);
|
ChatRoomLoader.save(plugin, chatRoom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void deleteChatRoom(ChatRoom chatRoom) {
|
public void deleteChatRoom(ChatRoom chatRoom) {
|
||||||
roomIdMap.remove(chatRoom.id);
|
roomIdMap.remove(chatRoom.id);
|
||||||
ChatRoomLoader.getFile(chatRoom.id).delete();
|
ChatRoomLoader.getFile(plugin, chatRoom.id).delete();
|
||||||
chatRoom.players.forEach(player -> setPlayerChatRoom(getById(defaultRoom), player));
|
chatRoom.players.forEach(player -> setPlayerChatRoom(getById(defaultRoom), player));
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,25 +13,23 @@ import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
public class ChatRoomLoader {
|
public class ChatRoomLoader {
|
||||||
private static File chatRoomsDir;
|
|
||||||
|
|
||||||
static void init(Plugin plugin) {
|
|
||||||
chatRoomsDir = new File(plugin.getDataFolder(), "storage/rooms");
|
|
||||||
chatRoomsDir.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file of persistent storage of a chat room
|
* Get the file of persistent storage of a chat room
|
||||||
* @return the file or null if ID is invalid
|
* @return the file or null if ID is invalid
|
||||||
*/
|
*/
|
||||||
static File getFile(String id) {
|
static File getFile(Plugin plugin, String id) {
|
||||||
|
Path chatRoomsPath = Paths.get(plugin.getDataFolder().getPath(), "rooms");
|
||||||
|
chatRoomsPath.toFile().mkdirs();
|
||||||
|
|
||||||
if (validateId(id) != 0)
|
if (validateId(id) != 0)
|
||||||
throw new RuntimeException("Invalid id: " + id);
|
throw new RuntimeException("Invalid id: " + id);
|
||||||
|
|
||||||
return new File(chatRoomsDir, id + ".yml");
|
return Paths.get(chatRoomsPath.toFile().getPath(), id + ".yml").toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,8 +62,8 @@ public class ChatRoomLoader {
|
||||||
* @param id the id of the chat room
|
* @param id the id of the chat room
|
||||||
* @return the chat room or null if no such chat room
|
* @return the chat room or null if no such chat room
|
||||||
*/
|
*/
|
||||||
static ChatRoom load(String id) {
|
static ChatRoom load(Plugin plugin, String id) {
|
||||||
File chatRoomFile = getFile(id);
|
File chatRoomFile = getFile(plugin, id);
|
||||||
if (!chatRoomFile.exists()) return null;
|
if (!chatRoomFile.exists()) return null;
|
||||||
|
|
||||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(chatRoomFile);
|
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(chatRoomFile);
|
||||||
|
@ -91,15 +89,14 @@ public class ChatRoomLoader {
|
||||||
*
|
*
|
||||||
* @throws IOException if saving failed
|
* @throws IOException if saving failed
|
||||||
*/
|
*/
|
||||||
static void save(ChatRoom chatRoom) throws IOException {
|
static void save(Plugin plugin, ChatRoom chatRoom) throws IOException {
|
||||||
YamlConfiguration configuration = new YamlConfiguration();
|
YamlConfiguration configuration = new YamlConfiguration();
|
||||||
configuration.set("password", chatRoom.password);
|
configuration.set("password", chatRoom.password);
|
||||||
configuration.set("color", chatRoom.color.getName());
|
configuration.set("color", chatRoom.color.getName());
|
||||||
// TODO consider just making this str to make it easier
|
|
||||||
configuration.set("owner.msb", chatRoom.owner.getUniqueId().getMostSignificantBits());
|
configuration.set("owner.msb", chatRoom.owner.getUniqueId().getMostSignificantBits());
|
||||||
configuration.set("owner.lsb", chatRoom.owner.getUniqueId().getLeastSignificantBits());
|
configuration.set("owner.lsb", chatRoom.owner.getUniqueId().getLeastSignificantBits());
|
||||||
|
|
||||||
File chatRoomFile = getFile(chatRoom.id);
|
File chatRoomFile = getFile(plugin, chatRoom.id);
|
||||||
configuration.save(chatRoomFile);
|
configuration.save(chatRoomFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.compass;
|
package eu.m724.tweaks.compass;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatColor;
|
import net.md_5.bungee.api.ChatColor;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
import net.md_5.bungee.api.chat.ComponentBuilder;
|
||||||
|
@ -25,9 +25,9 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
// TODO dimension check
|
// TODO dimension check
|
||||||
public class CompassModule extends TweaksModule implements Listener {
|
public class CompassListener implements Listener {
|
||||||
private final int precision = getConfig().compassPrecision(); // degrees every point
|
private final int precision = TweaksConfig.getConfig().compassPrecision(); // degrees every point
|
||||||
private final int width = getConfig().compassWidth(); // points left to right
|
private final int width = TweaksConfig.getConfig().compassWidth(); // points left to right
|
||||||
|
|
||||||
private final Map<Integer, String> points = Map.of(
|
private final Map<Integer, String> points = Map.of(
|
||||||
0, ChatColor.DARK_GRAY + "S",
|
0, ChatColor.DARK_GRAY + "S",
|
||||||
|
@ -36,11 +36,6 @@ public class CompassModule extends TweaksModule implements Listener {
|
||||||
270, ChatColor.DARK_GRAY + "E"
|
270, ChatColor.DARK_GRAY + "E"
|
||||||
);
|
);
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
public void onPlayerSwapHandItems(PlayerSwapHandItemsEvent event) {
|
||||||
if (event.getMainHandItem().getType() == Material.COMPASS || event.getOffHandItem().getType() == Material.COMPASS) {
|
if (event.getMainHandItem().getType() == Material.COMPASS || event.getOffHandItem().getType() == Material.COMPASS) {
|
21
src/main/java/eu/m724/tweaks/compass/CompassManager.java
Normal file
21
src/main/java/eu/m724/tweaks/compass/CompassManager.java
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.compass;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class CompassManager {
|
||||||
|
private final Plugin plugin;
|
||||||
|
|
||||||
|
public CompassManager(Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new CompassListener(), plugin);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.door;
|
package eu.m724.tweaks.door;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
|
@ -23,12 +22,7 @@ import org.bukkit.util.RayTraceResult;
|
||||||
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
public class DoorKnockModule extends TweaksModule implements Listener {
|
public class DoorKnockListener implements Listener {
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockDamageAbort(BlockDamageAbortEvent event) {
|
public void onBlockDamageAbort(BlockDamageAbortEvent event) {
|
||||||
Block block = event.getBlock();
|
Block block = event.getBlock();
|
24
src/main/java/eu/m724/tweaks/door/DoorManager.java
Normal file
24
src/main/java/eu/m724/tweaks/door/DoorManager.java
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.door;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class DoorManager {
|
||||||
|
|
||||||
|
public void init(Plugin plugin) {
|
||||||
|
if (TweaksConfig.getConfig().doorKnocking()) {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new DoorKnockListener(), plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TweaksConfig.getConfig().doorDoubleOpen()) {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new DoorOpenListener(), plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,12 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.door;
|
package eu.m724.tweaks.door;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.BlockFace;
|
import org.bukkit.block.BlockFace;
|
||||||
|
@ -16,11 +15,7 @@ import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.Action;
|
import org.bukkit.event.block.Action;
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
|
||||||
public class DoorOpenModule extends TweaksModule implements Listener {
|
public class DoorOpenListener implements Listener {
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
@ -76,4 +71,5 @@ public class DoorOpenModule extends TweaksModule implements Listener {
|
||||||
location.getBlock().setBlockData(nextDoor);
|
location.getBlock().setBlockData(nextDoor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,22 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.full;
|
package eu.m724.tweaks.full;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerLoginEvent;
|
import org.bukkit.event.player.PlayerLoginEvent;
|
||||||
|
|
||||||
public class FullModule extends TweaksModule implements Listener {
|
public class FullListener implements Listener {
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerLogin(PlayerLoginEvent event) {
|
public void onPlayerLogin(PlayerLoginEvent event) {
|
||||||
if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL && event.getPlayer().hasPermission("tweaks724.bypass-full")) {
|
if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL && event.getPlayer().hasPermission("tweaks724.bypass-full")) {
|
35
src/main/java/eu/m724/tweaks/hardcore/HardcoreManager.java
Normal file
35
src/main/java/eu/m724/tweaks/hardcore/HardcoreManager.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.hardcore;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.*;
|
||||||
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class HardcoreManager {
|
||||||
|
private final float chance = TweaksConfig.getConfig().hardcoreChance();
|
||||||
|
|
||||||
|
public void init(Plugin plugin) {
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Play.Server.LOGIN
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
int entityId = packet.getIntegers().read(0);
|
||||||
|
|
||||||
|
if (chance > ((48271 * entityId) % 65537) / 65537f) // gotta be fast
|
||||||
|
// the "is hardcore" boolean https://wiki.vg/Protocol#Login_.28play.29
|
||||||
|
packet.getBooleans().write(0, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.hardcore;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import net.minecraft.world.level.levelgen.RandomSupport;
|
|
||||||
import net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
// how we do it is much faster than any Random
|
|
||||||
public class HardcoreModule extends TweaksModule {
|
|
||||||
private final Xoroshiro128PlusPlus rng;
|
|
||||||
private final long chanceLong;
|
|
||||||
|
|
||||||
public HardcoreModule() {
|
|
||||||
this.rng = new Xoroshiro128PlusPlus(
|
|
||||||
RandomSupport.generateUniqueSeed(),
|
|
||||||
RandomSupport.generateUniqueSeed()
|
|
||||||
);
|
|
||||||
|
|
||||||
this.chanceLong = BigInteger.valueOf(Long.MIN_VALUE)
|
|
||||||
.add(
|
|
||||||
new BigDecimal(
|
|
||||||
BigInteger.valueOf(Long.MAX_VALUE).subtract(BigInteger.valueOf(Long.MIN_VALUE))
|
|
||||||
).multiply(
|
|
||||||
BigDecimal.valueOf(getConfig().hardcoreChance())
|
|
||||||
).toBigInteger()
|
|
||||||
).longValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
DebugLogger.fine("Chance long: " + chanceLong);
|
|
||||||
|
|
||||||
onPacketSend(PacketType.Play.Server.LOGIN, (event) -> {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
if (rng.nextLong() < chanceLong)
|
|
||||||
// the "is hardcore" boolean https://wiki.vg/Protocol#Login_.28play.29
|
|
||||||
packet.getBooleans().write(0, true);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,118 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.killswitch;
|
|
||||||
|
|
||||||
import com.sun.net.httpserver.HttpExchange;
|
|
||||||
import com.sun.net.httpserver.HttpHandler;
|
|
||||||
import com.sun.net.httpserver.HttpServer;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Base64;
|
|
||||||
|
|
||||||
public class KillswitchModule extends TweaksModule implements CommandExecutor, HttpHandler {
|
|
||||||
private final Ratelimit ratelimit = new Ratelimit();
|
|
||||||
|
|
||||||
private byte[] secret;
|
|
||||||
private String secretEncoded;
|
|
||||||
|
|
||||||
private void loadKey(File file) {
|
|
||||||
if (file.exists()) {
|
|
||||||
try {
|
|
||||||
this.secret = Files.readAllBytes(file.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Reading killswitch key", e);
|
|
||||||
}
|
|
||||||
DebugLogger.fine("Loaded key");
|
|
||||||
} else {
|
|
||||||
byte[] buf = new byte[16];
|
|
||||||
|
|
||||||
try {
|
|
||||||
SecureRandom.getInstanceStrong().nextBytes(buf);
|
|
||||||
Files.write(file.toPath(), buf);
|
|
||||||
} catch (IOException | NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException("Generating killswitch key", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.secret = buf;
|
|
||||||
DebugLogger.info("Killswitch key generated and saved to " + file.getPath());
|
|
||||||
}
|
|
||||||
|
|
||||||
this.secretEncoded = Base64.getEncoder().encodeToString(secret);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerCommand("servkill", this);
|
|
||||||
|
|
||||||
if (getConfig().killswitchListen() != null) {
|
|
||||||
loadKey(new File(getPlugin().getDataFolder(), "storage/killswitch key"));
|
|
||||||
|
|
||||||
ratelimit.runTaskTimerAsynchronously(getPlugin(), 0, 20 * 300);
|
|
||||||
|
|
||||||
var listenAddress = getConfig().killswitchListen().split(":");
|
|
||||||
InetSocketAddress bindAddress;
|
|
||||||
if (listenAddress.length == 1) {
|
|
||||||
bindAddress = new InetSocketAddress(Integer.parseInt(listenAddress[0]));
|
|
||||||
} else {
|
|
||||||
bindAddress = new InetSocketAddress(listenAddress[0], Integer.parseInt(listenAddress[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
HttpServer server = HttpServer.create(bindAddress, 0);
|
|
||||||
server.createContext("/", this);
|
|
||||||
server.setExecutor(null);
|
|
||||||
server.start();
|
|
||||||
DebugLogger.fine("server started");
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Starting HTTP server", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void kill() {
|
|
||||||
Runtime.getRuntime().halt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
kill();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void handle(HttpExchange exchange) throws IOException {
|
|
||||||
exchange.sendResponseHeaders(404, -1);
|
|
||||||
|
|
||||||
var path = exchange.getRequestURI().getPath();
|
|
||||||
if (!path.startsWith("/key/")) return;
|
|
||||||
|
|
||||||
var address = exchange.getRemoteAddress().getAddress();
|
|
||||||
if (!ratelimit.submitRequest(address)) {
|
|
||||||
DebugLogger.fine(address + " is ratelimited");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var key = path.substring(5);
|
|
||||||
if (key.equals(secretEncoded)) {
|
|
||||||
DebugLogger.fine("Got a request with valid key");
|
|
||||||
kill();
|
|
||||||
} else {
|
|
||||||
DebugLogger.fine("Got a request with invalid key");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.killswitch;
|
|
||||||
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
|
|
||||||
import java.net.InetAddress;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class Ratelimit extends BukkitRunnable {
|
|
||||||
private Set<InetAddress> requests = new HashSet<>();
|
|
||||||
|
|
||||||
boolean submitRequest(InetAddress address) {
|
|
||||||
return requests.add(address);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
requests = new HashSet<>();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.knockback;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.entity.EntityType;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.entity.EntityKnockbackByEntityEvent;
|
|
||||||
import org.bukkit.util.Vector;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class KnockbackModule extends TweaksModule implements Listener {
|
|
||||||
private final Map<EntityType, Vector> modifiers = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
getConfig().knockbackModifiers().forEach((k, v) -> {
|
|
||||||
EntityType type;
|
|
||||||
double mod;
|
|
||||||
|
|
||||||
String line = "(%s: %s)".formatted(k, v);
|
|
||||||
|
|
||||||
if (v instanceof Double d) {
|
|
||||||
mod = d;
|
|
||||||
} else if (v instanceof Integer i) {
|
|
||||||
mod = i;
|
|
||||||
} else {
|
|
||||||
DebugLogger.warning("In " + line + " the value is not a number ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
type = EntityType.valueOf(k);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
DebugLogger.warning("In" + line + " the key is not a valid entity type");
|
|
||||||
DebugLogger.warning("Valid entity types: https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mod == 1) return;
|
|
||||||
modifiers.put(type, new Vector(mod, mod >= 1 ? mod : 1, mod)); // don't touch vertical
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!modifiers.isEmpty()) {
|
|
||||||
registerEvents(this);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Class.forName("com.destroystokyo.paper.event.entity.EntityKnockbackByEntityEvent");
|
|
||||||
DebugLogger.warning("Ignore that. Server performance will NOT be affected.");
|
|
||||||
} catch (ClassNotFoundException ignored) { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onEntityKnockbackByEntity(EntityKnockbackByEntityEvent event) {
|
|
||||||
var modifier = modifiers.get(event.getSourceEntity().getType());
|
|
||||||
if (modifier != null) {
|
|
||||||
event.setFinalKnockback(event.getKnockback().multiply(modifier));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
103
src/main/java/eu/m724/tweaks/motd/MotdManager.java
Normal file
103
src/main/java/eu/m724/tweaks/motd/MotdManager.java
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.motd;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.*;
|
||||||
|
import com.comphenix.protocol.reflect.StructureModifier;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
|
import eu.m724.tweaks.TweaksPlugin;
|
||||||
|
import net.md_5.bungee.api.chat.TextComponent;
|
||||||
|
import net.md_5.bungee.chat.ComponentSerializer;
|
||||||
|
import net.minecraft.SharedConstants;
|
||||||
|
import net.minecraft.core.RegistryAccess;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.protocol.status.ServerStatus;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
|
|
||||||
|
public class MotdManager {
|
||||||
|
private final TweaksPlugin plugin;
|
||||||
|
|
||||||
|
private Component[] motds;
|
||||||
|
|
||||||
|
public MotdManager(TweaksPlugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() throws IOException {
|
||||||
|
// TODO adding more MOTD features would require checking whether to enable set
|
||||||
|
|
||||||
|
String motdSetName = TweaksConfig.getConfig().motdSet();
|
||||||
|
String motdSetPath = "motd sets/" + motdSetName + ".txt";
|
||||||
|
File motdSetsFile = new File(plugin.getDataFolder(), motdSetPath);
|
||||||
|
|
||||||
|
// create "motd sets" directory
|
||||||
|
motdSetsFile.getParentFile().mkdirs();
|
||||||
|
|
||||||
|
// if this is a builtin set
|
||||||
|
if (!motdSetsFile.exists() && plugin.hasResource(motdSetPath))
|
||||||
|
plugin.saveResource(motdSetPath, false);
|
||||||
|
|
||||||
|
if (!motdSetsFile.exists()) {
|
||||||
|
throw new RuntimeException("MOTD set \"%s\" doesn't exist".formatted(motdSetName));
|
||||||
|
}
|
||||||
|
|
||||||
|
String fileContent = Files.readString(motdSetsFile.toPath());
|
||||||
|
// MOTDs are split with an empty line
|
||||||
|
motds = Arrays.stream(fileContent.split("\n\n"))
|
||||||
|
.map(s -> {
|
||||||
|
JsonElement json = ComponentSerializer.toJson(TextComponent.fromLegacy(s.strip()));
|
||||||
|
return Component.Serializer.fromJson(json, RegistryAccess.EMPTY);
|
||||||
|
})
|
||||||
|
.toArray(Component[]::new);
|
||||||
|
|
||||||
|
registerListener(plugin);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void registerListener(Plugin plugin) {
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Status.Server.SERVER_INFO
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
|
||||||
|
Component motd = motds[ThreadLocalRandom.current().nextInt(motds.length)];
|
||||||
|
|
||||||
|
ServerStatus serverStatus = (ServerStatus) packet.getStructures().read(0).getHandle();
|
||||||
|
|
||||||
|
/* this:
|
||||||
|
* removes server mod prefix (Paper, Spigot, any brand)
|
||||||
|
* hides players
|
||||||
|
*/
|
||||||
|
ServerStatus newStatus = new ServerStatus(
|
||||||
|
motd,
|
||||||
|
Optional.empty(),
|
||||||
|
Optional.of(new ServerStatus.Version(
|
||||||
|
SharedConstants.getCurrentVersion().getName(),
|
||||||
|
SharedConstants.getProtocolVersion()
|
||||||
|
)),
|
||||||
|
serverStatus.favicon(),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
packet.getStructures().write(0, new InternalStructure(newStatus, new StructureModifier<>(ServerStatus.class)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,107 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.motd;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.events.*;
|
|
||||||
import com.comphenix.protocol.reflect.StructureModifier;
|
|
||||||
import com.google.gson.JsonElement;
|
|
||||||
import com.google.gson.JsonParseException;
|
|
||||||
import com.google.gson.JsonParser;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import net.md_5.bungee.api.chat.TextComponent;
|
|
||||||
import net.md_5.bungee.chat.ComponentSerializer;
|
|
||||||
import net.minecraft.SharedConstants;
|
|
||||||
import net.minecraft.core.RegistryAccess;
|
|
||||||
import net.minecraft.network.chat.Component;
|
|
||||||
import net.minecraft.network.protocol.status.ServerStatus;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public class MotdModule extends TweaksModule {
|
|
||||||
private Component[] motds;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
// TODO adding more MOTD features would require checking whether to enable set
|
|
||||||
|
|
||||||
String motdSetName = TweaksConfig.getConfig().motdSet();
|
|
||||||
String motdSetPath = "motd sets/" + motdSetName + ".txt";
|
|
||||||
File motdSetsFile = new File(getPlugin().getDataFolder(), motdSetPath);
|
|
||||||
|
|
||||||
// create "motd sets" directory
|
|
||||||
motdSetsFile.getParentFile().mkdirs();
|
|
||||||
|
|
||||||
// if this is a builtin set
|
|
||||||
if (!motdSetsFile.exists() && getPlugin().hasResource(motdSetPath))
|
|
||||||
getPlugin().saveResource(motdSetPath, false);
|
|
||||||
|
|
||||||
if (!motdSetsFile.exists()) {
|
|
||||||
throw new RuntimeException("MOTD set \"%s\" doesn't exist".formatted(motdSetName));
|
|
||||||
}
|
|
||||||
|
|
||||||
String fileContent;
|
|
||||||
try {
|
|
||||||
fileContent = Files.readString(motdSetsFile.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Reading motd set", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// MOTDs are split with an empty line
|
|
||||||
motds = Arrays.stream(fileContent.split("\n\n"))
|
|
||||||
.map(entry -> {
|
|
||||||
entry = entry.strip();
|
|
||||||
JsonElement json = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
json = JsonParser.parseString(entry);
|
|
||||||
DebugLogger.finer("JSON line: %s...", entry.substring(0, Math.min(entry.length(), 10)));
|
|
||||||
} catch (JsonParseException e) {
|
|
||||||
DebugLogger.finer("JSON line: %s...", entry.substring(0, Math.min(entry.length(), 10)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json == null) {
|
|
||||||
json = ComponentSerializer.toJson(TextComponent.fromLegacy(entry));
|
|
||||||
}
|
|
||||||
|
|
||||||
return Component.Serializer.fromJson(json, RegistryAccess.EMPTY);
|
|
||||||
})
|
|
||||||
.toArray(Component[]::new);
|
|
||||||
|
|
||||||
onPacketSend(PacketType.Status.Server.SERVER_INFO, (event) -> {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
|
|
||||||
Component motd = motds[ThreadLocalRandom.current().nextInt(motds.length)];
|
|
||||||
|
|
||||||
ServerStatus serverStatus = (ServerStatus) packet.getStructures().read(0).getHandle();
|
|
||||||
|
|
||||||
/* this:
|
|
||||||
* removes server mod prefix (Paper, Spigot, any brand)
|
|
||||||
* hides players
|
|
||||||
*/
|
|
||||||
ServerStatus newStatus = new ServerStatus(
|
|
||||||
motd,
|
|
||||||
Optional.empty(),
|
|
||||||
Optional.of(new ServerStatus.Version(
|
|
||||||
SharedConstants.getCurrentVersion().getName(),
|
|
||||||
SharedConstants.getProtocolVersion()
|
|
||||||
)),
|
|
||||||
serverStatus.favicon(),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
packet.getStructures().write(0, new InternalStructure(newStatus, new StructureModifier<>(ServerStatus.class)));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,12 +1,11 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.ping;
|
package eu.m724.tweaks.ping;
|
||||||
|
|
||||||
import org.bukkit.command.PluginCommand;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
public class PingChecker {
|
public class PingChecker {
|
||||||
|
@ -16,10 +15,8 @@ public class PingChecker {
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void init(PluginCommand pingCommand) {
|
public void init() {
|
||||||
new KeepAlivePingChecker(plugin).start();
|
new KeepAlivePingChecker(plugin).start();
|
||||||
new MsptChecker().init(plugin); // TODO should this be here
|
new MsptChecker().init(plugin); // TODO should this be here
|
||||||
|
|
||||||
pingCommand.setExecutor(new PingCommands());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
src/main/java/eu/m724/tweaks/pomodoro/PomodoroManager.java
Normal file
22
src/main/java/eu/m724/tweaks/pomodoro/PomodoroManager.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.pomodoro;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class PomodoroManager {
|
||||||
|
private final Plugin plugin;
|
||||||
|
|
||||||
|
public PomodoroManager(Plugin plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new PomodoroListener(), plugin);
|
||||||
|
new PomodoroRunnable(plugin).runTaskTimerAsynchronously(plugin, 0, 20L);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
|
|
||||||
public class PomodoroModule extends TweaksModule {
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(new PomodoroListener());
|
|
||||||
new PomodoroRunnable(getPlugin()).runTaskTimerAsynchronously(getPlugin(), 0, 20L);
|
|
||||||
|
|
||||||
registerCommand("pomodoro", new PomodoroCommands());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
package eu.m724.tweaks.pomodoro;
|
package eu.m724.tweaks.pomodoro;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
import net.md_5.bungee.api.ChatMessageType;
|
import net.md_5.bungee.api.ChatMessageType;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
@ -36,8 +37,7 @@ public class PomodoroRunnable extends BukkitRunnable {
|
||||||
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_FALL, 1.0f, 0.5f);
|
player.playSound(player.getLocation(), Sound.BLOCK_ANVIL_FALL, 1.0f, 0.5f);
|
||||||
if (remaining < -60 && force) {
|
if (remaining < -60 && force) {
|
||||||
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, () -> {
|
||||||
pomodoro.next();
|
player.kickPlayer(Language.getString("pomodoroEndKick"));
|
||||||
player.kickPlayer(Pomodoros.formatTimer(pomodoro, pomodoro.getRemainingSeconds(now)).toLegacyText());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ public class Pomodoros {
|
||||||
return timers.remove(player.getUniqueId()) != null;
|
return timers.remove(player.getUniqueId()) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
static BaseComponent formatTimer(PlayerPomodoro pomodoro, long remaining) {
|
static BaseComponent[] formatTimer(PlayerPomodoro pomodoro, long remaining) {
|
||||||
ComponentBuilder builder = new ComponentBuilder();
|
ComponentBuilder builder = new ComponentBuilder();
|
||||||
|
|
||||||
if (pomodoro.isBreak()) {
|
if (pomodoro.isBreak()) {
|
||||||
|
@ -66,6 +66,6 @@ public class Pomodoros {
|
||||||
builder.append(" o").color(color);
|
builder.append(" o").color(color);
|
||||||
}
|
}
|
||||||
|
|
||||||
return builder.build();
|
return builder.create();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.Language;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.NamespacedKey;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.ShapelessRecipe;
|
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
public class GatewayItem {
|
|
||||||
private final NamespacedKey gatewayKey;
|
|
||||||
|
|
||||||
public GatewayItem(Plugin plugin) {
|
|
||||||
var start = System.nanoTime();
|
|
||||||
|
|
||||||
this.gatewayKey = new NamespacedKey(plugin, "gateway");
|
|
||||||
var recipe = new ShapelessRecipe(gatewayKey, itemStack());
|
|
||||||
|
|
||||||
// this takes a long time for some reason. The first one especially
|
|
||||||
// do this somewhere off measure to JIT and skew the measurement: new RecipeChoice.MaterialChoice(Material.DIRT);
|
|
||||||
recipe.addIngredient(Material.NETHER_STAR);
|
|
||||||
recipe.addIngredient(Material.ENDER_CHEST);
|
|
||||||
recipe.addIngredient(Material.CHORUS_FLOWER);
|
|
||||||
recipe.addIngredient(Material.DAYLIGHT_DETECTOR);
|
|
||||||
|
|
||||||
plugin.getServer().addRecipe(recipe);
|
|
||||||
|
|
||||||
DebugLogger.finer("Adding the recipe took %d ms, which is a long time", (System.nanoTime() - start) / 1000000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack itemStack() {
|
|
||||||
var itemStack = new ItemStack(Material.DAYLIGHT_DETECTOR);
|
|
||||||
var meta = itemStack.getItemMeta();
|
|
||||||
|
|
||||||
meta.setItemName(Language.getString("redstoneGatewayItem"));
|
|
||||||
meta.getPersistentDataContainer().set(gatewayKey, PersistentDataType.BOOLEAN, true);
|
|
||||||
meta.setEnchantmentGlintOverride(true);
|
|
||||||
|
|
||||||
itemStack.setItemMeta(meta);
|
|
||||||
return itemStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isGateway(ItemStack itemStack) {
|
|
||||||
var meta = itemStack.getItemMeta();
|
|
||||||
if (meta == null) return false;
|
|
||||||
var value = meta.getPersistentDataContainer().get(gatewayKey, PersistentDataType.BOOLEAN);
|
|
||||||
|
|
||||||
return value != null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,53 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
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 org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
public class RedstoneCommands implements CommandExecutor {
|
|
||||||
private final GatewayItem gatewayItem;
|
|
||||||
|
|
||||||
public RedstoneCommands(GatewayItem gatewayItem) {
|
|
||||||
this.gatewayItem = gatewayItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
if (args.length > 0) {
|
|
||||||
if (args[0].equals("give")) {
|
|
||||||
Player player = null;
|
|
||||||
|
|
||||||
if (args.length > 1) {
|
|
||||||
player = Bukkit.getPlayerExact(args[1]);
|
|
||||||
if (player == null) {
|
|
||||||
sender.sendMessage("No player named " + args[1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (sender instanceof Player) {
|
|
||||||
player = (Player) sender;
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Specify a player to give to, or be a player");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var itemStack = gatewayItem.itemStack();
|
|
||||||
player.getInventory().addItem(itemStack);
|
|
||||||
sender.sendMessage("Given to " + player.getName());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sender.sendMessage("Argument needed");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,179 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import com.google.common.collect.BiMap;
|
|
||||||
import com.google.common.collect.HashBiMap;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.Particle;
|
|
||||||
import org.bukkit.block.Block;
|
|
||||||
import org.bukkit.block.data.AnaloguePowerable;
|
|
||||||
import org.bukkit.metadata.FixedMetadataValue;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
|
||||||
|
|
||||||
public class RedstoneGateways {
|
|
||||||
private final Plugin plugin;
|
|
||||||
|
|
||||||
private final BiMap<Integer, Location> gatewaysById = HashBiMap.create();
|
|
||||||
private final Map<Integer, Byte> gatewaysByPower = new HashMap<>();
|
|
||||||
|
|
||||||
public RedstoneGateways(Plugin plugin) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Event */
|
|
||||||
|
|
||||||
int onPlace(Block block) {
|
|
||||||
var repeaterId = ThreadLocalRandom.current().nextInt() & 0x7FFFFFF0;
|
|
||||||
|
|
||||||
gatewaysById.put(repeaterId, block.getLocation());
|
|
||||||
block.setMetadata("rid", new FixedMetadataValue(plugin, repeaterId));
|
|
||||||
|
|
||||||
RedstoneStore.getInstance().saveRepeaterData(block.getLocation(), repeaterId, (byte) 0);
|
|
||||||
|
|
||||||
return repeaterId;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onBreak(int repeaterId) {
|
|
||||||
delete(repeaterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
void delete(int repeaterId) {
|
|
||||||
var location = gatewaysById.remove(repeaterId);
|
|
||||||
if (location == null) return;
|
|
||||||
gatewaysByPower.remove(repeaterId);
|
|
||||||
|
|
||||||
RedstoneStore.getInstance().deleteSavedRepeaterData(location);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get functions */
|
|
||||||
|
|
||||||
private boolean isValid(int repeaterId) {
|
|
||||||
// check if there's a repeater with such ID stored
|
|
||||||
// if not, we're not loading because it's loaded as the block is
|
|
||||||
var loc = gatewaysById.get(repeaterId);
|
|
||||||
if (loc == null) {
|
|
||||||
DebugLogger.fine("isValid: Delete because no loc");
|
|
||||||
delete(repeaterId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if chunk the block is in is loaded
|
|
||||||
// you may think it could be simplified, but it can't without loading the chunk (to check if it's loaded)
|
|
||||||
var isLoaded = loc.getWorld().isChunkLoaded(loc.getBlockX() / 16, loc.getBlockZ() / 16);
|
|
||||||
if (!isLoaded) return false;
|
|
||||||
|
|
||||||
// check if the block is correct type
|
|
||||||
if (loc.getBlock().getType() != Material.DAYLIGHT_DETECTOR) {
|
|
||||||
DebugLogger.fine("isValid: Delete because not sensor");
|
|
||||||
delete(repeaterId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if the block has the same ID bound
|
|
||||||
var meta = loc.getBlock().getMetadata("rid");
|
|
||||||
if (meta.isEmpty() || meta.getFirst().asInt() != repeaterId) {
|
|
||||||
DebugLogger.fine("isValid: Delete because no meta");
|
|
||||||
delete(repeaterId);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getId(Block block) {
|
|
||||||
if (block.hasMetadata("rid")) {
|
|
||||||
var id = block.getMetadata("rid").getFirst().asInt();
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
var id = gatewaysById.inverse().get(block.getLocation());
|
|
||||||
|
|
||||||
if (id == null) {
|
|
||||||
// not in memory, check if repeater
|
|
||||||
var d = RedstoneStore.getInstance().getSavedRepeaterData(block.getLocation());
|
|
||||||
|
|
||||||
if (d == null) {
|
|
||||||
block.setMetadata("rid", new FixedMetadataValue(plugin, Integer.MIN_VALUE));
|
|
||||||
return Integer.MIN_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
id = d.getKey();
|
|
||||||
block.setMetadata("rid", new FixedMetadataValue(plugin, id));
|
|
||||||
|
|
||||||
gatewaysById.put(id, block.getLocation());
|
|
||||||
gatewaysByPower.put(id, d.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isValid(id)) return Integer.MIN_VALUE;
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block getBlock(int repeaterId) {
|
|
||||||
var location = gatewaysById.get(repeaterId);
|
|
||||||
if (location == null) return null;
|
|
||||||
|
|
||||||
if (!isValid(repeaterId)) return null;
|
|
||||||
|
|
||||||
var storedId = location.getBlock().getMetadata("rid").getFirst().asInt();
|
|
||||||
if (storedId != repeaterId) {
|
|
||||||
DebugLogger.fine("attempted retrieve, but doesn't exist, deleting " + repeaterId);
|
|
||||||
delete(repeaterId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugLogger.fine("retrieved " + repeaterId);
|
|
||||||
|
|
||||||
return location.getBlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Control functions */
|
|
||||||
|
|
||||||
byte getInboundPower(int repeaterId) {
|
|
||||||
var block = getBlock(repeaterId);
|
|
||||||
if (block == null) return -1;
|
|
||||||
|
|
||||||
block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
|
|
||||||
|
|
||||||
var power = (byte) block.getBlockPower();
|
|
||||||
DebugLogger.fine("Got " + repeaterId + " receives " + power);
|
|
||||||
return power;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte getOutboundPower(int repeaterId) {
|
|
||||||
var block = getBlock(repeaterId);
|
|
||||||
if (block == null) return -1;
|
|
||||||
|
|
||||||
var power = gatewaysByPower.getOrDefault(repeaterId, (byte) 0);
|
|
||||||
DebugLogger.fine("Got " + repeaterId + " outputs " + power);
|
|
||||||
return power;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setPower(int repeaterId, byte power) {
|
|
||||||
if (power < 0 || power > 15)
|
|
||||||
throw new IllegalArgumentException("Power should be 0-15, but is " + power);
|
|
||||||
|
|
||||||
var block = getBlock(repeaterId);
|
|
||||||
if (block == null) return;
|
|
||||||
|
|
||||||
var data = (AnaloguePowerable) block.getBlockData();
|
|
||||||
|
|
||||||
gatewaysByPower.put(repeaterId, power);
|
|
||||||
data.setPower(power);
|
|
||||||
|
|
||||||
block.getWorld().spawnParticle(Particle.LAVA, block.getLocation().add(0.5, 0.5, 0.5), 3);
|
|
||||||
|
|
||||||
DebugLogger.fine("Set power of " + repeaterId + " to " + power);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,91 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.Language;
|
|
||||||
import net.md_5.bungee.api.ChatColor;
|
|
||||||
import net.md_5.bungee.api.chat.ClickEvent;
|
|
||||||
import net.md_5.bungee.api.chat.ComponentBuilder;
|
|
||||||
import net.md_5.bungee.api.chat.HoverEvent;
|
|
||||||
import net.md_5.bungee.api.chat.hover.content.Text;
|
|
||||||
import org.bukkit.enchantments.Enchantment;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.block.Action;
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
|
||||||
import org.bukkit.event.block.BlockRedstoneEvent;
|
|
||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
|
||||||
|
|
||||||
public class RedstoneListener implements Listener {
|
|
||||||
private final RedstoneGateways redstoneGateways;
|
|
||||||
private final GatewayItem gatewayItem;
|
|
||||||
|
|
||||||
public RedstoneListener(RedstoneGateways redstoneGateways, GatewayItem gatewayItem) {
|
|
||||||
this.redstoneGateways = redstoneGateways;
|
|
||||||
this.gatewayItem = gatewayItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onBlockPlace(BlockPlaceEvent event) {
|
|
||||||
if (!gatewayItem.isGateway(event.getItemInHand())) return;
|
|
||||||
|
|
||||||
var block = event.getBlockPlaced();
|
|
||||||
var id = redstoneGateways.onPlace(block);
|
|
||||||
|
|
||||||
DebugLogger.fine("Gateway placed: " + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
|
||||||
var id = redstoneGateways.getId(event.getBlock());
|
|
||||||
if (id == Integer.MIN_VALUE) return;
|
|
||||||
|
|
||||||
redstoneGateways.onBreak(id);
|
|
||||||
|
|
||||||
if (event.getPlayer().getInventory().getItemInMainHand().containsEnchantment(Enchantment.SILK_TOUCH)) {
|
|
||||||
event.setDropItems(false);
|
|
||||||
event.getBlock().getWorld().dropItemNaturally(event.getBlock().getLocation(), gatewayItem.itemStack());
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugLogger.fine("Gateway broken: " + id);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onPlayerInteract(PlayerInteractEvent event) {
|
|
||||||
if (event.getAction() != Action.RIGHT_CLICK_BLOCK) return;
|
|
||||||
if (!event.getPlayer().isSneaking()) return;
|
|
||||||
|
|
||||||
var id = redstoneGateways.getId(event.getClickedBlock());
|
|
||||||
if (id == Integer.MIN_VALUE) return;
|
|
||||||
|
|
||||||
// TODO find a less lame way of showing ID
|
|
||||||
var component = new ComponentBuilder("Gateway ID: ").color(ChatColor.GOLD)
|
|
||||||
.append(String.valueOf(id)).color(ChatColor.AQUA)
|
|
||||||
.event(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(Language.getString("clickToCopy"))))
|
|
||||||
.event(new ClickEvent(ClickEvent.Action.COPY_TO_CLIPBOARD, String.valueOf(id)))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
event.getPlayer().spigot().sendMessage(component);
|
|
||||||
|
|
||||||
// cancel block place
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onBlockRedstone(BlockRedstoneEvent event) {
|
|
||||||
var block = event.getBlock();
|
|
||||||
|
|
||||||
var id = redstoneGateways.getId(block);
|
|
||||||
if (id == Integer.MIN_VALUE) return;
|
|
||||||
|
|
||||||
event.setNewCurrent(redstoneGateways.getOutboundPower(id));
|
|
||||||
|
|
||||||
DebugLogger.fine("Gateway redstone event: " + id);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,99 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksConfig;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.*;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class RedstoneModule extends TweaksModule {
|
|
||||||
private final RedstoneGateways redstoneGateways = new RedstoneGateways(getPlugin());
|
|
||||||
|
|
||||||
private DatagramSocket socket;
|
|
||||||
private RedstoneStateUpdateRunnable runnable;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
RedstoneStore.init(getPlugin());
|
|
||||||
var gatewayItem = new GatewayItem(getPlugin());
|
|
||||||
|
|
||||||
registerEvents(new RedstoneListener(redstoneGateways, gatewayItem));
|
|
||||||
registerCommand("retstone", new RedstoneCommands(gatewayItem));
|
|
||||||
|
|
||||||
this.runnable = new RedstoneStateUpdateRunnable(redstoneGateways);
|
|
||||||
this.runnable.runTaskTimer(getPlugin(), 0, 20); // TODO configurable
|
|
||||||
|
|
||||||
var listenAddress = TweaksConfig.getConfig().redstoneListen().split(":");
|
|
||||||
InetSocketAddress bindAddress;
|
|
||||||
if (listenAddress.length == 1) {
|
|
||||||
bindAddress = new InetSocketAddress(Integer.parseInt(listenAddress[0]));
|
|
||||||
} else {
|
|
||||||
bindAddress = new InetSocketAddress(listenAddress[0], Integer.parseInt(listenAddress[1]));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
initSocket(bindAddress);
|
|
||||||
} catch (SocketException e) {
|
|
||||||
throw new RuntimeException("Starting socket", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initSocket(SocketAddress bindAddress) throws SocketException {
|
|
||||||
socket = new DatagramSocket(bindAddress);
|
|
||||||
|
|
||||||
Executors.newSingleThreadExecutor().execute(() -> {
|
|
||||||
byte[] buf = new byte[4];
|
|
||||||
|
|
||||||
while (!socket.isClosed()) {
|
|
||||||
DatagramPacket packet
|
|
||||||
= new DatagramPacket(buf, buf.length);
|
|
||||||
try {
|
|
||||||
socket.receive(packet);
|
|
||||||
} catch (IOException e) {
|
|
||||||
DebugLogger.severe("Error reading packet: " + e.getMessage());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean write = (buf[0] >> 7 & 1) == 1;
|
|
||||||
byte data = (byte) (buf[3] & 0xF);
|
|
||||||
int gatewayId = ((buf[0] & 0x7F) << 24) | ((buf[1] & 0xFF) << 16) | ((buf[2] & 0xFF) << 8) | (buf[3] & 0xF0);
|
|
||||||
|
|
||||||
if (write) {
|
|
||||||
enqueueUpdate(gatewayId, data);
|
|
||||||
} else {
|
|
||||||
var newPacket = new DatagramPacket(new byte[1], 1, packet.getSocketAddress());
|
|
||||||
|
|
||||||
enqueueRetrieve(gatewayId, value -> {
|
|
||||||
DebugLogger.fine("Retrieved for " + gatewayId + " power " + value);
|
|
||||||
newPacket.setData(new byte[] { (byte) Math.max(value, 0) });
|
|
||||||
|
|
||||||
try {
|
|
||||||
socket.send(newPacket);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Sending response to get repeater value", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueUpdate(int gatewayId, byte power) {
|
|
||||||
DebugLogger.finer("Update enqueued " + gatewayId + " " + power);
|
|
||||||
runnable.enqueueUpdate(gatewayId, power);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void enqueueRetrieve(int gatewayId, Consumer<Byte> consumer) {
|
|
||||||
DebugLogger.finer("Retrieve enqueued " + gatewayId);
|
|
||||||
runnable.enqueueRetrieve(gatewayId, consumer);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class RedstoneStateUpdateRunnable extends BukkitRunnable {
|
|
||||||
private Map<Integer, Byte> updateQueue = new HashMap<>();
|
|
||||||
private Map<Integer, Consumer<Byte>> retrieveQueue = new HashMap<>();
|
|
||||||
|
|
||||||
private final RedstoneGateways redstoneGateways;
|
|
||||||
|
|
||||||
RedstoneStateUpdateRunnable(RedstoneGateways redstoneGateways) {
|
|
||||||
this.redstoneGateways = redstoneGateways;
|
|
||||||
}
|
|
||||||
|
|
||||||
void enqueueUpdate(int gatewayId, byte power) {
|
|
||||||
updateQueue.put(gatewayId, power);
|
|
||||||
}
|
|
||||||
|
|
||||||
void enqueueRetrieve(int repeaterId, Consumer<Byte> consumer) {
|
|
||||||
retrieveQueue.put(repeaterId, consumer);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
var updateQueue = this.updateQueue;
|
|
||||||
this.updateQueue = new HashMap<>();
|
|
||||||
|
|
||||||
var retrieveQueue = this.retrieveQueue;
|
|
||||||
this.retrieveQueue = new HashMap<>();
|
|
||||||
|
|
||||||
updateQueue.forEach((key, value) -> redstoneGateways.setPower(key, value));
|
|
||||||
retrieveQueue.forEach((key, value) -> value.accept(redstoneGateways.getInboundPower(key)));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2024 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.redstone;
|
|
||||||
|
|
||||||
import com.google.common.primitives.Ints;
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
|
|
||||||
public class RedstoneStore {
|
|
||||||
private static RedstoneStore INSTANCE;
|
|
||||||
|
|
||||||
private final File directory;
|
|
||||||
|
|
||||||
private RedstoneStore(Plugin plugin) {
|
|
||||||
this.directory = new File(plugin.getDataFolder(), "storage/redstone");
|
|
||||||
directory.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init(Plugin plugin) {
|
|
||||||
INSTANCE = new RedstoneStore(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
static RedstoneStore getInstance() {
|
|
||||||
return INSTANCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<Integer, Byte> getSavedRepeaterData(Location location) {
|
|
||||||
var file = getFile(location);
|
|
||||||
if (!file.exists()) return null;
|
|
||||||
|
|
||||||
byte[] bytes;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// TODO read just 4 bytes
|
|
||||||
bytes = Files.readAllBytes(file.toPath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Loading saved gateway data", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
var gatewayId = Ints.fromByteArray(bytes) & ~0xF;
|
|
||||||
var powerLevel = (byte) (bytes[3] & 0xF);
|
|
||||||
|
|
||||||
DebugLogger.fine("load " + location + " " + gatewayId + " " + powerLevel);
|
|
||||||
|
|
||||||
return Pair.of(gatewayId, powerLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void saveRepeaterData(Location location, int gatewayId, byte powerLevel) {
|
|
||||||
var file = getFile(location);
|
|
||||||
byte[] bytes = Ints.toByteArray((gatewayId & ~0xF) | (powerLevel & 0xF));
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.write(file.toPath(), bytes);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new RuntimeException("Saving repeater data", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
DebugLogger.fine("save " + location + " " + gatewayId + " " + powerLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
void deleteSavedRepeaterData(Location location) {
|
|
||||||
getFile(location).delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
private File getFile(Location location) {
|
|
||||||
return new File(directory, location.getWorld().getName() + " " + location.getBlockX() + " " + location.getBlockY() + " " + location.getBlockZ());
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
@ -21,7 +21,6 @@ import java.util.Set;
|
||||||
|
|
||||||
public class SleepListener implements Listener {
|
public class SleepListener implements Listener {
|
||||||
private final boolean instant = TweaksConfig.getConfig().sleepInstant();
|
private final boolean instant = TweaksConfig.getConfig().sleepInstant();
|
||||||
private final double heal = TweaksConfig.getConfig().sleepHeal() * 2; // hearts to half hearts
|
|
||||||
|
|
||||||
private final Set<Player> skippedCurrentNight = new HashSet<>();
|
private final Set<Player> skippedCurrentNight = new HashSet<>();
|
||||||
private long lastDay = 0;
|
private long lastDay = 0;
|
||||||
|
@ -31,6 +30,7 @@ public class SleepListener implements Listener {
|
||||||
if (event.getBedEnterResult() == PlayerBedEnterEvent.BedEnterResult.OK) {
|
if (event.getBedEnterResult() == PlayerBedEnterEvent.BedEnterResult.OK) {
|
||||||
SleepState.playersSleeping++;
|
SleepState.playersSleeping++;
|
||||||
|
|
||||||
|
if (instant) {
|
||||||
World world = event.getPlayer().getWorld();
|
World world = event.getPlayer().getWorld();
|
||||||
|
|
||||||
long day = world.getFullTime() / 24000;
|
long day = world.getFullTime() / 24000;
|
||||||
|
@ -38,13 +38,10 @@ public class SleepListener implements Listener {
|
||||||
lastDay = day;
|
lastDay = day;
|
||||||
|
|
||||||
if (!skippedCurrentNight.contains(event.getPlayer())) {
|
if (!skippedCurrentNight.contains(event.getPlayer())) {
|
||||||
if (instant) {
|
|
||||||
double onePlayerRatio = 1 / (event.getPlayer().getServer().getOnlinePlayers().size() * (world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE) / 100.0));
|
double onePlayerRatio = 1 / (event.getPlayer().getServer().getOnlinePlayers().size() * (world.getGameRuleValue(GameRule.PLAYERS_SLEEPING_PERCENTAGE) / 100.0));
|
||||||
world.setTime(Math.min(world.getTime() + (long) (10917 * onePlayerRatio), 23459));
|
world.setTime(Math.min(world.getTime() + (long) (10917 * onePlayerRatio), 23459));
|
||||||
skippedCurrentNight.add(event.getPlayer());
|
skippedCurrentNight.add(event.getPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
event.getPlayer().setHealth(event.getPlayer().getHealth() + heal);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +53,8 @@ public class SleepListener implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onTimeSkip(TimeSkipEvent event) {
|
public void onPlayerBedLeave(TimeSkipEvent event) {
|
||||||
if (event.getSkipReason() == TimeSkipEvent.SkipReason.NIGHT_SKIP) {
|
if (event.getSkipReason() == TimeSkipEvent.SkipReason.NIGHT_SKIP)
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
18
src/main/java/eu/m724/tweaks/sleep/SleepManager.java
Normal file
18
src/main/java/eu/m724/tweaks/sleep/SleepManager.java
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.sleep;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class SleepManager {
|
||||||
|
public void init(Plugin plugin) {
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(new SleepListener(), plugin);
|
||||||
|
if (!TweaksConfig.getConfig().sleepInstant())
|
||||||
|
new TimeForwardRunnable(plugin).runTaskTimer(plugin, 0, 1); // TODO maybe not
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.sleep;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
|
|
||||||
public class SleepModule extends TweaksModule {
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(new SleepListener());
|
|
||||||
|
|
||||||
if (!getConfig().sleepInstant())
|
|
||||||
new TimeForwardRunnable(getPlugin()).runTaskTimer(getPlugin(), 0, 1); // TODO maybe not
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,68 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.swing;
|
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.attribute.Attribute;
|
|
||||||
import org.bukkit.entity.Entity;
|
|
||||||
import org.bukkit.entity.LivingEntity;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public class SwingModule extends TweaksModule implements Listener {
|
|
||||||
private final Set<Material> tools = new HashSet<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
Arrays.stream(Material.values())
|
|
||||||
.filter(m -> m.name().contains("SWORD"))
|
|
||||||
.forEach(tools::add);
|
|
||||||
|
|
||||||
DebugLogger.finer("Tools: " + tools.size());
|
|
||||||
|
|
||||||
registerEvents(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onBreak(BlockBreakEvent event) {
|
|
||||||
var type = event.getBlock().getType();
|
|
||||||
if (type.isOccluding()) return;
|
|
||||||
|
|
||||||
var player = event.getPlayer();
|
|
||||||
var tool = player.getInventory().getItemInMainHand().getType();
|
|
||||||
Entity entity = null;
|
|
||||||
|
|
||||||
if (tools.contains(tool)) { // if sword, raycast to hit farther
|
|
||||||
var result = player.getWorld().rayTraceEntities(
|
|
||||||
player.getEyeLocation(),
|
|
||||||
player.getEyeLocation().getDirection(),
|
|
||||||
player.getAttribute(Attribute.PLAYER_ENTITY_INTERACTION_RANGE).getValue(),
|
|
||||||
e -> e != player
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result != null)
|
|
||||||
entity = result.getHitEntity();
|
|
||||||
} else {
|
|
||||||
entity = event.getBlock().getWorld()
|
|
||||||
.getNearbyEntities(event.getBlock().getLocation().add(0.5, 0.5, 0.5), 0.5, 0.5, 0.5)
|
|
||||||
.stream().filter(e -> (e instanceof LivingEntity && e != player))
|
|
||||||
.findFirst().orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (entity != null) {
|
|
||||||
player.attack(entity);
|
|
||||||
DebugLogger.fine("Swing " + player.getName() + " hit " + entity.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -36,6 +36,7 @@ public class PluginScanner {
|
||||||
Set<SpigotResource> spigotResources = new HashSet<>();
|
Set<SpigotResource> spigotResources = new HashSet<>();
|
||||||
|
|
||||||
for (Plugin plugin : plugins) {
|
for (Plugin plugin : plugins) {
|
||||||
|
// System.out.println("Found " + plugin.getName());
|
||||||
String pluginName = plugin.getName();
|
String pluginName = plugin.getName();
|
||||||
|
|
||||||
if (!configuration.isSet(pluginName)) {
|
if (!configuration.isSet(pluginName)) {
|
||||||
|
|
|
@ -1,17 +1,16 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.updater;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.Language;
|
import eu.m724.tweaks.Language;
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
|
@ -24,26 +23,25 @@ import java.util.logging.Logger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class UpdateChecker extends BukkitRunnable {
|
public class UpdateChecker extends BukkitRunnable {
|
||||||
private final Logger logger;
|
|
||||||
private final File cacheFile;
|
|
||||||
private final Set<VersionedResource> resources;
|
private final Set<VersionedResource> resources;
|
||||||
|
private final Logger logger;
|
||||||
|
|
||||||
static final Set<VersionedResource> availableUpdates = new HashSet<>();
|
static final Set<VersionedResource> availableUpdates = new HashSet<>();
|
||||||
static LocalTime lastChecked = null;
|
static LocalTime lastChecked = null;
|
||||||
|
|
||||||
UpdateChecker(Logger logger, File cacheFile, Set<VersionedResource> resources) {
|
UpdateChecker(Plugin plugin, Set<VersionedResource> resources) {
|
||||||
this.logger = logger;
|
this.logger = Logger.getLogger(plugin.getLogger().getName() + "." + getClass().getSimpleName());
|
||||||
this.cacheFile = cacheFile;
|
|
||||||
this.resources = resources; // TODO make a copy?
|
this.resources = resources; // TODO make a copy?
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkAll() {
|
private void checkAll() {
|
||||||
DebugLogger.fine("Checking for updates");
|
//logger.info("Checking for updates");
|
||||||
lastChecked = LocalTime.now(ZoneOffset.UTC);
|
lastChecked = LocalTime.now(ZoneOffset.UTC);
|
||||||
availableUpdates.clear();
|
availableUpdates.clear();
|
||||||
|
|
||||||
for (VersionedResource versionedResource : Set.copyOf(resources)) {
|
for (VersionedResource versionedResource : Set.copyOf(resources)) {
|
||||||
String pluginName = versionedResource.resource().plugin().getName();
|
String pluginName = versionedResource.resource().plugin().getName();
|
||||||
|
//logger.info(versionedResource.resource().resourceId() + " " + versionedResource.resource().plugin().getName());
|
||||||
int page = versionedResource.running() != null ? versionedResource.running().page() : 1;
|
int page = versionedResource.running() != null ? versionedResource.running().page() : 1;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -51,19 +49,20 @@ public class UpdateChecker extends BukkitRunnable {
|
||||||
if (!versionedResource.equals(newResource)) {
|
if (!versionedResource.equals(newResource)) {
|
||||||
resources.remove(versionedResource);
|
resources.remove(versionedResource);
|
||||||
if (newResource.running() == null) {
|
if (newResource.running() == null) {
|
||||||
logger.warning("Unable to find installed version of %s".formatted(pluginName));
|
logger.info("Unable to find installed version of %s".formatted(pluginName));
|
||||||
if (versionedResource.running() != null) {
|
if (versionedResource.running() != null) {
|
||||||
logger.warning("Did you downgrade %s? If so, clear cache".formatted(pluginName));
|
logger.info("Did you downgrade %s? If so, clear cache".formatted(pluginName));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!newResource.running().equals(newResource.latest())) {
|
if (!newResource.running().equals(newResource.latest())) {
|
||||||
availableUpdates.add(newResource);
|
availableUpdates.add(newResource);
|
||||||
|
//logger.info("Update available for %s. %d -> %d".formatted(pluginName, newResource.running().updateId(), newResource.latest().updateId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resources.add(newResource);
|
resources.add(newResource);
|
||||||
}
|
}
|
||||||
} catch (CompletionException e) {
|
} catch (CompletionException e) {
|
||||||
DebugLogger.severe("Unable to refresh %s: %s".formatted(pluginName, e.getMessage()));
|
logger.severe("Unable to refresh %s: %s".formatted(pluginName, e.getMessage()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +70,7 @@ public class UpdateChecker extends BukkitRunnable {
|
||||||
private void alert() {
|
private void alert() {
|
||||||
int n = availableUpdates.size();
|
int n = availableUpdates.size();
|
||||||
if (n == 0) return;
|
if (n == 0) return;
|
||||||
logger.info(Language.getString("updateAvailableNotice", n));
|
logger.info(Language.getString("updateAvailableNotice").formatted(n));
|
||||||
|
|
||||||
availableUpdates.stream()
|
availableUpdates.stream()
|
||||||
.map(u -> "- %s (%s -> %s)".formatted(u.resource().name(), u.running().label(), u.latest().label()))
|
.map(u -> "- %s (%s -> %s)".formatted(u.resource().name(), u.running().label(), u.latest().label()))
|
||||||
|
@ -82,9 +81,7 @@ public class UpdateChecker extends BukkitRunnable {
|
||||||
public void run() {
|
public void run() {
|
||||||
checkAll();
|
checkAll();
|
||||||
|
|
||||||
DebugLogger.finer("Done checking, now saving");
|
try (FileOutputStream outputStream = new FileOutputStream(UpdaterManager.cacheFile)) {
|
||||||
cacheFile.getParentFile().mkdirs();
|
|
||||||
try (FileOutputStream outputStream = new FileOutputStream(cacheFile)) {
|
|
||||||
VersionCheckCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet()));
|
VersionCheckCache.writeAll(outputStream, resources.stream().map(VersionedResource::running).filter(Objects::nonNull).collect(Collectors.toSet()));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
|
|
|
@ -35,7 +35,7 @@ public class UpdaterCommands implements CommandExecutor {
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
sender.spigot().sendMessage(
|
sender.spigot().sendMessage(
|
||||||
Language.getComponent("updateAvailableNotice", ChatColor.GRAY, n)
|
new ComponentBuilder(Language.getString("updateAvailableNotice").formatted(n)).color(ChatColor.GRAY).build()
|
||||||
);
|
);
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
@ -45,7 +45,7 @@ public class UpdaterCommands implements CommandExecutor {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sender.spigot().sendMessage(Language.getComponent("updatesNoUpdates", ChatColor.GREEN, lastChecked));
|
sender.sendMessage(Language.getString("updatesNoUpdates").formatted(lastChecked));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -71,7 +71,7 @@ public class UpdaterCommands implements CommandExecutor {
|
||||||
.event(
|
.event(
|
||||||
new HoverEvent(
|
new HoverEvent(
|
||||||
HoverEvent.Action.SHOW_TEXT,
|
HoverEvent.Action.SHOW_TEXT,
|
||||||
new Text(Language.getString("updatesClickToOpen", v.latest().description().title()))
|
new Text(Language.getString("updatesClickToOpen").formatted(v.latest().description().title()))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.build();
|
.build();
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.updater;
|
package eu.m724.tweaks.updater;
|
||||||
|
|
||||||
import eu.m724.tweaks.DebugLogger;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
import eu.m724.tweaks.updater.cache.ResourceVersion;
|
||||||
import eu.m724.tweaks.updater.cache.SpigotResource;
|
import eu.m724.tweaks.updater.cache.SpigotResource;
|
||||||
import eu.m724.tweaks.updater.cache.VersionedResource;
|
import eu.m724.tweaks.updater.cache.VersionedResource;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
|
@ -20,29 +19,28 @@ import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class UpdaterModule extends TweaksModule {
|
public class UpdaterManager {
|
||||||
@Override
|
static File cacheFile;
|
||||||
protected void onInit() {
|
|
||||||
// scan installed plugins
|
private final Plugin plugin;
|
||||||
Set<SpigotResource> resources;
|
|
||||||
try {
|
public UpdaterManager(Plugin plugin) {
|
||||||
resources = new PluginScanner(getPlugin()).load();
|
this.plugin = plugin;
|
||||||
} catch (IOException e) {
|
cacheFile = new File(plugin.getDataFolder(), "cache/updater");
|
||||||
throw new RuntimeException("Loading plugins", e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init() throws IOException {
|
||||||
|
// scan installed plugins
|
||||||
|
Set<SpigotResource> resources = new PluginScanner(plugin).load();
|
||||||
|
|
||||||
|
cacheFile.getParentFile().mkdirs(); // TODO move this somewhere else
|
||||||
|
|
||||||
// load installed versions from cache
|
// load installed versions from cache
|
||||||
var cacheFile = new File(getPlugin().getDataFolder(), "storage/cache/updater");
|
|
||||||
|
|
||||||
Set<ResourceVersion> installedVersions;
|
Set<ResourceVersion> installedVersions;
|
||||||
try (FileInputStream inputStream = new FileInputStream(cacheFile)) {
|
try (FileInputStream inputStream = new FileInputStream(cacheFile)) {
|
||||||
installedVersions = VersionCheckCache.loadAll(inputStream);
|
installedVersions = VersionCheckCache.loadAll(inputStream);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
installedVersions = new HashSet<>();
|
installedVersions = new HashSet<>();
|
||||||
} catch (IOException e) {
|
|
||||||
DebugLogger.warning("Error loading installed version cache, starting fresh. " + e.getMessage());
|
|
||||||
installedVersions = new HashSet<>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<ResourceVersion> ivf = installedVersions;
|
final Set<ResourceVersion> ivf = installedVersions;
|
||||||
|
@ -52,9 +50,7 @@ public class UpdaterModule extends TweaksModule {
|
||||||
)).collect(Collectors.toSet());
|
)).collect(Collectors.toSet());
|
||||||
|
|
||||||
|
|
||||||
new UpdateChecker(getPlugin().getLogger(), cacheFile, versionedResources)
|
new UpdateChecker(plugin, versionedResources)
|
||||||
.runTaskTimerAsynchronously(getPlugin(), 600, 12 * 3600 * 20); // 12 hours
|
.runTaskTimerAsynchronously(plugin, 600, 12 * 3600 * 20);
|
||||||
|
|
||||||
registerCommand("updates", new UpdaterCommands());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,29 +1,18 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2025 Minecon724
|
* Copyright (C) 2024 Minecon724
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
* in the project root for the full license text.
|
* in the project root for the full license text.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package eu.m724.tweaks.worldborder;
|
package eu.m724.tweaks.worldborder;
|
||||||
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
import org.bukkit.craftbukkit.v1_21_R1.CraftWorld;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.world.WorldLoadEvent;
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
|
||||||
public class WorldBorderExpandModule extends TweaksModule implements Listener {
|
public class WorldBorderExpanderListener implements Listener {
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
registerEvents(this);
|
|
||||||
|
|
||||||
// because the plugin loads "post world"
|
|
||||||
getPlugin().getServer().getWorlds().forEach(w -> {
|
|
||||||
onWorldLoad(new WorldLoadEvent(w));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onWorldLoad(WorldLoadEvent event) {
|
public void onWorldLoad(WorldLoadEvent event) {
|
||||||
ServerLevel level = ((CraftWorld) event.getWorld()).getHandle();
|
ServerLevel level = ((CraftWorld) event.getWorld()).getHandle();
|
|
@ -1,51 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (C) 2025 Minecon724
|
|
||||||
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
|
||||||
* in the project root for the full license text.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package eu.m724.tweaks.worldborder;
|
|
||||||
|
|
||||||
import com.comphenix.protocol.PacketType;
|
|
||||||
import com.comphenix.protocol.events.PacketContainer;
|
|
||||||
import eu.m724.tweaks.TweaksModule;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
|
|
||||||
public class WorldBorderHideModule extends TweaksModule {
|
|
||||||
private static final int EXTENSION_RADIUS = 512;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void onInit() {
|
|
||||||
getPlugin().getServer().getMessenger().registerOutgoingPluginChannel(getPlugin(), "tweaks724:worldborder");
|
|
||||||
|
|
||||||
byte[] infoArray = ByteBuffer.allocate(4).putInt(EXTENSION_RADIUS).array();
|
|
||||||
|
|
||||||
onPacketSend(PacketType.Play.Server.INITIALIZE_BORDER, (event) -> {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// old diameter
|
|
||||||
packet.getDoubles().write(2, packet.getDoubles().read(2) + EXTENSION_RADIUS * 2);
|
|
||||||
// new diameter
|
|
||||||
packet.getDoubles().write(3, packet.getDoubles().read(3) + EXTENSION_RADIUS * 2);
|
|
||||||
|
|
||||||
// border radius
|
|
||||||
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
|
||||||
// warning distance
|
|
||||||
packet.getIntegers().write(1, packet.getIntegers().read(1) + EXTENSION_RADIUS);
|
|
||||||
|
|
||||||
event.getPlayer().sendPluginMessage(getPlugin(), "tweaks724:worldborder", infoArray);
|
|
||||||
});
|
|
||||||
|
|
||||||
onPacketSend(PacketType.Play.Server.SET_BORDER_SIZE, (event) -> {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// diameter
|
|
||||||
packet.getDoubles().write(0, packet.getDoubles().read(0) + EXTENSION_RADIUS * 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
onPacketSend(PacketType.Play.Server.SET_BORDER_WARNING_DISTANCE, (event) -> {
|
|
||||||
PacketContainer packet = event.getPacket();
|
|
||||||
// warning distance
|
|
||||||
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.worldborder;
|
||||||
|
|
||||||
|
import com.comphenix.protocol.PacketType;
|
||||||
|
import com.comphenix.protocol.ProtocolLibrary;
|
||||||
|
import com.comphenix.protocol.events.ListenerPriority;
|
||||||
|
import com.comphenix.protocol.events.PacketAdapter;
|
||||||
|
import com.comphenix.protocol.events.PacketContainer;
|
||||||
|
import com.comphenix.protocol.events.PacketEvent;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
|
public class WorldBorderHider {
|
||||||
|
private static final int EXTENSION_RADIUS = 512;
|
||||||
|
|
||||||
|
public void init(Plugin plugin) {
|
||||||
|
plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, "tweaks724:worldborder");
|
||||||
|
byte[] infoArray = ByteBuffer.allocate(4).putInt(EXTENSION_RADIUS).array();
|
||||||
|
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Play.Server.INITIALIZE_BORDER
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// old diameter
|
||||||
|
packet.getDoubles().write(2, packet.getDoubles().read(2) + EXTENSION_RADIUS * 2);
|
||||||
|
// new diameter
|
||||||
|
packet.getDoubles().write(3, packet.getDoubles().read(3) + EXTENSION_RADIUS * 2);
|
||||||
|
|
||||||
|
// border radius
|
||||||
|
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
||||||
|
// warning distance
|
||||||
|
packet.getIntegers().write(1, packet.getIntegers().read(1) + EXTENSION_RADIUS);
|
||||||
|
|
||||||
|
event.getPlayer().sendPluginMessage(plugin, "tweaks724:worldborder", infoArray);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Play.Server.SET_BORDER_SIZE
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// diameter
|
||||||
|
packet.getDoubles().write(0, packet.getDoubles().read(0) + EXTENSION_RADIUS * 2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ProtocolLibrary.getProtocolManager().addPacketListener(new PacketAdapter(
|
||||||
|
plugin,
|
||||||
|
ListenerPriority.NORMAL,
|
||||||
|
PacketType.Play.Server.SET_BORDER_WARNING_DISTANCE
|
||||||
|
) {
|
||||||
|
@Override
|
||||||
|
public void onPacketSending(PacketEvent event) {
|
||||||
|
PacketContainer packet = event.getPacket();
|
||||||
|
// warning distance
|
||||||
|
packet.getIntegers().write(0, packet.getIntegers().read(0) + EXTENSION_RADIUS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2024 Minecon724
|
||||||
|
* Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
|
||||||
|
* in the project root for the full license text.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package eu.m724.tweaks.worldborder;
|
||||||
|
|
||||||
|
import eu.m724.tweaks.TweaksConfig;
|
||||||
|
import org.bukkit.event.world.WorldLoadEvent;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
|
||||||
|
public class WorldBorderManager {
|
||||||
|
public void init(Plugin plugin) {
|
||||||
|
if (TweaksConfig.getConfig().worldborderExpand()) {
|
||||||
|
WorldBorderExpanderListener wbrl = new WorldBorderExpanderListener();
|
||||||
|
plugin.getServer().getPluginManager().registerEvents(wbrl, plugin);
|
||||||
|
|
||||||
|
// because the plugin loads "post world"
|
||||||
|
plugin.getServer().getWorlds().forEach(w -> {
|
||||||
|
wbrl.onWorldLoad(new WorldLoadEvent(w));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TweaksConfig.getConfig().worldborderHide()) {
|
||||||
|
new WorldBorderHider().init(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -83,9 +83,6 @@ hardcore:
|
||||||
|
|
||||||
# Makes sleeping
|
# Makes sleeping
|
||||||
# And adds a nice animation
|
# And adds a nice animation
|
||||||
# Percentage: playersSleepingPercentage gamerule
|
|
||||||
# If instant: how much % of players to skip the night
|
|
||||||
# If not: how much % make skipping full speed
|
|
||||||
sleep:
|
sleep:
|
||||||
enabled: true
|
enabled: true
|
||||||
# This gives every player a "share" of the night
|
# This gives every player a "share" of the night
|
||||||
|
@ -93,8 +90,9 @@ sleep:
|
||||||
# For example, if 5 players online and night is 5 minutes, one can go to sleep and skip 1 minute of the night
|
# For example, if 5 players online and night is 5 minutes, one can go to sleep and skip 1 minute of the night
|
||||||
# Leaving the bed and reentering it does nothing
|
# Leaving the bed and reentering it does nothing
|
||||||
instant: false
|
instant: false
|
||||||
# How many hearts to heal after sleeping
|
# Percentage: playersSleepingPercentage gamerule
|
||||||
heal: 2.0
|
# If instant: how much % of players to skip the night
|
||||||
|
# If not: how much % make skipping full speed
|
||||||
|
|
||||||
# "Hostname" authentication
|
# "Hostname" authentication
|
||||||
# This makes a player need to join a unique hostname like "asd123.example.com" where "asd123" is the key
|
# This makes a player need to join a unique hostname like "asd123.example.com" where "asd123" is the key
|
||||||
|
@ -105,37 +103,7 @@ auth:
|
||||||
# The domain of the server. Doesn't do anything other than showing in /tauth new
|
# The domain of the server. Doesn't do anything other than showing in /tauth new
|
||||||
domain: "replace.me"
|
domain: "replace.me"
|
||||||
|
|
||||||
# Adds gateways emitting redstone, controlled over internet
|
|
||||||
# https://git.m724.eu/Minecon724/tweaks724/src/branch/master/RETSTONE.md
|
|
||||||
retstone:
|
|
||||||
enabled: true
|
|
||||||
# This takes host:port, listens on UDP
|
|
||||||
listen: 127.0.0.1:57931
|
|
||||||
|
|
||||||
# Knockback dealt BY those entities is multiplied by value
|
|
||||||
# Entity must be one of https://hub.spigotmc.org/javadocs/bukkit/org/bukkit/entity/EntityType.html
|
|
||||||
# 1 means no change
|
|
||||||
knockback:
|
|
||||||
player: 0.7
|
|
||||||
tnt: 5
|
|
||||||
creeper: 0.7
|
|
||||||
|
|
||||||
# Kills server after /servkill or HTTP request
|
|
||||||
# https://git.m724.eu/Minecon724/tweaks724/src/branch/master/KILLSWITCH.md
|
|
||||||
killswitch:
|
|
||||||
enabled: true
|
|
||||||
# This takes host:port, starts an HTTP server
|
|
||||||
# To disable HTTP server, set to null
|
|
||||||
listen: 127.0.0.1:57932
|
|
||||||
|
|
||||||
# Swing through grass (and alike)
|
|
||||||
# If using sword, you can also hit behind the grass
|
|
||||||
# If not, you can only hit the entity in the grass
|
|
||||||
swing:
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
|
|
||||||
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
|
# Finally, thank you for downloading Tweaks724, I hope you enjoy!
|
||||||
|
|
||||||
# Don't modify unless told to
|
# Don't modify unless told to
|
||||||
magic number don't modify this: 2
|
magic number don't modify this: 1
|
|
@ -7,5 +7,3 @@ Random MOTD for every ping
|
||||||
Or just one line. If it doesn't fit it will be passed onto the second line.
|
Or just one line. If it doesn't fit it will be passed onto the second line.
|
||||||
|
|
||||||
Put your own files in this directory
|
Put your own files in this directory
|
||||||
|
|
||||||
["",{"text":"Also supports","color":"#A18D94"},{"text":" JSON","color":"#FF00FF"},{"text":"\n"},{"text":"Java","color":"dark_aqua"},{"text":"Script ","color":"aqua"},{"text":"Object","color":"gray"},{"text":" Notation","color":"red"}]
|
|
|
@ -34,12 +34,6 @@ commands:
|
||||||
emergencyalert:
|
emergencyalert:
|
||||||
description: Send emergency alert
|
description: Send emergency alert
|
||||||
permission: tweaks724.emergencyalert
|
permission: tweaks724.emergencyalert
|
||||||
retstone:
|
|
||||||
description: Retstone commands
|
|
||||||
permission: tweaks724.retstone
|
|
||||||
servkill:
|
|
||||||
description: Immediately stop the server
|
|
||||||
permission: tweaks724.servkill
|
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
tweaks724:
|
tweaks724:
|
||||||
|
@ -55,7 +49,4 @@ permissions:
|
||||||
default: op
|
default: op
|
||||||
emergencyalert:
|
emergencyalert:
|
||||||
default: op
|
default: op
|
||||||
retstone:
|
|
||||||
default: op
|
|
||||||
servkill:
|
|
||||||
default: false
|
|
||||||
|
|
|
@ -4,13 +4,8 @@
|
||||||
# in the project root for the full license text.
|
# in the project root for the full license text.
|
||||||
#
|
#
|
||||||
|
|
||||||
languageNotice = Language: %s (%s)
|
|
||||||
# Language name in your language
|
|
||||||
language = English
|
|
||||||
# Language name in English
|
|
||||||
languageEnglish = English
|
|
||||||
|
|
||||||
updateAvailableNotice = Available updates (%d):
|
updateAvailableNotice = Available updates (%d):
|
||||||
|
pomodoroEndKick = Break time! Come back in 5 minutes.
|
||||||
|
|
||||||
# Used in /updates
|
# Used in /updates
|
||||||
updatesNotChecked = Not checked yet
|
updatesNotChecked = Not checked yet
|
||||||
|
@ -29,7 +24,3 @@ chatAlreadyHere = You're already in this room
|
||||||
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
|
authKickWrongKey = You're connecting to the wrong server address. You must connect to the one you're registered to.
|
||||||
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
|
# If force is enabled and player is not registered. Changing this reveals you're using this plugin
|
||||||
authKickUnregistered = You are not whitelisted on this server!
|
authKickUnregistered = You are not whitelisted on this server!
|
||||||
|
|
||||||
redstoneGatewayItem = Redstone gateway
|
|
||||||
|
|
||||||
clickToCopy = Click to copy to clipboard
|
|
Loading…
Reference in a new issue