Skip to content

Commit 008bee1

Browse files
authored
Merge pull request #2 from AvionBlock/v1.0.0
V1.0.0
2 parents 85a8efa + ba38ac9 commit 008bee1

File tree

16 files changed

+808
-27
lines changed

16 files changed

+808
-27
lines changed

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build and Publish
1+
name: Build and Archive
22

33
on:
44
push:
@@ -16,7 +16,7 @@ jobs:
1616
- name: Set up JDK
1717
uses: actions/setup-java@v4
1818
with:
19-
distribution: "temurin"
19+
distribution: "zulu"
2020
java-version: "21"
2121

2222
- name: Make gradlew executable

.github/workflows/release.yml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ on:
99
status:
1010
required: true
1111
description: "Status (beta, stable)"
12+
description:
13+
required: false
14+
description: "Release description"
1215

1316
env:
1417
VERSION: ${{ github.event.inputs.tag }}-${{ github.event.inputs.status }}
@@ -24,7 +27,7 @@ jobs:
2427
- name: Set up JDK
2528
uses: actions/setup-java@v4
2629
with:
27-
distribution: "temurin"
30+
distribution: "zulu"
2831
java-version: "21"
2932

3033
- name: Cache Gradle dependencies
@@ -73,7 +76,8 @@ jobs:
7376
with:
7477
prerelease: false
7578
tag: ${{ github.event.inputs.tag }}
76-
artifacts: build/libs/PlayerCorpses-*.jar
79+
artifacts: build/libs/PlayerCorpses-*-shaded.jar
80+
body: ${{ github.event.inputs.description }}
7781
env:
7882
GITHUB_REPOSITORY: AvionBlock/PlayerCorpses
7983

@@ -83,6 +87,7 @@ jobs:
8387
with:
8488
prerelease: true
8589
tag: ${{ github.event.inputs.tag }}
86-
artifacts: build/libs/PlayerCorpses-*.jar
90+
artifacts: build/libs/PlayerCorpses-*-shaded.jar
91+
body: ${{ github.event.inputs.description }}
8792
env:
8893
GITHUB_REPOSITORY: AvionBlock/PlayerCorpses

README.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
11
# PlayerCorpses
2-
Add player corpses to your server.
2+
3+
Add player corpses to your server.
4+
5+
## Requirements
6+
7+
Paper & Folia 1.21.4 with Java 21 (or higher) is required. Plugin should also work on Paper forks.
8+
Spigot is **not** supported.

build.gradle

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
plugins {
1010
id 'java'
11-
id 'com.gradleup.shadow' version '9.0.0-beta9'
11+
id 'com.gradleup.shadow' version '9.0.0-beta10'
1212
}
1313

