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
16 changes: 13 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@

Codex gives players a journal of discoveries: places they enter, creatures they
kill and lore that commands unlock. `/codex` opens the journal, and each entry
shows its text once it has been found. This copy tracks upstream 2.12.1 and builds
for Paper 1.21.10. It has no update checker or bStats reporting.
shows its text once it has been found.

Each roleplay character keeps its own journal, so a new character discovers the
world afresh and earns the discovery rewards again. An entry any of the account's
characters has found stays readable for out-of-character reference, and its hover
text names the living characters who can use it in character. What an account
found before journals were per character stays readable this way, but no
character knows it in character until it finds it again. This copy tracks upstream
2.12.1, builds for Paper 1.21.10 and needs TLibs 2.6.1 with RPCharacters. It stores
journals in files only, and has no update checker or bStats reporting.

## Documentation

Expand All @@ -16,7 +24,9 @@ discoveries, actions and placeholders.

## Tests

With Java 21, run `mvn clean verify`.
With Java 21 and the pinned plugin dependencies installed, run `mvn clean verify`.
JUnit and Mockito cover the per-character journals, which must keep 100% line
coverage. Upstream Codex has no tests.

## License

Expand Down
97 changes: 79 additions & 18 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
<properties>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<argLine></argLine>
<tlibs.version>2.6.1</tlibs.version>
</properties>

<dependencies>
Expand All @@ -36,12 +38,6 @@
<version>2.11.6</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>4.0.3</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.sk89q.worldguard</groupId>
<artifactId>worldguard-bukkit</artifactId>
Expand Down Expand Up @@ -72,6 +68,31 @@
<version>6.0.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>me.plugins</groupId>
<artifactId>tlibs</artifactId>
<version>${tlibs.version}</version>
<scope>provided</scope>
<exclusions>
<!-- The server supplies TLibs and its integrations. -->
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.14.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>5.20.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<repositories>
Expand Down Expand Up @@ -139,25 +160,65 @@
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.6.2</version>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.7.0</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.4</version>
<configuration>
<argLine>@{argLine} -javaagent:${org.mockito:mockito-core:jar} -Xshare:off</argLine>
<failIfNoTests>true</failIfNoTests>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.15</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
<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>
<createDependencyReducedPom>false</createDependencyReducedPom>
<relocations>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>net.tfminecraft.codex.libs.hikaricp</shadedPattern>
<!-- TFMC's character code is fully covered; upstream Codex has no tests. -->
<rules>
<rule>
<element>PACKAGE</element>
<includes>
<include>com.zaxxer.hikari.**</include>
<include>net.tfminecraft.codex.character</include>
</includes>
</relocation>
</relocations>
<limits>
<limit>
<counter>LINE</counter>
<value>MISSEDCOUNT</value>
<maximum>0</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
Expand Down
25 changes: 13 additions & 12 deletions src/main/java/net/tfminecraft/codex/Codex.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package net.tfminecraft.codex;

