Skip to content

GH-986 GH-1096 Moved sounds and enhanced death messages #1097

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Original file line number Diff line number Diff line change
Expand Up @@ -122,32 +122,6 @@ public Duration teleportationTimeToSpawn() {
@Comment("# Settings for player home management")
HomesConfig homes = new HomesConfig();

@Comment("")
@Comment("# Sound Configuration")
@Comment("# Settings for various sound effects")
@Bean
public Sounds sound = new Sounds();

public static class Sounds extends OkaeriConfig {
@Comment("# Enable sound when player joins the server")
public boolean enabledAfterJoin = true;
public Sound afterJoin = Sound.BLOCK_NOTE_BLOCK_PLING;
public float afterJoinVolume = 1.8F;
public float afterJoinPitch = 1F;

@Comment("# Enable sound when player leaves the server")
public boolean enableAfterQuit = true;
public Sound afterQuit = Sound.BLOCK_NOTE_BLOCK_BASEDRUM;
public float afterQuitVolume = 1.8F;
public float afterQuitPitch = 1F;

@Comment("# Enable sound when player sends a chat message")
public boolean enableAfterChatMessage = true;
public Sound afterChatMessage = Sound.ENTITY_ITEM_PICKUP;
public float afterChatMessageVolume = 1.8F;
public float afterChatMessagePitch = 1F;
}

@Bean(proxied = ChatSettings.class)
@Comment("")
@Comment("# Chat Configuration")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.eternalcode.core.configuration.migrations;

import eu.okaeri.configs.migrate.builtin.NamedMigration;

import static eu.okaeri.configs.migrate.ConfigMigrationDsl.move;

public class Migration_0004_Move_death_to_dedicated_section extends NamedMigration {

Migration_0004_Move_death_to_dedicated_section() {
super("Move death to dedicated section",
move("event.deathMessage", "death.deathMessage"),
move("event.unknownDeathCause", "death.unknownDeathCause"),
move("event.deathMessageByDamageCause", "death.deathMessageByDamageCause")
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.eternalcode.core.configuration.migrations;

import eu.okaeri.configs.migrate.builtin.NamedMigration;

import static eu.okaeri.configs.migrate.ConfigMigrationDsl.move;

public class Migration_0005_Move_join_quit_message_to_dedicated_section extends NamedMigration {

Migration_0005_Move_join_quit_message_to_dedicated_section() {
super("Move joinquit messages from event to joinQuit section",
move("event.joinMessage", "joinQuit.joinMessage"),
move("event.firstJoinMessage", "joinQuit.firstJoinMessage"),
move("event.quitMessage", "joinQuit.quitMessage")
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ public class Migrations {

public static final ConfigMigration[] ALL = new ConfigMigration[] {
new Migration_0001_Rename_privateChat_to_msg(),
new Migration_0004_Move_death_to_dedicated_section(),
new Migration_0005_Move_join_quit_message_to_dedicated_section()
};

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package com.eternalcode.core.feature.chat;

import com.eternalcode.multification.bukkit.notice.BukkitNotice;
import com.eternalcode.multification.notice.Notice;
import eu.okaeri.configs.OkaeriConfig;
import eu.okaeri.configs.annotation.Comment;
import java.time.Duration;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.bukkit.Sound;

@Getter
@Setter
Expand All @@ -23,4 +26,10 @@ public class ChatConfig extends OkaeriConfig implements ChatSettings {

@Comment("# Chat should be enabled?")
public boolean chatEnabled = true;

@Comment({
"# Sound played when a player sends a chat message.",
"# To disable, set this to: chatNotice: []"
})
public Notice chatNotice = BukkitNotice.sound(Sound.ENTITY_ITEM_PICKUP, 1.8F, 1F);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.eternalcode.core.feature.chat;

import com.eternalcode.multification.notice.Notice;

import java.time.Duration;

public interface ChatSettings {
Expand All @@ -17,4 +19,6 @@ public interface ChatSettings {
ChatSettings chatDelay(Duration delay);

ChatSettings linesToClear(int lines);

Notice chatNotice();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.eternalcode.core.feature.chat;

import com.eternalcode.core.injector.annotations.component.Controller;
import com.eternalcode.core.notice.NoticeService;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.AsyncPlayerChatEvent;

@Controller
class ChatSoundController implements Listener {

private final NoticeService noticeService;
private final ChatSettings settings;

ChatSoundController(NoticeService noticeService, ChatSettings settings) {
this.noticeService = noticeService;
this.settings = settings;
}

@EventHandler
void onSound(AsyncPlayerChatEvent event) {
this.noticeService.create()
.notice(this.settings.chatNotice())
.onlinePlayers()
.send();
}

}
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
package com.eternalcode.core.feature.deathmessage;


import com.eternalcode.commons.RandomElementUtil;
import com.eternalcode.core.feature.vanish.VanishService;
import com.eternalcode.core.injector.annotations.Inject;
import com.eternalcode.core.injector.annotations.component.Controller;
import com.eternalcode.core.notice.NoticeService;
import com.eternalcode.multification.notice.Notice;
import java.util.List;
import java.util.Optional;

import org.bukkit.block.Block;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.projectiles.ProjectileSource;

@Controller
class DeathMessageController implements Listener {
Expand All @@ -30,48 +35,190 @@ class DeathMessageController implements Listener {

@EventHandler
void onPlayerDeath(PlayerDeathEvent event) {
Player player = event.getEntity();
Player victim = event.getEntity();
event.setDeathMessage(null);
if (this.vanishService.isVanished(player)) {

if (this.vanishService.isVanished(victim)) {
return;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add option to not use custom death messages

EntityDamageEvent damageCause = player.getLastDamageCause();
EntityDamageEvent damageCause = victim.getLastDamageCause();
if (!(damageCause instanceof EntityDamageByEntityEvent causeByEntity)) {
this.handleEnvironmentalDeath(victim, damageCause);
return;
}

Entity directDamager = causeByEntity.getDamager();
if (directDamager instanceof Projectile projectile) {
this.handleProjectileDeath(victim, projectile);
return;
}

if (directDamager instanceof Player killer) {
this.handlePvPDeath(victim, killer);
return;
}
this.handleEntityDeath(victim, directDamager);
}

private void handleProjectileDeath(Player victim, Projectile projectile) {
ProjectileSource shooter = projectile.getShooter();

if (damageCause instanceof EntityDamageByEntityEvent causeByEntity && causeByEntity.getDamager() instanceof Player killer) {
if (shooter instanceof Player killerPlayer) {
String weaponType = this.getProjectileWeaponType(projectile);
this.noticeService.create()
.noticeOptional(translation -> RandomElementUtil.randomElement(translation.event().deathMessage()))
.placeholder("{PLAYER}", player.getName())
.placeholder("{KILLER}", killer.getName())
.noticeOptional(translation -> {
List<Notice> weaponMessages = translation.death().deathMessageByWeapon().get(weaponType);
return weaponMessages != null
? RandomElementUtil.randomElement(weaponMessages)
: RandomElementUtil.randomElement(translation.death().deathMessage());
})
.placeholder("{PLAYER}", victim.getName())
.placeholder("{KILLER}", killerPlayer.getName())
.placeholder("{WEAPON}", weaponType.toLowerCase().replace("_", " "))
.onlinePlayers()
.send();
return;
}

if (damageCause != null) {
EntityDamageEvent.DamageCause cause = damageCause.getCause();
if (shooter instanceof Entity shooterEntity) {
String entityType = shooterEntity.getType().name();
String projectileType = projectile.getType().name();
this.noticeService.create()
.noticeOptional(translation -> {
List<Notice> notifications = translation.event().deathMessageByDamageCause().get(cause);

if (notifications == null) {
return RandomElementUtil.randomElement(translation.event().unknownDeathCause());
List<Notice> entityMessages = translation.death().deathMessageByEntity().get(entityType);
if (entityMessages != null) {
return RandomElementUtil.randomElement(entityMessages);
}

return RandomElementUtil.randomElement(notifications);
List<Notice> projectileMessages = translation.death().deathMessageByEntity().get(projectileType);
if (projectileMessages != null) {
return RandomElementUtil.randomElement(projectileMessages);
}
return RandomElementUtil.randomElement(translation.death().deathMessage());
})
.placeholder("{PLAYER}", player.getName())
.placeholder("{CAUSE}", cause.name())
.placeholder("{PLAYER}", victim.getName())
.placeholder("{KILLER}", shooterEntity.getName())
.placeholder("{PROJECTILE}", projectileType.toLowerCase().replace("_", " "))
.onlinePlayers()
.send();
return;
}

String projectileType = projectile.getType().name();
this.noticeService.create()
.noticeOptional(translation -> RandomElementUtil.randomElement(translation.event().unknownDeathCause()))
.placeholder("{PLAYER}", player.getName())
.noticeOptional(translation -> {
List<Notice> projectileMessages = translation.death().deathMessageByEntity().get(projectileType);
return projectileMessages != null
? RandomElementUtil.randomElement(projectileMessages)
: RandomElementUtil.randomElement(translation.death().unknownDeathCause());
})
.placeholder("{PLAYER}", victim.getName())
.placeholder("{KILLER}", projectileType.toLowerCase().replace("_", " "))
.onlinePlayers()
.send();
}

private void handlePvPDeath(Player victim, Player killer) {
String weaponType = this.getWeaponType(killer.getInventory().getItemInMainHand());
this.noticeService.create()
.noticeOptional(translation -> Optional.ofNullable(translation.death().deathMessageByWeapon().get(weaponType))
.filter(list -> !list.isEmpty())
.map(RandomElementUtil::randomElement)
.orElseGet(() -> RandomElementUtil.randomElement(translation.death().deathMessage())))
.placeholder("{PLAYER}", victim.getName())
.placeholder("{KILLER}", killer.getName())
.placeholder("{WEAPON}", weaponType.toLowerCase().replace("_", " "))
.onlinePlayers()
.send();
}

private void handleEntityDeath(Player victim, Entity damager) {
String entityType = damager.getType().name();
this.noticeService.create()
.noticeOptional(translation -> {
List<Notice> entityMessages = translation.death().deathMessageByEntity().get(entityType);
return entityMessages != null
? RandomElementUtil.randomElement(entityMessages)
: RandomElementUtil.randomElement(translation.death().deathMessage());
})
.placeholder("{PLAYER}", victim.getName())
.placeholder("{KILLER}", damager.getName())
.onlinePlayers()
.send();
}

private void handleEnvironmentalDeath(Player victim, EntityDamageEvent damageCause) {
if (damageCause == null) {
this.handleUnknownDeath(victim);
return;
}

EntityDamageEvent.DamageCause cause = damageCause.getCause();
if (cause == EntityDamageEvent.DamageCause.CONTACT) {
String blockType = this.getContactBlockType(victim);
if (blockType != null) {
this.noticeService.create()
.noticeOptional(translation -> {
List<Notice> blockMessages = translation.death().deathMessageByEntity().get(blockType);
return blockMessages != null
? RandomElementUtil.randomElement(blockMessages)
: RandomElementUtil.randomElement(translation.death().unknownDeathCause());
})
.placeholder("{PLAYER}", victim.getName())
.onlinePlayers()
.send();
return;
}
}

this.noticeService.create()
.noticeOptional(translation -> {
List<Notice> notifications = translation.death().deathMessageByDamageCause().get(cause);
return notifications != null
? RandomElementUtil.randomElement(notifications)
: RandomElementUtil.randomElement(translation.death().unknownDeathCause());
})
.placeholder("{PLAYER}", victim.getName())
.placeholder("{CAUSE}", cause.name())
.onlinePlayers()
.send();
}

private void handleUnknownDeath(Player victim) {
this.noticeService.create()
.noticeOptional(translation -> RandomElementUtil.randomElement(translation.death().unknownDeathCause()))
.placeholder("{PLAYER}", victim.getName())
.onlinePlayers()
.send();
}

private String getProjectileWeaponType(Projectile projectile) {
return switch (projectile.getType()) {
case ARROW, SPECTRAL_ARROW -> "BOW";
case FIREBALL, SMALL_FIREBALL -> "FIREBALL";
default -> projectile.getType().name();
};
}

private String getWeaponType(ItemStack item) {
return item == null || item.getType().isAir()
? "HAND"
: item.getType().name();
}

private String getContactBlockType(Player player) {
Block blockAtFeet = player.getLocation().getBlock();
Block blockAtEyes = player.getEyeLocation().getBlock();

for (Block block : new Block[] { blockAtFeet, blockAtEyes }) {
String type = switch (block.getType()) {
case CACTUS, MAGMA_BLOCK, SWEET_BERRY_BUSH, WITHER_ROSE -> block.getType().name();
default -> null;
};
if (type != null) {
return type;
}
}
return null;
}
}
Loading