Skip to content

Commit a095229

Browse files
committed
JavaDocs/Stats/PlaceholderAPI support
Still need to remove stats on class leave, will sort next
1 parent a1f82a7 commit a095229

30 files changed

Lines changed: 853 additions & 23 deletions

build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,17 @@ repositories {
7373
includeGroup("modtale")
7474
}
7575
}
76+
maven {
77+
url = 'https://repo.helpch.at/releases/'
78+
}
7679
}
7780

7881
dependencies {
7982
vineflowerTool 'org.vineflower:vineflower:1.11.2'
8083
implementation("com.azuredoom.levelingcore:LevelingCore:0.+")
8184
vineImplementation 'curse.maven:hyui-1431415:7693755'
8285
vineImplementation 'curse.maven:dynamictooltipslib-1459711:7702598'
86+
vineCompileOnly 'at.helpch:placeholderapi-hytale:1.0.7'
8387
//vineImplementation 'modtale:3e453e84-81af-46bf-9e7d-c7de99d9c4f0:0.1.0-alpha@jar'
8488
//compileOnly fileTree(dir: "$rootDir/libs", include: ["*.jar"])
8589
//runtimeOnly fileTree(dir: "$rootDir/libs", include: ["*.jar"])

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
v0.1.0
2+
- Initial release with basic class support and equipment rules.

src/main/java/com/azuredoom/classescore/ClassesCore.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@
1414

1515
import com.azuredoom.classescore.api.ClassesCoreAPI;
1616
import com.azuredoom.classescore.bootstrap.ClassesBootstrap;
17-
import com.azuredoom.classescore.command.ClassCommand;
17+
import com.azuredoom.classescore.command.JoinClassCommand;
1818
import com.azuredoom.classescore.command.LeaveClassCommand;
1919
import com.azuredoom.classescore.compat.DynamicTooltipsLibCompat;
20+
import com.azuredoom.classescore.compat.placeholderapi.PlaceholderAPICompat;
2021
import com.azuredoom.classescore.config.ClassesCoreConfig;
2122
import com.azuredoom.classescore.data.ClassDefinition;
2223
import com.azuredoom.classescore.data.ClassRegistry;
@@ -26,8 +27,10 @@
2627
import com.azuredoom.classescore.gameplay.services.items.HandGateTickingSystem;
2728
import com.azuredoom.classescore.gameplay.services.items.ItemBlockPacketManager;
2829
import com.azuredoom.classescore.gameplay.services.items.PlayerRestrictionCache;
30+
import com.azuredoom.classescore.gameplay.services.stats.StatsTickingSystem;
2931
import com.azuredoom.classescore.service.ClassServiceImpl;
3032

33+
@SuppressWarnings("removal")
3134
public class ClassesCore extends JavaPlugin {
3235

3336
public static final HytaleLogger LOGGER = HytaleLogger.forEnclosingClass();
@@ -64,7 +67,7 @@ protected void setup() {
6467
classService = bootstrap.service();
6568
classRegistry = bootstrap.registry();
6669

67-
this.getCommandRegistry().registerCommand(new ClassCommand());
70+
this.getCommandRegistry().registerCommand(new JoinClassCommand());
6871
this.getCommandRegistry().registerCommand(new LeaveClassCommand());
6972

7073
if (config.get().isEnableClassItemRestrictions()) {
@@ -113,7 +116,9 @@ protected void setup() {
113116

114117
@Override
115118
protected void start() {
116-
LOGGER.at(Level.INFO).log("Starting classescore!");
119+
if (PluginManager.get().getPlugin(new PluginIdentifier("HelpChat", "PlaceholderAPI")) != null) {
120+
PlaceholderAPICompat.register();
121+
}
117122
}
118123

119124
@Override
@@ -135,6 +140,7 @@ public void registerAllSystems() {
135140
new HandGateTickingSystem(ITEM_BLOCK_PACKET_MANAGER.getHandCheckState(), PLAYER_RESTRICTION_CACHE)
136141
);
137142
getEntityStoreRegistry().registerSystem(new ClassDamageSystem());
143+
getEntityStoreRegistry().registerSystem(new StatsTickingSystem());
138144
}
139145

140146
public static Config<ClassesCoreConfig> getConfig() {

src/main/java/com/azuredoom/classescore/api/ClassesCoreAPI.java

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,50 +11,138 @@
1111
import com.azuredoom.classescore.data.ClassRegistry;
1212
import com.azuredoom.classescore.service.ClassServiceImpl;
1313

14+
/**
15+
* A utility class providing core API operations for managing and interacting with classes, class definitions, and
16+
* player class states in the system. This class acts as an intermediary between the underlying services and the
17+
* external modules.
18+
*/
1419
public final class ClassesCoreAPI {
1520

1621
private ClassesCoreAPI() {}
1722

23+
/**
24+
* Retrieves an instance of the {@link ClassServiceImpl} if present within the system.
25+
*
26+
* @return an {@code Optional} containing the {@code ClassServiceImpl} instance if available, or an empty
27+
* {@code Optional} if the service is not present.
28+
*/
1829
public static Optional<ClassServiceImpl> getClassServiceIfPresent() {
1930
return Optional.ofNullable(ClassesCore.getClassService());
2031
}
2132

33+
/**
34+
* Retrieves an instance of {@link ClassRegistry} if it is available in the system.
35+
*
36+
* @return an {@code Optional} containing the {@code ClassRegistry} instance if it is present, or an empty
37+
* {@code Optional} if the registry is not available.
38+
*/
2239
public static Optional<ClassRegistry> getClassRegistryIfPresent() {
2340
return Optional.ofNullable(ClassesCore.getClassRegistry());
2441
}
2542

43+
/**
44+
* Retrieves all available class definitions registered in the system. If no class registry is present, returns an
45+
* empty collection.
46+
*
47+
* @return a collection of {@code ClassDefinition} objects representing all registered classes, or an empty
48+
* collection if no registry is available.
49+
*/
2650
public static Collection<ClassDefinition> getClasses() {
2751
return getClassRegistryIfPresent()
2852
.map(ClassRegistry::all)
2953
.orElse(List.of());
3054
}
3155

56+
/**
57+
* Retrieves the {@code ClassDefinition} associated with the specified class identifier.
58+
* <p>
59+
* The method attempts to fetch the {@link ClassDefinition} from the class registry if it is present. If no registry
60+
* is available, or if the specified class identifier does not exist in the registry, the method returns an empty
61+
* {@code Optional}.
62+
*
63+
* @param classId the unique identifier of the class whose definition is to be retrieved
64+
* @return an {@code Optional} containing the {@code ClassDefinition} for the given identifier, or an empty
65+
* {@code Optional} if the class definition is not found or the registry is unavailable
66+
*/
3267
public static Optional<ClassDefinition> getClassDefinition(String classId) {
3368
return getClassRegistryIfPresent().flatMap(registry -> registry.get(classId));
3469
}
3570

71+
/**
72+
* This method determines if the specified player has a class assigned by checking the player's selected class ID
73+
* and verifying if it corresponds to a valid class definition in the system.
74+
*
75+
* @param playerId the unique identifier of the player whose class status is to be checked
76+
* @return {@code true} if the player has a selected class, and it exists in the class registry, {@code false}
77+
* otherwise
78+
*/
3679
public static boolean playerHasClass(UUID playerId) {
3780
return hasClass(getSelectedClassId(playerId).orElse(null));
3881
}
3982

83+
/**
84+
* Checks if a class with the specified identifier exists in the class registry. The method verifies the
85+
* availability of a {@code ClassRegistry}, and if present, attempts to retrieve the class with the given
86+
* identifier.
87+
*
88+
* @param classId the unique identifier of the class to check
89+
* @return {@code true} if the class exists in the registry, {@code false} otherwise
90+
*/
4091
public static boolean hasClass(String classId) {
4192
return getClassRegistryIfPresent().flatMap(registry -> registry.get(classId)).isPresent();
4293
}
4394

95+
/**
96+
* Retrieves the current class state of a specific player. The method attempts to get an instance of the
97+
* {@code ClassServiceImpl} and, if available, fetches the {@code PlayerClassState} associated with the given
98+
* player.
99+
*
100+
* @param playerId the unique identifier of the player whose class state is to be retrieved
101+
* @return an {@code Optional} containing the {@code PlayerClassState} if the player has a class state assigned, or
102+
* an empty {@code Optional} if no such state exists or the service is unavailable
103+
*/
44104
public static Optional<PlayerClassState> getPlayerState(UUID playerId) {
45105
return getClassServiceIfPresent().flatMap(service -> service.getPlayerState(playerId));
46106
}
47107

108+
/**
109+
* Retrieves the selected class ID associated with a specific player. This method fetches the player's current class
110+
* state and extracts the class ID if a class state is present.
111+
*
112+
* @param playerId the unique identifier of the player whose selected class ID is to be retrieved
113+
* @return an {@code Optional} containing the selected class ID if the player has a class state assigned, or an
114+
* empty {@code Optional} if no class state exists or the service is unavailable
115+
*/
48116
public static Optional<String> getSelectedClassId(UUID playerId) {
49117
return getPlayerState(playerId).map(PlayerClassState::classId);
50118
}
51119

120+
/**
121+
* Retrieves the {@code ClassDefinition} associated with the given player's currently selected class. The method
122+
* fetches the player's class state, extracts the class ID if available, and then attempts to retrieve the
123+
* corresponding {@code ClassDefinition} from the class registry.
124+
*
125+
* @param playerId the unique identifier of the player whose selected class is to be retrieved
126+
* @return an {@code Optional} containing the {@code ClassDefinition} for the player's selected class, or an empty
127+
* {@code Optional} if the player has no selected class or the class definition is not found in the registry
128+
*/
52129
public static Optional<ClassDefinition> getSelectedClass(UUID playerId) {
53130
return getPlayerState(playerId)
54131
.map(PlayerClassState::classId)
55132
.flatMap(ClassesCoreAPI::getClassDefinition);
56133
}
57134

135+
/**
136+
* Selects a class for the given player based on the specified class identifier.
137+
* <p>
138+
* This method verifies the validity of the class identifier and checks if the class exists in the system. It also
139+
* ensures that the {@code ClassServiceImpl} is available before proceeding with the selection. If all conditions
140+
* are satisfied, the method delegates the class selection to the service.
141+
*
142+
* @param playerId the unique identifier of the player for whom the class is to be selected
143+
* @param classId the unique identifier of the class to be selected
144+
* @return {@code true} if the class was successfully selected, {@code false} otherwise
145+
*/
58146
public static boolean selectClass(UUID playerId, String classId) {
59147
if (classId == null || classId.isBlank()) {
60148
return false;
@@ -72,6 +160,16 @@ public static boolean selectClass(UUID playerId, String classId) {
72160
return true;
73161
}
74162

163+
/**
164+
* Clears the class associated with a specific player and class ID.
165+
* <p>
166+
* This method interacts with the {@code ClassServiceImpl} to remove the association of a player with a class,
167+
* effectively clearing the player's current class state. If the service is unavailable, the operation will fail.
168+
*
169+
* @param playerId the unique identifier of the player whose class is to be cleared
170+
* @param classId the unique identifier of the class to be cleared
171+
* @return {@code true} if the class was successfully cleared, {@code false} if the service is unavailable
172+
*/
75173
public static boolean clearClass(UUID playerId, String classId) {
76174
var service = getClassServiceIfPresent().orElse(null);
77175
if (service == null) {
@@ -82,12 +180,33 @@ public static boolean clearClass(UUID playerId, String classId) {
82180
return true;
83181
}
84182

183+
/**
184+
* Determines whether a player is allowed to use a specific weapon based on their currently selected class. The
185+
* method retrieves the player's selected class definition and checks if the weapon is allowed according to the
186+
* equipment rules of that class. If the player has no selected class or the class definition is unavailable, the
187+
* method defaults to allowing the weapon.
188+
*
189+
* @param playerId the unique identifier of the player whose weapon usage is to be verified
190+
* @param weaponId the unique identifier of the weapon to check for usage allowance
191+
* @return {@code true} if the weapon is allowed for the player's selected class, or if no class is selected;
192+
* {@code false} otherwise
193+
*/
85194
public static boolean canUseWeapon(UUID playerId, String weaponId) {
86195
return getSelectedClass(playerId)
87196
.map(classDef -> classDef.equipmentRules().isWeaponAllowed(weaponId))
88197
.orElse(true);
89198
}
90199

200+
/**
201+
* Determines whether a player is allowed to use a specific armor based on their currently selected class. The
202+
* method retrieves the player's selected class definition and verifies if the armor is permitted according to the
203+
* equipment rules of that class. If the player has no selected class, the method defaults to allowing the armor.
204+
*
205+
* @param playerId the unique identifier of the player whose armor usage is being verified
206+
* @param armorId the unique identifier of the armor to check for usage allowance
207+
* @return {@code true} if the armor is allowed for the player's selected class, or if no class is selected;
208+
* {@code false} otherwise
209+
*/
91210
public static boolean canUseArmor(UUID playerId, String armorId) {
92211
return getSelectedClass(playerId)
93212
.map(classDef -> classDef.equipmentRules().isArmorAllowed(armorId))

src/main/java/com/azuredoom/classescore/api/model/PlayerClassState.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22

33
import java.util.UUID;
44

5+
/**
6+
* Represents the state of a player's selected class within a game.
7+
*
8+
* @param playerId The unique identifier of the player.
9+
* @param classId The unique identifier of the selected class.
10+
* @param createdAt The timestamp when the class selection was made.
11+
* @param updatedAt The timestamp when the class selection was last updated.
12+
*/
513
public record PlayerClassState(
614
UUID playerId,
715
String classId,

src/main/java/com/azuredoom/classescore/bootstrap/ClassesBootstrap.java

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,10 @@
2424

2525
import com.azuredoom.classescore.ClassesCore;
2626
import com.azuredoom.classescore.config.ClassesCoreConfig;
27-
import com.azuredoom.classescore.data.ClassDefinition;
28-
import com.azuredoom.classescore.data.ClassRegistry;
29-
import com.azuredoom.classescore.data.EquipmentRules;
30-
import com.azuredoom.classescore.data.PassiveDefinition;
31-
import com.azuredoom.classescore.data.PassiveType;
27+
import com.azuredoom.classescore.data.*;
3228
import com.azuredoom.classescore.db.JdbcClassesRepository;
3329
import com.azuredoom.classescore.service.ClassServiceImpl;
30+
import com.azuredoom.classescore.util.StatType;
3431

3532
public final class ClassesBootstrap {
3633

@@ -225,6 +222,29 @@ private ClassDefinition loadClass(InputStream stream, String sourceName) {
225222
var displayName = root.get("displayName").getAsString();
226223
var description = root.get("description").getAsString();
227224

225+
var stats = new ArrayList<StatDefinition>();
226+
var statsJson = root.getAsJsonArray("stats");
227+
228+
if (statsJson != null) {
229+
for (var element : statsJson) {
230+
var statObj = element.getAsJsonObject();
231+
232+
if (!statObj.has("id")) {
233+
throw new IllegalStateException("Stat missing 'id' in " + sourceName);
234+
}
235+
var statId = statObj.get("id").getAsString();
236+
237+
StatType.fromJson(statId);
238+
239+
var base = statObj.has("base") ? statObj.get("base").getAsInt() : 0;
240+
var perLevel = statObj.has("perLevel") ? statObj.get("perLevel").getAsInt() : 0;
241+
242+
if (base < 0 || perLevel < 0) {
243+
throw new IllegalStateException("Negative stat values not allowed: " + statId);
244+
}
245+
stats.add(new StatDefinition(statId, base, perLevel));
246+
}
247+
}
228248
var passives = new ArrayList<PassiveDefinition>();
229249
var passivesJson = root.getAsJsonArray("passives");
230250
if (passivesJson != null) {
@@ -262,6 +282,7 @@ private ClassDefinition loadClass(InputStream stream, String sourceName) {
262282
id,
263283
displayName,
264284
description,
285+
stats,
265286
passives,
266287
new EquipmentRules(allowedWeapons, allowedArmor)
267288
);
@@ -270,21 +291,19 @@ private ClassDefinition loadClass(InputStream stream, String sourceName) {
270291
}
271292
}
272293

273-
private ClassDefinition loadClass(String resourcePath) {
274-
try (var stream = plugin.getClass().getResourceAsStream(resourcePath)) {
275-
if (stream == null) {
276-
throw new IllegalStateException("Missing class resource: " + resourcePath);
277-
}
278-
return loadClass(stream, resourcePath);
279-
} catch (Exception e) {
280-
throw new RuntimeException("Failed to load class resource " + resourcePath, e);
281-
}
282-
}
283-
284294
private Path resolveAssetPackDirectory() {
285295
return Paths.get("mods").toAbsolutePath().normalize();
286296
}
287297

298+
/**
299+
* A record that encapsulates the result of the bootstrap process for managing class-related operations and
300+
* resources. It acts as a container for key parts involved in the system's class management and lifecycle control.
301+
*
302+
* @param repository The repository responsible for managing class data in the database.
303+
* @param registry The registry for storing and managing loaded class definitions.
304+
* @param service The service for handling higher-level class management operations.
305+
* @param closeable A resource that can be closed to release associated system resources.
306+
*/
288307
public record BootstrapResult(
289308
JdbcClassesRepository repository,
290309
ClassRegistry registry,

src/main/java/com/azuredoom/classescore/command/ClassCommand.java renamed to src/main/java/com/azuredoom/classescore/command/JoinClassCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@
1717
import com.azuredoom.classescore.api.ClassesCoreAPI;
1818
import com.azuredoom.classescore.lang.BaseLangMessages;
1919

20-
public final class ClassCommand extends AbstractPlayerCommand {
20+
public final class JoinClassCommand extends AbstractPlayerCommand {
2121

2222
@Nonnull
2323
private final RequiredArg<PlayerRef> playerArg;
2424

2525
private final RequiredArg<String> classIdArg;
2626

27-
public ClassCommand() {
27+
public JoinClassCommand() {
2828
super("joinclass", "Join a class");
2929
this.requirePermission("classescore.joinclass");
3030
this.playerArg = this.withRequiredArg(

0 commit comments

Comments
 (0)