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
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.proc>full</maven.compiler.proc>
<coreprotect.version>25.0.0</coreprotect.version>
<tlibs.version>2.0.0</tlibs.version>
<tlibs.version>2.4.1</tlibs.version>
<vehicleframework.version>2.0.1</vehicleframework.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,21 @@
public interface ConstructionFreeze {

/**
* @param constructorUuid player who started the project
* @param constructorUuid account that started the project
* @return why the project is paused, shown under the station timer, or null to keep counting down
*/
String freezeReason(UUID constructorUuid);

/**
* Stations call this form. Override it to freeze by character; the default asks
* {@link #freezeReason(UUID)} with the account.
*
* @param constructorUuid account that started the project
* @param constructorCharacterId character the account was playing when the project started,
* or null when it had no current character session or the project predates the field
* @return why the project is paused, or null to keep counting down
*/
default String freezeReason(UUID constructorUuid, UUID constructorCharacterId) {
return freezeReason(constructorUuid);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,22 @@ private ConstructionFreezes() {

/** @return the first freeze reason for this constructor, or null when nothing pauses it */
public static String reason(UUID constructorUuid) {
return reason(constructorUuid, null);
}

/**
* @param constructorCharacterId may be null; providers then decide by account
* @return the first freeze reason for this constructor, or null when nothing pauses it
*/
public static String reason(UUID constructorUuid, UUID constructorCharacterId) {
if (constructorUuid == null) {
return null;
}
for (RegisteredServiceProvider<ConstructionFreeze> registration
: Bukkit.getServicesManager().getRegistrations(ConstructionFreeze.class)) {
String reason;
try {
reason = registration.getProvider().freezeReason(constructorUuid);
reason = registration.getProvider().freezeReason(constructorUuid, constructorCharacterId);
} catch (RuntimeException e) {
// A broken provider must not stall every station on the server.
continue;
Expand Down
33 changes: 30 additions & 3 deletions src/main/java/net/tfminecraft/vfbuilders/core/ActiveStation.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class ActiveStation {
private Location loc;
private Location spawnLoc;
private UUID constructorUuid;
private UUID constructorCharacterId;

private TextDisplay timerDisplay;
private String freezeReason;
Expand All @@ -51,11 +52,23 @@ public ActiveStation(
int timeLeft,
Location spawnLoc,
UUID constructorUuid) {
this(loc, station, blueprintId, timeLeft, spawnLoc, constructorUuid, null);
}

public ActiveStation(
Location loc,
Station station,
String blueprintId,
int timeLeft,
Location spawnLoc,
UUID constructorUuid,
UUID constructorCharacterId) {
this.id = UUID.randomUUID();
this.loc = loc;
this.station = station;
this.timeLeft = timeLeft;
this.constructorUuid = constructorUuid;
this.constructorCharacterId = constructorCharacterId;

if (blueprintId != null) {
Blueprint blueprint = BlueprintLoader.getByString(blueprintId);
Expand All @@ -72,9 +85,14 @@ public ActiveStation(


public void selectBlueprint(Blueprint b, UUID constructorUuid) {
selectBlueprint(b, constructorUuid, null);
}

public void selectBlueprint(Blueprint b, UUID constructorUuid, UUID constructorCharacterId) {
blueprint = b;
timeLeft = b.getTime();
this.constructorUuid = constructorUuid;
this.constructorCharacterId = constructorCharacterId;
freezeReason = null;
ensureDisplay();
}
Expand All @@ -85,7 +103,7 @@ public boolean tick() {
return true;
}

String reason = ConstructionFreezes.reason(constructorUuid);
String reason = ConstructionFreezes.reason(constructorUuid, constructorCharacterId);
if (reason != null) {
freezeReason = reason;
ensureDisplay();
Expand Down Expand Up @@ -125,7 +143,8 @@ public void complete() {

Location completedSpawn = spawnLoc.clone();
Bukkit.getPluginManager().callEvent(
new VehicleConstructEvent(constructorUuid, vehicle, blueprint, completedSpawn, this));
new VehicleConstructEvent(
constructorUuid, constructorCharacterId, vehicle, blueprint, completedSpawn, this));

// Visual effects
Location center = completedSpawn.clone().add(0.5, 1, 0.5);
Expand All @@ -140,18 +159,21 @@ public void complete() {
spawnLoc = null;
blueprint = null;
constructorUuid = null;
constructorCharacterId = null;
}

public void cancelConstruction() {
if (blueprint != null) {
blueprint.drop(loc.clone().add(0.5, 1, 0.5));
Bukkit.getPluginManager().callEvent(
new VehicleConstructionCancelEvent(constructorUuid, blueprint, this));
new VehicleConstructionCancelEvent(
constructorUuid, constructorCharacterId, blueprint, this));
}
removeHolograms();
spawnLoc = null;
blueprint = null;
constructorUuid = null;
constructorCharacterId = null;
freezeReason = null;
timeLeft = 0;
}
Expand Down Expand Up @@ -200,6 +222,11 @@ public UUID getConstructorUuid() {
return constructorUuid;
}

/** Null when the constructor had no current character session, or for older saved projects. */
public UUID getConstructorCharacterId() {
return constructorCharacterId;
}

public void rebindDefinitions() {
if (station != null) {
Station updatedStation = StationLoader.getByString(station.getId());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package net.tfminecraft.vfbuilders.core;

import java.util.UUID;

import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import net.tfminecraft.tlibs.character.Characters;

/**
* The character a player builds as. TLibs' session API is probed on first use, so an older
* TLibs records no character instead of failing every build. Main thread only.
*/
public final class ConstructorCharacter {

static final String API = "net.tfminecraft.tlibs.character.Characters";
static final String SESSION = "net.tfminecraft.tlibs.character.CharacterSession";

static Boolean available;

private ConstructorCharacter() {
}

/**
* @return the player's current character, or null when the player has no current session
* or TLibs lacks the session API
*/
public static UUID of(Player player) {
if (available == null) {
available = probe(API);
}
return available ? current(player) : null;
}

static boolean probe(String api) {
try {
Class<?> characters = Class.forName(api);
characters.getMethod("currentSession", Player.class);
characters.getMethod("isCurrent", Class.forName(SESSION));
return true;
} catch (ReflectiveOperationException | LinkageError e) {
Bukkit.getLogger().warning(
"[VFBuilders] TLibs has no character session API; constructions record no character");
return false;
}
}

private static UUID current(Player player) {
return Characters.currentSession(player)
.filter(Characters::isCurrent)
.map(session -> session.ref().characterId())
.orElse(null);
}
}
34 changes: 22 additions & 12 deletions src/main/java/net/tfminecraft/vfbuilders/data/Database.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ public static void saveStations(Map<Location, ActiveStation> stations) {
data.spawnLocation = station.hasSpawnLocation() ? toSerializableLoc(station.getSpawnLocation()) : null;
data.blueprintId = station.hasBlueprint() ? station.getBlueprint().getId() : null;
data.timeLeft = station.getTimeLeft();
if (station.hasBlueprint() && station.getConstructorUuid() != null) {
data.constructorUuid = station.getConstructorUuid().toString();
if (station.hasBlueprint()) {
data.constructorUuid = toText(station.getConstructorUuid());
data.constructorCharacterId = toText(station.getConstructorCharacterId());
}

dataList.add(data);
Expand All @@ -60,22 +61,15 @@ public static HashMap<Location, ActiveStation> loadStations() {
Station baseStation = StationLoader.getByString(data.stationId);
if (baseStation == null) continue;

UUID constructorUuid = null;
if (data.constructorUuid != null && !data.constructorUuid.isEmpty()) {
try {
constructorUuid = UUID.fromString(data.constructorUuid);
} catch (IllegalArgumentException ignored) {
constructorUuid = null;
}
}

ActiveStation station = new ActiveStation(
loc,
baseStation,
data.blueprintId,
data.timeLeft,
data.spawnLocation != null ? toBukkitLoc(data.spawnLocation) : null,
constructorUuid
toUuid(data.constructorUuid),
// Stations saved before 2.2.0 have no character; SimpleFactions resolves the heir.
toUuid(data.constructorCharacterId)
);

loaded.put(loc, station);
Expand All @@ -88,6 +82,21 @@ public static HashMap<Location, ActiveStation> loadStations() {
}

// === Serializable Helpers ===
private static String toText(UUID id) {
return id != null ? id.toString() : null;
}

private static UUID toUuid(String text) {
if (text == null || text.isEmpty()) {
return null;
}
try {
return UUID.fromString(text);
} catch (IllegalArgumentException ignored) {
return null;
}
}

private static SerializableLoc toSerializableLoc(Location loc) {
return new SerializableLoc(loc.getWorld().getName(), loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
}
Expand Down Expand Up @@ -115,6 +124,7 @@ private static class StationData {
String blueprintId;
int timeLeft;
String constructorUuid;
String constructorCharacterId;
}
}

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package net.tfminecraft.vfbuilders.events;

import java.util.UUID;

import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
Expand All @@ -13,6 +15,7 @@ public class BeginVehicleConstructionEvent extends Event implements Cancellable
private static final HandlerList HANDLERS = new HandlerList();

private final Player constructor;
private final UUID constructorCharacterId;
private final Blueprint blueprint;
private final ActiveStation station;
private final Location spawnLocation;
Expand All @@ -24,7 +27,17 @@ public BeginVehicleConstructionEvent(
Blueprint blueprint,
ActiveStation station,
Location spawnLocation) {
this(constructor, null, blueprint, station, spawnLocation);
}

public BeginVehicleConstructionEvent(
Player constructor,
UUID constructorCharacterId,
Blueprint blueprint,
ActiveStation station,
Location spawnLocation) {
this.constructor = constructor;
this.constructorCharacterId = constructorCharacterId;
this.blueprint = blueprint;
this.station = station;
this.spawnLocation = spawnLocation;
Expand All @@ -35,6 +48,14 @@ public Player getConstructor() {
return constructor;
}

/**
* The character the constructor is playing, recorded on the station if construction starts.
* Null when the player has no current character session.
*/
public UUID getConstructorCharacterId() {
return constructorCharacterId;
}

public Blueprint getBlueprint() {
return blueprint;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public class VehicleConstructEvent extends Event {
private static final HandlerList HANDLERS = new HandlerList();

private final UUID constructorUuid;
private final UUID constructorCharacterId;
private final Player constructor;
private final ActiveVehicle vehicle;
private final Blueprint blueprint;
Expand All @@ -28,18 +29,38 @@ public VehicleConstructEvent(
Blueprint blueprint,
Location spawnLocation,
ActiveStation station) {
this(constructorUuid, null, vehicle, blueprint, spawnLocation, station);
}

public VehicleConstructEvent(
UUID constructorUuid,
UUID constructorCharacterId,
ActiveVehicle vehicle,
Blueprint blueprint,
Location spawnLocation,
ActiveStation station) {
this.constructorUuid = constructorUuid;
this.constructorCharacterId = constructorCharacterId;
this.constructor = constructorUuid != null ? Bukkit.getPlayer(constructorUuid) : null;
this.vehicle = vehicle;
this.blueprint = blueprint;
this.spawnLocation = spawnLocation;
this.station = station;
}

/** The account that started the project. */
public UUID getConstructorUuid() {
return constructorUuid;
}

/**
* The character the account was playing when the project started. Null when it had no
* current character session, or for projects saved before the character was recorded.
*/
public UUID getConstructorCharacterId() {
return constructorCharacterId;
}

public Player getConstructor() {
return constructor;
}
Expand Down
Loading