Compare commits

..
Author SHA1 Message Date
YoyoNow 4306fe7bc9 Merge pull request 'Fix SteamwarUser.setLocale' (#489) from Hut512/SteamWar:fix/setlocale-typo into main
Reviewed-on: SteamWar/SteamWar#489
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-09-14 12:18:40 +02:00
YoyoNow 58df6087f0 Merge pull request 'Fix NoClip' (#491) from Hut512/SteamWar:fix/swplayer-invalid-reference into main
Reviewed-on: SteamWar/SteamWar#491
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-09-14 12:18:16 +02:00
YoyoNow b9b7869124 Merge pull request 'Fix region water level' (#494) from Hut512/SteamWar:fix/testblock-water-level into main
Reviewed-on: SteamWar/SteamWar#494
2026-09-14 12:17:30 +02:00
YoyoNow 1e85b14667 Improve SteamEditWand 2026-09-14 10:02:39 +02:00
Hut512 35c27923aa Fix region water level 2026-09-12 20:07:07 +02:00
Hut512 c3b3e3e60f Fix NoClip instant block break 2026-09-07 22:21:53 +02:00
Hut512 3aa1bf7ffd Fix scoreboard cleanup 2026-09-07 21:15:01 +02:00
Hut512 5a02a58437 Fix SteamwarUser.setLocale 2026-09-07 15:24:32 +02:00
YoyoNow 6209b86149 Fix TeamCommand.info 2026-09-07 14:03:06 +02:00
YoyoNow 6f1403df9c Cleanup SWPlayer 2026-09-05 14:52:59 +02:00
YoyoNow 0113788da2 Fix SteamEditWand 2026-09-05 09:50:47 +02:00
YoyoNow 8a7f65e000 Merge pull request 'Fix CRIU subserver stop' (#485) from Hut512/SteamWar:main into main
Reviewed-on: SteamWar/SteamWar#485
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-09-03 21:39:15 +02:00
Hut512 8401f67b24 Fix CRIU subserver stop 2026-09-03 02:24:49 +02:00
YoyoNow 362468e756 Fix SteamEditWand 2026-09-01 11:14:30 +02:00
YoyoNow ece12df0bc Add SteamEdit 2026-09-01 10:32:56 +02:00
YoyoNow f35c07ab5b Fix EventStarter 2026-08-30 16:12:32 +02:00
YoyoNow 549f7e555c Remove NoTeamServer punishment 2026-08-30 13:04:52 +02:00
YoyoNow 859238d7fa Disable 'showtable' in EventCommand 2026-08-30 12:25:34 +02:00
YoyoNow a79b00f78f Fix EventCommand 2026-08-30 12:23:23 +02:00
YoyoNow 105eda32e6 Update CustomMap 2026-08-30 12:15:22 +02:00
YoyoNow b4487b8079 Update doc comment 2026-08-30 12:00:40 +02:00
YoyoNow ea3aad3bd2 Initial FightSWCommand 2026-08-29 12:52:09 +02:00
YoyoNow d307f890e2 Remove debug output 2026-08-26 22:35:39 +02:00
YoyoNow 97c1da1b2a Add debug output 2026-08-26 22:31:30 +02:00
YoyoNow 8a53aecfac Add debug output 2026-08-26 22:26:43 +02:00
YoyoNow 5236afba17 Add debug output 2026-08-26 22:17:33 +02:00
YoyoNow d3c8b6e1c6 Add debug output 2026-08-26 22:12:53 +02:00
YoyoNow 00ea792eee Merge pull request 'Improve AutoChecker and GameModeConfig again' (#478) from AutoChecker into main
Reviewed-on: SteamWar/SteamWar#478
2026-08-26 22:05:31 +02:00
YoyoNow 38e845b0e4 Improve AutoChecker and GameModeConfig again 2026-08-26 21:46:45 +02:00
YoyoNow c60a8caed8 Merge pull request 'Improve items for GameModeConfig' (#476) from AutoChecker into main
Reviewed-on: SteamWar/SteamWar#476
Reviewed-by: sakziea <59+sakziea@noreply.localhost>
2026-08-25 17:07:11 +02:00
YoyoNow 2e390286b2 Merge pull request 'VelocityCore - Server Links' (#477) from VelocityCore/ServerLinks into main
Reviewed-on: SteamWar/SteamWar#477
Reviewed-by: sakziea <59+sakziea@noreply.localhost>
2026-08-25 16:57:04 +02:00
YoyoNow 6476125a3f Add ServerLinks to login 2026-08-24 20:22:48 +02:00
YoyoNow 311437d451 Add ServerLinks to login 2026-08-24 20:22:02 +02:00
YoyoNow 5a52771ec1 Improve items for GameModeConfig 2026-08-24 20:05:58 +02:00
YoyoNow 72b70a62e1 Fix CustomItem 2026-08-19 12:05:09 +02:00
YoyoNow 8575dcac33 Add WindCharge option to LaunchScript 2026-08-19 11:06:34 +02:00
YoyoNow cb744f6aa0 Add AntiPlayerCollision 2026-08-18 10:48:16 +02:00
YoyoNow 227f63c9ff Add AntiPlayerCollision 2026-08-18 10:39:58 +02:00
YoyoNow 397b10c319 Merge pull request 'Velocity core /event command' (#465) from VelocityCore/EventCommand into main
Reviewed-on: SteamWar/SteamWar#465
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-08-14 07:53:43 +02:00
YoyoNow 32569f19d9 Closes: #468 2026-08-13 10:09:13 +02:00
YoyoNow f19e4158e7 Fix Check 2026-08-13 10:01:55 +02:00
YoyoNow 6c46b5b2a2 Fix Check 2026-08-13 09:51:56 +02:00
YoyoNow 58516448d9 Merge pull request 'Add deletion of PlayerData on /bau delmember' (#454) from VelocityCore/DeleteMemberOfBauDeletingPlayerData into main
Reviewed-on: SteamWar/SteamWar#454
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-08-13 09:50:14 +02:00
YoyoNow 683236bb59 Fix TexturePackSystem for newer versions 2026-08-13 09:39:42 +02:00
YoyoNow 8dc101639d Add alias of /tick rate to /tick rate 20 2026-08-11 21:48:28 +02:00
YoyoNow 792620804a Improve TPSSystem 2026-08-11 21:46:38 +02:00
YoyoNow 4aa7c99a6e Fix Check and CheckCommand permission 2026-08-11 21:05:36 +02:00
Sakziea cce18124f2 Remove unused translation 2026-08-05 20:30:36 +02:00
Sakziea 18ad0ad90c Add Clickevents to EventPage 2026-08-05 20:30:28 +02:00
Sakziea a58de898bb Add Clickevents to EventPage 2026-08-05 20:30:25 +02:00
Sakziea 507b7c2569 Add event showtable 2026-08-05 20:30:20 +02:00
Sakziea a18098b8f4 Fix Pull request comments 2026-08-05 20:30:15 +02:00
Sakziea 97773f292d Remove unused import 2026-08-05 20:30:09 +02:00
Sakziea 5fdfc03587 Fix /event [Team] move to /event team [Team] 2026-08-05 20:30:00 +02:00
Sakziea 493e66cc98 Add current event uses eventpage 2026-08-05 20:29:37 +02:00
Sakziea 2be3a136ae Add funktion to show next events and formatet the fights in pages 2026-08-05 20:29:28 +02:00
Sakziea c62a566447 Fix pull Request comment 2026-08-05 20:29:18 +02:00
Sakziea 0684765a76 Remove unused imports 2026-08-05 20:29:09 +02:00
Sakziea c40f29c3c1 Add Wind charge config 2026-08-05 20:28:53 +02:00
Sakziea 72dc4eee9e Fix Wind charges cross middle and interact with Blocks 2026-08-05 20:28:24 +02:00
Sakziea c7a949322e Fix Windcharge remove Water 2026-08-05 20:27:39 +02:00
Chaoscaot 9d5b7893f1 Merge pull request 'Replace Custom Observer with kotlinx StateFlows' (#444) from swui/flows into main
Reviewed-on: SteamWar/SteamWar#444
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-26 10:22:42 +02:00
Chaoscaot ae898e14c2 Merge branch 'main' into swui/flows 2026-07-26 10:20:35 +02:00
Chaoscaot 726f73cc45 Merge branch 'main' into VelocityCore/DeleteMemberOfBauDeletingPlayerData 2026-07-26 03:04:45 +02:00
YoyoNow badff1c70f Merge pull request 'Fix Wind Charges remove Water, interact with Blocks and cross middle' (#455) from FightSystem/Windcharge into main
Reviewed-on: SteamWar/SteamWar#455
2026-07-18 15:00:18 +02:00
Sakziea 1d2ac4f705 Fix pull Request comment 2026-07-18 14:58:24 +02:00
Sakziea b48c75ef74 Remove unused imports 2026-07-18 12:49:23 +02:00
Sakziea 8b6ea12a08 Add Wind charge config 2026-07-18 12:43:46 +02:00
Sakziea 801678ddd3 Fix Wind charges cross middle and interact with Blocks 2026-07-18 12:43:23 +02:00
Sakziea e5cc874834 Fix Windcharge remove Water 2026-07-18 11:08:51 +02:00
YoyoNow 95119fc93f Fix FightServer.kt and VelocityServer.kt @get:Optional annotations complaining about primitive types of field 2026-07-17 16:40:38 +02:00
YoyoNow d84ca3547a Merge pull request 'Fix AutoChecker only counts filled Dispenser' (#453) from SchematicSystem/AutoPrüfer into main
Reviewed-on: SteamWar/SteamWar#453
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-17 14:27:01 +02:00
Sakziea 25ab79abc0 Fix PullRequest comment 2026-07-17 14:23:55 +02:00
Sakziea 582d6a62e3 Fix PullRequest comment 2026-07-17 14:22:36 +02:00
Chaoscaot 5eec792aff Merge branch 'main' of https://git.steamwar.de/SteamWar/SteamWar 2026-07-17 12:05:00 +02:00
Chaoscaot e0f26c3e8d Delete event relations when fights and groups are removed 2026-07-17 12:03:15 +02:00
YoyoNow a59e9b4343 Closes: #323 2026-07-17 10:06:48 +02:00
YoyoNow 64e627514d Add deletion of PlayerData on /bau delmember 2026-07-17 09:47:40 +02:00
Sakziea a8c68864d8 Fix AutoChecker only counts filled Dispenser 2026-07-16 17:07:37 +02:00
YoyoNow c0668723d7 Merge pull request 'Add GameModeConfig.KitsConfig.MaxBlastResistance for disabling all Blocks with more than 9.0 blast resistance' (#451) from UpdateGameModeConfig into main
Reviewed-on: SteamWar/SteamWar#451
2026-07-16 16:42:16 +02:00
YoyoNow 5bc2daf37a Add GameModeConfig.KitsConfig.MaxBlastResistance for disabling all Blocks with more than 9.0 blast resistance 2026-07-16 16:39:56 +02:00
YoyoNow e6d39da36b Add GameModeConfig.KitsConfig.MaxBlastResistance for disabling all Blocks with more than 9.0 blast resistance 2026-07-16 16:39:27 +02:00
YoyoNow 390d388692 Closes: #442 2026-07-16 16:32:35 +02:00
YoyoNow 9a60ac228c Merge pull request 'Making /trace isolate toggle the tnt on and off to normal Trace show' (#445) from BauSystem/Trace into main
Reviewed-on: SteamWar/SteamWar#445
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-16 16:24:16 +02:00
Sakziea dab443b989 Fix pullRequest comments 2026-07-16 16:23:52 +02:00
Sakziea bf3c65c630 Fix when no tnt isolated show normal 2026-07-14 19:47:08 +02:00
Sakziea b488c4ed7c Fix /trace isolate {id} showing tnt from other traces 2026-07-14 19:29:12 +02:00
Sakziea 2e795aaf8e Fix /trace 1 still showes all the tnt of that trace 2026-07-06 17:49:09 +02:00
Sakziea 7a601235f5 Fix Trace isolating the same Tnt shows all Tnts 2026-07-06 17:27:47 +02:00
Chaoscaot 3a247de43d Replace Custom Observer with kotlinx StateFlows
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-06 01:13:05 +02:00
Chaoscaot 62e855ec1b Fix Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 14:39:20 +02:00
YoyoNow 9e7311934f Convert buildSrc from gradle/groovy to kts/kotlin 2026-07-05 14:14:04 +02:00
Chaoscaot 6fd3e6f690 Fix Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:51:45 +02:00
Chaoscaot 7acd51fd61 Fix Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:45:59 +02:00
Chaoscaot b278ca15f3 Fix Devserver
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:41:01 +02:00
Chaoscaot 029249c2b0 Fix Database Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:23:52 +02:00
Chaoscaot 1ceb10439b Fix Database Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:18:38 +02:00
Chaoscaot a5dfe6ab7e Fix Database Reset
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 12:59:29 +02:00
YoyoNow c8a5f567eb Add StreamingCommand for UserPerm.PREFIX_YOUTUBER 2026-07-05 11:54:07 +02:00
Chaoscaot 47fb4da85b Fix Inventory
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-20 21:43:05 +02:00
YoyoNow 0eef22aab0 Fix ServerStarter.tempWorld 2026-06-20 17:42:16 +02:00
D4rkr34lm 013d18614f Fix player nametags showing 2026-06-20 17:20:25 +02:00
YoyoNow c7c1ab64e0 Fix BoatRace 2026-06-18 15:30:07 +02:00
Chaoscaot b68a27fbb6 Merge pull request 'SWUI V2' (#418) from swui-v2 into main
Reviewed-on: SteamWar/SteamWar#418
Reviewed-by: D4rkr34lm <dark@steamwar.de>
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-18 14:10:59 +02:00
Chaoscaot 7038dc2aa5 Merge branch 'main' into swui-v2 2026-06-17 21:49:52 +02:00
Chaoscaot 7af586ec16 Fix Observer
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-17 21:48:27 +02:00
YoyoNow b04e99ce54 Merge pull request 'fix(FightSystem): prevent driedGhasts from spawing & plants from growing' (#434) from FightSystem/fix-dried-ghast-spawning into main
Reviewed-on: SteamWar/SteamWar#434
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-17 21:24:00 +02:00
YoyoNow 524702fbb9 Merge pull request 'Implement proper stop and not sleep on BauCommand.stop' (#435) from VelocityCore/BauCommand#stop into main
Reviewed-on: SteamWar/SteamWar#435
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-06-17 21:23:33 +02:00
D4rkr34lm e07298e748 Move listener to permanent 2026-06-17 21:21:17 +02:00
YoyoNow e1df793e9f Merge pull request 'VelocityCore /check command' (#430) from VelocityCore/CheckCommand into main
Reviewed-on: SteamWar/SteamWar#430
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-06-17 21:17:54 +02:00
YoyoNow 806a1affea Merge pull request 'fix(BauSystem): advanced flag entities being misplaced' (#433) from wip/fix-advanced-flag into main
Reviewed-on: SteamWar/SteamWar#433
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-17 21:14:27 +02:00
YoyoNow c538cdbbd2 Implement proper stop and not sleep on BauCommand.stop 2026-06-17 21:13:57 +02:00
D4rkr34lm d7ba19049a Add event handler 2026-06-17 21:10:55 +02:00
D4rkr34lm 47909b6f07 Add listener to prevent dried ghasts from growing 2026-06-17 21:09:07 +02:00
YoyoNow 48846a698f Fix TestblockCommand tab complete order 2026-06-17 21:04:34 +02:00
D4rkr34lm b771c95b99 Fix advanced flag and add lsp files to gitignore 2026-06-17 20:28:33 +02:00
YoyoNow d0aada2b00 Deactivate AdvancementsManager 2026-06-17 16:16:39 +02:00
YoyoNow 6522fc77f2 Improve color gradient 2026-06-17 11:14:53 +02:00
YoyoNow 27e01a56ae Improve CheckCommand 2026-06-17 11:09:32 +02:00
YoyoNow ed89770c0f Fix ConcurrentModificationException 2026-06-17 11:04:07 +02:00
YoyoNow 3ec3c90f04 Fix message on join 2026-06-17 10:57:04 +02:00
YoyoNow 73d4ed26c8 Implement CheckCommand for Checkers not having Check perm 2026-06-17 10:52:32 +02:00
YoyoNow 256bcfb1bf Update CheckCommand 2026-06-17 10:52:32 +02:00
YoyoNow 28ce288815 Merge pull request 'Velocity core/ advancements' (#429) from VelocityCore/Advancements into main
Reviewed-on: SteamWar/SteamWar#429
2026-06-17 10:24:21 +02:00
YoyoNow 6599dd026a Update CustomMap 2026-06-15 09:24:46 +02:00
YoyoNow 03052b677f Update CustomMap 2026-06-15 09:20:21 +02:00
YoyoNow f76a6fa79d Merge pull request 'fix(VelocityCore): server starter copping world to wrong path' (#427) from fix-event-server-naming into main
Reviewed-on: SteamWar/SteamWar#427
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-14 21:47:31 +02:00
D4rkr34lm 7fb7f46ca7 Fix path issues 2026-06-14 00:58:41 +02:00
YoyoNow 1269b7f00a Fix NoClipCommand 2026-06-12 22:16:00 +02:00
YoyoNow 91a0685724 Fix Missile spawning 2026-06-12 21:41:20 +02:00
YoyoNow 72dd2ef59a Fix Missile spawning 2026-06-12 20:43:43 +02:00
YoyoNow 54a1549973 Fix Missile spawning 2026-06-12 20:30:44 +02:00
D4rkr34lm fd5f5b92b4 Merge pull request 'fix(SchematicSystem): mixup of coordinates in size check' (#426) from fix-autochecker into main
Reviewed-on: SteamWar/SteamWar#426
2026-06-12 19:59:48 +02:00
D4rkr34lm 60dc5e4442 Fix formatiing 2026-06-12 19:56:12 +02:00
D4rkr34lm 4cdaf759af Fix mixup of dimensions in autochecker 2026-06-12 19:54:06 +02:00
YoyoNow 6e919d9148 Fix AdvancementsManager
(cherry picked from commit c221989f9c)
2026-06-12 16:29:28 +02:00
YoyoNow a20ec8c93d Add comment in Items 2026-06-12 15:36:21 +02:00
YoyoNow 18b65a2984 Remove item.json
Improve AdvancementsManager
2026-06-12 15:35:13 +02:00
YoyoNow 669235709e Fix WorldEditListener 2026-06-12 15:14:09 +02:00
YoyoNow 796e154c1c Fix paper in inventory 2026-06-12 15:07:46 +02:00
YoyoNow 9efe35fe0d Update LobbySystem run task 2026-06-12 14:52:46 +02:00
YoyoNow e0aaacd66a Fix AnvilGUI for 1.21 not being mojmapped 2026-06-12 14:52:03 +02:00
YoyoNow 7adb1e8b4a Remove automatic update for now 2026-06-12 14:22:44 +02:00
YoyoNow b88e592e79 Move item.json 2026-06-12 14:21:45 +02:00
YoyoNow 914134600e Improve Advancements performance 2026-06-12 14:19:47 +02:00
Chaoscaot 27877938bc Add support for GameMode templates and YAML-based configuration handling in DevCommand.
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-12 12:29:56 +02:00
Chaoscaot 70c8678c60 Refactor rendering system: Introduced RenderObject abstraction, replaced RenderBoundary with ObserverListener, and updated slot calculation for inventory types.
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-12 12:00:04 +02:00
Chaoscaot 997292d58e Merge branch 'main' into swui-v2 2026-06-10 21:43:25 +02:00
Chaoscaot 8050f51424 Cleanup for Merge
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 21:43:02 +02:00
Chaoscaot a6681ffaf6 Add Top-Level State and more Utils
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 16:07:37 +02:00
Chaoscaot a23530074c Merge remote-tracking branch 'origin/swui-v2' into swui-v2 2026-06-10 09:28:24 +02:00
Chaoscaot e88a4c624b Merge branch 'main' into swui-v2 2026-06-10 09:28:16 +02:00
Chaoscaot 105beaf7a6 Merge branch 'main' into swui-v2 2026-06-10 09:27:59 +02:00
Chaoscaot 5f7ab3cd7b Updates
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 09:26:04 +02:00
Chaoscaot 5ce69e6b7a SWUI V2
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 00:36:18 +02:00
YoyoNow 9e43d5cd1b Add more Advancements in progression 2026-06-01 14:03:50 +02:00
YoyoNow 2ad9ae3c7f Fix Advancements Placements 2026-05-31 23:04:08 +02:00
YoyoNow 847eb3fe5d Add even more Advancements 2026-05-31 22:31:02 +02:00
YoyoNow 8fa9f7b0d3 Add even more Advancements 2026-05-31 21:56:38 +02:00
YoyoNow 559cae2b6d Add playtime update 2026-05-31 20:20:14 +02:00
YoyoNow 5dbf3638d0 Add Advancement
Add Advancements
Add AdvancementsManager
Add SelectAdvancementTabPacket
Add item.json
Update ConnectionListener
2026-05-31 18:09:44 +02:00
162 changed files with 7890 additions and 1269 deletions
+5
View File
@@ -15,6 +15,11 @@ bin/
.vscode
.settings
# Language Server
**/.project
**/.factorypath
**/.classpath
# Other
lib
/WebsiteBackend/data
@@ -35,6 +35,7 @@ dependencies {
compileOnly(libs.classindex)
annotationProcessor(libs.classindex)
compileOnly(project(":SpigotCore", "default"))
compileOnly(project(":KotlinCore", "default"))
compileOnly(libs.axiom)
compileOnly(libs.authlib)
@@ -25,12 +25,14 @@ import de.steamwar.bausystem.configplayer.ConfigConverter;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.panzern.Panzern;
import de.steamwar.bausystem.features.slaves.panzern.PanzernAlgorithm;
import de.steamwar.bausystem.features.tracer.TraceManager;
import de.steamwar.bausystem.features.tracer.TraceRecorder;
import de.steamwar.bausystem.features.world.BauScoreboard;
import de.steamwar.bausystem.linkage.BauGuiItem;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.RegionSystem;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.bausystem.utils.TickManager;
@@ -39,8 +41,9 @@ import de.steamwar.command.AbstractValidator;
import de.steamwar.command.SWCommandUtils;
import de.steamwar.core.CRIUSleepEvent;
import de.steamwar.core.Core;
import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.core.WorldIdentifier;
import de.steamwar.core.worldedit.SteamEdit;
import de.steamwar.core.worldedit.WorldEditRendererCUIEditor;
import de.steamwar.linkage.AbstractLinker;
import de.steamwar.linkage.SpigotLinker;
import de.steamwar.message.Message;
@@ -48,6 +51,7 @@ import de.steamwar.providers.BauServerInfo;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
@@ -111,6 +115,9 @@ public class BauSystem extends JavaPlugin implements Listener {
if (any instanceof ConfigConverter) {
Config.addConfigConverter((ConfigConverter) any);
}
if (any instanceof BoundingBoxLoader) {
((BoundingBoxLoader) any).load();
}
}
};
try {
@@ -125,7 +132,19 @@ public class BauSystem extends JavaPlugin implements Listener {
TraceManager.instance.init();
TraceRecorder.instance.init();
new WorldEditRendererCUIEditor();
SteamEdit.init();
SteamEdit.ADJACENT_FILTERS = location -> {
Region region = Region.getRegion(location);
Region.Area area;
if (region.getBuildArea().inRegion(location, true)) {
area = region.getBuildArea();
} else if (region.getTestblockArea().inRegion(location, true)) {
area = region.getTestblockArea();
} else {
return SteamEdit.AdjacentFilter.ALWAYS;
}
return (x, y, z) -> area.inRegion(new Location(null, x, y, z), true);
};
Bukkit.getWorlds().get(0).setGameRule(GameRule.SEND_COMMAND_FEEDBACK, false);
@@ -290,7 +290,7 @@ public class KillcheckerVisualizer {
}
rEntities.get(point).die();
}
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5));
RBlockDisplay entity = new RBlockDisplay(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0, 0, 0));
entity.setBlock(MATERIALS[Math.min(count - 1, MATERIALS.length) - 1].createBlockData());
rEntities.put(point, entity);
if (outlinePoints.contains(point)) outlinePointsCache.add(point);
@@ -46,7 +46,7 @@ public class ObserverTracerListener implements Listener {
public ObserverTracerListener() {
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), () -> {
SWPlayer.allWithSingleComponent(ObserverTracer.class).forEach(pair -> {
if (pair.getPlayer().getGameMode() != GameMode.SPECTATOR) return;
if (pair.getSwPlayer().getPlayer().getGameMode() != GameMode.SPECTATOR) return;
pair.getComponent().show();
});
}, 15L, 15L);
@@ -185,17 +185,16 @@ public class TestblockCommand extends SWCommand {
return new TypeMapper<SchematicNode>() {
@Override
public List<String> tabCompletes(CommandSender commandSender, PreviousArguments previousArguments, String s) {
List<String> stringList = new ArrayList<>(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
List<String> stringList = new ArrayList<>();
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.byId(0), s));
stringList.addAll(SchematicNode.getNodeTabcomplete(SteamwarUser.get(((Player) commandSender).getUniqueId()), s));
return stringList;
}
@Override
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.byId(0), s);
}
SchematicNode node = SchematicNode.getNodeFromPath(SteamwarUser.byId(0), s);
if (node == null) node = SchematicNode.getNodeFromPath(SteamwarUser.get(((Player) commandSender).getUniqueId()), s);
return node;
}
};
@@ -19,6 +19,7 @@
package de.steamwar.bausystem.features.simulator;
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.Permission;
import de.steamwar.bausystem.SWUtils;
@@ -77,8 +78,16 @@ public class SimulatorCursor implements Listener {
return isSimulatorItem(player.getInventory().getItemInMainHand()) || isSimulatorItem(player.getInventory().getItemInOffHand());
}
private static Set<Player> scheduledUpdates = new HashSet<>();
private static void scheduleCursorUpdate(Player player) {
BauSystem.runTaskLater(BauSystem.getInstance(), () -> calcCursor(player), 1);
scheduledUpdates.add(player);
}
@EventHandler
public void onServerTickEnd(ServerTickEndEvent event) {
scheduledUpdates.forEach(SimulatorCursor::calcCursor);
scheduledUpdates.clear();
}
@EventHandler
@@ -122,6 +131,7 @@ public class SimulatorCursor implements Listener {
public void onPlayerQuit(PlayerQuitEvent event) {
cursorType.remove(event.getPlayer());
removeCursor(event.getPlayer());
scheduledUpdates.remove(event.getPlayer());
}
private static final Map<Player, Long> LAST_SNEAKS = new HashMap<>();
@@ -19,17 +19,28 @@
package de.steamwar.bausystem.features.slaves.laufbau;
import com.sk89q.worldedit.blocks.SkullBlock;
import com.sk89q.worldedit.world.block.BaseBlock;
import de.steamwar.inventory.SWItem;
import lombok.Getter;
import lombok.ToString;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.block.data.type.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@ToString
@Getter
public class BlockBoundingBox {
@@ -81,4 +92,197 @@ public class BlockBoundingBox {
public double volume() {
return volume;
}
static {
addPixel(Material.AIR.createBlockData(), 0, 0, 0, 0, 0, 0, null);
// addPixel(Material.COBWEB.createBlockData(), 0, 0, 0, 0, 0, 0, createItem("LAUFBAU_BLOCK_COBWEB", Material.COBWEB));
addPixel(Material.END_STONE.createBlockData(), 0, 0, 0, 16, 16, 16, null);
addPixel(Material.DIRT_PATH.createBlockData(), 0, 0, 0, 16, 15, 16, createItem("LAUFBAU_BLOCK_GRASS_PATH", Material.DIRT_PATH));
addPixel(Material.MUD.createBlockData(), 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SOUL_SAND", Material.SOUL_SAND));
Cocoa cocoaNorth = (Cocoa) Material.COCOA.createBlockData();
cocoaNorth.setAge(2);
cocoaNorth.setFacing(BlockFace.NORTH);
addPixel(cocoaNorth, 4, 3, 1, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_NORTH"));
Cocoa cocoaSouth = (Cocoa) Material.COCOA.createBlockData();
cocoaSouth.setAge(2);
cocoaSouth.setFacing(BlockFace.SOUTH);
addPixel(cocoaSouth, 4, 3, 7, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_SOUTH"));
Cocoa cocoaWest = (Cocoa) Material.COCOA.createBlockData();
cocoaWest.setAge(2);
cocoaWest.setFacing(BlockFace.WEST);
addPixel(cocoaWest, 1, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_WEST"));
Cocoa cocoaEast = (Cocoa) Material.COCOA.createBlockData();
cocoaEast.setAge(2);
cocoaEast.setFacing(BlockFace.EAST);
addPixel(cocoaEast, 7, 3, 4, 8, 9, 8, createItem("LAUFBAU_BLOCK_COCOA", Material.COCOA_BEANS, "LAUFBAU_FACING_EAST"));
TurtleEgg singleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
singleTurtleEgg.setEggs(1);
singleTurtleEgg.setHatch(0);
addPixel(singleTurtleEgg, 4, 0, 3, 9, 7, 9, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_1"));
TurtleEgg doubleTurtleEgg = (TurtleEgg) Material.TURTLE_EGG.createBlockData();
doubleTurtleEgg.setEggs(2);
doubleTurtleEgg.setHatch(0);
addPixel(doubleTurtleEgg, 1, 0, 1, 14, 7, 14, createItem("LAUFBAU_BLOCK_TURTLE_EGG", Material.TURTLE_EGG, "LAUFBAU_COUNT_2"));
addPixel(Material.CHEST.createBlockData(), 1, 0, 1, 14, 14, 14, createItem("LAUFBAU_BLOCK_CHEST", Material.CHEST));
Snow snowLayers8 = (Snow) Material.SNOW.createBlockData();
snowLayers8.setLayers(8);
addPixel(snowLayers8, 0, 0, 0, 16, 14, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_8"));
Directional headNorth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headNorth.setFacing(BlockFace.NORTH);
addPixel(headNorth, 4, 4, 8, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_NORTH"), BlockBoundingBox::randomPlayerHead);
Directional headSouth = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headSouth.setFacing(BlockFace.SOUTH);
addPixel(headSouth, 4, 4, 0, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_SOUTH"), BlockBoundingBox::randomPlayerHead);
Directional headWest = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headWest.setFacing(BlockFace.WEST);
addPixel(headWest, 8, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_WEST"), BlockBoundingBox::randomPlayerHead);
Directional headEast = (Directional) Material.PLAYER_WALL_HEAD.createBlockData();
headEast.setFacing(BlockFace.EAST);
addPixel(headEast, 0, 4, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_WALL_HEAD", Material.PLAYER_HEAD, "LAUFBAU_FACING_EAST"), BlockBoundingBox::randomPlayerHead);
Snow snowLayers7 = (Snow) Material.SNOW.createBlockData();
snowLayers7.setLayers(7);
addPixel(snowLayers7, 0, 0, 0, 16, 12, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_7"));
Snow snowLayers6 = (Snow) Material.SNOW.createBlockData();
snowLayers6.setLayers(6);
addPixel(snowLayers6, 0, 0, 0, 16, 10, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_6"));
addPixel(Material.STONECUTTER.createBlockData(), 0, 0, 0, 16, 9, 16, createItem("LAUFBAU_BLOCK_STONECUTTER", Material.STONECUTTER));
addPixel(Material.PLAYER_HEAD.createBlockData(), 4, 0, 4, 8, 8, 8, createItem("LAUFBAU_BLOCK_PLAYER_HEAD", Material.PLAYER_HEAD), BlockBoundingBox::randomPlayerHead);
addPixel(Material.CAKE.createBlockData(), 1, 0, 1, 14, 8, 14, createItem("LAUFBAU_BLOCK_CAKE", Material.CAKE));
Slab bottomSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
bottomSlab.setType(Slab.Type.BOTTOM);
addPixel(bottomSlab, 0, 0, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_BOTTOM"));
Slab topSlab = (Slab) Material.END_STONE_BRICK_SLAB.createBlockData();
topSlab.setType(Slab.Type.TOP);
addPixel(topSlab, 0, 8, 0, 16, 8, 16, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_SLAB", Material.END_STONE_BRICK_SLAB, "LAUFBAU_TYPE_TOP"));
SeaPickle quadSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
quadSeaPickle.setWaterlogged(false);
quadSeaPickle.setPickles(4);
addPixel(quadSeaPickle, 2, 0, 2, 12, 7, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_4"));
Campfire campfire = (Campfire) Material.CAMPFIRE.createBlockData();
campfire.setSignalFire(false);
campfire.setLit(false);
addPixel(campfire, 0, 0, 0, 16, 7, 16, createItem("LAUFBAU_BLOCK_CAMPFIRE", Material.CAMPFIRE));
SeaPickle trippleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
trippleSeaPickle.setWaterlogged(false);
trippleSeaPickle.setPickles(3);
addPixel(trippleSeaPickle, 2, 0, 2, 12, 6, 12, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_3"));
SeaPickle doubleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
doubleSeaPickle.setWaterlogged(false);
doubleSeaPickle.setPickles(2);
addPixel(doubleSeaPickle, 3, 0, 3, 10, 6, 10, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_2"));
SeaPickle singleSeaPickle = (SeaPickle) Material.SEA_PICKLE.createBlockData();
singleSeaPickle.setWaterlogged(false);
singleSeaPickle.setPickles(1);
addPixel(singleSeaPickle, 6, 0, 6, 4, 6, 4, createItem("LAUFBAU_BLOCK_SEA_PICKLE", Material.SEA_PICKLE, "LAUFBAU_COUNT_1"));
addPixel(Material.FLOWER_POT.createBlockData(), 5, 0, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_FLOWER_POT", Material.FLOWER_POT));
Snow snowLayers3 = (Snow) Material.SNOW.createBlockData();
snowLayers3.setLayers(3);
addPixel(snowLayers3, 0, 0, 0, 16, 4, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_3"));
TrapDoor bottomTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
bottomTrapDoor.setHalf(Bisected.Half.BOTTOM);
addPixel(bottomTrapDoor, 0, 0, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_BOTTOM"));
TrapDoor topTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
topTrapDoor.setHalf(Bisected.Half.TOP);
addPixel(topTrapDoor, 0, 13, 0, 16, 3, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_HALF_TOP"));
Snow snowLayers2 = (Snow) Material.SNOW.createBlockData();
snowLayers2.setLayers(2);
addPixel(snowLayers2, 0, 0, 0, 16, 2, 16, createItem("LAUFBAU_BLOCK_SNOW", Material.SNOW, "LAUFBAU_LAYERS_2"));
addPixel(Material.LILY_PAD.createBlockData(), 1, 0, 1, 14, 1.5, 14, createItem("LAUFBAU_BLOCK_LILY_PAD", Material.LILY_PAD));
addPixel(Material.WHITE_CARPET.createBlockData(), 0, 0, 0, 16, 1, 16, createItem("LAUFBAU_BLOCK_WHITE_CARPET", Material.WHITE_CARPET));
Directional endRodBottomTop = (Directional) Material.END_ROD.createBlockData();
endRodBottomTop.setFacing(BlockFace.UP);
addPixel(endRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
Directional endRodNorthSouth = (Directional) Material.END_ROD.createBlockData();
endRodNorthSouth.setFacing(BlockFace.NORTH);
addPixel(endRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
Directional endRodEastWest = (Directional) Material.END_ROD.createBlockData();
endRodEastWest.setFacing(BlockFace.EAST);
addPixel(endRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_END_ROD", Material.END_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
Directional lightningRodBottomTop = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodBottomTop.setFacing(BlockFace.UP);
addPixel(lightningRodBottomTop, 6, 0, 6, 4, 16, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
Directional lightningRodNorthSouth = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodNorthSouth.setFacing(BlockFace.NORTH);
addPixel(lightningRodNorthSouth, 6, 6, 0, 4, 4, 16, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
Directional lightningRodEastWest = (Directional) Material.LIGHTNING_ROD.createBlockData();
lightningRodEastWest.setFacing(BlockFace.EAST);
addPixel(lightningRodEastWest, 0, 6, 6, 16, 4, 4, createItem("LAUFBAU_BLOCK_LIGHTNING_ROD", Material.LIGHTNING_ROD, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
Waterlogged conduit = (Waterlogged) Material.CONDUIT.createBlockData();
conduit.setWaterlogged(false);
addPixel(conduit, 5, 5, 5, 6, 6, 6, createItem("LAUFBAU_BLOCK_CONDUIT", Material.CONDUIT));
TrapDoor northTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
northTrapDoor.setFacing(BlockFace.NORTH);
northTrapDoor.setOpen(true);
addPixel(northTrapDoor, 0, 0, 13, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_NORTH", "LAUFBAU_OPEN"));
TrapDoor southTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
southTrapDoor.setFacing(BlockFace.SOUTH);
southTrapDoor.setOpen(true);
addPixel(southTrapDoor, 0, 0, 0, 16, 16, 3, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_SOUTH", "LAUFBAU_OPEN"));
TrapDoor westTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
westTrapDoor.setFacing(BlockFace.WEST);
westTrapDoor.setOpen(true);
addPixel(westTrapDoor, 13, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_WEST", "LAUFBAU_OPEN"));
TrapDoor eastTrapDoor = (TrapDoor) Material.IRON_TRAPDOOR.createBlockData();
eastTrapDoor.setFacing(BlockFace.EAST);
eastTrapDoor.setOpen(true);
addPixel(eastTrapDoor, 0, 0, 0, 3, 16, 16, createItem("LAUFBAU_BLOCK_IRON_TRAPDOOR", Material.IRON_TRAPDOOR, "LAUFBAU_FACING_EAST", "LAUFBAU_OPEN"));
}
private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem) {
new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem);
}
private static void addPixel(BlockData blockData, double xPixel, double yPixel, double zPixel, double dxPixel, double dyPixel, double dzPixel, SWItem swItem, Consumer<BaseBlock> blockConsumer) {
new BlockBoundingBox(blockData, Arrays.asList(pixelCuboid(xPixel, yPixel, zPixel, dxPixel, dyPixel, dzPixel)), swItem, blockConsumer);
}
@SuppressWarnings("deprecation")
private static void randomPlayerHead(BaseBlock block) {
if (block instanceof SkullBlock) {
SkullBlock skullBlock = (SkullBlock) block;
skullBlock.setOwner(randomPlayerHead.get(random.nextInt(randomPlayerHead.size())).toString());
}
}
}
@@ -0,0 +1,25 @@
/*
* 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.bausystem.features.slaves.laufbau;
public interface BoundingBoxLoader {
void load();
}
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.slaves.laufbau;
import de.steamwar.bausystem.region.Point;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.bukkit.util.BoundingBox;
@Data
@AllArgsConstructor
@@ -34,15 +33,6 @@ public class Cuboid {
private double dy;
private double dz;
public Cuboid(BoundingBox boundingBox) {
this.x = boundingBox.getMinX();
this.y = boundingBox.getMinY();
this.z = boundingBox.getMinZ();
this.dx = boundingBox.getWidthX();
this.dy = boundingBox.getHeight();
this.dz = boundingBox.getWidthZ();
}
public boolean intersects(Cuboid cuboid) {
double minx = x - cuboid.dx;
double miny = y - cuboid.dy;
@@ -24,52 +24,15 @@ import de.steamwar.bausystem.SWUtils;
import de.steamwar.bausystem.shared.Pair;
import de.steamwar.bausystem.utils.WorldEditUtils;
import de.steamwar.command.SWCommand;
import de.steamwar.inventory.SWItem;
import de.steamwar.linkage.Linked;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.phys.shapes.CollisionContext;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Registry;
import org.bukkit.craftbukkit.block.CraftBlockType;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.util.CraftVoxelShape;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.VoxelShape;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@Linked
public class LaufbauCommand extends SWCommand {
static {
AtomicLong counter = new AtomicLong();
AtomicReference<VoxelShape> shape = new AtomicReference<>();
long time = System.currentTimeMillis();
Registry.BLOCK.forEach(blockType -> {
Block block = CraftBlockType.bukkitToMinecraftNew(blockType);
block.getStateDefinition().getPossibleStates().forEach(blockState -> {
VoxelShape voxelShape = new CraftVoxelShape(blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO, CollisionContext.empty()));
shape.set(voxelShape);
Material material = blockType.asMaterial();
if (!material.isItem()) return;
new BlockBoundingBox(
CraftBlockData.createData(blockState),
voxelShape.getBoundingBoxes().stream().map(Cuboid::new).collect(Collectors.toList()),
new SWItem(material, "Item")
);
counter.incrementAndGet();
});
});
System.out.println(System.currentTimeMillis() - time + "ms " + shape.get() + " " + counter.get());
}
public LaufbauCommand() {
super("laufbau", "laufsklave");
}
@@ -0,0 +1,261 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.AmethystCluster;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class AmethystBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
floorSmallAmethystBud();
ceilingSmallAmethystBud();
northSmallAmethystBud();
southSmallAmethystBud();
eastSmallAmethystBud();
westSmallAmethystBud();
floorMediumAmethystBud();
ceilingMediumAmethystBud();
northMediumAmethystBud();
southMediumAmethystBud();
eastMediumAmethystBud();
westMediumAmethystBud();
floorLargeAmethystBud();
ceilingLargeAmethystBud();
northLargeAmethystBud();
southLargeAmethystBud();
eastLargeAmethystBud();
westLargeAmethystBud();
floorAmethystCluster();
ceilingAmethystCluster();
northAmethystCluster();
southAmethystCluster();
eastAmethystCluster();
westAmethystCluster();
}
private void floorSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 4, 8, 3, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 13, 4, 8, 3, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 13, 8, 8, 3));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 0, 8, 8, 3));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 4, 4, 3, 8, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westSmallAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.SMALL_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(13, 4, 4, 3, 8, 8));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_SMALL_AMETHYST_BUD", Material.SMALL_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 4, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 12, 3, 10, 4, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 12, 10, 10, 4));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 4));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 4, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westMediumAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.MEDIUM_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(12, 3, 3, 4, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_MEDIUM_AMETHYST_BUD", Material.MEDIUM_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 5, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_UP"));
}
private void ceilingLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 11, 3, 10, 5, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_DOWN"));
}
private void northLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 11, 10, 10, 5));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_NORTH"));
}
private void southLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 5));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_SOUTH"));
}
private void eastLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 5, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_EAST"));
}
private void westLargeAmethystBud() {
AmethystCluster cluster = (AmethystCluster) Material.LARGE_AMETHYST_BUD.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(11, 3, 3, 5, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_LARGE_AMETHYST_BUD", Material.LARGE_AMETHYST_BUD, "LAUFBAU_FACING_WEST"));
}
private void floorAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.UP);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 0, 3, 10, 7, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_UP"));
}
private void ceilingAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 9, 3, 10, 7, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_DOWN"));
}
private void northAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 9, 10, 10, 7));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_NORTH"));
}
private void southAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 7));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_SOUTH"));
}
private void eastAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 3, 3, 7, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_EAST"));
}
private void westAmethystCluster() {
AmethystCluster cluster = (AmethystCluster) Material.AMETHYST_CLUSTER.createBlockData();
cluster.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(9, 3, 3, 7, 10, 10));
new BlockBoundingBox(cluster, cuboidList, createItem("LAUFBAU_BLOCK_AMETHYST_CLUSTER", Material.AMETHYST_CLUSTER, "LAUFBAU_FACING_WEST"));
}
}
@@ -0,0 +1,46 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class AzaleaBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.FLOWERING_AZALEA.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(6, 0, 6, 4, 8, 4));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_AZALEA", Material.FLOWERING_AZALEA));
}
}
@@ -0,0 +1,149 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Bell;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class BellBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
ceilingBell();
floorNorthBell();
floorEastBell();
doubleWallNorthBell();
doubleWallEastBell();
singleWallNorthBell();
singleWallSouthBell();
singleWallEastBell();
singleWallWestBell();
}
public void ceilingBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.CEILING);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 7, 2, 3, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_CEILING"));
}
public void floorNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.FLOOR);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 4, 16, 16, 8));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void floorEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.FLOOR);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 0, 8, 16, 16));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void doubleWallNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.DOUBLE_WALL);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 0, 2, 2, 16));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_DOUBLE_WALL", "LAUFBAU_FACING_NORTH"));
}
public void doubleWallEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.DOUBLE_WALL);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(0, 13, 7, 16, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_DOUBLE_WALL", "LAUFBAU_FACING_EAST"));
}
public void singleWallNorthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 0, 2, 2, 13));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_NORTH"));
}
public void singleWallSouthBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(7, 13, 3, 2, 2, 13));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_SOUTH"));
}
public void singleWallEastBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(3, 13, 7, 13, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_EAST"));
}
public void singleWallWestBell() {
Bell bell = (Bell) Material.BELL.createBlockData();
bell.setAttachment(Bell.Attachment.SINGLE_WALL);
bell.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 4, 8, 2, 8));
cuboidList.add(pixelCuboid(5, 6, 5, 6, 8, 6));
cuboidList.add(pixelCuboid(0, 13, 7, 13, 2, 2));
new BlockBoundingBox(bell, cuboidList, createItem("LAUFBAU_BLOCK_BELL", Material.BELL, "LAUFBAU_ATTACHMENT_SINGLE_WALL", "LAUFBAU_FACING_WEST"));
}
}
@@ -0,0 +1,46 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.BrewingStand;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class BrewingStandBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BrewingStand brewingStand = (BrewingStand) Material.BREWING_STAND.createBlockData();
List<Cuboid> cuboids = new ArrayList<>();
cuboids.add(pixelCuboid(1, 0, 1, 14, 2, 14));
cuboids.add(pixelCuboid(7, 2, 7, 2, 12, 2));
new BlockBoundingBox(brewingStand, cuboids, createItem("LAUFBAU_BLOCK_BREWING_STAND", Material.BREWING_STAND));
}
}
@@ -0,0 +1,62 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.Lightable;
import org.bukkit.block.data.type.Candle;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class CandleBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
caked();
single();
}
private void caked() {
Lightable candleCake = (Lightable) Material.CYAN_CANDLE_CAKE.createBlockData();
candleCake.setLit(true);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(7, 8, 7, 2, 6, 2));
new BlockBoundingBox(candleCake, cuboidList, createItem("LAUFBAU_BLOCK_CANDLE_CAKE", Material.CAKE));
}
private void single() {
Candle candle = (Candle) Material.CYAN_CANDLE.createBlockData();
candle.setCandles(1);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(7, 0, 7, 2, 6, 2));
new BlockBoundingBox(candle, cuboidList, createItem("LAUFBAU_BLOCK_CANDLE", Material.CYAN_CANDLE, "LAUFBAU_COUNT_1"));
}
}
@@ -0,0 +1,69 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Axis;
import org.bukkit.Material;
import org.bukkit.block.data.Orientable;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class ChainBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
bottomTopChain();
northSouthChain();
eastWestChain();
}
private void bottomTopChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.Y);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6.5, 0, 6.5, 3, 16, 3));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_UP", "LAUFBAU_FACING_DOWN"));
}
private void northSouthChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.Z);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6.5, 6.5, 0, 3, 3, 16));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
private void eastWestChain() {
Orientable chainBottomTop = (Orientable) Material.CHAIN.createBlockData();
chainBottomTop.setAxis(Axis.X);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 6.5, 6.5, 16, 3, 3));
new BlockBoundingBox(chainBottomTop, cuboidList, createItem("LAUFBAU_BLOCK_CHAIN", Material.CHAIN, "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
}
@@ -0,0 +1,89 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.MultipleFacing;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class ChorusPlantBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int ny = 0; ny < 2; ny++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int py = 0; py < 2; py++) {
for (int pz = 0; pz < 2; pz++) {
MultipleFacing chorusPlant = (MultipleFacing) Material.CHORUS_PLANT.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(3, 3, 3, 10, 10, 10));
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
chorusPlant.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 3, 3, 3, 10, 10));
}
if (ny == 1) {
lore.add("LAUFBAU_CONNECTION_DOWN");
chorusPlant.setFace(BlockFace.DOWN, true);
cuboidList.add(pixelCuboid(3, 0, 3, 10, 3, 10));
}
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
chorusPlant.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(3, 3, 0, 10, 10, 3));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
chorusPlant.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(13, 3, 3, 3, 10, 10));
}
if (py == 1) {
lore.add("LAUFBAU_CONNECTION_UP");
chorusPlant.setFace(BlockFace.UP, true);
cuboidList.add(pixelCuboid(3, 13, 3, 10, 3, 10));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
chorusPlant.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(3, 3, 13, 10, 10, 3));
}
new BlockBoundingBox(chorusPlant, cuboidList, createItem("LAUFBAU_BLOCK_CHORUS_PLANT", Material.CHORUS_PLANT, lore.toArray(new String[0])));
}
}
}
}
}
}
}
}
@@ -0,0 +1,45 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class DragonEggBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.DRAGON_EGG.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(1, 0, 1, 14, 16, 14));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_DRAGON_EGG", Material.DRAGON_EGG));
}
}
@@ -0,0 +1,59 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.BigDripleaf;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class DripLeafBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
tiltNone();
tiltPartial();
}
private void tiltNone() {
BigDripleaf bigDripleaf = (BigDripleaf) Material.BIG_DRIPLEAF.createBlockData();
bigDripleaf.setTilt(BigDripleaf.Tilt.NONE);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 11, 0, 16, 4, 16));
new BlockBoundingBox(bigDripleaf, cuboidList, createItem("LAUFBAU_BLOCK_BIG_DRIP_LEAF", Material.BIG_DRIPLEAF, "LAUFBAU_TILT_NONE"));
}
private void tiltPartial() {
BigDripleaf bigDripleaf = (BigDripleaf) Material.BIG_DRIPLEAF.createBlockData();
bigDripleaf.setTilt(BigDripleaf.Tilt.PARTIAL);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 11, 0, 16, 2, 16));
new BlockBoundingBox(bigDripleaf, cuboidList, createItem("LAUFBAU_BLOCK_BIG_DRIP_LEAF", Material.BIG_DRIPLEAF, "LAUFBAU_TILT_PARTIAL"));
}
}
@@ -0,0 +1,75 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Fence;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class FencesBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Fence fence = (Fence) Material.NETHER_BRICK_FENCE.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(6, 0, 6, 4, 24, 4));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(6, 0, 0, 4, 24, 6));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(6, 0, 10, 4, 24, 6));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 0, 6, 6, 24, 4));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(10, 0, 6, 6, 24, 4));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_NETHER_BRICK_FENCE", Material.NETHER_BRICK_FENCE, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -0,0 +1,157 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.FaceAttachable;
import org.bukkit.block.data.type.Grindstone;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class GrindstoneBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
floorNorthGrindstone();
floorEastGrindstone();
ceilingNorthGrindstone();
ceilingEastGrindstone();
wallNorthGrindstone();
wallSouthGrindstone();
wallEastGrindstone();
wallWestGrindstone();
}
public void floorNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.FLOOR);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 4, 2, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 0, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(12, 0, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(2, 7, 5, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 7, 5, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void floorEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.FLOOR);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(2, 4, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(6, 0, 2, 4, 7, 2));
cuboidList.add(pixelCuboid(6, 0, 12, 4, 7, 2));
cuboidList.add(pixelCuboid(5, 7, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(5, 7, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_FLOOR", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void ceilingNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.CEILING);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 2, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 9, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(12, 9, 6, 2, 7, 4));
cuboidList.add(pixelCuboid(2, 3, 5, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 3, 5, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_CEILING", "LAUFBAU_FACING_NORTH", "LAUFBAU_FACING_SOUTH"));
}
public void ceilingEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.CEILING);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(2, 0, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(6, 9, 2, 4, 7, 2));
cuboidList.add(pixelCuboid(6, 9, 12, 4, 7, 2));
cuboidList.add(pixelCuboid(5, 3, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(5, 3, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_CEILING", "LAUFBAU_FACING_EAST", "LAUFBAU_FACING_WEST"));
}
public void wallNorthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 0, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 6, 9, 2, 4, 7));
cuboidList.add(pixelCuboid(12, 6, 9, 2, 4, 7));
cuboidList.add(pixelCuboid(2, 5, 3, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 5, 3, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_NORTH"));
}
public void wallSouthGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 4, 8, 12, 12));
cuboidList.add(pixelCuboid(2, 6, 0, 2, 4, 7));
cuboidList.add(pixelCuboid(12, 6, 0, 2, 4, 7));
cuboidList.add(pixelCuboid(2, 5, 7, 2, 6, 6));
cuboidList.add(pixelCuboid(12, 5, 7, 2, 6, 6));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_SOUTH"));
}
public void wallEastGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 2, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(0, 6, 2, 7, 4, 2));
cuboidList.add(pixelCuboid(0, 6, 12, 7, 4, 2));
cuboidList.add(pixelCuboid(7, 5, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(7, 5, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_EAST"));
}
public void wallWestGrindstone() {
Grindstone grindstone = (Grindstone) Material.GRINDSTONE.createBlockData();
grindstone.setAttachedFace(FaceAttachable.AttachedFace.WALL);
grindstone.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 2, 4, 12, 12, 8));
cuboidList.add(pixelCuboid(9, 6, 2, 7, 4, 2));
cuboidList.add(pixelCuboid(9, 6, 12, 7, 4, 2));
cuboidList.add(pixelCuboid(3, 5, 2, 6, 6, 2));
cuboidList.add(pixelCuboid(3, 5, 12, 6, 6, 2));
new BlockBoundingBox(grindstone, cuboidList, createItem("LAUFBAU_BLOCK_GRINDSTONE", Material.GRINDSTONE, "LAUFBAU_ATTACHMENT_WALL", "LAUFBAU_FACING_WEST"));
}
}
@@ -0,0 +1,97 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Hopper;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class HopperBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
downHopper();
northHopper();
southHopper();
eastHopper();
westHopper();
}
public void downHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.DOWN);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 0, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_FLOOR"));
}
public void northHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 4, 0, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_NORTH"));
}
public void southHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(6, 4, 12, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_SOUTH"));
}
public void eastHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(12, 4, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_EAST"));
}
public void westHopper() {
Hopper hopper = (Hopper) Material.HOPPER.createBlockData();
hopper.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 10, 0, 16, 6, 16));
cuboidList.add(pixelCuboid(4, 4, 4, 8, 6, 8));
cuboidList.add(pixelCuboid(0, 4, 6, 4, 4, 4));
new BlockBoundingBox(hopper, cuboidList, createItem("LAUFBAU_BLOCK_HOPPER", Material.HOPPER, "LAUFBAU_CONNECTION_WEST"));
}
}
@@ -0,0 +1,75 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Fence;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class IronBarBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Fence fence = (Fence) Material.IRON_BARS.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(7, 0, 7, 2, 16, 2));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setFace(BlockFace.NORTH, true);
cuboidList.add(pixelCuboid(7, 0, 0, 2, 16, 7));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setFace(BlockFace.SOUTH, true);
cuboidList.add(pixelCuboid(7, 0, 9, 2, 16, 7));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setFace(BlockFace.WEST, true);
cuboidList.add(pixelCuboid(0, 0, 7, 7, 16, 2));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setFace(BlockFace.EAST, true);
cuboidList.add(pixelCuboid(9, 0, 7, 7, 16, 2));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_IRON_BARS", Material.IRON_BARS, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -0,0 +1,61 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.type.Lantern;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class LanternBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
lantern();
hangingLantern();
}
public void lantern() {
Lantern lantern = (Lantern) Material.LANTERN.createBlockData();
lantern.setHanging(false);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(5, 0, 5, 6, 7, 6));
cuboidList.add(pixelCuboid(6, 7, 6, 4, 2, 4));
new BlockBoundingBox(lantern, cuboidList, createItem("LAUFBAU_BLOCK_LANTERN", Material.LANTERN));
}
public void hangingLantern() {
Lantern lantern = (Lantern) Material.LANTERN.createBlockData();
lantern.setHanging(true);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(5, 1, 5, 6, 7, 6));
cuboidList.add(pixelCuboid(6, 8, 6, 4, 2, 4));
new BlockBoundingBox(lantern, cuboidList, createItem("LAUFBAU_BLOCK_LANTERN", Material.LANTERN, "LAUFBAU_HANGING"));
}
}
@@ -0,0 +1,46 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class LecternBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
BlockData blockData = Material.LECTERN.createBlockData();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 2, 16));
cuboidList.add(pixelCuboid(4, 2, 4, 8, 12, 8));
new BlockBoundingBox(blockData, cuboidList, createItem("LAUFBAU_BLOCK_LECTERN", Material.LECTERN));
}
}
@@ -0,0 +1,343 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Stairs;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class StairBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
straightBottomNorthStair();
straightBottomSouthStair();
straightBottomEastStair();
straightBottomWestStair();
straightTopNorthStair();
straightTopSouthStair();
straightTopEastStair();
straightTopWestStair();
outerLeftBottomNorthStair();
outerLeftBottomSouthStair();
outerLeftBottomEastStair();
outerLeftBottomWestStair();
outerLeftTopNorthStair();
outerLeftTopSouthStair();
outerLeftTopEastStair();
outerLeftTopWestStair();
innerLeftBottomNorthStair();
innerLeftBottomSouthStair();
innerLeftBottomEastStair();
innerLeftBottomWestStair();
innerLeftTopNorthStair();
innerLeftTopSouthStair();
innerLeftTopEastStair();
innerLeftTopWestStair();
}
public void straightBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void straightBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void straightBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void straightBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void straightTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void straightTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void straightTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void straightTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.STRAIGHT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 16));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_STRAIGHT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
public void outerLeftBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void outerLeftBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void outerLeftBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void outerLeftBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void outerLeftTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void outerLeftTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void outerLeftTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void outerLeftTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.OUTER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_OUTER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
public void innerLeftBottomNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_NORTH"));
}
public void innerLeftBottomSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_SOUTH"));
}
public void innerLeftBottomEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 8, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_EAST"));
}
public void innerLeftBottomWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.BOTTOM);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 8, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 8, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_BOTTOM", "LAUFBAU_FACING_WEST"));
}
public void innerLeftTopNorthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.NORTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_NORTH"));
}
public void innerLeftTopSouthStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.SOUTH);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_SOUTH"));
}
public void innerLeftTopEastStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.EAST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 0, 16, 8, 8));
cuboidList.add(pixelCuboid(8, 0, 8, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_EAST"));
}
public void innerLeftTopWestStair() {
Stairs stairs = (Stairs) Material.END_STONE_BRICK_STAIRS.createBlockData();
stairs.setShape(Stairs.Shape.INNER_LEFT);
stairs.setHalf(Stairs.Half.TOP);
stairs.setFacing(BlockFace.WEST);
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(0, 8, 0, 16, 8, 16));
cuboidList.add(pixelCuboid(0, 0, 8, 16, 8, 8));
cuboidList.add(pixelCuboid(0, 0, 0, 8, 8, 8));
new BlockBoundingBox(stairs, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_STAIRS", Material.END_STONE_BRICK_STAIRS, "LAUFBAU_SHAPE_INNER_LEFT", "LAUFBAU_HALF_TOP", "LAUFBAU_FACING_WEST"));
}
}
@@ -0,0 +1,79 @@
/*
* 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.bausystem.features.slaves.laufbau.boundingboxes;
import de.steamwar.bausystem.features.slaves.laufbau.BlockBoundingBox;
import de.steamwar.bausystem.features.slaves.laufbau.BoundingBoxLoader;
import de.steamwar.bausystem.features.slaves.laufbau.Cuboid;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.type.Wall;
import java.util.ArrayList;
import java.util.List;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.createItem;
import static de.steamwar.bausystem.features.slaves.laufbau.LaufbauUtils.pixelCuboid;
@Linked
public class WallBoundingBox implements BoundingBoxLoader {
@Override
public void load() {
v18();
}
private void v18() {
for (int nx = 0; nx < 2; nx++) {
for (int nz = 0; nz < 2; nz++) {
for (int px = 0; px < 2; px++) {
for (int pz = 0; pz < 2; pz++) {
Wall fence = (Wall) Material.END_STONE_BRICK_WALL.createBlockData();
List<String> lore = new ArrayList<>();
List<Cuboid> cuboidList = new ArrayList<>();
cuboidList.add(pixelCuboid(4, 0, 4, 8, 24, 8));
if (nz == 1) {
lore.add("LAUFBAU_CONNECTION_NORTH");
fence.setHeight(BlockFace.NORTH, Wall.Height.LOW);
cuboidList.add(pixelCuboid(5, 0, 0, 6, 24, 4));
}
if (pz == 1) {
lore.add("LAUFBAU_CONNECTION_SOUTH");
fence.setHeight(BlockFace.SOUTH, Wall.Height.LOW);
cuboidList.add(pixelCuboid(5, 0, 12, 6, 24, 4));
}
if (nx == 1) {
lore.add("LAUFBAU_CONNECTION_WEST");
fence.setHeight(BlockFace.WEST, Wall.Height.LOW);
cuboidList.add(pixelCuboid(0, 0, 5, 4, 24, 6));
}
if (px == 1) {
lore.add("LAUFBAU_CONNECTION_EAST");
fence.setHeight(BlockFace.EAST, Wall.Height.LOW);
cuboidList.add(pixelCuboid(12, 0, 5, 4, 24, 6));
}
new BlockBoundingBox(fence, cuboidList, createItem("LAUFBAU_BLOCK_END_STONE_BRICK_WALL", Material.END_STONE_BRICK_WALL, lore.toArray(new String[0])));
}
}
}
}
}
}
@@ -165,6 +165,7 @@ public class TPSSystem implements Listener {
}
@Register(value = "default", description = "TPSLIMIT_DEFAULT_HELP")
@Register(value = "rate")
public void reset(@Validator Player player) {
TickManager.impl.setTickRate(20.0F);
sendTickRateChange();
@@ -187,15 +188,18 @@ public class TPSSystem implements Listener {
}
@Register(value = {"rate", "0"}, description = "TICK_FREEZE_HELP")
@Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
public void freeze(@Validator Player player) {
public void rate(@Validator Player player) {
TickManager.impl.setFreeze(true);
sendTickRateChange();
}
@Register(value = "unfreeze", description = "TICK_UNFREEZE_HELP")
public void unfreeze(@Validator Player player) {
TickManager.impl.setTickRate(20.0F);
@Register(value = "freeze", description = "TICK_FREEZE_HELP_2")
public void freezeToggle(@Validator Player player) {
if (TickManager.impl.isFrozen()) {
TickManager.impl.setTickRate(20.0F);
} else {
TickManager.impl.setFreeze(true);
}
sendTickRateChange();
}
}
@@ -153,7 +153,11 @@ public class TraceCommand extends SWCommand {
@Register(value = "isolate", description = "TRACE_COMMAND_HELP_ISOLATE")
public void isolate(@Validator Player player, Trace trace, @ErrorMessage("TRACE_RECORD_ID_INVALID") TNTPoint... records) {
TraceManager.instance.isolate(player, records);
if (records.length == 0) {
TraceManager.instance.isolate(player, trace, trace.getRecords().toArray(TNTPoint[]::new));
} else {
TraceManager.instance.isolate(player, trace, records);
}
BauSystem.MESSAGE.send("TRACE_MESSAGE_ISOLATE", player);
}
@@ -347,9 +347,10 @@ public class TraceManager implements Listener {
* Toggles the isolated render for the given records and player
*
* @param player the player the trace is shown to
* @param records the record for which isolation is toggled
* @param ptrace the trace for whitch isolation is toggled
* @param records the records of the trace for which isolation is toggled
*/
public void isolate(Player player, TNTPoint... records) {
public void isolate(Player player, Trace ptrace, TNTPoint... records) {
unfollow(player);
Region region = Region.getRegion(player.getLocation());
@@ -374,12 +375,20 @@ public class TraceManager implements Listener {
isolateFlag.toggleId(record.getTntId());
}
if (isolateFlag.isEmpty() && playerTraceShowData.hasViewFlagOnly(IsolateFlag.class) && records.length != 0) {
playerTraceShowData.removeViewFlag(IsolateFlag.class);
}
PlayerTraceShowData finalPlayerTraceShowData = playerTraceShowData;
tracesByRegion.getOrDefault(region, Collections.emptyMap()).forEach((integer, trace) -> {
trace.render(player, finalPlayerTraceShowData);
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
trace.render(follower, finalPlayerTraceShowData);
});
if (trace.getUuid() == ptrace.getUuid() || finalPlayerTraceShowData.hasNoViewFlags()) {
trace.render(player, finalPlayerTraceShowData);
followerMap.getOrDefault(player, Collections.emptySet()).forEach(follower -> {
trace.render(follower, finalPlayerTraceShowData);
});
} else {
trace.hide(player);
}
});
}
@@ -135,6 +135,13 @@ public class TraceRecorder implements Listener {
Iterator<TNTPrimed> iter = trackedTNT.getOrDefault(region, Collections.emptyList()).iterator();
while (iter.hasNext()) {
TNTPrimed tnt = iter.next();
if (tnt.isDead()) {
iter.remove();
tntSpawnRegion.remove(tnt);
historyMap.remove(tnt);
tntSpawnRegion.remove(tnt);
continue;
}
if (tnt.getFuseTicks() == 80) continue;
TNTPoint record = record(tnt, wrappedTrace, Collections.emptyList());
if (record == null) {
@@ -95,4 +95,8 @@ public class PlayerTraceShowData {
public void addViewFlag(ViewFlag viewFlag) {
viewFlags.put(viewFlag.getClass(), viewFlag);
}
public <T extends ViewFlag> void removeViewFlag(Class<T> clazz) {
viewFlags.remove(clazz);
}
}
@@ -48,9 +48,9 @@ import static de.steamwar.bausystem.features.util.TNTClickListener.TNT_CLICK_DET
*/
public class TraceEntity extends RBlockDisplay {
private static final float TNT_VISUAL_SCALE = 0.98F;
private static final float TNT_VISUAL_OFFSET = -TNT_VISUAL_SCALE / 2.0F;
private static final Transformation TNT_VISUAL_TRANSFORM = new Transformation(
public static final float TNT_VISUAL_SCALE = 0.98F;
public static final float TNT_VISUAL_OFFSET = -TNT_VISUAL_SCALE / 2.0F;
public static final Transformation TNT_VISUAL_TRANSFORM = new Transformation(
new Vector3f(TNT_VISUAL_OFFSET, 0.0F, TNT_VISUAL_OFFSET),
new Quaternionf(0, 0, 0, 1),
new Vector3f(TNT_VISUAL_SCALE, TNT_VISUAL_SCALE, TNT_VISUAL_SCALE),
@@ -131,6 +131,7 @@ public abstract class ViewFlag {
if (yLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && yLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
RBlockDisplay y = new RBlockDisplay(server, yLocation);
y.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
y.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
}
Location secoundLocation;
@@ -143,6 +144,7 @@ public abstract class ViewFlag {
if (secoundLocation.distanceSquared(representative.getLocation()) >= 1.0 / 256.0 && secoundLocation.distanceSquared(previous.getLocation()) >= 1.0 / 256.0) {
RBlockDisplay second = new RBlockDisplay(server, secoundLocation);
second.setBlock(Material.WHITE_STAINED_GLASS.createBlockData());
second.setTransform(TraceEntity.TNT_VISUAL_TRANSFORM);
}
}
}
@@ -51,6 +51,10 @@ public class IsolateFlag extends ViewFlag {
}
}
public boolean isEmpty() {
return tntToIsolate.isEmpty();
}
@Override
public Stream<TNTPoint> filter(Stream<TNTPoint> records) {
if (tntToIsolate.isEmpty()) return records;
@@ -53,7 +53,7 @@ public class NoClipCommand extends SWCommand implements Listener {
@Override
public void onUnmount(SWPlayer player) {
player.setGameMode(GameMode.CREATIVE);
player.getPlayer().setGameMode(GameMode.CREATIVE);
}
}
@@ -115,6 +115,7 @@ public class NoClipCommand extends SWCommand implements Listener {
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
abilities.mayBuild = true;
abilities.mayfly = true;
abilities.instabuild = true;
swPlayer.setComponent(new NoClipData());
BauSystem.MESSAGE.send("OTHER_NOCLIP_SLOT_INFO", player);
@@ -139,6 +140,7 @@ public class NoClipCommand extends SWCommand implements Listener {
@EventHandler(ignoreCancelled = true)
public void onBlock(BlockCanBuildEvent event) {
if (event.getPlayer() == null) return;
if (SWPlayer.of(event.getPlayer()).hasComponent(NoClipData.class)) {
event.setBuildable(true);
}
@@ -0,0 +1,41 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.bausystem.features.world;
import de.steamwar.linkage.Linked;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.scoreboard.Scoreboard;
import org.bukkit.scoreboard.Team;
@Linked
public class AntiPlayerCollision implements Listener {
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerJoin(PlayerJoinEvent event) {
Scoreboard board = event.getPlayer().getScoreboard();
Team team = board.getTeam("players");
if (team == null) team = board.registerNewTeam("players");
team.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
team.addPlayer(event.getPlayer());
}
}
@@ -131,6 +131,7 @@ public class BauScoreboard implements Listener {
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
SWScoreboard.impl.removeScoreboard(event.getPlayer());
ADDITIONAL_SCOREBOARD_LINES.remove(event.getPlayer());
}
}
@@ -57,7 +57,7 @@ public class WorldEditListener implements Listener {
private static final Set<String> commands = new HashSet<>();
private static final Set<String> commandExclusions = new HashSet<>();
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r"};
private static final String[] shortcutCommands = {"//1", "//2", "//90", "//-90", "//180", "//p", "//c", "//flopy", "//floppy", "//flopyp", "//floppyp", "//u", "//r", "//download", "/download"};
public static boolean isWorldEditCommand(String command) {
for (String shortcut : shortcutCommands) {
@@ -325,7 +325,7 @@ public class FixedRegion implements Region {
}
floorLevel = prototype.getFloorOffset() != 0 ? minPoint.getY() + prototype.getFloorOffset() : 0;
waterLevel = prototype.getWaterOffset() != 0 ? minPoint.getX() + prototype.getWaterOffset() : 0;
waterLevel = prototype.getWaterOffset() != 0 ? minPoint.getY() + prototype.getWaterOffset() : 0;
File found = null;
File baseFile = new File(BauSystem.getInstance().getDataFolder().getParentFile(), "FightSystem");
+1
View File
@@ -18,6 +18,7 @@ dependencies {
implementation("com.github.ajalt.clikt:clikt:5.0.3")
implementation("com.github.ajalt.mordant:mordant:3.0.2")
implementation(libs.logback)
implementation("org.yaml:snakeyaml:2.2")
implementation("org.mariadb.jdbc:mariadb-java-client:3.3.1")
implementation(libs.exposedCore)
+18 -5
View File
@@ -7,6 +7,7 @@ import com.github.ajalt.mordant.rendering.TextColors
import com.github.ajalt.mordant.rendering.TextStyles
import de.steamwar.db.Database
import de.steamwar.db.execute
import de.steamwar.db.executeScript
import de.steamwar.db.useDb
import java.io.File
@@ -22,13 +23,25 @@ class ResetCommand : CliktCommand() {
val schema = schemaFile.readText()
val tables = execute("SHOW TABLES;") { it.getString(1) }
for (table in tables) {
execute("DROP TABLE IF EXISTS $table;") { }
execute("SET FOREIGN_KEY_CHECKS=0;") { }
val databaseObjects = execute("SHOW FULL TABLES;") { it.getString(1) to it.getString(2) }
for (view in databaseObjects.filter { it.second == "VIEW" }.map { it.first }) {
execute("DROP VIEW IF EXISTS `${view.replace("`", "``")}`;") { }
}
for (table in databaseObjects.filter { it.second == "BASE TABLE" }.map { it.first }) {
execute("DROP TABLE IF EXISTS `${table.replace("`", "``")}`;") { }
}
execute(schema) { }
executeScript(schema)
val seed = javaClass.getResource("/db/reset-seed.sql")
?: throw CliktError("Reset seed file not found!")
executeScript(seed.readText())
execute("SET FOREIGN_KEY_CHECKS=1;") { }
echo(TextColors.brightGreen(TextStyles.bold("Database reset!")))
}
}
}
+90 -14
View File
@@ -14,9 +14,11 @@ import com.github.ajalt.clikt.parameters.types.file
import com.github.ajalt.clikt.parameters.types.long
import com.github.ajalt.clikt.parameters.types.path
import com.sun.security.auth.module.UnixSystem
import org.yaml.snakeyaml.Yaml
import java.io.File
import kotlin.io.path.absolute
import kotlin.io.path.absolutePathString
import kotlin.random.Random
const val LOG4J_CONFIG = """<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN" packages="com.mojang.util">
@@ -69,35 +71,47 @@ class DevCommand : CliktCommand("dev") {
override fun run() {
val args = mutableListOf<String>()
val serverDirectory = File(workingDir, server)
val serverDir =
if (serverDirectory.exists() && serverDirectory.isDirectory) serverDirectory else File(workingDir, server)
var serverDir = resolveServerDirectory(server)
if (isVelocity(server)) {
runServer(
args, jvmArgs, listOf(
jar?.absolutePath
?: File("/jar/Velocity.jar").absolutePath
?: File("/jars/Velocity.jar").absolutePath
), serverDir
)
} else {
setLogConfig(args)
val version = findVersion(server)
?: throw CliktError("Unknown Server Version")
val gameModeTemplate = if (serverDir.isDirectory) null else loadGameModeTemplate(server)
if (gameModeTemplate != null) {
serverDir = gameModeTemplate.serverDir
args += "-Dconfig=$server.yml"
}
val worldFile = world?.absolute()?.toFile()
?: File(serverDir, "devtempworld")
val jarFile = jar?.absolutePath
?: File(workingDir, "devtempworld")
var jarFile = jar?.absolutePath
?: additionalVersions[server]?.let { supportedVersionJars[it] }
?: supportedVersionJars[version]
?: throw CliktError("Unknown Server Version")
if (gameModeTemplate != null) {
jarFile = if (gameModeTemplate.spigot) {
jarFile.replace("paper", "spigot")
} else {
jarFile.replace("spigot", "paper")
}
}
if (!worldFile.exists()) {
val templateFile = File(serverDir, "Bauwelt")
val templateFile = gameModeTemplate?.worldTemplate ?: File(serverDir, "Bauwelt")
if (!templateFile.exists()) {
throw CliktError("World Template not found!")
throw CliktError("Could not find world template: ${templateFile.absolutePath}")
}
worldFile.parentFile?.mkdirs()
templateFile.copyRecursively(worldFile)
}
val worldDir = worldFile.parentFile ?: workingDir
val devFile = File("/configs/DevServer/${System.getProperty("user.name")}.$port.$version")
if (System.getProperty("user.name") != "minecraft") {
@@ -108,10 +122,11 @@ class DevCommand : CliktCommand("dev") {
args, jvmArgs, listOf(
jarFile,
*(if (forceUpgrade) arrayOf("-forceUpgrade") else arrayOf()),
"--log-strip-color",
"--port", port.toString(),
"--level-name", worldFile.name,
"--world-dir", workingDir.absolutePath,
"--nogui",
"--world-dir", worldDir.absolutePath,
"nogui",
*(if (plugins != null) arrayOf("--plugins", plugins!!.absolutePathString()) else arrayOf())
), serverDir
)
@@ -123,6 +138,12 @@ class DevCommand : CliktCommand("dev") {
}
}
data class GameModeTemplate(
val serverDir: File,
val worldTemplate: File,
val spigot: Boolean
)
val jvmDefaultParams = arrayOf(
"-Xmx1G",
"-Xgc:excessiveGCratio=80",
@@ -138,6 +159,16 @@ class DevCommand : CliktCommand("dev") {
val jvmArgOverrides = arrayOf("--add-opens", "java.base/jdk.internal.misc=ALL-UNNAMED")
val jvmNonJava8Params = arrayOf(
*jvmArgOverrides,
"-XX:-CRIUSecProvider"
)
val extendedStartupParams = arrayOf(
"-Dpaper.disablePluginRemapping=true",
"-javaagent:/jars/AccessWidener.jar=start"
)
val supportedVersionJars = mapOf(
8 to "/jars/paper-1.8.8.jar",
9 to "/jars/spigot-1.9.4.jar",
@@ -165,6 +196,41 @@ class DevCommand : CliktCommand("dev") {
fun isVelocity(server: String): Boolean =
server.endsWith("Velocity")
fun resolveServerDirectory(server: String): File {
val localServer = File(workingDir, server)
if (localServer.isDirectory) {
return localServer
}
return File("/servers", server)
}
fun loadGameModeTemplate(server: String): GameModeTemplate? {
val configFile = File("/configs/GameModes/$server.yml")
if (!configFile.exists()) {
throw CliktError("Server/GameMode not found")
}
val document = configFile.reader().use { reader ->
Yaml().load<Map<String, Any?>>(reader)
} ?: throw CliktError("GameMode config is empty: ${configFile.absolutePath}")
val serverConfig = document["Server"] as? Map<*, *>
?: throw CliktError("GameMode config is missing Server section: ${configFile.absolutePath}")
val folder = serverConfig["Folder"] as? String
?: throw CliktError("GameMode config is missing Server.Folder: ${configFile.absolutePath}")
val maps = (serverConfig["Maps"] as? List<*>)
?.filterIsInstance<String>()
?.takeIf { it.isNotEmpty() }
?: throw CliktError("GameMode config is missing Server.Maps: ${configFile.absolutePath}")
val serverDir = File("/servers", folder)
val worldTemplate = File(File(serverDir, "arenas"), maps[Random.nextInt(maps.size)])
return GameModeTemplate(
serverDir = serverDir,
worldTemplate = worldTemplate,
spigot = serverConfig["Spigot"] == true
)
}
fun setLogConfig(args: MutableList<String>) {
args += "-DlogPath=${workingDir.absolutePath}/logs"
args += "-Dlog4j.configurationFile=${log4jConfig.absolutePath}"
@@ -175,13 +241,23 @@ class DevCommand : CliktCommand("dev") {
}
fun runServer(args: List<String>, jvmArgs: List<String>, cmd: List<String>, serverDir: File) {
val effectiveJvmArgs = mutableListOf<String>()
effectiveJvmArgs += jvmArgs
if (!isVelocity(server)) {
extendedStartupParams.forEach { arg ->
if (effectiveJvmArgs.none { it == arg }) {
effectiveJvmArgs += arg
}
}
}
val process = ProcessBuilder(
jvm?.absolutePath
?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "java",
*jvmArgs.toTypedArray(),
?: if (isJava8(server)) "/usr/lib/jvm/openj9-8/bin/java" else "/usr/lib/jvm/openj9-21/bin/java",
*effectiveJvmArgs.toTypedArray(),
*args.toTypedArray(),
*jvmDefaultParams,
*(if (isJava8(server)) arrayOf() else jvmArgOverrides),
*(if (isJava8(server)) arrayOf() else jvmNonJava8Params),
*(if (profile) arrayOf("-javaagent:/jars/LixfelsProfiler.jar=start") else arrayOf()),
"-Xshareclasses:nonfatal,name=$server",
"-jar",
@@ -190,4 +266,4 @@ class DevCommand : CliktCommand("dev") {
Runtime.getRuntime().addShutdownHook(Thread { if (process.isAlive) process.destroyForcibly() })
process.waitFor()
}
}
}
+120 -9
View File
@@ -16,15 +16,14 @@ import java.sql.ResultSet
import java.util.*
object Database {
lateinit var host: String
lateinit var port: String
lateinit var database: String
val host: String
val port: String
val database: String
val username: String
val password: String
lateinit var db: Database
fun ensureConnected() {
if (::db.isInitialized) {
return
}
init {
val config = File(System.getProperty("user.home"), "mysql.properties")
if (!config.exists()) {
@@ -38,9 +37,14 @@ object Database {
host = props.getProperty("host")
port = props.getProperty("port")
database = props.getProperty("database")
username = props.getProperty("user")
password = props.getProperty("password")
}
val username = props.getProperty("user")
val password = props.getProperty("password")
fun ensureConnected() {
if (::db.isInitialized) {
return
}
val url = "jdbc:mariadb://$host:$port/$database"
@@ -79,6 +83,113 @@ fun <T> JdbcTransaction.executeSingle(sql: String, transform: (ResultSet) -> T):
}.single()
}
fun JdbcTransaction.executeScript(sql: String) {
for (statement in splitSqlScript(sql)) {
exec(statement) { }
}
}
private fun splitSqlScript(sql: String): List<String> {
val statements = mutableListOf<String>()
val current = StringBuilder()
var quote: Char? = null
var inLineComment = false
var inBlockComment = false
var index = 0
fun addStatement() {
val statement = current.toString().trim()
if (statement.isNotEmpty()) {
statements += statement
}
current.clear()
}
while (index < sql.length) {
val char = sql[index]
val next = sql.getOrNull(index + 1)
if (inLineComment) {
current.append(char)
if (char == '\n') {
inLineComment = false
}
index++
continue
}
if (inBlockComment) {
current.append(char)
if (char == '*' && next == '/') {
current.append(next)
inBlockComment = false
index += 2
} else {
index++
}
continue
}
if (quote != null) {
current.append(char)
if (char == '\\' && quote != '`' && next != null) {
current.append(next)
index += 2
continue
}
if (char == quote) {
if (next == quote) {
current.append(next)
index += 2
continue
}
quote = null
}
index++
continue
}
when {
char == '-' && next == '-' -> {
current.append(char).append(next)
inLineComment = true
index += 2
}
char == '#' -> {
current.append(char)
inLineComment = true
index++
}
char == '/' && next == '*' -> {
current.append(char).append(next)
inBlockComment = true
index += 2
}
char == '\'' || char == '"' || char == '`' -> {
current.append(char)
quote = char
index++
}
char == ';' -> {
addStatement()
index++
}
else -> {
current.append(char)
index++
}
}
}
addStatement()
return statements
}
fun useDb(statement: JdbcTransaction.() -> Unit) {
de.steamwar.db.Database.ensureConnected()
transaction(de.steamwar.db.Database.db, statement = statement)
File diff suppressed because one or more lines are too long
+5
View File
@@ -19,6 +19,7 @@
plugins {
steamwar.kotlin
kotlin("plugin.lombok")
}
kotlin {
@@ -40,4 +41,8 @@ dependencies {
compileOnlyApi(libs.exposedDao)
compileOnlyApi(libs.exposedJdbc)
compileOnlyApi(libs.exposedTime)
testImplementation(kotlin("test"))
}
repositories {
mavenCentral()
}
@@ -86,6 +86,24 @@ class CheckedSchematic(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.seen eq false) }.orderBy(CheckedSchematicTable.endTime to SortOrder.DESC).toList()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") }.count()
}
@JvmStatic
fun countAccepted(owner: SteamwarUser, type: String) =
useDb {
find { (CheckedSchematicTable.nodeOwner eq owner.id) and (CheckedSchematicTable.declineReason eq "freigegeben") and (CheckedSchematicTable.nodeType like "$type%") }.count()
}
@JvmStatic
fun countChecked(validator: SteamwarUser) =
useDb {
find { CheckedSchematicTable.validator eq validator.id }.count()
}
}
val node by CheckedSchematicTable.nodeId.transform({ it?.let { EntityID(it, SchematicNodeTable) } }, { it?.value })
@@ -130,6 +130,43 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
}
)
}
@JvmStatic
fun countEventFights(fighter: SteamwarUser) =
useDb {
exec(
"SELECT COUNT(DISTINCT F.FightID) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID INNER JOIN EventFight EF on F.FightID = EF.Fight WHERE UserID = ?",
args = listOf(IntegerColumnType() to fighter.id.value)
) {
if (it.next()) {
it.getLong("FightCount")
} else {
0
}
}
?: 0
}
@JvmStatic
fun countPlacement(fighter: SteamwarUser, placement: Int) =
useDb {
exec(
"""
SELECT COUNT(DISTINCT EventFight.EventID) AS PlacementCount FROM TeamTeilnahme
INNER JOIN EventFight ON EventFight.EventID = TeamTeilnahme.EventID
INNER JOIN FightPlayer ON FightPlayer.FightID = EventFight.Fight
WHERE (IF(FightPlayer.Team = 1, EventFight.TeamBlue, EventFight.TeamRed)) = TeamTeilnahme.TeamID AND UserID = ? AND Placement = ?
""".trimIndent(),
args = listOf(IntegerColumnType() to fighter.id.value, IntegerColumnType() to placement)
) {
if (it.next()) {
it.getInt("PlacementCount")
} else {
0
}
}
?: 0
}
}
val fightID by EventFightTable.id.transform({ EntityID(it, EventFightTable) }, { it.value })
@@ -200,6 +237,7 @@ class EventFight(id: EntityID<Int>) : IntEntity(id), Comparable<EventFight> {
override fun delete() =
useDb {
EventRelation.deleteRelations(this@EventFight)
super.delete()
}
}
}
@@ -159,10 +159,13 @@ class EventGroup(id: EntityID<Int>) : IntEntity(id) {
}
override fun delete() =
useDb { super.delete() }
useDb {
EventRelation.deleteRelations(this@EventGroup)
super.delete()
}
enum class EventGroupType {
GROUP_STAGE,
ELIMINATION_STAGE
}
}
}
@@ -24,8 +24,10 @@ import org.jetbrains.exposed.v1.core.and
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.dao.id.IntIdTable
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.or
import org.jetbrains.exposed.v1.dao.IntEntity
import org.jetbrains.exposed.v1.dao.IntEntityClass
import org.jetbrains.exposed.v1.jdbc.deleteWhere
import org.jetbrains.exposed.v1.jdbc.select
object EventRelationTable : IntIdTable("EventRelation") {
@@ -59,6 +61,23 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
fun getGroupRelations(group: EventGroup) =
useDb { find { (EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP) }.toList() }
@JvmStatic
fun deleteRelations(fight: EventFight) =
useDb {
EventRelationTable.deleteWhere {
(EventRelationTable.fightId eq fight.id) or
((EventRelationTable.fromId eq fight.id.value) and (EventRelationTable.fromType eq FromType.FIGHT))
}
}
@JvmStatic
fun deleteRelations(group: EventGroup) =
useDb {
EventRelationTable.deleteWhere {
(EventRelationTable.fromId eq group.id.value) and (EventRelationTable.fromType eq FromType.GROUP)
}
}
@JvmStatic
fun create(fight: EventFight, fightTeam: FightTeam, fromType: FromType, fromId: Int, fromPlace: Int) =
useDb {
@@ -159,4 +178,4 @@ class EventRelation(id: EntityID<Int>) : IntEntity(id) {
enum class FromType {
FIGHT, GROUP
}
}
}
@@ -20,9 +20,12 @@
package de.steamwar.sql
import de.steamwar.sql.internal.useDb
import org.jetbrains.exposed.v1.core.IntegerColumnType
import org.jetbrains.exposed.v1.core.VarCharColumnType
import org.jetbrains.exposed.v1.core.dao.id.CompositeID
import org.jetbrains.exposed.v1.core.dao.id.CompositeIdTable
import org.jetbrains.exposed.v1.core.dao.id.EntityID
import org.jetbrains.exposed.v1.core.eq
import org.jetbrains.exposed.v1.core.inList
import org.jetbrains.exposed.v1.dao.CompositeEntity
import org.jetbrains.exposed.v1.dao.CompositeEntityClass
@@ -69,6 +72,28 @@ class FightPlayer(id: EntityID<CompositeID>) : CompositeEntity(id) {
useDb {
find { FightPlayerTable.fightId inList fightIds.toList() }.toList()
}
@JvmStatic
fun countFights(userId: Int) =
useDb {
find { FightPlayerTable.userId eq userId }.count()
}
@JvmStatic
fun countFights(userId: Int, type: String) =
useDb {
exec(
"SELECT COUNT(*) AS FightCount FROM FightPlayer INNER JOIN Fight F on FightPlayer.FightID = F.FightID WHERE UserID = ? AND GameMode LIKE ?",
args = listOf(IntegerColumnType() to userId, VarCharColumnType() to "$type%")
) {
if (it.next()) {
it.getInt("FightCount")
} else {
0
}
}
?: 0
}
}
val fightID by FightPlayerTable.fightId.transform({ EntityID(it, FightTable) }, { it.value })
@@ -146,12 +146,12 @@ public final class GameModeConfig<M, W> {
public final List<String> CheckQuestions;
/**
* The allowed checkers to check this schematic type denoted by a list of SteamWar ids.
* The allowed checkers to check this schematic type denoted by a list of SteamwarUser ids.
* The people need the {@link UserPerm#CHECK} to be able to check though.
*
* @implSpec {@code []} by default -> denoting every person with {@link UserPerm#CHECK} can check it
*/
public final List<Integer> Checkers;
public final Set<Integer> Checkers;
/**
* Bundle for countdowns during the fight
@@ -246,7 +246,7 @@ public final class GameModeConfig<M, W> {
}
CheckQuestions = loader.getStringList("CheckQuestions");
Checkers = loader.getIntList("Checkers");
Checkers = loader.getIntSet("Checkers");
Times = new TimesConfig(loader.with("Times"));
// Arena would be here to be in config order but needs Schematic.Size and EnterStages loaded afterwards
Schematic = new SchematicConfig<>(loader.with("Schematic"));
@@ -488,6 +488,27 @@ public final class GameModeConfig<M, W> {
*/
public final boolean NoFloor;
/**
* Allows Wind Charges to cross the Middle.
*
* @implSpec {@code false} by default
*/
public final boolean WindchargesCanCrossMiddle;
/**
* Allows Wind Charge interaction with Blocks.
*
* @implSpec {@code true} by default
*/
public final boolean WindchargesInteractWithBlocks;
/**
* Allows Wind Charge to destroy Water.
*
* @implSpec {@code false} by default
*/
public final boolean WindchargesDestroyWater;
private ArenaConfig(YMLWrapper<M, W> loader, SchematicConfig.SizeConfig Size, List<Integer> EnterStages) {
loaded = loader.canLoad();
WaterDepth = loader.getInt("WaterDepth", 0);
@@ -505,6 +526,9 @@ public final class GameModeConfig<M, W> {
Leaveable = loader.getBoolean("Leaveable", false);
AllowMissiles = loader.getBoolean("AllowMissiles", !EnterStages.isEmpty());
NoFloor = loader.getBoolean("NoFloor", false);
WindchargesCanCrossMiddle = loader.getBoolean("WindchargesCanCrossMiddle", false);
WindchargesInteractWithBlocks = loader.getBoolean("WindchargesInteractWithBlocks", true);
WindchargesDestroyWater = loader.getBoolean("WindchargesDestroyWater", false);
}
@ToString
@@ -664,13 +688,6 @@ public final class GameModeConfig<M, W> {
*/
public final int MaxBlocks;
/**
* Maximal amount of items per dispenser
*
* @implSpec {@code 128} by default
*/
public final int MaxDispenserItems;
/**
* Maximal blast resistance for the blocks
*
@@ -686,10 +703,12 @@ public final class GameModeConfig<M, W> {
public final double MaxDesignBlastResistance;
/**
* List of limited material (combinations)<br/>
* List contains tags Amount (integer) and Materials (List of material names in Spigot 1.12 AND Spigot 1.15 format)
* List of limited block materials
*
* @implSpec {@link SQLWrapper#getInventoryMaterials)} are all disallowed by default to have any content but are unlimited in number.
* @implSpec Any Block that has more Blast Resistance than {@link #MaxBlastResistance} will be defaulted to 0.
*/
public final Map<Set<M>, Integer> Limited;
public final List<BlockRule<M>> Limited;
private SchematicConfig(YMLWrapper<M, ?> loader) {
loaded = loader.canLoad();
@@ -707,32 +726,140 @@ public final class GameModeConfig<M, W> {
IgnorePublicOnly = loader.getBoolean("IgnorePublicOnly", false);
UnlimitedPrepare = loader.getBoolean("UnlimitedPrepare", false);
MaxBlocks = loader.getInt("MaxBlocks", 0);
MaxDispenserItems = loader.getInt("MaxDispenserItems", 128);
MaxBlastResistance = loader.getDouble("MaxBlastResistance", Double.MAX_VALUE);
MaxDesignBlastResistance = loader.getDouble("MaxDesignBlastResistance", MaxBlastResistance);
Map<Set<M>, Integer> Limited = new HashMap<>();
for (Map<?, ?> entry : loader.getMapList("Limited")) {
int amount = (Integer) entry.get("Amount");
Set<String> materials = new HashSet<>((List<String>) entry.get("Materials"));
if (amount == 0) {
materials.forEach(material -> {
Limited.put(Collections.singleton(loader.materialMapper.apply(material.toUpperCase())), 0);
});
} else {
Limited.put(Collections.unmodifiableSet(materials.stream().map(String::toUpperCase).map(loader.materialMapper).collect(Collectors.toSet())), amount);
}
List<BlockRule<M>> limited = new ArrayList<>();
Set<M> blocks = new HashSet<>();
for (YMLWrapper<M, ?> limitedLoader : loader.withAsList("Limited")) {
BlockRule<M> blockRule = new BlockRule<>(limitedLoader);
blocks.addAll(blockRule.Materials);
limited.add(blockRule);
}
SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance).forEach(material -> {
if (Limited.entrySet().stream().anyMatch(entry -> entry.getKey().contains(material))) return;
Limited.put(Collections.singleton((M) material), 0);
});
this.Limited = Collections.unmodifiableMap(Limited);
for (M material : (List<M>) SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance)) {
if (material == null || !blocks.add(material)) continue;
limited.add(new BlockRule<>(material, 0));
}
for (M material : (Set<M>) SQLWrapper.impl.getInventoryMaterials()) {
if (material == null || !blocks.add(material)) continue;
limited.add(new BlockRule<>(material, Integer.MAX_VALUE));
}
this.Limited = Collections.unmodifiableList(limited);
this.ReplacementsWithoutBlockUpdates = loader.getMap("ReplacementsWithoutBlockUpdates", loader.materialMapper, loader.materialMapper);
this.ReplacementsWithBlockUpdates = loader.getMap("ReplacementsWithBlockUpdates", loader.materialMapper, loader.materialMapper);
}
public int getMaxCount(M material) {
return Limited.stream()
.filter(rule -> rule.Materials.contains(material))
.mapToInt(rule -> rule.Amount)
.max()
.orElse(Integer.MAX_VALUE);
}
public boolean isInventory(M material) {
return Limited.stream()
.filter(rule -> rule.Materials.contains(material))
.anyMatch(rule -> rule.Content.loaded);
}
public Integer getItemAmount(M material, M item) {
return Limited.stream()
.filter(rule -> rule.Materials.contains(material))
.filter(rule -> rule.Content.Items.contains(item))
.mapToInt(rule -> rule.Content.Amount)
.max()
.orElse(0);
}
@ToString
public static final class BlockRule<M> {
/**
* The block materials this rule applies to
*/
public final Set<M> Materials;
/**
* Maximal amount of Blocks allowed in the schematic
*
* @implSpec {@code 0} by default
*/
public final int Amount;
/**
* The item content filter for Blocks
*
* @implSpec no Items with {@code Amount 0} (denies any item) by default
*/
public final Content<M> Content;
/**
* Resolves one {@code Materials} entry to the concrete materials it denotes: {@code storage}
* for {@link SQLWrapper#getStorageMaterials()}, {@code inventory} for
* {@link SQLWrapper#getInventoryMaterials()}, or the material itself otherwise.
*/
private Set<M> expandInventoryGroup(YMLWrapper<M, ?> loader, String name) {
switch (name.toUpperCase()) {
case "STORAGE":
return (Set<M>) SQLWrapper.impl.getStorageMaterials();
case "INVENTORY":
return (Set<M>) SQLWrapper.impl.getInventoryMaterials();
default:
M material = loader.materialMapper.apply(name.toUpperCase());
return material != null ? Collections.singleton(material) : Collections.emptySet();
}
}
private BlockRule(YMLWrapper<M, ?> loader) {
Set<M> blocks = loader.getStringList("Materials")
.stream()
.flatMap(value -> expandInventoryGroup(loader, value).stream())
.collect(Collectors.toSet());
Materials = Collections.unmodifiableSet(blocks);
Amount = loader.getInt("Amount", 0);
Content = new Content<>(loader.with("Content"));
}
private BlockRule(M block, int amount) {
Materials = Collections.singleton(block);
Amount = amount;
Content = new Content<>();
}
@ToString
public static final class Content<M> {
public final boolean loaded;
/**
* Items allowed by this rule
*/
public final Set<M> Items;
/**
* Maximal amount of an allowed item per single block instance
*
* @implSpec {@code 0} by default
*/
public final int Amount;
private Content(YMLWrapper<M, ?> loader) {
loaded = loader.canLoad();
List<M> items = loader.getMaterialList("Items");
Items = Collections.unmodifiableSet(new HashSet<>(items));
Amount = loader.getInt("Amount", 0);
}
private Content() {
loaded = false;
Items = new HashSet<>();
Amount = 0;
}
}
}
@ToString
public static final class SizeConfig {
@@ -929,6 +1056,13 @@ public final class GameModeConfig<M, W> {
*/
public final boolean PersonalKits;
/**
* Maximal blast resistance for the blocks in the kit
*
* @implSpec {@code 9.0} by default
*/
public final double MaxBlastResistance;
/**
* Items (Valid spigot material values) that are not allowed in the personal kit
*/
@@ -940,7 +1074,10 @@ public final class GameModeConfig<M, W> {
MemberDefault = loader.getString("MemberDefault", "default");
LeaderDefault = loader.getString("LeaderDefault", "default");
PersonalKits = loader.getBoolean("PersonalKits", false);
ForbiddenItems = loader.getMaterialList("ForbiddenItems");
MaxBlastResistance = loader.getDouble("MaxBlastResistance", 9.0);
List forbiddenItems = new ArrayList<>(loader.getMaterialList("ForbiddenItems"));
forbiddenItems.addAll(SQLWrapper.impl.getMaterialWithGreaterBlastResistance(MaxBlastResistance));
ForbiddenItems = Collections.unmodifiableList(forbiddenItems);
}
}
@@ -183,14 +183,6 @@ class Punishment(id: EntityID<Int>) : IntEntity(id) {
"UNNOFIGHTSERVER",
UserPerm.MODERATION
),
NoTeamServer(
"NOTEAMSERVER_TEAM",
"NOTEAMSERVER_PERMA",
"NOTEAMSERVER_UNTIL",
"UNNOTEAMSERVER_ERROR",
"UNNOTEAMSERVER",
UserPerm.MODERATION
),
Note("NOTE_TEAM", null, null, null, null, UserPerm.PUNISHMENTS, true);
fun isMulti() =
@@ -24,6 +24,7 @@ import de.steamwar.ImplementationProvider;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public interface SQLWrapper<M> {
SQLWrapper<?> impl = ImplementationProvider.getImpl("de.steamwar.sql.SQLWrapperImpl");
@@ -36,5 +37,21 @@ public interface SQLWrapper<M> {
return Collections.emptyList();
}
/**
* Storage-type inventory materials (chests, barrels, shulker boxes of any color) - the
* {@code storage} group usable in {@code GameModeConfig}'s {@code Limited}.
*/
default Set<M> getStorageMaterials() {
return Collections.emptySet();
}
/**
* Every inventory material - the {@code all} group usable in {@code GameModeConfig}'s
* {@code Limited}. Expected to be a superset of {@link #getStorageMaterials()}.
*/
default Set<M> getInventoryMaterials() {
return Collections.emptySet();
}
void additionalExceptionMetadata(StringBuilder builder);
}
@@ -307,12 +307,12 @@ class SteamwarUser(id: EntityID<Int>) : IntEntity(id) {
punishments[punishment] = Punishment.createPunishment(this@SteamwarUser.id.value, from, punishment, reason, time, perma)
}
fun setLocale(locale: Locale?, manualeLocale: Boolean) {
fun setLocale(locale: Locale?, manualLocale: Boolean) {
if (locale == null || (this.manualLocale && !manualLocale)) return
useDb {
this@SteamwarUser.locale = locale
this@SteamwarUser.manualLocale = manualeLocale
this@SteamwarUser.manualLocale = manualLocale
}
}
@@ -76,6 +76,25 @@ final class YMLWrapper<M, W> {
return new YMLWrapper<>(false, Collections.emptyMap(), materialMapper, winconditionMapper);
}
public List<YMLWrapper<M, W>> withAsList(String path) {
if (document.containsKey(path)) {
Object value = document.get(path);
if (value instanceof List) {
List<?> list = (List<?>) value;
List<Map> maps = list.stream()
.filter(Map.class::isInstance)
.map(Map.class::cast)
.collect(Collectors.toList());
if (maps.size() == list.size()) {
return (List) maps.stream()
.map(map -> new YMLWrapper(true, map, materialMapper, winconditionMapper))
.collect(Collectors.toList());
}
}
}
return Collections.emptyList();
}
public <T> T get(String path, T defaultValue, Function<Object, T> mapper) {
Object value = this.document.get(path);
if (value == null) return defaultValue;
@@ -139,6 +158,12 @@ final class YMLWrapper<M, W> {
return get(path, o -> (List<Integer>) o);
}
public Set<Integer> getIntSet(String path) {
List<Integer> list = get(path, o -> (List<Integer>) o);
if (list.isEmpty()) return Collections.emptySet();
return Collections.unmodifiableSet(new HashSet<>(list));
}
public List<SchematicType> getSchematicTypeList(String path) {
List<String> list = getStringList(path);
if (list.isEmpty()) {
+18 -6
View File
@@ -64,6 +64,10 @@ Arena:
AllowMissiles: false # defaults to true if EnterStages are present otherwise 'false'
# Denotes that there is no floor for this GameMode
NoFloor: false # defaults to false if missing
# Allows Wind Charges to cross the Middle.
WindchargesCanCrossMiddle: false # defaults to false if missing
# Allows Wind Charge interaction with Blocks.
WindchargesInteractWithBlocks: false # defaults to false if missing
Schematic:
# The size of the schematics
@@ -103,15 +107,23 @@ Schematic:
UnlimitedPrepare: false # defaults to false if missing
# Maximal amount of blocks allowed in the schematic
MaxBlocks: 0 # defaults to 0 (ignored) if missing
# Maximal amount of items per dispenser
MaxDispenserItems: 128 # defaults to 128 if missing
# Maximal blast resistance for the design blocks
MaxDesignBlastResistance: 100000000 # defaults to Double.MAX_VALUE if missing
# List of limited material (combinations)
# List contains tags Amount (integer) and Materials (List of material names in Spigot 1.12 AND Spigot 1.15 format)
# List of limited block materials
# InventoryMaterials are all disallowed by default to have any content but are unlimited in number
# Any Block that has more Blast Resistance than MaxBlastResistance will be defaulted to 0.
Limited:
- Materials: [ ]
Amount: 0
- Blocks: [ DISPENSER ]
MaxCount: 64
- Blocks: [ DISPENSER ]
MaxCount: 16
Content:
Items: [ ARROW, FIRE_CHARGE ]
Amount: 128
- Blocks: [ storage ]
Content:
Items: [ TNT ]
Amount: 1728
# The name of the game mode presented to the players
GameName: WarGear # defaults to WarGear if missing
@@ -39,6 +39,7 @@ public enum ArenaMode {
public static final Set<ArenaMode> Test = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK));
public static final Set<ArenaMode> Prepare = Collections.unmodifiableSet(EnumSet.of(PREPARE));
public static final Set<ArenaMode> Replay = Collections.unmodifiableSet(EnumSet.of(REPLAY, TEST));
public static final Set<ArenaMode> TestOrReferee = Collections.unmodifiableSet(EnumSet.of(TEST, CHECK, EVENT));
public static final Set<ArenaMode> AntiReplay = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(REPLAY)));
public static final Set<ArenaMode> AntiTest = Collections.unmodifiableSet(EnumSet.complementOf(EnumSet.of(TEST, CHECK)));
@@ -21,8 +21,8 @@ package de.steamwar.fightsystem;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.Core;
import de.steamwar.core.WorldEditRendererCUIEditor;
import de.steamwar.fightsystem.commands.TechareaCommand;
import de.steamwar.core.worldedit.SteamEdit;
import de.steamwar.core.worldedit.WorldEditRendererCUIEditor;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.listener.ClickAnalyzer;
@@ -108,7 +108,7 @@ public class FightSystem extends JavaPlugin {
}
});
new OneShotStateDependent(ArenaMode.All, FightState.PreSchemSetup, () -> Fight.playSound(SWSound.BLOCK_NOTE_PLING.getSound(), 100.0f, 2.0f));
new OneShotStateDependent(ArenaMode.Test, FightState.All, WorldEditRendererCUIEditor::new);
new OneShotStateDependent(ArenaMode.Test, FightState.All, SteamEdit::init);
Config.world.setGameRule(GameRule.REDUCED_DEBUG_INFO, ArenaMode.AntiTest.contains(Config.mode));
hullHider = new HullHider();
@@ -127,8 +127,6 @@ public class FightSystem extends JavaPlugin {
if (checkSchematicNode.isPrepared()) {
Fight.getRedTeam().setSchem(checkSchematicNode, NodeData.getRevisions(checkSchematicNode) - 1);
}
new TechareaCommand();
} else if (Config.mode == ArenaMode.PREPARE) {
Fight.getUnrotated().setSchem(SchematicNode.getSchematicNode(Config.PrepareSchemID));
}
@@ -24,35 +24,25 @@ import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Kit;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class AkCommand implements CommandExecutor {
public class AkCommand extends FightSWCommand {
public AkCommand() {
new StateDependentCommand(ArenaMode.Test, FightState.All, "ak", this);
super(ArenaMode.Test, FightState.All, "ak");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
if (!player.isOp()) return false;
protected boolean hasPerm(Player player, SteamwarUser user) {
return player.isOp() && user.hasPerm(UserPerm.ADMINISTRATION) && Core.getInstance() != FightSystem.getPlugin();
}
if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.ADMINISTRATION) && Core.getInstance() != FightSystem.getPlugin()) {
return false;
}
Kit.createKit(args[0], player);
return false;
@Register
public void run(@Validator Player player, String name) {
Kit.createKit(name, player);
}
}
@@ -0,0 +1,95 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.fightsystem.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.command.TypeValidator;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependent;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerCommandSendEvent;
import java.util.Set;
public abstract class FightSWCommand extends SWCommand implements Listener {
private final String command;
private final String[] aliases;
protected FightSWCommand(Set<ArenaMode> mode, Set<FightState> states, String command) {
super(command);
this.command = command;
this.aliases = new String[0];
stateDependant(mode, states);
}
protected FightSWCommand(Set<ArenaMode> mode, Set<FightState> states, String command, String... aliases) {
super(command, aliases);
this.command = command;
this.aliases = aliases;
stateDependant(mode, states);
}
private void stateDependant(Set<ArenaMode> mode, Set<FightState> states) {
FightSWCommand.this.unregister();
new StateDependent(mode, states) {
@Override
public void enable() {
System.out.println("--- Enable: " + command);
FightSWCommand.this.register();
}
@Override
public void disable() {
System.out.println("--- Disable: " + command);
FightSWCommand.this.unregister();
}
}.register();
}
public static void postFightStateChange() {
for (Player player : Bukkit.getOnlinePlayers()) {
player.updateCommands();
}
}
protected boolean hasPerm(Player player, SteamwarUser user) {
return true;
}
@EventHandler(ignoreCancelled = true)
public final void onPlayerCommandSend(PlayerCommandSendEvent event) {
if (hasPerm(event.getPlayer(), SteamwarUser.get(event.getPlayer().getUniqueId()))) return;
event.getCommands().remove(command);
for (String alias : aliases) {
event.getCommands().remove(alias);
}
}
@ClassValidator(value = Player.class, local = true)
public final TypeValidator<Player> permissionCheck() {
return (sender, value, messageSender) -> hasPerm(value, SteamwarUser.get(value.getUniqueId()));
}
}
@@ -19,92 +19,28 @@
package de.steamwar.fightsystem.commands;
import com.google.common.collect.ImmutableList;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.linkage.Linked;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.GameMode;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.defaults.BukkitCommand;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Player;
import org.bukkit.util.StringUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Linked
public class GamemodeCommand extends BukkitCommand {
private static final List<String> GAMEMODE_NAMES = ImmutableList.of("adventure", "creative", "survival",
"spectator");
public class GamemodeCommand extends FightSWCommand {
public GamemodeCommand() {
super("gamemode");
List<String> aliases = new ArrayList<>();
aliases.add("gm");
this.setAliases(aliases);
Map<String, Command> knownCommands = ((CraftServer) Bukkit.getServer()).getCommandMap().getKnownCommands();
knownCommands.remove("gamemode");
Commands.injectCommand(this);
super(ArenaMode.TestOrReferee, FightState.All, "gamemode", "gm");
}
@Override
public boolean execute(CommandSender sender, String currentAlias, String[] args) {
if (!(sender instanceof Player)) {
return false;
} else if (args.length == 0) {
FightSystem.getMessage().sendPrefixless("GAMEMODE_HELP", sender);
return false;
}
Player p = (Player) sender;
if (!(Config.test() || Config.isReferee(p))) {
FightSystem.getMessage().sendPrefixless("GAMEMODE_NOT_ALLOWED", p, ChatMessageType.ACTION_BAR);
return false;
}
GameMode mode = createMode(args[0]);
if (mode == null) {
FightSystem.getMessage().sendPrefixless("GAMEMODE_UNKNOWN", p, ChatMessageType.ACTION_BAR, args[0]);
return false;
}
p.setGameMode(mode);
return true;
protected boolean hasPerm(Player player, SteamwarUser user) {
return Config.test() || Config.isReferee(player);
}
@SuppressWarnings("deprecation")
private GameMode createMode(String modeArg) {
try {
return GameMode.getByValue(Integer.parseInt(modeArg));
} catch (NumberFormatException ignored) {
if ((modeArg.equalsIgnoreCase("creative")) || (modeArg.equalsIgnoreCase("c"))) {
return GameMode.CREATIVE;
} else if ((modeArg.equalsIgnoreCase("adventure")) || (modeArg.equalsIgnoreCase("a"))) {
return GameMode.ADVENTURE;
} else if ((modeArg.equalsIgnoreCase("spectator")) || (modeArg.equalsIgnoreCase("sp"))) {
return GameMode.SPECTATOR;
} else if ((modeArg.equalsIgnoreCase("survival")) || (modeArg.equalsIgnoreCase("s"))) {
return GameMode.SURVIVAL;
}
}
return null;
@Register(description = "GAMEMODE_HELP")
public void execute(@Validator Player player, GameMode gameMode) {
player.setGameMode(gameMode);
}
@Override
public List<String> tabComplete(CommandSender sender, String alias, String[] args) {
if (args.length == 1) {
return StringUtil.copyPartialMatches(args[0], GAMEMODE_NAMES, new ArrayList<>(GAMEMODE_NAMES.size()));
}
return ImmutableList.of();
}
}
@@ -20,34 +20,31 @@
package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.listener.Check;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class InfoCommand implements CommandExecutor {
public class InfoCommand extends FightSWCommand {
public InfoCommand() {
new StateDependentCommand(ArenaMode.All, FightState.All, "fightinfo", this);
super(ArenaMode.All, FightState.All, "fightinfo");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.CHECK)) return false;
protected boolean hasPerm(Player player, SteamwarUser user) {
return Check.checkPermission(user, Config.GameModeConfig);
}
@Register
public void run(@Validator Player player) {
for (FightTeam team : Fight.teams()) {
if (!team.isLeaderless()) {
FightSystem.getMessage().send("INFO_LEADER", player, team.getColoredName(), team.getLeader().getEntity().getName());
@@ -58,6 +55,5 @@ public class InfoCommand implements CommandExecutor {
FightSystem.getMessage().send("INFO_SCHEMATIC", player, team.getColoredName(), schematic.getName(), SteamwarUser.byId(schematic.getOwner()).getUserName(), schematic.getRank());
}
}
return false;
}
}
@@ -21,32 +21,23 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class KitCommand implements CommandExecutor {
public class KitCommand extends FightSWCommand {
public KitCommand() {
new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "kit", this);
super(ArenaMode.AntiReplay, FightState.Setup, "kit");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
@Register
public void execute(Player player) {
GUI.kitSelection(player, "");
}
if (args.length != 1) {
GUI.kitSelection(player, "");
} else {
Commands.kit(player, args[0]);
}
return false;
@Register
public void execute(Player player, String query) { // TODO: TabCompletion of Kit Names!
GUI.kitSelection(player, query);
}
}
@@ -21,28 +21,18 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class LeaveCommand implements CommandExecutor {
public class LeaveCommand extends FightSWCommand {
public LeaveCommand() {
new StateDependentCommand(ArenaMode.AntiReplay, FightState.Setup, "leave", this);
super(ArenaMode.AntiReplay, FightState.Setup, "leave");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
@Register
public void execute(Player player) {
Commands.leaveTeam(player);
return false;
}
}
@@ -20,52 +20,42 @@
package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.listener.Check;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SchematicType;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class LockschemCommand implements CommandExecutor {
public class LockschemCommand extends FightSWCommand {
public LockschemCommand() {
new StateDependentCommand(ArenaMode.All, FightState.Schem, "lockschem", this);
super(ArenaMode.All, FightState.Schem, "lockschem");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
protected boolean hasPerm(Player player, SteamwarUser user) {
return Check.checkPermission(user, Config.GameModeConfig);
}
if (!SteamwarUser.get(player.getUniqueId()).hasPerm(UserPerm.CHECK)) return false;
if (args.length != 1) {
FightSystem.getMessage().sendPrefixless("LOCKSCHEM_HELP", player);
return false;
}
String teamName = args[0];
@Register(description = "LOCKSCHEM_HELP")
public void execute(@Validator Player player, String teamName) {
FightTeam fightTeam = Fight.getTeamByName(teamName);
if (fightTeam == null) {
FightSystem.getMessage().sendPrefixless("UNKNOWN_TEAM", player, ChatMessageType.ACTION_BAR);
return false;
return;
}
SchematicNode.getSchematicNode(fightTeam.getSchematic()).setSchemtype(SchematicType.Normal);
FightSystem.getMessage().sendPrefixless("LOCKSCHEM_LOCKED", player, ChatMessageType.ACTION_BAR);
fightTeam.broadcastSystem("LOCKSCHEM_LOCKED_BY", player.getName());
return false;
}
}
@@ -21,28 +21,18 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class ReadyCommand implements CommandExecutor {
public class ReadyCommand extends FightSWCommand {
public ReadyCommand() {
new StateDependentCommand(ArenaMode.AntiPrepare, FightState.PostSchemSetup, "ready", this);
super(ArenaMode.AntiPrepare, FightState.PostSchemSetup, "ready");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
@Register
public void execute(Player player) {
Commands.toggleReady(player);
return false;
}
}
@@ -20,35 +20,19 @@
package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class RemoveCommand implements CommandExecutor {
public class RemoveCommand extends FightSWCommand {
public RemoveCommand() {
new StateDependentCommand(ArenaMode.VariableTeams, FightState.Setup, "remove", this);
super(ArenaMode.VariableTeams, FightState.Setup, "remove");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
if (args.length != 1) {
FightSystem.getMessage().sendPrefixless("REMOVE_HELP", player);
return false;
}
Commands.kick(player, args[0]);
return false;
@Register(description = "REMOVE_HELP")
public void execute(Player player, Player teamMember) {
Commands.kick(player, teamMember.getName());
}
}
@@ -26,37 +26,28 @@ import de.steamwar.fightsystem.fight.FightPlayer;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.fight.JoinRequest;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.util.function.BiConsumer;
@Linked
public class RequestsCommand implements CommandExecutor {
public class RequestsCommand extends FightSWCommand {
public RequestsCommand() {
new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "request", this);
new StateDependentCommand(ArenaMode.VariableTeams, FightState.AntiSpectate, "requests", this);
super(ArenaMode.VariableTeams, FightState.AntiSpectate, "request", "requests");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) return false;
Player player = (Player) sender;
@Register
public void execute(Player player) {
FightPlayer fp = Fight.getFightPlayer(player);
if (fp == null || !(fp.isLeader() || fp.isLiving())) {
GUI.joinRequest(player);
return false;
return;
}
if (Commands.checkGetLeader(player) == null) return false;
if (Commands.checkGetLeader(player) == null) return;
GUI.chooseJoinRequests(player);
return false;
}
public static void onJoinRequest(Player player, JoinRequest request, BiConsumer<JoinRequest, FightTeam> handleJoinRequest) {
@@ -24,32 +24,22 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.record.PacketProcessor;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class SkipCommand implements CommandExecutor {
public class SkipCommand extends FightSWCommand {
public SkipCommand() {
new StateDependentCommand(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(Config.mode) ? FightState.All : FightState.TeamFix, "skip", this);
super(ArenaMode.AntiPrepare, ArenaMode.Replay.contains(Config.mode) ? FightState.All : FightState.TeamFix, "skip");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player player = (Player) sender;
@Register
public void execute(Player player) {
if (PacketProcessor.isReplaying() && player.getUniqueId().equals(Fight.getBlueTeam().getDesignatedLeader())) {
PacketProcessor.currentReplay().skipToSubtitle();
} else {
Commands.toggleSkip(player);
}
return false;
}
}
@@ -21,27 +21,18 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class StateCommand implements CommandExecutor {
public class StateCommand extends FightSWCommand {
public StateCommand() {
new StateDependentCommand(ArenaMode.Test, FightState.All, "state", this);
super(ArenaMode.Test, FightState.All, "state");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
GUI.state((Player) sender);
return false;
@Register
public void execute(Player player) {
GUI.state(player);
}
}
@@ -22,26 +22,18 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class TBCommand implements CommandExecutor {
public class TBCommand extends FightSWCommand {
public TBCommand() {
new StateDependentCommand(ArenaMode.Check, FightState.All, "resettb", this);
super(ArenaMode.Check, FightState.All, "resettb");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
@Register
public void execute(Player player) {
Fight.getRedTeam().pasteSchem();
return false;
}
}
@@ -20,34 +20,20 @@ package de.steamwar.fightsystem.commands;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import net.minecraft.server.MinecraftServer;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class TPSWarpCommand implements CommandExecutor {
public class TPSWarpCommand extends FightSWCommand {
public TPSWarpCommand() {
new StateDependentCommand(ArenaMode.Prepare, FightState.PostSchemSetup, "tpswarp", this);
new StateDependentCommand(ArenaMode.Prepare, FightState.PostSchemSetup, "tpslimit", this);
super(ArenaMode.Prepare, FightState.PostSchemSetup, "tpswarp", "tpslimit");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
float tps;
try {
tps = Float.parseFloat(args[0]);
} catch (NumberFormatException | ArrayIndexOutOfBoundsException e) {
FightSystem.getMessage().send("TPSWARP_HELP", sender);
return false;
}
@Register(description = "TPSWARP_HELP")
public void execute(Player player, float tps) {
MinecraftServer.getServer().tickRateManager().setTickRate(tps);
FightSystem.getMessage().broadcastActionbar("TPSWARP_SET", tps);
return false;
}
}
@@ -19,42 +19,39 @@
package de.steamwar.fightsystem.commands;
import de.steamwar.command.SWCommand;
import de.steamwar.entity.CWireframe;
import de.steamwar.entity.REntityServer;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import org.bukkit.Bukkit;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.OneShotStateDependent;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class TechareaCommand extends SWCommand {
private final Map<UUID, REntityServer> servers = new HashMap<>();
@Linked
public class TechareaCommand extends FightSWCommand {
private REntityServer entityServer = new REntityServer();
public TechareaCommand() {
super("techarea");
Bukkit.getScheduler().runTaskTimer(FightSystem.getPlugin(), () -> servers.forEach((uuid, rEntityServer) -> rEntityServer.tick()), 2, 2);
}
@Register
public void genericCommand(Player player) {
if (servers.containsKey(player.getUniqueId())) {
servers.get(player.getUniqueId()).close();
} else {
super(ArenaMode.Check, FightState.All, "techarea");
new OneShotStateDependent(ArenaMode.Check, FightState.All, () -> {
if (!entityServer.getEntities().isEmpty()) return;
REntityServer server = new REntityServer();
CWireframe wireframe = new CWireframe(server);
wireframe.setPos1(Config.BlueInsetRegion.getMinLocation(Config.world));
wireframe.setPos2(Config.BlueInsetRegion.getMaxLocation(Config.world).subtract(1, 1, 1));
wireframe.setBlock(Material.RED_CONCRETE.createBlockData());
});
}
server.addPlayer(player);
servers.put(player.getUniqueId(), server);
@Register
public void genericCommand(Player player) {
if (entityServer.getPlayers().contains(player)) {
entityServer.removePlayer(player);
} else {
entityServer.addPlayer(player);
}
}
}
@@ -25,27 +25,24 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.SWException;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import java.io.StringWriter;
import java.util.Arrays;
import java.util.logging.Level;
@Linked
public class TechhiderbugCommand implements CommandExecutor {
public class TechhiderbugCommand extends FightSWCommand {
public TechhiderbugCommand() {
new StateDependentCommand(ArenaMode.All, FightState.All, "techhiderbug", this);
super(ArenaMode.All, FightState.All, "techhiderbug");
}
@Override
public boolean onCommand(CommandSender sender, Command cmd, String alias, String[] args) {
@Register
public void execute(Player player, String... args) {
StringWriter writer = new StringWriter();
try {
@@ -76,7 +73,6 @@ public class TechhiderbugCommand implements CommandExecutor {
Bukkit.getLogger().log(Level.SEVERE, "Error while generating bug report", e);
}
SWException.log("Techhider-Bug reported by " + sender.getName() + ": " + Arrays.toString(args), writer.toString());
return false;
SWException.log("Techhider-Bug reported by " + player.getName() + ": " + Arrays.toString(args), writer.toString());
}
}
@@ -23,28 +23,20 @@ import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightWorld;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@Linked
public class WGCommand implements CommandExecutor {
public class WGCommand extends FightSWCommand {
public WGCommand() {
new StateDependentCommand(ArenaMode.Check, FightState.All, "resetwg", this);
super(ArenaMode.Check, FightState.All, "resetwg");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
@Register
public void execute(Player player) {
FightWorld.resetWorld();
Fight.getBlueTeam().pasteSchem();
Fight.getRedTeam().pasteSchem();
return false;
}
}
@@ -25,49 +25,34 @@ import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.fight.Fight;
import de.steamwar.fightsystem.fight.FightTeam;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentCommand;
import de.steamwar.linkage.Linked;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import de.steamwar.sql.SteamwarUser;
import org.bukkit.entity.Player;
@Linked
public class WinCommand implements CommandExecutor {
public class WinCommand extends FightSWCommand {
public WinCommand() {
new StateDependentCommand(ArenaMode.Event, FightState.Ingame, "win", this);
super(ArenaMode.Event, FightState.Ingame, "win");
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player)) {
return false;
}
Player p = (Player) sender;
protected boolean hasPerm(Player player, SteamwarUser user) {
return Config.isReferee(player);
}
if (!Config.isReferee(p)) {
FightSystem.getMessage().sendPrefixless("NOT_FIGHTLEADER", p, ChatMessageType.ACTION_BAR);
return false;
}
if (args.length == 0) {
FightSystem.getMessage().sendPrefixless("WIN_HELP", p);
return false;
}
if (args[0].equalsIgnoreCase("tie")) {
@Register
public void execute(@Validator Player player, String teamName) {
if (teamName.equalsIgnoreCase("tie")) {
FightSystem.setSpectateState(null, "Referee", "WIN_FIGHTLEADER");
return false;
return;
}
for (FightTeam team : Fight.teams()) {
if (args[0].equalsIgnoreCase(team.getName())) {
if (teamName.equalsIgnoreCase(team.getName())) {
FightSystem.setSpectateState(team, "Referee", "WIN_FIGHTLEADER");
return false;
return;
}
}
return false;
}
}
@@ -25,6 +25,7 @@ import de.steamwar.fightsystem.FightSystem;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.GameModeConfig;
import de.steamwar.sql.SchematicNode;
import de.steamwar.sql.SteamwarUser;
import de.steamwar.sql.UserPerm;
@@ -44,14 +45,28 @@ public class Check implements Listener {
new StateDependentListener(ArenaMode.Check, FightState.All, this);
}
private boolean checkPermission(SteamwarUser user, SchematicNode schematic) {
GameModeConfig<Object, String> gameModeConfig = GameModeConfig.getAll().stream()
.filter(gmc -> gmc.Schematic.Type != null && gmc.Schematic.Type.checkType() != null && schematic.getSchemtype().name().equals(gmc.Schematic.Type.checkType().name()))
.findFirst()
.orElse(null);
if (gameModeConfig == null) gameModeConfig = GameModeConfig.getDefaults();
return checkPermission(user, gameModeConfig);
}
public static boolean checkPermission(SteamwarUser user, GameModeConfig gameModeConfig) {
if (user.hasPerm(UserPerm.ADMINISTRATION)) return true;
if (gameModeConfig.Checkers.isEmpty() && user.hasPerm(UserPerm.CHECK)) return true;
return gameModeConfig.Checkers.contains(user.getId());
}
@EventHandler
public void onJoin(PlayerJoinEvent e) {
Player player = e.getPlayer();
SteamwarUser user = SteamwarUser.get(player.getUniqueId());
if (user.hasPerm(UserPerm.CHECK)) return;
SchematicNode schem = SchematicNode.getSchematicNode(Config.CheckSchemID);
if (checkPermission(user, schem)) return;
if (user.getId() == schem.getOwner()) return;
FightSystem.getMessage().send("CHECK_JOIN_DENIED", player);
@@ -1,7 +1,7 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2025 SteamWar.de-Serverteam
* Copyright (C) 2026 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
@@ -31,17 +31,16 @@ import de.steamwar.linkage.Linked;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.data.type.Dispenser;
import org.bukkit.block.data.type.DriedGhast;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockDispenseEvent;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.*;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
@@ -258,4 +257,16 @@ public class Permanent implements Listener {
event.setCancelled(true);
FightSystem.getMessage().sendPrefixless("NO_BLOCK_BREAK", event.getPlayer(), ChatMessageType.ACTION_BAR);
}
/**
* Prevents Dried Ghast from spawning and plants from growing
*/
@EventHandler
public void onBlockGrow(BlockGrowEvent event) {
var type = event.getBlock().getType();
if (event.getBlock().getBlockData() instanceof DriedGhast || Tag.CROPS.isTagged(type) || Tag.SAPLINGS.isTagged(type)) {
event.setCancelled(true);
}
}
}
@@ -72,6 +72,9 @@ public class WaterRemover implements Listener {
@EventHandler
public void handleEntityExplode(EntityExplodeEvent event) {
if (event.getEntityType() == EntityType.WIND_CHARGE && !Config.GameModeConfig.Arena.WindchargesDestroyWater) {
return;
}
event.setYield(0); //No drops (additionally to world config)
FightTeam spawn = tnt.remove(event.getEntity().getEntityId());
@@ -0,0 +1,44 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.fightsystem.listener;
import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentListener;
import de.steamwar.linkage.Linked;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityExplodeEvent;
@Linked
public class WindchargeInteractionDisabler implements Listener {
public WindchargeInteractionDisabler() {
new StateDependentListener(!Config.GameModeConfig.Arena.WindchargesInteractWithBlocks, FightState.Running, this);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void handleEntityExplode(EntityExplodeEvent event) {
if (event.getEntityType() != EntityType.WIND_CHARGE) return;
event.blockList().clear();
}
}
@@ -23,14 +23,14 @@ import de.steamwar.fightsystem.Config;
import de.steamwar.fightsystem.states.FightState;
import de.steamwar.fightsystem.states.StateDependentTask;
import de.steamwar.linkage.Linked;
import net.minecraft.world.entity.projectile.windcharge.WindCharge;
import org.bukkit.Location;
import org.bukkit.entity.WindCharge;
@Linked
public class WindchargeStopper {
public WindchargeStopper() {
new StateDependentTask(true, FightState.Running, this::run, 1, 1);
new StateDependentTask(!Config.GameModeConfig.Arena.WindchargesCanCrossMiddle, FightState.Running, this::run, 1, 1);
}
private static final int middleLine = Config.SpecSpawn.getBlockZ();
@@ -39,13 +39,13 @@ public class WindchargeStopper {
private void run() {
Recording.iterateOverEntities(windChargeClass::isInstance, entity -> {
Location nextlocation = entity.getLocation().add(entity.getVelocity());
Location location = entity.getLocation();
Location prevLocation = location.clone().subtract(entity.getVelocity());
boolean passedMiddle = location.getBlockZ() > middleLine && prevLocation.getBlockZ() > middleLine ||
location.getBlockZ() < middleLine && prevLocation.getBlockZ() < middleLine;
boolean passedMiddle = nextlocation.getBlockZ() >= middleLine && location.getBlockZ() <= middleLine ||
nextlocation.getBlockZ() <= middleLine && location.getBlockZ() >= middleLine;
if (!passedMiddle) {
if (passedMiddle) {
entity.remove();
}
});
@@ -20,7 +20,7 @@
package de.steamwar.fightsystem.record;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import de.steamwar.core.WorldEditWrapper;
import de.steamwar.core.worldedit.WorldEditWrapper;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RPlayer;
@@ -19,6 +19,7 @@
package de.steamwar.fightsystem.states;
import de.steamwar.fightsystem.commands.FightSWCommand;
import lombok.Getter;
import java.util.*;
@@ -62,6 +63,7 @@ public enum FightState {
}
public static void setFightState(FightState state) {
if (fightState.equals(state)) return;
fightState = state;
for (Map.Entry<IStateDependent, Boolean> feature : stateDependentFeatures.entrySet()) {
@@ -77,6 +79,7 @@ public enum FightState {
feature.setValue(false);
}
}
FightSWCommand.postFightStateChange();
}
public static boolean setup() {
@@ -1,58 +0,0 @@
/*
* 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.fightsystem.states;
import de.steamwar.fightsystem.ArenaMode;
import de.steamwar.fightsystem.FightSystem;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.PluginCommand;
import java.util.Set;
public class StateDependentCommand extends StateDependent {
private static final CommandExecutor unavailable = (sender, cmd, s, strings) -> {
FightSystem.getMessage().sendPrefixless("COMMAND_CURRENTLY_UNAVAILABLE", sender, ChatMessageType.ACTION_BAR);
return false;
};
private final PluginCommand command;
private final CommandExecutor executor;
public StateDependentCommand(Set<ArenaMode> mode, Set<FightState> states, String name, CommandExecutor executor) {
super(mode, states);
this.executor = executor;
this.command = FightSystem.getPlugin().getCommand(name);
assert command != null;
disable();
register();
}
@Override
public void enable() {
command.setExecutor(executor);
}
@Override
public void disable() {
command.setExecutor(unavailable);
}
}
+1 -19
View File
@@ -10,22 +10,4 @@ depend:
- WorldEdit
api-version: "1.13"
commands:
ak:
request:
requests:
fightinfo:
leave:
ready:
kit:
remove:
lockschem:
state:
skip:
win:
resetwg:
resettb:
tpslimit:
tpswarp:
techhiderbug:
unrank:
commands:
+12
View File
@@ -53,3 +53,15 @@ tasks.register<FightServer>("WarGear21") {
config = "WarGear21.yml"
jar = "/jars/paper-1.21.6.jar"
}
tasks.register<FightServer>("WarShip21") {
group = "run"
description = "Run a WarShip 1.21 Fight Server"
dependsOn(":SpigotCore:shadowJar")
dependsOn(":FightSystem:shadowJar")
dependsOn(":KotlinCore:shadowJar")
template = "WarShip21"
worldName = "arenas/Artic"
config = "WarShip21.yml"
jar = "/jars/paper-1.21.6.jar"
}
+8
View File
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
/*
* This file is a part of the SteamWar software.
*
@@ -34,6 +36,7 @@ dependencies {
compileOnly(libs.paperapi)
compileOnly(project(":SpigotCore"))
implementation(libs.coroutinesCore)
implementation(libs.exposedCore)
implementation(libs.exposedDao)
implementation(libs.exposedJdbc)
@@ -41,3 +44,8 @@ dependencies {
implementation(libs.mysql)
implementation("org.slf4j:slf4j-simple:2.0.17")
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.compilerOptions {
freeCompilerArgs.set(listOf("-XXLanguage:+ContextParameters"))
}
@@ -0,0 +1,23 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
@DslMarker
annotation class RenderMarker()
@@ -0,0 +1,26 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
interface RenderObject {
fun destroy()
fun render()
}
@@ -0,0 +1,90 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalForInheritanceCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlin.reflect.KProperty
private val uiStateScope = CoroutineScope(SupervisorJob() + Dispatchers.Unconfined)
context(render: StateFlowListener)
fun <T> StateFlow<T>.listen(): StateFlow<T> {
render.track(this) {
drop(1).onEach { render.update() }.launchIn(uiStateScope)
}
return this
}
context(render: StateFlowListener)
fun <T> MutableStateFlow<T>.listen(): MutableStateFlow<T> {
render.track(this) {
drop(1).onEach { render.update() }.launchIn(uiStateScope)
}
return this
}
fun <T> StateFlow<T>.listen(callback: (T) -> Unit): () -> Unit {
callback(value)
val job = drop(1).onEach { callback(it) }.launchIn(uiStateScope)
return { job.cancel() }
}
operator fun <T> StateFlow<T>.getValue(thisRef: Any?, property: KProperty<*>): T = value
operator fun <T> MutableStateFlow<T>.setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
}
fun <T, R> StateFlow<T>.map(mapper: (T) -> R): StateFlow<R> = MappedStateFlow(this, mapper)
@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
private class MappedStateFlow<T, R>(
private val parent: StateFlow<T>,
private val mapper: (T) -> R,
): StateFlow<R> {
override val replayCache: List<R>
get() = listOf(value)
override val value: R
get() = mapper(parent.value)
override suspend fun collect(collector: FlowCollector<R>): Nothing {
var initialized = false
var previous: Any? = null
parent.collect {
val mapped = mapper(it)
if (!initialized || previous != mapped) {
initialized = true
previous = mapped
collector.emit(mapped)
}
}
}
}
@@ -0,0 +1,41 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import kotlinx.coroutines.Job
abstract class StateFlowListener {
private val jobs = mutableMapOf<Any, Job>()
internal fun track(key: Any, createJob: () -> Job) {
if (key in jobs) return
val job = createJob()
jobs[key] = job
job.invokeOnCompletion { jobs.remove(key) }
}
abstract fun update()
open fun destroy() {
jobs.values.toList().forEach { it.cancel() }
jobs.clear()
}
}
@@ -0,0 +1,46 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import de.steamwar.kotlin.ui.components.item
import de.steamwar.kotlin.util.count
import kotlinx.coroutines.flow.MutableStateFlow
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
val Counter = MutableStateFlow(0)
class TestInv(player: Player): UIInventory(player) {
override fun view() {
inventory(3, "") {
item {
val amount by Counter.map { it + 1 }.listen()
item = ItemStack.of(Material.STONE)
.count(amount)
x = 0
y = 0
onClick {
Counter.value += 1
}
}
}
}
}
@@ -0,0 +1,55 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import de.steamwar.kotlin.ui.context.WindowContext
import org.bukkit.entity.Player
import org.bukkit.event.inventory.InventoryType
abstract class UIInventory(val player: Player): StateFlowListener() {
var window: UIWindow? = null
abstract fun view()
fun open() {
if (window == null) {
view()
assert(window != null) { "View method must create a inventory" }
}
window!!.open()
}
fun render() {
window?.onClose()
window = null
open()
}
override fun update() = render()
protected fun inventory(size: Int, title: String, init: WindowContext.() -> Unit) {
window = UIWindow(size, title, player, init)
}
protected fun inventory(type: InventoryType, title: String, init: WindowContext.() -> Unit) {
window = UIWindow(type, title, player, init)
}
}
@@ -0,0 +1,91 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui
import de.steamwar.kotlin.KotlinCore
import de.steamwar.kotlin.ui.context.WindowContext
import net.kyori.adventure.text.Component
import org.bukkit.Bukkit
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.InventoryHolder
import org.bukkit.inventory.InventoryView
class UIWindow(val player: Player, val render: WindowContext.() -> Unit): InventoryHolder {
val onClicks = mutableMapOf<Int, (event: InventoryClickEvent) -> Unit>()
private var updating = false
lateinit var bukkitInv: Inventory
private set
val context by lazy { WindowContext(this) }
constructor(size: Int, title: String, player: Player, render: WindowContext.() -> Unit): this(player, render) {
bukkitInv = KotlinCore.plugin.server.createInventory(this, size * 9, Component.translatable(title))
}
constructor(type: InventoryType, title: String, player: Player, render: WindowContext.() -> Unit): this(player, render) {
assert(type != InventoryType.CHEST) { "Chest inventories should use the constructor with size" }
bukkitInv = KotlinCore.plugin.server.createInventory(this, type, Component.translatable(title))
}
fun open() {
render(context)
player.openInventory(bukkitInv)
}
fun onClose() {
if (updating) return
onClicks.clear()
context.destroy()
}
override fun getInventory() = bukkitInv
companion object : Listener {
init {
Bukkit.getPluginManager().registerEvents(this, KotlinCore.plugin)
}
@EventHandler
fun onInventoryClick(event: InventoryClickEvent) {
val window = event.inventory.holder
if (window is UIWindow) {
event.isCancelled = true
if (window.context.skipDoubleClick && event.click == ClickType.DOUBLE_CLICK) return
window.onClicks[event.slot]?.invoke(event)
}
}
@EventHandler
fun onInventoryClose(event: InventoryCloseEvent) {
val window = event.inventory.holder
if (window is UIWindow) {
window.onClose()
}
}
}
}
@@ -0,0 +1,66 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui.components
import de.steamwar.kotlin.ui.StateFlowListener
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.RenderObject
import de.steamwar.kotlin.ui.context.GroupContext
import de.steamwar.kotlin.ui.context.RenderParent
import org.bukkit.Material
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
class ItemContext(val parent: RenderParent, val renderFunc: ItemContext.() -> Unit): RenderObject, StateFlowListener() {
override fun update() {
val oldX = x
val oldY = y
render()
if (oldX != x || oldY != y) {
parent.resetSlot(oldX, oldY)
}
}
override fun destroy() {
super.destroy()
parent.resetSlot(x, y)
}
override fun render() {
renderFunc(this)
parent.renderItem(x, y, item, onClick)
}
init {
render()
}
var item: ItemStack = ItemStack.of(Material.AIR)
var onClick: (event: InventoryClickEvent) -> Unit = {}
var x: Int = 0
var y: Int = 0
fun onClick(func: (event: InventoryClickEvent) -> Unit) {
onClick = func
}
}
fun GroupContext.item(init: ItemContext.() -> Unit) = children.add(ItemContext(this, init))
@@ -0,0 +1,65 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui.context
import de.steamwar.kotlin.ui.StateFlowListener
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.RenderObject
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
@RenderMarker
open class GroupContext(val parent: RenderParent?, val init: GroupContext.() -> Unit): StateFlowListener(), RenderObject, RenderParent {
val children = mutableListOf<RenderObject>()
val updatedSlots = mutableSetOf<Pair<Int, Int>>()
override fun update() = render()
override fun destroy() {
children.forEach { it.destroy() }
super.destroy()
}
init {
init(this)
}
override fun renderItem(x: Int, y: Int, item: ItemStack, onClick: (event: InventoryClickEvent) -> Unit) {
updatedSlots.add(x to y)
parent?.renderItem(x, y, item, onClick)
}
override fun resetSlot(x: Int, y: Int) {
parent?.resetSlot(x, y)
}
fun group(init: GroupContext.() -> Unit) {
children.add(GroupContext(this, init))
}
override fun render() {
children.forEach { it.destroy() }
children.clear()
val oldUpdatedSlots = updatedSlots.toList()
updatedSlots.clear()
init(this)
(oldUpdatedSlots - updatedSlots).forEach { resetSlot(it.first, it.second) }
}
}
@@ -0,0 +1,29 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui.context
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.inventory.ItemStack
interface RenderParent {
fun renderItem(x: Int, y: Int, item: ItemStack, onClick: (event: InventoryClickEvent) -> Unit)
fun resetSlot(x: Int, y: Int)
}
@@ -0,0 +1,54 @@
/*
* This file is a part of the SteamWar software.
*
* Copyright (C) 2026 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.kotlin.ui.context
import de.steamwar.kotlin.ui.RenderMarker
import de.steamwar.kotlin.ui.UIWindow
import org.bukkit.Material
import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryType
import org.bukkit.inventory.ItemStack
@RenderMarker
class WindowContext(val window: UIWindow): GroupContext(null, {}) {
override fun renderItem(x: Int, y: Int, item: ItemStack, onClick: (event: InventoryClickEvent) -> Unit) {
val slot = calculateSlot(x, y)
window.bukkitInv.setItem(slot, item)
window.onClicks[slot] = onClick
}
override fun resetSlot(x: Int, y: Int) {
val slot = calculateSlot(x, y)
window.bukkitInv.setItem(slot, ItemStack.of(Material.AIR))
window.onClicks.remove(slot)
}
private fun calculateSlot(x: Int, y: Int) = when (window.inventory.type) {
InventoryType.DROPPER, InventoryType.DISPENSER -> x + y * 3
InventoryType.HOPPER -> x
else -> x + y * 9
}
fun outsideClick(click: (event: InventoryClickEvent) -> Unit) {
window.onClicks[-999] = click
}
var skipDoubleClick = true
}

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