some fixes. last dirty commit

This commit is contained in:
2025-12-08 20:17:05 +03:00
parent 3cbcfb385f
commit a135134b55
31 changed files with 1044 additions and 516 deletions

60
.idea/workspace.xml generated
View File

@@ -5,58 +5,37 @@
</component>
<component name="ChangeListManager">
<list default="true" id="46146984-f46a-4efa-a29f-c0632c66dbea" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.idea/modules/hdvtdev.BlockAndSeek.main.iml" afterDir="false" />
<change afterPath="$PROJECT_DIR$/BlockAndSeekPack/assets/minecraft/textures/misc/pumpkinblur.png" afterDir="false" />
<change afterPath="$PROJECT_DIR$/BlockAndSeekPack/pack.mcmeta" afterDir="false" />
<change afterPath="$PROJECT_DIR$/deploy.sh" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/GlowUtil.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/DashItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/FaceChangingItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/FreezeItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Grenade.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/LeaveItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/MenuItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/MorphItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Pistol.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/SoundMaker.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/FrecamManager.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekButton.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/Items.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.classpath" beforeDir="false" afterPath="$PROJECT_DIR$/.classpath" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/special/AntiGravity.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/special/Chorus.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/special/DeathBelt.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/special/Decoy.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/CommandManager.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/PartyManager.java" afterDir="false" />
<change afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/Party.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.gradle/buildOutputCleanup/buildOutputCleanup.lock" beforeDir="false" afterPath="$PROJECT_DIR$/.gradle/buildOutputCleanup/buildOutputCleanup.lock" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.gitignore" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/.name" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/ant.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/compiler.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/compiler.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/gradle.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/gradle.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/hotswap_agent.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/misc.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/modules.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/modules/BlockAndSeek.iml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/saveactions_settings.xml" beforeDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/vcs.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.gradle" beforeDir="false" afterPath="$PROJECT_DIR$/build.gradle" afterDir="false" />
<change beforePath="$PROJECT_DIR$/build.xml" beforeDir="false" afterPath="$PROJECT_DIR$/build.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" beforeDir="false" afterPath="$PROJECT_DIR$/gradle/wrapper/gradle-wrapper.properties" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/BlockAndSeek.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/BlocksGenerator.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Config.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Config.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Keys.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Keys.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Utils.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/Utils.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/eventListeners/ForceControlEventListener.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/eventListeners/RequiredEventListener.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/DashItem.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/DashItem.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Grenade.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Grenade.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/MorphItem.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/special/MorphItem.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Pistol.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/items/Pistol.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/GamesManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/ItemManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/MapsManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/PropManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/PropManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/TranslationManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/managers/WorldManager.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/menus/GamesMenu.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/menus/MapsMenu.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekGame.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekItem.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/BlockAndSeekMap.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/Items.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/Items.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/LazyLocation.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/objects/TranslationKey.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/roulette/RouletteCreator.java" afterDir="false" />
<change beforePath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java" beforeDir="false" afterPath="$PROJECT_DIR$/src/main/java/hdvtdev/blockandseek/roulette/RouletteList.java" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
@@ -92,6 +71,7 @@
<option name="RECENT_TEMPLATES">
<list>
<option value="Enum" />
<option value="Record" />
<option value="Class" />
</list>
</option>
@@ -121,7 +101,7 @@
&quot;RunOnceActivity.git.unshallow&quot;: &quot;true&quot;,
&quot;SHARE_PROJECT_CONFIGURATION_FILES&quot;: &quot;true&quot;,
&quot;SHELLCHECK.PATH&quot;: &quot;/home/hadvart/.local/share/JetBrains/IdeaIC2025.2/Shell Script/shellcheck&quot;,
&quot;git-widget-placeholder&quot;: &quot;dev/1.20.6&quot;,
&quot;git-widget-placeholder&quot;: &quot;dev-1.20.6&quot;,
&quot;kotlin-language-version-configured&quot;: &quot;true&quot;,
&quot;last_opened_file_path&quot;: &quot;/home/hadvart/IdeaProjects/blockandseek/BlockAndSeekPack/assets/minecraft/textures/misc&quot;,
&quot;settings.editor.selected.configurable&quot;: &quot;preferences.lookFeel&quot;

View File

@@ -7,12 +7,21 @@ import hdvtdev.blockandseek.items.Pistol;
import hdvtdev.blockandseek.managers.*;
import hdvtdev.blockandseek.objects.*;
import hdvtdev.blockandseek.roulette.RouletteCreator;
import java.io.File;
import java.time.Duration;
import java.util.*;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.LibsDisguises;
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.kyori.adventure.text.event.HoverEvent;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.*;
import org.bukkit.attribute.Attribute;
@@ -33,15 +42,17 @@ import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.RayTraceResult;
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.paper.LegacyPaperCommandManager;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.Suggestion;
import org.incendo.cloud.suggestion.SuggestionProvider;
public class BlockAndSeek extends JavaPlugin {
private static JavaPlugin javaPlugin;
private static LegacyPaperCommandManager<CommandSender> commandManager;
private static final String perm = "blockandseek.manage";
public static Plugin getInstance() {
@@ -69,12 +80,12 @@ public class BlockAndSeek extends JavaPlugin {
javaPlugin = this;
LibsDisguises libsDisguises =
(LibsDisguises) Bukkit.getPluginManager().getPlugin(
"LibsDisguises"
);
(LibsDisguises) Bukkit.getPluginManager().getPlugin(
"LibsDisguises"
);
if (libsDisguises == null) {
getLogger().severe(
"LibsDisguises not found! It's required for the plugin to work!"
"LibsDisguises not found! It's required for the plugin to work!"
);
super.onDisable();
}
@@ -82,17 +93,17 @@ public class BlockAndSeek extends JavaPlugin {
this.init();
PluginCommand command = Objects.requireNonNull(
getCommand("blockandseek")
getCommand("blockandseek")
);
PluginManager manager = getServer().getPluginManager();
boolean forceControl = Config.forceControl();
if (forceControl) getLogger().info("Using force control");
manager.registerEvents(
forceControl
? new ForceControlEventListener()
: new EventListener(),
this
forceControl
? new ForceControlEventListener()
: new EventListener(),
this
);
manager.registerEvents(new RequiredEventListener(), this);
}
@@ -125,294 +136,15 @@ public class BlockAndSeek extends JavaPlugin {
TranslationManager.loadLanguages();
MapsManager.loadMaps();
commandManager = LegacyPaperCommandManager.createNative(
this,
ExecutionCoordinator.simpleCoordinator()
);
if (
commandManager.hasCapability(
CloudBukkitCapabilities.NATIVE_BRIGADIER
)
) {
try {
commandManager.registerBrigadier();
} catch (IllegalStateException ignored) {}
}
this.registerCommands();
CommandManager.registerCommands("blockandseek");
CommandManager.registerCommands("bs");
} catch (Exception e) {
getLogger().severe("Cloud err: " + e.getMessage());
e.printStackTrace();
}
}
private static final UUID ZOOM_UUID = UUID.randomUUID();
private void registerCommands() {
var root = commandManager.commandBuilder("blockandseek");
var editBase = root
.literal("editMap")
.required(
"map_name",
StringParser.stringParser(),
MapsManager.mapSuggestions
);
//edit commands
commandManager.command(
editBase
.literal("setLobby")
.required("location", LocationParser.locationParser())
.handler(ctx -> {})
);
commandManager.command(
editBase
.literal("setLocation")
.required("location", LocationParser.locationParser())
.handler(ctx -> {
String configName = ctx.get("config_name");
Location location = ctx.get("location");
ctx
.sender()
.sendMessage(
"В конфиге " +
configName +
" точка установлена: " +
location.toString()
);
})
);
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("testGlow")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
RayTraceResult result = player.rayTraceBlocks(128);
if (result != null) {
Block block = result.getHitBlock();
if (block != null) {
GlowUtil.highlightBlock(player, block.getLocation().toBlockLocation());
}
}
}
})
);
commandManager.command(
root
.literal("menuTest")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
player
.getInventory()
.addItem(ItemManager.getItem(Items.MENU).getTranslated(player));
}
})
);
commandManager.command(
root
.literal("morphItem")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
player
.getInventory()
.addItem(ItemManager.getItem(Items.MORPH).getTranslated(player));
}
})
);
commandManager.command(
root
.literal("pistolGet")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
player
.getInventory()
.addItem(ItemManager.getItem(Items.PISTOL).getTranslated(player));
}
})
);
commandManager.command(
root
.literal("clear")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
AttributeInstance attribute = player.getAttribute(
Attribute.GENERIC_MOVEMENT_SPEED
);
if (
attribute != null &&
attribute.getModifier(ZOOM_UUID) != null
) {
attribute.removeModifier(ZOOM_UUID);
}
}
})
);
commandManager.command(
root
.literal("pistolTest")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
player.getInventory().addItem(ItemManager.getItem(Items.MORPH).getTranslated(player));
}
})
);
commandManager.command(
root
.literal("grenadeTest")
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
player.getInventory().addItem(ItemManager.getItem(Items.GRENADE).getTranslated(player));
}
})
);
commandManager.command(
root
.literal("reload")
.handler(ctx -> {
var sender = ctx.sender();
if (Config.loadConfig()) {
MapsManager.loadMaps();
TranslationManager.loadLanguages();
sender.sendMessage("Configs were reloaded!");
} else sender.sendMessage("Failed to reload configs! Check server logs.");
})
);
commandManager.command(
root
.literal("configTest")
.handler(ctx -> ctx.sender().sendMessage(Config.toStaticString()))
);
commandManager.command(
root
.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)
.required(
"map_name",
StringParser.stringParser(),
MapsManager.mapSuggestions
)
.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
.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);
}
})
);
}
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,
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);
}
}

