it works. commands are broken.
This commit is contained in:
Binary file not shown.
11
.idea/compiler.xml
generated
11
.idea/compiler.xml
generated
@@ -1,6 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="CompilerConfiguration">
|
<component name="CompilerConfiguration">
|
||||||
<bytecodeTargetLevel target="21" />
|
<annotationProcessing>
|
||||||
|
<profile name="Gradle Imported" enabled="true">
|
||||||
|
<outputRelativeToContentRoot value="true" />
|
||||||
|
<processorPath useClasspath="false">
|
||||||
|
<entry name="$USER_HOME$/.gradle/caches/modules-2/files-2.1/org.projectlombok/lombok/1.18.42/8365263844ebb62398e0dc33057ba10ba472d3b8/lombok-1.18.42.jar" />
|
||||||
|
</processorPath>
|
||||||
|
<module name="BlockAndSeek.main" />
|
||||||
|
</profile>
|
||||||
|
</annotationProcessing>
|
||||||
|
<bytecodeTargetLevel target="17" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="21" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/out" />
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
1
.idea/modules.xml
generated
1
.idea/modules.xml
generated
@@ -4,6 +4,7 @@
|
|||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" />
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.main.iml" />
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/modules/BlockAndSeek.test.iml" filepath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.test.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
5
.idea/modules/BlockAndSeek.main.iml
generated
5
.idea/modules/BlockAndSeek.main.iml
generated
@@ -1,5 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<module version="4">
|
<module version="4">
|
||||||
|
<component name="AdditionalModuleElements">
|
||||||
|
<content url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/../../build/generated/sources/annotationProcessor/java/main" isTestSource="false" generated="true" />
|
||||||
|
</content>
|
||||||
|
</component>
|
||||||
<component name="FacetManager">
|
<component name="FacetManager">
|
||||||
<facet type="minecraft" name="Minecraft">
|
<facet type="minecraft" name="Minecraft">
|
||||||
<configuration>
|
<configuration>
|
||||||
|
|||||||
108
build.gradle
108
build.gradle
@@ -1,6 +1,9 @@
|
|||||||
|
import java.nio.ByteBuffer
|
||||||
|
import java.nio.ByteOrder
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'java'
|
id 'java'
|
||||||
id("xyz.jpenilla.run-paper") version "2.3.1"
|
id "com.gradleup.shadow" version "9.2.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = 'hdvtdev'
|
group = 'hdvtdev'
|
||||||
@@ -8,6 +11,7 @@ version = '0.0.1-a'
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url 'https://storehouse.okaeri.eu/repository/maven-releases/'}
|
||||||
maven { url 'https://repo.md-5.net/content/groups/public/' }
|
maven { url 'https://repo.md-5.net/content/groups/public/' }
|
||||||
maven { url 'https://jitpack.io' }
|
maven { url 'https://jitpack.io' }
|
||||||
maven {
|
maven {
|
||||||
@@ -21,15 +25,24 @@ repositories {
|
|||||||
maven { url 'https://libraries.minecraft.net/' }
|
maven { url 'https://libraries.minecraft.net/' }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def okaeriConfigsVersion = '5.0.13'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.20.4-R0.1-SNAPSHOT")
|
||||||
implementation group: 'me.libraryaddict.disguises', name: 'libsdisguises', version: '11.0.6'
|
compileOnly group: 'me.libraryaddict.disguises', name: 'libsdisguises', version: '11.0.6'
|
||||||
//TODO implementation 'me.lucko:commodore:2.2'
|
compileOnly 'org.projectlombok:lombok:1.18.42'
|
||||||
|
annotationProcessor 'org.projectlombok:lombok:1.18.42'
|
||||||
|
|
||||||
|
implementation "eu.okaeri:okaeri-configs-validator-okaeri:$okaeriConfigsVersion"
|
||||||
|
implementation "eu.okaeri:okaeri-configs-yaml-bukkit:$okaeriConfigsVersion"
|
||||||
|
implementation "eu.okaeri:okaeri-configs-serdes-bukkit:$okaeriConfigsVersion"
|
||||||
|
implementation "eu.okaeri:okaeri-configs-serdes-commons:$okaeriConfigsVersion"
|
||||||
|
|
||||||
|
implementation "org.incendo:cloud-paper:2.0.0-beta.13"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def targetJavaVersion = 21
|
def targetJavaVersion = 17
|
||||||
java {
|
java {
|
||||||
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
def javaVersion = JavaVersion.toVersion(targetJavaVersion)
|
||||||
sourceCompatibility = javaVersion
|
sourceCompatibility = javaVersion
|
||||||
@@ -56,14 +69,83 @@ processResources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
jar {
|
tasks.shadowJar {
|
||||||
//destinationDirectory.set(file("/home/hadvart/Documents/Minecraft/Pufferfish 1.20.4/plugins"))
|
archiveClassifier.set("")
|
||||||
from sourceSets.main.output
|
relocate("eu.okaeri", "hdvtdev.blockandseek.libs.okaeri")
|
||||||
from {
|
relocate("org.incendo", "hdvtdev.blockandseek.libs.cloud")
|
||||||
configurations.runtimeClasspath.findAll {
|
|
||||||
it.name.startsWith('Java-Probability-Collection') || it.name.startsWith('commodore') || it.name.startsWith('brigadier')
|
|
||||||
}.collect { zipTree(it) }
|
|
||||||
}
|
|
||||||
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tasks.build {
|
||||||
|
dependsOn(tasks.shadowJar)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register('deploy') {
|
||||||
|
dependsOn build
|
||||||
|
|
||||||
|
|
||||||
|
doLast {
|
||||||
|
def targetDir = project.property('server.plugins.dir')
|
||||||
|
def rconHost = project.property('rcon.host')
|
||||||
|
def rconPort = project.property('rcon.port') as int
|
||||||
|
def rconPass = project.property('rcon.password')
|
||||||
|
|
||||||
|
|
||||||
|
def jarFile = tasks.jar.archiveFile.get().asFile
|
||||||
|
|
||||||
|
if (!file(targetDir).exists()) {
|
||||||
|
println "Err folder not found : $targetDir"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
copy {
|
||||||
|
from jarFile
|
||||||
|
into targetDir
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
sendRconCommand(rconHost, rconPort, rconPass, "plugman reload BlockAndSeek")
|
||||||
|
sendRconCommand(rconHost, rconPort, rconPass, "reload")
|
||||||
|
println "Plugin reloaded"
|
||||||
|
} catch (Exception e) {
|
||||||
|
println "RCON: ${e.message}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def sendRconCommand(String host, int port, String password, String command) {
|
||||||
|
new Socket(host, port).withCloseable { socket ->
|
||||||
|
def out = socket.outputStream
|
||||||
|
def inp = socket.inputStream
|
||||||
|
|
||||||
|
def sendPacket = { int id, int type, String body ->
|
||||||
|
byte[] bodyBytes = body.getBytes("UTF-8")
|
||||||
|
int length = 4 + 4 + bodyBytes.length + 2 // id + type + body + 2 nulls
|
||||||
|
ByteBuffer buffer = ByteBuffer.allocate(4 + length)
|
||||||
|
buffer.order(ByteOrder.LITTLE_ENDIAN)
|
||||||
|
|
||||||
|
buffer.putInt(length)
|
||||||
|
buffer.putInt(id)
|
||||||
|
buffer.putInt(type)
|
||||||
|
buffer.put(bodyBytes)
|
||||||
|
buffer.put((byte) 0)
|
||||||
|
buffer.put((byte) 0)
|
||||||
|
|
||||||
|
out.write(buffer.array())
|
||||||
|
out.flush()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sendPacket(1, 3, password)
|
||||||
|
|
||||||
|
inp.read(new byte[4096])
|
||||||
|
|
||||||
|
sendPacket(2, 2, command)
|
||||||
|
|
||||||
|
byte[] buffer = new byte[4096]
|
||||||
|
int read = inp.read(buffer)
|
||||||
|
if (read > 12) {
|
||||||
|
String response = new String(buffer, 12, read - 12 - 2, "UTF-8")
|
||||||
|
println "Server response: $response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
plugin.name=MySuperPlugin
|
||||||
|
|
||||||
|
server.plugins.dir=/home/hadvart/Documents/minecraft/Pufferfish/1.21.8/plugins
|
||||||
|
|
||||||
|
rcon.host=127.0.0.1
|
||||||
|
rcon.port=25575
|
||||||
|
rcon.password=14881488
|
||||||
@@ -1,315 +0,0 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.managers.ConfigManager;
|
|
||||||
import hdvtdev.blockAndSeek.managers.GamesManager;
|
|
||||||
import hdvtdev.blockAndSeek.managers.ItemManager;
|
|
||||||
import hdvtdev.blockAndSeek.managers.PropManager;
|
|
||||||
import hdvtdev.blockAndSeek.roulette.RouletteCreator;
|
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
|
||||||
import org.bukkit.*;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.PlayerInventory;
|
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class BlockAndSeekGame {
|
|
||||||
|
|
||||||
private final Map<Player, PlayerType> players = new ConcurrentHashMap<>();
|
|
||||||
private final Map<Player, RouletteCreator> hiderRoulette = new HashMap<>();
|
|
||||||
|
|
||||||
private volatile boolean started = false;
|
|
||||||
private final BlockAndSeekMap map;
|
|
||||||
private final Location lobby;
|
|
||||||
private final Location spawn;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
public BlockAndSeekGame(String name, BlockAndSeekMap map) {
|
|
||||||
this.map = map;
|
|
||||||
World world = Bukkit.getWorld(name);
|
|
||||||
world.setTime(1000);
|
|
||||||
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
|
|
||||||
world.setStorm(false);
|
|
||||||
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
|
|
||||||
this.name = name;
|
|
||||||
this.lobby = map.getLobbyLocation(world);
|
|
||||||
this.spawn = map.getSpawnLocation(world);
|
|
||||||
this.startBukkitTask();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int playerCount() {
|
|
||||||
return players.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isStarted() {
|
|
||||||
return started;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int maxPlayers() {
|
|
||||||
return map.getMaxPlayers();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean addPlayer(Player player) {
|
|
||||||
if (!started) {
|
|
||||||
players.put(player, PlayerType.HIDER);
|
|
||||||
player.getPersistentDataContainer().set(Keys.GAME, PersistentDataType.STRING, name);
|
|
||||||
player.teleport(lobby);
|
|
||||||
PlayerInventory inventory = player.getInventory();
|
|
||||||
inventory.clear();
|
|
||||||
inventory.setItem(8, Localization.translateItem(player, ItemManager.getLeaveItem()));
|
|
||||||
player.setGameMode(GameMode.SURVIVAL);
|
|
||||||
player.setInvulnerable(true);
|
|
||||||
player.setHealth(20.0);
|
|
||||||
player.setFoodLevel(20);
|
|
||||||
Localization.sendMessage(
|
|
||||||
players.keySet(),
|
|
||||||
true,
|
|
||||||
"player-join",
|
|
||||||
"{player}", player.getName(),
|
|
||||||
"{players}", players.size() + "/" + map.getMaxPlayers()
|
|
||||||
);
|
|
||||||
return true;
|
|
||||||
} else return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removePlayer(Player player) {
|
|
||||||
players.remove(player);
|
|
||||||
DisguiseAPI.undisguiseToAll(player);
|
|
||||||
player.getInventory().clear();
|
|
||||||
player.setGameMode(GameMode.SURVIVAL);
|
|
||||||
player.getPersistentDataContainer().remove(Keys.GAME);
|
|
||||||
Config config = ConfigManager.getConfig();
|
|
||||||
if (config.forceControl()) ItemManager.defaultInventory(player);
|
|
||||||
player.teleport(config.defaultSpawn());
|
|
||||||
|
|
||||||
|
|
||||||
Localization.sendMessage(
|
|
||||||
players.keySet(),
|
|
||||||
true,
|
|
||||||
"player-leave",
|
|
||||||
"{player}", player.getName(),
|
|
||||||
"{players}", started ? "" : players.size() + "/" + map.getMaxPlayers()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpectator(Player hider, @Nullable Player seeker) {
|
|
||||||
hider.spigot().respawn();
|
|
||||||
hider.teleport(hider.getLastDeathLocation());
|
|
||||||
players.put(hider, PlayerType.SPECTATOR);
|
|
||||||
hider.setGameMode(GameMode.SPECTATOR);
|
|
||||||
Localization.sendMessage(
|
|
||||||
players.keySet(),
|
|
||||||
true,
|
|
||||||
seeker == null ? "hider-died" : "hider-was-found",
|
|
||||||
"{hider}", hider.getName(),
|
|
||||||
"{seeker}", seeker == null ? "" : seeker.getName()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getHidersCount() {
|
|
||||||
return players.values().stream().filter(type -> type == PlayerType.HIDER).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getSeekersCount() {
|
|
||||||
return players.values().stream().filter(type -> type == PlayerType.SEEKER).count();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Player> getSeekers() {
|
|
||||||
return players.entrySet().stream().filter(entry -> entry.getValue() == PlayerType.SEEKER).map(Map.Entry::getKey).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Player> getHiders() {
|
|
||||||
return players.entrySet().stream().filter(entry -> entry.getValue() == PlayerType.HIDER).map(Map.Entry::getKey).toList();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Player getLastHider() {
|
|
||||||
return players.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void start() {
|
|
||||||
started = true;
|
|
||||||
selectRandomSeekers((int) Math.round(players.size() * 0.25));
|
|
||||||
List<Player> hiders = getHiders();
|
|
||||||
for (Player hider : hiders) {
|
|
||||||
hider.getPersistentDataContainer().set(Keys.HIDER, PersistentDataType.BOOLEAN, true);
|
|
||||||
hider.teleport(spawn);
|
|
||||||
hider.setInvulnerable(false);
|
|
||||||
PlayerInventory inventory = hider.getInventory();
|
|
||||||
inventory.clear();
|
|
||||||
inventory.addItem(Localization.translateItem(hider, ItemManager.getFreezeItem()));
|
|
||||||
inventory.addItem(Localization.translateItem(hider, ItemManager.getFaceChangingItem()));
|
|
||||||
hiderRoulette.put(hider, new RouletteCreator(hider, map.getBlocks()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void end(boolean force) {
|
|
||||||
GamesManager.remove(name);
|
|
||||||
if (!force) {
|
|
||||||
Config config = ConfigManager.getConfig();
|
|
||||||
Location serverLobby = config.defaultSpawn();
|
|
||||||
boolean defaultInventory = config.forceControl();
|
|
||||||
for (Player player : players.keySet()) {
|
|
||||||
|
|
||||||
|
|
||||||
DisguiseAPI.undisguiseToAll(player);
|
|
||||||
if (defaultInventory) ItemManager.defaultInventory(player);
|
|
||||||
player.setGlowing(false);
|
|
||||||
player.setInvulnerable(false);
|
|
||||||
Utils.setLevelWithBar(player, 0);
|
|
||||||
player.setVisibleByDefault(true);
|
|
||||||
player.setHealth(20);
|
|
||||||
player.setGameMode(GameMode.SURVIVAL);
|
|
||||||
player.teleport(serverLobby);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void preEnd() {
|
|
||||||
for (Player player : players.keySet()) {
|
|
||||||
PersistentDataContainer container = player.getPersistentDataContainer();
|
|
||||||
player.setInvulnerable(true);
|
|
||||||
container.remove(Keys.HIDER);
|
|
||||||
container.remove(Keys.SEEKER);
|
|
||||||
container.remove(Keys.GAME);
|
|
||||||
}
|
|
||||||
for (Player hider : getHiders()) {
|
|
||||||
hider.getInventory().clear();
|
|
||||||
PropManager.unfreezeIfFrozen(hider);
|
|
||||||
hider.setGlowing(true);
|
|
||||||
RouletteCreator rouletteCreator = hiderRoulette.get(hider);
|
|
||||||
rouletteCreator.getTask().cancelBoth();
|
|
||||||
rouletteCreator.closeInventory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void selectRandomSeekers(int count) {
|
|
||||||
ArrayList<Player> rawSeekers = new ArrayList<>();
|
|
||||||
Set<Player> playerSet = players.keySet();
|
|
||||||
for (Player player : playerSet) {
|
|
||||||
if (!GamesManager.triggerSeekerImmune(player)) rawSeekers.add(player);
|
|
||||||
}
|
|
||||||
Collections.shuffle(rawSeekers);
|
|
||||||
|
|
||||||
for (Player seeker : rawSeekers.subList(0, Math.min(count, playerSet.size()))) {
|
|
||||||
players.put(seeker, PlayerType.SEEKER);
|
|
||||||
ItemManager.setSeekerSet(seeker);
|
|
||||||
Utils.setLevelWithBar(seeker, 100);
|
|
||||||
seeker.setInvulnerable(false);
|
|
||||||
seeker.getPersistentDataContainer().set(Keys.SEEKER, PersistentDataType.BOOLEAN, true);
|
|
||||||
GamesManager.addSeekerImmune(seeker);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startBukkitTask() {
|
|
||||||
new BukkitRunnable() {
|
|
||||||
|
|
||||||
int waitTime = 30;
|
|
||||||
final int defaultWaitTime = waitTime;
|
|
||||||
int duration = map.getDuration();
|
|
||||||
final int seekerDeploy = duration - 15;
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (waitTime != 0) {
|
|
||||||
int playerSize = players.size();
|
|
||||||
if (playerSize >= map.getMinPlayers()) {
|
|
||||||
if (waitTime % 5 == 0 || waitTime <= 5) {
|
|
||||||
Localization.sendMessage(
|
|
||||||
players.keySet(),
|
|
||||||
true,
|
|
||||||
"wait-time-left",
|
|
||||||
"{time}", String.valueOf(waitTime)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
waitTime--;
|
|
||||||
} else if (playerSize == 0) {
|
|
||||||
end(true);
|
|
||||||
this.cancel();
|
|
||||||
} else if (waitTime != defaultWaitTime) {
|
|
||||||
waitTime = defaultWaitTime;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!started) {
|
|
||||||
start();
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if (players.isEmpty()) {
|
|
||||||
end(false);
|
|
||||||
this.cancel();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration > 0 && getHidersCount() == 0) {
|
|
||||||
Localization.sendTitle(
|
|
||||||
players.keySet(),
|
|
||||||
false,
|
|
||||||
"seekers-won"
|
|
||||||
);
|
|
||||||
preEnd();
|
|
||||||
duration = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration == seekerDeploy) {
|
|
||||||
for (Player seeker : getSeekers()) {
|
|
||||||
seeker.teleport(spawn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duration > 0 && getSeekersCount() == 0) duration = 0;
|
|
||||||
|
|
||||||
if (duration == 0) {
|
|
||||||
|
|
||||||
preEnd();
|
|
||||||
if (getHidersCount() == 1) {
|
|
||||||
Localization.sendTitle(
|
|
||||||
players.keySet(),
|
|
||||||
false,
|
|
||||||
"hiders-solo-win",
|
|
||||||
"{hider}", getLastHider().getName()
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
Localization.sendTitle(
|
|
||||||
players.keySet(),
|
|
||||||
false,
|
|
||||||
"hiders-won"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
duration--; // уменьшаем только один раз
|
|
||||||
} else if (duration > 0) {
|
|
||||||
Localization.sendActionBar(
|
|
||||||
players.keySet(),
|
|
||||||
false,
|
|
||||||
"game-time-left",
|
|
||||||
"{time}", String.valueOf(duration)
|
|
||||||
);
|
|
||||||
duration--;
|
|
||||||
} else if (duration == -10) {
|
|
||||||
end(false);
|
|
||||||
this.cancel();
|
|
||||||
} else {
|
|
||||||
duration--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}.runTaskTimer(BlockAndSeek.getInstance(), 0L, 20L);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private enum PlayerType {
|
|
||||||
SEEKER,
|
|
||||||
HIDER,
|
|
||||||
SPECTATOR
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,173 +0,0 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
|
||||||
|
|
||||||
|
|
||||||
import org.bukkit.Location;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.World;
|
|
||||||
import org.bukkit.configuration.serialization.ConfigurationSerializable;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
public class BlockAndSeekMap implements ConfigurationSerializable {
|
|
||||||
|
|
||||||
private List<Integer> spawn;
|
|
||||||
private List<Integer> lobby;
|
|
||||||
private int duration;
|
|
||||||
private int minPlayers;
|
|
||||||
private int maxPlayers;
|
|
||||||
private List<Block> blocks;
|
|
||||||
|
|
||||||
public BlockAndSeekMap() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public BlockAndSeekMap(List<Integer> spawn, List<Integer> lobby, int duration, int minPlayers, int maxPlayers,
|
|
||||||
List<Block> blocks) {
|
|
||||||
this.spawn = spawn;
|
|
||||||
this.lobby = lobby;
|
|
||||||
this.duration = duration;
|
|
||||||
this.minPlayers = minPlayers;
|
|
||||||
this.maxPlayers = maxPlayers;
|
|
||||||
this.blocks = blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getSpawn() {
|
|
||||||
return spawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Location getSpawnLocation(@Nullable World world) {
|
|
||||||
return new Location(world, spawn.getFirst(), spawn.get(1), spawn.get(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSpawn(List<Integer> spawn) {
|
|
||||||
this.spawn = spawn;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Integer> getLobby() {
|
|
||||||
return lobby;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Location getLobbyLocation(@Nullable World world) {
|
|
||||||
return new Location(world, lobby.getFirst(), lobby.get(1), lobby.get(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLobby(List<Integer> lobby) {
|
|
||||||
this.lobby = lobby;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getDuration() {
|
|
||||||
return duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDuration(int duration) {
|
|
||||||
this.duration = duration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMinPlayers() {
|
|
||||||
return minPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMinPlayers(int minPlayers) {
|
|
||||||
this.minPlayers = minPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getMaxPlayers() {
|
|
||||||
return maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setMaxPlayers(int maxPlayers) {
|
|
||||||
this.maxPlayers = maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Block> getBlocks() {
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBlocks(List<Block> blocks) {
|
|
||||||
this.blocks = blocks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isReady() {
|
|
||||||
return !spawn.isEmpty() && !lobby.isEmpty() && duration > 0 && !blocks.isEmpty() && minPlayers > 0 && maxPlayers > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static BlockAndSeekMap defaultMap() {
|
|
||||||
return new BlockAndSeekMap(List.of(), List.of(), 0, 0, 0, List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Set<MapStatus> check() {
|
|
||||||
Set<MapStatus> status = new HashSet<>();
|
|
||||||
if (spawn.isEmpty()) status.add(MapStatus.SPAWN_REQUIRED);
|
|
||||||
if (lobby.isEmpty()) status.add(MapStatus.LOBBY_REQUIRED);
|
|
||||||
if (duration <= 0) status.add(MapStatus.DURATION_REQUIRED);
|
|
||||||
if (minPlayers <= 0) status.add(MapStatus.MIN_PLAYERS_REQUIRED);
|
|
||||||
if (maxPlayers <= 0) status.add(MapStatus.MAX_PLAYERS_REQUIRED);
|
|
||||||
if (blocks.isEmpty()) status.add(MapStatus.BLOCKS_REQUIRED);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @NotNull Map<String, Object> serialize() {
|
|
||||||
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("spawn", spawn);
|
|
||||||
map.put("lobby", lobby);
|
|
||||||
map.put("duration", duration);
|
|
||||||
map.put("min-players", minPlayers);
|
|
||||||
map.put("max-players", maxPlayers);
|
|
||||||
List<Map<String, Object>> serBlocks = new ArrayList<>();
|
|
||||||
for (Block block : blocks) {
|
|
||||||
serBlocks.add(block.toMap());
|
|
||||||
}
|
|
||||||
map.put("blocks", serBlocks);
|
|
||||||
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public static BlockAndSeekMap deserialize(@NotNull Map<String, Object> args) {
|
|
||||||
|
|
||||||
BlockAndSeekMap map = new BlockAndSeekMap();
|
|
||||||
map.setSpawn((List<Integer>) args.get("spawn"));
|
|
||||||
map.setLobby((List<Integer>) args.get("lobby"));
|
|
||||||
map.setDuration((int) args.get("duration"));
|
|
||||||
map.setMinPlayers((int) args.get("min-players"));
|
|
||||||
map.setMaxPlayers((int) args.get("max-players"));
|
|
||||||
map.setBlocks(((List<Map<String, Object>>) args.get("blocks")).stream().map(Block::fromMap).toList());
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return String.format("BlockAndSeekMap[spawn=%s, lobby=%s, duration=%s, minPlayers=%s, maxPlayers=%s, blocks=%s]", spawn, lobby, duration, minPlayers, maxPlayers, blocks);
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum MapStatus {
|
|
||||||
SPAWN_REQUIRED,
|
|
||||||
LOBBY_REQUIRED,
|
|
||||||
DURATION_REQUIRED,
|
|
||||||
BLOCKS_REQUIRED,
|
|
||||||
MIN_PLAYERS_REQUIRED,
|
|
||||||
MAX_PLAYERS_REQUIRED
|
|
||||||
}
|
|
||||||
|
|
||||||
public record Block(@NotNull ItemStack block, int chance) {
|
|
||||||
public Map<String, Object> toMap() {
|
|
||||||
Map<String, Object> map = new HashMap<>();
|
|
||||||
map.put("block", block.getType().name());
|
|
||||||
map.put("chance", chance);
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Block fromMap(Map<String, Object> map) {
|
|
||||||
return new Block(new ItemStack(Material.valueOf(((String) map.get("block")).toUpperCase())), (int) map.get("chance"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,31 +1,39 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.eventListeners.RequiredEventListener;
|
import hdvtdev.blockandseek.eventListeners.RequiredEventListener;
|
||||||
import hdvtdev.blockAndSeek.eventListeners.EventListener;
|
import hdvtdev.blockandseek.eventListeners.EventListener;
|
||||||
import hdvtdev.blockAndSeek.eventListeners.ForceControlEventListener;
|
import hdvtdev.blockandseek.eventListeners.ForceControlEventListener;
|
||||||
|
import hdvtdev.blockandseek.managers.*;
|
||||||
|
import hdvtdev.blockandseek.objects.*;
|
||||||
|
import hdvtdev.blockandseek.roulette.RouletteCreator;
|
||||||
|
|
||||||
import me.libraryaddict.disguise.LibsDisguises;
|
import me.libraryaddict.disguise.LibsDisguises;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|
||||||
|
import org.bukkit.*;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
import org.bukkit.command.PluginCommand;
|
import org.bukkit.command.PluginCommand;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.plugin.Plugin;
|
import org.bukkit.plugin.Plugin;
|
||||||
import org.bukkit.plugin.PluginManager;
|
import org.bukkit.plugin.PluginManager;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
import org.bukkit.potion.PotionEffectType;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import org.incendo.cloud.Command;
|
|
||||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||||
import org.incendo.cloud.bukkit.parser.PlayerParser;
|
import org.incendo.cloud.bukkit.parser.location.LocationParser;
|
||||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||||
import org.incendo.cloud.parser.standard.IntegerParser;
|
|
||||||
import org.incendo.cloud.parser.standard.StringParser;
|
import org.incendo.cloud.parser.standard.StringParser;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.*;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class BlockAndSeek extends JavaPlugin {
|
public class BlockAndSeek extends JavaPlugin {
|
||||||
|
|
||||||
@@ -66,17 +74,13 @@ public class BlockAndSeek extends JavaPlugin {
|
|||||||
|
|
||||||
this.init();
|
this.init();
|
||||||
|
|
||||||
if (!Config.loadConfig()) getPluginLogger().warning("Failed to load BlockAndSeek config.toml! Using default config...");
|
|
||||||
|
|
||||||
|
|
||||||
PluginCommand command = Objects.requireNonNull(getCommand("blockandseek"));
|
PluginCommand command = Objects.requireNonNull(getCommand("blockandseek"));
|
||||||
|
|
||||||
|
|
||||||
PluginManager manager = getServer().getPluginManager();
|
PluginManager manager = getServer().getPluginManager();
|
||||||
manager.registerEvents(Config.forceControl() ? new ForceControlEventListener() : new EventListener(), this);
|
boolean forceControl = Config.forceControl();
|
||||||
|
if (forceControl) getLogger().info("Using force control");
|
||||||
|
manager.registerEvents(forceControl ? new ForceControlEventListener() : new EventListener(), this);
|
||||||
manager.registerEvents(new RequiredEventListener(), this);
|
manager.registerEvents(new RequiredEventListener(), this);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -105,6 +109,9 @@ public class BlockAndSeek extends JavaPlugin {
|
|||||||
saveResource("languages/en_US.yml", false);
|
saveResource("languages/en_US.yml", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MapsManager.loadMaps();
|
||||||
|
TranslationManager.loadLanguages();
|
||||||
|
|
||||||
commandManager = LegacyPaperCommandManager.createNative(
|
commandManager = LegacyPaperCommandManager.createNative(
|
||||||
this,
|
this,
|
||||||
ExecutionCoordinator.simpleCoordinator()
|
ExecutionCoordinator.simpleCoordinator()
|
||||||
@@ -130,53 +137,226 @@ public class BlockAndSeek extends JavaPlugin {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final PropManager propManager = new PropManager();
|
||||||
|
|
||||||
private void registerCommands() {
|
private void registerCommands() {
|
||||||
|
|
||||||
Command.Builder<CommandSender> root = commandManager.commandBuilder("blockandseek");
|
var root = commandManager.commandBuilder("blockandseek");
|
||||||
|
|
||||||
|
var editBase = root
|
||||||
|
.literal("editMap")
|
||||||
|
.required("map_name", StringParser.stringParser(), MapsManager.mapSuggestions);
|
||||||
|
|
||||||
|
//edit commands
|
||||||
|
|
||||||
|
|
||||||
|
commandManager.command(
|
||||||
|
editBase.literal("setLobby") // Это наш <parameter> как литерал
|
||||||
|
.required("location", LocationParser.locationParser())
|
||||||
|
.handler(ctx -> {
|
||||||
|
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
commandManager.command(
|
||||||
|
editBase.literal("setLocation")
|
||||||
|
.required("location", LocationParser.locationParser()) // Это <value>
|
||||||
|
.handler(ctx -> {
|
||||||
|
String configName = ctx.get("config_name");
|
||||||
|
Location location = ctx.get("location");
|
||||||
|
|
||||||
|
ctx.sender().sendMessage("В конфиге " + configName + " точка установлена: " + location.toString());
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
commandManager.command(root
|
||||||
|
.literal("maps")
|
||||||
|
.handler(ctx -> {
|
||||||
|
ctx.sender().sendMessage(MapsManager.getMaps().stream().map(BlockAndSeekMap::getWorld).collect(Collectors.joining(", ")));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
commandManager.command(root
|
||||||
|
.literal("testMessage")
|
||||||
|
.handler(ctx -> {
|
||||||
|
ctx.sender().sendMessage(MiniMessage.miniMessage().deserialize(" <gradient:#FFAA00:#FFD700><bold>System</bold></gradient> <dark_gray>»</dark_gray> <yellow>Ваш игровой режим изменен.</yellow>\n"));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
commandManager.command(root
|
||||||
|
.literal("menuTest")
|
||||||
|
.handler(ctx -> {
|
||||||
|
if (ctx.sender() instanceof Player player) {
|
||||||
|
player.getInventory().addItem(ItemManager.getMenuItem());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
commandManager.command(root
|
commandManager.command(root
|
||||||
.literal("reload")
|
.literal("localeTest")
|
||||||
|
.handler(ctx -> {
|
||||||
|
if (ctx.sender() instanceof Player player) {
|
||||||
|
player.sendMessage("Locale is: " + player.locale());
|
||||||
|
player.sendMessage(TranslationManager.get(player, TranslationKey.FREEZE_ITEM));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
commandManager.command(root
|
||||||
|
.literal("createGame")
|
||||||
.permission(perm)
|
.permission(perm)
|
||||||
|
.required("map_name", StringParser.stringParser(), MapsManager.mapSuggestions)
|
||||||
.handler(context -> {
|
.handler(context -> {
|
||||||
|
String name = context.get("map_name");
|
||||||
|
GamesManager.createGame(name);
|
||||||
|
if (context.sender() instanceof Player player) {
|
||||||
|
GamesManager.get(name).addPlayer(player);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
commandManager.command(root
|
commandManager.command(root
|
||||||
.literal("inttest")
|
.literal("createMap")
|
||||||
.required("text", IntegerParser.integerParser(0, 64))
|
|
||||||
|
|
||||||
.handler(context -> {
|
|
||||||
String text = context.get("text");
|
|
||||||
context.sender().sendMessage(text);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
commandManager.command(root
|
|
||||||
.literal("map")
|
|
||||||
.permission(perm)
|
.permission(perm)
|
||||||
.required("map", StringParser.stringParser())
|
.required("map_name", StringParser.stringParser(), MapsManager.worldSuggestions)
|
||||||
.required("action", StringParser.stringParser())
|
|
||||||
.handler(context -> {
|
.handler(context -> {
|
||||||
Player target = context.get("target");
|
String name = context.get("map_name");
|
||||||
int amount = context.getOrDefault("amount", 1);
|
MapsManager.createMap(name);
|
||||||
|
context.sender().sendMessage("Map probably created");
|
||||||
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
commandManager.command(root
|
||||||
|
.literal("joinGame")
|
||||||
|
.permission(perm)
|
||||||
|
.required("name", StringParser.stringParser())
|
||||||
|
.handler(context -> {
|
||||||
|
String name = context.get("name");
|
||||||
|
if (context.sender() instanceof Player player) {
|
||||||
|
BlockAndSeekGame game = GamesManager.get(name);
|
||||||
|
if (game != null) game.addPlayer(player);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
commandManager.command(
|
||||||
|
editBase.literal("generateBlocks")
|
||||||
|
.handler(ctx -> {
|
||||||
|
if (ctx.sender() instanceof Player player) {
|
||||||
|
|
||||||
|
String mapName = ctx.get("map_name");
|
||||||
|
BlockAndSeekMap map = MapsManager.getMap(mapName);
|
||||||
|
|
||||||
|
var cached = BlocksGenerator.get(map.getSpawn().getWorld().getName());
|
||||||
|
|
||||||
|
if (cached != null) {
|
||||||
|
new RouletteCreator(player, cached);
|
||||||
|
} else {
|
||||||
|
BlocksGenerator.getSortedBlockStats(player.getLocation(), 32, (var list) -> {
|
||||||
|
|
||||||
|
List<Map.Entry<Material, Long>> selectedBlocks = new ArrayList<>(list);
|
||||||
|
|
||||||
|
// 2. Перемешиваем и берем 30 случайных (или меньше, если всего блоков меньше 30)
|
||||||
|
Collections.shuffle(selectedBlocks);
|
||||||
|
if (selectedBlocks.size() > 30) {
|
||||||
|
selectedBlocks = selectedBlocks.subList(0, 30);
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedBlocks.sort((a, b) -> Long.compare(b.getValue(), a.getValue()));
|
||||||
|
|
||||||
|
List<Map.Entry<Material, Rarity>> result = new ArrayList<>();
|
||||||
|
|
||||||
|
// 4. Считаем общий вес редкостей (100 + 50 + 25 + ...) = 189
|
||||||
|
int totalWeight = Arrays.stream(Rarity.values()).mapToInt(Rarity::getChance).sum();
|
||||||
|
|
||||||
|
// Шаг веса на один блок.
|
||||||
|
// Представь длинную полоску длиной 189 единиц. Мы режем её на 30 равных частей.
|
||||||
|
// Куда попадает разрез — такая и редкость.
|
||||||
|
double weightStep = (double) totalWeight / selectedBlocks.size();
|
||||||
|
|
||||||
|
double currentWeightPosition = 0; // Текущая позиция на шкале весов
|
||||||
|
|
||||||
|
// Идем по отсортированному списку (от самых частых к самым редким)
|
||||||
|
for (Map.Entry<Material, Long> entry : selectedBlocks) {
|
||||||
|
|
||||||
|
// Определяем, в какой диапазон редкости попадает текущий блок
|
||||||
|
Rarity assignedRarity = Rarity.COMMON; // Дефолт
|
||||||
|
|
||||||
|
int weightCursor = 0;
|
||||||
|
for (Rarity r : Rarity.values()) {
|
||||||
|
weightCursor += r.getChance();
|
||||||
|
// Если текущая позиция веса меньше границы этой редкости — мы нашли её
|
||||||
|
// (Добавляем половину шага, чтобы брать "центр" диапазона блока для точности)
|
||||||
|
if ((currentWeightPosition + weightStep / 2) <= weightCursor) {
|
||||||
|
assignedRarity = r;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.add(new AbstractMap.SimpleEntry<>(entry.getKey(), assignedRarity));
|
||||||
|
|
||||||
|
// Сдвигаемся дальше по шкале
|
||||||
|
currentWeightPosition += weightStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var r = result.stream().map(e -> new PropBlock(new ItemStack(e.getKey()), e.getValue())).toList();
|
||||||
|
map.setBlocks(r);
|
||||||
|
|
||||||
|
map.save();
|
||||||
|
BlocksGenerator.addCache(player.getLocation().getWorld().getName(), r);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void spawnSmokeCloud(Location center) {
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
int ticksPassed = 0;
|
||||||
|
|
||||||
|
final int maxIterations = (10 * 20) / 5;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (ticksPassed >= maxIterations) {
|
||||||
|
this.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
World world = center.getWorld();
|
||||||
|
if (world == null) return;
|
||||||
|
|
||||||
|
|
||||||
|
world.spawnParticle(Particle.EXPLOSION_HUGE, center, 15, 1.2, 1.2, 1.2, 0.05);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (var entity : world.getNearbyEntities(center, 2.5, 2.5, 2.5)) {
|
||||||
|
if (entity instanceof Player player && player.getLocation().distanceSquared(center) <= 9) {
|
||||||
|
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ticksPassed++;
|
||||||
|
}
|
||||||
|
}.runTaskTimer(this, 0L, 5L);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,50 +1,191 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.objects.PropBlock;
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
import org.bukkit.block.data.AnaloguePowerable;
|
import org.bukkit.block.Banner;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.Comparator;
|
||||||
import org.bukkit.block.data.Openable;
|
import org.bukkit.block.data.*;
|
||||||
import org.bukkit.block.data.Powerable;
|
import org.bukkit.block.data.type.Observer;
|
||||||
|
import org.bukkit.block.data.type.Piston;
|
||||||
|
import org.bukkit.block.data.type.RedstoneWire;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import java.util.HashMap;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@ApiStatus.Experimental
|
@ApiStatus.Experimental
|
||||||
public class BlocksGenerator {
|
public class BlocksGenerator {
|
||||||
|
|
||||||
private static boolean isSupported(Material type, BlockData data) {
|
private static final Set<Material> BLACKLIST = EnumSet.noneOf(Material.class);
|
||||||
|
private static final Map<String, List<PropBlock>> cached = new HashMap<>();
|
||||||
|
|
||||||
if (type.isAir() || type.hasGravity() || !type.isSolid()) {
|
static {
|
||||||
|
// --- 1. ГРАВИТАЦИЯ (Сыпучие) ---
|
||||||
|
BLACKLIST.add(Material.SAND);
|
||||||
|
BLACKLIST.add(Material.RED_SAND);
|
||||||
|
BLACKLIST.add(Material.GRAVEL);
|
||||||
|
BLACKLIST.add(Material.DRAGON_EGG);
|
||||||
|
BLACKLIST.add(Material.ANVIL);
|
||||||
|
BLACKLIST.add(Material.CHIPPED_ANVIL);
|
||||||
|
BLACKLIST.add(Material.DAMAGED_ANVIL);
|
||||||
|
BLACKLIST.add(Material.POINTED_DRIPSTONE); // Сталактит (может упасть)
|
||||||
|
BLACKLIST.add(Material.SCAFFOLDING); // Строительные леса
|
||||||
|
|
||||||
|
// --- 2. РЕДСТОУН И МЕХАНИЗМЫ ---
|
||||||
|
BLACKLIST.addAll(Tag.BUTTONS.getValues()); // Все кнопки
|
||||||
|
BLACKLIST.addAll(Tag.PRESSURE_PLATES.getValues()); // Все нажимные плиты
|
||||||
|
BLACKLIST.addAll(Tag.DOORS.getValues()); // Двери
|
||||||
|
BLACKLIST.addAll(Tag.TRAPDOORS.getValues()); // Люки
|
||||||
|
BLACKLIST.addAll(Tag.FENCE_GATES.getValues()); // Калитки
|
||||||
|
BLACKLIST.addAll(Tag.RAILS.getValues()); // Рельсы
|
||||||
|
|
||||||
|
BLACKLIST.add(Material.REDSTONE_WIRE);
|
||||||
|
BLACKLIST.add(Material.REDSTONE_TORCH);
|
||||||
|
BLACKLIST.add(Material.REDSTONE_BLOCK); // Если не нужен блок редстоуна
|
||||||
|
BLACKLIST.add(Material.REPEATER);
|
||||||
|
BLACKLIST.add(Material.COMPARATOR);
|
||||||
|
BLACKLIST.add(Material.OBSERVER);
|
||||||
|
BLACKLIST.add(Material.PISTON);
|
||||||
|
BLACKLIST.add(Material.STICKY_PISTON);
|
||||||
|
BLACKLIST.add(Material.PISTON_HEAD);
|
||||||
|
BLACKLIST.add(Material.MOVING_PISTON);
|
||||||
|
BLACKLIST.add(Material.DISPENSER);
|
||||||
|
BLACKLIST.add(Material.DROPPER);
|
||||||
|
BLACKLIST.add(Material.HOPPER);
|
||||||
|
BLACKLIST.add(Material.DAYLIGHT_DETECTOR);
|
||||||
|
BLACKLIST.add(Material.TRIPWIRE);
|
||||||
|
BLACKLIST.add(Material.TRIPWIRE_HOOK);
|
||||||
|
BLACKLIST.add(Material.LEVER);
|
||||||
|
BLACKLIST.add(Material.TNT);
|
||||||
|
BLACKLIST.add(Material.NOTE_BLOCK);
|
||||||
|
BLACKLIST.add(Material.JUKEBOX);
|
||||||
|
BLACKLIST.add(Material.SCULK_SENSOR);
|
||||||
|
BLACKLIST.add(Material.SCULK_SHRIEKER);
|
||||||
|
BLACKLIST.add(Material.SCULK_CATALYST);
|
||||||
|
BLACKLIST.add(Material.COMMAND_BLOCK);
|
||||||
|
BLACKLIST.add(Material.REPEATING_COMMAND_BLOCK);
|
||||||
|
BLACKLIST.add(Material.CHAIN_COMMAND_BLOCK);
|
||||||
|
BLACKLIST.add(Material.LIGHTNING_ROD);
|
||||||
|
BLACKLIST.add(Material.BELL); // Колокол
|
||||||
|
|
||||||
|
// --- 3. ХРУПКИЕ / ЗАВИСЯЩИЕ ОТ ОПОРЫ (Растения, декор) ---
|
||||||
|
BLACKLIST.addAll(Tag.SAPLINGS.getValues()); // Саженцы
|
||||||
|
BLACKLIST.addAll(Tag.FLOWERS.getValues()); // Цветы
|
||||||
|
BLACKLIST.addAll(Tag.CROPS.getValues()); // Пшеница, картошка и т.д.
|
||||||
|
BLACKLIST.addAll(Tag.BANNERS.getValues()); // Флаги (стоячие и настенные)
|
||||||
|
BLACKLIST.addAll(Tag.SIGNS.getValues()); // Таблички
|
||||||
|
BLACKLIST.addAll(Tag.BEDS.getValues()); // Кровати
|
||||||
|
BLACKLIST.addAll(Tag.CANDLES.getValues()); // Свечи
|
||||||
|
BLACKLIST.addAll(Tag.CAMPFIRES.getValues()); // Костры
|
||||||
|
BLACKLIST.addAll(Tag.CAULDRONS.getValues()); // Котлы
|
||||||
|
BLACKLIST.addAll(Tag.WOOL_CARPETS.getValues()); // Ковры
|
||||||
|
BLACKLIST.addAll(Tag.FLOWER_POTS.getValues()); // Горшки
|
||||||
|
|
||||||
|
BLACKLIST.add(Material.BROWN_MUSHROOM);
|
||||||
|
BLACKLIST.add(Material.RED_MUSHROOM);
|
||||||
|
BLACKLIST.add(Material.CRIMSON_FUNGUS);
|
||||||
|
BLACKLIST.add(Material.WARPED_FUNGUS);
|
||||||
|
BLACKLIST.add(Material.SUGAR_CANE);
|
||||||
|
BLACKLIST.add(Material.BAMBOO);
|
||||||
|
BLACKLIST.add(Material.BAMBOO_SAPLING);
|
||||||
|
BLACKLIST.add(Material.CACTUS);
|
||||||
|
BLACKLIST.add(Material.DEAD_BUSH);
|
||||||
|
BLACKLIST.add(Material.SWEET_BERRY_BUSH);
|
||||||
|
BLACKLIST.add(Material.PUMPKIN_STEM);
|
||||||
|
BLACKLIST.add(Material.MELON_STEM);
|
||||||
|
BLACKLIST.add(Material.NETHER_WART);
|
||||||
|
BLACKLIST.add(Material.CHORUS_PLANT);
|
||||||
|
BLACKLIST.add(Material.CHORUS_FLOWER);
|
||||||
|
BLACKLIST.add(Material.KELP);
|
||||||
|
BLACKLIST.add(Material.KELP_PLANT);
|
||||||
|
BLACKLIST.add(Material.SEAGRASS);
|
||||||
|
BLACKLIST.add(Material.TALL_SEAGRASS);
|
||||||
|
BLACKLIST.add(Material.VINE);
|
||||||
|
BLACKLIST.add(Material.WEEPING_VINES);
|
||||||
|
BLACKLIST.add(Material.TWISTING_VINES);
|
||||||
|
BLACKLIST.add(Material.LILY_PAD);
|
||||||
|
BLACKLIST.add(Material.SMALL_DRIPLEAF);
|
||||||
|
BLACKLIST.add(Material.BIG_DRIPLEAF);
|
||||||
|
BLACKLIST.add(Material.SPORE_BLOSSOM);
|
||||||
|
BLACKLIST.add(Material.HANGING_ROOTS);
|
||||||
|
BLACKLIST.add(Material.GLOW_LICHEN);
|
||||||
|
BLACKLIST.add(Material.AMETHYST_CLUSTER);
|
||||||
|
BLACKLIST.add(Material.SMALL_AMETHYST_BUD);
|
||||||
|
BLACKLIST.add(Material.MEDIUM_AMETHYST_BUD);
|
||||||
|
BLACKLIST.add(Material.LARGE_AMETHYST_BUD);
|
||||||
|
BLACKLIST.add(Material.POINTED_DRIPSTONE);
|
||||||
|
BLACKLIST.add(Material.COCOA);
|
||||||
|
|
||||||
|
BLACKLIST.add(Material.TORCH);
|
||||||
|
BLACKLIST.add(Material.SOUL_TORCH);
|
||||||
|
BLACKLIST.add(Material.LANTERN);
|
||||||
|
BLACKLIST.add(Material.SOUL_LANTERN);
|
||||||
|
BLACKLIST.add(Material.CHAIN);
|
||||||
|
BLACKLIST.add(Material.END_ROD);
|
||||||
|
BLACKLIST.add(Material.IRON_BARS); // Обычно некрасиво в топах
|
||||||
|
BLACKLIST.add(Material.LADDER);
|
||||||
|
BLACKLIST.add(Material.SNOW); // Снежный покров (тонкий)
|
||||||
|
BLACKLIST.add(Material.TURTLE_EGG);
|
||||||
|
BLACKLIST.add(Material.CAKE);
|
||||||
|
|
||||||
|
// --- 4. КОНТЕЙНЕРЫ (Если не хочешь, чтобы выпадали сундуки) ---
|
||||||
|
BLACKLIST.add(Material.CHEST);
|
||||||
|
BLACKLIST.add(Material.TRAPPED_CHEST);
|
||||||
|
BLACKLIST.add(Material.ENDER_CHEST);
|
||||||
|
BLACKLIST.add(Material.BARREL);
|
||||||
|
BLACKLIST.add(Material.FURNACE);
|
||||||
|
BLACKLIST.add(Material.BLAST_FURNACE);
|
||||||
|
BLACKLIST.add(Material.SMOKER);
|
||||||
|
BLACKLIST.add(Material.BREWING_STAND);
|
||||||
|
BLACKLIST.add(Material.LECTERN);
|
||||||
|
BLACKLIST.add(Material.COMPOSTER);
|
||||||
|
BLACKLIST.add(Material.BEEHIVE);
|
||||||
|
BLACKLIST.add(Material.BEE_NEST);
|
||||||
|
|
||||||
|
// --- 5. ТЕХНИЧЕСКИЕ И ПРОЗРАЧНЫЕ ---
|
||||||
|
BLACKLIST.add(Material.BARRIER);
|
||||||
|
BLACKLIST.add(Material.STRUCTURE_VOID);
|
||||||
|
BLACKLIST.add(Material.STRUCTURE_BLOCK);
|
||||||
|
BLACKLIST.add(Material.JIGSAW);
|
||||||
|
BLACKLIST.add(Material.LIGHT);
|
||||||
|
BLACKLIST.add(Material.SPAWNER);
|
||||||
|
BLACKLIST.add(Material.COBWEB);
|
||||||
|
BLACKLIST.add(Material.SLIME_BLOCK); // Спорно, но липкий
|
||||||
|
BLACKLIST.add(Material.HONEY_BLOCK);
|
||||||
|
|
||||||
|
// --- 6. ЗАЧИСТКА ПО ИМЕНАМ (На всякий случай) ---
|
||||||
|
// Добавляем все, что мы могли забыть, но что имеет общие корни
|
||||||
|
for (Material m : Material.values()) {
|
||||||
|
String name = m.name();
|
||||||
|
if (name.contains("POTTED") || // Горшки с цветами
|
||||||
|
name.contains("WALL_") || // Настенные варианты (факелы, знаки)
|
||||||
|
name.contains("HEAD") || // Головы
|
||||||
|
name.contains("SKULL") || // Черепа
|
||||||
|
name.contains("BANNER") || // Флаги (дублируем для надежности)
|
||||||
|
name.contains("CORAL") // Кораллы (дохнут без воды)
|
||||||
|
) {
|
||||||
|
BLACKLIST.add(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Твой метод проверки стал очень простым
|
||||||
|
private static boolean isSupported(Material type) {
|
||||||
|
// 1. Воздух
|
||||||
|
if (type.isAir()) return false;
|
||||||
|
|
||||||
|
// 2. Черный список (самая надежная проверка)
|
||||||
|
if (BLACKLIST.contains(type)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data instanceof Powerable
|
// 3. Дополнительная защита: блок должен быть твердым
|
||||||
|| data instanceof Openable
|
// (Это отсечет то, что мы могли случайно забыть в списке, типа нитки/String)
|
||||||
|| data instanceof AnaloguePowerable) {
|
return type.isSolid();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return switch (type) {
|
|
||||||
case CACTUS, FARMLAND,
|
|
||||||
TNT, DISPENSER, DROPPER, HOPPER,
|
|
||||||
PISTON, STICKY_PISTON, OBSERVER,
|
|
||||||
COMMAND_BLOCK, REPEATING_COMMAND_BLOCK,
|
|
||||||
CHAIN_COMMAND_BLOCK,
|
|
||||||
SCULK_SENSOR, SCULK_SHRIEKER,
|
|
||||||
DAYLIGHT_DETECTOR, JUKEBOX,
|
|
||||||
TURTLE_EGG, DRAGON_EGG,
|
|
||||||
BAMBOO, BAMBOO_SAPLING,
|
|
||||||
CAKE, LECTERN, COMPOSTER,
|
|
||||||
CAMPFIRE, SOUL_CAMPFIRE,
|
|
||||||
BEEHIVE, BEE_NEST
|
|
||||||
-> false;
|
|
||||||
default -> true;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void getSortedBlockStats(Location center, int chunkRadius, Consumer<List<Map.Entry<Material, Long>>> callback) {
|
public static void getSortedBlockStats(Location center, int chunkRadius, Consumer<List<Map.Entry<Material, Long>>> callback) {
|
||||||
@@ -81,11 +222,10 @@ public class BlocksGenerator {
|
|||||||
for (int z = 0; z < 16; z++) {
|
for (int z = 0; z < 16; z++) {
|
||||||
for (int y = minH; y < maxH; y++) {
|
for (int y = minH; y < maxH; y++) {
|
||||||
|
|
||||||
|
|
||||||
BlockData data = snap.getBlockData(x, y, z);
|
BlockData data = snap.getBlockData(x, y, z);
|
||||||
Material type = data.getMaterial();
|
Material type = data.getMaterial();
|
||||||
|
|
||||||
if (isSupported(type, data)) {
|
if (isSupported(type)) {
|
||||||
counts.put(type, counts.getOrDefault(type, 0L) + 1);
|
counts.put(type, counts.getOrDefault(type, 0L) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,12 +233,9 @@ public class BlocksGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
List<Map.Entry<Material, Long>> sortedList = new ArrayList<>(counts.entrySet());
|
List<Map.Entry<Material, Long>> sortedList = new ArrayList<>(counts.entrySet());
|
||||||
sortedList.sort(Map.Entry.comparingByValue());
|
sortedList.sort(Map.Entry.comparingByValue());
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
new BukkitRunnable() {
|
new BukkitRunnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@@ -109,5 +246,21 @@ public class BlocksGenerator {
|
|||||||
}.runTaskAsynchronously(BlockAndSeek.getInstance());
|
}.runTaskAsynchronously(BlockAndSeek.getInstance());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void addCache(String key, List<PropBlock> propBlocks) {
|
||||||
|
cached.put(key, propBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static List<PropBlock> get(String key) {
|
||||||
|
return cached.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static PropBlock getRandom(String key) {
|
||||||
|
List<PropBlock> propBlocks = get(key);
|
||||||
|
return propBlocks == null ? null : propBlocks.get(random.nextInt(0, propBlocks.size()));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
|
||||||
|
|
||||||
import org.bukkit.command.Command;
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.command.TabExecutor;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class CommandListener implements TabExecutor {
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public @Nullable List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
import eu.okaeri.configs.ConfigManager;
|
import eu.okaeri.configs.ConfigManager;
|
||||||
import eu.okaeri.configs.OkaeriConfig;
|
import eu.okaeri.configs.OkaeriConfig;
|
||||||
@@ -8,22 +8,43 @@ import eu.okaeri.configs.serdes.commons.SerdesCommons;
|
|||||||
import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer;
|
import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer;
|
||||||
import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit;
|
import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit;
|
||||||
|
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.WorldCreator;
|
import org.bukkit.WorldCreator;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public class Config extends OkaeriConfig {
|
public class Config extends OkaeriConfig {
|
||||||
|
|
||||||
@Exclude
|
@Exclude
|
||||||
private static final AtomicReference<Config> config = new AtomicReference<>(new Config());
|
private static Config config;
|
||||||
|
|
||||||
|
static {
|
||||||
|
try {
|
||||||
|
File configFile = new File(BlockAndSeek.getPluginDataFolder(), "config.yml");
|
||||||
|
if (!configFile.exists()) configFile.createNewFile();
|
||||||
|
config = ConfigManager.create(Config.class, (it) -> {
|
||||||
|
it.withConfigurer(
|
||||||
|
new YamlBukkitConfigurer(),
|
||||||
|
new SerdesBukkit(),
|
||||||
|
new SerdesCommons()
|
||||||
|
);
|
||||||
|
it.withBindFile(configFile);
|
||||||
|
it.withLogger(BlockAndSeek.getPluginLogger());
|
||||||
|
it.saveDefaults();
|
||||||
|
});
|
||||||
|
|
||||||
|
config.load();
|
||||||
|
config.save();
|
||||||
|
} catch (Exception e) {
|
||||||
|
BlockAndSeek.getPluginLogger().severe("Failed to load config.yml: " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Comment("Server options.")
|
@Comment("Server options.")
|
||||||
private Server server = new Server(false);
|
private ServerSettings serverSettings = new ServerSettings();
|
||||||
@Comment("Spawn location. Useless if the Server.forceControl is false.")
|
@Comment("Spawn location. Useless if the Server.forceControl is false.")
|
||||||
private Location spawn = Objects.requireNonNull(Bukkit.createWorld(new WorldCreator("world"))).getSpawnLocation();
|
private Location spawn = Objects.requireNonNull(Bukkit.createWorld(new WorldCreator("world"))).getSpawnLocation();
|
||||||
@Comment("Show hidden BlockAndSeek commands.")
|
@Comment("Show hidden BlockAndSeek commands.")
|
||||||
@@ -31,50 +52,23 @@ public class Config extends OkaeriConfig {
|
|||||||
|
|
||||||
|
|
||||||
public static boolean debugEnabled() {
|
public static boolean debugEnabled() {
|
||||||
return config.get().enableDebugCommands;
|
return config.enableDebugCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean forceControl() {
|
public static boolean forceControl() {
|
||||||
return config.get().server.forceControl;
|
return config.serverSettings.forceControl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Location spawn() {
|
public static Location spawn() {
|
||||||
return config.get().spawn;
|
return config.spawn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toStaticString() {
|
||||||
public static boolean loadConfig() {
|
return String.format("BlockAndSeekConfig[forceControl = %s, spawn = %s, enableDebugCommands = %s]", forceControl(), spawn(), debugEnabled());
|
||||||
try {
|
|
||||||
Config conf = ConfigManager.create(Config.class, (it) -> {
|
|
||||||
it.withConfigurer(
|
|
||||||
new YamlBukkitConfigurer(),
|
|
||||||
new SerdesBukkit(),
|
|
||||||
new SerdesCommons()
|
|
||||||
);
|
|
||||||
it.withBindFile(new File(BlockAndSeek.getPluginDataFolder(), "config.yml"));
|
|
||||||
it.withLogger(BlockAndSeek.getPluginLogger());
|
|
||||||
it.saveDefaults();
|
|
||||||
});
|
|
||||||
|
|
||||||
config.setRelease(conf);
|
|
||||||
} catch (Exception e) {
|
|
||||||
BlockAndSeek.getPluginLogger().severe("Failed to load config.yml: " + e.getMessage());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Server {
|
private static class ServerSettings extends OkaeriConfig {
|
||||||
|
|
||||||
private boolean forceControl = false;
|
private boolean forceControl = false;
|
||||||
|
|
||||||
public Server(boolean forceControl) {
|
|
||||||
this.forceControl = forceControl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isForceControl() {
|
|
||||||
return forceControl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.NamespacedKey;
|
import org.bukkit.NamespacedKey;
|
||||||
@@ -8,21 +8,11 @@ import org.bukkit.scoreboard.Team;
|
|||||||
public class Keys {
|
public class Keys {
|
||||||
|
|
||||||
public static final NamespacedKey SOUND_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSoundItem");
|
public static final NamespacedKey SOUND_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSoundItem");
|
||||||
|
public static final NamespacedKey DASH_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekDashItem");
|
||||||
public static final NamespacedKey FREEZE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFreezeItem");
|
public static final NamespacedKey FREEZE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFreezeItem");
|
||||||
public static final NamespacedKey FACE_CHANGING_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFaceChangingItem");
|
public static final NamespacedKey FACE_CHANGING_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFaceChangingItem");
|
||||||
public static final NamespacedKey MENU_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekMenuItem");
|
public static final NamespacedKey MENU_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekMenuItem");
|
||||||
public static final NamespacedKey LEAVE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLeaveItem");
|
public static final NamespacedKey LEAVE_ITEM = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLeaveItem");
|
||||||
public static final NamespacedKey GAME_PAGE = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekGamePage");
|
|
||||||
|
|
||||||
public static final NamespacedKey FROZEN_PLAYER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekFrozenPlayer");
|
|
||||||
public static final NamespacedKey GAME = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekGame");
|
|
||||||
|
|
||||||
public static final NamespacedKey HIDER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekHider");
|
|
||||||
public static final NamespacedKey SEEKER = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekSeeker");
|
|
||||||
|
|
||||||
public static final NamespacedKey LANG_KEY = new NamespacedKey(BlockAndSeek.getInstance(), "BlockAndSeekLangKey");
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public static final Team NO_COLLIDE_TEAM;
|
public static final Team NO_COLLIDE_TEAM;
|
||||||
|
|
||||||
@@ -32,7 +22,5 @@ public class Keys {
|
|||||||
if (team == null) team = scoreboard.registerNewTeam("BlockAndSeekNoCollide");
|
if (team == null) team = scoreboard.registerNewTeam("BlockAndSeekNoCollide");
|
||||||
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
|
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
|
||||||
NO_COLLIDE_TEAM = team;
|
NO_COLLIDE_TEAM = team;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.inventory.meta.ItemMeta;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
public final class Localization {
|
|
||||||
|
|
||||||
private Localization() {}
|
|
||||||
|
|
||||||
private static final String defaultLanguage = "en_US";
|
|
||||||
private static final MiniMessage mm = MiniMessage.miniMessage();
|
|
||||||
|
|
||||||
private static final AtomicReference<Map<String, Map<String, String>>> translations = new AtomicReference<>();
|
|
||||||
|
|
||||||
public static Component get(Player player, String key, String... placeholders) {
|
|
||||||
return get(player.locale().toString(), key, placeholders);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Component get(String lang, String key, String... placeholders) {
|
|
||||||
String raw = translations.get().get(lang).getOrDefault(key, "?" + key + "?");
|
|
||||||
if (placeholders.length % 2 == 0) {
|
|
||||||
for (int i = 0; i < placeholders.length; i++) {
|
|
||||||
raw = raw.replace(placeholders[i], placeholders[++i]);
|
|
||||||
}
|
|
||||||
} else BlockAndSeek.getPluginLogger().warning("Wrong amount of placeholders for key: " + key);
|
|
||||||
|
|
||||||
return mm.deserialize(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack translateItem(Player player, ItemStack itemStack, String key) {
|
|
||||||
ItemMeta itemMeta = itemStack.getItemMeta();
|
|
||||||
itemMeta.displayName(get(player, key));
|
|
||||||
itemStack.setItemMeta(itemMeta);
|
|
||||||
return itemStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean loadTranslations() {
|
|
||||||
/*
|
|
||||||
Path path = BlockAndSeek.getPluginDataFolder().toPath().resolve("translations");
|
|
||||||
if (Files.notExists(path)) {
|
|
||||||
try {
|
|
||||||
Files.createDirectories(path);
|
|
||||||
} catch (IOException e) {
|
|
||||||
BlockAndSeek.getPluginLogger().severe("Failed to create \"translations\" dir: " + e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File[] files = path.toFile().listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File file : files) {
|
|
||||||
String lang = file.getName().split(".toml")[0];
|
|
||||||
Map<String, String> translation = new HashMap<>();
|
|
||||||
for (Map.Entry<String, Object> entry : new Toml().read(file).entrySet()) {
|
|
||||||
translation.put(entry.getKey(), entry.getValue().toString());
|
|
||||||
}
|
|
||||||
translations.get().put(lang, translation);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
BlockAndSeek.getPluginLogger().severe("Failed to load translations! " + path + " returned null.");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,12 @@
|
|||||||
package hdvtdev.blockAndSeek;
|
package hdvtdev.blockandseek;
|
||||||
|
|
||||||
|
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
import me.libraryaddict.disguise.disguisetypes.Disguise;
|
import org.bukkit.GameMode;
|
||||||
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
import org.bukkit.attribute.Attribute;
|
||||||
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
|
||||||
|
|
||||||
import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.block.data.BlockData;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
|
||||||
import org.bukkit.persistence.PersistentDataContainer;
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.bukkit.potion.PotionEffect;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
public final class Utils {
|
public final class Utils {
|
||||||
|
|
||||||
@@ -26,26 +18,38 @@ public final class Utils {
|
|||||||
p.setExp(0.9998f * ((float) level / 100));
|
p.setExp(0.9998f * ((float) level / 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isInOneTeam(Player p1, Player p2) {
|
public static void clearPlayer(Player player) {
|
||||||
var c1 = p1.getPersistentDataContainer();
|
|
||||||
var c2 = p2.getPersistentDataContainer();
|
|
||||||
return (c1.has(Keys.HIDER) && c2.has(Keys.HIDER)) || (c1.has(Keys.SEEKER) && c2.has(Keys.SEEKER));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean playerInGame(Player player) {
|
DisguiseAPI.undisguiseToAll(player);
|
||||||
return player.getPersistentDataContainer().has(Keys.GAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean hasPermsToDamage(Player p1, Player p2) {
|
player.getInventory().clear();
|
||||||
PersistentDataContainer c1 = p1.getPersistentDataContainer();
|
player.getInventory().setArmorContents(null);
|
||||||
PersistentDataContainer c2 = p2.getPersistentDataContainer();
|
player.getInventory().setExtraContents(null);
|
||||||
return (c1.has(Keys.SEEKER) || c1.has(Keys.HIDER)) && (c2.has(Keys.SEEKER) || c2.has(Keys.HIDER));
|
|
||||||
}
|
|
||||||
|
player.setGameMode(GameMode.SURVIVAL);
|
||||||
|
|
||||||
|
if (player.getAttribute(Attribute.GENERIC_MAX_HEALTH) != null) {
|
||||||
|
player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(20.0);
|
||||||
|
}
|
||||||
|
player.setHealth(20.0);
|
||||||
|
|
||||||
|
player.setFoodLevel(20);
|
||||||
|
player.setSaturation(5.0f);
|
||||||
|
player.setExhaustion(0f);
|
||||||
|
player.setInvulnerable(false);
|
||||||
|
player.setLevel(0);
|
||||||
|
player.setExp(0f);
|
||||||
|
player.setFireTicks(0);
|
||||||
|
player.setFallDistance(0f);
|
||||||
|
player.setWalkSpeed(0.2f);
|
||||||
|
player.setFlySpeed(0.1f);
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
player.setFlying(false);
|
||||||
|
player.setGliding(false);
|
||||||
|
player.setGlowing(false);
|
||||||
|
player.closeInventory();
|
||||||
|
|
||||||
public static void clearPlayer(Player p) {
|
|
||||||
PersistentDataContainer container = p.getPersistentDataContainer();
|
|
||||||
container.remove(Keys.SEEKER);
|
|
||||||
container.remove(Keys.HIDER);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package hdvtdev.blockAndSeek.eventListeners;
|
package hdvtdev.blockandseek.eventListeners;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.Keys;
|
import hdvtdev.blockandseek.Keys;
|
||||||
import hdvtdev.blockAndSeek.Utils;
|
import hdvtdev.blockandseek.Utils;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@@ -14,25 +14,22 @@ public class EventListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onDrop(PlayerDropItemEvent event) {
|
public void onDrop(PlayerDropItemEvent event) {
|
||||||
if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||||
if (event.getEntity() instanceof Player player && Utils.playerInGame(player)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
event.getEntity().setFoodLevel(20);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockPlacement(BlockPlaceEvent event) {
|
public void onBlockPlacement(BlockPlaceEvent event) {
|
||||||
if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
if (event.getPlayer().getPersistentDataContainer().has(Keys.GAME)) event.setCancelled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package hdvtdev.blockAndSeek.eventListeners;
|
package hdvtdev.blockandseek.eventListeners;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.Utils;
|
import hdvtdev.blockandseek.Config;
|
||||||
import hdvtdev.blockAndSeek.managers.ItemManager;
|
import hdvtdev.blockandseek.Utils;
|
||||||
|
import hdvtdev.blockandseek.managers.ItemManager;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.EventPriority;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.block.BlockBreakEvent;
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
import org.bukkit.event.block.BlockPlaceEvent;
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
@@ -21,6 +23,9 @@ public class ForceControlEventListener implements Listener {
|
|||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||||
Player player = event.getPlayer();
|
Player player = event.getPlayer();
|
||||||
|
player.teleport(Config.spawn());
|
||||||
|
Utils.clearPlayer(player);
|
||||||
|
player.setInvulnerable(true);
|
||||||
ItemManager.defaultInventory(player);
|
ItemManager.defaultInventory(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,17 +39,17 @@ public class ForceControlEventListener implements Listener {
|
|||||||
if (event.getSkipReason() != TimeSkipEvent.SkipReason.COMMAND) event.setCancelled(true);
|
if (event.getSkipReason() != TimeSkipEvent.SkipReason.COMMAND) event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onBlockPlacement(BlockPlaceEvent event) {
|
public void onBlockPlacement(BlockPlaceEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onBlockBreak(BlockBreakEvent event) {
|
public void onBlockBreak(BlockBreakEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||||
if (event.getEntity() instanceof Player player) {
|
if (event.getEntity() instanceof Player player) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
@@ -52,22 +57,12 @@ public class ForceControlEventListener implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onDrop(PlayerDropItemEvent event) {
|
public void onDrop(PlayerDropItemEvent event) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler(ignoreCancelled = true)
|
||||||
public void onPlayerDamage(EntityDamageByEntityEvent event) {
|
|
||||||
|
|
||||||
if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) {
|
|
||||||
if (!Utils.hasPermsToDamage(damager, victim)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onFallDamage(EntityDamageEvent e) {
|
public void onFallDamage(EntityDamageEvent e) {
|
||||||
if (e.getEntity() instanceof Player) {
|
if (e.getEntity() instanceof Player) {
|
||||||
if (e.getCause() == EntityDamageEvent.DamageCause.FALL) {
|
if (e.getCause() == EntityDamageEvent.DamageCause.FALL) {
|
||||||
|
|||||||
@@ -1,8 +1,15 @@
|
|||||||
package hdvtdev.blockAndSeek.eventListeners;
|
package hdvtdev.blockandseek.eventListeners;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.Keys;
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
import hdvtdev.blockAndSeek.Utils;
|
import hdvtdev.blockandseek.Keys;
|
||||||
import hdvtdev.blockAndSeek.GuiHolder;
|
import hdvtdev.blockandseek.Utils;
|
||||||
|
import hdvtdev.blockandseek.GuiHolder;
|
||||||
|
import hdvtdev.blockandseek.managers.PropManager;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.menus.GamesMenu;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
@@ -16,10 +23,17 @@ import org.bukkit.event.inventory.InventoryCloseEvent;
|
|||||||
import org.bukkit.event.player.PlayerInteractEvent;
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.event.server.ServerLoadEvent;
|
||||||
import org.bukkit.inventory.EquipmentSlot;
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
import static hdvtdev.blockAndSeek.Utils.isInOneTeam;
|
|
||||||
|
|
||||||
public class RequiredEventListener implements Listener {
|
public class RequiredEventListener implements Listener {
|
||||||
|
|
||||||
@@ -34,9 +48,36 @@ public class RequiredEventListener implements Listener {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//todo remove
|
||||||
|
private final PropManager propManager = new PropManager();
|
||||||
|
private final Set<UUID> coolDown = new HashSet<>();
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onRightClick(PlayerInteractEvent event) {
|
public void onRightClick(PlayerInteractEvent event) {
|
||||||
if (event.getHand() != EquipmentSlot.HAND) return;
|
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||||
|
if (event.getAction().isLeftClick()) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
|
||||||
|
ItemStack item = event.getItem();
|
||||||
|
if (item != null) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
PersistentDataContainer dataContainer = meta.getPersistentDataContainer();
|
||||||
|
if (dataContainer.has(Keys.MENU_ITEM)) {
|
||||||
|
new GamesMenu(player);
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,21 +119,7 @@ public class RequiredEventListener implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onPlayerDamage(EntityDamageByEntityEvent event) {
|
public void onPlayerDamage(EntityDamageByEntityEvent event) {
|
||||||
if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) {
|
|
||||||
if (isInOneTeam(damager, victim)) {
|
|
||||||
event.setCancelled(true);
|
|
||||||
} else if (victim.getPersistentDataContainer().has(Keys.SEEKER)) {
|
|
||||||
event.setDamage(0);
|
|
||||||
} else if (damager.getPersistentDataContainer().has(Keys.SEEKER)) {
|
|
||||||
double maxHealth = 20.0;
|
|
||||||
double currentHealth = damager.getHealth();
|
|
||||||
if (currentHealth < maxHealth) {
|
|
||||||
double newHealth = Math.min(currentHealth + event.getDamage(), maxHealth);
|
|
||||||
damager.setHealth(newHealth);
|
|
||||||
Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,40 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.objects.BlockAndSeekGame;
|
import hdvtdev.blockandseek.objects.BlockAndSeekGame;
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.WorldCreator;
|
import hdvtdev.blockandseek.objects.BlockAndSeekMap;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.util.*;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
public class GamesManager {
|
public class GamesManager {
|
||||||
|
|
||||||
private static final ConcurrentHashMap<String, BlockAndSeekGame> games = new ConcurrentHashMap<>();
|
private static final Map<String, BlockAndSeekGame> games = new HashMap<>();
|
||||||
private static final Set<Player> seekerImmune = ConcurrentHashMap.newKeySet();
|
private static final Set<UUID> seekerImmune = new HashSet<>();
|
||||||
|
|
||||||
public static boolean triggerSeekerImmune(Player player) {
|
public static boolean triggerSeekerImmune(UUID uuid) {
|
||||||
return seekerImmune.remove(player);
|
return seekerImmune.remove(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addSeekerImmune(Player player) {
|
public static void addSeekerImmune(Player player) {
|
||||||
seekerImmune.add(player);
|
seekerImmune.add(player.getUniqueId());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<String> getAvailableGames() {
|
public static Set<String> getAvailableGames() {
|
||||||
return games.keySet();
|
return games.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static @Nullable String createGame(String name) {
|
public static @Nullable BlockAndSeekGame createGame(String name) {
|
||||||
if (games.containsKey(name)) return name; //TODO use copy or create copy
|
|
||||||
|
|
||||||
|
BlockAndSeekMap map = MapsManager.getMap(name);
|
||||||
|
if (map != null) {
|
||||||
|
BlockAndSeekGame game = new BlockAndSeekGame(name, map);
|
||||||
|
games.put(name, game);
|
||||||
|
return game;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.Keys;
|
import hdvtdev.blockandseek.Keys;
|
||||||
import hdvtdev.blockAndSeek.Localization;
|
import hdvtdev.blockandseek.objects.TranslationKey;
|
||||||
|
import lombok.Getter;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
import org.bukkit.Color;
|
import org.bukkit.Color;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
@@ -14,10 +15,19 @@ import org.bukkit.inventory.meta.ItemMeta;
|
|||||||
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
import org.bukkit.inventory.meta.LeatherArmorMeta;
|
||||||
import org.bukkit.persistence.PersistentDataType;
|
import org.bukkit.persistence.PersistentDataType;
|
||||||
|
|
||||||
|
import static hdvtdev.blockandseek.objects.TranslationKey.*;
|
||||||
|
|
||||||
public class ItemManager {
|
public class ItemManager {
|
||||||
|
|
||||||
|
@Getter
|
||||||
private static final ItemStack freezeItem = new ItemStack(Material.HEART_OF_THE_SEA);
|
private static final ItemStack freezeItem = new ItemStack(Material.HEART_OF_THE_SEA);
|
||||||
|
@Getter
|
||||||
private static final ItemStack faceChangingItem = new ItemStack(Material.NETHER_STAR);
|
private static final ItemStack faceChangingItem = new ItemStack(Material.NETHER_STAR);
|
||||||
|
@Getter
|
||||||
|
private static final ItemStack dashItem = new ItemStack(Material.LAPIS_LAZULI);
|
||||||
|
@Getter
|
||||||
|
private static final ItemStack soundItem = new ItemStack(Material.BROWN_DYE);
|
||||||
|
|
||||||
|
|
||||||
private static final ItemStack seekerSword = new ItemStack(Material.WOODEN_SWORD);
|
private static final ItemStack seekerSword = new ItemStack(Material.WOODEN_SWORD);
|
||||||
private static final ItemStack seekerHelmet = new ItemStack(Material.LEATHER_HELMET);
|
private static final ItemStack seekerHelmet = new ItemStack(Material.LEATHER_HELMET);
|
||||||
@@ -25,9 +35,13 @@ public class ItemManager {
|
|||||||
private static final ItemStack seekerLeggings = new ItemStack(Material.LEATHER_LEGGINGS);
|
private static final ItemStack seekerLeggings = new ItemStack(Material.LEATHER_LEGGINGS);
|
||||||
private static final ItemStack seekerBoots = new ItemStack(Material.LEATHER_BOOTS);
|
private static final ItemStack seekerBoots = new ItemStack(Material.LEATHER_BOOTS);
|
||||||
|
|
||||||
|
@Getter
|
||||||
private static final ItemStack menuItem = new ItemStack(Material.COMPASS);
|
private static final ItemStack menuItem = new ItemStack(Material.COMPASS);
|
||||||
|
@Getter
|
||||||
private static final ItemStack games = new ItemStack(Material.BOOKSHELF);
|
private static final ItemStack games = new ItemStack(Material.BOOKSHELF);
|
||||||
|
@Getter
|
||||||
private static final ItemStack createGameButton = new ItemStack(Material.SLIME_BALL);
|
private static final ItemStack createGameButton = new ItemStack(Material.SLIME_BALL);
|
||||||
|
@Getter
|
||||||
private static final ItemStack leaveItem = new ItemStack(Material.RED_DYE);
|
private static final ItemStack leaveItem = new ItemStack(Material.RED_DYE);
|
||||||
|
|
||||||
|
|
||||||
@@ -53,8 +67,19 @@ public class ItemManager {
|
|||||||
menuMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
menuMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
menuItem.setItemMeta(menuMeta);
|
menuItem.setItemMeta(menuMeta);
|
||||||
|
|
||||||
|
ItemMeta dashMeta = dashItem.getItemMeta();
|
||||||
|
dashMeta.getPersistentDataContainer().set(Keys.DASH_ITEM, PersistentDataType.BOOLEAN, true);
|
||||||
|
dashMeta.addEnchant(Enchantment.ARROW_INFINITE, 1, true);
|
||||||
|
dashMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
dashItem.setItemMeta(dashMeta);
|
||||||
|
|
||||||
|
ItemMeta soundMeta = soundItem.getItemMeta();
|
||||||
|
soundMeta.getPersistentDataContainer().set(Keys.SOUND_ITEM, PersistentDataType.BOOLEAN, true);
|
||||||
|
soundMeta.addEnchant(Enchantment.ARROW_INFINITE, 1, true);
|
||||||
|
soundMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
|
||||||
|
soundItem.setItemMeta(soundMeta);
|
||||||
|
|
||||||
ItemMeta gamesMeta = games.getItemMeta();
|
ItemMeta gamesMeta = games.getItemMeta();
|
||||||
gamesMeta.getPersistentDataContainer().set(Keys.GAME_PAGE, PersistentDataType.BOOLEAN, true);
|
|
||||||
games.setItemMeta(gamesMeta);
|
games.setItemMeta(gamesMeta);
|
||||||
|
|
||||||
ItemMeta leaveMeta = leaveItem.getItemMeta();
|
ItemMeta leaveMeta = leaveItem.getItemMeta();
|
||||||
@@ -75,12 +100,12 @@ public class ItemManager {
|
|||||||
public static void setSeekerSet(Player seeker) {
|
public static void setSeekerSet(Player seeker) {
|
||||||
PlayerInventory inventory = seeker.getInventory();
|
PlayerInventory inventory = seeker.getInventory();
|
||||||
inventory.clear();
|
inventory.clear();
|
||||||
inventory.addItem(Localization.translateItem(seeker, seekerSword, "seeker_sword"));
|
inventory.addItem(TranslationManager.translateItem(seeker, seekerSword, TranslationKey.SEEKER_TEMPLATE));
|
||||||
ItemStack[] armor = new ItemStack[]{
|
ItemStack[] armor = new ItemStack[]{
|
||||||
Localization.translateItem(seeker, seekerBoots, "seeker_boots"),
|
TranslationManager.translateItem(seeker, seekerBoots, TranslationKey.SEEKER_TEMPLATE),
|
||||||
Localization.translateItem(seeker, seekerLeggings, "seeker_leggings"),
|
TranslationManager.translateItem(seeker, seekerLeggings, TranslationKey.SEEKER_TEMPLATE),
|
||||||
Localization.translateItem(seeker, seekerChestplate, "seeker_chestplate"),
|
TranslationManager.translateItem(seeker, seekerChestplate, TranslationKey.SEEKER_TEMPLATE),
|
||||||
Localization.translateItem(seeker, seekerHelmet, "seeker_helmet")
|
TranslationManager.translateItem(seeker, seekerHelmet, TranslationKey.SEEKER_TEMPLATE)
|
||||||
};
|
};
|
||||||
inventory.setArmorContents(armor);
|
inventory.setArmorContents(armor);
|
||||||
|
|
||||||
@@ -94,7 +119,6 @@ public class ItemManager {
|
|||||||
meta.setUnbreakable(true);
|
meta.setUnbreakable(true);
|
||||||
meta.addEnchant(Enchantment.PROTECTION_ENVIRONMENTAL, 10, true);
|
meta.addEnchant(Enchantment.PROTECTION_ENVIRONMENTAL, 10, true);
|
||||||
meta.addEnchant(Enchantment.THORNS, 3, true);
|
meta.addEnchant(Enchantment.THORNS, 3, true);
|
||||||
meta.displayName(Component.text("seeker-armor"));
|
|
||||||
|
|
||||||
return meta;
|
return meta;
|
||||||
}
|
}
|
||||||
@@ -102,32 +126,25 @@ public class ItemManager {
|
|||||||
public static void defaultInventory(Player player) {
|
public static void defaultInventory(Player player) {
|
||||||
PlayerInventory inventory = player.getInventory();
|
PlayerInventory inventory = player.getInventory();
|
||||||
inventory.clear();
|
inventory.clear();
|
||||||
inventory.addItem(Localization.translateItem(player, menuItem, "menu_item"));
|
inventory.addItem(TranslationManager.translateItem(player, menuItem, TranslationKey.MENU));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void hiderInventory(Player player) {
|
||||||
|
PlayerInventory playerInventory = player.getInventory();
|
||||||
|
playerInventory.clear();
|
||||||
|
playerInventory.addItem(
|
||||||
|
TranslationManager.translateItem(player, freezeItem, FREEZE_ITEM),
|
||||||
|
TranslationManager.translateItem(player, faceChangingItem, FACE_CHANGING_ITEM),
|
||||||
|
TranslationManager.translateItem(player, soundItem, SOUND_ITEM),
|
||||||
|
TranslationManager.translateItem(player, dashItem, DASH_ITEM)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void giveFaceChangingItem(Player player) {
|
public static void giveFaceChangingItem(Player player) {
|
||||||
player.getInventory().addItem(Localization.translateItem(player, faceChangingItem, "face_changing_item"));
|
player.getInventory().addItem(TranslationManager.translateItem(player, faceChangingItem, TranslationKey.SEEKER_TEMPLATE));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ItemStack getLeaveItem() {
|
|
||||||
return leaveItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack getCreateGameButton() {
|
|
||||||
return createGameButton;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack getGamesPageItem() {
|
|
||||||
return games;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack getMenuItem() {
|
|
||||||
return menuItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static ItemStack getFreezeItem() {
|
|
||||||
return freezeItem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,135 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
|
import eu.okaeri.configs.ConfigManager;
|
||||||
|
import eu.okaeri.configs.serdes.commons.SerdesCommons;
|
||||||
|
import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer;
|
||||||
|
import eu.okaeri.configs.yaml.bukkit.serdes.SerdesBukkit;
|
||||||
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
|
import hdvtdev.blockandseek.objects.BlockAndSeekMap;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.WorldCreator;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import org.incendo.cloud.suggestion.Suggestion;
|
import org.incendo.cloud.suggestion.Suggestion;
|
||||||
import org.incendo.cloud.suggestion.SuggestionProvider;
|
import org.incendo.cloud.suggestion.SuggestionProvider;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public final class MapsManager {
|
public final class MapsManager {
|
||||||
|
|
||||||
private MapsManager() {
|
private static final Map<String, BlockAndSeekMap> maps = new HashMap<>();
|
||||||
|
private static final File MAPS_DIR = new File(BlockAndSeek.getPluginDataFolder(), "maps");
|
||||||
|
|
||||||
|
private MapsManager() {}
|
||||||
|
|
||||||
|
public static void loadMaps() {
|
||||||
|
if (!MAPS_DIR.exists()) {
|
||||||
|
MAPS_DIR.mkdirs();
|
||||||
|
}
|
||||||
|
|
||||||
|
File[] files = MAPS_DIR.listFiles((dir, name) -> name.endsWith(".yml"));
|
||||||
|
if (files == null) return;
|
||||||
|
|
||||||
|
for (File file : files) {
|
||||||
|
String name = file.getName().replace(".yml", "");
|
||||||
|
try {
|
||||||
|
BlockAndSeekMap map = loadConfig(file);
|
||||||
|
maps.put(name, map);
|
||||||
|
} catch (Exception e) {
|
||||||
|
BlockAndSeek.getPluginLogger().severe("Error loading map " + name + ": " + e.getMessage());
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BlockAndSeek.getPluginLogger().info("Loaded " + maps.size() + " maps.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static BlockAndSeekMap getMap(String name) {
|
||||||
|
return maps.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Collection<BlockAndSeekMap> getMaps() {
|
||||||
|
return maps.values();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void createMap(String name) {
|
||||||
|
File mapFile = new File(MAPS_DIR, name + ".yml");
|
||||||
|
if (mapFile.exists()) {
|
||||||
|
throw new IllegalArgumentException("Map already exists!");
|
||||||
|
}
|
||||||
|
|
||||||
|
BlockAndSeekMap map = loadConfig(mapFile);
|
||||||
|
|
||||||
|
map.setWorld(name);
|
||||||
|
|
||||||
|
if (Bukkit.getWorld(name) != null) {
|
||||||
|
Location spawn = Bukkit.getWorld(name).getSpawnLocation();
|
||||||
|
map.setLobby(spawn);
|
||||||
|
map.setSpawn(spawn);
|
||||||
|
}
|
||||||
|
|
||||||
|
map.save();
|
||||||
|
maps.put(name, map);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockAndSeekMap loadConfig(File file) {
|
||||||
|
var map = ConfigManager.create(BlockAndSeekMap.class, (it) -> {
|
||||||
|
it.withConfigurer(
|
||||||
|
new YamlBukkitConfigurer(),
|
||||||
|
new SerdesBukkit(),
|
||||||
|
new SerdesCommons()
|
||||||
|
);
|
||||||
|
it.withBindFile(file);
|
||||||
|
it.withLogger(BlockAndSeek.getPluginLogger());
|
||||||
|
it.load(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
String worldName = map.getWorld();
|
||||||
|
if (worldName == null) {
|
||||||
|
BlockAndSeek.getPluginLogger().warning("Map " + file.getName() + " has no world defined!");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
World world = Bukkit.getWorld(worldName);
|
||||||
|
|
||||||
|
if (world == null) {
|
||||||
|
File worldFolder = new File(Bukkit.getWorldContainer(), worldName);
|
||||||
|
if (worldFolder.exists() && worldFolder.isDirectory()) {
|
||||||
|
BlockAndSeek.getPluginLogger().info("World '" + worldName + "' is not loaded. Loading now...");
|
||||||
|
world = Bukkit.createWorld(new WorldCreator(worldName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
map.getLobby().setWorld(world);
|
||||||
|
map.getSpawn().setWorld(world);
|
||||||
|
|
||||||
|
map.save();
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Suggestions ---
|
||||||
|
|
||||||
public static SuggestionProvider<CommandSender> worldSuggestions = (context, input) ->
|
public static SuggestionProvider<CommandSender> worldSuggestions = (context, input) ->
|
||||||
CompletableFuture.supplyAsync(() -> {
|
CompletableFuture.supplyAsync(() -> {
|
||||||
List<Suggestion> suggestions = new ArrayList<>();
|
// Лучше брать загруженные миры Bukkit, если карта должна быть в активном мире
|
||||||
|
// Если нужны папки миров:
|
||||||
File container = Bukkit.getWorldContainer();
|
File container = Bukkit.getWorldContainer();
|
||||||
|
File[] files = container.listFiles((dir, name) -> new File(dir, name + "/level.dat").exists());
|
||||||
|
|
||||||
File[] files = container.listFiles();
|
if (files == null) return Collections.emptyList();
|
||||||
if (files != null) {
|
|
||||||
for (File file : files) {
|
return Arrays.stream(files)
|
||||||
if (file.isDirectory() && new File(file, "level.dat").exists()) {
|
.map(File::getName)
|
||||||
suggestions.add(Suggestion.suggestion(file.getName()));
|
.map(Suggestion::suggestion)
|
||||||
}
|
.collect(Collectors.toList());
|
||||||
}
|
|
||||||
}
|
|
||||||
return suggestions;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
public static SuggestionProvider<CommandSender> mapSuggestions = (context, input) ->
|
public static SuggestionProvider<CommandSender> mapSuggestions = (context, input) ->
|
||||||
CompletableFuture.supplyAsync(() -> {
|
CompletableFuture.supplyAsync(() -> maps.keySet().stream()
|
||||||
List<Suggestion> suggestions = new ArrayList<>();
|
.map(Suggestion::suggestion)
|
||||||
|
.collect(Collectors.toList()));
|
||||||
File container = new File(Bukkit.getPluginsFolder(), "maps");
|
}
|
||||||
|
|
||||||
File[] files = container.listFiles();
|
|
||||||
if (files != null) {
|
|
||||||
for (File file : files) {
|
|
||||||
String name = file.getName();
|
|
||||||
if (file.isFile() && name.endsWith(".toml")) {
|
|
||||||
suggestions.add(Suggestion.suggestion(name.replace(".toml", ""))); //baddd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return suggestions;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,23 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.BlockAndSeek;
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
import me.libraryaddict.disguise.DisguiseAPI;
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
import me.libraryaddict.disguise.disguisetypes.Disguise;
|
import me.libraryaddict.disguise.disguisetypes.Disguise;
|
||||||
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
||||||
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
||||||
import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher;
|
import me.libraryaddict.disguise.disguisetypes.watchers.FallingBlockWatcher;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.Material;
|
import org.bukkit.Material;
|
||||||
import org.bukkit.block.Block;
|
import org.bukkit.block.Block;
|
||||||
import org.bukkit.block.data.BlockData;
|
import org.bukkit.block.data.BlockData;
|
||||||
|
import org.bukkit.block.data.Openable;
|
||||||
import org.bukkit.entity.ArmorStand;
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.EntityType;
|
import org.bukkit.entity.EntityType;
|
||||||
import org.bukkit.entity.FallingBlock;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -24,30 +27,105 @@ import java.util.UUID;
|
|||||||
public final class PropManager {
|
public final class PropManager {
|
||||||
|
|
||||||
private final Map<UUID, PropData> players = new HashMap<>();
|
private final Map<UUID, PropData> players = new HashMap<>();
|
||||||
|
private final Map<Location, UUID> props = new HashMap<>();
|
||||||
|
|
||||||
|
public void removePlayer(Player player) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isProped(UUID uuid) {
|
||||||
|
return props.containsValue(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forceUnfreeze(Player player) {
|
||||||
|
if (players.containsKey(player.getUniqueId())) {
|
||||||
|
freezeOrUnfreeze(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forceUnfreeze(UUID uuid) {
|
||||||
|
if (players.containsKey(uuid)) {
|
||||||
|
freezeOrUnfreeze(Bukkit.getPlayer(uuid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public UUID getProp(Location location) {
|
||||||
|
return props.remove(location);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//fixme: replace body with freezeOrUnfreeze(Player player) body
|
||||||
|
/*
|
||||||
|
public PropState freezeOrUnfreeze(UUID uuid) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
return freezeOrUnfreeze(player);
|
||||||
|
}
|
||||||
|
return PropState.FAILED;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
//i dont know how dis works xd
|
||||||
public PropState freezeOrUnfreeze(Player player) {
|
public PropState freezeOrUnfreeze(Player player) {
|
||||||
UUID uuid = player.getUniqueId();
|
UUID uuid = player.getUniqueId();
|
||||||
PropData propData = players.remove(uuid);
|
PropData propData = players.remove(uuid);
|
||||||
Location location = player.getLocation();
|
Location location = player.getLocation().toCenterLocation();
|
||||||
|
|
||||||
Block originalBlock = location.getBlock();
|
|
||||||
|
|
||||||
if (propData != null) {
|
if (propData != null) {
|
||||||
|
ArmorStand armorStand = propData.armorStand;
|
||||||
|
location.getWorld().setBlockData(location, propData.blockData);
|
||||||
|
location.setY(Math.floor(location.getY()));
|
||||||
|
player.setInvulnerable(false);
|
||||||
|
armorStand.removePassenger(player);
|
||||||
|
armorStand.remove();
|
||||||
|
|
||||||
originalBlock.setBlockData(propData.blockData);
|
|
||||||
|
|
||||||
|
return PropState.UNFROZEN;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
BlockData originalBlockData = originalBlock.getBlockData();
|
Block block = location.getBlock();
|
||||||
BlockData disguiseBlockData = getPlayerDisguiseData(player);
|
BlockData blockData = block.getBlockData();
|
||||||
|
|
||||||
|
Location blockLocation = block.getLocation();
|
||||||
|
Location centerLocation = blockLocation.toCenterLocation();
|
||||||
|
Location upperBlockLocation = centerLocation.clone();
|
||||||
|
upperBlockLocation.setY(upperBlockLocation.getY() + 1);
|
||||||
|
|
||||||
|
if (!upperBlockLocation.getBlock().isSolid() && !blockLocation.getBlock().isSolid()) {
|
||||||
|
props.put(blockLocation, uuid);
|
||||||
|
|
||||||
|
BlockData disguiseBlockData = getPlayerDisguiseData(player);
|
||||||
|
location.getWorld().setBlockData(blockLocation, disguiseBlockData == null ? Material.TARGET.createBlockData() : disguiseBlockData);
|
||||||
|
centerLocation.setY(centerLocation.getY() - 0.85);
|
||||||
|
|
||||||
|
player.setInvulnerable(true);
|
||||||
|
player.setFreezeTicks(40);
|
||||||
|
|
||||||
|
ArmorStand armorStand = location.getWorld().spawn(centerLocation, ArmorStand.class, stand -> {
|
||||||
|
stand.setVisible(false);
|
||||||
|
stand.setVisible(false);
|
||||||
|
stand.setCollidable(false);
|
||||||
|
stand.setGravity(true);
|
||||||
|
stand.setSmall(true);
|
||||||
|
stand.setCanMove(false);
|
||||||
|
stand.addPassenger(player);
|
||||||
|
stand.setInvulnerable(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
players.put(uuid, new PropData(armorStand, blockData));
|
||||||
|
return PropState.FROZEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
players.put(uuid, new PropData(null, originalBlockData, null));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return PropState.FAILED;
|
return PropState.FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +146,7 @@ public final class PropManager {
|
|||||||
FAILED
|
FAILED
|
||||||
}
|
}
|
||||||
|
|
||||||
private record PropData(ArmorStand armorStand, BlockData blockData, Disguise disguise) {
|
private record PropData(ArmorStand armorStand, BlockData blockData) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.objects.BlockAndSeekGame;
|
import hdvtdev.blockandseek.objects.BlockAndSeekGame;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -26,6 +26,14 @@ public class StateManager {
|
|||||||
stateToPlayers.computeIfAbsent(newState, k -> new HashSet<>()).add(uuid);
|
stateToPlayers.computeIfAbsent(newState, k -> new HashSet<>()).add(uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Set<UUID> getPlayers() {
|
||||||
|
return playerToState.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasPlayer(UUID uuid) {
|
||||||
|
return playerToState.containsKey(uuid);
|
||||||
|
}
|
||||||
|
|
||||||
public int playerCount() {
|
public int playerCount() {
|
||||||
return playerToState.size();
|
return playerToState.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
import eu.okaeri.configs.ConfigManager;
|
||||||
|
import eu.okaeri.configs.OkaeriConfig;
|
||||||
|
import eu.okaeri.configs.annotation.Exclude;
|
||||||
|
import eu.okaeri.configs.serdes.commons.SerdesCommons;
|
||||||
|
import eu.okaeri.configs.yaml.bukkit.YamlBukkitConfigurer;
|
||||||
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
|
import hdvtdev.blockandseek.objects.Translation;
|
||||||
|
import hdvtdev.blockandseek.objects.TranslationKey;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
|
public final class TranslationManager {
|
||||||
|
|
||||||
|
private TranslationManager() {}
|
||||||
|
|
||||||
|
public static final String defaultLanguage = "en_US";
|
||||||
|
public static final MiniMessage mm = MiniMessage.miniMessage();
|
||||||
|
public static final PlainTextComponentSerializer plaintText = PlainTextComponentSerializer.plainText();
|
||||||
|
|
||||||
|
public static final String prefix = "<gradient:#FFAA00:#FFD700><bold>BlockAndSeek</bold></gradient> <dark_gray>»</dark_gray>";
|
||||||
|
public static final String bracedPrefix = "<gradient:#FFAA00:#FFD700><bold>[BlockAndSeek]</bold></gradient>";
|
||||||
|
|
||||||
|
private static final Map<String, EnumMap<TranslationKey, String>> translations = new HashMap<>();
|
||||||
|
|
||||||
|
public static Component get(Player player, TranslationKey key, String... placeholders) {
|
||||||
|
return get(player.locale().toString(), key, placeholders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Component get(String lang, TranslationKey key, String... placeholders) {
|
||||||
|
String raw = translations.getOrDefault(lang, translations.get(defaultLanguage)).getOrDefault(key, "?" + key.toString() + "?");
|
||||||
|
if (placeholders.length % 2 == 0) {
|
||||||
|
for (int i = 0; i < placeholders.length; i++) {
|
||||||
|
raw = raw.replace(placeholders[i], placeholders[++i]);
|
||||||
|
}
|
||||||
|
} else BlockAndSeek.getPluginLogger().warning("Wrong amount of placeholders for key: " + key);
|
||||||
|
return mm.deserialize(raw);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ItemStack translateItem(Player player, ItemStack itemStack, TranslationKey key, String... placeholders) {
|
||||||
|
ItemMeta itemMeta = itemStack.getItemMeta();
|
||||||
|
itemMeta.displayName(get(player, key, placeholders));
|
||||||
|
itemStack.setItemMeta(itemMeta);
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void loadLanguages() {
|
||||||
|
File langDir = new File(BlockAndSeek.getPluginDataFolder(), "languages");
|
||||||
|
if (!langDir.exists()) langDir.mkdirs();
|
||||||
|
|
||||||
|
if (!new File(langDir, "en_US.yml").exists()) BlockAndSeek.saveResource("languages/en_US.yml");
|
||||||
|
if (!new File(langDir, "ru_RU.yml").exists()) BlockAndSeek.saveResource("languages/ru_RU.yml");
|
||||||
|
BlockAndSeek.getInstance().saveResource("languages/README.txt", true);
|
||||||
|
|
||||||
|
for (File lang : langDir.listFiles()) {
|
||||||
|
String name = lang.getName();
|
||||||
|
if (!name.endsWith(".yml")) continue;
|
||||||
|
|
||||||
|
Translation config = ConfigManager.create(Translation.class, (it) -> {
|
||||||
|
it.withConfigurer(new YamlBukkitConfigurer(), new SerdesCommons());
|
||||||
|
it.withBindFile(new File(langDir, name));
|
||||||
|
it.load(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
EnumMap<TranslationKey, String> enumMap = new EnumMap<>(TranslationKey.class);
|
||||||
|
enumMap.putAll(config.getMessages());
|
||||||
|
|
||||||
|
translations.put(name.replace(".yml", ""), enumMap);
|
||||||
|
|
||||||
|
BlockAndSeek.getPluginLogger().info("Loaded " + name + " translation");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package hdvtdev.blockAndSeek.managers;
|
package hdvtdev.blockandseek.managers;
|
||||||
|
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.BlockAndSeek;
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
|
|
||||||
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
|
import io.papermc.paper.threadedregions.scheduler.AsyncScheduler;
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,73 @@
|
|||||||
package hdvtdev.blockAndSeek.menus;
|
package hdvtdev.blockandseek.menus;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.Localization;
|
import hdvtdev.blockandseek.managers.TranslationManager;
|
||||||
import hdvtdev.blockAndSeek.GuiHolder;
|
import hdvtdev.blockandseek.GuiHolder;
|
||||||
|
import hdvtdev.blockandseek.managers.GamesManager;
|
||||||
|
import hdvtdev.blockandseek.managers.ItemManager;
|
||||||
|
import hdvtdev.blockandseek.objects.TranslationKey;
|
||||||
import net.kyori.adventure.text.Component;
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.minimessage.MiniMessage;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
import org.bukkit.inventory.Inventory;
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public class GamesMenu implements GuiHolder {
|
public class GamesMenu implements GuiHolder {
|
||||||
|
|
||||||
|
|
||||||
private final Inventory inventory;
|
private final Inventory inventory;
|
||||||
|
|
||||||
public GamesMenu(Player player) {
|
public GamesMenu(Player player) {
|
||||||
Component title = Localization.get(player, "games_menu");
|
Component title = TranslationManager.get(player, TranslationKey.GAMES_MENU);
|
||||||
this.inventory = Bukkit.createInventory(this, 54, title);
|
this.inventory = Bukkit.createInventory(this, 54, title);
|
||||||
initInventory();
|
initInventory();
|
||||||
|
showInventory(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initInventory() {
|
private void initInventory() {
|
||||||
|
inventory.setItem(53, ItemManager.getCreateGameButton());
|
||||||
|
for (String gameName : GamesManager.getAvailableGames()) {
|
||||||
|
ItemStack gameItem = new ItemStack(Material.AMETHYST_BLOCK);
|
||||||
|
ItemMeta itemMeta = gameItem.getItemMeta();
|
||||||
|
itemMeta.displayName(TranslationManager.get(TranslationManager.defaultLanguage, TranslationKey.GAME, "%name%", gameName));
|
||||||
|
var game = GamesManager.get(gameName);
|
||||||
|
itemMeta.lore(List.of(Component.text(game.players())));
|
||||||
|
gameItem.setItemMeta(itemMeta);
|
||||||
|
inventory.addItem(gameItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(InventoryClickEvent event) {
|
public void onClick(InventoryClickEvent event) {
|
||||||
|
int slot = event.getSlot();
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
if (slot == 53) {
|
||||||
|
new MapsMenu(player);
|
||||||
|
} else {
|
||||||
|
ItemStack item = event.getCurrentItem();
|
||||||
|
if (item != null) {
|
||||||
|
String gameName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", "");
|
||||||
|
var game = GamesManager.get(gameName);
|
||||||
|
if (game != null) {
|
||||||
|
if (!game.addPlayer(player)) {
|
||||||
|
player.sendMessage(TranslationManager.get(player, TranslationKey.GAME_IS_FULL, "%game%", gameName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
event.getInventory().close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
66
src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java
Normal file
66
src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package hdvtdev.blockandseek.menus;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.GuiHolder;
|
||||||
|
import hdvtdev.blockandseek.managers.GamesManager;
|
||||||
|
import hdvtdev.blockandseek.managers.ItemManager;
|
||||||
|
import hdvtdev.blockandseek.managers.MapsManager;
|
||||||
|
import hdvtdev.blockandseek.managers.TranslationManager;
|
||||||
|
import hdvtdev.blockandseek.objects.BlockAndSeekMap;
|
||||||
|
import hdvtdev.blockandseek.objects.TranslationKey;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static hdvtdev.blockandseek.objects.TranslationKey.UNKNOWN_MAP;
|
||||||
|
|
||||||
|
public class MapsMenu implements GuiHolder {
|
||||||
|
|
||||||
|
private final Inventory inventory;
|
||||||
|
|
||||||
|
public MapsMenu(Player player) {
|
||||||
|
Component title = TranslationManager.get(player, TranslationKey.GAMES_MENU);
|
||||||
|
this.inventory = Bukkit.createInventory(this, 54, title);
|
||||||
|
init();
|
||||||
|
showInventory(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
for (BlockAndSeekMap map : MapsManager.getMaps()) {
|
||||||
|
ItemStack gameItem = new ItemStack(Material.MAP);
|
||||||
|
ItemMeta itemMeta = gameItem.getItemMeta();
|
||||||
|
itemMeta.displayName(TranslationManager.get(TranslationManager.defaultLanguage, TranslationKey.MAP, "%name%", map.getWorld()));
|
||||||
|
gameItem.setItemMeta(itemMeta);
|
||||||
|
inventory.addItem(gameItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(InventoryClickEvent event) {
|
||||||
|
ItemStack item = event.getCurrentItem();
|
||||||
|
event.setCancelled(true);
|
||||||
|
if (item != null) {
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
String mapName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", "");
|
||||||
|
var map = MapsManager.getMap(mapName);
|
||||||
|
if (map != null) {
|
||||||
|
GamesManager.createGame(mapName).addPlayer(player);
|
||||||
|
} else {
|
||||||
|
player.sendMessage(TranslationManager.get(player, UNKNOWN_MAP, "%map%", mapName, "%maps%", MapsManager.getMaps().stream().map(BlockAndSeekMap::getWorld).collect(Collectors.joining(", "))));
|
||||||
|
}
|
||||||
|
player.closeInventory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @NotNull Inventory getInventory() {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,33 +1,121 @@
|
|||||||
package hdvtdev.blockAndSeek.objects;
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
|
import hdvtdev.blockandseek.Config;
|
||||||
|
import hdvtdev.blockandseek.Keys;
|
||||||
|
import hdvtdev.blockandseek.managers.TranslationManager;
|
||||||
|
import hdvtdev.blockandseek.Utils;
|
||||||
|
import hdvtdev.blockandseek.managers.GamesManager;
|
||||||
|
import hdvtdev.blockandseek.managers.ItemManager;
|
||||||
|
import hdvtdev.blockandseek.managers.PropManager;
|
||||||
|
import hdvtdev.blockandseek.managers.StateManager;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.menus.GamesMenu;
|
||||||
|
import hdvtdev.blockandseek.roulette.RouletteCreator;
|
||||||
|
import me.libraryaddict.disguise.DisguiseAPI;
|
||||||
|
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
||||||
|
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.title.Title;
|
||||||
|
|
||||||
import hdvtdev.blockAndSeek.managers.StateManager;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.ArmorStand;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockDamageEvent;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import org.bukkit.event.entity.*;
|
||||||
|
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||||
|
import org.bukkit.event.inventory.InventoryCloseEvent;
|
||||||
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.Inventory;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
import org.bukkit.persistence.PersistentDataContainer;
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class BlockAndSeekGame {
|
public class BlockAndSeekGame {
|
||||||
|
|
||||||
private final BlockAndSeekMap map;
|
private final BlockAndSeekMap map;
|
||||||
private final World world;
|
|
||||||
private final StateManager stateManager = new StateManager();
|
private final StateManager stateManager = new StateManager();
|
||||||
|
private final PropManager propManager = new PropManager();
|
||||||
|
private final String name;
|
||||||
|
|
||||||
public BlockAndSeekGame(BlockAndSeekMap blockAndSeekMap) {
|
private GamePhase phase;
|
||||||
|
|
||||||
|
public BlockAndSeekGame(String name, BlockAndSeekMap blockAndSeekMap) {
|
||||||
|
this.name = name;
|
||||||
this.map = blockAndSeekMap;
|
this.map = blockAndSeekMap;
|
||||||
this.world = Objects.requireNonNull(Bukkit.getWorld(blockAndSeekMap.world()));
|
start();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean addPlayer(Player player) {
|
public boolean addPlayer(Player player) {
|
||||||
if (stateManager.playerCount() < map.maxPlayers()) {
|
if (phase instanceof LobbyPhase && stateManager.playerCount() < map.getMaxPlayers()) {
|
||||||
stateManager.setPlayerState(player.getUniqueId(), PlayerType.NONE);
|
stateManager.setPlayerState(player.getUniqueId(), PlayerType.NONE);
|
||||||
|
player.teleport(map.getLobby());
|
||||||
|
player.setInvulnerable(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayer(Player player) {
|
public String players() {
|
||||||
stateManager.removePlayer(player.getUniqueId());
|
return stateManager.getPlayers().size() + "/" + map.getMaxPlayers();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void start() {
|
||||||
|
phase = new LobbyPhase();
|
||||||
|
phase.onEnable();
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (phase != null) {
|
||||||
|
phase.tick();
|
||||||
|
} else this.cancel();
|
||||||
|
}
|
||||||
|
}.runTaskTimer(BlockAndSeek.getInstance(), 0, 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void endGame() {
|
||||||
|
phase = null;
|
||||||
|
GamesManager.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendToAll(TranslationKey key, String... placeholders) {
|
||||||
|
for (UUID uuid : stateManager.getPlayers()) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
player.sendMessage(TranslationManager.get(player, key, placeholders));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcastToAll(TranslationKey key, String... placeholders) {
|
||||||
|
for (UUID uuid : stateManager.getPlayers()) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
player.showTitle(Title.title(TranslationManager.get(player, key, placeholders), Component.empty()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actionBarToAll(TranslationKey key, String... placeholders) {
|
||||||
|
for (UUID uuid : stateManager.getPlayers()) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
player.sendActionBar(TranslationManager.get(player, key, placeholders));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum PlayerType {
|
public enum PlayerType {
|
||||||
@@ -37,6 +125,343 @@ public class BlockAndSeekGame {
|
|||||||
SPECTATOR
|
SPECTATOR
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//fixme: player leave event: count == 0 -> phase = null -> delete game
|
||||||
|
private class LobbyPhase extends GamePhase {
|
||||||
|
|
||||||
|
private static final int WAIT_TIME = 30;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTick() {
|
||||||
|
|
||||||
|
if (map.getMinPlayers() > stateManager.playerCount()) {
|
||||||
|
super.tick = 0;
|
||||||
|
} else {
|
||||||
|
int timeLeft = WAIT_TIME - tick;
|
||||||
|
|
||||||
|
if (timeLeft <= 0) {
|
||||||
|
this.onDisable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeLeft == 30 || timeLeft == 15 || timeLeft == 10 || timeLeft <= 5) {
|
||||||
|
sendToAll(TranslationKey.TIME_TO_START, "%time%", String.valueOf(timeLeft));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
sendToAll(TranslationKey.WAITING_FOR_PLAYERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
phase = new StartedGamePhase();
|
||||||
|
phase.onEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private class StartedGamePhase extends GamePhase implements Listener {
|
||||||
|
|
||||||
|
private long gameDuration = map.getGameDuration().toSeconds();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTick() {
|
||||||
|
if (stateManager.getPlayersInState(PlayerType.SEEKER).isEmpty() || gameDuration == 0) {
|
||||||
|
var props = stateManager.getPlayersInState(PlayerType.PROP);
|
||||||
|
if (props.size() == 1) {
|
||||||
|
Player player = Bukkit.getPlayer(props.iterator().next());
|
||||||
|
if (player != null) {
|
||||||
|
broadcastToAll(TranslationKey.HIDER_SOLO_WIN, "%player%", player.getName());
|
||||||
|
} else broadcastToAll(TranslationKey.HIDERS_WIN);
|
||||||
|
} else broadcastToAll(TranslationKey.HIDERS_WIN);
|
||||||
|
this.onDisable();
|
||||||
|
} else if (stateManager.getPlayersInState(PlayerType.PROP).isEmpty()) {
|
||||||
|
broadcastToAll(TranslationKey.SEEKERS_WIN);
|
||||||
|
this.onDisable();
|
||||||
|
} else {
|
||||||
|
actionBarToAll(TranslationKey.TIME_LEFT, "%time%", String.valueOf(gameDuration));
|
||||||
|
}
|
||||||
|
gameDuration--;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
Plugin instance = BlockAndSeek.getInstance();
|
||||||
|
instance.getServer().getPluginManager().registerEvents(this, instance);
|
||||||
|
selectSeekers(1 + (stateManager.playerCount() / 7));
|
||||||
|
for (UUID uuid : stateManager.getPlayersInState(PlayerType.NONE)) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
stateManager.setPlayerState(uuid, PlayerType.PROP);
|
||||||
|
ItemManager.hiderInventory(player);
|
||||||
|
player.teleport(map.getSpawn());
|
||||||
|
new RouletteCreator(player, map.getBlocks());
|
||||||
|
player.setInvulnerable(false);
|
||||||
|
} else BlockAndSeek.getPluginLogger().warning("Player is null. ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectSeekers(int count) {
|
||||||
|
ArrayList<UUID> rawSeekers = new ArrayList<>();
|
||||||
|
Set<UUID> playerSet = stateManager.getPlayers();
|
||||||
|
for (UUID uuid : playerSet) {
|
||||||
|
if (!GamesManager.triggerSeekerImmune(uuid)) rawSeekers.add(uuid);
|
||||||
|
}
|
||||||
|
Collections.shuffle(rawSeekers);
|
||||||
|
|
||||||
|
var seekers = rawSeekers.subList(0, Math.min(count, playerSet.size()));
|
||||||
|
|
||||||
|
for (UUID seeker : seekers) {
|
||||||
|
Player player = Bukkit.getPlayer(seeker);
|
||||||
|
if (player != null) {
|
||||||
|
stateManager.setPlayerState(seeker, PlayerType.SEEKER);
|
||||||
|
ItemManager.setSeekerSet(player);
|
||||||
|
Utils.setLevelWithBar(player, 100);
|
||||||
|
GamesManager.addSeekerImmune(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (UUID seeker : seekers) {
|
||||||
|
Player player = Bukkit.getPlayer(seeker);
|
||||||
|
if (player != null) {
|
||||||
|
player.teleport(map.getSpawn());
|
||||||
|
player.setInvulnerable(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.runTaskLater(BlockAndSeek.getInstance(), map.getSeekerSpawnDelay().toSeconds() * 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
HandlerList.unregisterAll(this);
|
||||||
|
phase = new EndedGamePhase();
|
||||||
|
phase.onEnable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onPlayerLeaveEvent(PlayerQuitEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (stateManager.hasPlayer(uuid)) {
|
||||||
|
stateManager.removePlayer(uuid);
|
||||||
|
Utils.clearPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onItemDrop(PlayerDropItemEvent event) {
|
||||||
|
if (stateManager.hasPlayer(event.getPlayer().getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onPlayerDamage(EntityDamageEvent event) {
|
||||||
|
if (event.getEntity() instanceof Player player) {
|
||||||
|
if (stateManager.hasPlayer(player.getUniqueId())) {
|
||||||
|
if (event.getCause() == EntityDamageEvent.DamageCause.FALL) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onPlayerDeath(PlayerDeathEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (stateManager.hasPlayer(uuid)) {
|
||||||
|
stateManager.setPlayerState(uuid, PlayerType.SPECTATOR);
|
||||||
|
player.setGameMode(GameMode.SPECTATOR);
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onBlockBreak(BlockBreakEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (stateManager.hasPlayer(player.getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onRegainHealth(EntityRegainHealthEvent event) {
|
||||||
|
if (event.getEntity() instanceof Player player) {
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
PlayerType playerType = stateManager.getState(uuid);
|
||||||
|
|
||||||
|
if (playerType == PlayerType.SEEKER) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
} else if (playerType == PlayerType.PROP) {
|
||||||
|
if (!propManager.isProped(uuid)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onEntityDismount(EntityDismountEvent event) {
|
||||||
|
if (event.getEntity() instanceof Player player && event.getDismounted() instanceof ArmorStand) {
|
||||||
|
if (stateManager.hasPlayer(player.getUniqueId())) {
|
||||||
|
propManager.forceUnfreeze(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onBlockPlace(BlockPlaceEvent event) {
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (stateManager.hasPlayer(player.getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onPlayerDamageByPlayer(EntityDamageByEntityEvent event) {
|
||||||
|
if (event.getDamager() instanceof Player damager && event.getEntity() instanceof Player victim) {
|
||||||
|
PlayerType damagerType = stateManager.getState(damager.getUniqueId());
|
||||||
|
PlayerType victimType = stateManager.getState(victim.getUniqueId());
|
||||||
|
if (damagerType == victimType) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
} else {
|
||||||
|
if (damagerType == PlayerType.SEEKER) {
|
||||||
|
double currentHealth = damager.getHealth();
|
||||||
|
if (currentHealth < 20) {
|
||||||
|
double newHealth = Math.min(currentHealth + event.getDamage(), 20);
|
||||||
|
damager.setHealth(newHealth);
|
||||||
|
Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onInventoryClose(InventoryCloseEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
if (inventory.getHolder() instanceof RouletteCreator rouletteCreator && event.getReason() != InventoryCloseEvent.Reason.PLUGIN) {
|
||||||
|
Player player = (Player) event.getPlayer();
|
||||||
|
DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, rouletteCreator.randomPropItem()));
|
||||||
|
DisguiseAPI.setActionBarShown(player, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onBlockDamage(BlockDamageEvent event) {
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
if (PlayerType.SEEKER.equals(stateManager.getState(uuid))) {
|
||||||
|
UUID prop = propManager.getProp(event.getBlock().getLocation());
|
||||||
|
if (prop != null) {
|
||||||
|
propManager.forceUnfreeze(prop);
|
||||||
|
} else {
|
||||||
|
player.damage(2);
|
||||||
|
Utils.setLevelWithBar(player, (int) Math.round(player.getHealth() * 5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private void onInventoryClick(InventoryClickEvent event) {
|
||||||
|
Inventory inventory = event.getInventory();
|
||||||
|
if (inventory.getHolder() instanceof RouletteCreator) {
|
||||||
|
ItemStack itemStack = event.getCurrentItem();
|
||||||
|
int slot = event.getSlot();
|
||||||
|
if (itemStack != null && (slot == 21 || slot == 23 || slot == 25)) {
|
||||||
|
Player player = (Player) event.getWhoClicked();
|
||||||
|
player.closeInventory(InventoryCloseEvent.Reason.PLUGIN);
|
||||||
|
DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, itemStack));
|
||||||
|
DisguiseAPI.setActionBarShown(player, false);
|
||||||
|
}
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Set<UUID> coolDown = new HashSet<>();
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onRightClick(PlayerInteractEvent event) {
|
||||||
|
if (event.getHand() != EquipmentSlot.HAND) return;
|
||||||
|
if (event.getAction().isLeftClick()) return;
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
UUID uuid = player.getUniqueId();
|
||||||
|
|
||||||
|
ItemStack item = event.getItem();
|
||||||
|
if (item != null) {
|
||||||
|
ItemMeta meta = item.getItemMeta();
|
||||||
|
if (meta != null) {
|
||||||
|
PersistentDataContainer dataContainer = meta.getPersistentDataContainer();
|
||||||
|
if (dataContainer.has(Keys.FREEZE_ITEM)) {
|
||||||
|
if (!coolDown.contains(uuid)) {
|
||||||
|
player.sendActionBar(Component.text(propManager.freezeOrUnfreeze(event.getPlayer()).toString()));
|
||||||
|
coolDown.add(uuid);
|
||||||
|
new BukkitRunnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
coolDown.remove(uuid);
|
||||||
|
}
|
||||||
|
}.runTaskLater(BlockAndSeek.getInstance(), 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EndedGamePhase extends GamePhase {
|
||||||
|
|
||||||
|
private final long endTick = map.getDelayBeforeGameEnd().toSeconds();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTick() {
|
||||||
|
if (super.tick == endTick) {
|
||||||
|
this.onDisable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable() {
|
||||||
|
for (UUID uuid : stateManager.getPlayers()) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
propManager.forceUnfreeze(player);
|
||||||
|
player.setInvulnerable(true);
|
||||||
|
player.setGlowing(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable() {
|
||||||
|
for (UUID uuid : stateManager.getPlayers()) {
|
||||||
|
Player player = Bukkit.getPlayer(uuid);
|
||||||
|
if (player != null) {
|
||||||
|
//propManager.removePlayer(player);
|
||||||
|
Utils.clearPlayer(player);
|
||||||
|
player.setInvulnerable(true);
|
||||||
|
ItemManager.defaultInventory(player);
|
||||||
|
player.teleport(Config.spawn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
endGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,59 @@
|
|||||||
package hdvtdev.blockAndSeek.objects;
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import eu.okaeri.configs.OkaeriConfig;
|
||||||
import org.bukkit.World;
|
import eu.okaeri.configs.annotation.Comment;
|
||||||
|
import eu.okaeri.configs.annotation.CustomKey;
|
||||||
|
import eu.okaeri.validator.annotation.Min;
|
||||||
|
|
||||||
public record BlockAndSeekMap(String world, Cords spawn, Cords lobby,
|
import lombok.Getter;
|
||||||
int minPlayers, int maxPlayers, int duration, int seekerSpawnDelay, int delayBeforeEnd) {
|
import lombok.Setter;
|
||||||
|
|
||||||
public static void prepareWorld(World world) {
|
import org.bukkit.Location;
|
||||||
if (Integer.parseInt(Bukkit.getMinecraftVersion().replaceAll("[^0-9]", "")) >= 1215) {
|
import org.bukkit.Material;
|
||||||
String cmd = "execute in " + world.getKey() + " run gamerule locatorBar true";
|
import org.bukkit.inventory.ItemStack;
|
||||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), cmd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public class BlockAndSeekMap extends OkaeriConfig {
|
||||||
|
|
||||||
|
@Comment("The name of the world where the game takes place")
|
||||||
|
private String world;
|
||||||
|
|
||||||
|
@Comment("The main spawn point inside the arena")
|
||||||
|
private Location spawn;
|
||||||
|
|
||||||
|
@Comment("The waiting lobby location where players join before the match")
|
||||||
|
private Location lobby;
|
||||||
|
|
||||||
|
@Comment("Minimum number of players required to start the game")
|
||||||
|
@Min(2)
|
||||||
|
@CustomKey("min-players")
|
||||||
|
private int minPlayers = 2;
|
||||||
|
|
||||||
|
@Comment("Maximum number of players allowed in the game")
|
||||||
|
@CustomKey("max-players")
|
||||||
|
private int maxPlayers = 12;
|
||||||
|
|
||||||
|
@Comment("Total duration of the match. Format examples: 10m, 300s, 1h")
|
||||||
|
@CustomKey("game-duration")
|
||||||
|
private Duration gameDuration = Duration.ofMinutes(10);
|
||||||
|
|
||||||
|
@Comment("How long seekers must wait before they are released")
|
||||||
|
@CustomKey("seeker-spawn-delay")
|
||||||
|
private Duration seekerSpawnDelay = Duration.ofSeconds(30);
|
||||||
|
|
||||||
|
@Comment("Time to stay in the arena after the game ends (Post-game phase)")
|
||||||
|
@Comment("Allows players to look around, check positions and chat before being sent to lobby")
|
||||||
|
@CustomKey("delay-before-game-end")
|
||||||
|
private Duration delayBeforeGameEnd = Duration.ofSeconds(10);
|
||||||
|
|
||||||
|
@Comment("Available blocks for hiders")
|
||||||
|
private List<PropBlock> blocks = new ArrayList<>(List.of(new PropBlock(new ItemStack(Material.TARGET), Rarity.LEGENDARY)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,18 @@
|
|||||||
package hdvtdev.blockandseek.objects;
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
public interface GamePhase {
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public abstract class GamePhase {
|
||||||
|
|
||||||
|
protected int tick = 0;
|
||||||
|
|
||||||
|
public final void tick() {
|
||||||
|
onTick();
|
||||||
|
tick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void onTick();
|
||||||
|
protected abstract void onEnable();
|
||||||
|
protected abstract void onDisable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
package hdvtdev.blockAndSeek.objects;
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
|
import eu.okaeri.configs.OkaeriConfig;
|
||||||
|
import eu.okaeri.configs.annotation.Comment;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
public record PropBlock(ItemStack block, int chance) {
|
public class PropBlock extends OkaeriConfig {
|
||||||
public PropBlock(ItemStack block, Rarity rarity) {
|
|
||||||
this(block, rarity.toChance());
|
private ItemStack block;
|
||||||
|
private Rarity rarity = Rarity.COMMON;
|
||||||
|
|
||||||
|
public ItemStack getBlock() {
|
||||||
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Rarity getRarity() {
|
||||||
|
return rarity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropBlock(ItemStack itemStack, Rarity rarity) {
|
||||||
|
this.block = itemStack;
|
||||||
|
this.rarity = rarity;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,20 @@
|
|||||||
package hdvtdev.blockAndSeek.objects;
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
public enum Rarity {
|
public enum Rarity {
|
||||||
|
COMMON(100), // Очень часто (как грязь)
|
||||||
|
UNCOMMON(50), // Часто (половина от обычного)
|
||||||
|
RARE(25), // Редко
|
||||||
|
EPIC(10), // Очень редко
|
||||||
|
MYTHIC(3), // Почти невозможно
|
||||||
|
LEGENDARY(1); // Чудо
|
||||||
|
|
||||||
COMMON,// 38%
|
private final int weight;
|
||||||
UNCOMMON,// 27%
|
|
||||||
RARE,// 19%
|
|
||||||
EPIC,// 10%
|
|
||||||
MYTHIC,// 4%
|
|
||||||
LEGENDARY; // 2%
|
|
||||||
|
|
||||||
public int toChance() {
|
Rarity(int weight) {
|
||||||
return switch (this.ordinal()) {
|
this.weight = weight;
|
||||||
case 1 -> 27;
|
|
||||||
case 2 -> 19;
|
|
||||||
case 3 -> 10;
|
|
||||||
case 4 -> 4;
|
|
||||||
case 5 -> 2;
|
|
||||||
default -> 38;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
public int getChance() {
|
||||||
|
return weight;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/main/java/hdvtdev/blockandseek/objects/Translation.java
Normal file
17
src/main/java/hdvtdev/blockandseek/objects/Translation.java
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
|
import eu.okaeri.configs.OkaeriConfig;
|
||||||
|
import eu.okaeri.configs.annotation.Header;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Header("Translations lives here")
|
||||||
|
@Getter
|
||||||
|
public class Translation extends OkaeriConfig {
|
||||||
|
|
||||||
|
private Map<TranslationKey, String> messages = new EnumMap<>(TranslationKey.class);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package hdvtdev.blockandseek.objects;
|
||||||
|
|
||||||
|
public enum TranslationKey {
|
||||||
|
// Misc
|
||||||
|
UNKNOWN_COMMAND,
|
||||||
|
SEEKER_TEMPLATE,
|
||||||
|
|
||||||
|
// Maps management
|
||||||
|
UNKNOWN_MAP,
|
||||||
|
SUCCESSFUL_MAP_CREATION,
|
||||||
|
|
||||||
|
// Menus
|
||||||
|
MENU,
|
||||||
|
GAMES_MENU,
|
||||||
|
MAPS_MENU,
|
||||||
|
|
||||||
|
// Menus buttons
|
||||||
|
GAME,
|
||||||
|
CREATE_GAME,
|
||||||
|
MAP,
|
||||||
|
|
||||||
|
// Game
|
||||||
|
TIME_LEFT,
|
||||||
|
TIME_TO_START,
|
||||||
|
PLAYER_JOINED,
|
||||||
|
PLAYER_LEFT,
|
||||||
|
SEEKERS_WIN,
|
||||||
|
HIDERS_WIN,
|
||||||
|
HIDER_SOLO_WIN,
|
||||||
|
ROULETTE,
|
||||||
|
GAME_IS_FULL,
|
||||||
|
WAITING_FOR_PLAYERS,
|
||||||
|
|
||||||
|
// Items
|
||||||
|
FREEZE_ITEM,
|
||||||
|
FACE_CHANGING_ITEM,
|
||||||
|
SOUND_ITEM,
|
||||||
|
LEAVE_ITEM,
|
||||||
|
DASH_ITEM;
|
||||||
|
}
|
||||||
@@ -1,4 +1,11 @@
|
|||||||
package hdvtdev.blockAndSeek.roulette;
|
package hdvtdev.blockandseek.roulette;
|
||||||
|
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.BlockAndSeek;
|
||||||
|
import hdvtdev.blockandseek.managers.TranslationManager;
|
||||||
|
import hdvtdev.blockandseek.objects.PropBlock;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.objects.TranslationKey;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Sound;
|
import org.bukkit.Sound;
|
||||||
@@ -7,15 +14,14 @@ import org.bukkit.inventory.Inventory;
|
|||||||
import org.bukkit.inventory.InventoryHolder;
|
import org.bukkit.inventory.InventoryHolder;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
import org.bukkit.scheduler.BukkitRunnable;
|
import org.bukkit.scheduler.BukkitRunnable;
|
||||||
import org.bukkit.scheduler.BukkitTask;
|
|
||||||
import org.jetbrains.annotations.ApiStatus;
|
import org.jetbrains.annotations.ApiStatus;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
/*
|
|
||||||
public final class RouletteCreator implements InventoryHolder {
|
public final class RouletteCreator implements InventoryHolder {
|
||||||
|
|
||||||
|
|
||||||
@@ -24,146 +30,116 @@ public final class RouletteCreator implements InventoryHolder {
|
|||||||
private static final Random random = new Random();
|
private static final Random random = new Random();
|
||||||
|
|
||||||
private final Inventory roulette;
|
private final Inventory roulette;
|
||||||
private Task task;
|
private boolean isRunning = true;
|
||||||
private volatile Boolean closedByPlayer = true;
|
|
||||||
|
|
||||||
public RouletteCreator(@NotNull Player player, List<BlockAndSeekMap.Block> blocks) {
|
public RouletteCreator(@NotNull Player player, @NotNull List<PropBlock> blocks) {
|
||||||
roulette = Bukkit.createInventory(this, 45, Localization.getComponent(player, "roulette-title"));
|
roulette = Bukkit.createInventory(this, 45, TranslationManager.get(player, TranslationKey.ROULETTE));
|
||||||
this.createUnoptimizedRoulette(roulette, player, blocks);
|
this.createSmoothRoulette(roulette, player, blocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
public @NotNull Task getTask() {
|
|
||||||
return task;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @Nullable Boolean isClosedByPlayer() {
|
|
||||||
return closedByPlayer;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Inventory getInventory() {
|
public @NotNull Inventory getInventory() {
|
||||||
return roulette;
|
return roulette;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void closeInventoryBySystem() {
|
|
||||||
closedByPlayer = false;
|
|
||||||
roulette.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeInventory() {
|
|
||||||
closedByPlayer = null;
|
|
||||||
roulette.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack randomPropItem() {
|
public ItemStack randomPropItem() {
|
||||||
return roulette.getItem(slots[random.nextInt(0, 15)]);
|
return isRunning ? roulette.getItem(slots[random.nextInt(0, 15)]) : roulette.getItem(midSlots[random.nextInt(0, 3)]);
|
||||||
}
|
|
||||||
|
|
||||||
public ItemStack randomMidPropItem() {
|
|
||||||
return roulette.getItem(midSlots[random.nextInt(0, 3)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiStatus.Experimental
|
@ApiStatus.Experimental
|
||||||
private void createUnoptimizedRoulette(Inventory gui, Player player, List<BlockAndSeekMap.Block> blocks) {
|
private void createSmoothRoulette(Inventory gui, Player player, List<PropBlock> blocks) {
|
||||||
|
player.openInventory(gui);
|
||||||
BukkitTask rouletteTask = new BukkitRunnable() {
|
|
||||||
|
|
||||||
|
new BukkitRunnable() {
|
||||||
final RouletteGenerator rouletteGenerator = new RouletteGenerator(blocks);
|
final RouletteGenerator rouletteGenerator = new RouletteGenerator(blocks);
|
||||||
|
|
||||||
final List<RouletteList<ItemStack>> rows = List.of(
|
final List<RouletteList<ItemStack>> sources = List.of(
|
||||||
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
||||||
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
new RouletteList<>(rouletteGenerator.getRandomRow(15)),
|
||||||
new RouletteList<>(rouletteGenerator.getRandomRow(15))
|
new RouletteList<>(rouletteGenerator.getRandomRow(15))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final List<ItemStack[]> columns = new ArrayList<>();
|
||||||
final List<ItemStack[]> items;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
List<ItemStack[]> rawItems = new ArrayList<>();
|
for (int i = 0; i < 3; i++) {
|
||||||
for (int j = 0; j < 3; j++) {
|
ItemStack[] col = new ItemStack[5];
|
||||||
ItemStack[] itemStacks = new ItemStack[5];
|
for (int row = 0; row < 5; row++) {
|
||||||
for (int l = 0; l < 5; l++) {
|
col[row] = sources.get(i).next();
|
||||||
itemStacks[l] = rows.get(j).next();
|
|
||||||
}
|
}
|
||||||
rawItems.add(j, itemStacks);
|
columns.add(col);
|
||||||
}
|
}
|
||||||
items = rawItems;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final long startTime = System.currentTimeMillis();
|
final int[] colStartIndices = {3, 5, 7};
|
||||||
double currentSpeed = 0;
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
|
int ticksAlive = 0; // Общее время работы анимации
|
||||||
|
int ticksUntilNextMove = 0; // Обратный отсчет до следующего кадра
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
// Безопасность
|
||||||
long now = System.currentTimeMillis();
|
if (!player.isOnline() || !player.getOpenInventory().getTopInventory().equals(gui)) {
|
||||||
double elapsed = (now - startTime) / 1000.0;
|
|
||||||
|
|
||||||
if (elapsed >= 5) {
|
|
||||||
this.cancel();
|
this.cancel();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
double speed;
|
// Увеличиваем общий счетчик жизни таймера
|
||||||
if (elapsed < 2) speed = 1.0;
|
ticksAlive++;
|
||||||
else if (elapsed < 2.2) speed = 0.8;
|
|
||||||
else if (elapsed < 2.4) speed = 0.6;
|
|
||||||
else if (elapsed < 2.6) speed = 0.5;
|
|
||||||
else if (elapsed < 2.8) speed = 0.4;
|
|
||||||
else if (elapsed < 3) speed = 0.33;
|
|
||||||
else if (elapsed < 3.2) speed = 0.28;
|
|
||||||
else if (elapsed < 3.5) speed = 0.22;
|
|
||||||
else if (elapsed < 3.8) speed = 0.15;
|
|
||||||
else speed = 0.1;
|
|
||||||
|
|
||||||
task(speed);
|
// Если время ожидания еще не вышло — ждем
|
||||||
|
if (ticksUntilNextMove > 0) {
|
||||||
|
ticksUntilNextMove--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
i++;
|
updateRoulette();
|
||||||
|
|
||||||
|
if (ticksAlive < 30) { // 0 - 1.5 сек:
|
||||||
|
ticksUntilNextMove = 1; // Каждые 2 тика (быстро, но не мыло)
|
||||||
|
} else if (ticksAlive < 50) { // 1.5 - 2.5 сек:
|
||||||
|
ticksUntilNextMove = 2; // Чуть медленнее (каждые 3 тика)
|
||||||
|
} else if (ticksAlive < 65) { // 2.5 - 3.2 сек:
|
||||||
|
ticksUntilNextMove = 3; // Еще медленнее (каждые 4 тика)
|
||||||
|
} else if (ticksAlive < 75) { // 3.2 - 3.7 сек:
|
||||||
|
ticksUntilNextMove = 5; // Заметное торможение
|
||||||
|
} else if (ticksAlive < 85) { // 3.7 - 4.2 сек:
|
||||||
|
ticksUntilNextMove = 8; // Почти конец
|
||||||
|
} else if (ticksAlive < 95) { // Последние вздохи
|
||||||
|
ticksUntilNextMove = 12;
|
||||||
|
} else if (ticksAlive < 110) {
|
||||||
|
ticksUntilNextMove = 20; // Финальный медленный шаг
|
||||||
|
} else {
|
||||||
|
// КОНЕЦ
|
||||||
|
isRunning = false;
|
||||||
|
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1f, 2f);
|
||||||
|
this.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void task(double speed) {
|
private void updateRoulette() {
|
||||||
if (currentSpeed >= 1) {
|
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 1f);
|
||||||
currentSpeed = 0;
|
|
||||||
for (int j = 0; j < 5; j++) {
|
for (int colIndex = 0; colIndex < 3; colIndex++) {
|
||||||
gui.setItem(3 + j * 9, items.getFirst()[j]);
|
ItemStack[] colItems = columns.get(colIndex);
|
||||||
gui.setItem(5 + j * 9, items.get(1)[j]);
|
|
||||||
gui.setItem(7 + j * 9, items.get(2)[j]);
|
for (int row = 0; row < 5; row++) {
|
||||||
|
int slot = colStartIndices[colIndex] + (row * 9);
|
||||||
|
gui.setItem(slot, colItems[row]);
|
||||||
}
|
}
|
||||||
|
|
||||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.5f, 2f);
|
System.arraycopy(colItems, 0, colItems, 1, 4);
|
||||||
|
colItems[0] = sources.get(colIndex).next();
|
||||||
for (int j = 4; j >= 1; j--) {
|
}
|
||||||
items.getFirst()[j] = items.getFirst()[j - 1];
|
|
||||||
items.get(1)[j] = items.get(1)[j - 1];
|
|
||||||
items.get(2)[j] = items.get(2)[j - 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
items.getFirst()[0] = rows.getFirst().next();
|
|
||||||
items.get(1)[0] = rows.get(1).next();
|
|
||||||
items.get(2)[0] = rows.get(2).next();
|
|
||||||
} else currentSpeed += speed;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}.runTaskTimer(BlockAndSeek.getInstance(), 0, 1);
|
}.runTaskTimer(BlockAndSeek.getInstance(), 0L, 1L);
|
||||||
|
|
||||||
|
|
||||||
task = new Task(rouletteTask, Bukkit.getScheduler().runTaskLater(BlockAndSeek.getInstance(), this::closeInventoryBySystem, 300));
|
|
||||||
|
|
||||||
player.openInventory(gui);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public record Task(BukkitTask rouletteTask, BukkitTask autoCloseTask) {
|
|
||||||
public void cancelBoth() {
|
|
||||||
rouletteTask.cancel();
|
|
||||||
autoCloseTask.cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
package hdvtdev.blockAndSeek.roulette;
|
package hdvtdev.blockandseek.roulette;
|
||||||
|
|
||||||
|
|
||||||
import com.lewdev.probabilitylib.ProbabilityCollection;
|
import com.lewdev.probabilitylib.ProbabilityCollection;
|
||||||
|
|
||||||
|
import hdvtdev.blockandseek.objects.PropBlock;
|
||||||
|
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
/*
|
|
||||||
public class RouletteGenerator {
|
public class RouletteGenerator {
|
||||||
|
|
||||||
private final ProbabilityCollection<ItemStack> probabilityCollection = new ProbabilityCollection<>();
|
private final ProbabilityCollection<ItemStack> probabilityCollection = new ProbabilityCollection<>();
|
||||||
|
|
||||||
public RouletteGenerator(List<BlockAndSeekMap.Block> blocks) {
|
public RouletteGenerator(List<PropBlock> blocks) {
|
||||||
for (BlockAndSeekMap.Block block : blocks) {
|
for (PropBlock block : blocks) {
|
||||||
probabilityCollection.add(block.block(), block.chance());
|
probabilityCollection.add(block.getBlock(), block.getRarity().getChance());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,7 +26,6 @@ public class RouletteGenerator {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package hdvtdev.blockAndSeek.roulette;
|
package hdvtdev.blockandseek.roulette;
|
||||||
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
|||||||
2
src/main/resources/languages/README.txt
Normal file
2
src/main/resources/languages/README.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Place your translations in language folder. Translation file name must be a language tag and file extension must be .yml.
|
||||||
|
Use en_US.yml as example.
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
messages:
|
||||||
|
UNKNOWN_COMMAND: "<gold>Unknown command: <red>%command%</red>."
|
||||||
|
SEEKER_TEMPLATE: "<gradient:#8B0000:#B22222:#DC143C><bold>%template%</bold></gradient>"
|
||||||
|
UNKNOWN_MAP: "<gold>Unknown map: <red>%map%</red>. Available maps: </gold><dark_aqua><b>%maps%</b></dark_aqua>"
|
||||||
|
SUCCESSFUL_MAP_CREATION: "<gold>Map <dark_aqua><b>%map%</b></dark_aqua> was <green>successfully</green> created. Use <b>/blockandseek map <dark_aqua>%map%</dark_aqua> to edit</b>"
|
||||||
|
MENU: <yellow>menu</yellow>
|
||||||
|
GAMES_MENU: "<gold>games</gold>"
|
||||||
|
MAPS_MENU: "<gold>maps</gold>"
|
||||||
|
GAME: "<gradient:#52e555:#20962d>%name%</gradient>"
|
||||||
|
CREATE_GAME: "<gold><b>Create game</b></gold>"
|
||||||
|
MAP: "<gradient:#20e3b2:#29ffc6>%name%</gradient>"
|
||||||
|
TIME_LEFT: "<gold>Time left %time%</gold>"
|
||||||
|
PLAYER_JOINED: "<gold><b>%player%</b></gold><yellow> joined. <b>%count%/%max%<b>"
|
||||||
|
PLAYER_LEFT: "<gold><b>%player%</b></gold><yellow> <red>left</red>. <b>%count%/%max%<b>"
|
||||||
|
SEEKERS_WIN: "<b><red>Seekers won this game!</red></b>"
|
||||||
|
HIDERS_WIN: "<b><gold>Hiders won this game!</gold></b>"
|
||||||
|
HIDER_SOLO_WIN: "<b><gold><aqua>%player%</aqua> won this game!</gold></b>"
|
||||||
|
FREEZE_ITEM: "<gradient:#00c6fb:#005bea>Freezer 3000</gradient>"
|
||||||
|
SOUND_ITEM: "<gradient:#f3e6ff:#dcb3ff>Sounder 3000</gradient>"
|
||||||
|
LEAVE_ITEM: "<red><b>Leave</red></b>"
|
||||||
|
DASH_ITEM: "<gradient:#43cea2:#185a9d>Dash</gradient>"
|
||||||
|
ROULETTE: "<b><gold>Blocks roulette</b></gold>"
|
||||||
|
TIME_TO_START: "<gold>Game starts in <b>%time%</b></gold>"
|
||||||
|
GAME_IS_FULL: "<yellow><red>failed></red> to join %game%. Game is full."
|
||||||
|
FACE_CHANGING_ITEM: "FACE_CHANGING_ITEM: todo"
|
||||||
|
WAITING_FOR_PLAYERS: "<gold>Waiting for players</gold>"
|
||||||
23
src/main/resources/languages/ru_RU.yml
Normal file
23
src/main/resources/languages/ru_RU.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
messages:
|
||||||
|
UNKNOWN_COMMAND: "<gold>Неизвестная команда: <red>%command%</red>."
|
||||||
|
SEEKER_TEMPLATE: <gradient:#8B0000:#B22222:#DC143C><bold>%template%</bold></gradient>
|
||||||
|
UNKNOWN_MAP: "<gold>Неизвестная карта: <red>%map%</red>. Доступные карты: </gold><dark_aqua><b>%maps%</b></dark_aqua>"
|
||||||
|
SUCCESSFUL_MAP_CREATION: <gold>Карта <dark_aqua><b>%map%</b></dark_aqua> была <green>успешно</green> создана. Используйте <b>/blockandseek map <dark_aqua>%map%</dark_aqua>, чтобы редактировать</b>
|
||||||
|
MENU: <yellow>меню</yellow>
|
||||||
|
GAMES_MENU: <gold>игры</gold>
|
||||||
|
MAPS_MENU: <gold>карты</gold>
|
||||||
|
GAME: <gradient:#52e555:#20962d>%name%</gradient>
|
||||||
|
CREATE_GAME: <gold><b>Создать игру</b></gold>
|
||||||
|
MAP: <gradient:#20e3b2:#29ffc6>%name%</gradient>
|
||||||
|
TIME_LEFT: "<gold>Осталось времени: %time%</gold>"
|
||||||
|
PLAYER_JOINED: <gold><b>%player%</b></gold><yellow> присоединился. <b>%count%/%max%<b>
|
||||||
|
PLAYER_LEFT: <gold><b>%player%</b></gold><yellow> <red>вышел</red>. <b>%count%/%max%<b>
|
||||||
|
SEEKERS_WIN: <b><red>Искатели победили!</red></b>
|
||||||
|
HIDERS_WIN: <b><gold>Прячущиеся победили!</gold></b>
|
||||||
|
HIDER_SOLO_WIN: <b><gold><aqua>%player%</aqua> победил!</gold></b>
|
||||||
|
FREEZE_ITEM: <gradient:#00c6fb:#005bea>Замораживатель 3000</gradient>
|
||||||
|
SOUND_ITEM: <gradient:#f3e6ff:#dcb3ff>Шумелка 3000</gradient>
|
||||||
|
LEAVE_ITEM: <red><b>Выйти</red></b>
|
||||||
|
DASH_ITEM: <gradient:#43cea2:#185a9d>Рывок</gradient>
|
||||||
|
ROULETTE: <b><gold>Рулетка блоков</b></gold>
|
||||||
|
TIME_TO_START: <gold>Игра начнется через <b>%time%</b></gold>
|
||||||
@@ -1,7 +1,11 @@
|
|||||||
name: BlockAndSeek
|
name: BlockAndSeek
|
||||||
version: '0.0.1-a'
|
version: '0.0.1-a'
|
||||||
main: hdvtdev.blockAndSeek.BlockAndSeek
|
main: hdvtdev.blockandseek.BlockAndSeek
|
||||||
api-version: '1.20'
|
api-version: '1.20'
|
||||||
|
load: POSTWORLD
|
||||||
|
|
||||||
|
depend:
|
||||||
|
- LibsDisguises
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
blockandseek.manage:
|
blockandseek.manage:
|
||||||
@@ -12,4 +16,4 @@ commands:
|
|||||||
blockandseek:
|
blockandseek:
|
||||||
aliases:
|
aliases:
|
||||||
- bs
|
- bs
|
||||||
usage: "Usage: /blockandseek [subcommand]"
|
usage: "Usage: /blockandseek [subcommand]"
|
||||||
|
|||||||
Reference in New Issue
Block a user