108 Commits

Author SHA1 Message Date
0ae094abe4 With EndsWithHandler
Some checks failed
SteamWarCI Build failed
2025-12-21 09:45:37 +01:00
3d6c50938c Improve error messages
Some checks failed
SteamWarCI Build failed
2025-11-24 10:00:45 +01:00
e9d814bc95 Fix AssertionUtils.SimpleAssertion.assertNoInitialize
Some checks failed
SteamWarCI Build failed
2025-11-23 21:20:08 +01:00
ef61cf455d Fix MapperHandler, SupplierHandler, ValidatorHandler
Some checks failed
SteamWarCI Build failed
Improve HandlerForVariableElement.getAnnotations()
Improve HandlerForTypeMirror.isEnum
Add HandlerForTypeMirror.getTypeName
2025-11-23 21:14:09 +01:00
b6bad4e78e Fix HandlerForVariableElement.getAnnotations
Some checks failed
SteamWarCI Build failed
2025-11-23 20:54:08 +01:00
18659385d2 Add Annotation Processor for compile time checks
Some checks failed
SteamWarCI Build failed
2025-11-23 20:27:44 +01:00
f6fc65a370 Fix SupplierHandler checking for AbstractTypeMapper instead of AbstractTypeSupplier
Some checks failed
SteamWarCI Build failed
2025-11-23 16:36:48 +01:00
fbc14d0503 Fix AbstractCommand with empty args for execute
Some checks failed
SteamWarCI Build failed
2025-11-23 16:18:14 +01:00
9fe38bcf61 Fix java version for Velocity CommandFramework
Some checks failed
SteamWarCI Build failed
2025-11-23 15:11:06 +01:00
fd22c1cccc Fix registering of commands
Some checks failed
SteamWarCI Build failed
2025-11-23 08:32:44 +01:00
b627b3b4a6 Fix build errors of CommandFramework
Some checks failed
SteamWarCI Build failed
2025-11-23 08:27:11 +01:00
f9faa9b296 Initial copy from other repository (nothing is fixed here)
Some checks failed
SteamWarCI Build failed
2025-11-22 23:08:48 +01:00
e343d044ff Refactor Discord authentication endpoint for improved error handling and structure
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-14 23:56:04 +01:00
f923a007a7 Revert "Add EventCache for efficient retrieval of event groups and teams"
All checks were successful
SteamWarCI Build successful
This reverts commit 8b4f864f99.

Revert "Refactor EventFights and Fight classes to improve player initialization and retrieval"

This reverts commit 8d705e7a84.

Revert "Refactor EventFights and Fight classes to improve player initialization and retrieval"