View File

@@ -24,7 +24,7 @@ public class BlocksGenerator {
private static final Map<String, List<PropBlock>> cached = new HashMap<>();
static {
// --- 1. ГРАВИТАЦИЯ (Сыпучие) ---
BLACKLIST.add(Material.SAND);
BLACKLIST.add(Material.RED_SAND);
BLACKLIST.add(Material.GRAVEL);
@@ -32,20 +32,19 @@ public class BlocksGenerator {
BLACKLIST.add(Material.ANVIL);
BLACKLIST.add(Material.CHIPPED_ANVIL);
BLACKLIST.add(Material.DAMAGED_ANVIL);
BLACKLIST.add(Material.POINTED_DRIPSTONE); // Сталактит (может упасть)
BLACKLIST.add(Material.SCAFFOLDING); // Строительные леса
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.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.REDSTONE_BLOCK);
BLACKLIST.add(Material.REPEATER);
BLACKLIST.add(Material.COMPARATOR);
BLACKLIST.add(Material.OBSERVER);
@@ -70,20 +69,19 @@ public class BlocksGenerator {
BLACKLIST.add(Material.REPEATING_COMMAND_BLOCK);
BLACKLIST.add(Material.CHAIN_COMMAND_BLOCK);
BLACKLIST.add(Material.LIGHTNING_ROD);
BLACKLIST.add(Material.BELL); // Колокол
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.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);
@@ -126,13 +124,12 @@ public class BlocksGenerator {
BLACKLIST.add(Material.SOUL_LANTERN);
BLACKLIST.add(Material.CHAIN);
BLACKLIST.add(Material.END_ROD);
BLACKLIST.add(Material.IRON_BARS); // Обычно некрасиво в топах
BLACKLIST.add(Material.IRON_BARS);
BLACKLIST.add(Material.LADDER);
BLACKLIST.add(Material.SNOW); // Снежный покров (тонкий)
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);
@@ -146,7 +143,6 @@ public class BlocksGenerator {
BLACKLIST.add(Material.BEEHIVE);
BLACKLIST.add(Material.BEE_NEST);
// --- 5. ТЕХНИЧЕСКИЕ И ПРОЗРАЧНЫЕ ---
BLACKLIST.add(Material.BARRIER);
BLACKLIST.add(Material.STRUCTURE_VOID);
BLACKLIST.add(Material.STRUCTURE_BLOCK);
@@ -154,40 +150,34 @@ public class BlocksGenerator {
BLACKLIST.add(Material.LIGHT);
BLACKLIST.add(Material.SPAWNER);
BLACKLIST.add(Material.COBWEB);
BLACKLIST.add(Material.SLIME_BLOCK); // Спорно, но липкий
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") // Кораллы (дохнут без воды)
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. Воздух
public static boolean isSupported(Material type) {
if (type.isAir()) return false;
// 2. Черный список (самая надежная проверка)
if (BLACKLIST.contains(type)) {
return false;
}
// 3. Дополнительная защита: блок должен быть твердым
// (Это отсечет то, что мы могли случайно забыть в списке, типа нитки/String)
return type.isSolid();
}
@ApiStatus.Experimental
public static void getSortedBlockStats(Location center, int chunkRadius, Consumer<List<Map.Entry<Material, Long>>> callback) {
World world = center.getWorld();
if (world == null) return;

View File

@@ -13,6 +13,7 @@ import hdvtdev.blockandseek.objects.LazyLocation;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.WorldCreator;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
@@ -69,6 +70,10 @@ public class Config extends OkaeriConfig {
return config.spawn.getLocation();
}
public static void teleportToSpawn(Player player) {
config.spawn.teleport(player);
}
public static String toStaticString() {
return String.format("BlockAndSeekConfig[forceControl = %s, spawn = %s, enableDebugCommands = %s]", forceControl(), spawn(), debugEnabled());
}

View File

@@ -2,6 +2,7 @@ package hdvtdev.blockandseek;
import hdvtdev.blockandseek.managers.PropManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import me.libraryaddict.disguise.DisguiseAPI;
import org.bukkit.GameMode;
import org.bukkit.attribute.Attribute;
@@ -40,6 +41,7 @@ public final class Utils {
player.getInventory().setArmorContents(null);
player.getInventory().setExtraContents(null);
PropManager.removePlayer(player);
BlockAndSeekItem.removeCooldownImune(player.getUniqueId());
player.setGameMode(GameMode.SURVIVAL);
@@ -47,7 +49,7 @@ public final class Utils {
player.getAttribute(Attribute.GENERIC_MAX_HEALTH).setBaseValue(20.0);
}
player.setHealth(20.0);
player.clearActivePotionEffects();
player.setFoodLevel(20);
player.setSaturation(5.0f);
player.setExhaustion(0f);
@@ -69,4 +71,28 @@ public final class Utils {
}
private static final String serverVersion = org.bukkit.Bukkit.getBukkitVersion().split("-")[0];
public static boolean isVersionAtLeast(String ver) {
String[] serverParts = serverVersion.split("\\.");
String[] targetParts = ver.split("\\.");
boolean isHighEnough = true;
int length = Math.max(serverParts.length, targetParts.length);
for (int i = 0; i < length; i++) {
int sPart = i < serverParts.length ? Integer.parseInt(serverParts[i]) : 0;
int tPart = i < targetParts.length ? Integer.parseInt(targetParts[i]) : 0;
if (sPart != tPart) {
isHighEnough = sPart > tPart;
break;
}
}
return isHighEnough;
}
}

View File

@@ -3,15 +3,14 @@ package hdvtdev.blockandseek.eventListeners;
import hdvtdev.blockandseek.Config;
import hdvtdev.blockandseek.Utils;
import hdvtdev.blockandseek.managers.ItemManager;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.*;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.weather.WeatherChangeEvent;
@@ -19,7 +18,6 @@ import org.bukkit.event.world.TimeSkipEvent;
public class ForceControlEventListener implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
@@ -29,6 +27,12 @@ public class ForceControlEventListener implements Listener {
ItemManager.defaultInventory(player);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerDeath(PlayerDeathEvent event) {
event.setCancelled(true);
Config.teleportToSpawn(event.getPlayer());
}
@EventHandler
public void onWeatherChange(WeatherChangeEvent event) {
if (event.getCause() != WeatherChangeEvent.Cause.COMMAND) event.setCancelled(true);
@@ -71,5 +75,14 @@ public class ForceControlEventListener implements Listener {
}
}
private static final String worldName = Config.spawn().getWorld().getName();
@EventHandler
private void onEntityDamage(EntityDamageByEntityEvent event) {
if (event.getDamager().getWorld().getName().equals(worldName)) {
event.setCancelled(true);
}
}
}

View File

@@ -1,43 +1,17 @@
package hdvtdev.blockandseek.eventListeners;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.Keys;
import hdvtdev.blockandseek.Utils;
import hdvtdev.blockandseek.GuiHolder;
import hdvtdev.blockandseek.managers.PropManager;
import hdvtdev.blockandseek.menus.GamesMenu;
import hdvtdev.blockandseek.*;
import hdvtdev.blockandseek.managers.PartyManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import net.kyori.adventure.text.Component;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockDamageEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDismountEvent;
import org.bukkit.event.entity.EntityRegainHealthEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.server.ServerLoadEvent;
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 org.bukkit.util.RayTraceResult;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public class RequiredEventListener implements Listener {
@@ -51,42 +25,16 @@ public class RequiredEventListener implements Listener {
//player.setResourcePack("https://gitea.hdvtdev.tech/hdvt/idk/raw/branch/main/pack.zip", "f32bf084b01b57601d7ae3711e5c88e31ce637a3", true);
}
@EventHandler
public void onBlockDamage(BlockDamageEvent event) {
}
@EventHandler
public void onPlayerClick(PlayerInteractEvent event) {
BlockAndSeekItem item = BlockAndSeekItem.tryCast(event.getItem());
if (item != null) {
item.onRawInteract(event);
}
if (item != null) item.onRawInteract(event);
}
@EventHandler
public void onEntityDismount(EntityDismountEvent event) {
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
}
@EventHandler
public void onPlayerDeath(PlayerDeathEvent event) {
}
@EventHandler
public void onInventoryClose(InventoryCloseEvent event) {
private void onPlayerLeave(PlayerQuitEvent event) {
Player player = event.getPlayer();
//todo party leave
}
@EventHandler
@@ -97,14 +45,4 @@ public class RequiredEventListener implements Listener {
}
}
@EventHandler
public void onRegainHealth(EntityRegainHealthEvent event) {
}
@EventHandler
public void onPlayerDamage(EntityDamageByEntityEvent event) {
}
}

View File

@@ -25,7 +25,7 @@ public class DashItem extends BlockAndSeekItem {
public DashItem() {
super(Items.DASH, Duration.ofSeconds(75), ClickAction.RIGHT_CLICK);
super(Items.DASH, Duration.ofSeconds(75), ClickAction.RIGHT_CLICK, false);
}
@Override

View File

@@ -13,6 +13,7 @@ import org.bukkit.block.Block;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
@@ -30,7 +31,7 @@ import java.util.stream.Collectors;
public class Grenade extends BlockAndSeekItem {
public Grenade() {
super(Items.GRENADE, Duration.ofSeconds(10), ClickAction.RIGHT_CLICK);
super(Items.GRENADE, Duration.ofSeconds(20), ClickAction.RIGHT_CLICK);
}
@Override
@@ -69,7 +70,7 @@ public class Grenade extends BlockAndSeekItem {
Location hitLoc = hit.getHitPosition().toLocation(location.getWorld());
int radius = 4;
List<UUID> props = hitLoc.getNearbyEntities(radius, radius, radius).stream().filter(entity -> entity instanceof Player p && !p.equals(player))
List<UUID> props = hitLoc.getNearbyEntities(radius, radius, radius).stream().filter(entity -> entity instanceof LivingEntity p && !p.equals(player))
.map(Entity::getUniqueId).collect(Collectors.toCollection(ArrayList::new));
@@ -106,11 +107,15 @@ public class Grenade extends BlockAndSeekItem {
if (!props.isEmpty()) {
player.playSound(player, Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f);
World world = location.getWorld();
for (UUID uuid : props) {
Player hider = Bukkit.getPlayer(uuid);
LivingEntity hider = (LivingEntity) world.getEntity(uuid);
if (hider != null) {
hider.damage(13.5);
Utils.healSeeker(player, 13.5);
if (hider instanceof Player) {
Utils.healSeeker(player, 13.5);
} else Utils.healSeeker(player, 5);
}
}
} else Utils.damageSeeker(player, 25);

View File

@@ -11,6 +11,7 @@ import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
@@ -70,14 +71,16 @@ public class Pistol extends BlockAndSeekItem {
if (result != null) {
Entity hitEntity = result.getHitEntity();
if (hitEntity instanceof Player target) {
if (hitEntity instanceof LivingEntity target) {
target.damage(5);
double strength = 0.1;
double x = -target.getLocation().getDirection().getX();
double z = -target.getLocation().getDirection().getZ();
target.knockback(strength, x, z);
player.playSound(player, Sound.ENTITY_ARROW_HIT_PLAYER, 1f, 1f);
Utils.healSeeker(player, 5);
if (target instanceof Player) {
Utils.healSeeker(player, 5);
} else Utils.healSeeker(player, 2.5);
} else {
Block hitBlock = result.getHitBlock();
if (hitBlock != null) {

View File

@@ -0,0 +1,60 @@
package hdvtdev.blockandseek.items.special;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.managers.PropManager;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import org.bukkit.EntityEffect;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
public class AntiGravity extends BlockAndSeekItem {
public AntiGravity() {
super(Items.ANTI_GRAVITY);
}
@Override
protected void onInteract(@NotNull PlayerInteractEvent event) {
Location location = event.getPlayer().getLocation();
var players = location.getWorld().getNearbyPlayers(location, 64);
for (Player player : players) {
PropManager.forceUnfreeze(player.getUniqueId());
player.addPotionEffect(new PotionEffect(PotionEffectType.LEVITATION, 2, 20, false, false, false));
player.setGravity(false);
player.setAllowFlight(true);
}
new BukkitRunnable() {
@Override
public void run() {
for (Player player : players) {
player.setGravity(true);
player.setAllowFlight(false);
}
}
}.runTaskLater(BlockAndSeek.getInstance(), 15 * 20);
}
@Override
protected @NotNull ItemStack buildRawItem() {
ItemStack itemStack = new ItemStack(Material.POPPED_CHORUS_FRUIT);
itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true));
return itemStack;
}
@Override
public @NotNull ItemStack getTranslated(Player player) {
return TranslationManager.translateItem(player, getCloned(), TranslationKey.ANTI_GRAVITY);
}
}

View File

@@ -0,0 +1,99 @@
package hdvtdev.blockandseek.items.special;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.ThreadLocalRandom;
@ApiStatus.Experimental
public class Chorus extends BlockAndSeekItem {
private static final int distantion = 24;
public Chorus() {
super(Items.CHORUS);
}
@Override
protected void onInteract(@NotNull PlayerInteractEvent event) {
Player player = event.getPlayer();
if (event.getAction().isRightClick()) {
teleport(player);
} else {
Location location = player.getLocation();
location.getWorld().getNearbyPlayers(location, 5).stream().filter(p -> !p.equals(player)).findAny().ifPresent(Chorus::teleport);
}
}
private static void teleport(Player player) {
new BukkitRunnable() {
int jumpsLeft = 5;
@Override
public void run() {
if (!player.isOnline() || jumpsLeft <= 0) {
this.cancel();
return;
}
Location origin = player.getLocation();
for (int i = 0; i < 48; i++) {
//i probably need distantion + 1 but im too lazy)
int x = ThreadLocalRandom.current().nextInt(-distantion, distantion);
int y = ThreadLocalRandom.current().nextInt(-distantion, distantion);
int z = ThreadLocalRandom.current().nextInt(-distantion, distantion);
Location target = origin.clone().add(x, y, z);
if (target.getBlock().isPassable() &&
target.clone().add(0, 1, 0).getBlock().isPassable() &&
target.clone().add(0, -1, 0).getBlock().getType().isSolid()) {
target.setX(Math.floor(target.getX()) + 0.5);
target.setZ(Math.floor(target.getZ()) + 0.5);
target.setYaw(origin.getYaw());
target.setPitch(origin.getPitch());
player.teleport(target, PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT);
player.getWorld().playSound(target, Sound.ITEM_CHORUS_FRUIT_TELEPORT, 1.0f, 1.0f);
break;
}
}
jumpsLeft--;
}
}.runTaskTimer(BlockAndSeek.getInstance(), 0L, 4);
}
@Override
protected @NotNull ItemStack buildRawItem() {
ItemStack itemStack = new ItemStack(Material.CHORUS_FRUIT);
itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true));
return itemStack;
}
@Override
public @NotNull ItemStack getTranslated(Player player) {
return TranslationManager.translateItem(player, getCloned(), TranslationKey.CHORUS);
}
}

View File

@@ -0,0 +1,52 @@
package hdvtdev.blockandseek.items.special;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import org.bukkit.*;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
public class DeathBelt extends BlockAndSeekItem {
public DeathBelt() {
super(Items.DEATH_BELT);
}
private static final double radius = 3.0;
@Override
protected void onInteract(@NotNull PlayerInteractEvent event) {
Player player = event.getPlayer();
player.getInventory().remove(event.getItem());
Location location = player.getLocation();
World world = location.getWorld();
world.spawnParticle(Particle.EXPLOSION, location, 1);
world.playSound(location, Sound.ENTITY_GENERIC_EXPLODE, 1f, 1f);
for (Entity entity : location.getWorld().getNearbyEntities(location, radius, radius, radius)) {
if (entity instanceof LivingEntity victim && entity.getLocation().distance(location) <= radius) {
victim.damage(55.0);
}
}
}
@Override
protected @NotNull ItemStack buildRawItem() {
ItemStack itemStack = new ItemStack(Material.TNT_MINECART);
itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true));
return itemStack;
}
@Override
public @NotNull ItemStack getTranslated(Player player) {
return TranslationManager.translateItem(player, getCloned(), TranslationKey.DEATH_BELT);
}
}

View File

@@ -0,0 +1,72 @@
package hdvtdev.blockandseek.items.special;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.managers.PropManager;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import me.libraryaddict.disguise.DisguiseAPI;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.entity.Villager;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
import java.time.Duration;
public class Decoy extends BlockAndSeekItem {
public Decoy() {
super(Items.DECOY, Duration.ZERO, ClickAction.RIGHT_CLICK, true);
}
@Override
protected void onInteract(@NotNull PlayerInteractEvent event) {
Player player = event.getPlayer();
Location location = player.getLocation();
player.getInventory().remove(event.getItem());
if (PropManager.getProp(location.toBlockLocation()) != null) {
PropManager.forceUnfreeze(player.getUniqueId());
}
player.setVisibleByDefault(false);
DisguiseAPI.disguiseNextEntity(DisguiseAPI.getDisguise(player));
Villager villager = location.getWorld().spawn(location, Villager.class, v -> {
v.setProfession(Villager.Profession.NITWIT);
v.setAdult();
v.setAgeLock(true);
v.setSilent(true);
v.setAI(false);
});
new BukkitRunnable() {
@Override
public void run() {
villager.setAI(true);
player.setVisibleByDefault(true);
}
}.runTaskLater(BlockAndSeek.getInstance(), 3 * 20);
}
@Override
protected @NotNull ItemStack buildRawItem() {
ItemStack itemStack = new ItemStack(Material.FIREWORK_STAR);
itemStack.editMeta(itemMeta -> itemMeta.addEnchant(Enchantment.INFINITY, 1, true));
return itemStack;
}
@Override
public @NotNull ItemStack getTranslated(Player player) {
return TranslationManager.translateItem(player, getCloned(), TranslationKey.DECOY);
}
}

View File

@@ -1,5 +1,6 @@
package hdvtdev.blockandseek.items;
package hdvtdev.blockandseek.items.special;
import hdvtdev.blockandseek.BlocksGenerator;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
@@ -26,14 +27,25 @@ public class MorphItem extends BlockAndSeekItem {
protected void onInteract(@NotNull PlayerInteractEvent event) {
Block block = event.getClickedBlock();
Player player = event.getPlayer();
ItemStack itemStack = event.getItem();
if (block == null) {
RayTraceResult result = player.rayTraceBlocks(128);
if (result != null) {
block = result.getHitBlock();
} else return;
}
if (block == null) return;
if (!BlocksGenerator.isSupported(block.getType())) {
player.sendMessage(TranslationKey.BLOCK_NOT_SUPPORTED.translate(player));
return;
}
player.getInventory().remove(itemStack);
DisguiseAPI.disguiseToAll(player, new MiscDisguise(DisguiseType.FALLING_BLOCK, new ItemStack(block.getType())));
}

View File

@@ -0,0 +1,143 @@
package hdvtdev.blockandseek.managers;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.Config;
import hdvtdev.blockandseek.GlowUtil;
import hdvtdev.blockandseek.objects.BlockAndSeekGame;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.block.Block;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.RayTraceResult;
import org.incendo.cloud.Command;
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
import org.incendo.cloud.bukkit.parser.location.LocationParser;
import org.incendo.cloud.execution.ExecutionCoordinator;
import org.incendo.cloud.paper.LegacyPaperCommandManager;
import org.incendo.cloud.parser.standard.StringParser;
import org.incendo.cloud.suggestion.SuggestionProvider;
import java.util.List;
import java.util.UUID;
import java.util.stream.Stream;
public final class CommandManager {
private static final LegacyPaperCommandManager<CommandSender> commandManager;
private static final String perm = "blockandseek.manage";
static {
commandManager = LegacyPaperCommandManager.createNative(
BlockAndSeek.getInstance(),
ExecutionCoordinator.simpleCoordinator()
);
if (
commandManager.hasCapability(
CloudBukkitCapabilities.NATIVE_BRIGADIER
)
) {
try {
commandManager.registerBrigadier();
} catch (IllegalStateException ignored) {
}
}
}
public static void registerCommands() {
var root = commandManager.commandBuilder("blockandseek", "bs");
if (Config.debugEnabled()) testCommands(root);
var partyBase = root.literal("party");
var reloadBase = root.literal("reload").permission(perm); //all, config, langs, maps
var createBase = root.literal("create"); //party, map, game
var mapBase = root.literal("map").permission(perm); //name <set action> <val>
var editMapBase = mapBase.literal("set");
commandManager.command(
createBase
.literal("map")
.required("worldName", StringParser.stringParser(), MapsManager.worldSuggestions)
.handler(ctx -> {
MapsManager.addMap(ctx.get("worldName"));
})
);
commandManager.command(
partyBase
.required("name", StringParser.stringParser(),
SuggestionProvider.blockingStrings((ctx, input) ->
Stream.concat(Bukkit.getOnlinePlayers().stream()
.map(Player::getName).filter(n -> !n.equals(ctx.sender().getName())), Stream.of("leave", "info"))
.toList()
)
)
.handler(ctx -> { /* ... */ })
);
commandManager.command(
partyBase
.literal("join")
.required("playerId", StringParser.stringParser())
.required("partyId", StringParser.stringParser())
.handler(ctx -> {
if (ctx.sender() instanceof Player player) {
Player owner = Bukkit.getPlayer(UUID.fromString(ctx.get("playerId")));
if (owner != null) {
PartyManager.joinParty(player.getUniqueId(), ctx.get("partyID"));
player.sendMessage("Вы вступили в пати " + owner.getUniqueId());
} else player.sendMessage("Пати не существует!");
}
})
);
commandManager.command(
reloadBase.literal("languages").handler(ctx -> TranslationManager.loadLanguages())
);
commandManager.command(
reloadBase.literal("maps").handler(ctx -> MapsManager.loadMaps())
);
commandManager.command(
reloadBase.literal("config").handler(ctx -> Config.loadConfig())
);
commandManager.command(
reloadBase.literal("all").handler(ctx -> {
Config.loadConfig();
MapsManager.loadMaps();
TranslationManager.loadLanguages();
})
);
}
private static void testCommands(Command.Builder<CommandSender> root) {
}
}

View File

@@ -29,6 +29,10 @@ public class GamesManager {
public static BlockAndSeekGame createGame(String name) {
if (games.containsKey(name)) {
return games.get(name);
}
BlockAndSeekMap map = MapsManager.getMap(name);
BlockAndSeekGame game = new BlockAndSeekGame(name, map);
games.put(name, game);

View File

@@ -1,12 +1,11 @@
package hdvtdev.blockandseek.managers;
import hdvtdev.blockandseek.Keys;
import hdvtdev.blockandseek.items.*;
import hdvtdev.blockandseek.items.special.*;
import hdvtdev.blockandseek.objects.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Items;
import hdvtdev.blockandseek.objects.TranslationKey;
import lombok.Getter;
import net.kyori.adventure.text.Component;
import org.bukkit.Color;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@@ -16,18 +15,14 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.bukkit.persistence.PersistentDataType;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import static hdvtdev.blockandseek.objects.TranslationKey.*;
import java.util.*;
public class ItemManager {
private static final Map<Items, BlockAndSeekItem> items = new EnumMap<>(Items.class);
private static final Map<Items, BlockAndSeekItem> specialItems = new EnumMap<>(Items.class);
static {
items.put(Items.MORPH, new MorphItem());
@@ -38,6 +33,16 @@ public class ItemManager {
items.put(Items.PISTOL, new Pistol());
items.put(Items.GRENADE, new Grenade());
items.put(Items.FREEZE, new FreezeItem());
items.put(Items.DEATH_BELT, new DeathBelt());
items.put(Items.DECOY, new Decoy());
items.put(Items.CHORUS, new Chorus());
items.put(Items.ANTI_GRAVITY, new AntiGravity());
specialItems.put(Items.DEATH_BELT, new DeathBelt());
specialItems.put(Items.DECOY, new Decoy());
specialItems.put(Items.MORPH, new MorphItem());
specialItems.put(Items.ANTI_GRAVITY, new AntiGravity());
//specialItems.put(Items.CHORUS, new Chorus());
}
@@ -45,6 +50,12 @@ public class ItemManager {
return items.get(item);
}
public static List<BlockAndSeekItem> getSpecItems() {
List<BlockAndSeekItem> itemList = new ArrayList<>(specialItems.values());
Collections.shuffle(itemList);
return itemList;
}
private static final ItemStack seekerSword = new ItemStack(Material.WOODEN_SWORD);
private static final ItemStack seekerHelmet = new ItemStack(Material.LEATHER_HELMET);
private static final ItemStack seekerChestplate = new ItemStack(Material.LEATHER_CHESTPLATE);

View File

@@ -0,0 +1,127 @@
package hdvtdev.blockandseek.managers;
import hdvtdev.blockandseek.objects.Party;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.*;
import java.util.*;
public class PartyManager {
public enum Code {
NOT_EXIST, // Пати не существует
ALREADY_IN_PARTY, // Игрок уже в пати
NOT_IN_PARTY, // Игрок не в пати (для команд выхода/кика)
NOT_AN_OWNER, OK // Успешно
}
private static final Map<UUID, Party> playerPartyMap = new HashMap<>();
private static final Map<UUID, Party> partiesById = new HashMap<>();
/**
* Создать новую пати.
*/
public static Code createParty(@NotNull UUID owner) {
if (playerPartyMap.containsKey(owner)) {
return Code.ALREADY_IN_PARTY;
}
Party party = new Party(owner);
partiesById.put(party.getPartyId(), party);
playerPartyMap.put(owner, party);
return Code.OK;
}
public static Code joinParty(@NotNull UUID player, @NotNull UUID partyId) {
if (playerPartyMap.containsKey(player)) {
return Code.ALREADY_IN_PARTY;
}
Party party = partiesById.get(partyId);
if (party == null) {
return Code.NOT_EXIST;
}
party.addMember(player);
playerPartyMap.put(player, party);
return Code.OK;
}
public static Code joinPartyByMember(@NotNull UUID player, @NotNull UUID memberInParty) {
Party party = playerPartyMap.get(memberInParty);
if (party == null) {
return Code.NOT_EXIST;
}
return joinParty(player, party.getPartyId());
}
public static Code leaveParty(@NotNull UUID player) {
Party party = playerPartyMap.get(player);
if (party == null) {
return Code.NOT_IN_PARTY;
}
// Удаляем игрока из списка участников и из мапы
party.removeMember(player);
playerPartyMap.remove(player);
// Если пати опустела - удаляем её полностью
if (party.getMembers().isEmpty()) {
partiesById.remove(party.getPartyId());
return Code.OK;
}
if (party.getOwner().equals(player)) {
UUID newOwner = party.getMembers().iterator().next();
party.setOwner(newOwner);
//todo send message to owner
}
return Code.OK;
}
public static Code disbandParty(@NotNull UUID requester) {
Party party = playerPartyMap.get(requester);
if (party == null) {
return Code.NOT_IN_PARTY;
}
// Проверяем, является ли запрашивающий лидером
if (!party.getOwner().equals(requester)) {
return Code.NOT_AN_OWNER; // Технически "права не существуют"
}
// Удаляем записи о пати у всех участников
for (UUID member : party.getMembers()) {
playerPartyMap.remove(member);
}
// Удаляем саму пати
partiesById.remove(party.getPartyId());
party.getMembers().clear();
return Code.OK;
}
@Nullable
public static Party getParty(@NotNull UUID player) {
return playerPartyMap.get(player);
}
}

View File

@@ -18,14 +18,15 @@ import org.bukkit.entity.Player;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class PropManager {
private static final Map<UUID, PropData> players = new ConcurrentHashMap<>();
private static final Map<Location, UUID> props = new ConcurrentHashMap<>();
private static final Map<UUID, PropData> players = new HashMap<>();
private static final Map<Location, UUID> props = new HashMap<>();
private PropManager() {}
@@ -73,6 +74,7 @@ public class PropManager {
player.teleport(propLocation.toCenterLocation());
player.setInvulnerable(false);
player.setInvisible(false);
player.setVisibleByDefault(true);
player.setGameMode(GameMode.SURVIVAL);
@@ -103,6 +105,7 @@ public class PropManager {
centerLocation.setY(centerLocation.getY() - 0.85);
player.setInvulnerable(true);
player.setInvisible(true);
player.setVisibleByDefault(false);
player.setFreezeTicks(40);

View File

@@ -1,14 +1,12 @@
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.BlockAndSeekItem;
import hdvtdev.blockandseek.objects.Translation;
import hdvtdev.blockandseek.objects.TranslationKey;
import lombok.Getter;
@@ -21,6 +19,7 @@ import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.*;
@@ -28,7 +27,8 @@ import java.util.concurrent.atomic.AtomicReference;
public final class TranslationManager {
private TranslationManager() {}
private TranslationManager() {
}
public static final String defaultLanguage = "en_US";
public static final MiniMessage mm = MiniMessage.miniMessage();
@@ -38,7 +38,6 @@ public final class TranslationManager {
public static final String bracedPrefix = "<gradient:#FFAA00:#FFD700><bold>[BlockAndSeek]</bold></gradient>";
private static final Map<String, EnumMap<TranslationKey, String>> translations = new HashMap<>();
private static final Map<String, BlockAndSeekItem> itemTranslations = new HashMap<>();
public static Component get(Player player, TranslationKey key, String... placeholders) {
return get(player.locale().toString(), key, placeholders);
@@ -55,7 +54,7 @@ public final class TranslationManager {
}
public static ItemStack translateItem(Player player, ItemStack itemStack, TranslationKey key, String... placeholders) {
ItemMeta itemMeta = itemStack.getItemMeta();
ItemMeta itemMeta = itemStack.getItemMeta();
itemMeta.displayName(get(player, key, placeholders));
itemStack.setItemMeta(itemMeta);
return itemStack;
@@ -89,6 +88,55 @@ public final class TranslationManager {
}
@SafeVarargs
private static String processPlaceholders(@NotNull String text, @NotNull Map.Entry<String, String>... placeholders) {
if (placeholders.length == 0) return text;
Map<String, String> params = Map.ofEntries(placeholders);
StringBuilder sb = new StringBuilder(text.length() + 32);
int cursor = 0;
int len = text.length();
while (cursor < len) {
int start = text.indexOf('%', cursor);
if (start == -1) {
sb.append(text, cursor, len);
break;
}
if (start > cursor && text.charAt(start - 1) == '\\') {
sb.append(text, cursor, start - 1);
sb.append('%');
cursor = start + 1;
continue;
}
int end = text.indexOf('%', start + 1);
if (end == -1) {
sb.append(text, cursor, len);
break;
}
sb.append(text, cursor, start);
String key = text.substring(start + 1, end);
String replacement = params.get(key);
if (replacement != null) {
sb.append(replacement);
} else {
sb.append('%').append(key).append('%');
}
cursor = end + 1;
}
return sb.toString();
}

View File

@@ -1,12 +1,15 @@
package hdvtdev.blockandseek.menus;
import hdvtdev.blockandseek.managers.PartyManager;
import hdvtdev.blockandseek.managers.TranslationManager;
import hdvtdev.blockandseek.GuiHolder;
import hdvtdev.blockandseek.managers.GamesManager;
import hdvtdev.blockandseek.managers.ItemManager;
import hdvtdev.blockandseek.objects.Party;
import hdvtdev.blockandseek.objects.TranslationKey;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@@ -14,9 +17,11 @@ 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.List;
import java.util.UUID;
public class GamesMenu implements GuiHolder {
@@ -58,9 +63,22 @@ public class GamesMenu implements GuiHolder {
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));
Party party = PartyManager.getParty(player.getUniqueId());
if (party != null) {
for (UUID member : party.getMembers()) {
Player p = Bukkit.getPlayer(member);
if (p != null) {
if (!game.addPlayer(p)) {
p.sendMessage(TranslationManager.get(p, TranslationKey.GAME_IS_FULL, "%game%", gameName));
}
}
}
} else {
if (!game.addPlayer(player)) {
player.sendMessage(TranslationManager.get(player, TranslationKey.GAME_IS_FULL, "%game%", gameName));
}
}
}
event.getInventory().close();
}

View File

@@ -1,11 +1,9 @@
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.managers.*;
import hdvtdev.blockandseek.objects.BlockAndSeekMap;
import hdvtdev.blockandseek.objects.Party;
import hdvtdev.blockandseek.objects.TranslationKey;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
@@ -18,6 +16,7 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import static hdvtdev.blockandseek.objects.TranslationKey.UNKNOWN_MAP;
@@ -52,7 +51,29 @@ public class MapsMenu implements GuiHolder {
Player player = (Player) event.getWhoClicked();
String mapName = TranslationManager.plaintText.serialize(item.displayName()).replaceAll("[\\[\\]]", "");
if (MapsManager.hasMap(mapName)) {
GamesManager.createGame(mapName).addPlayer(player);
Party party = PartyManager.getParty(player.getUniqueId());
if (party != null) {
var members = party.getMembers();
var game = GamesManager.createGame(mapName);
if (members.size() + game.playerCount() > game.maxPlayers()) {
Player owner = Bukkit.getPlayer(party.getOwner());
if (owner != null) {
owner.sendMessage("Пати слишком жирная чтобы уместица в игре");
}
} else {
for (UUID uuid : members) {
Player member = Bukkit.getPlayer(uuid);
if (member != null) {
game.addPlayer(member);
}
}
}
} else {
GamesManager.createGame(mapName).addPlayer(player);
}
} else {
player.sendMessage(UNKNOWN_MAP.translate(player, "%map%", mapName, "%maps%", String.join(", ", MapsManager.getAllMaps())));
}

View File

@@ -11,6 +11,7 @@ import hdvtdev.blockandseek.managers.PropManager;
import hdvtdev.blockandseek.managers.StateManager;
import hdvtdev.blockandseek.roulette.RouletteCreator;
import hdvtdev.blockandseek.roulette.RouletteList;
import me.libraryaddict.disguise.DisguiseAPI;
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
@@ -18,10 +19,10 @@ import me.libraryaddict.disguise.disguisetypes.MiscDisguise;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.Sound;
import org.bukkit.*;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Item;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
@@ -40,6 +41,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.util.Vector;
import org.bukkit.plugin.Plugin;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
@@ -75,6 +77,14 @@ public class BlockAndSeekGame {
return stateManager.getPlayers().size() + "/" + map.getMaxPlayers();
}
public int playerCount() {
return stateManager.playerCount();
}
public int maxPlayers() {
return map.getMaxPlayers();
}
private void start() {
phase = new LobbyPhase();
phase.onEnable();
@@ -169,6 +179,8 @@ public class BlockAndSeekGame {
private long gameDuration = map.getGameDuration().toSeconds();
private final long midGame = gameDuration / 2;
private final long suddenDeath = map.getSuddenDeath().toSeconds();
@Override
public void onTick() {
@@ -192,6 +204,17 @@ public class BlockAndSeekGame {
new RouletteCreator(player, map.getBlocks());
}
}
} else if (gameDuration == suddenDeath) {
for (UUID uuid : stateManager.getPlayersInState(PlayerType.SEEKER)) {
Player player = Bukkit.getPlayer(uuid);
if (player != null) {
BlockAndSeekItem.addCooldownImune(uuid);
player.setWalkSpeed(0.5f);
player.setInvulnerable(true);
player.setGlowing(false);
player.addPotionEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, Integer.MAX_VALUE, 1, false, false, false));
}
}
}
actionBarToAll(TranslationKey.TIME_LEFT, "%time%", String.valueOf(gameDuration));
}
@@ -213,6 +236,37 @@ public class BlockAndSeekGame {
player.setInvulnerable(false);
} else BlockAndSeek.getPluginLogger().warning("Player is null. ");
}
long specialItemSpawnTime = map.getSpawnSpecialItems().toSeconds() * 20;
new BukkitRunnable() {
private final RouletteList<BlockAndSeekItem> specialItems = new RouletteList<>(ItemManager.getSpecItems());
private final Location spawn = map.getSpawn().getLocation();
private final Vector zero = new Vector(0, 0, 0);
private UUID prevItem;
@Override
public void run() {
if (phase == null) {
this.cancel();
} else {
Location location = spawn.clone().toCenterLocation();
ItemStack specialItem = specialItems.next().getTranslated(location.getNearbyPlayers(256).iterator().next()); //fixme: translation for all
location.setY(location.getY() + 1.5);
World world = location.getWorld();
if (prevItem != null) {
Entity entity = world.getEntity(prevItem);
if (entity != null) entity.remove();
}
Item item = world.dropItem(location, specialItem);
prevItem = item.getUniqueId();
item.setGlowing(true);
item.setCanMobPickup(false);
item.setGravity(false);
item.setVelocity(zero);
item.setUnlimitedLifetime(true);
}
}
}.runTaskTimer(BlockAndSeek.getInstance(), specialItemSpawnTime, specialItemSpawnTime);
}
private void selectSeekers(int count) {
@@ -230,8 +284,8 @@ public class BlockAndSeekGame {
Player player = Bukkit.getPlayer(seeker);
if (player != null) {
stateManager.setPlayerState(seeker, PlayerType.SEEKER);
player.setWalkSpeed(0.27f);
player.setWalkSpeed(0.25f);
player.setGlowing(true);
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, (int) spawnDelay, 2));
ItemManager.setSeekerSet(player);
Utils.setLevelWithBar(player, 100);
@@ -270,6 +324,21 @@ public class BlockAndSeekGame {
}
}
@EventHandler
private void onItemPickup(EntityPickupItemEvent event) {
if (event.getEntity() instanceof Player player) {
if (stateManager.getState(player.getUniqueId()) == PlayerType.PROP) {
Item item = event.getItem();
BlockAndSeekItem blockAndSeekItem = BlockAndSeekItem.tryCast(item.getItemStack());
if (blockAndSeekItem != null) {
item.remove();
player.getInventory().addItem(blockAndSeekItem.getTranslated(player));
}
}
event.setCancelled(true);
}
}
@EventHandler
private void onItemDrop(PlayerDropItemEvent event) {
if (stateManager.hasPlayer(event.getPlayer().getUniqueId())) {
@@ -283,6 +352,8 @@ public class BlockAndSeekGame {
if (stateManager.hasPlayer(player.getUniqueId())) {
if (event.getCause() == EntityDamageEvent.DamageCause.FALL) {
event.setCancelled(true);
} else if (stateManager.getState(player.getUniqueId()) == PlayerType.SEEKER) {
Utils.setLevelWithBar(player, (int) Math.round(player.getHealth() * 5));
}
}
}
@@ -351,12 +422,9 @@ public class BlockAndSeekGame {
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));
}
Utils.healSeeker(damager, event.getDamage());
} else if (victimType == PlayerType.SEEKER) {
Utils.setLevelWithBar(damager, (int) Math.round(damager.getHealth() * 5));
}
}
}
@@ -440,11 +508,14 @@ public class BlockAndSeekGame {
if (player != null) {
//propManager.removePlayer(player);
Utils.clearPlayer(player);
player.setInvulnerable(true);
player.setInvulnerable(false);
ItemManager.defaultInventory(player);
player.teleport(Config.spawn());
}
}
for (Entity entity : map.getSpawn().getLocation().getWorld().getEntities()) {
entity.remove();
}
endGame();
}

View File

@@ -3,6 +3,7 @@ package hdvtdev.blockandseek.objects;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.managers.ItemManager;
import hdvtdev.blockandseek.managers.PropManager;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Player;
@@ -15,7 +16,9 @@ import org.jetbrains.annotations.Nullable;
import java.time.Duration;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
public abstract class BlockAndSeekItem {
@@ -24,6 +27,7 @@ public abstract class BlockAndSeekItem {
private final long cooldown;
private final ItemStack rawItem;
private final Set<Action> actions;
private final boolean availableForProp;
private static final Set<Action> rightClickOnly = EnumSet.of(Action.RIGHT_CLICK_BLOCK, Action.RIGHT_CLICK_AIR);
private static final Set<Action> leftClickOnly = EnumSet.of(Action.LEFT_CLICK_BLOCK, Action.LEFT_CLICK_AIR);
@@ -32,7 +36,9 @@ public abstract class BlockAndSeekItem {
Action.LEFT_CLICK_BLOCK, Action.LEFT_CLICK_AIR
);
public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction) {
private static final Set<UUID> cooldownImune = new HashSet<>();
public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction, boolean availableForProp) {
this.actions = switch (clickAction) {
case RIGHT_CLICK -> rightClickOnly;
case LEFT_CLICK -> leftClickOnly;
@@ -40,18 +46,35 @@ public abstract class BlockAndSeekItem {
};
this.cooldown = cooldown.toMillis() / 50;
this.rawItem = asItemStack(id);
this.availableForProp = availableForProp;
}
public BlockAndSeekItem(@NotNull Items id) {
this(id, Duration.ZERO, ClickAction.ANY);
this(id, Duration.ZERO, ClickAction.ANY, true);
}
public BlockAndSeekItem(@NotNull Items id, @NotNull ClickAction action) {
this(id, Duration.ZERO, action);
this(id, Duration.ZERO, action, true);
}
public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown) {
this(id, cooldown, ClickAction.ANY);
this(id, cooldown, ClickAction.ANY, true);
}
public BlockAndSeekItem(@NotNull Items id, boolean availableForProp) {
this(id, Duration.ZERO, ClickAction.ANY, availableForProp);
}
public BlockAndSeekItem(@NotNull Items id, @NotNull Duration cooldown, @NotNull ClickAction clickAction) {
this(id, cooldown, clickAction, true);
}
public static void addCooldownImune(UUID uuid) {
cooldownImune.add(uuid);
}
public static void removeCooldownImune(UUID uuid) {
cooldownImune.remove(uuid);
}
@NotNull
@@ -63,16 +86,19 @@ public abstract class BlockAndSeekItem {
public final boolean onRawInteract(@NotNull PlayerInteractEvent event) {
if (this.actions.contains(event.getAction())) {
if (cooldown != 0) {
Player player = event.getPlayer();
Material material = event.getMaterial();
if (!player.hasCooldown(material)) {
player.setCooldown(material, (int) cooldown);
Player player = event.getPlayer();
UUID uuid = player.getUniqueId();
if (availableForProp || !PropManager.isProped(uuid)) {
if (cooldown != 0) {
Material material = event.getMaterial();
if (!player.hasCooldown(material)) {
player.setCooldown(material, cooldownImune.contains(uuid) ? 6 : (int) cooldown);
onInteract(event);
}
return false;
} else {
onInteract(event);
}
return false;
} else {
onInteract(event);
}
}

View File

@@ -48,7 +48,13 @@ public class BlockAndSeekMap extends OkaeriConfig {
private Duration delayBeforeGameEnd = Duration.ofSeconds(10);
@Comment("Create blocks roulette for all hiders to select a new prop")
private boolean midGameBlockSwap = true;
@CustomKey("midgame-block-swap")
private boolean midgameBlockSwap = true;
@Comment("If not zero, spawns random super items (for ex: morph item, decoy) every n time on map spawn (a bit higher)")
@Comment("Format examples: 1m, 300s")
@CustomKey("spawn-special-items")
private Duration spawnSpecialItems = Duration.ofMinutes(4);
@Comment("Grants seeker infinite health, speed, and jump boost for the specified time before the game ends.")
@Comment("Format examples: 10m, 300s, 1h. If duration is zero, sudden death will be disabled")
@@ -58,9 +64,4 @@ public class BlockAndSeekMap extends OkaeriConfig {
@Comment("Available prop blocks for hiders")
private List<PropBlock> blocks = new ArrayList<>(List.of(new PropBlock(new ItemStack(Material.TARGET), Rarity.LEGENDARY)));
}
}

View File

@@ -15,7 +15,7 @@ public enum Items implements PersistentDataType<String, Items> {
MENU,
SOUND_MAKER,
DASH,
MORPH, GRENADE;
MORPH, GRENADE, DECOY, DEATH_BELT, CHORUS, ANTI_GRAVITY;
public static final PersistentDataType<String, Items> TYPE = PISTOL;

View File

@@ -7,12 +7,10 @@ import eu.okaeri.configs.annotation.Exclude;
import hdvtdev.blockandseek.BlockAndSeek;
import hdvtdev.blockandseek.Utils;
import lombok.NoArgsConstructor;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import org.bukkit.*;
import org.bukkit.entity.Player;
@NoArgsConstructor
@@ -34,9 +32,18 @@ public class LazyLocation extends OkaeriConfig {
@Exclude
private Location location;
@SuppressWarnings("deprecation") // for world.setGameRuleValue because 1.20.6 does not have GameRule.LOCATORBAR
private void loadLocation() {
BlockAndSeek.getPluginLogger().info("Loading world \"" + worldName + "\"");
World world = Bukkit.createWorld(new WorldCreator(worldName));
world.setGameRule(GameRule.DO_MOB_SPAWNING, false);
world.setGameRule(GameRule.DO_DAYLIGHT_CYCLE, false);
world.setGameRule(GameRule.DO_WEATHER_CYCLE, false);
world.setGameRule(GameRule.RANDOM_TICK_SPEED, 0);
world.setAutoSave(false);
if (Utils.isVersionAtLeast("1.21.5")) {
world.setGameRuleValue("locatorbar", "false");
}
this.location = new Location(world, x, y, z, yaw, pitch);
}

View File

@@ -0,0 +1,33 @@
package hdvtdev.blockandseek.objects;
import lombok.Getter;
import lombok.Setter;
import org.jetbrains.annotations.NotNull;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
@Getter
public class Party {
@Setter
private UUID owner;
private final Set<UUID> members = new HashSet<>();
private final UUID partyId = UUID.randomUUID();
public Party(@NotNull UUID owner) {
this.owner = owner;
this.members.add(owner);
}
public void addMember(@NotNull UUID member) {
members.add(member);
}
public void removeMember(@NotNull UUID member) {
members.remove(member);
}
}

View File

@@ -6,11 +6,22 @@ import org.bukkit.entity.Player;
public enum TranslationKey {
// Misc
CHORUS,
BLOCK_NOT_SUPPORTED,
UNKNOWN_COMMAND,
SEEKER_TEMPLATE,
CONFIG_RELOADED,
// Maps management
UNKNOWN_MAP,
MAP_CREATED,
MAP_NOT_CREATED,
MAP_EXIST,
PARTY_INVITE,
PARTY_KICK,
PARTY_LEAVE,
PARTY_INFO,
PARTY_JOIN,
SUCCESSFUL_MAP_CREATION,
// Menus
@@ -29,18 +40,35 @@ public enum TranslationKey {
PLAYER_JOINED,
PLAYER_LEFT,
SEEKERS_WIN,
SEEKERS_SPAWN,
SEEKERS_SPAWNED,
SEEKER_DIED,
HIDER_FOUND,
HIDER_DIED,
HIDER_DIED_BY_HIDER,
HIDERS_WIN,
HIDER_SOLO_WIN,
ROULETTE,
GAME_IS_FULL,
WAITING_FOR_PLAYERS,
GAME_STARTED,
SUPER_ITEM_SPAWN,
SUPER_ITEM_SPAWNED,
BLOCK_SWAP,
BLOCK_SWAPPING,
// Items
FREEZE_ITEM,
FACE_CHANGING_ITEM,
SOUND_ITEM,
LEAVE_ITEM,
DASH_ITEM, MORPH_ITEM, PISTOL, GRENADE;
GAME_START_ITEM,
DASH_ITEM,
MORPH_ITEM,
PISTOL, GRENADE,
DECOY,
DEATH_BELT,
ANTI_GRAVITY;
public Component translate(Player player, String... placeholders) {
return TranslationManager.get(player, this, placeholders);