import net.tfminecraft.codex.api.CodexAPI;
import net.tfminecraft.codex.character.CharacterJournals;
import net.tfminecraft.codex.character.CharacterStore;
import net.tfminecraft.codex.api.ExpansionCodex;
import net.tfminecraft.codex.commands.MainCommand;
import net.tfminecraft.codex.config.ConfigsManager;
import net.tfminecraft.codex.database.MySQLConnection;
import net.tfminecraft.codex.listeners.InventoryListener;
import net.tfminecraft.codex.listeners.PlayerListener;
import net.tfminecraft.codex.listeners.dependencies.EliteMobsListener;
Expand Down Expand Up @@ -37,8 +38,8 @@ public class Codex extends JavaPlugin {
private DiscoveryManager discoveryManager;
private DependencyManager dependencyManager;
private PlayerDataManager playerDataManager;
private CharacterJournals characterJournals;

private MySQLConnection mySQLConnection;
private PlayerDataSaveTask playerDataSaveTask;
private VerifyManager verifyManager;

Expand All @@ -61,8 +62,10 @@ public void onEnable(){
return;
}

characterJournals = new CharacterJournals(playerDataManager, new CharacterStore(getDataFolder().toPath()), getLogger());
registerEvents();
registerCommands();
characterJournals.start();

reloadPlayerDataSaveTask();

Expand All @@ -74,16 +77,13 @@ public void onEnable(){
this.verifyManager = new VerifyManager(this);
this.verifyManager.verify();

if(configsManager.getMainConfigManager().isMySQL()){
mySQLConnection = new MySQLConnection(this);
mySQLConnection.setupMySql();
}

Bukkit.getConsoleSender().sendMessage(prefix+MessagesManager.getLegacyColoredMessage("&eHas been enabled! &fVersion: "+version));
}

public void onDisable(){
configsManager.getPlayersConfigManager().saveConfigs();
if(characterJournals != null){
characterJournals.stop();
}

Bukkit.getConsoleSender().sendMessage(prefix+MessagesManager.getLegacyColoredMessage("&eHas been disabled! &fVersion: "+version));
}
Expand All @@ -95,6 +95,7 @@ public void registerEvents(){
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new InventoryListener(this), this);
pm.registerEvents(new PlayerListener(this), this);
pm.registerEvents(characterJournals, this);
if(dependencyManager.getWorldGuardManager() != null){
pm.registerEvents(new WorldGuardListener(this), this);
}
Expand Down Expand Up @@ -210,12 +211,12 @@ public DependencyManager getDependencyManager() {
return dependencyManager;
}

public PlayerDataManager getPlayerDataManager() {
return playerDataManager;
public CharacterJournals getCharacterJournals() {
return characterJournals;
}

public MySQLConnection getMySQLConnection() {
return mySQLConnection;
public PlayerDataManager getPlayerDataManager() {
return playerDataManager;
}

public CategoryManager getCategoryManager() {
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/net/tfminecraft/codex/api/CodexAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static boolean hasCompletedCategory(String playerName, String categoryNam
}

public static PlayerData getPlayerData(Player player){
return plugin.getPlayerDataManager().getPlayer(player,false);
return plugin.getPlayerDataManager().getPlayer(player);
}

public static PlayerData getPlayerData(String playerName){
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package net.tfminecraft.codex.character;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.tfminecraft.codex.model.data.PlayerData;
import net.tfminecraft.codex.model.data.PlayerDataCategory;
import net.tfminecraft.codex.model.data.PlayerDataDiscovery;

/**
* What the account knows beyond the played character, read when a character's session starts: its
* other characters' journals and its journal from before characters had their own. Every such entry
* stays readable for out-of-character reference; only living characters who found it themselves can
* use it in character. The played character's own journal is live, so it is checked separately.
*/
public final class AccountKnowledge {
/** A discovery known elsewhere on the account: a date it was found, and which living characters know it. */
public record Known(String date, List<String> livingNames) {
}

private final String characterName;
private final Map<String, Known> others;

AccountKnowledge(String characterName, Map<String, Known> others) {
this.characterName = characterName;
this.others = others;
}

public static AccountKnowledge empty(String characterName) {
return new AccountKnowledge(characterName, Map.of());
}

public String characterName() {
return characterName;
}

/** The other characters' discoveries, keyed {@code category:discovery}. */
public Known other(String category, String discovery) {
return others.get(key(category, discovery));
}

/** Living characters who know the entry in character, the played character first when it does. */
public List<String> knownInCharacterBy(PlayerData current, String category, String discovery) {
List<String> names = new ArrayList<>();
if (current != null && current.hasDiscovery(category, discovery)) {
names.add(characterName);
}
Known known = other(category, discovery);
if (known != null) {
names.addAll(known.livingNames());
}
return names;
}

static String key(String category, String discovery) {
return category + ":" + discovery;
}

/** Collects journals. Each is added once; dead characters and the old account journal count but are not named. */
static final class Builder {
private final Map<String, String> dates = new HashMap<>();
private final Map<String, List<String>> names = new HashMap<>();

void add(List<PlayerDataCategory> categories, String name, boolean alive) {
for (PlayerDataCategory category : categories) {
for (PlayerDataDiscovery discovery : category.getDiscoveries()) {
String key = key(category.getName(), discovery.getDiscoveryName());
dates.putIfAbsent(key, discovery.getDiscoverDate());
List<String> known = names.computeIfAbsent(key, ignored -> new ArrayList<>());
if (alive) {
known.add(name);
}
}
}
}

AccountKnowledge build(String characterName) {
Map<String, Known> others = new HashMap<>();
names.forEach((key, known) -> others.put(key, new Known(dates.get(key), List.copyOf(known))));
return new AccountKnowledge(characterName, Map.copyOf(others));
}
}
}
Loading
Loading