Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
dde28fa
2x2 Tree grow fix
Chub74 May 26, 2026
37a0d95
Fixed Decompactor still running even after theres no storage space left
Chub74 May 28, 2026
56b22fd
Factory Stuff
Chub74 May 28, 2026
20ef1de
Show days remaining on pearls
grepsedawk May 28, 2026
179f6b6
Fix world comparison in BastionBlock.compareTo
grepsedawk May 30, 2026
50b8c52
Fix swapped server/world in insertData overloads
grepsedawk May 30, 2026
3e79629
Persist applied migration id in Migrator
grepsedawk May 30, 2026
b19528b
Add DestinationScoreboard for rail dest sidebar line
grepsedawk May 31, 2026
87915aa
Update dest sidebar line on destination change and login
grepsedawk May 31, 2026
dd2da6d
Restore dest sidebar line on player join
grepsedawk May 31, 2026
50f52fe
Merge pull request #18 from Chub74/RealisticBiomes
Longboyy Jun 1, 2026
f8f9a00
Merge pull request #20 from grepsedawk/eden-687-show-days-remaining-o…
Longboyy Jun 1, 2026
0efc15a
Merge pull request #24 from Chub74/Factory
Longboyy Jun 1, 2026
0547eb6
Merge pull request #26 from grepsedawk/fix-bastion-world-compareto
Longboyy Jun 2, 2026
4a65805
Merge pull request #27 from grepsedawk/fix-civspy-insert-server-world
Longboyy Jun 2, 2026
4e2eea2
Merge pull request #28 from grepsedawk/fix-nameapi-migrator-persist
Longboyy Jun 2, 2026
db785a2
Cap dest sidebar line to avoid stale entries
grepsedawk Jun 2, 2026
7b75310
Merge pull request #29 from grepsedawk/dest-on-sb
Longboyy Jun 2, 2026
6711355
remove bundle
Tylerrr93 Jun 4, 2026
7140b4c
Fix crawl in combat
Longboyy Jun 6, 2026
bbe5580
Merge remote-tracking branch 'Tylerrr93/main'
Longboyy Jun 6, 2026
0c4a5f9
Remove unfinished AOE repair recipe
grepsedawk Jun 13, 2026
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
7 changes: 7 additions & 0 deletions libraries/name-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,11 @@ dependencies {
api(libs.configurate.yaml)
api("org.mariadb.jdbc:mariadb-java-client:3.5.6")
implementation(libs.slf4j.api)

testImplementation(libs.bundles.junit)
testImplementation("org.mockito:mockito-core:5.11.0")
}

