Skip to content
Open
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 @@ -236,6 +236,15 @@ public void onPacketSending(PacketEvent event) {

// Actions: 0 (Create), 3 (Add Members), 4 (Remove Members)
if (action == 0 || action == 3 || action == 4) {
// For the vanish team, non-staff clients never receive ADD packets for
// vanished players, so they must also never receive REMOVE packets —
// otherwise MC crashes with "Player is not on any team" when unvanishing.
String teamName = packet.getStrings().read(0);
if ("Vanishpp_Vanished".equals(teamName) && (action == 3 || action == 4)) {
event.setCancelled(true);
return;
}

Collection<String> players = packet.getSpecificModifier(Collection.class).read(0);
if (players != null) {
List<String> scrubbed = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -970,10 +970,15 @@ public void applyVanishEffects(Player player) {

// ALWAYS clear existing mob targets when vanishing (regardless of mob_targeting rule)
// The rule only controls whether new targets can be acquired AFTER vanishing
// Each mob's target access must run on its owning region's thread (Folia safety)
for (Entity entity : player.getWorld().getEntities()) {
if (entity instanceof Mob mob && player.equals(mob.getTarget())) {
mob.setTarget(null);
mob.getPathfinder().stopPathfinding();
if (entity instanceof Mob mob) {
vanishScheduler.runEntity(mob, () -> {
if (player.equals(mob.getTarget())) {
mob.setTarget(null);
mob.getPathfinder().stopPathfinding();
}
}, null);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,15 @@ public void onPacketSending(PacketEvent event) {

// Actions: 0 (Create), 3 (Add Members), 4 (Remove Members)
if (action == 0 || action == 3 || action == 4) {
// For the vanish team, non-staff clients never receive ADD packets for
// vanished players, so they must also never receive REMOVE packets —
// otherwise MC crashes with "Player is not on any team" when unvanishing.
String teamName = packet.getStrings().read(0);
if ("Vanishpp_Vanished".equals(teamName) && (action == 3 || action == 4)) {
event.setCancelled(true);
return;
}

Collection<String> players = packet.getSpecificModifier(Collection.class).read(0);
if (players != null) {
List<String> scrubbed = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ public void register() {
private void sweepMobTargets() {
for (Player p : Bukkit.getOnlinePlayers()) {
if (!plugin.isVanished(p)) continue;

// Only enforce clearing if mob_targeting rule is OFF
if (plugin.getRuleManager().getRule(p, RuleManager.MOB_TARGETING)) continue;

// Check all nearby mobs and clear any that have the vanished player as target
for (Entity entity : p.getNearbyEntities(128, 128, 128)) {
if (!(entity instanceof Mob mob)) continue;

// Clear target if aimed at this vanished player
if (p.equals(mob.getTarget())) {
mob.setTarget(null);
try {
mob.getPathfinder().stopPathfinding();
} catch (Throwable ignored) {}
}
// getNearbyEntities requires the owning region thread — dispatch per entity.
plugin.getVanishScheduler().runEntity(p, () -> sweepForPlayer(p), null);
}
}

private void sweepForPlayer(Player p) {
for (Entity entity : p.getNearbyEntities(128, 128, 128)) {
if (!(entity instanceof Mob mob)) continue;
if (p.equals(mob.getTarget())) {
mob.setTarget(null);
try {
mob.getPathfinder().stopPathfinding();
} catch (Throwable ignored) {}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,25 @@ public VanishStats getStats(UUID uuid) {
return VanishStats.empty();
}

@Override
public void setStats(UUID uuid, VanishStats stats) {
String q = type.equals("postgresql")
? "INSERT INTO vpp_stats (uuid,total_ms,vanish_count,longest_ms) VALUES(?,?,?,?)"
+ " ON CONFLICT (uuid) DO UPDATE SET total_ms=EXCLUDED.total_ms,"
+ " vanish_count=EXCLUDED.vanish_count, longest_ms=EXCLUDED.longest_ms"
: "INSERT INTO vpp_stats (uuid,total_ms,vanish_count,longest_ms) VALUES(?,?,?,?)"
+ " ON DUPLICATE KEY UPDATE total_ms=VALUES(total_ms),"
+ " vanish_count=VALUES(vanish_count), longest_ms=VALUES(longest_ms)";
try (Connection conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(q)) {
ps.setString(1, uuid.toString());
ps.setLong(2, stats.getTotalVanishTimeMs());
ps.setInt(3, stats.getVanishCount());
ps.setLong(4, stats.getLongestSessionMs());
ps.executeUpdate();
} catch (SQLException e) { handleDatabaseError(e); }
}

@Override
public void recordVanishSession(UUID uuid, long durationMs) {
if (durationMs <= 0) return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,15 @@ public VanishStats getStats(UUID uuid) {
return new VanishStats(total, count, longest);
}

@Override
public void setStats(UUID uuid, VanishStats stats) {
String base = "stats." + uuid + ".";
config.set(base + "total-ms", stats.getTotalVanishTimeMs());
config.set(base + "count", stats.getVanishCount());
config.set(base + "longest-ms", stats.getLongestSessionMs());
save();
}

@Override
public void recordVanishSession(UUID uuid, long durationMs) {
if (durationMs <= 0) return;
Expand Down