Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@
import dev.lrxh.neptune.profile.data.ProfileState;
import dev.lrxh.neptune.profile.impl.Profile;
import dev.lrxh.neptune.providers.clickable.Replacement;
import dev.lrxh.neptune.utils.CC;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import net.kyori.adventure.title.Title;
import java.time.Duration;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
Expand Down Expand Up @@ -51,6 +55,15 @@ public void add(QueueEntry queueEntry, boolean add) {
MessagesLocale.QUEUE_JOIN.send(playerUUID,
new Replacement("<kit>", kit.getDisplayName()),
new Replacement("<maxPing>", String.valueOf(profile.getSettingData().getMaxPing())));

// One-shot title: Joined Queue
Bukkit.getScheduler().runTask(Neptune.get(), () -> {
Player p = Bukkit.getPlayer(playerUUID);
if (p != null && p.isOnline()) {
Title.Times times = Title.Times.times(Duration.ZERO, Duration.ofMillis(1200), Duration.ZERO);
p.showTitle(Title.title(CC.color("&eJoined Queue"), CC.color("&7Searching for opponent..."), times));
}
});
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,17 @@
import dev.lrxh.neptune.utils.CC;
import dev.lrxh.neptune.utils.PlayerUtil;
import dev.lrxh.neptune.utils.tasks.NeptuneRunnable;
import dev.lrxh.neptune.utils.tasks.TaskScheduler;
import net.kyori.adventure.title.Title;
import org.bukkit.Sound;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import dev.lrxh.neptune.Neptune;
import java.time.Duration;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.Location;
import org.bukkit.World;
import dev.lrxh.neptune.game.arena.VirtualArena;

import java.util.Map;
import java.util.Queue;
Expand Down Expand Up @@ -83,42 +91,105 @@ public void run() {
}

kit.getRandomArena().thenAccept(arena -> {
if (arena == null) {
PlayerUtil.sendMessage(uuid1, CC.error("No valid arena was found for this kit!"));
PlayerUtil.sendMessage(uuid2, CC.error("No valid arena was found for this kit!"));
return;
}
Bukkit.getScheduler().runTask(Neptune.get(), () -> {
if (arena == null) {
PlayerUtil.sendMessage(uuid1, CC.error("No valid arena was found for this kit!"));
PlayerUtil.sendMessage(uuid2, CC.error("No valid arena was found for this kit!"));
return;
}

// Re-fetch players on main thread and validate online
Player p1 = Bukkit.getPlayer(uuid1);
Player p2 = Bukkit.getPlayer(uuid2);
if (p1 == null || p2 == null || !p1.isOnline() || !p2.isOnline()) {
return;
}

Participant participant1 = new Participant(player1);
Participant participant2 = new Participant(player2);

MessagesLocale.MATCH_FOUND.send(uuid1,
new Replacement("<opponent>", participant2.getNameUnColored()),
new Replacement("<kit>", kit.getDisplayName()),
new Replacement("<arena>", arena.getDisplayName()),
new Replacement("<opponent-ping>", String.valueOf(ping2)),
new Replacement("<opponent-elo>", String.valueOf(profile2.getGameData().get(kit).getElo())),
new Replacement("<elo>", String.valueOf(profile1.getGameData().get(kit).getElo())),
new Replacement("<ping>", String.valueOf(ping1)));

MessagesLocale.MATCH_FOUND.send(uuid2,
new Replacement("<opponent>", participant1.getNameUnColored()),
new Replacement("<kit>", kit.getDisplayName()),
new Replacement("<arena>", arena.getDisplayName()),
new Replacement("<opponent-ping>", String.valueOf(ping1)),
new Replacement("<opponent-elo>", String.valueOf(profile1.getGameData().get(kit).getElo())),
new Replacement("<elo>", String.valueOf(profile2.getGameData().get(kit).getElo())),
new Replacement("<ping>", String.valueOf(ping2)));

TaskScheduler.get().startTaskCurrentTick(new NeptuneRunnable() {
@Override
public void run() {
Participant participant1 = new Participant(p1);
Participant participant2 = new Participant(p2);

MessagesLocale.MATCH_FOUND.send(uuid1,
new Replacement("<opponent>", participant2.getNameUnColored()),
new Replacement("<kit>", kit.getDisplayName()),
new Replacement("<arena>", arena.getDisplayName()),
new Replacement("<opponent-ping>", String.valueOf(ping2)),
new Replacement("<opponent-elo>", String.valueOf(profile2.getGameData().get(kit).getElo())),
new Replacement("<elo>", String.valueOf(profile1.getGameData().get(kit).getElo())),
new Replacement("<ping>", String.valueOf(ping1)));

MessagesLocale.MATCH_FOUND.send(uuid2,
new Replacement("<opponent>", participant1.getNameUnColored()),
new Replacement("<kit>", kit.getDisplayName()),
new Replacement("<arena>", arena.getDisplayName()),
new Replacement("<opponent-ping>", String.valueOf(ping1)),
new Replacement("<opponent-elo>", String.valueOf(profile1.getGameData().get(kit).getElo())),
new Replacement("<elo>", String.valueOf(profile2.getGameData().get(kit).getElo())),
new Replacement("<ping>", String.valueOf(ping2)));

// Preload arena chunks so teleport feels instant after delay
preloadArena(arena);

// Prepare players: close inventory, brief blindness, play accept sound, animate titles
p1.closeInventory();
p2.closeInventory();

p1.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));
p2.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));

Sound sound = Sound.ITEM_MACE_SMASH_AIR;
p1.playSound(p1.getLocation(), sound, 1.0f, 1.0f);
p2.playSound(p2.getLocation(), sound, 1.0f, 1.0f);

animateTitles(p1, p2, 100L);

// Delay start to allow arena generation to finalize
Bukkit.getScheduler().runTaskLater(Neptune.get(), () -> {
MatchService.get().startMatch(participant1, participant2, kit, arena, false,
kit.is(KitRule.BEST_OF_THREE) ? 3 : 1);
}
}, 100L);
});
});
}
}