This reverts commit 78352a3e67.
2025-11-14 23:25:05 +01:00
78352a3e67 Refactor EventFights and Fight classes to improve player initialization and retrieval
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-14 23:18:38 +01:00
8d705e7a84 Refactor EventFights and Fight classes to improve player initialization and retrieval
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-14 23:14:13 +01:00
8b4f864f99 Add EventCache for efficient retrieval of event groups and teams
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-14 22:47:27 +01:00
f9cb712b07 Merge pull request 'Simplify Tokens and add Discord OAuth' (#220) from authv3 into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #220
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-11-14 22:43:04 +01:00
b3b13d2950 Move Chatter.disconnect call to ensure proper execution after IP ban check.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-13 23:01:37 +01:00
08ad5edf76 Simplify Tokens and add Discord OAuth
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-13 14:31:05 +01:00
afcf3a1906 Fix Schematic Move
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-12 22:52:51 +01:00
33efd26d48 Fix build.gradle.kts
All checks were successful
SteamWarCI Build successful
2025-11-12 07:43:36 +01:00
2a96b3c26a Hotfix AutoCheckerItems for 1.19
Some checks failed
SteamWarCI Build failed
2025-11-11 22:06:44 +01:00
3de4b3871d Hotfix ModifyPart
All checks were successful
SteamWarCI Build successful
2025-11-11 21:42:38 +01:00
67223be80e Trigger rebuild
All checks were successful
SteamWarCI Build successful
2025-11-11 21:28:13 +01:00
81715736ae Refactor TeamTable to introduce default values for color and deleted, and make address column nullable.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 18:44:46 +01:00
36691c6fea Refactor TeamTable to introduce default values for color and deleted, and make address column nullable.
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 18:44:25 +01:00
58618a3991 Fix FightTeam.removeLeader
All checks were successful
SteamWarCI Build successful
Fix FightTeam.setLeader
2025-11-11 17:36:19 +01:00
e6848b27a0 Refactor FightTable to use WinningTeam enum for win column and adjust related logic.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 17:25:38 +01:00
93d0011b46 Update openMaterialSelector to exclude non-item materials in UtilGui.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 17:20:33 +01:00
f56fedefe4 Fix Obsidian and Bedrock
All checks were successful
SteamWarCI Build successful
2025-11-11 17:07:56 +01:00
167bb4e266 Fix YMLWrapper
All checks were successful
SteamWarCI Build successful
2025-11-11 17:05:46 +01:00
f6a9ce184b Closes: #214
All checks were successful
SteamWarCI Build successful
Closes: #215
2025-11-11 16:40:26 +01:00
d5708c110c Refactor NodeDataTable to use default current timestamp for createdAt and ensure schemData reads blob as bytes.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 00:18:16 +01:00
f23c1215b7 Refactor NodeDataTable to use insert instead of insertIgnore and add blobParam import.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-11 00:15:19 +01:00
cfcaf1569c Add GameModeConfig.Schematic.MaxBlastResistance
All checks were successful
SteamWarCI Build successful
2025-11-10 21:39:35 +01:00
dc56b67ff6 Sort fights by start time in descending order and refactor saveFromStream method to use useDb block.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 14:18:13 +01:00
13c4a3ff8b Sort fights by start time in descending order and refactor saveFromStream method to use useDb block.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 12:27:02 +01:00
7e5a13989b Sort fights by start time in descending order and refactor saveFromStream method to use useDb block.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 12:24:51 +01:00
990a03ca6c Add Exposed library dependencies to WebsiteBackend build script.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:57:12 +01:00
4a608fe5b5 Fix SchematicType.fromDB
All checks were successful
SteamWarCI Build successful
2025-11-10 11:55:17 +01:00
5ca15aa117 Refactor PersonalKitTable to use explicit ID column initialization and update create method to utilize insert operation.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:50:39 +01:00
9b459bd12c Refactor PersonalKitTable to use explicit ID column initialization and update create method to utilize insert operation.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:40:34 +01:00
b20d37e252 Refactor PersonalKitTable to use explicit ID column initialization and update create method to utilize insert operation.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:40:20 +01:00
a8c98594a9 Fix GameModeConfig.Schematic.SubTypes
All checks were successful
SteamWarCI Build successful
2025-11-10 11:32:03 +01:00
1c076b5bbf Fix incorrect field references in BauweltMember methods.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:19:56 +01:00
133ddb39cc Add ID column initialization for BauweltMember
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 11:09:57 +01:00
ebb375d8d6 Improve messages
All checks were successful
SteamWarCI Build successful
2025-11-10 11:04:29 +01:00
8ada9a6335 Fix UserElo.getEloFromDb
All checks were successful
SteamWarCI Build successful
2025-11-10 11:01:31 +01:00
0760a5a08a Update build scripts: migrate to Spigot API, adjust JVM toolchains and Java version.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:42:24 +01:00
852ff95757 Update build scripts: migrate to Spigot API, adjust JVM toolchains and Java version.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:40:36 +01:00
5c7d388876 Remove unused SLF4J exclusion from shadowJar task.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:34:44 +01:00
4f92f8132d Remove unused SLF4J exclusion from shadowJar task.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:27:58 +01:00
56fb63f781 Add MySQL dependency to KotlinCore build script.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:17:37 +01:00
273efff87d Remove unused api-version field from plugin.yml.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:16:14 +01:00
0cac6f36c1 Remove unused api-version field from plugin.yml.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:09:44 +01:00
8680b9e6cf Change api dependencies to compileOnlyApi in build.gradle.kts and rename KitName column to Name in PersonalKitTable.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 09:02:23 +01:00
6c94efaf90 Improve TeamCommand.info
All checks were successful
SteamWarCI Build successful
2025-11-10 09:00:18 +01:00
f6261ad989 Improve output for DevCommand reloadmodes 2025-11-10 09:00:18 +01:00
614e989892 Rename IgnoreTable to IgnoredPlayers in IgnoreSystemTable for improved clarity.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-10 08:47:32 +01:00
84e1f605bd Merge pull request 'Exposed!' (#179) from exposed into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #179
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2025-11-10 08:42:59 +01:00
0ea5a62dbe Merge branch 'main' into exposed
All checks were successful
SteamWarCI Build successful
2025-11-10 08:40:42 +01:00
0eb6047139 Merge remote-tracking branch 'origin/exposed' into exposed
All checks were successful
SteamWarCI Build successful
2025-11-09 17:48:12 +01:00
fcebecf745 Add placement column to TeamTeilnahme table and corresponding property.
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-09 17:48:02 +01:00
dd14e9f518 Cleanup Session
All checks were successful
SteamWarCI Build successful
2025-11-09 17:30:21 +01:00
6c5239c8fc Optimize imports across SQL module: replace explicit class imports with wildcard imports, remove unused imports for cleaner structure.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-09 17:28:40 +01:00
fc71f47add Remove needsAdmin property from PunishmentType enum and refactor related declarations for cleaner structure.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-09 17:25:19 +01:00
5d36393643 Refactor EventRelation, EventGroup, and EventFight classes: ensure database operations are enclosed in useDb, add default values for group points, and override delete methods. Update Gradle build script to include lombok dependencies.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-08 22:44:22 +01:00
ebc6f50261 Refactor Gradle build scripts: update source set exclusions, add java-library plugin, and remove redundant configurations in SQL module.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-08 13:52:27 +01:00
69cf219e39 Fix FlatteningWrapper21
All checks were successful
SteamWarCI Build successful
2025-11-07 22:47:05 +01:00
fb4e53165f Hotfix FixedFlagStorage.clear and FixedGlobalFlagStorage.clear
All checks were successful
SteamWarCI Build successful
2025-11-07 22:42:48 +01:00
415d783365 Hotfix SEND_COMMAND_FEEDBACK in 1.20+
All checks were successful
SteamWarCI Build successful
2025-11-07 22:17:30 +01:00
ee99708340 Hotfix (FA)WE Selection 1.20+
All checks were successful
SteamWarCI Build successful
2025-11-07 22:13:31 +01:00
c9d74fb656 Remove redundant SQL logger in useDb and extra newlines in SQLConfig.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 18:59:01 +01:00
e50e52950b Refactor Token and SteamwarUser classes: enhance owner property with memoized transformation, increase hash generation key size, and ensure database usage in useDb block.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 18:57:34 +01:00
cac0ae3e13 Hotfix MaterialLazyInit for 1.21
All checks were successful
SteamWarCI Build successful
2025-11-07 15:41:48 +01:00
f9b3dd34cf Trigger rebuild
All checks were successful
SteamWarCI Build successful
2025-11-07 15:25:20 +01:00
e5a61226ca Add newline at end of build.gradle.kts file for consistency.
All checks were successful
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 15:06:37 +01:00
0c35ace5e2 Remove redundant Java installation paths in Gradle configuration.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 14:54:30 +01:00
23bcf14ca5 Update Gradle configuration to specify multiple Java installation paths for compatibility.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 14:53:07 +01:00
63a5fcff97 Add Kotlin plugin and configure build scripts for Kotlin compatibility, integrate exposed library dependencies, and enhance JVM settings.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 14:40:10 +01:00
39b3cdb897 Introduce GDPRQuery command for GDPR data generation, refactor SQL statements, and improve null safety across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-07 12:42:15 +01:00
3ccfe92afb Remove DC prefix for discord send messages to cleanup the chat
All checks were successful
SteamWarCI Build successful
2025-11-07 08:46:26 +01:00
c17b76851d Improve chat from discord
All checks were successful
SteamWarCI Build successful
2025-11-07 08:44:07 +01:00
f0e18bfc72 Improve CouncilChannel and StaticMessageChannel
All checks were successful
SteamWarCI Build successful
2025-11-07 08:39:42 +01:00
160f982955 Improve ChatListener for STC Chat
All checks were successful
SteamWarCI Build successful
Add debug output for DiscordChannel
Fix CouncilChannel
2025-11-07 08:34:19 +01:00
6ac0143459 Remove outdated SQL-related Java classes (GDPRQuery, Field, SelectStatement, SqlTypeMapper, Statement) and update references across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-06 11:30:01 +01:00
98ca9e852c Merge pull request 'Add version dependant impl of tps warp to fight system' (#187) from FightSystem/Add-version-dependent-impl-of-tps-warp into main
All checks were successful
SteamWarCI Build successful
Reviewed-on: #187
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2025-11-06 09:50:24 +01:00
D4rkr34lm
17910ec8a4 Add version dependant impl
All checks were successful
SteamWarCI Build successful
2025-11-06 02:07:20 +01:00
56bc75763b Migrate Token class to Kotlin, remove outdated Java implementation, and refactor references across modules. Update timestamp fields to use CurrentTimestamp where applicable.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-05 21:44:52 +01:00
8272c73b48 Migrate SQL-related classes (Referee, SchemElo, Script, Session, SWException, TeamTeilnahme) to Kotlin and remove outdated Java implementations. Update references across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-05 17:47:30 +01:00
9acfb32ae0 Refactor SQL classes: update GameModeConfig functions, improve null safety in SchematicNode and SchematicType, and adjust NodeMemberTable structure.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-05 17:04:01 +01:00
b2a4b05545 Merge branch 'main' into exposed
# Conflicts:
#	CommonCore/SQL/src/de/steamwar/sql/GameModeConfig.java
#	CommonCore/SQL/src/de/steamwar/sql/Punishment.java
2025-11-05 16:18:30 +01:00
89e2df0eb2 Migrate Punishment and PollAnswer classes to Kotlin and remove outdated Java implementations. Update references across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-04 21:17:53 +01:00
73da9179bf Migrate SQL-related classes (IgnoreSystem, Mod, NodeDownload, NodeMember) to Kotlin and remove old Java implementations. Update references across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-02 19:28:14 +01:00
0fbbcdacea Migrate Fight, FightPlayer, and SchematicType classes to Kotlin and remove old Java implementations. Update references across modules.
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-11-01 13:52:26 +01:00
4e6933f2fd Remove Event-related SQL classes and update relevant references across modules
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-30 23:14:25 +01:00
eea1073892 Migrate Event class to Kotlin and update references across modules
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-29 23:17:17 +01:00
702aa1cfa6 Refactor CheckedSchematic and migrate to Kotlin
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-29 17:42:29 +01:00
6ea73f4890 Refactor NodeData
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 22:25:31 +01:00
14e82f36a5 Rename .java to .kt
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 22:25:31 +01:00
a8eaf3daa7 Fixes
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 21:31:57 +01:00
b51ea484e4 Refactor UserConfig
Some checks failed
SteamWarCI Build failed
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 20:38:02 +01:00
8bef19ed8b Rename .java to .kt
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 20:38:02 +01:00
1aff7b30a6 Refactor SchematicNode
Some checks failed
SteamWarCI Build failed
2025-10-28 19:03:30 +01:00
c8ac984ad3 Rename .java to .kt 2025-10-28 19:03:30 +01:00
a462231bab Starting...
Some checks failed
SteamWarCI Build failed
2025-10-27 18:34:31 +01:00
e6bbb76a0b Rename .java to .kt 2025-10-27 18:34:30 +01:00
448 changed files with 21721 additions and 5231 deletions

1
.gitignore vendored
View File

@@ -13,6 +13,7 @@ steamwar.properties
# VSCode
bin/
.vscode
.settings
# Other
lib

View File

@@ -46,6 +46,7 @@ import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -128,6 +129,8 @@ public class BauSystem extends JavaPlugin implements Listener {
TraceRecorder.instance.init();
new WorldEditRendererCUIEditor();
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
}
@EventHandler

View File

@@ -36,7 +36,7 @@ public class BauServer {
private Integer owner;
public UUID getOwner() {
return SteamwarUser.get(getOwnerID()).getUUID();
return SteamwarUser.byId(getOwnerID()).getUUID();
}
public int getOwnerID() {

View File

@@ -47,7 +47,7 @@ public class InfoCommand extends SWCommand {
@Register(description = "BAU_INFO_COMMAND_HELP")
public void genericCommand(Player p) {
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.get(bauServer.getOwnerID()).getUserName());
BauSystem.MESSAGE.send("BAU_INFO_COMMAND_OWNER", p, SteamwarUser.byId(bauServer.getOwnerID()).getUserName());
Region region = Region.getRegion(p.getLocation());
for (Flag flag : Flag.getFlags()) {
if (!region.getFlags().has(flag).isApplicable()) continue;
@@ -97,7 +97,7 @@ public class InfoCommand extends SWCommand {
st.append("§8, ");
}
st.append("§7");
st.append(SteamwarUser.get(bauweltMembers.get(i).getMemberID()).getUserName());
st.append(SteamwarUser.byId(bauweltMembers.get(i).getMemberID()).getUserName());
}
return st.toString();
}

View File

@@ -31,7 +31,6 @@ import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeMapper;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.LinkedInstance;
import de.steamwar.sql.BauweltMember;
import de.steamwar.sql.Punishment;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
@@ -198,7 +197,7 @@ public class TestblockCommand extends SWCommand {
@Override
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
List<String> stringList = new ArrayList<>(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.get(0), s));
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s));
return stringList;
}
@@ -206,7 +205,7 @@ public class TestblockCommand extends SWCommand {
public SchematicNode map(CommandSender commandSender, PreviousArguments previousArguments, String s) {
SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
if (node == null) {
node = SchematicNode.getNodeFromPath(SteamwarUser.get(0), s);
node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
}
return node;
}

View File

@@ -38,7 +38,7 @@ public class ScriptHelper {
BookMeta meta = (BookMeta) itemStack.getItemMeta();
if(!writeable) {
meta.setTitle(script.getName());
meta.setAuthor(SteamwarUser.get(script.getUserId()).getUserName());
meta.setAuthor(SteamwarUser.byId(script.getUserId()).getUserName());
}
meta.setPages(getScriptPages(script));
itemStack.setItemMeta(meta);

View File

@@ -89,7 +89,7 @@ public class StorageLib implements LuaLib, Enable, Disable {
jsonObject.keySet().forEach(key -> {
map.put(key, fromJson(jsonObject.get(key)));
});
SteamwarUser steamwarUser = SteamwarUser.get(Integer.parseInt(playerStorage.getName().substring(0, playerStorage.getName().length() - ".json".length())));
SteamwarUser steamwarUser = SteamwarUser.byId(Integer.parseInt(playerStorage.getName().substring(0, playerStorage.getName().length() - ".json".length())));
PLAYER_STORAGE.put(steamwarUser.getUUID(), map);
} catch (Exception e) {}
}

View File

@@ -54,7 +54,7 @@ public class YAPIONFormatSimulatorLoader implements SimulatorLoader {
}
String name = file.getName().substring(0, file.getName().length() - 7);
SteamwarUser steamwarUser = SteamwarUser.get(Integer.parseInt(name));
SteamwarUser steamwarUser = SteamwarUser.byId(Integer.parseInt(name));
List<Simulator> simulators = new ArrayList<>();
for (String s : yapionObject.getKeys()) {

View File

@@ -87,6 +87,7 @@ public class MaterialLazyInit {
Block block = Bukkit.getWorlds().get(0).getBlockAt(0, 0, 0);
block.setType(material);
unmoveable = block.getPistonMoveReaction() == PistonMoveReaction.BLOCK || block.getPistonMoveReaction() == PistonMoveReaction.IGNORE || block.getState() instanceof TileState;
block.setType(Material.AIR);
}
if (material.isItem() && material != Material.AIR) {

View File

@@ -41,7 +41,7 @@ public class AntiBauAddMemberFix implements Listener {
}
if (BauweltMember.getBauMember(BauServer.getInstance().getOwner(), event.getPlayer().getUniqueId()) == null) {
event.getPlayer().kickPlayer("");
throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.get(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
throw new SecurityException("The player " + event.getPlayer().getName() + " joined on the server of " + SteamwarUser.byId(BauServer.getInstance().getOwnerID()).getUserName() + " without being added!");
}
}

View File

@@ -84,7 +84,12 @@ public class FixedFlagStorage implements FlagStorage {
@Override
public void clear() {
flagMap.clear();
for (Flag flag : Flag.getFlags()) {
if (flag == Flag.TESTBLOCK) continue;
if (flag == Flag.COLOR) continue;
if (flag == Flag.CHANGED) continue;
flagMap.remove(flag);
}
}
@Override

View File

@@ -91,7 +91,12 @@ public class FixedGlobalFlagStorage implements FlagStorage {
@Override
public void clear() {
flagMap.clear();
for (Flag flag : Flag.getFlags()) {
if (flag == Flag.TESTBLOCK) continue;
if (flag == Flag.COLOR) continue;
if (flag == Flag.CHANGED) continue;
flagMap.remove(flag);
}
}
@Override

View File

@@ -50,5 +50,6 @@ tasks.register<DevServer>("DevBau21") {
description = "Run a 1.21 Dev Bau"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":BauSystem:shadowJar")
dependsOn(":SchematicSystem:shadowJar")
template = "Bau21"
}

View File

@@ -0,0 +1,27 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
testImplementation(libs.junit)
testImplementation(libs.hamcrest)
}

View File

@@ -0,0 +1,32 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
dependencies {
implementation(project(":CommandFramework:CommandFrameworkBase", "default"))
annotationProcessor(project(":CommandFramework:CommandFrameworkBase", "default"))
}

View File

@@ -0,0 +1,5 @@
de.steamwar.command.annotationprocessor.impl.CachedAnnotationProcessor
de.steamwar.command.annotationprocessor.impl.MapperAnnotationProcessor
de.steamwar.command.annotationprocessor.impl.RegisterAnnotationProcessor
de.steamwar.command.annotationprocessor.impl.SupplierAnnotationProcessor
de.steamwar.command.annotationprocessor.impl.ValidatorAnnotationProcessor

View File

@@ -17,29 +17,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql;
package de.steamwar.command;
import de.steamwar.sql.internal.Field;
import de.steamwar.sql.internal.Statement;
import de.steamwar.sql.internal.Table;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.sql.Timestamp;
import javax.lang.model.element.AnnotationMirror;
import java.lang.annotation.Annotation;
@AllArgsConstructor
public class Session {
public class HandlerForAnnotationMirror<A extends Annotation> implements Handler.AnnotationWrapper<A> {
private static final Table<Session> table = new Table<>(Session.class);
private static final Statement insert = table.insert(Table.PRIMARY);
private A annotation;
public static void insertSession(int userID, Timestamp startTime){
insert.update(userID, startTime);
@Getter
private AnnotationMirror annotationMirror;
public HandlerForAnnotationMirror(A annotation, AnnotationMirror annotationMirror) {
this.annotation = annotation;
this.annotationMirror = annotationMirror;
}
@Field(keys = {Table.PRIMARY})
private int userId;
@Field(keys = {Table.PRIMARY})
private Timestamp startTime;
@Field(def = "CURRENT_TIMESTAMP")
private Timestamp endTime;
@Override
public A getAnnotation() {
return annotation;
}
}

View File

@@ -0,0 +1,68 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.Getter;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.util.List;
public class HandlerForExecutableElement implements Handler.MethodWrapper {
@Getter
private final ExecutableElement method;
private final Types types;
private final Elements elements;
public HandlerForExecutableElement(ExecutableElement method, Types types, Elements elements) {
this.method = method;
this.types = types;
this.elements = elements;
}
@Override
public String getName() {
return method.getSimpleName().toString();
}
@Override
public int getParameterCount() {
return method.getParameters().size();
}
@Override
public Handler.TypeWrapper getReturnType() {
return new HandlerForTypeMirror(method.getReturnType(), types, elements);
}
@Override
public Handler.ParameterWrapper[] getParameters() {
Handler.ParameterWrapper[] parameters = new Handler.ParameterWrapper[method.getParameters().size()];
List<? extends VariableElement> variableElements = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
VariableElement variableElement = variableElements.get(i);
parameters[i] = new HandlerForVariableElement(variableElement, types, elements, i == parameters.length - 1 && method.isVarArgs());
}
return parameters;
}
}

View File

@@ -0,0 +1,121 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.type.ArrayType;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
public class HandlerForTypeMirror implements Handler.TypeWrapper {
private final TypeMirror type;
private final Types types;
private final Elements elements;
public HandlerForTypeMirror(TypeMirror type, Types types, Elements elements) {
this.type = type;
this.types = types;
this.elements = elements;
}
@Override
public boolean isAssignableTo(Class<?> clazz) {
return types.isAssignable(types.erasure(type), types.erasure(elements.getTypeElement(clazz.getTypeName()).asType()));
}
@Override
public boolean isAssignableTo(Handler.TypeWrapper type) {
if (type instanceof ForClass) {
return isAssignableTo(((ForClass) type).getClazz());
} else if (type instanceof HandlerForTypeMirror) {
return types.isAssignable(types.erasure(this.type), types.erasure(((HandlerForTypeMirror) type).type));
}
return false;
}
@Override
public boolean isPrimitive() {
return type.getKind().isPrimitive();
}
@Override
public boolean isArray() {
return type instanceof ArrayType;
}
@Override
public boolean isEnum() {
if (type.getKind() != TypeKind.DECLARED) {
return false;
}
DeclaredType declaredType = (DeclaredType) type;
Element element = declaredType.asElement();
return element.getKind() == ElementKind.ENUM;
}
@Override
public boolean is(Class<?> clazz) {
if (type.getKind() == TypeKind.VOID && clazz == Void.TYPE) {
return true;
} else if (type.getKind().isPrimitive() && clazz.isPrimitive()) {
return type.toString().equals(clazz.getTypeName());
} else if (!type.getKind().isPrimitive() && !clazz.isPrimitive()) {
return types.isSameType(types.erasure(type), types.erasure(elements.getTypeElement(clazz.getTypeName()).asType()));
} else {
return false;
}
}
@Override
public boolean is(Handler.TypeWrapper type) {
if (type instanceof ForClass) {
return is(((ForClass) type).getClazz());
} else if (type instanceof HandlerForTypeMirror) {
return types.isSameType(types.erasure(this.type), types.erasure(((HandlerForTypeMirror) type).type));
}
return false;
}
@Override
public Handler.TypeWrapper getComponentType() {
if (type instanceof ArrayType) {
return new HandlerForTypeMirror(((ArrayType) type).getComponentType(), types, elements);
} else {
return new HandlerForTypeMirror(null, types, elements);
}
}
@Override
public String getName() {
return type.toString();
}
@Override
public String getTypeName() {
return type.toString();
}
}

View File

@@ -0,0 +1,151 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.command.utils.Pair;
import lombok.Getter;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
public class HandlerForVariableElement implements Handler.ParameterWrapper {
@Getter
private final VariableElement parameter;
private final Types types;
private final Elements elements;
private final boolean varArgs;
public HandlerForVariableElement(VariableElement variableElement, Types types, Elements elements, boolean varArgs) {
this.parameter = variableElement;
this.types = types;
this.elements = elements;
this.varArgs = varArgs;
}
@Override
public Handler.TypeWrapper getType() {
return new HandlerForTypeMirror(parameter.asType(), types, elements);
}
@Override
public boolean isVarArgs() {
return varArgs;
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
return parameter.getAnnotation(annotation) != null;
}
@Override
public <A extends Annotation> Handler.AnnotationWrapper<A> getAnnotation(Class<A> annotation) {
A ann = parameter.getAnnotation(annotation);
AnnotationMirror annMirror = parameter.getAnnotationMirrors()
.stream()
.filter(am -> new HandlerForTypeMirror(am.getAnnotationType(), types, elements).is(annotation))
.findFirst()
.orElse(null);
return new HandlerForAnnotationMirror<>(ann, annMirror);
}
@Override
public String getName() {
return parameter.getSimpleName().toString();
}
@Override
public List<Handler.AnnotationWrapper<?>> getAnnotations() {
return parameter.getAnnotationMirrors()
.stream()
.collect(Collectors.toMap(Function.identity(), annotationMirror -> {
Class<?> clazz = getClass(annotationMirror.getAnnotationType().toString());
if (clazz == null) return null;
return parameter.getAnnotation((Class<? extends Annotation>) clazz);
}))
.entrySet()
.stream()
.filter(entry -> entry.getValue() != null)
.collect(Collectors.toMap(Map.Entry::getKey, entry -> {
Annotation annotation = entry.getValue();
try {
Method method = annotation.annotationType().getMethod("value");
Class<?> returnType = method.getReturnType();
if (!returnType.isArray()) {
return List.of(annotation);
}
Class<?> innerReturnType = returnType.getComponentType();
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
return List.of(annotation);
}
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
Class<? extends Annotation> containerType = repeatable.value();
if (containerType == returnType) {
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
}
try {
return Arrays.asList((Annotation[]) method.invoke(annotation));
} catch (Exception e) {
return List.of(annotation);
}
} catch (NoSuchMethodException e) {
return List.of(annotation);
}
}))
.entrySet()
.stream()
.flatMap(entry -> {
return entry.getValue()
.stream()
.map(annotation -> new Pair<AnnotationMirror, Annotation>(entry.getKey(), annotation));
})
.filter(pair -> pair.b.annotationType().isAnnotationPresent(Handler.Implementation.class))
.map(pair -> new HandlerForAnnotationMirror<>(pair.b, pair.a))
.collect(Collectors.toList());
}
private Class<?> getClass(String name) {
try {
return Class.forName(name);
} catch (ClassNotFoundException e) {
// Ignore
}
if (!name.contains(".")) return null;
Class<?> outerClass = getClass(name.substring(0, name.lastIndexOf('.')));
if (outerClass == null) return null;
name = name.substring(name.lastIndexOf('.') + 1);
for (Class<?> declaredClass : outerClass.getDeclaredClasses()) {
if (declaredClass.getSimpleName().equals(name)) {
return declaredClass;
}
}
return null;
}
}

View File

@@ -0,0 +1,156 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor;
import de.steamwar.command.Handler;
import de.steamwar.command.HandlerForAnnotationMirror;
import de.steamwar.command.HandlerForExecutableElement;
import de.steamwar.command.HandlerForVariableElement;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class AbstractAnnotationProcessor extends AbstractProcessor {
private Messager messager;
private Types types;
private Elements elements;
public abstract Class<? extends Annotation> getAnnotationClass();
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
this.messager = processingEnv.getMessager();
this.types = processingEnv.getTypeUtils();
this.elements = processingEnv.getElementUtils();
}
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton(this.getAnnotationClass().getCanonicalName());
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
List<ExecutableElement> elements = roundEnv.getElementsAnnotatedWith(getAnnotationClass())
.stream()
.filter(element -> element.getKind() == ElementKind.METHOD)
.map(ExecutableElement.class::cast)
.collect(Collectors.toList());
if (elements.isEmpty()) return false;
elements.forEach(element -> {
checkMethodAnnotation(element, element.getAnnotation(getAnnotationClass()));
});
return false;
}
private Handler getHandler(Annotation annotation, Element element) {
Handler.Implementation implementation = annotation.annotationType().getAnnotation(Handler.Implementation.class);
if (implementation == null) return null;
try {
return implementation.value().getConstructor().newInstance();
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
messager.printMessage(Diagnostic.Kind.ERROR, "Handler " + implementation.value().getName() + " cannot be used to check the argument validity", element);
return null;
}
}
private void checkMethodAnnotation(ExecutableElement method, Annotation annotation) {
Handler handler = getHandler(annotation, method);
if (handler == null) return;
if (!(handler instanceof Handler.HandlerMethod)) {
messager.printMessage(Diagnostic.Kind.ERROR, "Handler " + handler.getClass().getName() + " is not a HandlerMethod", method);
return;
}
Handler.HandlerMethod handlerMethod = (Handler.HandlerMethod) handler;
try {
handlerMethod.check(new HandlerForAnnotationMirror(annotation, null), new HandlerForExecutableElement(method, types, elements), DataCheckableImpl.INSTANCE);
} catch (Handler.HandlerException e) {
Handler.CodePlace codePlace = e.getCodePlace();
AnnotationMirror[] annotationMirrors = new AnnotationMirror[0];
if (codePlace.getAnnotations().length > 0) {
annotationMirrors = Arrays.stream(codePlace.getAnnotations())
.map(annotationWrapper -> (HandlerForAnnotationMirror) annotationWrapper)
.map(HandlerForAnnotationMirror::getAnnotationMirror)
.toArray(AnnotationMirror[]::new);
}
Element element = null;
if (codePlace.getMethod() != null) {
element = ((HandlerForExecutableElement) codePlace.getMethod()).getMethod();
} else if (codePlace.getParameter() != null) {
element = ((HandlerForVariableElement) codePlace.getParameter()).getParameter();
}
if (annotationMirrors.length > 0) {
for (int i = 0; i < annotationMirrors.length; i++) {
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element, annotationMirrors[i]);
}
} else {
messager.printMessage(Diagnostic.Kind.ERROR, e.getMessage(), element);
}
}
}
private static final class DataCheckableImpl implements Handler.DataCheckable {
private static final DataCheckableImpl INSTANCE = new DataCheckableImpl();
@Override
public boolean hasExecutorMapper(Class<?> clazz) {
return true;
}
@Override
public boolean hasMapper(String key) {
return true;
}
@Override
public boolean hasValidator(String key) {
return true;
}
@Override
public boolean hasSupplier(String key) {
return true;
}
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor.impl;
import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor;
import de.steamwar.command.annotations.Cached;
import java.lang.annotation.Annotation;
public class CachedAnnotationProcessor extends AbstractAnnotationProcessor {
@Override
public Class<? extends Annotation> getAnnotationClass() {
return Cached.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor.impl;
import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor;
import de.steamwar.command.annotations.Mapper;
import java.lang.annotation.Annotation;
public class MapperAnnotationProcessor extends AbstractAnnotationProcessor {
@Override
public Class<? extends Annotation> getAnnotationClass() {
return Mapper.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor.impl;
import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor;
import de.steamwar.command.annotations.Register;
import java.lang.annotation.Annotation;
public class RegisterAnnotationProcessor extends AbstractAnnotationProcessor {
@Override
public Class<? extends Annotation> getAnnotationClass() {
return Register.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor.impl;
import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor;
import de.steamwar.command.annotations.Supplier;
import java.lang.annotation.Annotation;
public class SupplierAnnotationProcessor extends AbstractAnnotationProcessor {
@Override
public Class<? extends Annotation> getAnnotationClass() {
return Supplier.class;
}
}

View File

@@ -0,0 +1,33 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotationprocessor.impl;
import de.steamwar.command.annotationprocessor.AbstractAnnotationProcessor;
import de.steamwar.command.annotations.Validator;
import java.lang.annotation.Annotation;
public class ValidatorAnnotationProcessor extends AbstractAnnotationProcessor {
@Override
public Class<? extends Annotation> getAnnotationClass() {
return Validator.class;
}
}

View File

@@ -0,0 +1,27 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}

View File

@@ -0,0 +1,216 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.command.graph.NodeData;
import de.steamwar.command.graph.RootNode;
import de.steamwar.command.utils.Pair;
import de.steamwar.command.utils.Triple;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
public abstract class AbstractCommand<T> {
private static final Map<Class<? extends AbstractCommand<?>>, Map<Class<?>, Function<?, ?>>> EXECUTOR_MAPPER = new HashMap<>();
public static <E, T> void addExecutorMapper(Class<? extends AbstractCommand<E>> wrapper, Class<T> executorType, Function<E, T> mapper) {
EXECUTOR_MAPPER.computeIfAbsent(wrapper, __ -> new HashMap<>())
.putIfAbsent(executorType, mapper);
}
protected final String command;
protected final String permission;
private final Consumer<CommandLoader<T>> initializer;
protected final String[] aliases;
protected final List<String> descriptions = new ArrayList<>();
private boolean initialized = false;
protected final RootNode<T> rootNode = new RootNode<>();
private final Map<String, AbstractTypeMapper<T, ?>> localTypeMapper = new HashMap<>();
private final Map<String, AbstractTypeValidator<T, ?>> localValidators = new HashMap<>();
private final Map<String, AbstractTypeSupplier<T, ?>> localSupplier = new HashMap<>();
protected AbstractCommand(String command, Consumer<CommandLoader<T>> initializer, String... aliases) {
this(command, null, initializer, aliases);
}
protected AbstractCommand(String command, String permission, Consumer<CommandLoader<T>> initializer, String... aliases) {
this.command = command;
this.permission = permission;
this.initializer = initializer;
this.aliases = aliases;
initCommand();
unregister();
register();
}
protected synchronized void initCommand() {
}
public abstract void unregister();
public abstract void register();
protected void commandSystemError(T sender, CommandFrameworkException e) {
Logger.getGlobal().log(Level.WARNING, "An unexpected error occurred", e);
}
protected void sendMessage(T sender, String message, Object[] args) {
}
public final void execute(T sender, String alias, String[] args) {
initialize();
List<Runnable> errors = new ArrayList<>();
try {
boolean executed = rootNode.execute(sender, new NodeData(alias, fixArgs(args, true), (s, args1) -> {
errors.add(() -> sendMessage(sender, s, args1));
}));
if (executed) return;
if (!errors.isEmpty()) {
errors.forEach(Runnable::run);
return;
}
descriptions.forEach(s -> sendMessage(sender, s, new Object[0]));
} catch (CommandFrameworkException e) {
commandSystemError(sender, e);
}
}
public final List<String> tabComplete(T sender, String alias, String[] args) throws IllegalArgumentException {
initialize();
List<Collection<String>> tabCompletes = new ArrayList<>();
rootNode.tabComplete(sender, new NodeData(alias, fixArgs(args, false), (s, args1) -> {}), tabCompletes);
return tabCompletes.stream()
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.filter(Objects::nonNull)
.filter(s -> !s.isEmpty())
.distinct()
.collect(Collectors.toList());
}
private String[] fixArgs(String[] args, boolean allowEmpty) {
int removedCount = 0;
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if (arg.isEmpty() && i != args.length - 1) {
removedCount++;
continue;
}
args[i] = args[i - removedCount];
}
if (removedCount != 0) {
args = Arrays.copyOf(args, args.length - removedCount);
}
if (args.length == 0 && !allowEmpty) {
return new String[]{""};
}
return args;
}
private synchronized void initialize() {
if (initialized) return;
List<Object> commandObjects = new ArrayList<>();
initializer.accept(new CommandLoader<>() {
@Override
public AbstractCommand<T> get() {
return AbstractCommand.this;
}
@Override
public void add(Object command) {
commandObjects.add(command);
}
});
List<Pair<DataImpl, Method>> methods = new ArrayList<>();
for (Object commandObject : commandObjects) {
DataImpl dataImpl = new DataImpl(this, commandObject, rootNode, EXECUTOR_MAPPER.getOrDefault(this.getClass(), Collections.emptyMap()), (Map) localTypeMapper, CommandUtils.MAPPER_FUNCTIONS, (Map) localValidators, CommandUtils.VALIDATOR_FUNCTIONS, (Map) localSupplier, CommandUtils.SUPPLIER_FUNCTIONS);
methods(commandObject).stream()
.filter(method -> Arrays.stream(method.getAnnotations()).anyMatch(anno -> anno.annotationType().isAnnotationPresent(Handler.Implementation.class)))
.forEach(method -> methods.add(new Pair<>(dataImpl, method)));
}
Map<Integer, Map<Triple<DataImpl, Method, Annotation>, List<Handler.HandlerMethod<Annotation>>>> handlerMap = new HashMap<>();
for (Pair<DataImpl, Method> commandMethod : methods) {
List<Annotation> annotations = CommandUtils.getAnnotations(commandMethod.b);
for (Annotation annotation : annotations) {
Handler.Implementation handler = annotation.annotationType().getAnnotation(Handler.Implementation.class);
Handler handlerObject;
try {
handlerObject = handler.value().getConstructor().newInstance();
} catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
InvocationTargetException e) {
throw new UnsupportedOperationException("Handler " + handler.value().getName() + " cannot be used to check the argument validity", e);
}
if (!(handlerObject instanceof Handler.HandlerMethod)) {
throw new UnsupportedOperationException("Handler " + handlerObject.getClass().getName() + " is not a HandlerMethod");
}
handlerMap.computeIfAbsent(((Handler.HandlerMethod<?>) handlerObject).getRunPriority(), k -> new LinkedHashMap<>())
.computeIfAbsent(new Triple<>(commandMethod.a, commandMethod.b, annotation), k -> new ArrayList<>())
.add((Handler.HandlerMethod<Annotation>) handlerObject);
}
}
List<Integer> runPriorities = new ArrayList<>(handlerMap.keySet());
runPriorities.sort(Comparator.naturalOrder());
for (int runPriority : runPriorities) {
handlerMap.get(runPriority).forEach((dataMethodAnnotationTriple, handlerMethods) -> {
handlerMethods.forEach(annotationHandlerMethod -> {
try {
annotationHandlerMethod.check(new Handler.AnnotationWrapper.ForAnnotation<>(dataMethodAnnotationTriple.c), new Handler.MethodWrapper.ForMethod(dataMethodAnnotationTriple.b), dataMethodAnnotationTriple.a);
} catch (Exception e) {
throw new UnsupportedOperationException("Method check failed for " + dataMethodAnnotationTriple.b.getName(), e);
}
annotationHandlerMethod.run(dataMethodAnnotationTriple.c, dataMethodAnnotationTriple.b, dataMethodAnnotationTriple.a);
});
});
}
rootNode.sort();
initialized = true;
}
// TODO: Implement this when Message System is ready
/*
public void addDefaultHelpMessage(String message) {
defaultHelpMessages.add(message);
}
*/
private List<Method> methods(Object commandObject) {
List<Method> methods = new ArrayList<>();
Class<?> current = commandObject.getClass();
while (current != null) {
methods.addAll(Arrays.asList(current.getDeclaredMethods()));
current = current.getSuperclass();
}
return methods;
}
}

View File

@@ -0,0 +1,48 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import java.util.Collection;
public interface AbstractTypeMapper<K, T> {
/**
* The CommandSender can be null!
*/
T map(K sender, PreviousArguments previousArguments, String s);
Collection<String> tabComplete(K sender, PreviousArguments previousArguments, String s);
/**
* @return true if the next element should be appended to the current tab complete.
*/
default boolean appendNextElementTabCompletions() {
return false;
}
/**
* Normalize the cache key by sender and user provided argument. <br>
* Note: The CommandSender can be null if the cache is defined as a global cache!<br>
* Returning null and the empty string are equivalent.
*/
default String normalize(K sender, String s) {
return null;
}
}

View File

@@ -0,0 +1,25 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
public interface AbstractTypeSupplier<K, T> {
T get(K sender, PreviousArguments previousArguments);
}

View File

@@ -0,0 +1,62 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import java.util.function.BooleanSupplier;
@FunctionalInterface
public interface AbstractTypeValidator<K, T> {
/**
* Validates the given value.
*
* @param sender The sender of the command.
* @param value The value to validate or null if mapping returned null.
* @param messageSender The message sender to send messages to the player. Never send messages directly to the player.
* @return The result of the validation.
*/
boolean validate(K sender, T value, MessageSender messageSender);
default AbstractTypeValidator<K, T> and(AbstractTypeValidator<K, T> other) {
return (sender, value, messageSender) -> validate(sender, value, messageSender) && other.validate(sender, value, messageSender);
}
default AbstractTypeValidator<K, T> or(AbstractTypeValidator<K, T> other) {
return (sender, value, messageSender) -> validate(sender, value, messageSender) || other.validate(sender, value, messageSender);
}
default AbstractTypeValidator<K, T> not() {
return (sender, value, messageSender) -> !validate(sender, value, messageSender);
}
@FunctionalInterface
interface MessageSender {
void send(String s, Object... args);
default boolean send(boolean condition, String s, Object... args) {
if (condition) send(s, args);
return condition;
}
default boolean send(BooleanSupplier condition, String s, Object... args) {
return send(condition.getAsBoolean(), s, args);
}
}
}

View File

@@ -0,0 +1,93 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.function.Function;
import java.util.stream.Stream;
public class CommandFrameworkException extends RuntimeException {
private Function causeMessage;
private Throwable cause;
private Function stackTraceExtractor;
private String extraStackTraces;
private String message;
public CommandFrameworkException(InvocationTargetException invocationTargetException, String alias, String[] args) {
this(e -> {
StringBuilder st = new StringBuilder();
st.append(e.getCause().getClass().getTypeName());
if (e.getCause().getMessage() != null) {
st.append(": ").append(e.getCause().getMessage());
}
if (alias != null && !alias.isEmpty()) {
st.append("\n").append("Performed command: " + alias + " " + String.join(" ", args));
}
return st.toString();
}, invocationTargetException, e -> {
StackTraceElement[] stackTraceElements = e.getCause().getStackTrace();
return Arrays.stream(stackTraceElements).limit(stackTraceElements.length - e.getStackTrace().length);
}, null);
}
private <T extends Throwable> CommandFrameworkException(Function<T, String> causeMessage, T cause, Function<T, Stream<StackTraceElement>> stackTraceExtractor, String extraStackTraces) {
super(causeMessage.apply(cause), cause);
this.causeMessage = causeMessage;
this.cause = cause;
this.stackTraceExtractor = stackTraceExtractor;
this.extraStackTraces = extraStackTraces;
}
public synchronized String getBuildStackTrace() {
if (message != null) {
return message;
}
StringBuilder st = new StringBuilder();
st.append(causeMessage.apply(cause)).append("\n");
((Stream<StackTraceElement>) stackTraceExtractor.apply(cause)).forEach(stackTraceElement -> {
st.append("\tat ").append(stackTraceElement.toString()).append("\n");
});
if (extraStackTraces != null) {
st.append("\tat ").append(extraStackTraces).append("\n");
}
message = st.toString();
return message;
}
@Override
public void printStackTrace() {
printStackTrace(System.err);
}
@Override
public void printStackTrace(PrintStream s) {
s.print(getBuildStackTrace());
}
@Override
public void printStackTrace(PrintWriter s) {
s.print(getBuildStackTrace());
}
}

View File

@@ -0,0 +1,26 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
public interface CommandLoader<T> {
AbstractCommand<T> get();
void add(Object command);
}

View File

@@ -0,0 +1,148 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.command.mapper.BooleanMapper;
import de.steamwar.command.mapper.NumberMapper;
import lombok.experimental.UtilityClass;
import java.lang.annotation.Annotation;
import java.lang.annotation.Repeatable;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.*;
import java.util.function.ToIntFunction;
@UtilityClass
public class CommandUtils {
final Map<String, AbstractTypeMapper<?, ?>> MAPPER_FUNCTIONS = new HashMap<>();
final Map<String, AbstractTypeValidator<?, ?>> VALIDATOR_FUNCTIONS = new HashMap<>();
final Map<String, AbstractTypeSupplier<?, ?>> SUPPLIER_FUNCTIONS = new HashMap<>();
static final AbstractTypeMapper<Object, String> STRING_MAPPER = new AbstractTypeMapper<>() {
@Override
public String map(Object sender, PreviousArguments previousArguments, String s) {
return s;
}
@Override
public Collection<String> tabComplete(Object sender, PreviousArguments previousArguments, String s) {
return Collections.singletonList(s);
}
};
static {
addMapper(boolean.class, Boolean.class, new BooleanMapper());
addMapper(int.class, Integer.class, new NumberMapper(Integer::parseInt, false));
addMapper(long.class, Long.class, new NumberMapper(Long::parseLong, false));
addMapper(float.class, Float.class, new NumberMapper(Float::parseFloat, true));
addMapper(double.class, Double.class, new NumberMapper(Double::parseDouble, true));
MAPPER_FUNCTIONS.put(String.class.getTypeName(), STRING_MAPPER);
}
private static void addMapper(Class<?> clazz, Class<?> alternativeClazz, AbstractTypeMapper<?, ?> mapper) {
MAPPER_FUNCTIONS.put(clazz.getTypeName(), mapper);
MAPPER_FUNCTIONS.put(alternativeClazz.getTypeName(), mapper);
}
public static <K, T> void addMapper(Class<T> clazz, AbstractTypeMapper<K, T> mapper) {
addMapper(clazz.getTypeName(), mapper);
}
public static <T> void addMapper(String name, AbstractTypeMapper<T, ?> mapper) {
MAPPER_FUNCTIONS.putIfAbsent(name, mapper);
}
public static <T> void addValidator(Class<T> clazz, AbstractTypeValidator<T, ?> validator) {
addValidator(clazz.getTypeName(), validator);
}
public static <T> void addValidator(String name, AbstractTypeValidator<T, ?> validator) {
VALIDATOR_FUNCTIONS.putIfAbsent(name, validator);
}
public static <T> void addSupplier(Class<T> clazz, AbstractTypeSupplier<T, ?> supplier) {
addSupplier(clazz.getTypeName(), supplier);
}
public static <T> void addSupplier(String name, AbstractTypeSupplier<T, ?> supplier) {
SUPPLIER_FUNCTIONS.putIfAbsent(name, supplier);
}
public static List<Annotation> getAnnotations(AnnotatedElement annotatedElement) {
List<Annotation> annotationList = new ArrayList<>();
for (Annotation annotation : annotatedElement.getAnnotations()) {
try {
Method method = annotation.annotationType().getMethod("value");
Class<?> returnType = method.getReturnType();
if (!returnType.isArray()) {
annotationList.add(annotation);
continue;
}
Class<?> innerReturnType = returnType.getComponentType();
if (!(innerReturnType.isAnnotation() && innerReturnType.isAnnotationPresent(Repeatable.class))) {
annotationList.add(annotation);
continue;
}
Repeatable repeatable = innerReturnType.getAnnotation(Repeatable.class);
Class<? extends Annotation> containerType = repeatable.value();
if (containerType == returnType) {
throw new UnsupportedOperationException("Repeatable annotation must have a container annotation");
}
try {
Annotation[] innerAnnotations = (Annotation[]) method.invoke(annotation);
Collections.addAll(annotationList, innerAnnotations);
} catch (Exception e) {
annotationList.add(annotation);
}
} catch (NoSuchMethodException e) {
annotationList.add(annotation);
}
}
annotationList.removeIf(anno -> !anno.annotationType().isAnnotationPresent(Handler.Implementation.class));
return annotationList;
}
public static <T extends Handler> List<Annotation> getAnnotations(AnnotatedElement annotatedElement, Class<T> type) {
List<Annotation> annotations = getAnnotations(annotatedElement);
annotations.removeIf(annotation -> {
Handler.Implementation implementation = annotation.annotationType().getAnnotation(Handler.Implementation.class);
return implementation == null || !type.isAssignableFrom(implementation.value());
});
return annotations;
}
public static ToIntFunction<Number> createComparator(String type, Handler.TypeWrapper clazz, int iValue, long lValue, float fValue, double dValue) {
if (clazz.is(int.class) || clazz.is(Integer.class)) {
return number -> Integer.compare(number.intValue(), iValue);
} else if (clazz.is(long.class) || clazz.is(Long.class)) {
return number -> Long.compare(number.longValue(), lValue);
} else if (clazz.is(float.class) || clazz.is(Float.class)) {
return number -> Float.compare(number.floatValue(), fValue);
} else if (clazz.is(double.class) || clazz.is(Double.class)) {
return number -> Double.compare(number.doubleValue(), dValue);
} else {
throw new IllegalArgumentException(type + " annotation is not supported for " + clazz);
}
}
}

View File

@@ -0,0 +1,186 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.command.annotations.Supplier;
import de.steamwar.command.graph.*;
import de.steamwar.command.handler.GreedyHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
class DataImpl implements Handler.DataCheckable, Handler.DataReadable, Handler.DataWritable {
private final AbstractCommand<?> container;
private final Object self;
private final RootNode<?> node;
private final Map<Class<?>, Function<?, ?>> executorMapper;
private final Map<String, AbstractTypeMapper<?, ?>> mapper;
private final Map<String, AbstractTypeMapper<?, ?>> globalMapper;
private final Map<String, AbstractTypeValidator<?, ?>> validator;
private final Map<String, AbstractTypeValidator<?, ?>> globalValidator;
private final Map<String, AbstractTypeSupplier<?, ?>> supplier;
private final Map<String, AbstractTypeSupplier<?, ?>> globalSupplier;
private final Map<Method, Object> cache = new HashMap<>();
DataImpl(AbstractCommand<?> container, Object self, RootNode<?> node, Map<Class<?>, Function<?, ?>> executorMapper, Map<String, AbstractTypeMapper<?, ?>> mapper, Map<String, AbstractTypeMapper<?, ?>> globalMapper, Map<String, AbstractTypeValidator<?, ?>> validator, Map<String, AbstractTypeValidator<?, ?>> globalValidator, Map<String, AbstractTypeSupplier<?, ?>> supplier, Map<String, AbstractTypeSupplier<?, ?>> globalSupplier) {
this.container = container;
this.self = self;
this.node = node;
this.executorMapper = executorMapper;
this.mapper = mapper;
this.globalMapper = globalMapper;
this.validator = validator;
this.globalValidator = globalValidator;
this.supplier = supplier;
this.globalSupplier = globalSupplier;
}
@Override
public boolean hasExecutorMapper(Class<?> clazz) {
return getExecutorMapper(clazz) != null;
}
@Override
public Function<?, ?> getExecutorMapper(Class<?> clazz) {
for (Map.Entry<Class<?>, Function<?, ?>> entry : executorMapper.entrySet()) {
if (entry.getKey().isAssignableFrom(clazz)) {
return entry.getValue();
}
}
return null;
}
@Override
public boolean hasMapper(String key) {
return mapper.containsKey(key) || globalMapper.containsKey(key);
}
@Override
public <A, B> AbstractTypeMapper<A, B> getMapper(String key) {
return (AbstractTypeMapper<A, B>) mapper.getOrDefault(key, globalMapper.get(key));
}
@Override
public <A, B> void addMapper(String key, boolean local, AbstractTypeMapper<A, B> mapper) {
if (local) {
this.mapper.put(key, mapper);
} else {
this.globalMapper.putIfAbsent(key, mapper);
}
}
@Override
public boolean hasValidator(String key) {
return validator.containsKey(key) || globalValidator.containsKey(key);
}
@Override
public <A, B> AbstractTypeValidator<A, B> getValidator(String key) {
return (AbstractTypeValidator<A, B>) validator.getOrDefault(key, globalValidator.get(key));
}
@Override
public <A, B> void addValidator(String key, boolean local, AbstractTypeValidator<A, B> validator) {
if (local) {
this.validator.put(key, validator);
} else {
this.globalValidator.putIfAbsent(key, validator);
}
}
@Override
public boolean hasSupplier(String key) {
return supplier.containsKey(key) || globalSupplier.containsKey(key);
}
@Override
public <A, B> AbstractTypeSupplier<A, B> getSupplier(String key) {
return (AbstractTypeSupplier<A, B>) supplier.getOrDefault(key, globalSupplier.get(key));
}
@Override
public <A, B> void addSupplier(String key, boolean local, AbstractTypeSupplier<A, B> supplier) {
if (local) {
this.supplier.put(key, supplier);
} else {
this.globalSupplier.putIfAbsent(key, supplier);
}
}
/**
* Invoking the same method twice will result in the exact same result.
*/
@Override
public <T> T invoke(Method method) {
return (T) cache.computeIfAbsent(method, m -> {
try {
return m.invoke(self);
} catch (IllegalAccessException | InvocationTargetException e) {
return null;
} catch (Exception e) {
throw new RuntimeException(e);
}
});
}
@Override
public void addCommand(Method method, String[] subCommand, String[] description, boolean noTabComplete) {
Node<?> temp = node;
container.descriptions.addAll(Arrays.asList(description));
if (noTabComplete) {
temp = temp.addChild(null, new NoTabCompleteNode<>());
}
for (int i = 0; i < subCommand.length; i++) {
temp = temp.addChild(null, new LiteralNode<>(subCommand[i]));
}
Parameter[] parameters = method.getParameters();
for (int i = 0; i < parameters.length; i++) {
Parameter parameter = parameters[i];
if (i == 0) {
temp = temp.addChild(parameter, new ExecutorTypeNode<>(parameter, i, this));
continue;
}
if (parameter.isAnnotationPresent(Supplier.class)) {
temp = temp.addChild(parameter, new SupplierNode<>(parameter, this));
continue;
}
Class<?> type = parameter.getType();
boolean isArray = parameter.isVarArgs() || type.isArray();
if (!isArray) {
temp = temp.addChild(parameter, new TypeNode<>(parameter, i, this));
continue;
}
boolean greedy = parameter.isVarArgs() || GreedyHandler.isGreedy(parameter);
if (greedy) {
temp = temp.addChild(parameter, new GreedyArrayNode<>(parameter, i, this));
} else {
temp = temp.addChild(parameter, new NonGreedyArrayNode<>(parameter, i, this));
}
}
temp.addChild(null, new ExecuteNode<>(self, method));
}
}

View File

@@ -0,0 +1,370 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.Getter;
import java.lang.annotation.*;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
import java.util.stream.Collectors;
public interface Handler {
default Optional<Class<?>> getGenericTypeOfReturn(Method method) {
Type type;
try {
type = method.getGenericReturnType();
} catch (Exception e) {
return Optional.empty();
}
if (!(type instanceof ParameterizedType)) {
return Optional.empty();
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] generics = parameterizedType.getActualTypeArguments();
if (generics.length != 1 && generics.length != 2) {
return Optional.empty();
}
Type genericType = generics[generics.length - 1];
try {
return Optional.of(Class.forName(genericType.getTypeName()));
} catch (Exception e) {
return Optional.empty();
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@interface Implementation {
Class<? extends Handler> value();
}
class HandlerException extends Exception {
@Getter
private final CodePlace codePlace;
public HandlerException(String message, CodePlace codePlace) {
super(message);
this.codePlace = codePlace;
}
}
interface DataCheckable {
boolean hasExecutorMapper(Class<?> clazz);
boolean hasMapper(String key);
boolean hasValidator(String key);
boolean hasSupplier(String key);
}
interface DataReadable {
Function<?, ?> getExecutorMapper(Class<?> clazz);
<A, B> AbstractTypeMapper<A, B> getMapper(String key);
<A, B> AbstractTypeValidator<A, B> getValidator(String key);
<A, B> AbstractTypeSupplier<A, B> getSupplier(String key);
}
interface DataWritable {
Function<?, ?> getExecutorMapper(Class<?> clazz);
<A, B> void addMapper(String key, boolean local, AbstractTypeMapper<A, B> mapper);
<A, B> void addValidator(String key, boolean local, AbstractTypeValidator<A, B> validator);
<A, B> void addSupplier(String key, boolean local, AbstractTypeSupplier<A, B> supplier);
/**
* Invoking the same method twice will result in the exact same result.
*/
<T> T invoke(Method method);
void addCommand(Method method, String[] subCommand, String[] description, boolean noTabComplete);
}
interface HandlerMethod<T extends Annotation> extends Handler {
void check(AnnotationWrapper<T> annotation, MethodWrapper method, DataCheckable dataCheckable) throws HandlerException;
int getRunPriority();
void run(T annotation, Method method, DataWritable dataWritable);
}
interface HandlerParameter<T extends Annotation, A, B> extends Handler {
void check(AnnotationWrapper<T> annotation, MethodWrapper methodWrapper, ParameterWrapper parameter, int index, DataCheckable dataCheckable) throws HandlerException;
default boolean needsParentTypeMapper() {
return false;
}
/**
* Null values are allowed to be returned.
*/
default AbstractTypeMapper<A, B> getTypeMapper(T annotation, Parameter parameter, int index, DataReadable dataReadable, AbstractTypeMapper<A, B> parentTypeMapper) {
return null;
}
default int getValidatorPriority() {
return 0;
}
/**
* Null values are allowed to be returned.
*/
default AbstractTypeValidator<A, B> getValidator(T annotation, Parameter parameter, int index, DataReadable dataReadable) {
return null;
}
}
@Getter
class CodePlace {
private final MethodWrapper method;
private final ParameterWrapper parameter;
private final AnnotationWrapper<?>[] annotations;
public CodePlace(MethodWrapper method, AnnotationWrapper<?>... annotations) {
this.method = method;
this.parameter = null;
this.annotations = annotations;
}
public CodePlace(ParameterWrapper parameter, AnnotationWrapper<?>... annotations) {
this.method = null;
this.parameter = parameter;
this.annotations = annotations;
}
}
interface MethodWrapper {
String getName();
int getParameterCount();
TypeWrapper getReturnType();
ParameterWrapper[] getParameters();
class ForMethod implements MethodWrapper {
@Getter
private final Method method;
public ForMethod(Method method) {
this.method = method;
}
@Override
public String getName() {
return method.getName();
}
@Override
public int getParameterCount() {
return method.getParameterCount();
}
@Override
public TypeWrapper getReturnType() {
return new TypeWrapper.ForClass(method.getReturnType());
}
@Override
public ParameterWrapper[] getParameters() {
return Arrays.stream(method.getParameters()).map(ParameterWrapper.ForParameter::new).toArray(ParameterWrapper[]::new);
}
}
}
interface ParameterWrapper {
TypeWrapper getType();
boolean isVarArgs();
boolean isAnnotationPresent(Class<? extends Annotation> annotation);
<A extends Annotation> AnnotationWrapper<A> getAnnotation(Class<A> annotation);
String getName();
List<AnnotationWrapper<?>> getAnnotations();
class ForParameter implements ParameterWrapper {
@Getter
private final Parameter parameter;
public ForParameter(Parameter parameter) {
this.parameter = parameter;
}
@Override
public TypeWrapper getType() {
return new TypeWrapper.ForClass(this.parameter.getType());
}
@Override
public boolean isVarArgs() {
return parameter.isVarArgs();
}
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotation) {
return parameter.isAnnotationPresent(annotation);
}
@Override
public <A extends Annotation> AnnotationWrapper<A> getAnnotation(Class<A> annotation) {
return new AnnotationWrapper.ForAnnotation<>(parameter.getAnnotation(annotation));
}
@Override
public String getName() {
return parameter.getName();
}
@Override
public List<AnnotationWrapper<?>> getAnnotations() {
return CommandUtils.getAnnotations(parameter)
.stream()
.map(AnnotationWrapper.ForAnnotation::new)
.collect(Collectors.toList());
}
}
}
interface TypeWrapper {
boolean isAssignableTo(Class<?> clazz);
boolean isAssignableTo(TypeWrapper type);
boolean isPrimitive();
boolean isArray();
boolean isEnum();
boolean is(Class<?> clazz);
boolean is(TypeWrapper type);
TypeWrapper getComponentType();
String getName();
String getTypeName();
class ForClass implements TypeWrapper {
@Getter
private final Class<?> clazz;
public ForClass(Class<?> clazz) {
this.clazz = clazz;
}
@Override
public boolean isAssignableTo(Class<?> clazz) {
return clazz.isAssignableFrom(this.clazz);
}
@Override
public boolean isAssignableTo(TypeWrapper type) {
if (type instanceof ForClass) {
return ((ForClass) type).getClazz().isAssignableFrom(clazz);
}
return false;
}
@Override
public boolean isPrimitive() {
return clazz.isPrimitive();
}
@Override
public boolean isArray() {
return clazz.isArray();
}
@Override
public boolean isEnum() {
return clazz.isEnum();
}
@Override
public boolean is(Class<?> clazz) {
return this.clazz == clazz;
}
@Override
public boolean is(TypeWrapper type) {
if (type instanceof ForClass) {
return ((ForClass) type).getClazz() == this.clazz;
}
return false;
}
@Override
public TypeWrapper getComponentType() {
return new TypeWrapper.ForClass(this.clazz.getComponentType());
}
@Override
public String getName() {
return this.clazz.getName();
}
@Override
public String getTypeName() {
return this.clazz.getTypeName();
}
}
}
interface AnnotationWrapper<A extends Annotation> {
A getAnnotation();
class ForAnnotation<A extends Annotation> implements AnnotationWrapper<A> {
private A annotation;
public ForAnnotation(A annotation) {
this.annotation = annotation;
}
@Override
public A getAnnotation() {
return this.annotation;
}
}
}
}

View File

@@ -0,0 +1,30 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import java.util.Arrays;
import java.util.List;
public interface OptionEnum<T extends Enum<T> & OptionEnum<T>> {
default List<String> getTabCompletes() {
return Arrays.asList("-" + ((T) this).name().toLowerCase());
}
T[] getRemoved();
}

View File

@@ -0,0 +1,96 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2022 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import lombok.NonNull;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
public class PreviousArguments {
public final String[] userArgs;
public final Object[] mappedArgs;
public final boolean hasMoreArguments;
private final Function<String, Object> getByNameFunction;
private boolean usedOptionalValue = false;
public PreviousArguments(String[] userArgs, Object[] mappedArgs, boolean hasMoreArguments, Function<String, Object> getByNameFunction) {
this.userArgs = userArgs;
this.mappedArgs = mappedArgs;
this.hasMoreArguments = hasMoreArguments;
this.getByNameFunction = getByNameFunction;
}
public boolean hasUsedOptionalValue() {
return usedOptionalValue;
}
public void usedOptionalValue() {
this.usedOptionalValue = true;
}
public String getUserArg(int index) {
return userArgs[userArgs.length - index - 1];
}
public <T> T getMappedArg(int index) {
return (T) mappedArgs[mappedArgs.length - index - 1];
}
public <T> Optional<T> getFirst(Class<T> clazz) {
for (Object o : mappedArgs) {
if (clazz.isInstance(o)) {
return Optional.of((T) o);
}
}
return Optional.empty();
}
public <T> List<T> getAll(Class<T> clazz) {
List<T> list = new ArrayList<>();
for (Object o : mappedArgs) {
if (clazz.isInstance(o)) {
list.add((T) o);
}
if (o == null) {
continue;
}
if (o.getClass().isArray()) {
Object[] array = (Object[]) o;
if (array.length == 0) {
continue;
}
for (Object o1 : array) {
if (clazz.isInstance(o1)) {
list.add((T) o1);
}
}
}
}
return list;
}
public <T> T getByName(@NonNull String name) {
return (T) getByNameFunction.apply(name);
}
}

View File

@@ -0,0 +1,109 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2020 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command;
import de.steamwar.command.mapper.internal.DelegatingMapper;
import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.experimental.UtilityClass;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@UtilityClass
public class TabCompletionCache {
private final Map<Key, TabCompletions> tabCompletionCache = new ConcurrentHashMap<>();
Set<AbstractTypeMapper<?, ?>> cached = new HashSet<>();
Set<AbstractTypeMapper<?, ?>> global = new HashSet<>();
Map<AbstractTypeMapper<?, ?>, Long> cacheDuration = new HashMap<>();
static {
Thread thread = new Thread(() -> {
while (true) {
Set<Key> toRemove = new HashSet<>();
for (Map.Entry<Key, TabCompletions> tabCompletionsEntry : tabCompletionCache.entrySet()) {
if (System.currentTimeMillis() - tabCompletionsEntry.getValue().timestamp > cacheDuration.get(tabCompletionsEntry.getKey().typeMapper)) {
toRemove.add(tabCompletionsEntry.getKey());
}
}
for (Key key : toRemove) {
tabCompletionCache.remove(key);
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
});
thread.setName("TabCompletionCache Invalidator");
thread.setDaemon(true);
thread.start();
}
public void add(AbstractTypeMapper<?, ?> typeMapper, boolean global, long cacheDuration, TimeUnit timeUnit) {
TabCompletionCache.cached.add(typeMapper);
if (global) TabCompletionCache.global.add(typeMapper);
TabCompletionCache.cacheDuration.put(typeMapper, timeUnit.toMillis(cacheDuration));
}
public <A, B> AbstractTypeMapper<A, B> cached(AbstractTypeMapper<A, B> dataMapper, AbstractTypeMapper<A, B> toBeCached) {
if (!cached.contains(dataMapper)) return toBeCached;
boolean global = TabCompletionCache.global.contains(dataMapper);
long cacheDuration = TabCompletionCache.cacheDuration.get(dataMapper);
return new DelegatingMapper<>(toBeCached, null) {
@Override
public Collection<String> tabComplete(A sender, PreviousArguments previousArguments, String s) {
String normalizedArg = dataMapper.normalize(global ? null : sender, s);
if (normalizedArg == null) normalizedArg = "";
Key key = new Key(global ? null : sender, normalizedArg, dataMapper);
TabCompletions tabCompletions = tabCompletionCache.computeIfAbsent(key, ignore -> {
return new TabCompletions(System.currentTimeMillis(), toBeCached.tabComplete(sender, previousArguments, s));
});
if (System.currentTimeMillis() - tabCompletions.timestamp > cacheDuration) {
tabCompletions.tabCompletions = toBeCached.tabComplete(sender, previousArguments, s);
}
tabCompletions.timestamp = System.currentTimeMillis();
return tabCompletions.tabCompletions;
}
};
}
@EqualsAndHashCode
@AllArgsConstructor
private static class Key {
private Object sender;
private String arg;
private AbstractTypeMapper<?, ?> typeMapper;
}
@AllArgsConstructor
private static class TabCompletions {
private long timestamp;
private Collection<String> tabCompletions;
}
}

View File

@@ -0,0 +1,37 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.AllowNullHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to allow null values passed to the command.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(AllowNullHandler.Impl.class)
public @interface AllowNull {
}

View File

@@ -0,0 +1,53 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.ArrayLengthHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define a minimum and maximum length the supplied array can have.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(ArrayLengthHandler.Impl.class)
public @interface ArrayLength {
/**
* Inclusive
*/
int min() default 0;
/**
* Inclusive
*/
int max() default Integer.MAX_VALUE;
/**
* Error message if too few Elements got parsed. There are 2 arguments provided to the message.
* The first is the number of elements that got parsed as a number and the second one is how many
* should have been parsed, so the min number of elements expected.
*/
String error() default "";
}

View File

@@ -0,0 +1,52 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.AbstractTypeMapper;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.CachedHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;
/**
* This annotation is used to register a or {@link Mapper}
* on registration as being cached. Only TabCompletions are cached for the duration
* denoted by {@link #timeUnit()} and {@link #cacheDuration()} using
* {@link TimeUnit#toMillis(long)}. If {@link #global()} is {@code true}, the
* cache will not be created per player but for everyone. This is useful for
* commands that are not player specific.
* <br><br>
* To calculate the cache key for a {@link AbstractTypeMapper} the
* {@link AbstractTypeMapper#normalize(Object, String)} method is called.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Handler.Implementation(CachedHandler.Impl.class)
public @interface Cached {
long cacheDuration() default 5;
TimeUnit timeUnit() default TimeUnit.SECONDS;
boolean global() default false;
}

View File

@@ -0,0 +1,56 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.AbstractTypeMapper;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.ClassMapperHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for registering a method as a class mapper.
* The annotated method will be executed while {@link #initialize()}
* is evaluated. The result of this method will be cached under the
* name {@link ClassMapper#value()} converted to a {@link String} using
* {@link Class#getTypeName()}. {@link AbstractTypeMapper} will be used
* as the default mapper if the type this mapper is registered for is
* found as a parameter of any command method annotated with {@link Register}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Handler.Implementation(ClassMapperHandler.Impl.class)
@Deprecated
@DeprecationInfo("Use @Mapper instead")
public @interface ClassMapper {
/**
* The type this mapper is registered for.
*/
Class<?> value();
/**
* If {@code true}, the mapper will only be used in the current command class.
*/
boolean local() default true;
}

View File

@@ -0,0 +1,53 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.ClassValidatorHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for registering a method as a class validator.
* The annotated method will be executed while {@link #initialize()}
* is evaluated. The result of this method will be cached under the
* name {@link ClassValidator#value()} converted to a {@link String} using
* {@link Class#getTypeName()}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Handler.Implementation(ClassValidatorHandler.Impl.class)
@Deprecated
@DeprecationInfo("Use @Validator instead")
public @interface ClassValidator {
/**
* The type this validator is registered for.
*/
Class<?> value();
/**
* If {@code true}, the validator will only be used in the current command class.
*/
boolean local() default true;
}

View File

@@ -0,0 +1,28 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface DeprecationInfo {
String value();
}

View File

@@ -0,0 +1,38 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.EndsWithHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(EndsWithHandler.Impl.class)
public @interface EndsWith {
String value();
String error() default "";
}

View File

@@ -0,0 +1,48 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.ErrorMessageHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define an error message for a parameter.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(ErrorMessageHandler.Impl.class)
public @interface ErrorMessage {
/**
* Error message to be displayed when the parameter is invalid.
*/
String value();
/**
* This is the short form for 'allowEmptyArrays'.
*/
@Deprecated
@DeprecationInfo("Use @ArrayLength instead of this flag")
boolean allowEAs() default true;
}

View File

@@ -0,0 +1,46 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.GreedyHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation can have a huge performance impact. Both positive and negative.
* You can design your command to be more flexible and allow performance improvements if used correctly.
* <br><br>
* The more restrictive the underlying array type is, the more performance can be gained.
* <br><br>
* Using this annotation on the varargs parameter of a command will not have any effect, since they are already treated as greedy arrays.
* <br><br>
* The {@link #backTrackingDepth()} can be used to limit the amount of backtracking that is done. This can be used to improve performance.
* For varargs parameters, this value is defaulted to 0, since they are at the end of the parameter list.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(GreedyHandler.Impl.class)
public @interface Greedy {
int backTrackingDepth() default Integer.MAX_VALUE;
}

View File

@@ -0,0 +1,46 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.LengthHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define a minimum and maximum length the supplied string can have.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(LengthHandler.Impl.class)
public @interface Length {
/**
* Inclusive
*/
int min() default 0;
/**
* Inclusive
*/
int max() default Integer.MAX_VALUE;
}

View File

@@ -0,0 +1,58 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.AbstractTypeMapper;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.MapperHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Annotation for registering a method as a mapper. The annotated method will
* be executed while {@link #initialize()} is evaluated. The result of this
* method will be cached under either {@link Mapper#value()} or {@link Mapper#value()}.
* If {@link Mapper#type()} is used any parameter using that type will be using
* this {@link AbstractTypeMapper} implicitly. While using this annotation on
* a method it can be possible to not supply any type. On a parameter you can
* only use this annotation using the {@link Mapper#value()} value.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Handler.Implementation(MapperHandler.Impl.class)
public @interface Mapper {
/**
* The name this mapper is registered for.
*/
String value() default "";
/**
* The type this mapper is registered for.
*/
Class<?> type() default void.class;
/**
* If {@code true}, the mapper will only be used in the current command class.
*/
boolean local() default true;
}

View File

@@ -0,0 +1,70 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.MaxHandler;
import de.steamwar.command.handler.MaxReferenceHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define a maximum number value for a parameter.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(MaxHandler.Impl.class)
public @interface Max {
int intValue() default Integer.MAX_VALUE;
long longValue() default Long.MAX_VALUE;
float floatValue() default Float.MAX_VALUE;
double doubleValue() default Double.MAX_VALUE;
boolean inclusive() default true;
/**
* Error message to be displayed when the argument supplied is bigger than this allows.
* Two arguments are supplied to the error message. The first is the number that got parsed
* and the second is the max this annotation allows.
*/
String error() default "";
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(MaxReferenceHandler.Impl.class)
@interface Reference {
String value();
boolean inclusive() default true;
/**
* Error message to be displayed when the argument supplied is smaller than this allows.
* Two arguments are supplied to the error message. The first is the number that got parsed
* and the second is the min this annotation allows.
*/
String error() default "";
}
}

View File

@@ -0,0 +1,70 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.MinHandler;
import de.steamwar.command.handler.MinReferenceHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define a minimum number value for a parameter.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(MinHandler.Impl.class)
public @interface Min {
int intValue() default Integer.MIN_VALUE;
long longValue() default Long.MIN_VALUE;
float floatValue() default Float.MIN_VALUE;
double doubleValue() default Double.MIN_VALUE;
boolean inclusive() default true;
/**
* Error message to be displayed when the argument supplied is smaller than this allows.
* Two arguments are supplied to the error message. The first is the number that got parsed
* and the second is the min this annotation allows.
*/
String error() default "";
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(MinReferenceHandler.Impl.class)
@interface Reference {
String value();
boolean inclusive() default true;
/**
* Error message to be displayed when the argument supplied is smaller than this allows.
* Two arguments are supplied to the error message. The first is the number that got parsed
* and the second is the min this annotation allows.
*/
String error() default "";
}
}

View File

@@ -1,7 +1,7 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
* Copyright (C) 2024 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
@@ -17,18 +17,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.sql.internal;
package de.steamwar.command.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Field {
String[] keys() default {};
String def() default "";
boolean nullable() default false;
boolean autoincrement() default false;
@Target({ElementType.PARAMETER})
public @interface Name {
String value();
}

View File

@@ -0,0 +1,46 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.OptionalValueHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define a default value for a parameter.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(OptionalValueHandler.Impl.class)
public @interface OptionalValue {
/**
* Will pe parsed against the TypeMapper specified by the parameter or annotation.
*/
String value();
/**
* The method name stands for 'onlyUseIfNoneIsGiven'.
*/
boolean onlyUINIG() default false;
}

View File

@@ -0,0 +1,38 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.RegexHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(RegexHandler.Impl.class)
public @interface Regex {
String value();
String error() default "";
}

View File

@@ -0,0 +1,57 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.RegisterHandler;
import java.lang.annotation.*;
/**
* Annotation for registering a method as a command.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Register.Registers.class)
@Handler.Implementation(RegisterHandler.Impl.class)
public @interface Register {
/**
* Identifier of subcommand.
*/
String[] value() default {};
/**
* Description of subcommand.
*/
String[] description() default {};
/**
* If {@code true}, the command will not be tab completed.
*/
boolean noTabComplete() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Handler.Implementation(RegisterHandler.Impl.class)
@interface Registers {
Register[] value();
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.StartsWithHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(StartsWithHandler.Impl.class)
public @interface StartsWith {
String value();
String error() default "";
}

View File

@@ -0,0 +1,58 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2023 SteamWar.de-Serverteam
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.command.annotations;
import de.steamwar.command.Handler;
import de.steamwar.command.handler.StaticValueHandler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to define static values for a parameter like an enum just without the enum.
* You can use this annotation on a parameter of type {@link String} or {@link int}, {@link long} and
* {@link boolean}. While using an int, the value will represent the index into the value array. While
* using a boolean, the {@link #falseValues()} defines which indices are considered {@code false} or
* {@code true}.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Handler.Implementation(StaticValueHandler.Impl.class)
@Deprecated
@DeprecationInfo("Use @Values instead")
public @interface StaticValue {
String[] value();
/**
* This is the short form for 'allowImplicitSwitchExpressions'
* and can be set to true if you want to allow int as well as boolean as annotated parameter types.
* The value array needs to be at least 2 long for this flag to be considered.
* While using an int, the value will represent the index into the value array.
* While using a boolean, the {@link #falseValues()} defines which indices are
* considered {@code false} or {@code true}.
*/
@Deprecated
@DeprecationInfo("Dont need to set this to true")
boolean allowISE() default false;
int[] falseValues() default {0};
}

Some files were not shown because too many files have changed in this diff Show More