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
8 changes: 8 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,11 @@ jobs:
name: unit-test-reports-${{ github.run_id }}-${{ github.run_attempt }}
path: target/surefire-reports/
if-no-files-found: error

- name: Upload coverage report
if: ${{ !cancelled() && hashFiles('target/site/jacoco/jacoco.xml') != '' }}
uses: actions/upload-artifact@v7
with:
name: coverage-report-${{ github.run_id }}-${{ github.run_attempt }}
path: target/site/jacoco/
if-no-files-found: error
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,14 @@ mvn -B --no-transfer-progress clean verify
JUnit 5 and Mockito cover track geometry, train routing and placement, persistence,
locomotive behaviour and other logic that runs without a server. They do not start a
live Paper server or load ModelEngine models. The Build workflow runs the suite on pull
requests targeting `main` and on pushes to `main` and uploads the Surefire reports. No coverage gate is
enforced.
requests targeting `main` and on pushes to `main` and uploads the Surefire reports. JaCoCo requires 100% line coverage across all production classes, with no
coverage exclusions. HTML and XML reports are written to `target/site/jacoco/`
and uploaded by the Build workflow.

bStats is bundled from the upstream `bstats-bukkit:3.1.0` Maven artifact and
relocated into the plugin's namespace. This replaces the same-version vendored
copy; third-party dependency bytecode is outside the plugin's production-source
coverage denominator. Metrics configuration and lifecycle integration remain tested.

## License

Expand Down
63 changes: 63 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@
</properties>

<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.2.8.Final</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bstats</groupId>
<artifactId>bstats-bukkit</artifactId>
<version>3.1.0</version>
</dependency>
<!-- ModelEngine mount APIs expose these types. -->
<dependency>
<groupId>it.unimi.dsi</groupId>
Expand Down Expand Up @@ -132,9 +143,19 @@
<version>2.0.17</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>7.0.61</version>
<scope>test</scope>
</dependency>
</dependencies>