tasks.withType<Test> {
useJUnitPlatform()
}
36 changes: 22 additions & 14 deletions libraries/name-api/src/main/java/net/civmc/nameapi/Migrator.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.NavigableMap;
Expand Down Expand Up @@ -32,33 +33,40 @@ public void registerMigration(String namespace, int id, @Language("mariadb") Str

public void migrate(Connection connection) throws SQLException {
connection.setAutoCommit(false);
connection.createStatement().executeUpdate("CREATE TABLE IF NOT EXISTS migrations (" +
"namespace VARCHAR(64) PRIMARY KEY," +
"id INT NOT NULL)");
try (Statement createTable = connection.createStatement()) {
createTable.executeUpdate("CREATE TABLE IF NOT EXISTS migrations (" +
"namespace VARCHAR(64) PRIMARY KEY," +
"id INT NOT NULL)");
}

for (Map.Entry<String, NavigableMap<Integer, String[]>> entry : migrations.entrySet()) {
PreparedStatement getMigrationId = connection.prepareStatement("SELECT id FROM migrations WHERE namespace = ? FOR UPDATE");
getMigrationId.setString(1, entry.getKey());
ResultSet resultSet = getMigrationId.executeQuery();
int minId;
if (resultSet.next()) {
minId = resultSet.getInt("id");
} else {
minId = -1;
try (PreparedStatement getMigrationId = connection.prepareStatement("SELECT id FROM migrations WHERE namespace = ? FOR UPDATE")) {
getMigrationId.setString(1, entry.getKey());
ResultSet resultSet = getMigrationId.executeQuery();
if (resultSet.next()) {
minId = resultSet.getInt("id");
} else {
minId = -1;
}
}

NavigableMap<Integer, String[]> value = entry.getValue().tailMap(minId, false);
int maxId = entry.getValue().lastKey();
for (String[] migration : value.sequencedValues()) {
for (String sql : migration) {
connection.createStatement().executeUpdate(sql);
try (Statement statement = connection.createStatement()) {
statement.executeUpdate(sql);
}
}
}

if (maxId != minId) {
PreparedStatement setMigrationId = connection.prepareStatement("REPLACE INTO migrations (namespace, id) VALUES (?, ?)");
setMigrationId.setString(1, entry.getKey());
setMigrationId.setInt(2, maxId);
try (PreparedStatement setMigrationId = connection.prepareStatement("REPLACE INTO migrations (namespace, id) VALUES (?, ?)")) {
setMigrationId.setString(1, entry.getKey());
setMigrationId.setInt(2, maxId);
setMigrationId.executeUpdate();
}
}
}
connection.setAutoCommit(true);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package net.civmc.nameapi;

import org.junit.jupiter.api.Test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

class MigratorTest {

@Test
void persistsAppliedMigrationId() throws SQLException {
Connection connection = mock(Connection.class);
when(connection.createStatement()).thenReturn(mock(Statement.class));

ResultSet emptyResult = mock(ResultSet.class);
when(emptyResult.next()).thenReturn(false);

PreparedStatement selectStatement = mock(PreparedStatement.class);
when(selectStatement.executeQuery()).thenReturn(emptyResult);
when(connection.prepareStatement("SELECT id FROM migrations WHERE namespace = ? FOR UPDATE"))
.thenReturn(selectStatement);

PreparedStatement replaceStatement = mock(PreparedStatement.class);
when(connection.prepareStatement("REPLACE INTO migrations (namespace, id) VALUES (?, ?)"))
.thenReturn(replaceStatement);

Migrator migrator = new Migrator();
migrator.registerMigration("test", 0, "SELECT 1");
migrator.migrate(connection);

verify(replaceStatement).setInt(2, 0);
verify(replaceStatement).executeUpdate();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -463,15 +463,14 @@ public String getStrengthText() {
return formatter.format(rein.getHealth()) + "/" + formatter.format(rein.getType().getHealth());
}

// TODO: Test world-aware comparison
@Override
public int compareTo(BastionBlock other) {
UUID thisWorld = location.getWorld().getUID();
int thisX = location.getBlockX();
int thisY = location.getBlockY();
int thisZ = location.getBlockZ();

UUID otherWorld = location.getWorld().getUID();
UUID otherWorld = other.location.getWorld().getUID();
int otherX = other.location.getBlockX();
int otherY = other.location.getBlockY();
int otherZ = other.location.getBlockZ();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package isaac.bastion;

import isaac.bastion.storage.BastionBlockStorage;
import java.util.UUID;
import org.bukkit.Chunk;
import org.bukkit.Location;
import org.bukkit.World;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import vg.civcraft.mc.citadel.Citadel;
import vg.civcraft.mc.citadel.ReinforcementManager;
import vg.civcraft.mc.citadel.model.Reinforcement;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

class BastionBlockCompareToTest {

private MockedStatic<Citadel> citadelStatic;
private MockedStatic<Bastion> bastionStatic;
private BastionType type;

// Locations hold their World via WeakReference; keep strong refs so getWorld() stays valid.
private final UUID worldUidLow = new UUID(0L, 1L);
private final UUID worldUidHigh = new UUID(0L, 2L);
private World worldLow;
private World worldHigh;

@BeforeEach
void setUp() {
worldLow = mockWorld(worldUidLow);
worldHigh = mockWorld(worldUidHigh);

type = mock(BastionType.class);
when(type.getWarmupTime()).thenReturn(0L);

Citadel citadel = mock(Citadel.class);
ReinforcementManager reinforcementManager = mock(ReinforcementManager.class);
Reinforcement reinforcement = mock(Reinforcement.class);
when(reinforcement.getGroupId()).thenReturn(1);
when(reinforcementManager.getReinforcement(any(Location.class))).thenReturn(reinforcement);
when(citadel.getReinforcementManager()).thenReturn(reinforcementManager);

citadelStatic = Mockito.mockStatic(Citadel.class);
citadelStatic.when(Citadel::getInstance).thenReturn(citadel);

Bastion plugin = mock(Bastion.class);
BastionBlockStorage storage = mock(BastionBlockStorage.class);
bastionStatic = Mockito.mockStatic(Bastion.class);
bastionStatic.when(Bastion::getPlugin).thenReturn(plugin);
bastionStatic.when(Bastion::getBastionStorage).thenReturn(storage);
}

@AfterEach
void tearDown() {
try {
citadelStatic.close();
} finally {
bastionStatic.close();
}
}

private World mockWorld(UUID uid) {
World world = mock(World.class);
Chunk chunk = mock(Chunk.class);
when(world.getChunkAt(any(Location.class))).thenReturn(chunk);
when(world.getUID()).thenReturn(uid);
return world;
}

private BastionBlock block(World world, int x, int y, int z) {
return new BastionBlock(new Location(world, x, y, z), 0L, 1, type);
}

@Test
void ordersBlocksByWorldUidWhenCoordsAreIdentical() {
BastionBlock low = block(worldLow, 10, 64, 20);
BastionBlock high = block(worldHigh, 10, 64, 20);

Assertions.assertTrue(low.compareTo(high) < 0,
"block in lower world UID must sort before identical coords in higher world UID");
Assertions.assertTrue(high.compareTo(low) > 0,
"block in higher world UID must sort after identical coords in lower world UID");
Assertions.assertNotEquals(0, low.compareTo(high),
"blocks in different worlds with identical coords must not compare equal");
Assertions.assertNotEquals(low, high,
"blocks in different worlds are distinct instances and not equal");
}

@Test
void compareToIsAntisymmetricAcrossWorldsAndCoords() {
BastionBlock[] blocks = {
block(worldLow, 0, 0, 0),
block(worldLow, 0, 0, 5),
block(worldLow, 0, 7, 0),
block(worldLow, 3, 0, 0),
block(worldHigh, 0, 0, 0),
block(worldHigh, 3, 7, 5),
block(worldHigh, -4, -2, -8),
};

for (BastionBlock a : blocks) {
for (BastionBlock b : blocks) {
Assertions.assertEquals(
Integer.signum(a.compareTo(b)),
-Integer.signum(b.compareTo(a)),
"compareTo must be antisymmetric for every pair");
}
}
}
}
3 changes: 3 additions & 0 deletions plugins/civspy-api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ version = "2.0.1"
dependencies {
implementation("com.zaxxer:HikariCP:3.4.2")
implementation("org.postgresql:postgresql:42.3.5")

testImplementation(libs.bundles.junit)
testImplementation("org.mockito:mockito-core:5.11.0")
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,40 +228,40 @@ public int insertData(String key, UUID uuid, String sValue, Number nValue, Long
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z) {
return insertData(key, world, server, chunk_x, chunk_z, null, null, null, null, null);
return insertData(key, server, world, chunk_x, chunk_z, null, null, null, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, String value) {
return insertData(key, world, server, chunk_x, chunk_z, null, value, null, null, null);
return insertData(key, server, world, chunk_x, chunk_z, null, value, null, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, Number value) {
return insertData(key, world, server, chunk_x, chunk_z, null, null, value, null, null);
return insertData(key, server, world, chunk_x, chunk_z, null, null, value, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, String sValue, Number nValue) {
return insertData(key, world, server, chunk_x, chunk_z, null, sValue, nValue, null, null);
return insertData(key, server, world, chunk_x, chunk_z, null, sValue, nValue, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, String sValue, Number nValue,
Long time, Connection connection) {
return insertData(key, world, server, chunk_x, chunk_z, null, sValue, nValue, time, connection);
return insertData(key, server, world, chunk_x, chunk_z, null, sValue, nValue, time, connection);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, UUID uuid) {
return insertData(key, world, server, chunk_x, chunk_z, uuid, null, null, null, null);
return insertData(key, server, world, chunk_x, chunk_z, uuid, null, null, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, UUID uuid, String value) {
return insertData(key, world, server, chunk_x, chunk_z, uuid, value, null, null, null);
return insertData(key, server, world, chunk_x, chunk_z, uuid, value, null, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, UUID uuid, Number value) {
return insertData(key, world, server, chunk_x, chunk_z, uuid, null, value, null, null);
return insertData(key, server, world, chunk_x, chunk_z, uuid, null, value, null, null);
}

public int insertData(String key, String server, String world, Integer chunk_x, Integer chunk_z, UUID uuid, String sValue, Number nValue) {
return insertData(key, world, server, chunk_x, chunk_z, uuid, sValue, nValue, null, null);
return insertData(key, server, world, chunk_x, chunk_z, uuid, sValue, nValue, null, null);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.programmerdan.minecraft.civspy.database;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

public class DatabaseInsertDataTest {

/**
* INSERT_STRING binds (stat_time, stat_key, string_value, server, world, ...), so with a string value
* present the server column is parameter 4 and the world column is parameter 5.
*/
private static final int SERVER_INDEX = 4;
private static final int WORLD_INDEX = 5;

@Test
public void convenienceOverloadBindsServerAndWorldToCorrectColumns() throws Exception {
Connection connection = Mockito.mock(Connection.class);
PreparedStatement statement = Mockito.mock(PreparedStatement.class);
when(connection.prepareStatement(Database.INSERT_STRING)).thenReturn(statement);
when(statement.executeUpdate()).thenReturn(1);

Database db = new Database(Logger.getLogger("test"), null, null, null, 0, null, 0, 0L, 0L, 0L);

db.insertData("test.key", "the-server", "the-world", 7, 9, "string-value", null, 123L, connection);

ArgumentCaptor<Integer> indexCaptor = ArgumentCaptor.forClass(Integer.class);
ArgumentCaptor<String> valueCaptor = ArgumentCaptor.forClass(String.class);
verify(statement, atLeastOnce()).setString(indexCaptor.capture(), valueCaptor.capture());

Map<Integer, String> boundStrings = new HashMap<>();
List<Integer> indices = indexCaptor.getAllValues();
List<String> values = valueCaptor.getAllValues();
for (int i = 0; i < indices.size(); i++) {
boundStrings.put(indices.get(i), values.get(i));
}

assertEquals("the-server", boundStrings.get(SERVER_INDEX), "server must bind to the server column");
assertEquals("the-world", boundStrings.get(WORLD_INDEX), "world must bind to the world column");
}
}
1 change: 1 addition & 0 deletions plugins/combattagplus-paper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ dependencies {
}

compileOnly(libs.barapi)
compileOnly(files("./libs/GSit-3.3.1.jar"))
}
Binary file added plugins/combattagplus-paper/libs/GSit-3.3.1.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import net.minelink.ctplus.hook.Hook;
import net.minelink.ctplus.hook.HookManager;
import net.minelink.ctplus.listener.ForceFieldListener;
import net.minelink.ctplus.listener.GSitListener;
import net.minelink.ctplus.listener.InstakillListener;
import net.minelink.ctplus.listener.NpcListener;
import net.minelink.ctplus.listener.PlayerListener;
Expand Down Expand Up @@ -112,6 +113,8 @@ public void onEnable() {
Bukkit.getPluginManager().registerEvents(new PlayerListener(this), this);
Bukkit.getPluginManager().registerEvents(new TagListener(this), this);

Bukkit.getPluginManager().registerEvents(new GSitListener(this), this);

// Anti-SafeZone task
ForceFieldTask.run(this);

Expand Down
Loading
Loading