private void animateTitles(Player p1, Player p2, long delayTicks) {
String[] titles = {
"&e⚔ &6Match Found &e⚔",
"&6⚔ &eMatch Found &6⚔",
"&e⚔ &6Match Found &e⚔",
"&6⚔ &eMatch Found &6⚔"
};

String[] subs = {
"&7Teleporting to arena.",
"&7Teleporting to arena..",
"&7Teleporting to arena...",
"&7Teleporting to arena."
};
for (long t = 1L; t < delayTicks; t += 5L) {
int idx = (int) ((t / 5L) % titles.length);
Bukkit.getScheduler().runTaskLater(Neptune.get(), () -> {
Title.Times times = Title.Times.times(Duration.ZERO, Duration.ofMillis(500), Duration.ZERO);
p1.showTitle(Title.title(CC.color(titles[idx]), CC.color(subs[idx]), times));
p2.showTitle(Title.title(CC.color(titles[idx]), CC.color(subs[idx]), times));
}, t);
}
}

private void preloadArena(VirtualArena arena) {
if (arena == null) return;
Location[] important = new Location[]{arena.getRedSpawn(), arena.getBlueSpawn(), arena.getMin(), arena.getMax()};
for (Location loc : important) {
if (loc == null) continue;
World world = loc.getWorld();
if (world == null) continue;
int baseCx = loc.getBlockX() >> 4;
int baseCz = loc.getBlockZ() >> 4;
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
world.getChunkAt(baseCx + dx, baseCz + dz).load(true);
}
}
}
}
}
66 changes: 64 additions & 2 deletions Plugin/src/main/java/dev/lrxh/neptune/game/duel/DuelRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@
import dev.lrxh.neptune.utils.CC;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
import net.kyori.adventure.title.Title;
import java.time.Duration;
import org.bukkit.Location;
import org.bukkit.World;

import java.util.ArrayList;
import java.util.List;
Expand All @@ -33,6 +38,23 @@ public DuelRequest(UUID sender, Kit kit, VirtualArena arena, boolean party, int
this.rounds = rounds;
}

private void preloadArena(dev.lrxh.neptune.game.arena.VirtualArena arena) {
if (arena == null) return;
Location[] important = new Location[]{arena.getRedSpawn(), arena.getBlueSpawn(), arena.getMin(), arena.getMax()};
for (Location loc : important) {
if (loc == null) continue;
World world = loc.getWorld();
if (world == null) continue;
int baseCx = loc.getBlockX() >> 4;
int baseCz = loc.getBlockZ() >> 4;
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
world.getChunkAt(baseCx + dx, baseCz + dz).load(true);
}
}
}
}