<repositories>
<repository>
<id>minecraft-libraries</id>
<url>https://libraries.minecraft.net/</url>
</repository>
<repository>
<id>papermc</id>
<url>https://repo.papermc.io/repository/maven-public/</url>
Expand Down Expand Up @@ -168,6 +189,38 @@
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.15</version>
<executions>
<execution><goals><goal>prepare-agent</goal></goals></execution>
<execution>
<id>coverage-report</id>
<phase>verify</phase>
<goals><goal>report</goal></goals>
</execution>
<execution>
<id>coverage-check</id>
<phase>verify</phase>
<goals><goal>check</goal></goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>MISSEDCOUNT</value>
<maximum>0</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
Expand All @@ -177,6 +230,12 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<systemPropertyVariables>
<!-- Tests run before shading; the runtime JAR uses the relocation below. -->
<bstats.relocatecheck>false</bstats.relocatecheck>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down Expand Up @@ -217,6 +276,10 @@
</filter>
</filters>
<relocations>
<relocation>
<pattern>org.bstats</pattern>
<shadedPattern>net.tfminecraft.vehicleframework.shadeutils.bstats</shadedPattern>
</relocation>
<relocation>
<pattern>org.apache.commons.lang3</pattern>
<shadedPattern>net.tfminecraft.vehicleframework.shadeutils.lang3</shadedPattern>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import net.tfminecraft.vehicleframework.managers.CommandManager;
import net.tfminecraft.vehicleframework.managers.VehicleManager;
import net.tfminecraft.vehicleframework.protocol.VehiclePacketListener;
import net.tfminecraft.vehicleframework.util.Metrics;
import org.bstats.bukkit.Metrics;
import net.tfminecraft.vehicleframework.util.MythicMobsIntegration;
import net.tfminecraft.vehicleframework.util.TabCompletion;
import net.tfminecraft.vehicleframework.tracks.TrackBuildAnimator;
Expand Down Expand Up @@ -187,7 +187,7 @@ public void loadConfigs() {
configLoader.load(new File(getDataFolder(), "config.yml"));
trainsLoader.load(new File(getDataFolder(), "trains.yml"));
VFLogger.info("Loading fuel...");
fuelLoader.load(new File(getDataFolder(), "fuel.yml"));
fuelLoader.reload(new File(getDataFolder(), "fuel.yml"));
weaponTemplateLoader.clear();
VFLogger.info("Loading weapon templates...");
weaponTemplateLoader.loadFolder(new File(getDataFolder(), "templates/weapons"));
Expand All @@ -201,19 +201,11 @@ public void loadConfigs() {
deathTemplateLoader.loadFolder(new File(getDataFolder(), "templates/death"));
File folder = new File(getDataFolder(), "vehicles");
VFLogger.info("Loading vehicles...");
for (final File file : folder.listFiles()) {
if(!file.isDirectory()) {
vehicleLoader.load(file);
}
}
vehicleLoader.reload(folder);

folder = new File(getDataFolder(), "ammunition");
VFLogger.info("Loading ammunition...");
for (final File file : folder.listFiles()) {
if(!file.isDirectory()) {
ammunitionLoader.load(file);
}
}
ammunitionLoader.reload(folder);
GroundEngineLog.configure(Cache.groundEngineLogging, Cache.wipeLog, getDataFolder());
TrackLog.configure(Cache.debugLogging, Cache.debugLogging, getDataFolder());
PersistenceLog.configure(Cache.persistenceLogging, getDataFolder());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ private void rotateNoAdd(double x, double y, double z) {
}

public void normalize(boolean nx, boolean ny, boolean nz) {
rotateToTarget(0f, 0f, 0f, 2f, true, true, true);
rotateToTarget(0f, 0f, 0f, 1f, ny, nx, nz);
}

public AxisAngle4d getAngles() {
Expand Down
41 changes: 21 additions & 20 deletions src/main/java/net/tfminecraft/vehicleframework/cache/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,30 +20,31 @@ public class Cache {

public static HashMap<Material, Material> convertExplode = new HashMap<>();

public static int despawnDistance;
// Keep the same defaults as an empty config if the first YAML load fails.
public static int despawnDistance = 64 * 64;

public static boolean blockDamage;
public static boolean blockDamage = true;

public static Set<Location> lightLocations = new HashSet<>();

public static String skinItem;
public static String repairItem;
public static String destroyItem;
public static String ticketItem;
public static String trackItemSmall;
public static String trackItemMedium;
public static String trackItemLarge;
public static String skinItem = "v.bucket";
public static String repairItem = "v.iron_shovel";
public static String destroyItem = "v.stone_axe";
public static String ticketItem = "v.paper";
public static String trackItemSmall = "ia.tfmc:track_small";
public static String trackItemMedium = "ia.tfmc:track_medium";
public static String trackItemLarge = "ia.tfmc:track_large";
public static String appliedTrackItemSmall;
public static String appliedTrackItemMedium;
public static String appliedTrackItemLarge;
public static double appliedTrackDisplayYOffset = 0.5;
public static int trackResyncChunksPerTick = 2;
public static String trackLayerItem;
public static String trackRemoverItem;
public static String trackRecorderItem;
public static String trackJunctionItem;
public static String trackSwitchItem;
public static String trackItem;
public static String trackLayerItem = "v.iron_shovel";
public static String trackRemoverItem = "v.iron_pickaxe";
public static String trackRecorderItem = "v.clock";
public static String trackJunctionItem = "v.diamond_shovel";
public static String trackSwitchItem = "ia.tfmc:railroad_switch";
public static String trackItem = "ia.tfmc:train_track";
public static double trackSwitchOffsetAlong = -1.2;
public static double trackSwitchOffsetOut = 2.4;
public static double trackSwitchOffsetY = 0;
Expand All @@ -69,8 +70,8 @@ public class Cache {
public static double trackJunctionArmDistance = 16;
public static double trackDesiredGradeDegrees = 6;
public static double trackMaxGradeDegrees = 10;
public static Particle trackFxParticle;
public static Material trackFxBlock;
public static Particle trackFxParticle = Particle.BLOCK;
public static Material trackFxBlock = Material.GRAVEL;
public static int trackFxCount = 3;
public static int trackFxWidth = 3;
public static double trackFxExtra = 0.06;
Expand All @@ -87,15 +88,15 @@ public class Cache {
public static String trackBuildSound2 = "minecraft:block.iron.place";
public static float trackBuildSound2Volume = 1.0f;
public static float trackBuildSound2Pitch = 2.0f;
public static Particle trackBuildParticle;
public static Material trackBuildBlock;
public static Particle trackBuildParticle = Particle.BLOCK;
public static Material trackBuildBlock = Material.GRAVEL;
public static int trackBuildCount = 6;
public static int trackBuildWidth = 1;
public static double trackBuildExtra = 0.08;
public static double trackBuildYOffset = 0.08;

public static boolean enableLogging;
public static String mythicMob;
public static String mythicMob = "none";

public static boolean allowWhitelist;
public static boolean whitelistedByDefault;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public DamageData(List<String> list) {
return;
}
for(String s : list) {
String type = s.split("\\(")[0].toUpperCase();
String type = s.split("\\(")[0].toUpperCase(java.util.Locale.ROOT);
Double damage = Double.parseDouble(s.split("\\(")[1].replace(")", ""));
modifiers.put(type, damage);
}
Expand All @@ -26,7 +26,7 @@ public DamageData(Map<String, Object> map) {
if (entry.getKey() == null || entry.getValue() == null) {
continue;
}
modifiers.put(entry.getKey().toUpperCase(), toDouble(entry.getValue()));
modifiers.put(entry.getKey().toUpperCase(java.util.Locale.ROOT), toDouble(entry.getValue()));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class DeathOverride {

public DeathOverride(ConfigurationSection config) {
conditions = config.getStringList("conditions");
death = VehicleDeath.valueOf(config.getString("type").toUpperCase());
death = VehicleDeath.valueOf(config.getString("type").toUpperCase(java.util.Locale.ROOT));
}

public List<String> getConditions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public class ParticleData {

public ParticleData(ConfigurationSection config) {
try {
particle = Particle.valueOf(config.getString("particle", "FLAME").toUpperCase());
particle = Particle.valueOf(config.getString("particle", "FLAME").toUpperCase(java.util.Locale.ROOT));
} catch (Exception e) {
// TODO: handle exception
particle = Particle.FLAME;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void playSound(List<Player> players, Location loc, Vector speed, float pi
// Calculate the relative velocity along the direction of the sound
Vector relativePosition = loc.toVector().subtract(playerLoc.toVector()); // Source to listener
double distance = relativePosition.length(); // Normalize to get direction
relativePosition.normalize();
if (distance > 0) relativePosition.multiply(1.0 / distance);

// Project the speed and player velocity onto the direction vector
double sourceVelocity = speed.dot(relativePosition); // Source velocity along line of sight
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,7 @@ public static SnapshotAttempt tryFromLive(ActiveVehicle vehicle) {
String message = ex.getMessage();
return SnapshotAttempt.fail(message == null || message.isBlank() ? "encode failed" : "encode failed: " + message);
}
if (payload == null || payload.isBlank()) {
return SnapshotAttempt.fail("empty payload");
}
String owner = vehicle.getOwnerData() == null ? "none" : vehicle.getOwnerData().getOwner();
String owner = vehicle.getOwnerData().getOwner();
double x = loc.getX();
double z = loc.getZ();
return SnapshotAttempt.ok(new VehicleSnapshot(
Expand Down Expand Up @@ -166,7 +163,7 @@ private static String encodePayload(ActiveVehicle v) {
default:
break;
}
componentsObject.put(type.toString().toLowerCase(), componentData);
componentsObject.put(type.toString().toLowerCase(java.util.Locale.ROOT), componentData);
}
vehicleData.put("components", componentsObject);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ public synchronized void logEntry(String s) {
}

// Check if rotation is needed
long lineCount = Files.lines(logFile.toPath()).count();
long lineCount;
try (var lines = Files.lines(logFile.toPath())) {
lineCount = lines.count();
}
if (lineCount > 400) {
rotateLog();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static Optional<IncompleteVehicle> decode(JSONObject json, String uuid) {
? asInt(componentData.get("sinkprogress"))
: 0;
try {
Component c = Component.valueOf(componentType.toUpperCase());
Component c = Component.valueOf(componentType.toUpperCase(java.util.Locale.ROOT));
switch (c) {
case ENGINE:
if (componentData.containsKey("throttle")) {
Expand Down Expand Up @@ -247,7 +247,7 @@ public static String encode(IncompleteVehicle vehicle) {
if (type == Component.GEARED_ENGINE) {
componentData.put("gear", (long) vehicle.getGear());
}
componentsObject.put(type.toString().toLowerCase(), componentData);
componentsObject.put(type.toString().toLowerCase(java.util.Locale.ROOT), componentData);
}
}
json.put("components", componentsObject);
Expand Down Expand Up @@ -353,27 +353,31 @@ private static boolean bool(Object value) {

private static float asFloat(Object value) {
if (value instanceof Number number) {
return number.floatValue();
float result = number.floatValue();
return Float.isFinite(result) ? result : 0f;
}
if (value == null) {
return 0f;
}
try {
return Float.parseFloat(String.valueOf(value));
float result = Float.parseFloat(String.valueOf(value));
return Float.isFinite(result) ? result : 0f;
} catch (NumberFormatException ex) {
return 0f;
}
}

private static double asDouble(Object value) {
if (value instanceof Number number) {
return number.doubleValue();
double result = number.doubleValue();
return Double.isFinite(result) ? result : 0d;
}
if (value == null) {
return 0d;
}
try {
return Double.parseDouble(String.valueOf(value));
double result = Double.parseDouble(String.valueOf(value));
return Double.isFinite(result) ? result : 0d;
} catch (NumberFormatException ex) {
return 0d;
}
Expand Down
Loading