Skip to content
Merged
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
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
<rpcharacters.version>2.4.0</rpcharacters.version>
<tlibs.version>2.0.0</tlibs.version>
<rpcharacters.version>2.16.0</rpcharacters.version>
<tlibs.version>2.3.0</tlibs.version>
</properties>

<dependencies>
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/net/tfminecraft/surgery/SurgeryPlugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ public class SurgeryPlugin extends JavaPlugin {

@Override
public void onEnable() {
try {
net.tfminecraft.tlibs.character.Characters.available();
} catch (LinkageError error) {
getLogger().severe("Surgery requires TLibs 2.3.0 or newer. Update TLibs and restart the server.");
getServer().getPluginManager().disablePlugin(this);
return;
}
instance = this;

saveDefaultConfig();
Expand Down Expand Up @@ -45,6 +52,9 @@ public void onDisable() {
// the abandonment handler, which tries to schedule a task on a
// disabling plugin (IllegalPluginAccessException)
HandlerList.unregisterAll(this);
if (surgeryMenuManager != null) {
surgeryMenuManager.shutdown();
}

// Close open surgery menus. After a reload the holder class comes from
// a new classloader, so the instanceof check in the listener no longer
Expand Down
19 changes: 15 additions & 4 deletions src/main/java/net/tfminecraft/surgery/commands/SurgeryCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import net.tfminecraft.surgery.managers.SurgeryUIUpdater;
import net.tfminecraft.surgery.procedures.Ailments;
import net.tfminecraft.surgery.procedures.Durations;
import net.tfminecraft.tlibs.character.CharacterSession;
import net.tfminecraft.tlibs.character.Characters;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.Command;
Expand Down Expand Up @@ -71,7 +73,9 @@ private void offer(Player surgeon, String patientName) {
surgeon.sendMessage(uiUpdater.getMessage("command-player-not-found", "&cPlayer not found or not online!"));
return;
}
if (!checkCanStart(surgeon, patient)) {
CharacterSession surgeonSession = Characters.currentSession(surgeon).orElse(null);
CharacterSession patientSession = Characters.currentSession(patient).orElse(null);
if (!checkCanStart(surgeon, patient, surgeonSession, patientSession)) {
return;
}

Expand All @@ -88,7 +92,7 @@ private void offer(Player surgeon, String patientName) {
}

int timeoutSeconds = Math.max(10, plugin.getConfig().getInt("request-timeout-seconds", 60));
requests.offer(patient.getUniqueId(), surgeon.getUniqueId(), ailment.traitId(),
requests.offer(patientSession, surgeonSession, ailment.traitId(),
now + timeoutSeconds * 1000L);

String ailmentName = ChatColor.stripColor(ailment.displayName());
Expand Down Expand Up @@ -125,7 +129,7 @@ private void accept(Player patient) {
patient.sendMessage(uiUpdater.getMessage("request-surgeon-gone"));
return;
}
if (!checkCanStart(surgeon, patient)) {
if (!checkCanStart(surgeon, patient, request.surgeonSession(), request.patientSession())) {
patient.sendMessage(uiUpdater.getMessage("request-cannot-start").replace("%surgeon%", surgeon.getName()));
return;
}
Expand Down Expand Up @@ -162,7 +166,14 @@ private boolean canOperate(Player surgeon) {
// ==============================================
// Checks shared by offering and accepting; messages the surgeon on failure
// ==============================================
private boolean checkCanStart(Player surgeon, Player patient) {
private boolean checkCanStart(Player surgeon, Player patient,
CharacterSession surgeonSession, CharacterSession patientSession) {
if (surgeonSession == null || patientSession == null
|| !Characters.isCurrent(surgeonSession) || !Characters.isCurrent(patientSession)) {
surgeon.sendMessage(uiUpdater.getMessage("command-character-required",
"&cBoth characters must be ready before surgery."));
return false;
}
// Block re-entry: opening a second menu fires the old menu's close event,
// which fails the surgery and wipes the freshly initialized session
if (menuManager.getStateManager().hasSession(surgeon.getUniqueId())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@
import org.bukkit.event.Listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.ItemStack;
import net.tfminecraft.rpcharacters.lifecycle.CharacterActivatedEvent;
import net.tfminecraft.rpcharacters.permadeath.CharacterPermakillEvent;
import net.tfminecraft.tlibs.character.CharacterSessionEndEvent;
import net.tfminecraft.surgery.managers.SurgeryMenuManager;

public class PlayerListener implements Listener {
Expand All @@ -21,34 +19,9 @@ public PlayerListener(SurgeryMenuManager menuManager) {
this.menuManager = menuManager;
}

// LOW runs before RPCharacters unloads the quitting player's characters,
// so the failure command and penalty still find the same character
@EventHandler(priority = EventPriority.LOW)
public void onPlayerQuit(PlayerQuitEvent event) {
// Fail an in-progress surgery (quitting is not a free escape from the
// failure command) and remove leftover state so nothing leaks
menuManager.handleSurgeonQuit(event.getPlayer());

// The quitting player may also be someone's patient; fail that surgeon's
// surgery now instead of on their next move
menuManager.handlePatientQuit(event.getPlayer());

// Pending offers to or from the quitting player can no longer be answered
menuManager.getRequestManager().forget(event.getPlayer().getUniqueId());
}

@EventHandler
public void onCharacterActivated(CharacterActivatedEvent event) {
// The operation belongs to the characters who began it; a switch or
// permakill ends it before the result can land on another character
menuManager.handleCharacterActivated(event.getOwnerUuid(), event.getCharacter().getId());
}

@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onCharacterPermakill(CharacterPermakillEvent event) {
// The kill is certain once no listener cancelled it; the last
// character's death fires no activation, so it is handled here
menuManager.handleCharacterPermakilled(event.getPlayer().getUniqueId(), event.getCharacter().getId());
@EventHandler(priority = EventPriority.LOWEST)
public void onSessionEnd(CharacterSessionEndEvent event) {
menuManager.handleSessionEnd(event);
}

@EventHandler
Expand Down Expand Up @@ -76,7 +49,7 @@ public void onInventoryClick(InventoryClickEvent event) {
int slot = event.getSlot();

// Handle the click
menuManager.handleItemClick(player, clickedItem, slot);
menuManager.handleItemClick(player, event.getInventory(), clickedItem, slot);
}
}
}
Expand All @@ -89,7 +62,7 @@ public void onInventoryClose(InventoryCloseEvent event) {
if (event.getPlayer() instanceof Player) {
Player player = (Player) event.getPlayer();
// Handle abandonment (giving up on surgery)
menuManager.handleSurgeryAbandonment(player);
menuManager.handleSurgeryAbandonment(player, event.getInventory());
}
}
}
Expand Down
Loading