1414
group = 'io.greitan'
@@ -34,9 +34,9 @@ dependencies {
3434
// Paper API
3535
compileOnly 'io.papermc.paper:paper-api:1.21.4-R0.1-SNAPSHOT'
3636
// FancyNpcs
37-
compileOnly "de.oliver:FancyNpcs:2.4.2"
37+
compileOnly "de.oliver:FancyNpcs:2.4.4"
3838
// FoliaLib
39-
implementation 'com.github.TechnicallyCoded:FoliaLib:0.4.3'
39+
implementation 'com.github.TechnicallyCoded:FoliaLib:0.4.4'
4040

4141
// Lombok
4242
compileOnly 'org.projectlombok:lombok:1.18.36'
@@ -55,15 +55,16 @@ java {
5555
}
5656

5757
shadowJar {
58-
archiveClassifier.set('all')
58+
archiveClassifier.set('shaded')
5959
// Relocate package to avoid conflicts
6060
relocate "com.tcoded.folialib", "io.greitan.avion.lib.folialib"
61+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
6162
}
6263

6364
// Custom task to copy the shadow JAR to a test server
6465
task copyToTestServer(type: Copy) {
6566
from shadowJar // Get the shadow JAR
66-
into "D:\\JavaTest\\plugins" // Define the target directory for the JAR
67+
into "C:\\JavaTest\\plugins" // Define the target directory for the JAR
6768
}
6869

6970
// Ensure shadowJar task is executed after build
Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,58 @@
1+
/*
2+
* Comments generated using 0xAlpha AI Comment Generator v1.4.1
3+
* Copyright (c) 2025 by 0xAlpha. All rights reserved.
4+
* This software is provided "as-is", without warranty of any kind, express or implied.
5+
*/
16
package io.greitan.avion;
27

3-
import lombok.Getter;
4-
import io.greitan.avion.utils.Logger;
58
import org.bukkit.plugin.java.JavaPlugin;
9+
import io.greitan.avion.listeners.*;
10+
import io.greitan.avion.utils.*;
11+
import lombok.Getter;
12+
import net.kyori.adventure.text.minimessage.MiniMessage;
613

14+
/**
15+
* Main class for the PlayerCorpses plugin.
16+
*/
717
public class PlayerCorpses extends JavaPlugin {
18+
819
private static @Getter PlayerCorpses instance;
20+
private static @Getter LocaleManager locManager;
21+
private static @Getter MiniMessage MM = MiniMessage.miniMessage();
922

23+
/**
24+
* Called when the plugin is enabled. Initializes locale manager and registers
25+
* event listeners.
26+
*/
1027
@Override
1128
public void onEnable() {
1229
instance = this;
13-
this.reload();
14-
Logger.info("Plugin enabled!");
30+
reload();
31+
32+
getServer().getPluginManager().registerEvents(new PlayerDeathListener(locManager), this);
33+
getServer().getPluginManager().registerEvents(new NpcInteractListener(locManager), this);
34+
35+
Logger.info(locManager.getMessage("plugin.enabled"));
1536
}
1637

38+
/**
39+
* Called when the plugin is disabled. Logs the shutdown message.
40+
*/
1741
@Override
1842
public void onDisable() {
19-
getLogger().info("Plugin disabled!");
43+
Logger.info(locManager.getMessage("plugin.disabled"));
2044
}
2145

46+
/**
47+
* Reloads the plugin configuration and sets the locale.
48+
*/
2249
public void reload() {
2350
saveDefaultConfig();
2451
reloadConfig();
52+
53+
String locale = getConfig().getString("config.locale", "en_us");
54+
locManager = new LocaleManager(this, locale);
55+
56+
Logger.info("Language set to: " + locale);
2557
}
2658
}
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
/*
2+
* Comments generated using 0xAlpha AI Comment Generator v1.4.1
3+
* Copyright (c) 2025 by 0xAlpha. All rights reserved.
4+
* This software is provided "as-is", without warranty of any kind, express or implied.
5+
*/
6+
package io.greitan.avion.listeners;
7+
8+
import org.bukkit.Bukkit;
9+
import org.bukkit.Location;
10+
import org.bukkit.Material;
11+
import org.bukkit.NamespacedKey;
12+
import org.bukkit.configuration.file.YamlConfiguration;
13+
import org.bukkit.entity.Player;
14+
import org.bukkit.event.EventHandler;
15+
import org.bukkit.event.Listener;
16+
import org.bukkit.event.inventory.InventoryClickEvent;
17+
import org.bukkit.event.inventory.InventoryType;
18+
import org.bukkit.inventory.Inventory;
19+
import org.bukkit.inventory.ItemStack;
20+
import org.bukkit.persistence.PersistentDataType;
21+
22+
import de.oliver.fancynpcs.api.FancyNpcsPlugin;
23+
import de.oliver.fancynpcs.api.Npc;
24+
import de.oliver.fancynpcs.api.events.NpcInteractEvent;
25+
import de.oliver.fancynpcs.api.events.NpcRemoveEvent;
26+
import de.oliver.fancynpcs.api.events.NpcStopLookingEvent;
27+
import io.greitan.avion.PlayerCorpses;
28+
import io.greitan.avion.utils.LocaleManager;
29+
import io.greitan.avion.utils.Logger;
30+
import io.greitan.avion.utils.MenuBuilder;
31+
import io.greitan.avion.utils.YamlBase;
32+
import net.kyori.adventure.text.Component;
33+
34+
import java.util.stream.IntStream;
35+
36+
public class NpcInteractListener implements Listener {
37+
private final LocaleManager localeManager;
38+
private final Component MENU_TITLE;
39+
40+
/**
41+
* Constructor initializes the listener with a locale manager.
42+
*
43+
* @param localeManager Locale manager for handling messages.
44+
*/
45+
public NpcInteractListener(LocaleManager localeManager) {
46+
this.localeManager = localeManager;
47+
this.MENU_TITLE = PlayerCorpses.getMM().deserialize(localeManager.getMessage("menu.title"));
48+
}
49+
50+
/**
51+
* Handles NPC interaction, shows the menu when a player interacts with an NPC.
52+
*
53+
* @param e The NPC interaction event.
54+
*/
55+
@EventHandler
56+
public void npcInteract(NpcInteractEvent e) {
57+
showMenu(e.getPlayer(), e.getNpc());
58+
}
59+
60+
/**
61+
* Handles inventory click events in the menu.
62+
*
63+
* @param event The inventory click event.
64+
*/
65+
@EventHandler
66+
public void onInventoryClick(InventoryClickEvent event) {
67+
if (!(event.getWhoClicked() instanceof Player player))
68+
return;
69+
if (event.getInventory().getType() != InventoryType.CHEST)
70+
return;
71+
if (!event.getView().title().equals(MENU_TITLE))
72+
return;
73+
74+
event.setCancelled(true);
75+
76+
ItemStack clickedItem = event.getCurrentItem();
77+
if (clickedItem == null || clickedItem.getType() == Material.AIR)
78+
return;
79+
80+
// Handle actions based on the clicked item
81+
String action = switch (clickedItem.getType()) {
82+
case ARROW -> "break";
83+
case BARRIER -> "back";
84+
default -> null;
85+
};
86+
87+
if (action != null) {
88+
player.closeInventory();
89+
handleAction(player, action, clickedItem);
90+
}
91+
}
92+
93+
/**
94+
* Executes the appropriate action based on the clicked item.
95+
*
96+
* @param player The player who clicked the item.
97+
* @param action The action to perform.
98+
* @param clickedItem The item clicked.
99+
*/
100+
private void handleAction(Player player, String action, ItemStack clickedItem) {
101+
NamespacedKey key = new NamespacedKey(PlayerCorpses.getInstance(), "corpse");
102+
String npcID = clickedItem.getItemMeta().getPersistentDataContainer().get(key, PersistentDataType.STRING);
103+
switch (action) {
104+
case "break" -> {
105+
if (npcID != null)
106+
breakCorpse(player, npcID);
107+
player.sendMessage(PlayerCorpses.getMM().deserialize(localeManager.getMessage("menu.action.break")));
108+
}
109+
case "back" -> {
110+
player.sendMessage(PlayerCorpses.getMM().deserialize(localeManager.getMessage("menu.action.back")));
111+
}
112+
default -> {
113+
}
114+
}
115+
}
116+
117+
/**
118+
* Breaks the corpse NPC and handles the drop of items from the corpse.
119+
*
120+
* @param player The player interacting with the NPC.
121+
* @param npcID The NPC ID.
122+
*/
123+
private void breakCorpse(Player player, String npcID) {
124+
Npc npc = FancyNpcsPlugin.get().getNpcManager().getNpcById(npcID);
125+
String containerId = npc.getData().getName();
126+
YamlConfiguration containerData;
127+
128+
try {
129+
containerData = YamlBase.loadPlayerData(player.getName(), containerId);
130+
} catch (IllegalStateException e) {
131+
Logger.error(e);
132+
return;
133+
}
134+
135+
Location dropLocation = npc.getData().getLocation();
136+
137+
// Remove NPC and handle its drops
138+
if (new NpcRemoveEvent(npc, Bukkit.getServer().getConsoleSender()).callEvent()) {
139+
npc.removeForAll();
140+
for (Player onlinePlayer : Bukkit.getOnlinePlayers()) {
141+
if (npc.getIsLookingAtPlayer().getOrDefault(onlinePlayer.getUniqueId(), false)) {
142+
npc.getIsLookingAtPlayer().put(onlinePlayer.getUniqueId(), false);
143+
new NpcStopLookingEvent(npc, onlinePlayer).callEvent();
144+
}
145+
}
146+
FancyNpcsPlugin.get().getNpcManager().removeNpc(npc);
147+
148+
// Drop items if any exist
149+
if (containerData.contains("inventory")) {
150+
try {
151+
ItemStack[] inventoryContents = YamlBase
152+
.itemStackArrayFromBase64(containerData.getString("inventory"));
153+
for (ItemStack item : inventoryContents) {
154+
if (item != null) {
155+
dropLocation.getWorld().dropItemNaturally(dropLocation, item);
156+
}
157+
}
158+
} catch (IllegalStateException e) {
159+
Logger.error(e);
160+
}
161+
}
162+
163+
YamlBase.deletePlayerData(player.getName(), containerId);
164+
} else {
165+
player.sendMessage(PlayerCorpses.getMM().deserialize(localeManager.getMessage("corpse.break_error")));
166+
}
167+
}
168+
169+
/**
170+
* Shows the interaction menu for a player and NPC.
171+
*
172+
* @param player The player to show the menu to.
173+
* @param npc The NPC the player is interacting with.
174+
*/
175+
private void showMenu(Player player, Npc npc) {
176+
Inventory inv = Bukkit.createInventory(null, 27, MENU_TITLE);
177+
fillBorders(inv);
178+
inv.setItem(11,
179+
MenuBuilder.createItem(Material.BARRIER, localeManager.getMessage("menu.button.back"),
180+
null, npc.getData().getId()));
181+
inv.setItem(15,
182+
MenuBuilder.createItem(Material.ARROW, localeManager.getMessage("menu.button.break"),
183+
null, npc.getData().getId()));
184+
player.openInventory(inv);
185+
}
186+
187+
/**
188+
* Fills the borders of the inventory with decorative items.
189+
*
190+
* @param inv The inventory to fill.
191+
*/
192+
private void fillBorders(Inventory inv) {
193+
IntStream.range(0, 27)
194+
.filter(i -> i != 11 && i != 15)
195+
.forEach(i -> inv.setItem(i,
196+
MenuBuilder.createItem(Material.LIGHT_BLUE_STAINED_GLASS_PANE, "", null, null)));
197+
}
198+
}

0 commit comments

Comments
 (0)