public void start(UUID receiver) {
if (party) {
partyDuel(receiver);
Expand Down Expand Up @@ -61,6 +83,7 @@ public void partyDuel(UUID receiver) {
Profile senderProfile = API.getProfile(getSender());

List<Participant> participants = new ArrayList<>();
List<Player> players = new ArrayList<>();

List<Participant> teamAList = new ArrayList<>();

Expand All @@ -72,6 +95,7 @@ public void partyDuel(UUID receiver) {
Participant participant = new Participant(player);
teamAList.add(participant);
participants.add(participant);
players.add(player);
}

List<Participant> teamBList = new ArrayList<>();
Expand All @@ -84,6 +108,7 @@ public void partyDuel(UUID receiver) {
Participant participant = new Participant(player);
teamBList.add(participant);
participants.add(participant);
players.add(player);
}

MatchTeam teamA = new MatchTeam(teamAList);
Expand All @@ -108,8 +133,45 @@ public void partyDuel(UUID receiver) {
return;
}

Bukkit.getScheduler().runTask(Neptune.get(), () -> {
// Preload arena chunks so teleport feels instant after delay
preloadArena(arena);

// Play accept sound, close inventories, and show titles to all party members
Sound sound = Sound.ITEM_MACE_SMASH_AIR;
for (Player p : players) {
p.playSound(p.getLocation(), sound, 1.0f, 1.0f);
p.closeInventory();
}

partyDuelTitles(players, 100L);

Bukkit.getScheduler().runTaskLater(Neptune.get(), () -> {
MatchService.get().startMatch(teamA, teamB, kit, arena);
});
}, 100L);
}

private void partyDuelTitles(List<Player> players, long delayTicks) {
String[] titles = {
"&e⚔ &6Duel Accepted &e⚔",
"&6⚔ &6Duel Accepted &6⚔",
"&e⚔ &6Duel Accepted &e⚔",
"&6⚔ &6Duel Accepted &6⚔"
};

String[] subs = {
"&7Teleporting to arena.",
"&7Teleporting to arena..",
"&7Teleporting to arena...",
"&7Teleporting to arena."
};
for (long t = 1L; t < delayTicks; t += 5L) {
int idx = (int) ((t / 5L) % titles.length);
Bukkit.getScheduler().runTaskLater(Neptune.get(), () -> {
Title.Times times = Title.Times.times(Duration.ZERO, Duration.ofMillis(500), Duration.ZERO);
for (Player p : players) {
p.showTitle(Title.title(CC.color(titles[idx]), CC.color(subs[idx]), times));
}
}, t);
}
}
}
27 changes: 25 additions & 2 deletions Plugin/src/main/java/dev/lrxh/neptune/game/kit/Kit.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;

import java.util.*;
import java.util.concurrent.CompletableFuture;
Expand Down Expand Up @@ -223,7 +224,18 @@ public void giveLoadout(UUID playerUUID) {
player.getInventory().setContents(gameData.get(this).getKitLoadout().toArray(new ItemStack[0]));
}

player.addPotionEffects(potionEffects);
// Ensure no invisibility persists from kit or prior state
player.removePotionEffect(PotionEffectType.INVISIBILITY);
player.setInvisible(false);

// Apply kit potion effects excluding invisibility
List<PotionEffect> effects = new ArrayList<>();
for (PotionEffect effect : potionEffects) {
if (effect != null && effect.getType() != PotionEffectType.INVISIBILITY) {
effects.add(effect);
}
}
player.addPotionEffects(effects);

player.updateInventory();
}
Expand All @@ -244,7 +256,18 @@ public void giveLoadout(Participant participant) {
participant.getColor().getContentColor()));
}

player.addPotionEffects(potionEffects);
// Ensure no invisibility persists from kit or prior state
player.removePotionEffect(PotionEffectType.INVISIBILITY);
player.setInvisible(false);

// Apply kit potion effects excluding invisibility
List<PotionEffect> effects2 = new ArrayList<>();
for (PotionEffect effect : potionEffects) {
if (effect != null && effect.getType() != PotionEffectType.INVISIBILITY) {
effects2.add(effect);
}
}
player.addPotionEffects(effects2);

player.updateInventory();
}
Expand Down
20 changes: 18 additions & 2 deletions Plugin/src/main/java/dev/lrxh/neptune/game/match/Match.java
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ public void checkRules() {
participant.setDead(false);
});

resetVisibilityInMatch();
showPlayerForSpectators();
}

Expand All @@ -358,19 +359,33 @@ public void hideHealth() {
public void hideParticipant(Participant participant) {
forEachParticipant(p -> {
if (!p.equals(participant)) {
p.getPlayer().hidePlayer(Neptune.get(), participant.getPlayer());
if (p.getPlayer() != null && participant.getPlayer() != null) {
p.getPlayer().hidePlayer(Neptune.get(), participant.getPlayer());
}
}
});
}

public void showParticipant(Participant participant) {
forEachParticipant(p -> {
if (!p.equals(participant)) {
p.getPlayer().showPlayer(Neptune.get(), participant.getPlayer());
if (p.getPlayer() != null && participant.getPlayer() != null) {
p.getPlayer().showPlayer(Neptune.get(), participant.getPlayer());
}
}
});
}

public void resetVisibilityInMatch() {
forEachParticipant(a -> forEachParticipant(b -> {
if (!a.equals(b)) {
if (a.getPlayer() != null && b.getPlayer() != null) {
a.getPlayer().showPlayer(Neptune.get(), b.getPlayer());
}
}
}));
}

private void showHealth() {
forEachPlayer(player -> {
Objective objective = player.getScoreboard().getObjective(DisplaySlot.BELOW_NAME);
Expand Down Expand Up @@ -403,6 +418,7 @@ public void setupParticipants() {
par.reset();
showParticipant(par);
});
resetVisibilityInMatch();
}

public void sendDeathMessage(Participant deadParticipant) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ public void onLeave(Participant participant, boolean quit) {
public void startMatch() {
setState(MatchState.IN_ROUND);
showPlayerForSpectators();
resetVisibilityInMatch();
playSound(Sound.ENTITY_FIREWORK_ROCKET_BLAST);
sendTitle(CC.color(MessagesLocale.MATCH_START_TITLE_HEADER.getString()), CC.color(MessagesLocale.MATCH_START_TITLE_FOOTER.getString()), 20);
}
Expand Down
Loading