Compare commits

...
Author SHA1 Message Date
YoyoNow f63390915b Add glyph flight for enchant particles and blend team links
Pull Request Build / Build (pull_request) Successful in 1m57s
Entries with the enchant particle get a Glyph flight setting: float down as
usual, fly into the player or fly out of them, the latter two unlocked by the
WarGear Season placement and participation. Team link lines now start in the
drawing player's particle and blend into the partner's along the way.
2026-10-26 15:13:39 +01:00
YoyoNow db939e27d9 Turn the touches back into reward designs styled like any other
The Touch setting is gone. Its unique mechanics become reward designs that use
the entry's particle: Burst (on jumping, landing or sneaking, as a puff or a
ring), Footprints, Team link, Shimmer and Heartbeat. Each is unlocked by any
of the rewards that had it, and Burst's triggers are locked separately. The
wing beat becomes the Beat on jump wing motion, unlocked by WarGear Season
2022. December snow and the glyphs are dropped: the first is a plain particle
with a condition, the second only works with enchanting glyphs.
2026-10-26 15:08:08 +01:00
YoyoNow 36e6329f2b Redraw beating wings every tick only after a jump
The wing beat touch no longer lowers the entry's interval. Its wings are drawn
every tick during the beat and at their usual interval otherwise; the extra
redraws do not count towards the slot budget.
2026-10-26 15:02:56 +01:00
YoyoNow b2300c128e Let the wing beat touch beat the entry's own wings
On a Wings entry the touch adds a beat after each jump to the wings' motion
and draws nothing of its own; picking it redraws the wings every 2 ticks like
a motion does. Other designs keep the dragon breath wings.
2026-10-26 14:59:32 +01:00
YoyoNow 9cb4e0b7db Unlock everything for administrators
Every particle requirement passes for users with the administration
permission. Lore keeps naming the regular requirement.
2026-10-26 14:49:53 +01:00
YoyoNow 8e4730bd12 Turn reward touches into an unlockable Touch setting
Every entry gets a Touch setting next to its design, offering the 16 touches
the rewards carried, each unlocked by its reward. The reward designs that the
builder can now make are removed; only the underwater rain cloud and the
medium, hard and advanced egg hunt designs stay. Reward requirements move to
Unlocks, shared by touches, wing images and cosy smoke. The trail duration
moves to the particle row to make room in the design row.
2026-10-26 14:48:29 +01:00
YoyoNow baa278a1f5 Cap particle speed at 0.05 and give each wing shape its own icon
Speed steps by 0.005 up to 0.05; presets keep their faster particles. Number
values now show up to three decimals.
2026-10-26 14:43:44 +01:00
YoyoNow 8fd6fdf81e Unlock tournament wing images and cosy smoke for building
The MiniWarGear league, Underwater MWG, WarGear season 2022 and WarGear clash
wing images become Wings shapes, locked behind the placement that earns their
reward. Cosy campfire smoke becomes a buildable particle for Hells Bells
participants. Choice options can now carry a requirement: locked options show
it in the picker, are skipped when cycling and hide entries that use them.
2026-10-26 14:37:40 +01:00
YoyoNow 7d0f5aceae Give the rebuildable reward designs unique touches
Rewards whose look the basic designs can build now carry a touch the builder
cannot make: bursts on jumping, landing or sneaking, footprints, a line to
nearby players with the same reward, a December extra, aimed enchanting
glyphs, a heartbeat, a jump-beat wing or an orbiting shape. BodyMotion tracks
the jump, land and sneak events the touches react to.
2026-10-26 14:34:50 +01:00
YoyoNow ad9087c038 Remove the breathe wing motion
Wings keep the flap motions only; saved breathing wings load as none.
2026-10-26 13:57:59 +01:00
YoyoNow 872da5f62a Open wings with speed and let them flap or breathe
All wings stand 5 degrees open when idle and open up to 15 degrees the
faster the player moves. The wings design gets a motion setting to flap
slowly, flap quickly or breathe; picking a motion redraws the wing every
2 ticks so it looks smooth, and going back to none restores every 20.
Body rotation tracking now also tracks speed, as BodyMotion.
2026-10-26 13:55:58 +01:00
YoyoNow e830d087c9 Merge wing designs, turn wings with the body, limit leaves
Wing and Drawn wings become one Wings design whose shapes include the
images and the drawn bat, butterfly and fairy; for drawn shapes the points
per wing replace the amount. Body rotation is tracked per player the way
the client turns the body, and wings, the heart beat and body placement
follow it instead of the head. Leaves particles are for the server team
only, and typed hex colours show the closest dye.
2026-10-26 13:39:28 +01:00
YoyoNow b4661ea345 Add colour along the wing and sparkle to lobby wings
Both wing designs can colour their points from the spine to the tips
instead of changing colour over time, and a sparkle setting shows only a
share of the points each tick, which also lowers their cost. The angel
and phoenix drawn shapes are removed.
2026-10-26 13:34:23 +01:00
YoyoNow 4e5945d2bc Lower drawn wings to the shoulder blades
The drawn shapes had their shoulder joint at head height. They now sit
about 1.3 blocks above the feet at the default size.
2026-10-26 10:50:57 +01:00
YoyoNow a5b8f00c58 Add drawn wing shapes to the slot builder
A new Drawn wings design draws angel, bat, butterfly, fairy and phoenix
wings from lines and curves instead of images. The points per wing can be
set from 6 to 60, so sparse wings stay cheap enough to show often.
2026-10-26 10:48:32 +01:00
YoyoNow 8e23490b04 Settle open particle slot questions
Slots hold up to 9 entries, so the slot editor is one entry row plus the
bottom bar, and the server team may spawn 90 particles per tick. The
water and lava rings for taking part in any event return as reward
designs, and locked slots can be deleted from their read-only view.
2026-10-26 10:33:15 +01:00
YoyoNow 4c6b5e654a Quiet no-op particle setting clicks and show entry particle counts
Clicking a step past the minimum or maximum, or setting an unchanged
value, now does nothing instead of showing the budget message, and
changes that lower a slot's particles are allowed even over budget.
Entries show their particles per tick in the slot editor list, and the
entry editor's paper shows the edited entry's share.
2026-10-26 10:23:24 +01:00
YoyoNow 38a33b7298 Show the resulting value on number step buttons
Each step button on the number screen shows the value it leads to, and
marks when that value is the minimum or maximum.
2026-10-26 10:20:50 +01:00
YoyoNow 32797bd2a8 Limit lobby particle speed to 0.2
Speed went up to 1, which makes most particles shoot several blocks away.
It now goes up to 0.2; presets use at most 0.1.
2026-10-26 10:12:14 +01:00
YoyoNow 28b62bf27b Limit lobby particle spread to half a block
Spread went up to 2 blocks, which scatters a design's particles far
around the player. It now goes up to 0.5 in steps of 0.01.
2026-10-26 10:12:10 +01:00
YoyoNow db915f7be7 Keep large and lingering particles out of the slot builder
Explosion, sonic boom, sweep attack, gusts, campfire and large smoke,
dust pillar, block marker and shriek are a block or more in size or rise
for seconds and wall players in once a design spawns many of them. They
stay available to presets only.
2026-10-26 10:10:21 +01:00
YoyoNow aef26b5e9f Add the trail particle with duration and target
Trail particles fly from where they spawn to a target offset over the
chosen number of ticks, in the entry's colour. The target follows the
body like other offsets when the entry is placed relative to it.
2026-10-26 10:10:17 +01:00
YoyoNow 8009098965 Space out entry editor rows and show empty slots as firework stars
Settings in the entry editor start one column after the row headers, and
empty particle slots show a firework star instead of a gray pane.
2026-10-26 09:49:20 +01:00
YoyoNow 47f0d9858b Place lobby particle entries relative to the body
Entries get a World/Body setting. In body mode offsets, heights and wings
follow the body's facing and lie along the body while gliding or swimming,
so wings stay on the back. Rings circle the body but keep their world
angle, so they do not turn with the player. New wings default to body;
presets and rewards stay in world mode and look exactly as before.
2026-10-26 09:49:11 +01:00
YoyoNow c3eda01e20 Cycle particle settings with up to five options
Choices with up to five options cycle forward on left click and backward
on right click, listing all options in the lore. Two-option choices still
read as a toggle; longer choices keep their list.
2026-10-26 09:49:07 +01:00
YoyoNow 5e81081620 Toggle two-option particle settings on click
Choices with exactly two options switch on click like on/off settings,
and their lore lists both options with the current one highlighted.
2026-10-26 09:49:02 +01:00
YoyoNow ed70d65bc4 Size particle choice menus by their options
Lists that fit on one page get one row per nine options plus the bottom
bar, so a condition with three options opens a two row menu. Longer lists
keep the paged 6 row menu.
2026-10-26 09:48:57 +01:00
YoyoNow 2ce8799a19 Use black panes for the particle menu bottom bar
Unused bottom bar columns are black glass panes, empty places above it
are gray, including the free entry places of the slot editor.
2026-10-26 09:48:51 +01:00
YoyoNow 15036a7ba0 Allow hex colour codes for lobby particles
The colour screen gets a button to type a colour as #RRGGBB or #RGB,
next to picking one of the dye colours.
2026-10-26 09:48:46 +01:00
YoyoNow d77c014409 Translate lobby particle types and blocks
Add English and German names for all 104 selectable particle types and
the 43 blocks of the block setting.
2026-10-26 09:48:41 +01:00
YoyoNow 6b5441bb04 Offer nearly every vanilla particle in the slot builder
Add the remaining particles, including colour, colour transition, block
and item particles, which take their colours or a new block setting from
the entry. Only particles that cover the screen, show only under water or
need a target stay out.
2026-10-26 09:48:36 +01:00
YoyoNow 54d30f4a42 Fill unused particle menu columns with gray panes
Unused bottom bar columns show a gray glass pane instead of a barrier,
and the slot editor drops its use button since the particle menu
toggles slots with a click.
2026-10-26 09:48:32 +01:00
YoyoNow e41f76937e Give particle menus a shared bottom bar
Back, use, add, rename, icon, particle count and delete or reset now sit
in the same column of the last row in every particle menu, and columns a
menu does not use show a barrier.
2026-10-26 09:48:28 +01:00
YoyoNow 0c7ee052e8 Toggle particle slots with a click and label entry editor rows
A slot with entries is switched on or off with a click in the particle
menu and edited with a shift click; empty slots still open the editor.
The entry editor rows get distinct glowing header icons.
2026-10-26 09:48:25 +01:00
YoyoNow b60cdfc88d Simplify lobby particle menus
Every menu item now acts on a plain click: slots open their editor with a
use button, entries open their editor, and duplicating is gone. The entry
editor groups settings into labelled rows, numbers and colours get their
own screens instead of relying on right click or Q, and slot names show
the particles per tick used out of the maximum.
2026-10-26 09:48:20 +01:00
YoyoNow 98f04451a4 Polish lobby particle slots
Count the real particle amount of reward designs, set slot budgets to
30 particles per tick (60 for the server team), let requirements test
only against an UnlockContext, and drop requirements and messages the
old particle menu used.
2026-10-26 09:48:05 +01:00
YoyoNow c95901bc42 Add lobby particle slot menus
Replace the particle inventory with a main menu showing the 7 slots and
unlocked presets, a slot editor with a read-only view for locked slots,
and an entry editor with pickers for designs, choices, colours and icons.
Slots are limited to 10 entries and a particles-per-tick budget.
2026-10-26 09:48:00 +01:00
YoyoNow 211e2693cf Move lobby presets and rewards onto the particle slot model
Team- and user-specific particles become presets built from entries,
tournament and egg hunt particles become fixed reward designs, and the
old particle enums, ParticleEnum and ParticleData are removed. The
particle menu temporarily lists only unlocked presets.
2026-10-26 09:47:55 +01:00
YoyoNow 1980375e73 Add configurable particle slot model
Introduce parameters, particle types, designs and entries that build the
existing particle elements, store each of the 7 particle slots in its own
UserConfig key, and let LobbyPlayer select a slot next to the old enum
particles. Slots 4-5 need a team, 6-7 the server team.
2026-10-26 09:47:49 +01:00
YoyoNow ef041272bb Refactor lobby particle runtime for multi-entry particles
Tick particles from per-player cached always/move lists, drop the
per-instance listeners in Delayed and RandomParticle, and compute
particle viewers once per tick instead of once per spawned point.
2026-10-26 09:47:43 +01:00
YoyoNow bfbf98c1d6 Fix GUI.schemDialog for overriden Public list
Deploy / Build (push) Successful in 2m57s
Deploy / Deploy (push) Successful in 8s
2026-10-23 11:05:28 +02:00
YoyoNow c4b46e4431 Add override for Publics in GameModeConfig.Schematic
Deploy / Build (push) Successful in 2m22s
Deploy / Deploy (push) Successful in 8s
2026-10-21 08:22:05 +02:00
YoyoNow c238b9bdf2 Improve CheckCommand
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 9s
2026-10-21 08:02:05 +02:00
YoyoNow fec4007120 Merge pull request 'Fixed Replay not starting for Normal Users' (#510) from 12312/SteamWar:main into main
Deploy / Build (push) Successful in 2m34s
Deploy / Deploy (push) Successful in 9s
Reviewed-on: #510
2026-10-20 19:37:39 +02:00
12312 11798c3ec0 Fixed Replay not starting for Normal Users
Pull Request Build / Build (pull_request) Successful in 1m30s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 6s
Fixed Replay not starting for Normal Users.
2026-10-19 22:19:33 +02:00
YoyoNow 9935ab785d Fix NoClipCommand
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 8s
2026-10-19 11:21:15 +02:00
YoyoNow 8e3e71dd96 CLine: render as a single display shown by view distance
Deploy / Build (push) Successful in 2m24s
Deploy / Deploy (push) Successful in 9s
The line no longer needs start, middle and end parts that were moved
around the player. It is one display that is visible for a player as soon
as any chunk the line passes through is in their view distance.
REntity#canView now receives the chunk positions of player and entity.
2026-10-19 10:41:34 +02:00
YoyoNow 3fe2e006b9 REntityServer: use per-entity view range instead of chunk view distance
Entities now decide per player whether they are visible. REntity defaults
to the player view radius, RDisplay derives it from its viewRange (1 = 64
blocks) capped at the client view distance, so values like Float.MAX_VALUE
stay cheap. Changing the viewRange re-evaluates the viewers. Fixes #488
2026-10-19 10:40:03 +02:00
YoyoNow 9d5fcc07e8 Only notify the owner's dev server about Bauwelt member changes
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 9s
Dev servers are registered per owner (lowercase username), so there is
no need to wake every dev server.
2026-10-19 10:25:42 +02:00
YoyoNow 0c3e63d521 Restore BauweltMember cache and notify all dev servers on member changes
getBauMember never read its cache after the Exposed migration, so every
scoreboard render hit the DB (Too many connections, #479). Cache by
(bauwelt, member) incl. negative results, evict on addMember/remove, and
send BaumemberUpdatePacket to the Bauserver and all dev servers (also on
addmember). BauMemberUpdate clears the cache itself to not depend on
handler order.
2026-10-19 10:24:41 +02:00
YoyoNow 27d260a8d2 Delete CRIU checkpoint on /bau delete
Deploy / Build (push) Successful in 2m24s
Deploy / Deploy (push) Successful in 8s
/bau delete only removed the world folder. The checkpoint of the build
server stayed in place, so the next start restored the old JVM state
against a freshly copied world (superflat world, plugins inactive).
Extract ServerStarter#checkpointDir and delete the checkpoint together
with the world.
Fixes #438
2026-10-19 10:14:10 +02:00
YoyoNow 37f017b84c Improve action bar loading bar for server start
Deploy / Build (push) Successful in 2m24s
Deploy / Deploy (push) Successful in 8s
2026-10-19 09:59:02 +02:00
YoyoNow 21d0a4359d Update .gitignore
Deploy / Build (push) Successful in 2m49s
Deploy / Deploy (push) Successful in 10s
2026-10-19 09:31:38 +02:00
YoyoNow 8318d408b6 Fix REntity relative move rotation in 1.21
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 9s
Pass yaw before pitch to ClientboundMoveEntityPacket.Rot/PosRot and stop
converting the already byte-encoded rotation a second time.
2026-10-19 09:27:27 +02:00
YoyoNow d14ddc4fab Fix lag from PistonCalculator at high TPS
Deploy / Build (push) Successful in 2m27s
Deploy / Deploy (push) Successful in 9s
Bundle piston order recalculations into one run every 200ms (wall clock,
independent of TPS) instead of one full recalculation and entity rebuild
per piston/place/break event. Tracked pistons that get moved are removed
from the visualization instead of being moved along.

Fixes #227
2026-10-19 09:19:41 +02:00
YoyoNow 5cc5529533 Reenable ReplayCommand
Deploy / Build (push) Successful in 2m18s
Deploy / Deploy (push) Successful in 9s
2026-10-19 09:07:08 +02:00
YoyoNow 380693a2b7 Fix REntity position desync and velocity in 1.21 replays
Deploy / Build (push) Successful in 2m22s
Deploy / Deploy (push) Successful in 10s
Send ClientboundEntityPositionSyncPacket instead of the teleport packet so
relative moves keep working afterwards, and pass rotation in degrees.
Pass the velocity unscaled to Vec3 instead of pre-multiplying by 8000.
Fixes #247
2026-10-19 09:03:52 +02:00
YoyoNow 69aef9dfb6 Fix ClassCastException for replay player equipment
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 8s
PacketProcessor passes Bukkit EquipmentSlots to REntity#setItem, which cast
them to the NMS EquipmentSlot. Take the Bukkit slot and map it to the NMS
slot when building the equipment packet.
2026-10-19 08:38:42 +02:00
YoyoNow 097df865e5 Resend replay player tab entry when skin arrives
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 8s
RPlayer requests the skin asynchronously, so the first tab list packet is
usually sent without textures and viewers already in range kept the default
skin. Re-send despawn/delist/list/spawn to the current viewers once the
skin response is received.
2026-10-19 08:21:52 +02:00
YoyoNow 230f8c521a Use PistonStructureResolver in PistonCalculator
Deploy / Build (push) Successful in 2m35s
Deploy / Deploy (push) Successful in 9s
Numbering now comes directly from the vanilla resolver instead of a
custom breadth-first search, so the order matches the real move order
(including backtracking through slime/honey chains). The display of
more than 12 blocks is removed; a blocked piston is shown in red.

Refs: #158
2026-10-18 20:09:10 +02:00
YoyoNow 253a975c73 Show no player hover for players of the public team
Deploy / Build (push) Successful in 2m47s
Deploy / Deploy (push) Failing after 5s
2026-10-18 20:01:24 +02:00
YoyoNow 12dd46176b Suggest /team info SW when clicking the SW prefix 2026-10-18 20:01:19 +02:00
YoyoNow 2111d72387 Suggest /team info when clicking a team prefix
Clicking the team prefix in the global/local chat or an event team
prefix in the fight chat puts /team info <shorthand> into the chat
input; the hover explains the click.
2026-10-18 20:01:15 +02:00
YoyoNow 3aa471c3ab Read global chat on fight servers after /chat global join
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 12s
2026-10-16 11:29:02 +02:00
YoyoNow 47557d7bb8 Keep global chat readable after writing into it on fight servers
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 9s
Writing /global <text> on a fight server shows the global chat until
the player leaves the server or runs /chat global leave, without
changing the default channel.
2026-10-16 11:17:30 +02:00
YoyoNow 62850b2e11 Let moderators read all fight chats automatically
Deploy / Build (push) Successful in 2m32s
Deploy / Deploy (push) Successful in 8s
/chat arenas join|leave lets moderators read the fight and team chats
of every arena and event spectate server; the choice is saved across
relogs. /chat <arena> leave excludes a single arena for the session.
2026-10-16 11:09:52 +02:00
YoyoNow 7f47d687d3 Hide /chat msg from players without moderation permission 2026-10-16 11:09:45 +02:00
YoyoNow 362e1cebff Name the fight channel Fight
The server name is already shown in the second line of the hover.
2026-10-16 11:09:41 +02:00
YoyoNow 39cacbd701 Show team on hover for @name mentions 2026-10-16 11:09:36 +02:00
YoyoNow 503261ce6d Name team chat channels TeamChat and ServerTeamChat 2026-10-16 11:09:30 +02:00
YoyoNow 8a86ebde83 Make DM names hoverable and channel icons clickable
- Both names in direct messages show their team on hover
- Clicking a channel icon suggests the command to write a single
  message into that channel
2026-10-16 11:09:24 +02:00
YoyoNow be915770b1 Show server name in local channel hover
Deploy / Build (push) Successful in 2m27s
Deploy / Deploy (push) Successful in 9s
2026-10-16 09:46:22 +02:00
YoyoNow 70c4225827 Merge pull request 'Chat channels' (#506) from feature/chat-channels into main
Deploy / Build (push) Successful in 3m4s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #506
2026-10-16 09:19:54 +02:00
YoyoNow 904a850a3f Remove duplicated chat channel logic
Pull Request Build / Build (pull_request) Successful in 1m29s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
- Shared send-or-switch helper for /global, /local, /tc and /stc
- Shared helpers for "is on server" and the player's current local
  channel
- Read fight infos from TablistManager instead of keeping a second map
- /chat resolves fight servers (arenas and spectate servers) by name in
  one place
- Reuse the global and participant formats instead of identical keys
2026-10-16 09:17:01 +02:00
YoyoNow 4c75879915 Keep spectators in fight chat and treat spectate servers as fight servers
Pull Request Build / Build (pull_request) Successful in 1m30s
- '+' from a spectator on a fight server stays in the fight chat
- Event spectate servers (static servers with a spectate port) use a
  local fight chat by default and hide the global chat like arenas
2026-10-16 09:07:58 +02:00
YoyoNow 65cc6119b0 Show default channel notice with its icon
The notice on join, on every default change and for /chat is now
"<icon> is your default channel" in green without the SteamWar prefix;
hovering the icon shows the channel name.
2026-10-16 09:00:41 +02:00
YoyoNow 975d42c17f Add team hovers to fight chat and make DMs non-default
- Names in the fight chat show the sender's team on hover like
  everywhere else; the Blue/Red team prefix is only hoverable in event
  fights, where it is the actual team
- Server team members using the SW prefix show the SteamWar team
- Direct messages can no longer be the default channel; /msg and /r
  require a message again
2026-10-16 08:59:26 +02:00
YoyoNow 317cb0adf8 Add channel icons and hovers to chat messages
Every chat message now starts with a fixed icon of its channel
(🌍 Global, ⌂ Local, ⚔ fight, ⚑ fight team, 👥 TC, ⚙ STC, ✉ DM),
highlighted yellow if it is the receiver's default channel. Hovering
the icon shows the channel name, hovering the sender shows their team
name and shorthand.
2026-10-16 08:48:30 +02:00
YoyoNow 4266a7f35b Merge pull request 'fix: Remove Help Text for /team server' (#499) from 12312/SteamWar:main into main
Deploy / Build (push) Successful in 2m49s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #499
2026-10-15 20:25:47 +02:00
YoyoNow 26d5ff7aad Merge pull request 'Fix SmartPlace reversing debug stick' (#505) from fix/smartplace-debugstick into main
Deploy / Build (push) Successful in 2m53s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #505
2026-10-15 20:09:49 +02:00
YoyoNow b21ff415a8 Show channel tags as plain gray prefix
Pull Request Build / Build (pull_request) Successful in 1m32s
Messages from a channel that is not the receiver's default are now
prefixed with the plain channel name in dark gray instead of brackets.
Direct messages get no tag, as their format already shows sender and
receiver.
2026-10-15 20:06:58 +02:00
YoyoNow 9fe05b59e4 Rework chat into Velocity-managed channels
Chat is now handled entirely by VelocityCore through channels with
separate readers and writers (Global, Local/Fight, Blue/Red fight team,
Team, ServerTeam, Alert and 1:1 direct messages). Each player has a
saved default channel; messages from other channels are tagged with
the channel name, and every default change is announced.

- /global, /local, /tc, /stc, /msg and /r switch the default channel
  when called without a message
- /chat <channel> switches, /chat <channel> join|leave toggles reading
  (saved); moderators can join arenas by name and write with
  /chat <channel> msg <text>
- '+' sends from global to local and from local/fight to the fight team
- Referees write yellow in the fight chat
- Subservers no longer receive chat; arenas get a record-only
  ChatRecordPacket so replays keep their chat
- Remove the chat listeners of SpigotCore, FightSystem, MissileWars,
  TowerRun and TNTLeague

Closes #460, #129
2026-10-15 19:55:25 +02:00
YoyoNow 2302f9aafb Fix SmartPlace reversing debug stick
Pull Request Build / Build (pull_request) Successful in 1m32s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-10-15 18:14:19 +02:00
YoyoNow d727982ce0 Fix AutoChecker inventory rules
Deploy / Build (push) Successful in 9m6s
Deploy / Deploy (push) Successful in 20s
Count every inventory block towards exactly one Schematic.Limited rule:
filled blocks towards a rule whose Content allows all their items, empty
blocks towards a rule without Content (unlimited if there is none). Each
rule's Amount now caps how many blocks it covers, instead of taking the
highest Amount of all rules for that block type.

Inventory blocks whose items fit no rule are now checked and reported,
items from different rules in one block are reported as mixed, and the
auto-fix trims or removes them accordingly.

Remove the hardcoded wargearseason26 wind charge handling and its 2048
limit, wind charges are configured via Limited rules now.

Log a warning for Limited rules that match no blocks, e.g. a misspelled
'Materials' key.

Fixes #458, #481, #502
2026-10-15 17:53:06 +02:00
YoyoNow 2b42f0d13c Remove YAPION from BauSystem_Main module
Deploy / Build (push) Successful in 40m13s
Deploy / Deploy (push) Successful in 5m54s
2026-09-29 14:26:57 +02:00
12312 3e3a209c80 Removed Extra Line
Pull Request Build / Build (pull_request) Successful in 1m36s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 5s
2026-09-24 21:49:20 +02:00
12312 1d43021853 Remove TEAM_HELP_SERVER Deutsch 2026-09-24 21:47:22 +02:00
12312 5a224c1bcc Remove TEAM_HELP_SERVER English 2026-09-24 21:46:18 +02:00
12312 6330dbc2b1 VelocityCore/src/de/steamwar/velocitycore/commands/TeamCommand.java aktualisiert 2026-09-24 21:43:20 +02:00
YoyoNow 4306fe7bc9 Merge pull request 'Fix SteamwarUser.setLocale' (#489) from Hut512/SteamWar:fix/setlocale-typo into main
Deploy / Build (push) Successful in 18m57s
Deploy / Deploy (push) Successful in 26s
Reviewed-on: #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
Deploy / Build (push) Successful in 19m39s
Deploy / Deploy (push) Successful in 32s
Reviewed-on: #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
Deploy / Build (push) Successful in 19m18s
Deploy / Deploy (push) Successful in 24s
Reviewed-on: #494
2026-09-14 12:17:30 +02:00
YoyoNow 1e85b14667 Improve SteamEditWand
Deploy / Build (push) Successful in 12m55s
Deploy / Deploy (push) Successful in 23s
2026-09-14 10:02:39 +02:00
Hut512 35c27923aa Fix region water level
Pull Request Build / Build (pull_request) Failing after 4m56s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 10s
2026-09-12 20:07:07 +02:00
Hut512 c3b3e3e60f Fix NoClip instant block break
Pull Request Build / Build (pull_request) Successful in 1m25s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
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
Pull Request Build / Build (pull_request) Successful in 1m25s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-09-07 15:24:32 +02:00
YoyoNow 6209b86149 Fix TeamCommand.info
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 11s
2026-09-07 14:03:06 +02:00
YoyoNow 6f1403df9c Cleanup SWPlayer
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 14s
2026-09-05 14:52:59 +02:00
YoyoNow 0113788da2 Fix SteamEditWand
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 11s
2026-09-05 09:50:47 +02:00
YoyoNow 8a7f65e000 Merge pull request 'Fix CRIU subserver stop' (#485) from Hut512/SteamWar:main into main
Deploy / Build (push) Successful in 2m27s
Deploy / Deploy (push) Successful in 13s
Reviewed-on: #485
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-09-03 21:39:15 +02:00
Hut512 8401f67b24 Fix CRIU subserver stop
Pull Request Build / Build (pull_request) Successful in 1m30s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-09-03 02:24:49 +02:00
YoyoNow 362468e756 Fix SteamEditWand
Deploy / Build (push) Successful in 2m22s
Deploy / Deploy (push) Successful in 12s
2026-09-01 11:14:30 +02:00
YoyoNow ece12df0bc Add SteamEdit
Deploy / Build (push) Successful in 41m8s
Deploy / Deploy (push) Successful in 10s
2026-09-01 10:32:56 +02:00
YoyoNow f35c07ab5b Fix EventStarter
Deploy / Build (push) Successful in 2m28s
Deploy / Deploy (push) Successful in 10s
2026-08-30 16:12:32 +02:00
YoyoNow 549f7e555c Remove NoTeamServer punishment
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 11s
2026-08-30 13:04:52 +02:00
YoyoNow 859238d7fa Disable 'showtable' in EventCommand
Deploy / Build (push) Successful in 2m31s
Deploy / Deploy (push) Successful in 13s
2026-08-30 12:25:34 +02:00
YoyoNow a79b00f78f Fix EventCommand
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 18s
2026-08-30 12:23:23 +02:00
YoyoNow 105eda32e6 Update CustomMap
Deploy / Build (push) Successful in 2m22s
Deploy / Deploy (push) Successful in 10s
2026-08-30 12:15:22 +02:00
YoyoNow b4487b8079 Update doc comment
Deploy / Build (push) Successful in 2m35s
Deploy / Deploy (push) Successful in 11s
2026-08-30 12:00:40 +02:00
YoyoNow ea3aad3bd2 Initial FightSWCommand
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 11s
2026-08-29 12:52:09 +02:00
YoyoNow d307f890e2 Remove debug output
Deploy / Build (push) Successful in 2m22s
Deploy / Deploy (push) Successful in 12s
2026-08-26 22:35:39 +02:00
YoyoNow 97c1da1b2a Add debug output
Deploy / Build (push) Successful in 2m18s
Deploy / Deploy (push) Successful in 11s
2026-08-26 22:31:30 +02:00
YoyoNow 8a53aecfac Add debug output
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 13s
2026-08-26 22:26:43 +02:00
YoyoNow 5236afba17 Add debug output
Deploy / Build (push) Successful in 2m18s
Deploy / Deploy (push) Successful in 12s
2026-08-26 22:17:33 +02:00
YoyoNow d3c8b6e1c6 Add debug output
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 11s
2026-08-26 22:12:53 +02:00
YoyoNow 00ea792eee Merge pull request 'Improve AutoChecker and GameModeConfig again' (#478) from AutoChecker into main
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #478
2026-08-26 22:05:31 +02:00
YoyoNow 38e845b0e4 Improve AutoChecker and GameModeConfig again
Pull Request Build / Build (pull_request) Successful in 1m33s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-08-26 21:46:45 +02:00
YoyoNow c60a8caed8 Merge pull request 'Improve items for GameModeConfig' (#476) from AutoChecker into main
Deploy / Build (push) Successful in 2m38s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #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
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #477
Reviewed-by: sakziea <59+sakziea@noreply.localhost>
2026-08-25 16:57:04 +02:00
YoyoNow 6476125a3f Add ServerLinks to login
Pull Request Build / Build (pull_request) Successful in 1m31s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 13s
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
Pull Request Build / Build (pull_request) Successful in 1m38s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-08-24 20:05:58 +02:00
YoyoNow 72b70a62e1 Fix CustomItem
Deploy / Build (push) Successful in 2m16s
Deploy / Deploy (push) Successful in 11s
2026-08-19 12:05:09 +02:00
YoyoNow 8575dcac33 Add WindCharge option to LaunchScript
Deploy / Build (push) Successful in 2m17s
Deploy / Deploy (push) Successful in 11s
2026-08-19 11:06:34 +02:00
YoyoNow cb744f6aa0 Add AntiPlayerCollision
Deploy / Build (push) Successful in 2m17s
Deploy / Deploy (push) Successful in 11s
2026-08-18 10:48:16 +02:00
YoyoNow 227f63c9ff Add AntiPlayerCollision
Deploy / Build (push) Successful in 2m24s
Deploy / Deploy (push) Successful in 11s
2026-08-18 10:39:58 +02:00
YoyoNow 397b10c319 Merge pull request 'Velocity core /event command' (#465) from VelocityCore/EventCommand into main
Deploy / Build (push) Successful in 2m12s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #465
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-08-14 07:53:43 +02:00
YoyoNow 32569f19d9 Closes: #468
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 11s
2026-08-13 10:09:13 +02:00
YoyoNow f19e4158e7 Fix Check
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 13s
2026-08-13 10:01:55 +02:00
YoyoNow 6c46b5b2a2 Fix Check
Deploy / Build (push) Successful in 2m20s
Deploy / Deploy (push) Successful in 11s
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
Deploy / Build (push) Successful in 2m17s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #454
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-08-13 09:50:14 +02:00
YoyoNow 683236bb59 Fix TexturePackSystem for newer versions
Deploy / Build (push) Successful in 2m11s
Deploy / Deploy (push) Successful in 10s
2026-08-13 09:39:42 +02:00
YoyoNow 8dc101639d Add alias of /tick rate to /tick rate 20
Deploy / Build (push) Successful in 2m23s
Deploy / Deploy (push) Successful in 15s
2026-08-11 21:48:28 +02:00
YoyoNow 792620804a Improve TPSSystem
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 11s
2026-08-11 21:46:38 +02:00
YoyoNow 4aa7c99a6e Fix Check and CheckCommand permission
Deploy / Build (push) Successful in 3m30s
Deploy / Deploy (push) Successful in 11s
2026-08-11 21:05:36 +02:00
Sakziea cce18124f2 Remove unused translation
Pull Request Build / Build (pull_request) Successful in 3m33s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 8s
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
Deploy / Build (push) Successful in 2m47s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #444
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-26 10:22:42 +02:00
Chaoscaot ae898e14c2 Merge branch 'main' into swui/flows
Pull Request Build / Build (pull_request) Successful in 1m56s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-07-26 10:20:35 +02:00
Chaoscaot 726f73cc45 Merge branch 'main' into VelocityCore/DeleteMemberOfBauDeletingPlayerData
Pull Request Build / Build (pull_request) Successful in 1m32s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
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
Deploy / Build (push) Successful in 2m36s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #455
2026-07-18 15:00:18 +02:00
Sakziea 1d2ac4f705 Fix pull Request comment
Pull Request Build / Build (pull_request) Successful in 1m30s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-07-18 14:58:24 +02:00
Sakziea b48c75ef74 Remove unused imports
Pull Request Build / Build (pull_request) Successful in 1m31s
2026-07-18 12:49:23 +02:00
Sakziea 8b6ea12a08 Add Wind charge config
Pull Request Build / Build (pull_request) Successful in 1m33s
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
Deploy / Build (push) Successful in 2m50s
Deploy / Deploy (push) Successful in 10s
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
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #453
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-17 14:27:01 +02:00
Sakziea 25ab79abc0 Fix PullRequest comment
Pull Request Build / Build (pull_request) Successful in 1m38s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-07-17 14:23:55 +02:00
Sakziea 582d6a62e3 Fix PullRequest comment
Pull Request Build / Build (pull_request) Successful in 1m34s
2026-07-17 14:22:36 +02:00
Chaoscaot 5eec792aff Merge branch 'main' of https://git.steamwar.de/SteamWar/SteamWar
Deploy / Build (push) Successful in 2m32s
Deploy / Deploy (push) Successful in 10s
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
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 10s
2026-07-17 10:06:48 +02:00
YoyoNow 64e627514d Add deletion of PlayerData on /bau delmember
Pull Request Build / Build (pull_request) Successful in 1m29s
2026-07-17 09:47:40 +02:00
Sakziea a8c68864d8 Fix AutoChecker only counts filled Dispenser
Pull Request Build / Build (pull_request) Successful in 1m31s
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
Deploy / Build (push) Successful in 2m32s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #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
Pull Request Build / Build (pull_request) Successful in 2m10s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
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
Pull Request Build / Build (pull_request) Successful in 1m51s
2026-07-16 16:39:27 +02:00
YoyoNow 390d388692 Closes: #442
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 11s
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
Deploy / Build (push) Successful in 4m29s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #445
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-07-16 16:24:16 +02:00
Sakziea dab443b989 Fix pullRequest comments
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 11s
Pull Request Build / Build (pull_request) Successful in 4m2s
2026-07-16 16:23:52 +02:00
Sakziea bf3c65c630 Fix when no tnt isolated show normal
Pull Request Build / Build (pull_request) Successful in 3m14s
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
Pull Request Build / Build (pull_request) Successful in 1m30s
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
Pull Request Build / Build (pull_request) Successful in 1m50s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-06 01:13:05 +02:00
Chaoscaot 62e855ec1b Fix Reset
Deploy / Build (push) Successful in 2m24s
Deploy / Deploy (push) Successful in 10s
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
Deploy / Build (push) Successful in 2m43s
Deploy / Deploy (push) Successful in 11s
2026-07-05 14:14:04 +02:00
Chaoscaot 6fd3e6f690 Fix Reset
Deploy / Build (push) Successful in 2m14s
Deploy / Deploy (push) Successful in 10s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:51:45 +02:00
Chaoscaot 7acd51fd61 Fix Reset
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:45:59 +02:00
Chaoscaot b278ca15f3 Fix Devserver
Deploy / Build (push) Successful in 2m20s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:41:01 +02:00
Chaoscaot 029249c2b0 Fix Database Reset
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 10s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:23:52 +02:00
Chaoscaot 1ceb10439b Fix Database Reset
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 13s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 13:18:38 +02:00
Chaoscaot a5dfe6ab7e Fix Database Reset
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-07-05 12:59:29 +02:00
YoyoNow c8a5f567eb Add StreamingCommand for UserPerm.PREFIX_YOUTUBER
Deploy / Build (push) Successful in 3m44s
Deploy / Deploy (push) Successful in 12s
2026-07-05 11:54:07 +02:00
Chaoscaot 47fb4da85b Fix Inventory
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 12s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-20 21:43:05 +02:00
YoyoNow 0eef22aab0 Fix ServerStarter.tempWorld
Deploy / Build (push) Successful in 2m10s
Deploy / Deploy (push) Successful in 10s
2026-06-20 17:42:16 +02:00
D4rkr34lm 013d18614f Fix player nametags showing
Deploy / Build (push) Successful in 2m18s
Deploy / Deploy (push) Successful in 13s
2026-06-20 17:20:25 +02:00
YoyoNow c7c1ab64e0 Fix BoatRace
Deploy / Build (push) Successful in 2m16s
Deploy / Deploy (push) Successful in 12s
2026-06-18 15:30:07 +02:00
Chaoscaot b68a27fbb6 Merge pull request 'SWUI V2' (#418) from swui-v2 into main
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #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
Pull Request Build / Build (pull_request) Successful in 2m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-06-17 21:49:52 +02:00
Chaoscaot 7af586ec16 Fix Observer
Pull Request Build / Build (pull_request) Successful in 1m59s
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
Deploy / Build (push) Successful in 2m50s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #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
Deploy / Build (push) Successful in 2m52s
Deploy / Deploy (push) Successful in 19s
Reviewed-on: #435
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-06-17 21:23:33 +02:00
D4rkr34lm e07298e748 Move listener to permanent
Pull Request Build / Build (pull_request) Successful in 1m42s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 16s
2026-06-17 21:21:17 +02:00
YoyoNow e1df793e9f Merge pull request 'VelocityCore /check command' (#430) from VelocityCore/CheckCommand into main
Deploy / Build (push) Successful in 2m20s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #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
Deploy / Build (push) Successful in 2m47s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #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
Pull Request Build / Build (pull_request) Successful in 1m34s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-06-17 21:13:57 +02:00
D4rkr34lm d7ba19049a Add event handler
Pull Request Build / Build (pull_request) Successful in 2m20s
2026-06-17 21:10:55 +02:00
D4rkr34lm 47909b6f07 Add listener to prevent dried ghasts from growing
Pull Request Build / Build (pull_request) Successful in 2m2s
2026-06-17 21:09:07 +02:00
YoyoNow 48846a698f Fix TestblockCommand tab complete order
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 10s
2026-06-17 21:04:34 +02:00
D4rkr34lm b771c95b99 Fix advanced flag and add lsp files to gitignore
Pull Request Build / Build (pull_request) Successful in 1m43s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 15s
2026-06-17 20:28:33 +02:00
YoyoNow d0aada2b00 Deactivate AdvancementsManager
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 11s
2026-06-17 16:16:39 +02:00
YoyoNow 6522fc77f2 Improve color gradient
Pull Request Build / Build (pull_request) Successful in 1m21s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 10s
2026-06-17 11:14:53 +02:00
YoyoNow 27e01a56ae Improve CheckCommand
Pull Request Build / Build (pull_request) Successful in 1m24s
2026-06-17 11:09:32 +02:00
YoyoNow ed89770c0f Fix ConcurrentModificationException
Pull Request Build / Build (pull_request) Successful in 1m22s
2026-06-17 11:04:07 +02:00
YoyoNow 3ec3c90f04 Fix message on join
Pull Request Build / Build (pull_request) Successful in 1m22s
2026-06-17 10:57:04 +02:00
YoyoNow 73d4ed26c8 Implement CheckCommand for Checkers not having Check perm
Pull Request Build / Build (pull_request) Successful in 1m23s
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
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #429
2026-06-17 10:24:21 +02:00
YoyoNow 6599dd026a Update CustomMap
Deploy / Build (push) Successful in 2m10s
Deploy / Deploy (push) Successful in 10s
2026-06-15 09:24:46 +02:00
YoyoNow 03052b677f Update CustomMap
Deploy / Build (push) Successful in 2m19s
Deploy / Deploy (push) Successful in 12s
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
Deploy / Build (push) Successful in 2m45s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #427
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-14 21:47:31 +02:00
D4rkr34lm 7fb7f46ca7 Fix path issues
Pull Request Build / Build (pull_request) Successful in 1m52s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 11s
2026-06-14 00:58:41 +02:00
YoyoNow 1269b7f00a Fix NoClipCommand
Deploy / Build (push) Successful in 2m16s
Deploy / Deploy (push) Successful in 12s
2026-06-12 22:16:00 +02:00
YoyoNow 91a0685724 Fix Missile spawning
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 10s
2026-06-12 21:41:20 +02:00
YoyoNow 72dd2ef59a Fix Missile spawning
Deploy / Build (push) Successful in 2m20s
Deploy / Deploy (push) Successful in 11s
2026-06-12 20:43:43 +02:00
YoyoNow 54a1549973 Fix Missile spawning
Deploy / Build (push) Successful in 2m42s
Deploy / Deploy (push) Successful in 11s
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
Deploy / Build (push) Successful in 2m29s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #426
2026-06-12 19:59:48 +02:00
D4rkr34lm 60dc5e4442 Fix formatiing
Pull Request Build / Build (pull_request) Successful in 1m22s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-06-12 19:56:12 +02:00
D4rkr34lm 4cdaf759af Fix mixup of dimensions in autochecker
Pull Request Build / Build (pull_request) Successful in 1m22s
2026-06-12 19:54:06 +02:00
YoyoNow 6e919d9148 Fix AdvancementsManager
Pull Request Build / Build (pull_request) Successful in 1m36s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 7s
(cherry picked from commit c221989f9c6128f55e84bb260a9b319193934edf)
2026-06-12 16:29:28 +02:00
YoyoNow a20ec8c93d Add comment in Items
Pull Request Build / Build (pull_request) Successful in 1m34s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-06-12 15:36:21 +02:00
YoyoNow 18b65a2984 Remove item.json
Pull Request Build / Build (pull_request) Successful in 1m34s
Improve AdvancementsManager
2026-06-12 15:35:13 +02:00
YoyoNow 669235709e Fix WorldEditListener
Deploy / Build (push) Successful in 2m11s
Deploy / Deploy (push) Successful in 11s
2026-06-12 15:14:09 +02:00
YoyoNow 796e154c1c Fix paper in inventory
Deploy / Build (push) Successful in 2m23s
Deploy / Deploy (push) Successful in 11s
2026-06-12 15:07:46 +02:00
YoyoNow 9efe35fe0d Update LobbySystem run task
Deploy / Build (push) Successful in 2m25s
Deploy / Deploy (push) Successful in 10s
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
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-06-12 14:22:44 +02:00
YoyoNow b88e592e79 Move item.json
Pull Request Build / Build (pull_request) Failing after 1m4s
2026-06-12 14:21:45 +02:00
YoyoNow 914134600e Improve Advancements performance
Pull Request Build / Build (pull_request) Successful in 1m30s
2026-06-12 14:19:47 +02:00
Chaoscaot 27877938bc Add support for GameMode templates and YAML-based configuration handling in DevCommand.
Deploy / Build (push) Successful in 2m23s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-12 12:29:56 +02:00
YoyoNow 701964c2f2 Fix DevCommand.kt
Deploy / Build (push) Successful in 2m56s
Deploy / Deploy (push) Successful in 11s
2026-06-12 12:15:07 +02:00
Chaoscaot 70c8678c60 Refactor rendering system: Introduced RenderObject abstraction, replaced RenderBoundary with ObserverListener, and updated slot calculation for inventory types.
Pull Request Build / Build (pull_request) Successful in 1m58s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-12 12:00:04 +02:00
YoyoNow 6cbfc94e6d Merge pull request 'Access widener for paper' (#420) from AccessWidener into main
Deploy / Build (push) Successful in 2m53s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #420
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-06-12 11:16:33 +02:00
YoyoNow c0ff123279 Fix EntityDamage only applying cancel for Player
Deploy / Build (push) Successful in 2m34s
Deploy / Deploy (push) Successful in 11s
2026-06-12 11:09:13 +02:00
YoyoNow 5511a1f08e Fix steamwar.devserver.gradle
Pull Request Build / Build (pull_request) Successful in 2m1s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-06-12 10:41:18 +02:00
YoyoNow 8c8da355bb Fix build.yml
Pull Request Build / Build (pull_request) Successful in 2m3s
2026-06-12 10:02:34 +02:00
Chaoscaot 7326ed4aa0 Merge pull request 'Remove some deprecated code in favor of newer code' (#421) from RemoveDeprecatedCode into main
Deploy / Build (push) Successful in 2m0s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #421
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-06-12 09:58:05 +02:00
YoyoNow 2d59eb81c7 Fix ColorInit and CustomMap deprecation warnings
Pull Request Build / Build (pull_request) Successful in 2m1s
2026-06-12 09:49:32 +02:00
YoyoNow 711920464a Remove some deprecated code in favor of newer code
Pull Request Build / Build (pull_request) Successful in 1m14s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-06-12 09:37:43 +02:00
YoyoNow 117dbd08ae Implement startup arguments into steamwar.devserver.gradle
Pull Request Build / Build (pull_request) Successful in 2m2s
2026-06-11 23:54:42 +02:00
YoyoNow b36464e69e Implement Velocity changes
Pull Request Build / Build (pull_request) Successful in 2m3s
2026-06-11 23:50:34 +02:00
YoyoNow f5ac006c0c Fix REntity.EntityDataPacketBuilder 2026-06-11 23:49:38 +02:00
YoyoNow 414bfbfe3c Fix ClassTransformer public constructor 2026-06-11 23:48:33 +02:00
YoyoNow c362a3e1f0 Remove unused code
Pull Request Build / Build (pull_request) Successful in 2m2s
2026-06-11 23:24:11 +02:00
YoyoNow 2b43af8851 Remove unneded reflection
Pull Request Build / Build (pull_request) Successful in 2m2s
2026-06-11 23:22:05 +02:00
YoyoNow 1590f8f0ee Remove Reflection
Pull Request Build / Build (pull_request) Successful in 2m4s
2026-06-11 23:18:22 +02:00
YoyoNow 932732737d Unreflect more stuff
Pull Request Build / Build (pull_request) Successful in 2m4s
2026-06-11 22:35:13 +02:00
YoyoNow 2bc164c1b0 Extract widener definition into a widener.gradle.kts plugin
Pull Request Build / Build (pull_request) Successful in 2m2s
2026-06-11 20:38:33 +02:00
YoyoNow aa66b3dc83 Optimize imports
Pull Request Build / Build (pull_request) Successful in 1m24s
2026-06-11 18:29:44 +02:00
YoyoNow f5d9c6e175 Unreflect everything
Pull Request Build / Build (pull_request) Successful in 1m23s
2026-06-11 18:26:15 +02:00
YoyoNow 36b31fac77 Remove unneeded code
Pull Request Build / Build (pull_request) Successful in 1m21s
Cleanup build.gradle.kts
2026-06-11 13:49:35 +02:00
YoyoNow 641cefad01 Add comments to bausystem.accesswidener
Pull Request Build / Build (pull_request) Successful in 1m22s
2026-06-11 13:46:55 +02:00
YoyoNow eb866125ea Remove reflection from BauSystem 2026-06-11 13:45:49 +02:00
YoyoNow 961331f029 Fix Agent and WideningTransformer and ClassPatcher 2026-06-11 13:19:04 +02:00
YoyoNow 786257ad0e Add initial AccessWidener 2026-06-11 12:22:44 +02:00
Chaoscaot 997292d58e Merge branch 'main' into swui-v2
Pull Request Build / Build (pull_request) Successful in 1m54s
2026-06-10 21:43:25 +02:00
Chaoscaot 8050f51424 Cleanup for Merge
Pull Request Build / Build (pull_request) Successful in 1m40s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 21:43:02 +02:00
YoyoNow e176b3bca8 Fix steamwar.devserver.gradle 'worldName' parameter
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 11s
2026-06-10 20:46:13 +02:00
Chaoscaot a6681ffaf6 Add Top-Level State and more Utils
Pull Request Build / Build (pull_request) Successful in 1m21s
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
Pull Request Build / Build (pull_request) Successful in 1m45s
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
Pull Request Build / Build (pull_request) Successful in 1m35s
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
YoyoNow f81f05c3d0 Merge pull request 'Add RedstoneEngineCommand' (#406) from BauSystem/RedstoneEngineCommand into main
Deploy / Build (push) Successful in 2m15s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #406
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-06-10 09:04:15 +02:00
YoyoNow 0afb6ce06a Merge branch 'main' into BauSystem/RedstoneEngineCommand
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 14s
Pull Request Build / Build (pull_request) Successful in 1m24s
2026-06-10 09:03:55 +02:00
Chaoscaot 5ce69e6b7a SWUI V2
Pull Request Build / Build (pull_request) Successful in 1m19s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-06-10 00:36:18 +02:00
YoyoNow a938abde3f Add 'debug' property to enable/disable debugger
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 10s
2026-06-09 23:00:46 +02:00
YoyoNow ec9b0387c5 Fix permission for BlastResistanceCommand
Deploy / Build (push) Successful in 2m0s
Deploy / Deploy (push) Successful in 12s
2026-06-09 16:42:40 +02:00
YoyoNow 03c3d49659 Add BlastResistanceCommand
Deploy / Build (push) Successful in 2m10s
Deploy / Deploy (push) Successful in 11s
2026-06-09 16:38:22 +02:00
Chaoscaot 8d9a77ab67 Merge pull request 'chore(VelocityCore): reennable replays for serverteam' (#417) from wip/VelocityCore-reenable-replays-for-serverteam into main
Deploy / Build (push) Successful in 1m57s
Deploy / Deploy (push) Successful in 13s
Reviewed-on: #417
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-06-07 00:06:07 +02:00
D4rkr34lm fc2997e011 Rennable replays for serverteam
Pull Request Build / Build (pull_request) Successful in 1m13s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-06-06 12:17:23 +02:00
D4rkr34lm 8eb5f5ddf2 fix(BauSystem): cursor not properly disapearing
Deploy / Build (push) Successful in 1m57s
Deploy / Deploy (push) Successful in 11s
2026-06-03 21:23:36 +02:00
YoyoNow aa807060f4 Merge pull request 'fix(SpigotCore): small collection of rendering bugs in new cursor' (#413) from BauSystem/fix-small-sim-cursor-bug into main
Deploy / Build (push) Successful in 1m58s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #413
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-02 21:39:13 +02:00
D4rkr34lm 9bbbab9d4b Fix collection of rendering issues
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-06-02 21:33:31 +02:00
YoyoNow 7cca4ada10 Merge pull request 'refactor(BauSystem): Extract sim cursor into generic curser and refactor sim cursor' (#410) from BauSystem/refactor-sim-cursor-no2 into main
Deploy / Build (push) Successful in 2m21s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #410
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-02 20:22:00 +02:00
YoyoNow 725e6df047 Merge pull request 'fix(SpigotCore): versions above 1.21.6 being kicked from arena' (#412) from SpigotCore/fix-newer-version-being-kicked-from-arena into main
Deploy / Build (push) Successful in 2m52s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #412
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-06-02 20:19:57 +02:00
D4rkr34lm f3ce124a23 Make dev velocity easier to debug and fix version issue
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 12s
Pull Request Build / Build (pull_request) Successful in 1m42s
2026-06-02 20:18:13 +02:00
D4rkr34lm e83f72a53e Further simplification
Pull Request Build / Build (pull_request) Successful in 1m11s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 12s
2026-06-01 22:01:52 +02:00
D4rkr34lm def0c19e43 Refactor simulation cursor to use new generic cursor
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-06-01 21:51:54 +02:00
D4rkr34lm 3810ccd63d Add proper onclick handleing 2026-06-01 21:27:34 +02:00
YoyoNow 9e43d5cd1b Add more Advancements in progression
Pull Request Build / Build (pull_request) Successful in 1m30s
2026-06-01 14:03:50 +02:00
YoyoNow 2ad9ae3c7f Fix Advancements Placements
Pull Request Build / Build (pull_request) Successful in 1m10s
2026-05-31 23:04:08 +02:00
YoyoNow 847eb3fe5d Add even more Advancements
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-31 22:31:02 +02:00
YoyoNow 8fa9f7b0d3 Add even more Advancements
Pull Request Build / Build (pull_request) Successful in 1m9s
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
Pull Request Build / Build (pull_request) Successful in 1m5s
Add Advancements
Add AdvancementsManager
Add SelectAdvancementTabPacket
Add item.json
Update ConnectionListener
2026-05-31 18:09:44 +02:00
D4rkr34lm a018af1c8a Refactor to use Player components for better usability 2026-05-31 13:20:24 +02:00
YoyoNow fd8f942014 Fix RedstoneEngine not registering
Pull Request Build / Build (pull_request) Successful in 1m8s
2026-05-31 11:37:43 +02:00
YoyoNow eab8826583 Fix RedstoneEngine not registering
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-31 11:36:21 +02:00
YoyoNow bc0177df43 Add ExperimentalCommand
Pull Request Build / Build (pull_request) Successful in 1m7s
2026-05-31 00:56:05 +02:00
YoyoNow 1dc78b8eb8 Add RedstoneEngineCommand
Pull Request Build / Build (pull_request) Successful in 1m7s
2026-05-31 00:44:56 +02:00
YoyoNow a9fb982143 Merge pull request 'Fix WorldDir of Event servers' (#405) from VelocityCore/FixEventWorldDir into main
Deploy / Build (push) Successful in 1m56s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #405
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-30 18:33:17 +02:00
YoyoNow 5b8d881e01 Fix WorldDir of Event servers
Pull Request Build / Build (pull_request) Successful in 1m7s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-30 18:30:51 +02:00
YoyoNow eb55f4b395 Merge pull request 'Remove global Entity Interact callback' (#404) from SpigotCore/RemoveGlobalEntityServerCallback into main
Deploy / Build (push) Successful in 1m56s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #404
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-30 15:27:45 +02:00
YoyoNow 273db91d06 Fix compile
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 10s
2026-05-30 15:24:20 +02:00
YoyoNow 983ad544c1 Remove global Entity Interact callback
Pull Request Build / Build (pull_request) Failing after 55s
2026-05-30 15:18:37 +02:00
YoyoNow a6a34b2221 Fix Schem add on WGS Schems
Deploy / Build (push) Successful in 1m52s
Deploy / Deploy (push) Successful in 11s
2026-05-30 14:13:08 +02:00
YoyoNow 6c6bd19038 Merge pull request 'fix(BauSystem): interaction with trace entity not showing details text' (#398) from BauSystem/fix-interaction-with-trace-entity into main
Deploy / Build (push) Successful in 1m53s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #398
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-05-30 13:35:35 +02:00
D4rkr34lm 89e05cd109 Remove remnatn of old impl
Pull Request Build / Build (pull_request) Successful in 1m11s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-30 13:30:47 +02:00
D4rkr34lm ea9d7ac584 Refactor to use better impl of interaction entity in REntity system
Pull Request Build / Build (pull_request) Failing after 57s
2026-05-30 13:29:50 +02:00
D4rkr34lm 17e1cf53b0 Merge branch 'main' into BauSystem/fix-interaction-with-trace-entity
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-30 13:24:43 +02:00
YoyoNow f64f337f17 Merge pull request 'Add RInteraction Entity' (#403) from SpigotCore/RInteraction into main
Deploy / Build (push) Successful in 1m59s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #403
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-30 13:22:35 +02:00
YoyoNow c5f5be7d58 Add RInteraction Entity
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-30 13:17:49 +02:00
Chaoscaot 9f18644763 Merge pull request 'fix(FightSystem): arrow stopper removing entites not shot by player (#399)' (#402) from wip/399-fix-error-stopper-for-dispensers into main
Deploy / Build (push) Successful in 1m58s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #402
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-30 12:11:12 +02:00
D4rkr34lm 1de17d27f4 Fix arrow stopper
Pull Request Build / Build (pull_request) Successful in 1m15s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-30 11:55:59 +02:00
D4rkr34lm 3cd0db9bdf Merge branch 'main' into BauSystem/fix-interaction-with-trace-entity
Pull Request Build / Build (pull_request) Successful in 1m6s
2026-05-25 21:32:12 +02:00
D4rkr34lm 9711b48f2f Fix interaction with trace entity not showing detail text
Pull Request Build / Build (pull_request) Failing after 1m3s
2026-05-25 18:20:42 +02:00
Chaoscaot 9934b8bbb2 Fix TNTLeague InviteCommand.kt
Deploy / Build (push) Successful in 1m55s
Deploy / Deploy (push) Successful in 12s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-25 01:55:20 +02:00
Chaoscaot 6447265b90 Merge pull request 'feat(BauSystem): use display entity to render trace' (#397) from BauSystem/use-display-entities-for-trace-render into main
Deploy / Build (push) Successful in 1m57s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #397
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-25 01:40:30 +02:00
D4rkr34lm 71258318db Replace trace rendering by fallingblockentity with display entity for better accuracy
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 34s
2026-05-24 23:39:50 +02:00
Chaoscaot 52e95e2649 Merge pull request 'fix(VelocityCore): disable replays' (#395) from disable-replays into main
Deploy / Build (push) Successful in 2m10s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #395
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-24 13:45:32 +02:00
D4rkr34lm de6ac2cf20 fix
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 10s
Pull Request Build / Build (pull_request) Successful in 1m20s
2026-05-24 13:44:57 +02:00
D4rkr34lm 628001e693 Disable Replays
Pull Request Build / Build (pull_request) Successful in 1m8s
2026-05-24 13:42:08 +02:00
Chaoscaot 47c148d64a Merge pull request 'fix(SpigotCore): techhider not hiding waterlogged blocks if neccecary' (#393) from fix-techhider-not-hidding-waterlogged-blocks into main
Deploy / Build (push) Successful in 1m56s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #393
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-23 16:33:11 +02:00
D4rkr34lm 78617d5a98 another fix
Pull Request Build / Build (pull_request) Successful in 1m9s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-05-23 16:15:31 +02:00
D4rkr34lm 69b924ded6 fix techhider not hiding waterlogged blocks if neccecary
Pull Request Build / Build (pull_request) Successful in 1m7s
2026-05-23 12:29:19 +02:00
YoyoNow 002f7e5542 Merge pull request 'fix(FightSystem): techhider being active in check and test state' (#392) from fix-techhider-being-active-in-check-n-test-arena into main
Deploy / Build (push) Successful in 2m1s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #392
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-05-23 06:23:16 +02:00
D4rkr34lm 5d70f75ac9 Move techhider init into enable to prevent always active even in check and test state
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-22 23:12:39 +02:00
YoyoNow 7f21a31ec9 Merge pull request 'refactor(SpigotCore): Techhider to ensure safety and improve reviewablity' (#338) from FightSystem/fix-tech-and-hull-hider into main
Deploy / Build (push) Successful in 2m3s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #338
2026-05-22 21:37:03 +02:00
YoyoNow 23b5ab3e82 Fix build
Pull Request Build / Build (pull_request) Successful in 1m15s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-05-22 21:35:01 +02:00
YoyoNow 4f9fe07951 Fix final formatting stuff
Pull Request Build / Build (pull_request) Failing after 1m7s
2026-05-22 21:29:58 +02:00
YoyoNow 3bcff4c5ce Merge pull request 'perf(FightSystem): increase chunk hiding performance by skipping irrelavant chunks' (#385) from FightSystem/Optimize-new-techhider into FightSystem/fix-tech-and-hull-hider
Pull Request Build / Build (pull_request) Successful in 1m25s
Reviewed-on: #385
Reviewed-by: YoyoNow <4+yoyonow@noreply.localhost>
2026-05-22 20:52:11 +02:00
D4rkr34lm 1810cb7546 Fix inlineing
Pull Request Build / Build (pull_request) Successful in 1m21s
2026-05-22 20:51:24 +02:00
D4rkr34lm e55ca911c4 Inline get all regions
Pull Request Build / Build (pull_request) Successful in 1m12s
2026-05-22 20:41:05 +02:00
D4rkr34lm 793f2de6c3 Sync with base branch
Pull Request Build / Build (pull_request) Successful in 1m13s
2026-05-22 19:42:36 +02:00
D4rkr34lm 54fa47bd99 Ensure parity with old techhider by suppressing select packets
Pull Request Build / Build (pull_request) Successful in 1m11s
2026-05-22 19:39:57 +02:00
YoyoNow 14a770b207 Merge pull request 'fix(BauSystem): tick step bossbar remaining visable' (#391) from fix-390-fix-tickstep-bosbar-not-disapearing into main
Deploy / Build (push) Successful in 1m53s
Deploy / Deploy (push) Successful in 12s
Reviewed-on: #391
2026-05-22 18:56:30 +02:00
D4rkr34lm 7b3a04f4eb Remove unused custom event
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-22 18:49:51 +02:00
D4rkr34lm f2a06057a8 Fix tick step bossbar remaining visable
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-22 18:46:36 +02:00
D4rkr34lm e11f3f7cbc Fix preschem state and techider not being always active
Pull Request Build / Build (pull_request) Successful in 1m12s
2026-05-22 18:27:53 +02:00
D4rkr34lm ebc10c1ce4 Fix constructor visiblity
Pull Request Build / Build (pull_request) Successful in 1m13s
2026-05-22 17:57:15 +02:00
D4rkr34lm d682e35159 Resolve open comments
Pull Request Build / Build (pull_request) Successful in 1m12s
2026-05-22 17:55:12 +02:00
D4rkr34lm 7d74eb0c09 add old techhider to skip supporting bausystem for now
Pull Request Build / Build (pull_request) Successful in 1m11s
2026-05-22 17:40:33 +02:00
D4rkr34lm 7e18207b87 fix entities not despawning
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-22 16:32:49 +02:00
YoyoNow 72b23ad116 Add filling off Hull for reset and paste with either visible blocks or occluding blocks
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-22 16:24:34 +02:00
YoyoNow c508627d92 Merge pull request 'fix(BauSystem): techhider bypass on bau by middleclick pick' (#389) from fix-387-bau-techhider-bypass-by-middleclick into main
Deploy / Build (push) Successful in 1m56s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #389
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-22 10:17:19 +02:00
D4rkr34lm 93ff982649 fix techhider bypass on bau by middleclick pick
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-21 23:57:38 +02:00
D4rkr34lm 21f6394359 Fix section packet being unnececarily reconstructed
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-21 22:20:40 +02:00
D4rkr34lm 29d0c8978c Rmeove old player join quickfix
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-21 22:00:15 +02:00
D4rkr34lm 7366f83b15 Merge branch 'FightSystem/fix-tech-and-hull-hider' into FightSystem/Optimize-new-techhider
Pull Request Build / Build (pull_request) Failing after 1m8s
2026-05-21 21:57:41 +02:00
YoyoNow 9240bcfd5f Add blockUsedForObfuscation
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-21 20:57:59 +02:00
D4rkr34lm bede8caa82 Add chunk skipping optimisation
Pull Request Build / Build (pull_request) Failing after 1m8s
2026-05-21 20:20:18 +02:00
D4rkr34lm 108aa2af9a remove unused reflection class
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-21 18:46:00 +02:00
D4rkr34lm d07a86c13f remove container hiding as it has no lacalaity mapping posibility
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-21 18:41:55 +02:00
D4rkr34lm 29106d5bb5 Add bundle packet handling
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-21 18:20:15 +02:00
YoyoNow 32fd4b4630 Add Sound handling
Pull Request Build / Build (pull_request) Failing after 1m5s
2026-05-21 18:11:42 +02:00
YoyoNow c241aef932 Add BlockEntityType handling
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-21 17:53:51 +02:00
D4rkr34lm 2db24ef2eb Merge remote-tracking branch 'origin/FightSystem/fix-tech-and-hull-hider' into FightSystem/fix-tech-and-hull-hider
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-21 15:08:41 +02:00
D4rkr34lm a2caa79f99 Erste bugs ausgemerzt 2026-05-21 15:06:33 +02:00
YoyoNow e49cfa9495 Fix duplicates in CouncilChannel
Deploy / Build (push) Successful in 1m52s
Deploy / Deploy (push) Successful in 11s
2026-05-21 13:19:27 +02:00
YoyoNow 1f44b3169e Remove unused stuff
Pull Request Build / Build (pull_request) Failing after 1m7s
2026-05-21 13:05:16 +02:00
YoyoNow 49fafa5955 Fix build
Pull Request Build / Build (pull_request) Failing after 1m9s
2026-05-21 13:00:53 +02:00
YoyoNow c81e6b15e5 Merge branch 'main' into FightSystem/fix-tech-and-hull-hider
Pull Request Build / Build (pull_request) Failing after 1m5s
# Conflicts:
#	FightSystem/FightSystem_Core/src/de/steamwar/fightsystem/utils/HullHider.java
#	SpigotCore/SpigotCore_Main/src/de/steamwar/core/events/AntiNocom.java
2026-05-21 12:59:22 +02:00
D4rkr34lm dc0365834a fixes
Pull Request Build / Build (pull_request) Failing after 55s
2026-05-21 12:13:41 +02:00
YoyoNow 13334e03a4 Add Debugger for remote JVM
Deploy / Build (push) Successful in 2m10s
Deploy / Deploy (push) Successful in 15s
2026-05-21 12:11:40 +02:00
YoyoNow b35b2c0138 Add jvmArgs to steamwar.devserver.gradle
Deploy / Build (push) Successful in 2m8s
Deploy / Deploy (push) Successful in 13s
2026-05-21 11:31:39 +02:00
YoyoNow 6ef311ce68 Merge pull request 'Fix CouncilChannel' (#384) from VelocityCore/FixDiscordBot into main
Deploy / Build (push) Successful in 1m52s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #384
2026-05-21 11:23:06 +02:00
YoyoNow 68d9c55525 Downgrade JDA to 5.5.1
Pull Request Build / Build (pull_request) Successful in 1m9s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-21 11:21:35 +02:00
YoyoNow dcd70c5ced Fix CouncilChannel
Pull Request Build / Build (pull_request) Failing after 1m2s
Update JDA to 6.4.1
2026-05-21 11:20:37 +02:00
D4rkr34lm a1d22b7d77 twast
Pull Request Build / Build (pull_request) Failing after 53s
2026-05-21 10:26:46 +02:00
YoyoNow 3b6fdbeec3 Fix CouncilChannel
Deploy / Build (push) Successful in 1m52s
Deploy / Deploy (push) Successful in 11s
2026-05-21 10:16:17 +02:00
YoyoNow 714f86a55b Improve Tablist Header colors
Deploy / Build (push) Successful in 1m58s
Deploy / Deploy (push) Successful in 14s
2026-05-21 10:02:34 +02:00
YoyoNow a177cc4faf Fix Tablist
Deploy / Build (push) Successful in 1m47s
Deploy / Deploy (push) Successful in 13s
Add UpdateTeamsPacketImpl back
2026-05-21 09:54:48 +02:00
YoyoNow 09aa2ee22c Fix compile of VelocityCore
Deploy / Build (push) Successful in 1m53s
Deploy / Deploy (push) Successful in 12s
2026-05-21 08:43:28 +02:00
YoyoNow b8499a7a8a Fix Tablist
Deploy / Build (push) Failing after 1m12s
Deploy / Deploy (push) Has been skipped
2026-05-21 08:36:24 +02:00
YoyoNow e50bff3d38 Merge pull request 'Unwrap the wrappers' (#381) from UnwrapWrapper into main
Deploy / Build (push) Successful in 1m54s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #381
2026-05-21 07:56:16 +02:00
D4rkr34lm 8424f842c3 resolve last compile issue in techhider
Pull Request Build / Build (pull_request) Failing after 1m4s
2026-05-21 00:18:12 +02:00
YoyoNow 8f23f57415 Fix TeamCommand
Deploy / Build (push) Successful in 1m53s
Deploy / Deploy (push) Successful in 11s
2026-05-20 23:01:50 +02:00
YoyoNow 3b65b93e73 Merge pull request 'SW Prefix Implementation' (#383) from Jaki/SteamWar:main into main
Deploy / Build (push) Successful in 1m56s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #383
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-20 22:47:46 +02:00
Jakob Schulz 4a458f0e92 fix: update team name checks to use constants for better readability
Pull Request Build / Build (pull_request) Successful in 1m7s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-20 22:38:23 +02:00
Jakob Schulz 5f5a98bcd6 refactor team prefix handling and improve configuration parsing
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-20 22:35:19 +02:00
D4rkr34lm 72df919312 cut down old protocol wrapper
Pull Request Build / Build (pull_request) Failing after 57s
2026-05-20 21:47:17 +02:00
D4rkr34lm 7ed36fe56e removed reflections form anti nocom guard
Pull Request Build / Build (pull_request) Failing after 59s
2026-05-20 21:44:28 +02:00
D4rkr34lm a7a8c4d051 Fix imports in tinyProtocol
Pull Request Build / Build (pull_request) Failing after 59s
2026-05-20 21:33:01 +02:00
D4rkr34lm 5da3767378 Started embedding new techhider into fight system
Pull Request Build / Build (pull_request) Failing after 58s
2026-05-20 21:30:44 +02:00
Jakob Schulz 53f98d4cd7 evaluate the config preference once per message
Pull Request Build / Build (pull_request) Successful in 1m7s
2026-05-20 19:30:06 +02:00
Jakob Schulz 48fb6b5ed7 add parsing for chat prefix mode configuration 2026-05-20 19:06:05 +02:00
Jakob Schulz 24d8ec7301 add "/team prefix" command 2026-05-20 18:34:10 +02:00
D4rkr34lm ba29e5cf23 Add tinyProtocol Handler for techhider
Pull Request Build / Build (pull_request) Failing after 55s
2026-05-20 18:28:39 +02:00
Jakob Schulz a5992a9e4e add "/team info SW" command to display the serverteam 2026-05-20 17:44:52 +02:00
Chaoscaot e94eac9b9d Fix Cauldrons in Schematic GUI
Deploy / Build (push) Successful in 1m48s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-20 16:50:04 +02:00
YoyoNow a000beee20 Remove TinyProtocol.addTypedFilter
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-20 13:52:13 +02:00
YoyoNow 2fd6c40b15 Remove some more wrappers
Pull Request Build / Build (pull_request) Successful in 1m11s
2026-05-20 13:27:49 +02:00
D4rkr34lm 32a2cbb4dd Finish initial implementation of logic
Pull Request Build / Build (pull_request) Failing after 56s
2026-05-19 22:47:22 +02:00
D4rkr34lm cf7a1ee086 Implement logic for hiding chunk data (not finished)
Pull Request Build / Build (pull_request) Failing after 55s
2026-05-19 22:17:41 +02:00
YoyoNow 8da7956523 Fix build
Pull Request Build / Build (pull_request) Successful in 1m10s
2026-05-19 21:03:38 +02:00
YoyoNow 9b821ff08f Unwrap the wrappers
Pull Request Build / Build (pull_request) Failing after 1m2s
2026-05-19 19:41:04 +02:00
YoyoNow ae6f279dcf Merge pull request 'add setting to disable block generators' (#375) from Jaki/SteamWar:main into main
Deploy / Build (push) Successful in 1m58s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #375
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-19 19:25:25 +02:00
Jakob Schulz deb56c0c02 rename property
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-19 19:24:03 +02:00
YoyoNow aead25650e Add debug output to TinyProtocol
Deploy / Build (push) Successful in 1m51s
Deploy / Deploy (push) Successful in 12s
2026-05-19 18:55:46 +02:00
YoyoNow 53ada2de83 Add debug output to TinyProtocol
Deploy / Build (push) Successful in 1m51s
Deploy / Deploy (push) Successful in 12s
2026-05-19 18:50:17 +02:00
YoyoNow 496cc3121c Add debug output to TinyProtocol
Deploy / Build (push) Successful in 2m1s
Deploy / Deploy (push) Successful in 11s
2026-05-19 18:41:15 +02:00
Jakob Schulz e9c766dbbb migrate to per material config
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-19 18:39:10 +02:00
Jakob Schulz 706f6ed743 add setting to disable block generators
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-18 21:26:38 +02:00
D4rkr34lm 270d82eb71 Merge branch 'main' into FightSystem/fix-tech-and-hull-hider
Pull Request Build / Build (pull_request) Failing after 34s
2026-05-17 19:58:16 +02:00
Chaoscaot 6da180136e Merge pull request 'fix(SpigotCore): rEntity move packet using incorrect position' (#372) from fix-rentity-system into main
Deploy / Build (push) Successful in 1m51s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #372
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-17 19:30:45 +02:00
Chaoscaot 463d8336a7 Merge branch 'main' into fix-rentity-system
Pull Request Build / Build (pull_request) Successful in 1m7s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-17 19:29:16 +02:00
Chaoscaot c241b9c264 Merge pull request 'fix-pipeline' (#373) from fix-pipeline into main
Deploy / Build (push) Successful in 1m59s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #373
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-17 19:25:06 +02:00
Chaoscaot b98273a7b2 Fix build, maybe?
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 14s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-17 19:20:44 +02:00
Chaoscaot bd28b133a2 Fix build, maybe?
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-17 19:05:24 +02:00
D4rkr34lm 5c618d03e8 Fix entity move
Pull Request Build / Build (pull_request) Successful in 1m7s
2026-05-17 18:21:33 +02:00
Chaoscaot 89b8a3ea42 Merge pull request 'fix(CI): force clean rebuild in pipeline' (#371) from fix-pipeline into main
Deploy / Build (push) Successful in 1m42s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #371
2026-05-17 15:12:49 +02:00
D4rkr34lm 4198a08cda fix pipeline
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 15s
Pull Request Build / Build (pull_request) Successful in 1m17s
2026-05-17 15:11:32 +02:00
D4rkr34lm 9f319128cc Update multiblock update packet filter 2026-05-17 13:49:46 +02:00
Chaoscaot 088d548d61 Merge pull request 'Format code' (#370) from Format into main
Deploy / Build (push) Successful in 1m26s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #370
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-17 10:59:30 +02:00
YoyoNow e435154c12 Format code
Pull Request Build / Build (pull_request) Successful in 1m10s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-17 10:13:31 +02:00
YoyoNow eceb58b28c Format code
Pull Request Build / Build (pull_request) Successful in 1m13s
2026-05-17 10:12:22 +02:00
YoyoNow 5125453406 Format code 2026-05-17 10:08:06 +02:00
YoyoNow d110df924e Format code
Pull Request Build / Build (pull_request) Successful in 1m12s
2026-05-16 23:08:09 +02:00
YoyoNow 81dd8045f2 Remove unused code
Deploy / Build (push) Successful in 1m29s
Deploy / Deploy (push) Successful in 10s
2026-05-16 22:41:17 +02:00
Chaoscaot 245072f02c Merge pull request 'Remove more Reflection usage' (#368) from ReduceReflection into main
Deploy / Build (push) Successful in 1m36s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #368
2026-05-16 22:24:54 +02:00
YoyoNow 00147f2a74 Optimize imports
Pull Request Build / Build (pull_request) Successful in 1m8s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-05-16 22:23:00 +02:00
YoyoNow fcc370c353 Remove even more useless stuff
Pull Request Build / Build (pull_request) Failing after 1m2s
2026-05-16 22:21:06 +02:00
D4rkr34lm 3bd1cf7167 Even more handlers 2026-05-16 22:12:25 +02:00
YoyoNow cfa650bcf4 Remove more reflection calls
Pull Request Build / Build (pull_request) Successful in 1m6s
2026-05-16 21:41:50 +02:00
YoyoNow ba4ee08489 Remove most Reflection from REntity
Pull Request Build / Build (pull_request) Successful in 1m8s
2026-05-16 21:34:18 +02:00
D4rkr34lm 723a7dc0ca Add handling for container 2026-05-16 20:14:09 +02:00
D4rkr34lm 88de28ed68 Add new handler 2026-05-16 19:25:32 +02:00
D4rkr34lm 6f1a3fe70c Update a lot of handlers and prepare for merge with main 2026-05-16 19:19:49 +02:00
D4rkr34lm 4a43e09a8b Add more handlers 2026-05-16 14:45:36 +02:00
Chaoscaot 6fb018b86b Merge pull request 'Remove MinVersion and MaxVersion' (#362) from CleanupCommonCore into main
Deploy / Build (push) Successful in 1m27s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #362
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-16 14:43:01 +02:00
YoyoNow ec310dfee9 Remove MinVersion and MaxVersion
Pull Request Build / Build (pull_request) Successful in 1m6s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-16 14:41:02 +02:00
YoyoNow 9de5a93997 Remove MinVersion annotation
Deploy / Build (push) Successful in 2m9s
Deploy / Deploy (push) Successful in 11s
2026-05-16 14:37:36 +02:00
Chaoscaot ce88e88859 Merge pull request 'Upgrade all projects to Java 21 and migrate dependencies to Paper and FastAsyncWorldEdit.' (#360) from Refactor/remove-old-dependencies into main
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Reviewed-on: #360
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-16 14:36:59 +02:00
Chaoscaot 5589c6cd20 Merge branch 'main' into Refactor/remove-old-dependencies
Pull Request Build / Build (pull_request) Successful in 1m27s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-16 14:31:11 +02:00
Chaoscaot 35dead9c74 Merge pull request 'Reflection Reduction' (#357) from ReflectionReduction into main
Deploy / Build (push) Successful in 1m51s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #357
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-16 14:29:39 +02:00
YoyoNow f1fbe14e60 Fix ChunkHider
Pull Request Build / Build (pull_request) Successful in 1m12s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 9s
2026-05-16 14:27:07 +02:00
YoyoNow b146c9928f Fix FlatteningWrapper
Pull Request Build / Build (pull_request) Successful in 1m42s
2026-05-16 14:08:29 +02:00
Chaoscaot 136b0f5b97 Refactor to simplify API usage and improve compatibility by replacing legacy methods and adapting to updated libraries.
Pull Request Build / Build (pull_request) Successful in 2m1s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-16 14:08:28 +02:00
Chaoscaot 2d679028c0 Merge remote-tracking branch 'origin/ReflectionReduction' into Refactor/remove-old-dependencies 2026-05-16 14:03:19 +02:00
YoyoNow ce1f947f4b Remove Core.getVersion calls
Pull Request Build / Build (pull_request) Successful in 1m10s
2026-05-16 14:02:57 +02:00
Chaoscaot 5fb51b63c3 Fix Build
Pull Request Build / Build (pull_request) Failing after 1m14s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-16 13:54:37 +02:00
Chaoscaot c04dc8fd86 Merge remote-tracking branch 'refs/remotes/origin/ReflectionReduction' into Refactor/remove-old-dependencies
# Conflicts:
#	MissileWars/build.gradle.kts
2026-05-16 13:53:29 +02:00
YoyoNow ab3970981d Remove more reflection
Pull Request Build / Build (pull_request) Failing after 1m1s
2026-05-16 13:46:42 +02:00
YoyoNow 9e4c9ce04a Remove more reflection
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-16 13:38:10 +02:00
Chaoscaot 44e37467d6 Fix Build
Pull Request Build / Build (pull_request) Failing after 1m21s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-16 13:29:49 +02:00
Chaoscaot 7c74ca014d Upgrade all projects to Java 21 and migrate dependencies to Paper and FastAsyncWorldEdit.
Pull Request Build / Build (pull_request) Failing after 1m13s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-16 13:26:18 +02:00
YoyoNow e7454f6ce8 Fight FightWorld
Pull Request Build / Build (pull_request) Successful in 1m9s
2026-05-16 13:07:06 +02:00
YoyoNow a100d2d798 Remove more Reflection stuff
Pull Request Build / Build (pull_request) Failing after 1m6s
2026-05-16 13:02:20 +02:00
YoyoNow 3c48e7c02d Remove most calls to Reflection.getClass 2026-05-16 13:01:50 +02:00
YoyoNow 2b3c79fcab Merge pull request 'fix(FighSystem): Add chunk packet resend after join to enhance security' (#358) from FightSystem/tech-hider-hardening into main
Deploy / Build (push) Successful in 1m58s
Deploy / Deploy (push) Successful in 10s
Reviewed-on: #358
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-16 12:58:00 +02:00
YoyoNow 7ff778b60a Merge pull request 'UpdateTinyProtocol' (#359) from UpdateTinyProtocol into main
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Reviewed-on: #359
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-16 12:57:15 +02:00
YoyoNow b83476b451 Fix TechhiderbugCommand
Pull Request Build / Build (pull_request) Successful in 1m12s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 8s
2026-05-16 12:28:52 +02:00
YoyoNow 58652cac5c Fix BauSystem build and local CMDFramework build
Pull Request Build / Build (pull_request) Failing after 1m9s
2026-05-16 12:22:40 +02:00
YoyoNow b216438a47 Add SteamWar adaption for TinyProtocol
Pull Request Build / Build (pull_request) Failing after 1m3s
2026-05-16 11:52:06 +02:00
YoyoNow 604657a084 Add singleton to TinyProtocol 2026-05-16 11:37:39 +02:00
YoyoNow 5a57b5f799 Remove Reflection from TinyProtocol 2026-05-16 11:36:09 +02:00
YoyoNow be233c65fe Update TinyProtocol 2026-05-16 11:18:40 +02:00
D4rkr34lm 9f201f8191 update packet codec
Pull Request Build / Build (pull_request) Successful in 1m7s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 14s
2026-05-15 21:50:09 +02:00
Chaoscaot 55c1962294 Fix MissileWars Missile Pasting
Deploy / Build (push) Successful in 1m27s
Deploy / Deploy (push) Successful in 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 20:53:13 +02:00
Chaoscaot 441932b30a Fix MissileWars Missile Pasting
Deploy / Build (push) Successful in 1m30s
Deploy / Deploy (push) Successful in 10s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 20:39:30 +02:00
D4rkr34lm bdecec304a Update with nms based refresh 2026-05-15 20:26:15 +02:00
D4rkr34lm 75e3e77478 Merge branch 'main' into FightSystem/tech-hider-hardening 2026-05-15 20:16:20 +02:00
Chaoscaot 5c93ca6143 Update bug report URL in DiscordTicketType enum
Deploy / Build (push) Successful in 1m24s
Deploy / Deploy (push) Successful in 10s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 16:49:18 +02:00
D4rkr34lm 0452a9faa5 Add processors for a sed of id only entity packets 2026-05-15 16:23:23 +02:00
D4rkr34lm 9a75f38226 Continue 2026-05-15 16:14:05 +02:00
Chaoscaot 6d24aa160f Fix CI
Deploy / Build (push) Successful in 1m28s
Deploy / Deploy (push) Successful in 10s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 16:12:39 +02:00
Chaoscaot 105630bbd8 Fix CI
Deploy / Build (push) Successful in 1m30s
Deploy / Deploy (push) Failing after 8s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 16:09:36 +02:00
Chaoscaot 228ab5b2f2 Merge pull request 'Cleanup Version Code' (#339) from RemoveVersionCode into main
Deploy / Build (push) Failing after 1m34s
Deploy / Deploy (push) Has been skipped
Reviewed-on: #339
2026-05-15 16:07:25 +02:00
Chaoscaot b97fe7e5b1 Merge branch 'main' into RemoveVersionCode
Pull Request Build / Build (pull_request) Successful in 1m18s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 7s
2026-05-15 16:05:42 +02:00
YoyoNow 01db4fa951 Fix CraftbukkitWrapper for FightSystem
Pull Request Build / Build (pull_request) Successful in 1m19s
2026-05-15 16:00:50 +02:00
Chaoscaot cb153b50f1 Merge remote-tracking branch 'origin/main'
Deploy / Build (push) Successful in 1m31s
Deploy / Deploy (push) Successful in 9s
2026-05-15 15:51:06 +02:00
Chaoscaot 8b33bf40c3 Add CLI artifact deployment and service restart steps in build workflow
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:51:01 +02:00
YoyoNow 9a6221b723 Fix DiscordChannel
Deploy / Build (push) Successful in 1m31s
Deploy / Deploy (push) Successful in 8s
2026-05-15 15:44:27 +02:00
Chaoscaot a20b1cb263 Disable blank issues in Gitea configuration
Deploy / Build (push) Successful in 1m38s
Deploy / Deploy (push) Successful in 8s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:39:04 +02:00
Chaoscaot cfe6055083 Disable blank issues in Gitea configuration
Deploy / Build (push) Has started running
Deploy / Deploy (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:38:11 +02:00
Chaoscaot eea9abdc56 Add Templates
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:37:29 +02:00
Chaoscaot 138b94e562 Merge pull request 'Test Backporting' (#354) from test/backporting into main
Deploy / Build (push) Successful in 3m22s
Deploy / Deploy (push) Successful in 7s
Reviewed-on: #354
2026-05-15 15:09:46 +02:00
Chaoscaot d11467bd1b Test Backporting
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 15s
Pull Request Build / Build (pull_request) Successful in 2m44s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:09:28 +02:00
Chaoscaot 7be40d9bf9 Merge pull request 'Test Backporting' (#352) from test/backporting into main
Deploy / Build (push) Successful in 2m1s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #352
2026-05-15 15:03:40 +02:00
Chaoscaot dae8073992 Test Backporting
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 11s
Pull Request Build / Build (pull_request) Successful in 2m15s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:03:22 +02:00
Chaoscaot 143e7dc17c Test Backporting
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 15:03:01 +02:00
Chaoscaot f4ace64173 Merge pull request 'Test Backporting' (#351) from test/backporting into main
Deploy / Build (push) Successful in 2m30s
Deploy / Deploy (push) Successful in 7s
Reviewed-on: #351
2026-05-15 14:55:44 +02:00
Chaoscaot 236b486845 Test Backporting
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 14s
Pull Request Build / Build (pull_request) Successful in 2m13s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:55:13 +02:00
Chaoscaot c666f0228d Test Backporting
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:54:31 +02:00
YoyoNow 81049856b5 Fix build
Pull Request Build / Build (pull_request) Successful in 1m38s
2026-05-15 14:52:17 +02:00
YoyoNow 4813e24848 Remove LegacyBauSystem 2026-05-15 14:52:17 +02:00
YoyoNow d61d001ddf Cleanup FightSystem 2026-05-15 14:52:17 +02:00
YoyoNow 060364abb5 Cleanup SpigotCore 2026-05-15 14:52:17 +02:00
YoyoNow 13185f0e05 Cleanup SchematicSystem 2026-05-15 14:52:17 +02:00
YoyoNow fd266969f5 Cleanup BauSystem 2026-05-15 14:52:17 +02:00
Chaoscaot bd471330e1 Merge pull request 'Test Backporting' (#350) from test/backporting into main
Deploy / Build (push) Successful in 3m31s
Deploy / Deploy (push) Successful in 19s
Reviewed-on: #350
2026-05-15 14:48:42 +02:00
Chaoscaot 92602efa9e Test Backporting
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 10s
Pull Request Build / Build (pull_request) Successful in 2m45s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:48:13 +02:00
Chaoscaot 55a39ac85a Merge remote-tracking branch 'origin/main'
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
2026-05-15 14:47:41 +02:00
Chaoscaot 39898825ef Test Backporting
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:47:37 +02:00
Chaoscaot 59a2d1454e Merge pull request 'Test Backporting' (#349) from test/backporting into main
Deploy / Build (push) Successful in 2m28s
Deploy / Deploy (push) Successful in 11s
Reviewed-on: #349
2026-05-15 14:41:44 +02:00
Chaoscaot 16c324cf32 Test Backporting
Backport CommonCore / Create CommonCore backport PRs (pull_request) Successful in 15s
Pull Request Build / Build (pull_request) Successful in 2m2s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:41:25 +02:00
Chaoscaot b923b98b2c Test Backporting
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:41:06 +02:00
Chaoscaot afca7d5135 Merge pull request 'Test Backporting' (#348) from test/backporting into main
Deploy / Build (push) Successful in 1m31s
Deploy / Deploy (push) Successful in 8s
Reviewed-on: #348
2026-05-15 14:37:22 +02:00
Chaoscaot a05bebcd81 Test Backporting
Pull Request Build / Build (pull_request) Successful in 1m36s
Backport CommonCore / Create CommonCore backport PRs (pull_request) Failing after 11s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:35:30 +02:00
Chaoscaot 02cc8330ca Add automated CommonCore backport workflow
Deploy / Build (push) Successful in 1m46s
Deploy / Deploy (push) Successful in 11s
- Create backport PRs for merged CommonCore changes on `main`
- Auto-merge successful backport PRs into `version/*` branches
- Add opt-out label handling for backports
2026-05-15 14:35:02 +02:00
Chaoscaot f8397b8bab Test Backporting
Deploy / Build (push) Successful in 2m6s
Deploy / Deploy (push) Successful in 7s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:15:35 +02:00
Chaoscaot 38603fbe45 Merge pull request 'Test Backporting' (#347) from test/backporting into main
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Reviewed-on: #347
2026-05-15 14:14:15 +02:00
Chaoscaot 78700e868d Test Backporting
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 11s
Pull Request Build / Build (pull_request) Successful in 2m15s
Pull Request Build / Merge backport (pull_request) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:14:04 +02:00
Chaoscaot 259e8bdb7b Test Backporting
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:13:41 +02:00
Chaoscaot 0ea3c25b7b Merge pull request 'Test Backporting' (#346) from test/backporting into main
Deploy / Build (push) Successful in 2m48s
Deploy / Deploy (push) Successful in 8s
Reviewed-on: #346
2026-05-15 14:02:39 +02:00
Chaoscaot 2fa1b7d329 Test Backporting
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 10s
Pull Request Build / Build (pull_request) Successful in 2m25s
Pull Request Build / Merge backport (pull_request) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:02:24 +02:00
Chaoscaot af805f6ba4 Merge pull request 'Test Backporting' (#345) from test/backporting into main
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Reviewed-on: #345
2026-05-15 14:01:41 +02:00
Chaoscaot 34c361d3f8 Test Backporting
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 8s
Pull Request Build / Build (pull_request) Successful in 2m17s
Pull Request Build / Merge backport (pull_request) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 14:01:22 +02:00
Chaoscaot 83eb621b0f Merge pull request 'Test Backporting' (#344) from test/backporting into main
Deploy / Build (push) Successful in 1m30s
Deploy / Deploy (push) Successful in 7s
Reviewed-on: #344
2026-05-15 13:58:00 +02:00
Chaoscaot 65aaf4857d Test Backporting
Pull Request Build / Build (pull_request) Successful in 2m8s
Pull Request Build / Merge backport (pull_request) Has been skipped
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 8s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:55:12 +02:00
Chaoscaot 7d52447b00 Merge pull request 'Test Backporting' (#343) from test/backporting into main
Deploy / Build (push) Successful in 3m20s
Deploy / Deploy (push) Successful in 9s
Reviewed-on: #343
2026-05-15 13:54:00 +02:00
Chaoscaot 046ab8d1a8 Merge branch 'main' into test/backporting
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 12s
Pull Request Build / Build (pull_request) Successful in 2m49s
Pull Request Build / Merge backport (pull_request) Has been skipped
2026-05-15 13:53:53 +02:00
Chaoscaot 33c032092d Test Backporting
Pull Request Build / Build (pull_request) Successful in 2m7s
Pull Request Build / Merge backport (pull_request) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:53:09 +02:00
Chaoscaot b8eeb93a8f Merge pull request 'Test Backporting' (#342) from test/backporting into main
Deploy / Build (push) Successful in 2m26s
Deploy / Deploy (push) Successful in 7s
Reviewed-on: #342
2026-05-15 13:44:41 +02:00
Chaoscaot e95f68406f Test Backporting
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 16s
Pull Request Build / Build (pull_request) Successful in 2m14s
Pull Request Build / Merge backport (pull_request) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:44:23 +02:00
Chaoscaot c6f432a5c4 Test Backporting
Deploy / Deploy (push) Has been cancelled
Deploy / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:43:56 +02:00
Chaoscaot 9ca7446dba .gitea/workflows/backport-commoncore.yml aktualisiert
Deploy / Build (push) Has started running
Deploy / Deploy (push) Has been cancelled
2026-05-15 13:42:26 +02:00
Chaoscaot 773a1adf64 Merge pull request 'Test Backporting' (#341) from test/backporting into main
Deploy / Build (push) Successful in 1m32s
Deploy / Deploy (push) Successful in 8s
Reviewed-on: #341
2026-05-15 13:38:23 +02:00
Chaoscaot 6afe5d4c0d Test Backporting
Pull Request Build / Build (pull_request) Successful in 1m11s
Pull Request Build / Merge backport (pull_request) Has been skipped
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 13s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:31:49 +02:00
Chaoscaot 755a05fe34 Add merge-backport workflow to automate PR backports after successful builds
Deploy / Build (push) Successful in 1m28s
Deploy / Deploy (push) Successful in 7s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 13:31:11 +02:00
Chaoscaot 202da658ee Refactor workflows: split pull request build, rename deploy, and remove unused steps
Deploy / Build (push) Successful in 1m31s
Deploy / Deploy (push) Successful in 7s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 12:47:00 +02:00
Chaoscaot a5856cf240 Merge pull request 'Test Autobackporting' (#340) from test/backporting into main
Build / Build (push) Successful in 1m37s
Build / Deploy (push) Successful in 7s
Build / Merge backport (push) Has been skipped
Reviewed-on: #340
2026-05-15 12:31:37 +02:00
Chaoscaot 38099e6167 Test Autobackporting
Build / Build (push) Successful in 1m12s
Build / Build (pull_request) Successful in 1m12s
Build / Deploy (push) Has been skipped
Build / Merge backport (push) Has been skipped
Build / Deploy (pull_request) Has been skipped
Build / Merge backport (pull_request) Has been skipped
Backport CommonCore / Backport CommonCore changes (pull_request) Failing after 7s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 12:28:10 +02:00
Chaoscaot d307038e5e Use non basic caching
Build / Build (push) Successful in 3m21s
Build / Deploy (push) Successful in 7s
Build / Merge backport (push) Has been skipped
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 12:07:41 +02:00
Chaoscaot d5aeeaf5e3 Add backport workflow for CommonCore changes and update build.yml
Build / Deploy (push) Has been cancelled
Build / Merge backport (push) Has been cancelled
Build / Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 12:04:02 +02:00
Chaoscaot 134a05ea23 Add build.yml
Build / Build (push) Successful in 3m8s
Build / Deploy (push) Successful in 9s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 11:37:16 +02:00
Chaoscaot db63f2a67c Add build.yml
Build / Build (push) Failing after 3m45s
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 11:29:08 +02:00
Chaoscaot 97a3c3ef35 .gitea/workflows/build.yml aktualisiert
/ Build (push) Successful in 3m54s
2026-05-15 11:09:37 +02:00
Chaoscaot a40e904ab3 .gitea/workflows/build.yml aktualisiert
/ Build (push) Failing after 2m0s
2026-05-15 11:06:54 +02:00
Chaoscaot a8a89b0809 .gitea/workflows/build.yml aktualisiert
/ Build (push) Failing after 5m8s
2026-05-15 10:30:13 +02:00
Chaoscaot 480efd1f8b Add build.yml
/ Build (push) Has been cancelled
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-15 10:11:29 +02:00
YoyoNow 26baccf3c4 Test push 2026-05-15 10:09:02 +02:00
Manuel Frohn 42808f40c0 preclassify packets as safe
SteamWarCI Build failed
2026-05-15 00:48:45 +02:00
Manuel Frohn 57c21122e6 Classify packets by scope
SteamWarCI Build failed
2026-05-15 00:32:09 +02:00
Manuel Frohn 42faba70d9 Add remaining packets with toss handler for now
SteamWarCI Build failed
2026-05-14 22:08:17 +02:00
Manuel Frohn 99e1f01869 Update bypass list with harmless play-client bound packets
SteamWarCI Build failed
2026-05-14 21:38:37 +02:00
Manuel Frohn 13bddbe359 Update bypass list with full set of configuration and login packets
SteamWarCI Build failed
2026-05-14 20:21:36 +02:00
D4rkr34lm 51ff0e1a9f Fix remaining local issues
SteamWarCI Build failed
2026-05-14 11:57:26 +02:00
D4rkr34lm 6766862a00 Refactored over all functionality
SteamWarCI Build failed
2026-05-13 22:48:44 +02:00
Chaoscaot 916f9b2557 Merge pull request 'SteamWar CLI merge' (#330) from feature/steamwar-cli into main
SteamWarCI Build successful
Reviewed-on: #330
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-13 22:42:59 +02:00
Manuel Frohn c30aad179b Continue refactor
SteamWarCI Build failed
2026-05-13 17:20:32 +02:00
Manuel Frohn d3aad6a198 Move over signle block event package processing
SteamWarCI Build failed
2026-05-13 16:24:45 +02:00
Manuel Frohn 744dc67ca9 Move over identified packages from old impl
SteamWarCI Build failed
2026-05-13 15:33:08 +02:00
Manuel Frohn 164a7f5826 Replace tinyProtocolLib with newest version
SteamWarCI Build failed
2026-05-13 14:04:38 +02:00
Manuel Frohn 210cfcf3a6 Add player join chunk refrech
SteamWarCI Build successful
2026-05-13 13:47:29 +02:00
YoyoNow 34992344b2 Fix CheckCommand.accept
SteamWarCI Build successful
2026-05-12 16:47:30 +02:00
YoyoNow 1ea8dea381 Fix WhoisCommand.whois
SteamWarCI Build successful
2026-05-11 21:03:51 +02:00
Chaoscaot 15aa0572f3 Merge pull request 'Implement old bau behavior for WGS' (#332) from old-bau-behavior into main
SteamWarCI Build successful
Reviewed-on: #332
Reviewed-by: D4rkr34lm <dark@steamwar.de>
2026-05-10 18:55:25 +02:00
Chaoscaot 6a843f4a71 Implement old bau behavior for WGS
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-10 11:29:26 +02:00
Chaoscaot a63c1a94ca Fix TNT explosion logic to handle non-TNT entities correctly
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-09 21:10:43 +02:00
Chaoscaot 43263035d9 Merge pull request 'Add DB Indexes for future local Development deployments' (#262) from add-db-indexes into main
SteamWarCI Build successful
Reviewed-on: #262
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-05-09 20:23:56 +02:00
Chaoscaot 42ab55d0f8 Merge branch 'main' into add-db-indexes
SteamWarCI Build successful
# Conflicts:
#	CommonCore/SQL/src/de/steamwar/sql/BannedUserIPs.kt
2026-05-09 20:22:15 +02:00
Chaoscaot 44846cce57 Unpack CLI distribution in release
SteamWarCI Build successful
- Remove CLI installDist from build step
- Copy the packaged sw.zip into /jars during release
- Use `rm -rf` for the existing `/jars/sw` cleanup
2026-05-09 16:51:04 +02:00
Chaoscaot 1451750bcb Add SteamWar CLI module
SteamWarCI Build successful
- add Clikt-based `sw` entrypoint and subcommands
- include database, user, dev, and profiler commands
- wire CLI build and CI install/release steps
2026-05-09 16:46:59 +02:00
YoyoNow 8ade5180cb Fix FightSystem
SteamWarCI Build successful
2026-05-08 20:55:17 +02:00
Chaoscaot d0535d0c47 Merge pull request '[fightsystem]: Fix broken kit system' (#322) from bugfix/fightsystem-broken-kits into main
SteamWarCI Build successful
Reviewed-on: #322
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-04 18:31:25 +02:00
zOnlyKroks 79fa09e39b Chaos zufrieden stellen
SteamWarCI Build successful
2026-05-04 18:27:28 +02:00
Chaoscaot 4010c2125c Refactor lazy loading of dependents and relations to return lists
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-05-04 13:41:07 +02:00
zOnlyKroks 32de0077de [fightsystem]: Rework blacklist to whitelist
SteamWarCI Build successful
2026-05-03 14:15:59 +02:00
Chaoscaot bd53e016c5 Merge pull request 'feat: Add highligh flag for tracer' (#320) from BauSystem/add-highlight-trace-flag into main
SteamWarCI Build successful
Reviewed-on: #320
Reviewed-by: zOnlyKroks <zonlyknox@gmail.com>
2026-05-03 13:04:37 +02:00
zOnlyKroks 5b1ed644d1 [fightsystem]: Fix broken kit system
SteamWarCI Build successful
2026-05-03 12:52:23 +02:00
D4rkr34lm a41787d89d Add flag
SteamWarCI Build successful
2026-05-02 13:36:32 +02:00
Chaoscaot 8e392b56c3 Merge pull request 'fix: windcharge check' (#318) from fix/mssing-string-get into main
SteamWarCI Build successful
Reviewed-on: #318
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-01 12:30:42 +02:00
D4rkr34lm 42feadcd2d Add left out name get
SteamWarCI Build successful
2026-05-01 11:53:57 +02:00
Chaoscaot 15f0344416 Merge pull request 'feat: Add temporary hardcoded windcharge check to autockecker for WGS' (#316) from fix/enable-windcharges-for-wgs into main
SteamWarCI Build successful
Reviewed-on: #316
Reviewed-by: Chaoscaot <max@chaoscaot.de>
2026-05-01 11:03:38 +02:00
D4rkr34lm c90a977ab2 use same hacky impl as in fight system
SteamWarCI Build successful
2026-05-01 11:02:33 +02:00
D4rkr34lm b186228f4e Revert "swap out used api"
SteamWarCI Build successful
This reverts commit 5f38474809.
2026-05-01 10:59:23 +02:00
D4rkr34lm 5f38474809 swap out used api
SteamWarCI Build failed
2026-05-01 10:54:53 +02:00
Manuel Frohn 4f27320548 Implement hardcoded windcharge check
SteamWarCI Build successful
2026-04-30 14:44:54 +02:00
D4rkr34lm ba7bd1f1dd Configure V21 impl
SteamWarCI Build failed
2026-04-30 12:52:46 +02:00
YoyoNow fbe70e7ead Improve CheckCommand for WGS
SteamWarCI Build successful
2026-04-24 10:09:56 +02:00
YoyoNow 30a499be1d Hotfix CheckCommand
SteamWarCI Build successful
Remove uneeded stuff in SQLWrapper
2026-04-23 23:33:02 +02:00
Chaoscaot 86e212fe42 Fix Kits
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-04-23 18:23:13 +02:00
YoyoNow 4a646e6be0 Improve WindchargeStopper
SteamWarCI Build successful
2026-04-23 12:09:17 +02:00
YoyoNow bc0dc1925e Merge pull request 'Add WindchargeStopper to handle wind charge entity removal based on fight boundaries' (#182) from windcharges into main
SteamWarCI Build successful
Reviewed-on: #182
Reviewed-by: YoyoNow <yoyonow@noreply.localhost>
2026-04-23 12:04:34 +02:00
YoyoNow c3af4dbc68 Merge pull request 'Add CreateKitCommand' (#271) from add-kit-command into main
SteamWarCI Build successful
Reviewed-on: #271
2026-04-23 12:01:18 +02:00
YoyoNow 703639537d Fix CreateKitCommand
SteamWarCI Build failed
2026-04-23 11:59:28 +02:00
YoyoNow 9ac3bf6a6c Redesign GameModeConfig and SchematicType
SteamWarCI Build successful
2026-04-23 11:54:50 +02:00
YoyoNow 41ea6c9407 Fix ViewFlag.ADVANCED
SteamWarCI Build successful
2026-04-23 08:27:43 +02:00
YoyoNow 67e9a3544e Fix Tablist.disable removing gm knowledge
SteamWarCI Build successful
2026-04-20 13:45:16 +02:00
YoyoNow f69ae3e77b Fix BauLock
SteamWarCI Build successful
2026-04-20 13:31:45 +02:00
Chaoscaot 73f903fc23 Merge branch 'main' into add-db-indexes
SteamWarCI Build successful
2026-01-23 23:04:11 +01:00
Chaoscaot 25116c3865 Add CreateKitCommand
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2026-01-03 02:30:36 +01:00
Chaoscaot 22ed7e23da Add DB Indexes for future local Development deployments
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-12-25 20:51:57 +01:00
Chaoscaot c0163d813e Add WindchargeStopper to handle wind charge entity removal based on fight boundaries
SteamWarCI Build successful
Signed-off-by: Chaoscaot <max@maxsp.de>
2025-10-28 23:00:53 +01:00
1160 changed files with 33987 additions and 38665 deletions
+60
View File
@@ -0,0 +1,60 @@
name: Bug Report
about: Du hast einen Fehler gefunden? Melde ihn hier!
labels: [ "typ/bug" ]
body:
- type: markdown
attributes:
value: |
ACHTUNG: Sollte es bei dem Bug ein Sicherheitsrisiko geben, melde es bitte auf unserem Discord Server
- type: textarea
id: description
attributes:
label: Description
description: |
Beschreibe deinen Bug in kurzer Form.
- type: input
id: mc-ver
attributes:
label: Minecraft Version
description: Minecraft Version des Clients
validations:
required: true
- type: input
id: mc-ver-ser
attributes:
label: Minecraft Version Server
description: Minecraft Version des Servers, nur bei Bau oder Arenen Servern
- type: dropdown
id: can-reproduce
attributes:
label: Kannst du den Fehler wiederholen?
description: |
Wenn du den Fehler wiederholen kannst, können wir dieses Problem schneller beheben.
Solltest du den Fehler nicht wiederholen können, melde dich bitte auf unserem Discord Server.
options:
- "Yes"
- "No"
validations:
required: true
- type: textarea
id: reproduce-steps
attributes:
label: Wie kannst du den Fehler wiederholen?
description: Welche Schritte musst du ausführen, um den Fehler wiederholen zu können?
validations:
required: true
- type: textarea
id: expected-result
attributes:
label: Was sollte passieren?
description: Was sollte hier deiner Erwartung nach passieren?
- type: input
id: logs
attributes:
label: Auf welchem Server ist der Fehler aufgetreten?
description: Gebe bitte den Namen des Servers an, auf dem der Fehler aufgetreten ist. z.B. "Lobby", "Lixfels Bauserver" etc.
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Sollte es ein Visuelles Problem geben, kannst du hier Screenshots hinzufügen.
+1
View File
@@ -0,0 +1 @@
blank_issues_enabled: true
@@ -0,0 +1,17 @@
name: Feature Idee
about: Du hast eine Idee für ein neues Feature, welches SteamWar nicht hat? Stelle sie hier vor.
labels: [ "typ/idee" ]
body:
- type: textarea
id: description
attributes:
label: Feature Beschreibung
placeholder: |
Ich glaube, dass ...
validations:
required: true
- type: textarea
id: screenshots
attributes:
label: Screenshots
description: Wenn es sich um etwas grafisches handelt, kannst du hier Screenshots hinzufügen.
+193
View File
@@ -0,0 +1,193 @@
name: Backport CommonCore
on:
pull_request:
types:
- closed
branches:
- main
permissions:
contents: write
pull-requests: write
env:
BACKPORT_PATH: CommonCore
BACKPORT_BRANCH_PREFIX: backport/commoncore
DISABLE_BACKPORT_LABEL: no-backport
jobs:
backport:
name: Create CommonCore backport PRs
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Check backport eligibility
id: eligibility
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
run: |
set -euo pipefail
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
echo "Backport debug: server=${GITHUB_SERVER_URL}"
echo "Backport debug: api=${api_url}"
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
echo "Backport debug: action=$(jq -r '.action // ""' "$GITHUB_EVENT_PATH")"
merged="$(jq -r '.pull_request.merged // (.pull_request.merged_at != null)' "$GITHUB_EVENT_PATH")"
base_branch="$(jq -r '.pull_request.base.ref' "$GITHUB_EVENT_PATH")"
has_disable_label="$(jq -r --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.pull_request.labels[]?; .name == $disable_backport_label)' "$GITHUB_EVENT_PATH")"
echo "Backport debug: pr=$(jq -r '.pull_request.number // ""' "$GITHUB_EVENT_PATH") base=${base_branch} merged=${merged}"
echo "Backport debug: disable label present=${has_disable_label}"
{
echo "should_backport=$([[ "$merged" == "true" && "$base_branch" == "main" && "$has_disable_label" != "true" ]] && echo true || echo false)"
echo "pr_number=$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
echo "pr_title<<EOF"
jq -r '.pull_request.title' "$GITHUB_EVENT_PATH"
echo "EOF"
} >> "$GITHUB_OUTPUT"
labels="$(curl -fsS \
-H "Accept: application/json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
"${api_url}/repos/${GITHUB_REPOSITORY}/labels")"
if ! jq -e --arg disable_backport_label "$DISABLE_BACKPORT_LABEL" 'any(.[]; .name == $disable_backport_label)' <<< "$labels" >/dev/null; then
curl -fsS -X POST \
-H "Accept: application/json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Content-Type: application/json" \
-d "$(jq -n --arg name "$DISABLE_BACKPORT_LABEL" --arg color "ededed" --arg description "Disable automatic CommonCore backporting for this pull request." '{name: $name, color: $color, description: $description}')" \
"${api_url}/repos/${GITHUB_REPOSITORY}/labels"
fi
- name: Create backport pull requests
if: steps.eligibility.outputs.should_backport == 'true'
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
PR_NUMBER: ${{ steps.eligibility.outputs.pr_number }}
PR_TITLE: ${{ steps.eligibility.outputs.pr_title }}
run: |
set -euo pipefail
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
repo_api_path="/repos/${GITHUB_REPOSITORY}"
api_request() {
local method="$1"
local path="$2"
local output="$3"
local data_file="${4:-}"
local status
local args=(-sS -X "$method" -H "Accept: application/json" -H "Authorization: token ${GITHUB_TOKEN}" -w "%{http_code}" -o "$output")
if [[ -n "$data_file" ]]; then
args+=(-H "Content-Type: application/json" --data-binary "@${data_file}")
fi
echo "Backport debug: ${method} ${path}"
if ! status="$(curl "${args[@]}" "${api_url}${path}")"; then
echo "Backport debug: ${method} ${path} failed before HTTP status was captured."
if [[ -s "$output" ]]; then
echo "Backport debug: response body:"
cat "$output"
fi
return 1
fi
echo "Backport debug: ${method} ${path} -> HTTP ${status}"
if [[ ! "$status" =~ ^2 ]]; then
echo "Backport debug: response body:"
cat "$output"
return 1
fi
}
echo "Backport debug: event=${GITHUB_EVENT_NAME:-unknown}"
echo "Backport debug: server=${GITHUB_SERVER_URL}"
echo "Backport debug: api=${api_url}"
echo "Backport debug: repository=${GITHUB_REPOSITORY}"
echo "Backport debug: pr=${PR_NUMBER}"
echo "Backport debug: actor=${GITHUB_ACTOR:-unknown}"
git config user.name "SteamWar Backport Bot"
git config user.email "actions@steamwar.de"
if [[ "${GITHUB_SERVER_URL}" == https://* ]]; then
auth_host="${GITHUB_SERVER_URL#https://}"
git remote set-url origin "https://oauth2:${GITHUB_TOKEN}@${auth_host}/${GITHUB_REPOSITORY}.git"
fi
git fetch --prune origin '+refs/heads/version/*:refs/remotes/origin/version/*'
api_request GET "${repo_api_path}" repo-debug.json
jq -r '"Backport debug: repo permissions admin=\(.permissions.admin // "unknown") push=\(.permissions.push // "unknown") pull=\(.permissions.pull // "unknown")"' repo-debug.json || true
echo "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff"
curl -fsSL -w "Backport debug: GET ${repo_api_path}/pulls/${PR_NUMBER}.diff -> HTTP %{http_code}\n" \
-H "Accept: text/plain" \
-H "Authorization: token ${GITHUB_TOKEN}" \
"${api_url}${repo_api_path}/pulls/${PR_NUMBER}.diff" \
-o pull-request.diff
if ! grep -Eq "^diff --git a/${BACKPORT_PATH}/" pull-request.diff; then
echo "Pull request #${PR_NUMBER} has no ${BACKPORT_PATH} changes to backport."
exit 0
fi
mapfile -t target_branches < <(git for-each-ref --format='%(refname:strip=3)' refs/remotes/origin/version)
if [[ "${#target_branches[@]}" -eq 0 ]]; then
echo "No version/* branches found."
exit 0
fi
for target_branch in "${target_branches[@]}"; do
safe_target="${target_branch//\//-}"
backport_branch="${BACKPORT_BRANCH_PREFIX}/pr-${PR_NUMBER}-to-${safe_target}"
git checkout -B "${backport_branch}" "origin/${target_branch}"
git reset --hard "origin/${target_branch}"
if ! git apply --3way --index --include="${BACKPORT_PATH}/**" pull-request.diff; then
echo "Failed to apply CommonCore backport for ${target_branch}."
exit 1
fi
if git diff --cached --quiet; then
echo "CommonCore changes from #${PR_NUMBER} are already present in ${target_branch}."
continue
fi
git commit -m "Backport CommonCore changes from #${PR_NUMBER}" -m "${PR_TITLE}"
git push --force-with-lease origin "${backport_branch}"
api_request GET "${repo_api_path}/pulls?state=open" open-pulls.json
open_pr_number="$(jq -r --arg base "$target_branch" --arg head "$backport_branch" '[.[] | select(.base.ref == $base and .head.ref == $head) | (.number // .index)][0] // empty' open-pulls.json)"
if [[ -n "$open_pr_number" ]]; then
echo "Backport PR #${open_pr_number} already exists for ${target_branch}."
continue
fi
pr_body="$(printf 'Automatic CommonCore backport of #%s.\n\nOriginal PR title: %s\n\nOnly files below `CommonCore/` are included.' "$PR_NUMBER" "$PR_TITLE")"
jq -n \
--arg base "$target_branch" \
--arg head "$backport_branch" \
--arg title "Backport CommonCore changes from #${PR_NUMBER} to ${target_branch}" \
--arg body "$pr_body" \
'{base: $base, head: $head, title: $title, body: $body}' > create-pull.json
echo "Backport debug: create PR base=${target_branch} head=${backport_branch}"
api_request POST "${repo_api_path}/pulls" create-pull-response.json create-pull.json
done
+150
View File
@@ -0,0 +1,150 @@
name: Deploy
on:
push:
branches:
- main
- version/*
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Setup Java 8
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 8
- name: Setup Java 11
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 11
- name: Setup Java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
- name: Setup Maven Repository
env:
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
run: |
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
- name: Build with Gradle
run: ./gradlew clean build --no-daemon --no-build-cache --refresh-dependencies
- name: Stage deploy artifacts
shell: bash
run: |
set -euo pipefail
rm -rf deploy
mkdir -p deploy
cp "AccessWidener/build/libs/AccessWidener-all.jar" "deploy/AccessWidener.jar"
cp "BauSystem/build/libs/BauSystem-all.jar" "deploy/BauSystem.jar"
cp "FightSystem/build/libs/FightSystem-all.jar" "deploy/FightSystem.jar"
cp "KotlinCore/build/libs/KotlinCore-all.jar" "deploy/KotlinCore.jar"
cp "TNTLeague/build/libs/TNTLeague.jar" "deploy/TNTLeague.jar"
cp "LobbySystem/build/libs/LobbySystem.jar" "deploy/LobbySystem.jar"
cp "MissileWars/build/libs/MissileWars.jar" "deploy/MissileWars.jar"
cp "Realtime/build/libs/Realtime.jar" "deploy/RealTime.jar"
cp "SchematicSystem/build/libs/SchematicSystem-all.jar" "deploy/SchematicSystem.jar"
cp "SpigotCore/build/libs/SpigotCore-all.jar" "deploy/SpigotCore.jar"
cp "Teamserver/build/libs/Teamserver.jar" "deploy/Builder.jar"
cp "TowerRun/build/libs/TowerRun.jar" "deploy/TowerRun.jar"
cp "VelocityCore/Persistent/build/libs/Persistent.jar" "deploy/PersistentVelocityCore.jar"
cp "VelocityCore/Dependencies/build/libs/Dependencies-all.jar" "deploy/DependenciesVelocityCore.jar"
cp "VelocityCore/build/libs/VelocityCore-all.jar" "deploy/VelocityCore.jar"
cp "WebsiteBackend/build/libs/WebsiteBackend-all.jar" "deploy/website-api.jar"
cp "CLI/build/distributions/sw.zip" "deploy/sw.zip"
- name: Upload deploy artifacts
uses: actions/upload-artifact@v3
with:
name: steamwar-jars
path: deploy/
deploy:
name: Deploy
runs-on: ubuntu-latest
needs: build
steps:
- name: Download deploy artifacts
uses: actions/download-artifact@v3
with:
name: steamwar-jars
path: deploy
- name: Resolve deploy target
id: target
shell: bash
run: |
set -euo pipefail
if [[ "${GITHUB_REF_NAME}" == "main" ]]; then
echo "path=/jars/current" >> "$GITHUB_OUTPUT"
elif [[ "${GITHUB_REF_NAME}" == version/* ]]; then
version="${GITHUB_REF_NAME#version/}"
if [[ ! "$version" =~ ^[A-Za-z0-9._-]+$ ]]; then
echo "Unsupported version branch name: ${GITHUB_REF_NAME}" >&2
exit 1
fi
echo "path=/jars/${version}" >> "$GITHUB_OUTPUT"
else
echo "Unsupported deployment branch: ${GITHUB_REF_NAME}" >&2
exit 1
fi
- name: Upload jars with scp
shell: bash
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
DEPLOY_PATH: ${{ steps.target.outputs.path }}
run: |
set -euo pipefail
: "${DEPLOY_HOST:?Missing DEPLOY_HOST secret}"
: "${DEPLOY_USER:?Missing DEPLOY_USER secret}"
: "${DEPLOY_SSH_KEY:?Missing DEPLOY_SSH_KEY secret}"
port="${DEPLOY_PORT:-22}"
mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "$DEPLOY_SSH_KEY" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -p "$port" "$DEPLOY_HOST" >> ~/.ssh/known_hosts
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mkdir -p '$DEPLOY_PATH/upload'"
scp -i ~/.ssh/deploy_key -P "$port" deploy/* "${DEPLOY_USER}@${DEPLOY_HOST}:$DEPLOY_PATH/upload"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -f '$DEPLOY_PATH'/*.jar '$DEPLOY_PATH'/*.zip"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "mv '$DEPLOY_PATH'/upload/* '$DEPLOY_PATH'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "rm -r '$DEPLOY_PATH/upload'"
ssh -i ~/.ssh/deploy_key -p "$port" "${DEPLOY_USER}@${DEPLOY_HOST}" "chmod o-w '$DEPLOY_PATH'/*"
- name: Restart Services
shell: bash
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PORT: ${{ secrets.DEPLOY_PORT }}
DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
run: |
set -euo pipefail
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "sudo systemctl restart api.service"
ssh -i ~/.ssh/deploy_key -p "$DEPLOY_PORT" "${DEPLOY_USER}@${DEPLOY_HOST}" "unzip -o /jars/current/sw.zip -d /jars"
+76
View File
@@ -0,0 +1,76 @@
name: Pull Request Build
on:
pull_request:
permissions:
contents: write
pull-requests: write
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v6
- name: Setup Java 8
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 8
- name: Setup Java 11
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 11
- name: Setup Java 17
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 17
- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: 21
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v6
- name: Setup Maven Repository
env:
SW_MAVEN_CREDENTIALS: ${{ secrets.SW_MAVEN_CREDENTIALS }}
run: |
echo "$SW_MAVEN_CREDENTIALS" > steamwar.properties
- name: Build with Gradle
run: ./gradlew build --no-daemon
- name: Merge successful backport PR
shell: bash
env:
GITHUB_TOKEN: ${{ secrets.CI_BOT_TOKEN }}
BACKPORT_BRANCH_PREFIX: backport/commoncore
run: |
set -euo pipefail
head_branch="$(jq -r '.pull_request.head.ref // ""' "$GITHUB_EVENT_PATH")"
base_branch="$(jq -r '.pull_request.base.ref // ""' "$GITHUB_EVENT_PATH")"
pr_number="$(jq -r '.pull_request.number' "$GITHUB_EVENT_PATH")"
if [[ "${head_branch}" != "${BACKPORT_BRANCH_PREFIX}/"* ]]; then
echo "Not a CommonCore backport PR."
exit 0
fi
if [[ "${base_branch}" != version/* ]]; then
echo "Backport PR target is not a version/* branch."
exit 0
fi
api_url="${GITHUB_API_URL:-${GITHUB_SERVER_URL}/api/v1}"
curl -fsS -X POST \
-H "Accept: application/json" \
-H "Authorization: token ${GITHUB_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"Do":"merge","delete_branch_after_merge":true}' \
"${api_url}/repos/${GITHUB_REPOSITORY}/pulls/${pr_number}/merge"
+11
View File
@@ -7,14 +7,25 @@
!gradle/wrapper/gradle-wrapper.jar
steamwar.properties
# Kotlin
.kotlin
# IntelliJ IDEA
*.iml
.idea
!.idea/copyright
!.idea/runConfigurations
# VSCode
bin/
.vscode
.settings
# Language Server
**/.project
**/.factorypath
**/.classpath
# Other
lib
/WebsiteBackend/data
+15
View File
@@ -0,0 +1,15 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Remote JVM Debugger" type="Remote">
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" />
<option name="HOST" value="localhost" />
<option name="PORT" value="5005" />
<option name="AUTO_RESTART" value="false" />
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="5005" />
<option name="LOCAL" value="false" />
</RunnerSettings>
<method v="2" />
</configuration>
</component>
@@ -18,18 +18,28 @@
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
`java-library`
alias(libs.plugins.shadow)
}
dependencies {
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.nms18)
implementation("org.ow2.asm:asm:9.7")
implementation("org.ow2.asm:asm-commons:9.7")
}
tasks.shadowJar {
manifest {
attributes(
"Manifest-Version" to "1.0",
"Build-Jdk-Spec" to "21",
"Main-Class" to "de.steamwar.Main",
"Premain-Class" to "de.steamwar.Agent",
"Can-Retransform-Classes" to "true",
"Can-Redefine-Classes" to "true",
)
}
}
tasks.build {
dependsOn(tasks.shadowJar)
}
@@ -0,0 +1,49 @@
/*
* 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;
/**
* A single parsed line from a .accesswidener file.
* <p>
* Examples:
* accessible class net/minecraft/server/level/ServerPlayer
* accessible method net/minecraft/server/level/ServerPlayer getStats ()V
* mutable field net/minecraft/world/entity/Entity id I
* extendable class net/minecraft/world/level/chunk/LevelChunk
*/
public record AccessWidenerEntry(
/** accessible | mutable | extendable (may have "transitive-" prefix) */
String directive,
/** class | method | field */
String memberType,
/** Internal class name, e.g. net/minecraft/server/level/ServerPlayer */
String target,
/** Method/field name, null for class entries */
String name,
/** Descriptor, null for class entries */
String descriptor) {
/**
* Returns true if this entry targets the class with the given internal name.
*/
public boolean targets(String internalName) {
return target.equals(internalName);
}
}
@@ -0,0 +1,104 @@
/*
* 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;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
/**
* Parses Fabric-compatible .accesswidener files.
* <p>
* Supported format:
* <pre>
* accessWidener v2 named
*
* # comments are supported
* accessible class net/minecraft/Foo
* accessible method net/minecraft/Foo someMethod ()V
* accessible field net/minecraft/Foo someField I
* mutable field net/minecraft/Foo someField I
* extendable class net/minecraft/Foo
* extendable method net/minecraft/Foo someMethod ()V
*
* # transitive variants (expose widening to dependents)
* transitive-accessible class net/minecraft/Foo
* </pre>
*/
public final class AccessWidenerParser {
private AccessWidenerParser() {
}
public static List<AccessWidenerEntry> parse(InputStream in) throws IOException {
List<AccessWidenerEntry> entries = new ArrayList<>();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8))) {
String line;
boolean headerSeen = false;
while ((line = reader.readLine()) != null) {
// Strip inline comments
int commentIdx = line.indexOf('#');
if (commentIdx >= 0) line = line.substring(0, commentIdx);
line = line.strip();
if (line.isEmpty()) continue;
if (!headerSeen) {
// First non-blank, non-comment line must be the header
if (!line.startsWith("accessWidener")) {
throw new IOException("Missing accessWidener header, got: " + line);
}
headerSeen = true;
continue;
}
AccessWidenerEntry entry = parseLine(line);
if (entry != null) entries.add(entry);
}
}
return entries;
}
private static AccessWidenerEntry parseLine(String line) {
String[] parts = line.split("\\s+");
if (parts.length < 3) return null;
String directive = parts[0]; // accessible / mutable / extendable / transitive-*
String memberType = parts[1]; // class / method / field
String target = parts[2]; // internal class name
return switch (memberType) {
case "class" -> new AccessWidenerEntry(directive, "class", target, null, null);
case "method", "field" -> {
if (parts.length < 5) yield null;
yield new AccessWidenerEntry(directive, memberType, target, parts[3], parts[4]);
}
default -> null;
};
}
}
@@ -0,0 +1,75 @@
/*
* 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;
import java.io.File;
import java.io.IOException;
import java.lang.instrument.Instrumentation;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
/**
* Java agent entry point.
* <p>
* At JVM startup: java -javaagent:paper-access-widener-agent.jar -jar server.jar
* <p>
* On attach the agent:
* <ol>
* <li>Find all .jar files inside the plugins folder</li>
* <li>Scan all found jars for *.accesswidener resources</li>
* <li>Transform any class during loading</li>
* </ol>
*/
public class Agent {
private Agent() {
throw new IllegalStateException("Utility class");
}
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
// -javaagent: startup
public static void premain(String args, Instrumentation inst) {
init(inst);
}
private static void init(Instrumentation inst) {
LOG.info("[AccessWidener] Agent initialising.");
List<AccessWidenerEntry> entries = new ArrayList<>();
File file = new File(new File(".").getAbsoluteFile(), "plugins/");
File[] files = file.listFiles();
if (files == null) files = new File[0];
for (File jarFile : files) {
if (!jarFile.isFile()) continue;
if (!jarFile.getName().endsWith(".jar")) continue;
try {
entries.addAll(Utils.findAndParseAccessWideners(jarFile.toPath()));
} catch (IOException e) {
LOG.warning("Failed to parse access wideners from " + jarFile.getAbsolutePath());
}
}
LOG.info("[AccessWidener] Loaded " + entries.size() + " access wideners.");
inst.addTransformer(new WideningTransformer(entries), false);
LOG.info("[AccessWidener] Agent ready.");
}
}
@@ -0,0 +1,83 @@
/*
* 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;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Uses ASM to patch class bytecode according to a list of access widener entries.
*
* Returns {@code null} if the class is not targeted by any entry (no-op signal
* to the caller so it can skip the write).
*/
public class ClassPatcher {
private static final Logger LOG = Logger.getLogger("ClassPatcher");
private final List<AccessWidenerEntry> entries;
/** Pre-computed set of targeted internal names for fast filtering. */
private final Set<String> targets;
private final Set<String> targetsPublicConstructor;
public ClassPatcher(List<AccessWidenerEntry> entries) {
this.entries = entries;
this.targets = entries.stream()
.map(AccessWidenerEntry::target)
.flatMap(s -> {
if (!s.contains("$")) return Stream.of(s);
int index = s.lastIndexOf('$');
return Stream.of(s, s.substring(0, index));
})
.collect(Collectors.toSet());
this.targetsPublicConstructor = entries.stream()
.filter(entry -> entry.directive().equals("transitive-extendable"))
.map(AccessWidenerEntry::target)
.collect(Collectors.toSet());
}
/**
* Patches {@code classBytes} if {@code className} is targeted.
*
* @return patched bytes, or {@code null} if no changes were needed
*/
public byte[] patch(String className, byte[] classBytes) {
if (!targets.contains(className)) return null;
try {
ClassReader cr = new ClassReader(classBytes);
ClassWriter cw = new ClassWriter(cr, 0);
cr.accept(new ClassTransformer(cw, className, entries, targetsPublicConstructor.contains(className)), ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
return cw.toByteArray();
} catch (Exception e) {
LOG.warning("[AccessWidener] Failed to transform " + className + ": " + e.getMessage());
return null;
}
}
}
@@ -0,0 +1,125 @@
/*
* 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;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import java.util.List;
public class ClassTransformer extends ClassVisitor {
private final String internalName;
private final List<AccessWidenerEntry> entries;
private final boolean appendPublicConstructor;
public ClassTransformer(ClassVisitor cv, String internalName, List<AccessWidenerEntry> entries, boolean appendPublicConstructor) {
super(Opcodes.ASM9, cv);
this.internalName = internalName;
this.entries = entries;
this.appendPublicConstructor = appendPublicConstructor;
}
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
int newAccess = access;
for (AccessWidenerEntry e : entries) {
if (!e.targets(internalName) || !"class".equals(e.memberType())) continue;
newAccess = applyDirective(e.directive(), newAccess, false);
}
if (appendPublicConstructor) {
MethodVisitor methodVisitor = visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
methodVisitor.visitCode();
methodVisitor.visitVarInsn(Opcodes.ALOAD, 0);
methodVisitor.visitMethodInsn(
Opcodes.INVOKESPECIAL,
"java/lang/Object",
"<init>",
"()V",
false
);
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(1, 1);
methodVisitor.visitEnd();
}
super.visit(version, newAccess, name, signature, superName, interfaces);
}
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
int newAccess = access;
for (AccessWidenerEntry e : entries) {
if (!e.target().equals(name) || !"class".equals(e.memberType())) continue;
newAccess = applyDirective(e.directive(), newAccess, false);
}
super.visitInnerClass(name, outerName, innerName, newAccess);
}
@Override
public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
int newAccess = access;
for (AccessWidenerEntry e : entries) {
if (!e.targets(internalName) || !"method".equals(e.memberType())) continue;
if (!name.equals(e.name()) || !descriptor.equals(e.descriptor())) continue;
newAccess = applyDirective(e.directive(), newAccess, false);
}
return super.visitMethod(newAccess, name, descriptor, signature, exceptions);
}
@Override
public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) {
int newAccess = access;
for (AccessWidenerEntry e : entries) {
if (!e.targets(internalName) || !"field".equals(e.memberType())) continue;
if (!name.equals(e.name())) continue;
newAccess = applyDirective(e.directive(), newAccess, true);
}
return super.visitField(newAccess, name, descriptor, signature, value);
}
/**
* Apply a directive to an access bitmask.
*
* @param directive accessible / mutable / extendable (with optional "transitive-" prefix)
* @param access current access flags
* @param isField true when processing a field (mutable removes final)
*/
private static int applyDirective(String directive, int access, boolean isField) {
// Strip transitive- prefix — the widening itself is the same
String effective = directive.startsWith("transitive-") ? directive.substring("transitive-".length()) : directive;
return switch (effective) {
case "accessible" -> makePublic(access);
case "extendable" -> makePublic(removeFinal(access));
case "mutable" -> isField ? removeFinal(access) : access;
default -> access;
};
}
private static int makePublic(int access) {
return (access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED)) | Opcodes.ACC_PUBLIC;
}
private static int removeFinal(int access) {
return access & ~Opcodes.ACC_FINAL;
}
}
@@ -0,0 +1,125 @@
/*
* 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;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
/**
* Command-line tool that produces a widened copy of a JAR for use as a
* compile-time stub in IntelliJ / Gradle.
*
* Usage:
* java -jar jar-widener.jar <input.jar> <output.jar> [file.accesswidener ...]
*
* The output JAR is identical to the input JAR except that every class
* targeted by the access widener entries has its access flags patched:
* accessible → public
* extendable → public + non-final
* mutable → non-final field
*
* Intended for use as a Gradle task so IntelliJ sees the already-widened
* class when you Ctrl+click NMS code, and javac compiles without complaints.
*/
public class Main {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.err.println("Usage: jar-widener <input.jar> <output.jar> [*.accesswidener ...]");
System.exit(1);
}
Path inputJar = Path.of(args[0]);
Path outputJar = Path.of(args[1]);
if (!Files.exists(inputJar)) {
System.err.println("Input JAR not found: " + inputJar);
System.exit(1);
}
// --- Collect all access widener entries ---
List<AccessWidenerEntry> entries = new ArrayList<>();
if (args.length > 2) {
for (int i = 2; i < args.length; i++) {
Path awFile = Path.of(args[i]);
if (!Files.exists(awFile)) {
System.err.println("Warning: access widener file not found, skipping: " + awFile);
continue;
}
try (InputStream in = Files.newInputStream(awFile)) {
List<AccessWidenerEntry> parsed = AccessWidenerParser.parse(in);
System.out.println("Loaded " + parsed.size() + " entries from " + awFile.getFileName());
entries.addAll(parsed);
}
}
}
if (entries.isEmpty()) {
System.out.println("No access widener entries found — copying JAR unchanged.");
Files.createDirectories(outputJar.getParent());
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
return;
}
System.out.println("Widening " + inputJar.getFileName()
+ " with " + entries.size() + " total entr"
+ (entries.size() == 1 ? "y" : "ies") + "...");
// --- Copy input → output, transforming .class files in place ---
Files.createDirectories(outputJar.getParent());
Files.copy(inputJar, outputJar, StandardCopyOption.REPLACE_EXISTING);
ClassPatcher patcher = new ClassPatcher(entries);
try (FileSystem fs = FileSystems.newFileSystem(outputJar)) {
// Walk every .class entry in the JAR
try (var stream = Files.walk(fs.getPath("/"))) {
stream.filter(p -> p.toString().endsWith(".class"))
.forEach(classPath -> patchClass(fs, classPath, patcher));
}
}
System.out.println("Done. Widened JAR written to " + outputJar);
}
private static void patchClass(FileSystem fs, Path classPath, ClassPatcher patcher) {
// Derive internal class name from path e.g. /net/minecraft/Foo.class → net/minecraft/Foo
String internalName = classPath.toString()
.replaceFirst("^/", "")
.replace(".class", "");
try {
byte[] original = Files.readAllBytes(classPath);
byte[] patched = patcher.patch(internalName, original);
if (patched != null) {
Files.write(classPath, patched);
System.out.println(" Widened: " + internalName);
}
} catch (IOException e) {
System.err.println(" Warning: failed to patch " + internalName + ": " + e.getMessage());
}
}
}
@@ -0,0 +1,60 @@
/*
* 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;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class Utils {
private static final Logger LOG = Logger.getLogger("AccessWidenerAgent");
private Utils() {
throw new IllegalStateException("Utility class");
}
public static List<AccessWidenerEntry> findAndParseAccessWideners(Path jarPath) throws IOException {
List<AccessWidenerEntry> results = new ArrayList<>();
try (ZipFile zip = new ZipFile(jarPath.toFile())) {
Enumeration<? extends ZipEntry> entries = zip.entries();
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.isDirectory() || !entry.getName().endsWith(".accesswidener")) continue;
try (InputStream in = zip.getInputStream(entry)) {
results.addAll(AccessWidenerParser.parse(in));
} catch (IOException e) {
LOG.warning("[AccessWidener] Failed to parse " + entry.getName()
+ " in " + jarPath.getFileName() + ": " + e.getMessage());
}
}
}
return results;
}
}
@@ -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;
import java.lang.instrument.ClassFileTransformer;
import java.security.ProtectionDomain;
import java.util.List;
/**
* Transforms class bytecode to apply access widening rules.
* <p>
* Also monitors for new plugin ClassLoaders appearing (when plugins load after
* the agent attaches) and automatically picks up their .accesswidener files.
*/
public class WideningTransformer implements ClassFileTransformer {
private final ClassPatcher patcher;
public WideningTransformer(List<AccessWidenerEntry> entries) {
patcher = new ClassPatcher(entries);
}
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) {
return patcher.patch(className, classfileBuffer);
}
}
-35
View File
@@ -1,35 +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/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
compileOnly(libs.nms15)
compileOnly(libs.worldedit15)
}
@@ -1,239 +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.bausystem.utils;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
import com.sk89q.worldedit.extent.clipboard.Clipboard;
import com.sk89q.worldedit.extent.clipboard.io.BuiltInClipboardFormat;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormats;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardReader;
import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter;
import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.mask.Mask2D;
import com.sk89q.worldedit.function.operation.ForwardExtentCopy;
import com.sk89q.worldedit.function.operation.Operations;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.transform.AffineTransform;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.selector.CuboidRegionSelector;
import com.sk89q.worldedit.session.ClipboardHolder;
import com.sk89q.worldedit.world.World;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockTypes;
import de.steamwar.bausystem.region.Point;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import javax.annotation.Nullable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiPredicate;
import java.util.logging.Level;
public class FlatteningWrapper15 implements FlatteningWrapper {
@Override
public boolean isNoBook(ItemStack item) {
return item.getType() != Material.WRITABLE_BOOK && item.getType() != Material.WRITTEN_BOOK;
}
private static final Set<Material> unpushable = new HashSet<>(Arrays.asList(Material.BARRIER, Material.BEACON, Material.COMMAND_BLOCK, Material.CHAIN_COMMAND_BLOCK, Material.REPEATING_COMMAND_BLOCK, Material.ENCHANTING_TABLE, Material.END_GATEWAY, Material.END_PORTAL, Material.ENDER_CHEST, Material.GRINDSTONE, Material.JIGSAW, Material.JUKEBOX, Material.NETHER_PORTAL, Material.OBSIDIAN, Material.STRUCTURE_VOID, Material.BARREL, Material.BEEHIVE, Material.BEE_NEST, Material.BLAST_FURNACE, Material.BREWING_STAND, Material.CHEST, Material.DAYLIGHT_DETECTOR, Material.DISPENSER, Material.DROPPER, Material.FURNACE, Material.HOPPER, Material.LECTERN, Material.SMOKER, Material.TRAPPED_CHEST));
// TODO: FLOWER
private static final Set<Material> breaking = new HashSet<>(Arrays.asList(Material.BAMBOO, Material.CACTUS, Material.CAKE, Material.CARVED_PUMPKIN, Material.CHORUS_FLOWER, Material.CHORUS_PLANT, Material.COBWEB, Material.COCOA, Material.DRAGON_EGG, Material.FIRE, Material.FLOWER_POT, Material.JACK_O_LANTERN, Material.LADDER, Material.LAVA, Material.LAVA, Material.LEVER, Material.LILY_PAD, Material.MELON, Material.NETHER_WART, Material.PUMPKIN, Material.COMPARATOR, Material.REDSTONE_WIRE, Material.REPEATER, Material.TORCH, Material.STRUCTURE_VOID, Material.SCAFFOLDING, Material.SEA_PICKLE, Material.SNOW, Material.SUGAR_CANE, Material.TORCH, Material.TRIPWIRE, Material.TRIPWIRE_HOOK, Material.TURTLE_EGG, Material.VINE, Material.WATER, Material.WHEAT));
@Override
public boolean isUnpusheable(Material material) {
if (unpushable.contains(material)) {
return true;
}
String name = material.name();
return name.contains("BANNER") || name.contains("SIGN");
}
@Override
public boolean isBreakingOnPush(Material material) {
if (breaking.contains(material)) {
return true;
}
String name = material.name();
return name.contains("BED") || name.contains("BUTTON") || name.contains("CARPET") || (name.contains("DOOR") && !name.contains("TRAPDOOR")) || name.contains("HEAD") || name.contains("LEAVES") || name.contains("MUSHROOM") || name.contains("PRESSURE_PLATE") || name.contains("SHULKER_BOX");
}
@Override
public boolean isWorldEditCommand(String command) {
if (command.startsWith("/")) {
command = command.replaceFirst("/", "");
}
command = command.toLowerCase();
return WorldEdit.getInstance().getPlatformManager().getPlatformCommandManager().getCommandManager().containsCommand(command);
}
private static final WorldEditPlugin WORLDEDIT_PLUGIN = Objects.requireNonNull((WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"));
private static final World BUKKITWORLD = new BukkitWorld(Bukkit.getWorlds().get(0));
@Override
public void setSelection(Player p, Point minPoint, Point maxPoint) {
WORLDEDIT_PLUGIN.getSession(p).setRegionSelector(BUKKITWORLD, new CuboidRegionSelector(BUKKITWORLD, minPoint.toBlockVector3(), maxPoint.toBlockVector3()));
}
@Override
public Clipboard loadSchematic(File file) {
Clipboard clipboard;
try (ClipboardReader reader = Objects.requireNonNull(ClipboardFormats.findByFile(file)).getReader(new FileInputStream(file))) {
clipboard = reader.read();
} catch (NullPointerException | IOException e) {
throw new SecurityException("Bausystem schematic not found", e);
}
return clipboard;
}
@Override
public EditSession paste(PasteBuilder pasteBuilder) {
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorlds().get(0)), -1)) {
Clipboard clipboard = pasteBuilder.getClipboard();
if (!pasteBuilder.getMappers().isEmpty()) {
BlockVector3 minimum = clipboard.getRegion().getMinimumPoint();
for (int x = 0; x < clipboard.getDimensions().getX(); x++) {
for (int y = 0; y < clipboard.getDimensions().getY(); y++) {
for (int z = 0; z < clipboard.getDimensions().getZ(); z++) {
BlockVector3 pos = minimum.add(x, y, z);
pasteBuilder.getMappers().forEach(mapper -> mapper.accept(clipboard, pos));
}
}
}
}
AtomicReference<BlockVector3> pastePoint = new AtomicReference<>();
if (!pasteBuilder.getPredicates().isEmpty()) {
e.setMask(new Mask() {
@Override
public boolean test(BlockVector3 blockVector3) {
BaseBlock block = clipboard.getFullBlock(blockVector3.subtract(pastePoint.get()).add(clipboard.getRegion().getMinimumPoint()));
String blockName = block.getBlockType().toString().toLowerCase();
for (BiPredicate<BaseBlock, String> predicate : pasteBuilder.getPredicates()) {
if (!predicate.test(block, blockName)) return false;
}
return true;
}
public Mask copy() {
return this;
}
@Nullable
@Override
public Mask2D toMask2D() {
return null;
}
});
}
ClipboardHolder ch = new ClipboardHolder(clipboard);
BlockVector3 dimensions = clipboard.getDimensions();
BlockVector3 v = BlockVector3.at(pasteBuilder.getPastPoint().getX(), pasteBuilder.getPastPoint().getY(), pasteBuilder.getPastPoint().getZ());
BlockVector3 offset = clipboard.getRegion().getMinimumPoint().subtract(clipboard.getOrigin());
if (pasteBuilder.isRotate()) {
ch.setTransform(new AffineTransform().rotateY(180));
v = v.add(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset.multiply(-1, 1, -1)).subtract(0, 0, 1);
} else {
v = v.subtract(dimensions.getX() / 2, 0, dimensions.getZ() / 2).subtract(offset);
}
pastePoint.set(v);
if (pasteBuilder.isReset()) {
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3()), Objects.requireNonNull(BlockTypes.AIR).getDefaultState().toBaseBlock());
if (pasteBuilder.getWaterLevel() != 0) {
e.setBlocks(new CuboidRegion(pasteBuilder.getMinPoint().toBlockVector3(), pasteBuilder.getMaxPoint().toBlockVector3().withY(pasteBuilder.getWaterLevel())), Objects.requireNonNull(BlockTypes.WATER).getDefaultState().toBaseBlock());
}
}
Operations.completeBlindly(ch.createPaste(e).to(v).ignoreAirBlocks(pasteBuilder.isIgnoreAir()).build());
return e;
} catch (WorldEditException e) {
throw new SecurityException(e.getMessage(), e);
}
}
@Override
public Clipboard copy(Point minPoint, Point maxPoint, Point copyPoint) {
BukkitWorld bukkitWorld = new BukkitWorld(Bukkit.getWorlds().get(0));
CuboidRegion region = new CuboidRegion(bukkitWorld, minPoint.toBlockVector3(), maxPoint.toBlockVector3());
BlockArrayClipboard clipboard = new BlockArrayClipboard(region);
try (EditSession e = WorldEdit.getInstance().getEditSessionFactory().getEditSession(bukkitWorld, -1)) {
ForwardExtentCopy copy = new ForwardExtentCopy(
e, region, clipboard, region.getMinimumPoint()
);
copy.setCopyingEntities(false);
copy.setCopyingBiomes(false);
Operations.complete(copy);
clipboard.setOrigin(copyPoint.toBlockVector3());
return clipboard;
} catch (WorldEditException e) {
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
return null;
}
}
@Override
public boolean backup(Point minPoint, Point maxPoint, File file) {
Clipboard clipboard = copy(minPoint, maxPoint, minPoint);
try (ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(file))) {
writer.write(clipboard);
return true;
} catch (IOException e) {
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
return false;
}
}
@Override
public boolean inWater(org.bukkit.World world, Vector tntPosition) {
Block block = world.getBlockAt(tntPosition.getBlockX(), tntPosition.getBlockY(), tntPosition.getBlockZ());
if (block.getType() == Material.WATER)
return true;
BlockData data = block.getBlockData();
if (!(data instanceof Waterlogged))
return false;
return ((Waterlogged) data).isWaterlogged();
}
}
@@ -1,129 +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.bausystem.utils;
import de.steamwar.Reflection;
import de.steamwar.bausystem.features.util.NoClipCommand;
import net.minecraft.server.v1_15_R1.*;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class NMSWrapper15 implements NMSWrapper {
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
@Override
@SuppressWarnings("deprecation")
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().playerInteractManager, EnumGamemode.getById(gameMode.getValue()));
}
@Override
public void setSlotToItemStack(Player player, Object o) {
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
int index = packetPlayInSetCreativeSlot.b();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItemStack()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
private static final Reflection.Field<Integer> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, int.class, 0);
@Override
public void setGameStateChangeReason(Object packet) {
gameStateChangeReason.set(packet, 3);
}
@Override
public void setPlayerBuildAbilities(Player player) {
((CraftPlayer) player).getHandle().abilities.mayBuild = true;
((CraftPlayer) player).getHandle().abilities.canInstantlyBuild = true;
}
@Override
public Material pathMaterial() {
return Material.GRASS_PATH;
}
private static final int threshold = 2048;
@Override
public boolean checkItemStack(ItemStack item) {
net.minecraft.server.v1_15_R1.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
NBTTagCompound tag = nmsItem.getTag();
if (tag != null && tag.hasKey("BlockEntityTag")) {
NBTTagCompound blockTag = tag.getCompound("BlockEntityTag");
if (blockTag.hasKey("Items")) {
return drillDown(blockTag.getList("Items", 10), 0, 0) > threshold;
}
}
return false;
}
private int drillDown(NBTTagList items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (NBTBase nbtBase : items) {
if (!(nbtBase instanceof NBTTagCompound))
continue;
NBTTagCompound slot = (NBTTagCompound) nbtBase;
if (slot.hasKey("tag")) {
invalid += slot.getByte("Count");
NBTTagCompound iTag = slot.getCompound("tag");
if (iTag.hasKey("BlockEntityTag")) {
NBTTagCompound blockTag = iTag.getCompound("BlockEntityTag");
if (blockTag.hasKey("Items")) {
invalid = drillDown(blockTag.getList("Items", 10), layer + 1, invalid);
}
}
}
if (invalid > threshold)
break;
}
return invalid;
}
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
@Override
public Object resetExplosionKnockback(Object packet) {
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), Vec3D.a);
}
}
@@ -1,43 +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.bausystem.utils;
import org.bukkit.Material;
public class PlaceItemWrapper15 implements PlaceItemWrapper {
public PlaceItemWrapper15() {
for (Material material : Material.values()) {
if (!material.isBlock()) continue;
if (material.isLegacy()) continue;
String nonWall = material.name().replace("_WALL_", "").replace("WALL_", "").replace("_WALL", "");
try {
Material nonWallMaterial = Material.valueOf(nonWall);
if (nonWallMaterial != material && nonWallMaterial.isItem() && !nonWallMaterial.isBlock()) {
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(nonWallMaterial, material);
}
} catch (Exception e) {
// Ignore
}
}
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(Material.REDSTONE, Material.REDSTONE_WIRE);
}
}
@@ -1,51 +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.bausystem.utils;
import de.steamwar.Reflection;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.PacketPlayInFlying;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class PlayerMovementWrapper15 implements PlayerMovementWrapper {
@Override
public void setPosition(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (Float.isNaN(packetPlayInFlying.a(Float.NaN))) {
entityPlayer.e(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0));
} else {
entityPlayer.setLocation(packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0), packetPlayInFlying.a(0F), packetPlayInFlying.b(0F));
}
}
@Override
public Object convertToOut(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
teleportPosition.set(packet, packetPlayInFlying.a(0.0), packetPlayInFlying.b(0.0), packetPlayInFlying.c(0.0),
Float.isNaN(packetPlayInFlying.a(Float.NaN)) ? player.getLocation().getYaw() : packetPlayInFlying.a(0.0F),
Float.isNaN(packetPlayInFlying.b(Float.NaN)) ? player.getLocation().getPitch() : packetPlayInFlying.b(0.0F));
return packet;
}
}
@@ -1,140 +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.bausystem.utils;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
import de.steamwar.bausystem.utils.tps.TPSFreezeUtils;
import de.steamwar.bausystem.utils.tps.TPSLimitUtils;
import de.steamwar.core.TPSWarpUtils;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class TickManager15 implements TickManager, Listener {
private static float currentTPSLimit = 20;
private boolean currentlyStepping = false;
private float currentLimit;
private int stepsTotal;
private int stepsLeft;
@Override
public boolean canFreeze() {
return TPSFreezeUtils.isCanFreeze();
}
@Override
public void setTickRate(float tickRate) {
if (currentlyStepping) {
currentlyStepping = false;
Bukkit.getOnlinePlayers().forEach(player -> {
BossBarService.instance.remove(player, Region.getGlobalRegion(), "TickStep");
});
}
TPSWarpUtils.warp(tickRate);
if (currentTPSLimit == 0 && tickRate != 0) {
TPSFreezeUtils.unfreeze();
}
currentTPSLimit = tickRate;
if (tickRate == 0) {
TPSLimitUtils.unlimit();
TPSFreezeUtils.freeze();
} else if (tickRate < 20.0) {
TPSLimitUtils.limit(tickRate);
} else if (tickRate >= 20) {
TPSLimitUtils.unlimit();
}
}
@Override
public boolean isFrozen() {
return TPSFreezeUtils.frozen();
}
@Override
public void setFreeze(boolean freeze) {
if (freeze) {
setTickRate(0);
}
}
@Override
public void stepTicks(int ticks) {
currentLimit = 0;
setTickRate(20);
stepsLeft = ticks;
stepsTotal = ticks;
currentlyStepping = true;
}
@Override
public void sprintTicks(int ticks) {
currentLimit = currentTPSLimit;
setTickRate(4000);
stepsLeft = ticks;
stepsTotal = ticks;
currentlyStepping = true;
}
@Override
public boolean isSprinting() {
return currentlyStepping && currentTPSLimit > 20;
}
@Override
public boolean isStepping() {
return currentlyStepping && currentTPSLimit <= 20;
}
@Override
public float getTickRate() {
return currentTPSLimit;
}
@Override
public void setBlockTpsPacket(boolean block) {
}
@Override
public long getTotalTicks() {
return stepsTotal;
}
@Override
public long getDoneTicks() {
return stepsTotal - stepsLeft;
}
@Override
public long getRemainingTicks() {
return stepsLeft;
}
@EventHandler
public void onTickEnd(TickEndEvent event) {
if (!currentlyStepping) return;
stepsLeft--;
if (stepsLeft <= 0) {
setTickRate(currentLimit);
}
}
}
@@ -1,131 +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.bausystem.utils.tps;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.core.BountifulWrapper;
import de.steamwar.core.ChatWrapper;
import de.steamwar.core.Core;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
@UtilityClass
class PacketCache {
private static List<Object> packets = new ArrayList<>();
private static Set<Entity> entities = new HashSet<>();
private static BukkitTask task = null;
private static Class<?> vec3dClass = Reflection.getClass("net.minecraft.world.phys.Vec3");
private static Reflection.Field<Object> zeroVec3d = (Reflection.Field<Object>) Reflection.getField(vec3dClass, vec3dClass, 0);
private static Object ZERO_VEC3D = zeroVec3d.get(null);
private static Class<?> velocityPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket");
private static Reflection.Constructor velocityPacketConstructor = Reflection.getConstructor(velocityPacketClass, int.class, vec3dClass);
private static Class<?> teleportPacketClass = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket");
private static Class<?> entityClass = Reflection.getClass("net.minecraft.world.entity.Entity");
private static Reflection.Constructor teleportPacketConstructor = Reflection.getConstructor(teleportPacketClass, entityClass);
private static Class<?> craftEntityClass = Reflection.getClass("org.bukkit.craftbukkit.entity.CraftEntity");
private static Reflection.Method getHandle = Reflection.getMethod(craftEntityClass, "getHandle");
private static Object noGravityDataWatcher = BountifulWrapper.impl.getDataWatcherObject(5, Boolean.class);
private static Object fuseDataWatcher = BountifulWrapper.impl.getDataWatcherObject(8, Integer.class);
public void continuousSendCache() {
if (task != null) {
return;
}
createPackets();
task = new BukkitRunnable() {
@Override
public void run() {
_sendCache();
}
}.runTaskTimer(Core.getInstance(), 1, 1);
}
public void sendCache() {
if (task != null) {
task.cancel();
task = null;
}
_sendCache();
}
private void _sendCache() {
createPackets();
for (Player player : Bukkit.getOnlinePlayers()) {
for (Object packet : packets) {
TinyProtocol.instance.sendPacket(player, packet);
}
}
}
public void clearCache() {
packets.clear();
entities.clear();
if (task != null) {
task.cancel();
task = null;
}
}
private void createPackets() {
if (entities.stream().anyMatch(Entity::isDead)) {
entities.clear();
packets.clear();
}
List<Entity> entities = Bukkit.getWorlds().get(0).getEntities().stream()
.filter(e -> !(e instanceof Player))
.filter(e -> PacketCache.entities.add(e))
.collect(Collectors.toList());
for (Entity entity : entities) {
packets.add(teleportPacketConstructor.invoke(getHandle.invoke(entity)));
}
for (Entity entity : entities) {
packets.add(velocityPacketConstructor.invoke(entity.getEntityId(), ZERO_VEC3D));
}
for (Entity entity : entities) {
packets.add(ChatWrapper.impl.getDataWatcherPacket(entity.getEntityId(), noGravityDataWatcher, true));
}
for (Entity entity : entities) {
if (!(entity instanceof TNTPrimed)) continue;
TNTPrimed tnt = (TNTPrimed) entity;
int fuse = tnt.getFuseTicks();
packets.add(ChatWrapper.impl.getDataWatcherPacket(entity.getEntityId(), fuseDataWatcher, fuse - (fuse % 5) + 1));
}
}
}
@@ -1,76 +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.bausystem.utils.tps;
import de.steamwar.Reflection;
import lombok.Getter;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.World;
@UtilityClass
public class TPSFreezeUtils {
private static Reflection.Field<Boolean> fieldAccessor;
@Getter
private static final boolean canFreeze;
private static final Reflection.Method getWorldHandle = Reflection.getTypedMethod(Reflection.getClass("org.bukkit.craftbukkit.CraftWorld"), "getHandle", null);
@Getter
private static boolean frozen = false;
private static final World world = Bukkit.getWorlds().get(0);
static {
Reflection.Field<Boolean> fieldAccessor;
try {
fieldAccessor = Reflection.getField(Reflection.getClass("net.minecraft.server.level.ServerLevel"), "freezed", boolean.class);
} catch (IllegalArgumentException e) {
fieldAccessor = null;
}
canFreeze = fieldAccessor != null;
TPSFreezeUtils.fieldAccessor = fieldAccessor;
}
public void freeze() {
setFreeze(world, true);
}
public void unfreeze() {
setFreeze(world, false);
}
public boolean frozen() {
return canFreeze && frozen;
}
private void setFreeze(World world, boolean state) {
if (canFreeze) {
fieldAccessor.set(getWorldHandle.invoke(world), state);
if (state) {
PacketCache.continuousSendCache();
} else {
PacketCache.clearCache();
}
frozen = state;
}
}
}
@@ -1,124 +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.bausystem.utils.tps;
import de.steamwar.Reflection;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.bausystem.utils.PlayerMovementWrapper;
import de.steamwar.core.Core;
import lombok.experimental.UtilityClass;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.function.BiFunction;
@UtilityClass
public class TPSLimitUtils {
private static long currentTime = System.nanoTime();
private static BukkitTask tpsLimiter = null;
private static Queue<Runnable> packetQueue = new ConcurrentLinkedQueue<>();
public void unlimit() {
if (tpsLimiter != null) tpsLimiter.cancel();
tpsLimiter = null;
}
public void limit(double tps) {
if (tpsLimiter != null) tpsLimiter.cancel();
double delay = 20 / tps;
int loops = (int) Math.ceil(delay);
long sleepDelay = (long) (50 * delay) / loops;
tpsLimiter = Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
PacketCache.sendCache();
for (int i = 0; i < loops; i++) {
sleepUntilNextTick(sleepDelay);
PacketCache.sendCache();
while (true) {
Runnable runnable = packetQueue.poll();
if (runnable == null) break;
runnable.run();
}
}
PacketCache.clearCache();
}, 0, 1);
}
private void sleepUntilNextTick(long neededDelta) {
long lastTime = currentTime;
currentTime = System.nanoTime();
long timeDelta = (currentTime - lastTime) / 1000000;
if (neededDelta - timeDelta < 0) return;
try {
Thread.sleep(neededDelta - timeDelta);
currentTime = System.nanoTime();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
/*
static {
long timeInterval = 50;
final long[] lastTime = {System.currentTimeMillis()};
final double[] tps = {20.0};
Bukkit.getScheduler().runTaskTimer(Core.getInstance(), () -> {
long currentTime = System.currentTimeMillis();
if (currentTime > lastTime[0]) {
tps[0] = (double)timeInterval / (double)(currentTime - lastTime[0]) * 20.0;
}
lastTime[0] = currentTime;
Bukkit.getOnlinePlayers().forEach(player -> {
SWUtils.sendToActionbar(player, String.valueOf((int) (tps[0] * 10.0) / 10.0));
});
}, timeInterval / 50L, timeInterval / 50L);
}
*/
private static final Class<?> position = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$Pos");
private static final Class<?> positionLook = Reflection.getClass("net.minecraft.network.protocol.game.ServerboundMovePlayerPacket$PosRot");
static {
BiFunction<Player, Object, Object> positionSetter = (player, o) -> {
if (tpsLimiter != null) {
Object object = PlayerMovementWrapper.impl.convertToOut(player, o);
packetQueue.add(() -> {
PlayerMovementWrapper.impl.setPosition(player, o);
Bukkit.getOnlinePlayers().forEach(p -> {
if (p == player) return;
TinyProtocol.instance.sendPacket(p, object);
});
});
return null;
}
return o;
};
TinyProtocol.instance.addFilter(position, positionSetter);
TinyProtocol.instance.addFilter(positionLook, positionSetter);
}
}
@@ -1,135 +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.bausystem.utils;
import de.steamwar.Reflection;
import de.steamwar.bausystem.features.util.NoClipCommand;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.protocol.game.*;
import net.minecraft.server.level.PlayerInteractManager;
import net.minecraft.world.level.EnumGamemode;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_18_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class NMSWrapper18 implements NMSWrapper {
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
@Override
@SuppressWarnings("deprecation")
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
}
@Override
public void setSlotToItemStack(Player player, Object o) {
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
int index = packetPlayInSetCreativeSlot.b();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
@Override
public void setGameStateChangeReason(Object packet) {
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
}
@Override
public void setPlayerBuildAbilities(Player player) {
((CraftPlayer) player).getHandle().fs().d = true;
((CraftPlayer) player).getHandle().fs().e = true;
}
@Override
public Material pathMaterial() {
return Material.DIRT_PATH;
}
private static final int threshold = 2048;
@Override
public boolean checkItemStack(ItemStack item) {
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
NBTTagCompound tag = nmsItem.t();
if (tag != null && tag.e("BlockEntityTag")) {
NBTTagCompound blockTag = tag.p("BlockEntityTag");
if (blockTag.e("Items")) {
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
}
}
return false;
}
private int drillDown(NBTTagList items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (NBTBase nbtBase : items) {
if (!(nbtBase instanceof NBTTagCompound))
continue;
NBTTagCompound slot = (NBTTagCompound) nbtBase;
if (slot.e("tag")) {
invalid += slot.f("Count");
NBTTagCompound iTag = slot.p("tag");
if (iTag.e("BlockEntityTag")) {
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
if (blockTag.e("Items")) {
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
}
}
}
if (invalid > threshold)
break;
}
return invalid;
}
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
@Override
public Object resetExplosionKnockback(Object packet) {
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
}
}
@@ -1,51 +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.bausystem.utils;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.PacketPlayInFlying;
import net.minecraft.server.level.EntityPlayer;
import org.bukkit.craftbukkit.v1_18_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class PlayerMovementWrapper18 implements PlayerMovementWrapper {
@Override
public void setPosition(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (packetPlayInFlying.h) {
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
} else {
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
}
}
@Override
public Object convertToOut(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
-37
View File
@@ -1,37 +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/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.paperapi)
compileOnly(libs.nms19)
}
@@ -1,134 +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.bausystem.utils;
import de.steamwar.Reflection;
import de.steamwar.bausystem.features.util.NoClipCommand;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.protocol.game.*;
import net.minecraft.server.level.PlayerInteractManager;
import net.minecraft.world.level.EnumGamemode;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_19_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class NMSWrapper19 implements NMSWrapper {
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
@Override
@SuppressWarnings("deprecation")
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().d, EnumGamemode.a(gameMode.getValue()));
}
@Override
public void setSlotToItemStack(Player player, Object o) {
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
int index = packetPlayInSetCreativeSlot.b();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
@Override
public void setGameStateChangeReason(Object packet) {
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
}
@Override
public void setPlayerBuildAbilities(Player player) {
((CraftPlayer) player).getHandle().fF().d = true;
((CraftPlayer) player).getHandle().fF().e = true;
}
@Override
public Material pathMaterial() {
return Material.DIRT_PATH;
}
private static final int threshold = 2048;
@Override
public boolean checkItemStack(ItemStack item) {
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
NBTTagCompound tag = nmsItem.v();
if (tag != null && tag.e("BlockEntityTag")) {
NBTTagCompound blockTag = tag.p("BlockEntityTag");
if (blockTag.e("Items")) {
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
}
}
return false;
}
private int drillDown(NBTTagList items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (NBTBase nbtBase : items) {
if (!(nbtBase instanceof NBTTagCompound))
continue;
NBTTagCompound slot = (NBTTagCompound) nbtBase;
if (slot.e("tag")) {
invalid += slot.f("Count");
NBTTagCompound iTag = slot.p("tag");
if (iTag.e("BlockEntityTag")) {
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
if (blockTag.e("Items")) {
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
}
}
}
if (invalid > threshold)
break;
}
return invalid;
}
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
@Override
public Object resetExplosionKnockback(Object packet) {
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
}
}
@@ -1,51 +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.bausystem.utils;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.PacketPlayInFlying;
import net.minecraft.server.level.EntityPlayer;
import org.bukkit.craftbukkit.v1_19_R2.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class PlayerMovementWrapper19 implements PlayerMovementWrapper {
@Override
public void setPosition(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (packetPlayInFlying.h) {
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
} else {
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
}
}
@Override
public Object convertToOut(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
@@ -1,50 +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.bausystem.utils;
import com.destroystokyo.paper.event.server.ServerTickEndEvent;
import com.destroystokyo.paper.event.server.ServerTickStartEvent;
import de.steamwar.bausystem.BauSystem;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class TickListener19 implements TickListener, Listener {
private boolean tickStartRan = false;
public TickListener19() {
Bukkit.getPluginManager().registerEvents(this, BauSystem.getInstance());
}
@EventHandler
public void onServerTickStart(ServerTickStartEvent event) {
if (TickManager.impl.isFrozen()) return;
Bukkit.getPluginManager().callEvent(new TickStartEvent());
tickStartRan = true;
}
@EventHandler
public void onServerTickEnd(ServerTickEndEvent event) {
if (!tickStartRan) return;
Bukkit.getPluginManager().callEvent(new TickEndEvent());
tickStartRan = false;
}
}
-36
View File
@@ -1,36 +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/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
dependencies {
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.nms20)
}
@@ -1,136 +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.bausystem.utils;
import de.steamwar.Reflection;
import de.steamwar.bausystem.features.util.NoClipCommand;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.network.protocol.game.PacketPlayInSetCreativeSlot;
import net.minecraft.network.protocol.game.PacketPlayOutExplosion;
import net.minecraft.network.protocol.game.PacketPlayOutGameStateChange;
import net.minecraft.server.level.PlayerInteractManager;
import net.minecraft.world.level.EnumGamemode;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
public class NMSWrapper20 implements NMSWrapper {
private static final Reflection.Field<EnumGamemode> playerGameMode = Reflection.getField(PlayerInteractManager.class, EnumGamemode.class, 0);
@Override
@SuppressWarnings("deprecation")
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(((CraftPlayer) player).getHandle().e, EnumGamemode.a(gameMode.getValue()));
}
@Override
public void setSlotToItemStack(Player player, Object o) {
PacketPlayInSetCreativeSlot packetPlayInSetCreativeSlot = (PacketPlayInSetCreativeSlot) o;
int index = packetPlayInSetCreativeSlot.a();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.c()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
private static final Reflection.Field<PacketPlayOutGameStateChange.a> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, PacketPlayOutGameStateChange.a.class, 12);
@Override
public void setGameStateChangeReason(Object packet) {
gameStateChangeReason.set(packet, PacketPlayOutGameStateChange.d);
}
@Override
public void setPlayerBuildAbilities(Player player) {
((CraftPlayer) player).getHandle().fO().d = true;
((CraftPlayer) player).getHandle().fO().e = true;
}
@Override
public Material pathMaterial() {
return Material.DIRT_PATH;
}
private static final int threshold = 2048;
@Override
public boolean checkItemStack(ItemStack item) {
net.minecraft.world.item.ItemStack nmsItem = CraftItemStack.asNMSCopy(item);
NBTTagCompound tag = nmsItem.v();
if (tag != null && tag.e("BlockEntityTag")) {
NBTTagCompound blockTag = tag.p("BlockEntityTag");
if (blockTag.e("Items")) {
return drillDown(blockTag.c("Items", 10), 0, 0) > threshold;
}
}
return false;
}
private int drillDown(NBTTagList items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (NBTBase nbtBase : items) {
if (!(nbtBase instanceof NBTTagCompound))
continue;
NBTTagCompound slot = (NBTTagCompound) nbtBase;
if (slot.e("tag")) {
invalid += slot.f("Count");
NBTTagCompound iTag = slot.p("tag");
if (iTag.e("BlockEntityTag")) {
NBTTagCompound blockTag = iTag.p("BlockEntityTag");
if (blockTag.e("Items")) {
invalid = drillDown(blockTag.c("Items", 10), layer + 1, invalid);
}
}
}
if (invalid > threshold)
break;
}
return invalid;
}
private final Class<?> explosionPacket = Reflection.getClass("net.minecraft.network.protocol.game.ClientboundExplodePacket");
private final Reflection.Field<Double> a = Reflection.getField(explosionPacket, double.class, 0);
private final Reflection.Field<Double> b = Reflection.getField(explosionPacket, double.class, 1);
private final Reflection.Field<Double> c = Reflection.getField(explosionPacket, double.class, 2);
private final Reflection.Field<Float> d = Reflection.getField(explosionPacket, float.class, 0);
private final Reflection.Field<List> e = Reflection.getField(explosionPacket, List.class, 0);
@Override
public Object resetExplosionKnockback(Object packet) {
PacketPlayOutExplosion packetPlayOutExplosion = (PacketPlayOutExplosion) packet;
return new PacketPlayOutExplosion(a.get(packetPlayOutExplosion), b.get(packetPlayOutExplosion), c.get(packetPlayOutExplosion), d.get(packetPlayOutExplosion), e.get(packetPlayOutExplosion), null);
}
}
@@ -1,43 +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.bausystem.utils;
import org.bukkit.Material;
import org.bukkit.block.data.BlockData;
public class PlaceItemWrapper20 implements PlaceItemWrapper {
public PlaceItemWrapper20() {
for (Material material : Material.values()) {
if (!material.isBlock()) continue;
if (material.isLegacy()) continue;
BlockData blockData = material.createBlockData();
Material placementMaterial = blockData.getPlacementMaterial();
if (material == placementMaterial) continue;
if (placementMaterial == Material.AIR) continue;
if (placementMaterial.isItem() && !placementMaterial.isBlock()) {
ITEM_MATERIAL_TO_BLOCK_MATERIAL.put(placementMaterial, material);
}
if (material.name().contains("WALL")) {
BLOCK_MATERIAL_TO_WALL_BLOCK_MATERIAL.put(placementMaterial, material);
}
}
}
}
@@ -1,51 +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.bausystem.utils;
import de.steamwar.Reflection;
import net.minecraft.network.protocol.game.PacketPlayInFlying;
import net.minecraft.server.level.EntityPlayer;
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class PlayerMovementWrapper20 implements PlayerMovementWrapper {
@Override
public void setPosition(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
if (packetPlayInFlying.h) {
entityPlayer.b(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c, packetPlayInFlying.d, packetPlayInFlying.e);
} else {
entityPlayer.e(packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c);
}
}
@Override
public Object convertToOut(Player player, Object object) {
PacketPlayInFlying packetPlayInFlying = ((PacketPlayInFlying) object);
Object packet = Reflection.newInstance(teleportPacket);
teleportEntity.set(packet, player.getEntityId());
teleportPosition.set(packet, packetPlayInFlying.a, packetPlayInFlying.b, packetPlayInFlying.c,
packetPlayInFlying.h ? player.getLocation().getYaw() : packetPlayInFlying.d,
packetPlayInFlying.h ? player.getLocation().getPitch() : packetPlayInFlying.e);
return packet;
}
}
-36
View File
@@ -1,36 +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/>.
*/
plugins {
steamwar.java
}
java {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
dependencies {
compileOnly(project(":BauSystem:BauSystem_Main", "default"))
compileOnly(project(":SpigotCore", "default"))
compileOnly(libs.paperapi21)
compileOnly(libs.nms21)
}
@@ -1,133 +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.bausystem.utils;
import de.steamwar.Reflection;
import de.steamwar.bausystem.features.util.NoClipCommand;
import io.papermc.paper.datacomponent.DataComponentTypes;
import io.papermc.paper.datacomponent.item.ItemContainerContents;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.network.protocol.game.ClientboundExplodePacket;
import net.minecraft.network.protocol.game.ClientboundGameEventPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.entity.player.Abilities;
import net.minecraft.world.level.GameType;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import java.util.List;
import java.util.Optional;
public class NMSWrapper21 implements NMSWrapper {
private static final Reflection.Field<ServerPlayerGameMode> playerInteractManager = Reflection.getField(ServerPlayer.class, null, ServerPlayerGameMode.class);
private static final Reflection.Field<GameType> playerGameMode = Reflection.getField(ServerPlayerGameMode.class, GameType.class, 0);
@Override
public void setInternalGameMode(Player player, GameMode gameMode) {
playerGameMode.set(playerInteractManager.get(((CraftPlayer) player).getHandle()), GameType.byId(gameMode.getValue()));
}
@Override
public void setSlotToItemStack(Player player, Object o) {
ClientboundContainerSetSlotPacket packetPlayInSetCreativeSlot = (ClientboundContainerSetSlotPacket) o;
int index = packetPlayInSetCreativeSlot.getSlot();
if (index >= 36 && index <= 44) {
index -= 36;
} else if (index > 44) {
index -= 5;
} else if (index <= 8) {
index = index - 8 + 36;
}
player.getInventory().setItem(index, CraftItemStack.asBukkitCopy(packetPlayInSetCreativeSlot.getItem()));
if (index < 9) player.getInventory().setHeldItemSlot(index);
player.updateInventory();
}
private static final Reflection.Field<ClientboundGameEventPacket.Type> gameStateChangeReason = Reflection.getField(NoClipCommand.gameStateChange, ClientboundGameEventPacket.Type.class, 14);
@Override
public void setGameStateChangeReason(Object packet) {
gameStateChangeReason.set(packet, ClientboundGameEventPacket.CHANGE_GAME_MODE);
}
@Override
public void setPlayerBuildAbilities(Player player) {
Abilities abilities = (((CraftPlayer) player).getHandle()).getAbilities();
abilities.mayBuild = true;
abilities.mayfly = true;
}
@Override
public Material pathMaterial() {
return Material.DIRT_PATH;
}
private static final int threshold = 2048;
@Override
public boolean checkItemStack(ItemStack item) {
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
return false;
}
return drillDown(data.contents(), 0, 0) > threshold;
}
private int drillDown(List<ItemStack> items, int layer, int start) {
if (layer > 2) return start + threshold;
int invalid = start;
for (int i = start; i < items.size(); i++) {
ItemStack item = items.get(i);
if (item.isEmpty()) continue;
invalid += item.getAmount();
ItemContainerContents data = item.getData(DataComponentTypes.CONTAINER);
if (data == null) {
continue;
}
List<ItemStack> subItems = data.contents();
if (subItems.size() > 1) {
invalid = drillDown(subItems, layer + 1, invalid);
}
}
return invalid;
}
@Override
public Object resetExplosionKnockback(Object packet) {
ClientboundExplodePacket explosion = (ClientboundExplodePacket) packet;
return new ClientboundExplodePacket(
explosion.center(),
Optional.empty(),
explosion.explosionParticle(),
explosion.explosionSound()
);
}
}
@@ -1,46 +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.bausystem.utils;
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
public class PlayerMovementWrapper21 implements PlayerMovementWrapper {
@Override
public void setPosition(Player player, Object object) {
ServerboundMovePlayerPacket packetPlayInFlying = ((ServerboundMovePlayerPacket) object);
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
if (packetPlayInFlying.hasPos) {
serverPlayer.setPosRaw(packetPlayInFlying.x, packetPlayInFlying.y, packetPlayInFlying.z);
}
if (packetPlayInFlying.hasRot) {
serverPlayer.setXRot(packetPlayInFlying.xRot);
serverPlayer.setYRot(packetPlayInFlying.yRot);
}
}
@Override
public Object convertToOut(Player player, Object object) {
return object;
}
}
@@ -1,149 +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.bausystem.utils;
import com.comphenix.tinyprotocol.TinyProtocol;
import de.steamwar.Reflection;
import de.steamwar.bausystem.BauSystem;
import net.minecraft.network.protocol.game.ClientboundTickingStatePacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.ServerTickRateManager;
import net.minecraft.world.TickRateManager;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class TickManager21 implements TickManager {
private static final ServerTickRateManager manager = MinecraftServer.getServer().tickRateManager();
private static final Reflection.Field<Integer> frozenTicksToRun = Reflection.getField(TickRateManager.class, int.class, 0);
private static final Reflection.Field<Long> remainingSprintTicks = Reflection.getField(ServerTickRateManager.class, long.class, 0);
private boolean blockTpsPacket = true;
private int totalSteps;
public TickManager21() {
TinyProtocol.instance.addFilter(ClientboundTickingStatePacket.class, this::blockPacket);
}
private Object blockPacket(Player player, Object packet) {
if (blockTpsPacket) {
return new ClientboundTickingStatePacket(20, manager.isFrozen());
} else {
return packet;
}
}
@Override
public boolean canFreeze() {
return true;
}
@Override
public void setBlockTpsPacket(boolean block) {
blockTpsPacket = block;
if (blockTpsPacket) {
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(20, manager.isFrozen());
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
} else {
ClientboundTickingStatePacket packet = new ClientboundTickingStatePacket(manager.tickrate(), manager.isFrozen());
Bukkit.getOnlinePlayers().forEach(player -> TinyProtocol.instance.sendPacket(player, packet));
}
}
@Override
public void setTickRate(float tickRate) {
if (isFrozen()) {
setFreeze(false);
}
manager.setTickRate(tickRate);
}
@Override
public boolean isFrozen() {
return manager.isFrozen();
}
@Override
public void setFreeze(boolean freeze) {
manager.setFrozen(freeze);
}
@Override
public void stepTicks(int ticks) {
if (manager.isSprinting()) {
manager.stopSprinting();
} else if (manager.isSteppingForward()) {
manager.stopStepping();
}
this.totalSteps = ticks;
manager.setFrozen(true);
manager.stepGameIfPaused(ticks);
manager.setFrozen(false);
Bukkit.getScheduler().runTaskTimer(BauSystem.getInstance(), (bukkitTask) -> {
if (manager.isSteppingForward()) return;
manager.setFrozen(true);
bukkitTask.cancel();
}, 1, 1);
}
@Override
public void sprintTicks(int ticks) {
if (manager.isSteppingForward()) {
manager.stopStepping();
} else if (manager.isSprinting()) {
manager.stopSprinting();
}
this.totalSteps = ticks;
manager.requestGameToSprint(ticks, true);
}
@Override
public boolean isSprinting() {
return manager.isSprinting();
}
@Override
public boolean isStepping() {
return manager.isSteppingForward();
}
@Override
public float getTickRate() {
return manager.tickrate();
}
@Override
public long getRemainingTicks() {
if (isSprinting()) {
return remainingSprintTicks.get(manager);
} else {
return frozenTicksToRun.get(manager);
}
}
@Override
public long getDoneTicks() {
return totalSteps - getRemainingTicks();
}
@Override
public long getTotalTicks() {
return totalSteps;
}
}
+14 -5
View File
@@ -19,6 +19,7 @@
plugins {
steamwar.java
widener
}
tasks.compileJava {
@@ -26,21 +27,29 @@ tasks.compileJava {
}
java {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
dependencies {
compileOnly(libs.classindex)
annotationProcessor(libs.classindex)
compileOnly(project(":SpigotCore", "default"))
compileOnly(project(":KotlinCore", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.axiom)
compileOnly(libs.authlib)
compileOnly(libs.fawe18)
compileOnly(libs.paperapi)
compileOnly(libs.nms)
compileOnly(libs.fawe)
compileOnly(libs.netty)
implementation(libs.luaj)
implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
// implementation(files("$projectDir/../libs/YAPION-SNAPSHOT.jar"))
}
widener {
fromCatalog(libs.nms)
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,13 @@
accessWidener v2 named
# For NoClipCommand
accessible field net/minecraft/server/level/ServerPlayerGameMode gameModeForPlayer Lnet/minecraft/world/level/GameType;
# For PlaceItemUtils
accessible field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
mutable field org/bukkit/craftbukkit/block/CraftBlockState position Lnet/minecraft/core/BlockPos;
accessible field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
mutable field org/bukkit/craftbukkit/block/CraftBlockState world Lorg/bukkit/craftbukkit/CraftWorld;
# For TickManager
accessible field net/minecraft/server/ServerTickRateManager remainingSprintTicks J
@@ -20,8 +20,7 @@
package de.steamwar.bausystem;
import de.steamwar.bausystem.config.BauServer;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.configplayer.ConfigConverter;
import de.steamwar.bausystem.config.ConfigStore;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.features.script.lua.SteamWarLuaPlugin;
import de.steamwar.bausystem.features.script.lua.libs.LuaLib;
@@ -32,17 +31,17 @@ 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.TickListener;
import de.steamwar.bausystem.utils.TickManager;
import de.steamwar.bausystem.worlddata.WorldData;
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;
@@ -50,6 +49,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;
@@ -110,9 +110,6 @@ public class BauSystem extends JavaPlugin implements Listener {
if (any instanceof PanzernAlgorithm) {
Panzern.add((PanzernAlgorithm) any);
}
if (any instanceof ConfigConverter) {
Config.addConfigConverter((ConfigConverter) any);
}
if (any instanceof BoundingBoxLoader) {
((BoundingBoxLoader) any).load();
}
@@ -127,12 +124,22 @@ public class BauSystem extends JavaPlugin implements Listener {
return;
}
TickListener.impl.init();
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);
@@ -148,9 +155,8 @@ public class BauSystem extends JavaPlugin implements Listener {
@Override
public void onDisable() {
linker.unlink();
WorldData.write();
RegionSystem.INSTANCE.save();
Config.getInstance().saveAll();
ConfigStore.saveAll();
}
private <T extends CommandSender> AbstractValidator<T, ?> validator(Permission permission) {
@@ -0,0 +1,47 @@
/*
* 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.config;
/**
* Converts a config of one version into the next version, e.g. ConfigV1 to
* ConfigV2. The converter for the second newest version converts into the
* current version. Converters are registered in the {@link ConfigStore}
* of the config.
*
* @param <F> the config version to convert from
* @param <T> the config version to convert to
*/
public interface ConfigConverter<F extends VersionedConfig, T extends VersionedConfig> {
/**
* @return the version this converter converts from
*/
int version();
/**
* Converts the config to the next version. If anything goes wrong do not
* silently exit this method, throw an Exception. The {@link ConfigStore}
* will deal with it.
*
* @param config the config to convert
* @return the converted config
*/
T convert(F config);
}
@@ -0,0 +1,364 @@
/*
* 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.config;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import de.steamwar.sql.UserConfig;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.logging.Level;
/**
* Loads, converts and saves a versioned config stored as JSON. Older versions
* are converted with the registered {@link ConfigConverter}s, legacy formats
* that are not JSON can be read with {@link #legacy(Predicate, Function)}.
* <p>
* A store can be bound to where the config is stored:
* <ul>
* <li>{@link #userConfig(String)}: one config per player in the {@link UserConfig}, use {@link #get(Player)}</li>
* <li>{@link #file(File)}: one config in a file, use {@link #get()}</li>
* <li>unbound: use {@link #load(File)} and {@link #save(File, VersionedConfig)}</li>
* </ul>
*
* @param <T> the current config version
*/
public class ConfigStore<T extends VersionedConfig> {
private static final List<ConfigStore<?>> STORES = new ArrayList<>();
private final Class<T> type;
private final int version;
private final Supplier<T> defaultConfig;
private final Map<Integer, Class<? extends VersionedConfig>> jsonVersions = new HashMap<>();
private final Map<Integer, ConfigConverter<?, ?>> converters = new HashMap<>();
private final List<LegacyFormat> legacyFormats = new ArrayList<>();
private Gson gson = new Gson();
private Integer unversionedVersion = null;
private String userConfigKey = null;
private Predicate<T> removeIf = config -> false;
private final Map<UUID, T> playerConfigs = new ConcurrentHashMap<>();
private File file = null;
private File legacyFile = null;
private Function<String, ? extends VersionedConfig> legacyFileReader = null;
private T fileConfig = null;
private record LegacyFormat(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
}
public ConfigStore(Class<T> type, int version, Supplier<T> defaultConfig) {
this.type = type;
this.version = version;
this.defaultConfig = defaultConfig;
jsonVersions.put(version, type);
STORES.add(this);
}
public ConfigStore<T> gson(Gson gson) {
this.gson = gson;
return this;
}
/**
* Registers an older config version that is stored as JSON.
*/
public ConfigStore<T> jsonVersion(int version, Class<? extends VersionedConfig> type) {
jsonVersions.put(version, type);
return this;
}
public ConfigStore<T> converter(ConfigConverter<?, ?> converter) {
if (converters.putIfAbsent(converter.version(), converter) != null) {
throw new IllegalStateException("Duplicate converter for version " + converter.version() + " of " + type.getSimpleName());
}
return this;
}
/**
* Registers a legacy format that is not JSON, stored strings matching the predicate are read by the reader.
*/
public ConfigStore<T> legacy(Predicate<String> matches, Function<String, ? extends VersionedConfig> reader) {
legacyFormats.add(new LegacyFormat(matches, reader));
return this;
}
/**
* The version of stored JSON without a version field.
*/
public ConfigStore<T> unversioned(int version) {
this.unversionedVersion = version;
return this;
}
/**
* Binds this store to the {@link UserConfig} with the given key, one config per player.
*/
public ConfigStore<T> userConfig(String key) {
this.userConfigKey = key;
return this;
}
/**
* Removes the config from the {@link UserConfig} instead of saving it, if the predicate matches.
*/
public ConfigStore<T> removeIf(Predicate<T> removeIf) {
this.removeIf = removeIf;
return this;
}
/**
* Binds this store to a single file.
*/
public ConfigStore<T> file(File file) {
this.file = file;
return this;
}
/**
* Legacy file to read, if the file of this store does not exist yet.
*/
public ConfigStore<T> legacyFile(File legacyFile, Function<String, ? extends VersionedConfig> reader) {
this.legacyFile = legacyFile;
this.legacyFileReader = reader;
return this;
}
/**
* Reads a stored config and converts it to the current version.
*
* @throws RuntimeException if the config could not be read or converted
*/
public T read(String stored) {
for (LegacyFormat legacyFormat : legacyFormats) {
if (legacyFormat.matches().test(stored)) {
return update(legacyFormat.reader().apply(stored));
}
}
JsonObject json = JsonParser.parseString(stored).getAsJsonObject();
int storedVersion;
if (json.has("version")) {
storedVersion = json.get("version").getAsInt();
} else if (unversionedVersion != null) {
storedVersion = unversionedVersion;
json.addProperty("version", storedVersion);
} else {
throw new IllegalStateException("Missing version of " + type.getSimpleName());
}
Class<? extends VersionedConfig> storedType = jsonVersions.get(storedVersion);
if (storedType == null) {
throw new IllegalStateException("Unknown version " + storedVersion + " of " + type.getSimpleName());
}
return update(gson.fromJson(json, storedType));
}
public String write(T config) {
return gson.toJson(config);
}
/**
* Converts a config to the current version.
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public T update(VersionedConfig config) {
while (config.getVersion() < version) {
ConfigConverter converter = converters.get(config.getVersion());
if (converter == null) {
throw new IllegalStateException("No converter found for version " + config.getVersion() + " of " + type.getSimpleName());
}
VersionedConfig converted = converter.convert(config);
if (converted.getVersion() <= config.getVersion()) {
throw new IllegalStateException("Version did not increase after conversion of version " + config.getVersion() + " of " + type.getSimpleName());
}
config = converted;
}
if (!type.isInstance(config)) {
throw new IllegalStateException("Version " + config.getVersion() + " is not the current version of " + type.getSimpleName());
}
return type.cast(config);
}
/**
* @return the config stored in the file, or the default config if the file is missing or empty
* @throws RuntimeException if the config could not be read or converted
*/
public T load(File file) throws IOException {
if (file.length() == 0) {
return defaultConfig.get();
}
return read(Files.readString(file.toPath(), StandardCharsets.UTF_8));
}
public void save(File file, T config) throws IOException {
Files.writeString(file.toPath(), write(config), StandardCharsets.UTF_8);
}
/**
* Get the config of a player, loads it from the {@link UserConfig} and converts it if necessary.
*/
public T get(Player player) {
requireUserConfig();
return playerConfigs.computeIfAbsent(player.getUniqueId(), this::loadPlayer);
}
/**
* Save the config of a player, this does not unload the config.
*/
public void save(Player player) {
requireUserConfig();
T config = playerConfigs.get(player.getUniqueId());
if (config != null) {
savePlayer(player.getUniqueId(), config);
}
}
/**
* Save and unload the config of a player.
*/
public void unload(Player player) {
if (userConfigKey == null) return;
T config = playerConfigs.remove(player.getUniqueId());
if (config != null) {
savePlayer(player.getUniqueId(), config);
}
}
private T loadPlayer(UUID uuid) {
String stored = UserConfig.getConfig(uuid, userConfigKey);
if (stored == null) {
return defaultConfig.get();
}
try {
return read(stored);
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + type.getSimpleName() + " of " + uuid, e);
return defaultConfig.get();
}
}
private void savePlayer(UUID uuid, T config) {
if (removeIf.test(config)) {
UserConfig.removePlayerConfig(uuid, userConfigKey);
} else {
UserConfig.updatePlayerConfig(uuid, userConfigKey, write(config));
}
}
private void requireUserConfig() {
if (userConfigKey == null) {
throw new IllegalStateException(type.getSimpleName() + " is not stored in the UserConfig");
}
}
/**
* Get the config of the file of this store, loads it and converts it if necessary.
*/
public T get() {
requireFile();
if (fileConfig == null) {
fileConfig = loadFile();
save();
}
return fileConfig;
}
/**
* Save the config to the file of this store, if it was loaded.
*/
public void save() {
requireFile();
if (fileConfig == null) return;
try {
save(file, fileConfig);
} catch (IOException e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not write " + file, e);
}
}
private T loadFile() {
try {
if (file.length() != 0) {
return load(file);
}
if (legacyFile != null && legacyFile.length() != 0) {
return update(legacyFileReader.apply(Files.readString(legacyFile.toPath(), StandardCharsets.UTF_8)));
}
return defaultConfig.get();
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not load " + file + ", using default " + type.getSimpleName(), e);
backupBrokenFile();
return defaultConfig.get();
}
}
private void backupBrokenFile() {
if (file.length() == 0) return;
try {
Files.copy(file.toPath(), new File(file.getParentFile(), file.getName() + ".broken").toPath(), StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
Bukkit.getLogger().log(Level.SEVERE, "Could not backup broken " + file, e);
}
}
private void requireFile() {
if (file == null) {
throw new IllegalStateException(type.getSimpleName() + " is not bound to a file");
}
}
static void unloadAll(Player player) {
STORES.forEach(store -> store.unload(player));
}
/**
* Saves every loaded config and unloads the configs of the players.
*/
public static void saveAll() {
for (ConfigStore<?> store : STORES) {
if (store.userConfigKey != null) {
store.playerConfigs.forEach((uuid, config) -> saveUnchecked(store, uuid, config));
store.playerConfigs.clear();
}
if (store.file != null) {
store.save();
}
}
}
@SuppressWarnings("unchecked")
private static <T extends VersionedConfig> void saveUnchecked(ConfigStore<T> store, UUID uuid, Object config) {
store.savePlayer(uuid, (T) config);
}
}
@@ -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
@@ -17,21 +17,29 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.core.events;
package de.steamwar.bausystem.config;
import de.steamwar.core.Core;
import de.steamwar.core.CRIUSleepEvent;
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.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerQuitEvent;
/**
* Saves and unloads the configs of the {@link ConfigStore}s bound to the UserConfig
* when a player quits, configs are loaded on first use.
*/
@Linked
public class ChattingEvent implements Listener {
public class ConfigStoreListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
private void onChat(AsyncPlayerChatEvent event) {
event.setCancelled(true);
Core.MESSAGE.broadcastPrefixless("LOCAL_CHAT", event.getPlayer().getDisplayName(), event.getMessage());
@EventHandler(priority = EventPriority.MONITOR)
public void onPlayerQuit(PlayerQuitEvent event) {
ConfigStore.unloadAll(event.getPlayer());
}
@EventHandler
public void onCRIUSleep(CRIUSleepEvent event) {
ConfigStore.saveAll();
}
}
@@ -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
@@ -17,15 +17,13 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
plugins {
steamwar.java
}
dependencies {
compileOnly(project(":FightSystem:FightSystem_Core", "default"))
compileOnly(project(":FightSystem:FightSystem_18", "default"))
compileOnly(libs.spigotapi)
compileOnly(libs.nms19)
package de.steamwar.bausystem.config;
/**
* Common interface of every version of a config stored by a {@link ConfigStore},
* the current version (e.g. Config) and every older version (ConfigV1, ConfigV2, ...).
*/
public interface VersionedConfig {
int getVersion();
}
@@ -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.bausystem.config.legacy;
import lombok.experimental.UtilityClass;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.inventory.ItemStack;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Deserializes {@link ItemStack}s that were serialized by YAPION, read with {@link YapionReader}.
*/
@UtilityClass
@Deprecated
public class YapionItemDeserializer {
private static final String TYPE_IDENTIFIER = "@type";
public ItemStack deserializeItem(Object yapion) {
if (yapion == null) return null;
Object result = deserialize(yapion);
if (result instanceof ItemStack itemStack) return itemStack;
throw new IllegalArgumentException("Not an ItemStack: " + result);
}
private Object deserialize(Object yapion) {
if (yapion instanceof List<?> list) {
List<Object> result = new ArrayList<>();
list.forEach(o -> result.add(deserialize(o)));
return result;
}
if (yapion instanceof YapionReader.YapionMap map) {
Map<Object, Object> result = new LinkedHashMap<>();
map.entries().forEach((key, value) -> result.put(deserialize(key), deserialize(value)));
return result;
}
if (yapion instanceof Map<?, ?> object) {
return deserializeObject(object);
}
return yapion;
}
private Object deserializeObject(Map<?, ?> object) {
Map<String, Object> data = new LinkedHashMap<>();
object.forEach((key, value) -> {
if (!TYPE_IDENTIFIER.equals(key)) data.put((String) key, deserialize(value));
});
if (!(object.get(TYPE_IDENTIFIER) instanceof String type)) {
return data;
}
Class<?> javaType = javaUtilClass(type);
if (javaType != null && Collection.class.isAssignableFrom(javaType)) {
return data.getOrDefault("values", new ArrayList<>());
}
if (javaType != null && Map.class.isAssignableFrom(javaType)) {
return data.containsKey("values") ? data.get("values") : data;
}
data.put(ConfigurationSerialization.SERIALIZED_TYPE_KEY, type.equals("org.bukkit.inventory.meta.ItemMeta") ? "ItemMeta" : type);
return ConfigurationSerialization.deserializeObject(data);
}
private Class<?> javaUtilClass(String type) {
if (!type.startsWith("java.util.")) return null;
try {
return Class.forName(type);
} catch (ClassNotFoundException e) {
return null;
}
}
}
@@ -0,0 +1,323 @@
/*
* 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.config.legacy;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
/**
* Minimal reader for the legacy YAPION format, only used to migrate old data.
* <p>
* The result is built from plain java objects:
* <ul>
* <li>YAPION objects {@code {key(value)}} become a {@link LinkedHashMap} of String to value</li>
* <li>YAPION arrays {@code [a,b]} become a {@link List}</li>
* <li>YAPION maps {@code <(a):(b)>} become a {@link YapionMap}</li>
* <li>YAPION values {@code (value)} become null, Boolean, Number or String</li>
* </ul>
*/
@Deprecated
public class YapionReader {
private static final Pattern INTEGER = Pattern.compile("[-+]?\\d+");
private static final Pattern DECIMAL = Pattern.compile("[-+]?(\\d+\\.\\d*|\\.\\d+|\\d+)([eE][-+]?\\d+)?");
public record YapionMap(Map<Object, Object> entries) {
}
public static Map<String, Object> parse(String yapion) {
YapionReader reader = new YapionReader(yapion);
reader.skipWhitespace();
Map<String, Object> result = reader.readObject();
reader.skipWhitespace();
if (reader.index != yapion.length()) {
throw reader.error("Unexpected trailing content");
}
return result;
}
public static double getDouble(Map<?, ?> object, String key, double defaultValue) {
return object.get(key) instanceof Number value ? value.doubleValue() : defaultValue;
}
public static int getInt(Map<?, ?> object, String key, int defaultValue) {
return object.get(key) instanceof Number value ? value.intValue() : defaultValue;
}
public static boolean getBoolean(Map<?, ?> object, String key, boolean defaultValue) {
return object.get(key) instanceof Boolean value ? value : defaultValue;
}
public static String getString(Map<?, ?> object, String key, String defaultValue) {
return object.get(key) instanceof String value ? value : defaultValue;
}
/**
* @return the entries of the array that are YAPION objects
*/
public static List<Map<?, ?>> getObjects(Map<?, ?> object, String key) {
List<Map<?, ?>> objects = new ArrayList<>();
if (object.get(key) instanceof List<?> array) {
array.forEach(o -> {
if (o instanceof Map<?, ?> map) objects.add(map);
});
}
return objects;
}
private final String input;
private int index = 0;
private YapionReader(String input) {
this.input = input;
}
private Object readAny() {
return switch (peek()) {
case '{' -> readObject();
case '[' -> readArray();
case '<' -> readMap();
case '(' -> readValue();
default -> throw error("Expected '{', '[', '<' or '('");
};
}
private Map<String, Object> readObject() {
expect('{');
Map<String, Object> object = new LinkedHashMap<>();
while (true) {
skipWhitespace();
if (peek() == '}') {
index++;
return object;
}
StringBuilder key = new StringBuilder();
while (true) {
char c = peek();
if (c == '(' || c == '{' || c == '[' || c == '<') break;
if (c == '}') throw error("Key without value");
key.append(readChar());
}
object.put(key.toString(), readAny());
}
}
private List<Object> readArray() {
expect('[');
List<Object> array = new ArrayList<>();
skipWhitespace();
if (peek() == ']') {
index++;
return array;
}
while (true) {
int start = index;
skipWhitespace();
char c = peek();
if (c == '{' || c == '[' || c == '<' || c == '(') {
array.add(readAny());
skipWhitespace();
} else {
// Whitespace is part of plain values
index = start;
StringBuilder value = new StringBuilder();
while (peek() != ',' && peek() != ']') {
value.append(readChar());
}
array.add(typed(value.toString()));
}
char separator = input.charAt(index++);
if (separator == ']') return array;
if (separator != ',') throw error("Expected ',' or ']'");
}
}
private YapionMap readMap() {
expect('<');
Map<Object, Object> map = new LinkedHashMap<>();
while (true) {
skipWhitespace();
if (peek() == '>') {
index++;
return new YapionMap(map);
}
Object key = readAny();
skipWhitespace();
expect(':');
skipWhitespace();
map.put(key, readAny());
}
}
/**
* YAPION does not escape parentheses in values, balanced parentheses are part of the value.
* A backslash only escapes a backslash, a unicode sequence or a control character, otherwise it is kept.
*/
private Object readValue() {
expect('(');
StringBuilder value = new StringBuilder();
int depth = 0;
while (true) {
char c = peek();
if (c == '\\') {
value.append(readValueEscape());
continue;
}
index++;
if (c == '(') {
depth++;
} else if (c == ')') {
if (depth == 0) break;
depth--;
}
value.append(c);
}
return typed(value.toString());
}
private String readValueEscape() {
index++;
if (index >= input.length()) return "\\";
char escaped = input.charAt(index);
switch (escaped) {
case '\\', '(', ')':
index++;
return String.valueOf(escaped);
case 'n':
index++;
return "\n";
case 't':
index++;
return "\t";
case 'r':
index++;
return "\r";
case 'u':
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
index += 5;
return String.valueOf(unicode);
}
return "\\";
default:
return "\\";
}
}
/**
* Reads one character of a key or plain array value, resolving backslash escapes.
* A backslash that does not escape anything is kept, as the old player config
* collapsed escaped backslashes into a single one.
*/
private char readChar() {
char c = input.charAt(index++);
if (c != '\\') return c;
if (index >= input.length()) throw error("Unterminated escape");
char escaped = input.charAt(index);
switch (escaped) {
case 'n':
index++;
return '\n';
case 't':
index++;
return '\t';
case 'r':
index++;
return '\r';
case 'u':
if (index + 5 <= input.length() && input.substring(index + 1, index + 5).matches("[0-9a-fA-F]{4}")) {
char unicode = (char) Integer.parseInt(input.substring(index + 1, index + 5), 16);
index += 5;
return unicode;
}
return '\\';
case '\\', ',', ' ', '(', ')', '{', '}', '[', ']', '<', '>', '"', ':', '@':
index++;
return escaped;
default:
return '\\';
}
}
private static Object typed(String value) {
if (value.equals("null")) return null;
if (value.equals("true")) return true;
if (value.equals("false")) return false;
if (value.length() >= 2 && value.startsWith("\"") && value.endsWith("\"")) {
return value.substring(1, value.length() - 1);
}
try {
if (INTEGER.matcher(value).matches()) {
long l = Long.parseLong(value);
if (l >= Integer.MIN_VALUE && l <= Integer.MAX_VALUE) return (int) l;
return l;
}
if (value.length() > 1) {
String number = value.substring(0, value.length() - 1);
switch (value.charAt(value.length() - 1)) {
case 'L':
if (INTEGER.matcher(number).matches()) return Long.parseLong(number);
break;
case 'S':
if (INTEGER.matcher(number).matches()) return Short.parseShort(number);
break;
case 'B':
if (INTEGER.matcher(number).matches()) return Byte.parseByte(number);
break;
case 'F':
if (DECIMAL.matcher(number).matches()) return Float.parseFloat(number);
break;
case 'D':
if (DECIMAL.matcher(number).matches()) return Double.parseDouble(number);
break;
default:
break;
}
}
if (DECIMAL.matcher(value).matches()) return Double.parseDouble(value);
} catch (NumberFormatException e) {
// Not a number, fall through to String
}
return value;
}
private void skipWhitespace() {
while (index < input.length() && Character.isWhitespace(input.charAt(index))) {
index++;
}
}
private char peek() {
if (index >= input.length()) throw error("Unexpected end of input");
return input.charAt(index);
}
private void expect(char c) {
if (peek() != c) throw error("Expected '" + c + "'");
index++;
}
private IllegalArgumentException error(String message) {
return new IllegalArgumentException(message + " at index " + index);
}
}
@@ -0,0 +1,63 @@
/*
* 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.config.serializer;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import java.io.IOException;
import java.util.Base64;
import java.util.logging.Level;
/**
* Stores an {@link ItemStack} as Base64 of {@link ItemStack#serializeAsBytes()}, which
* contains the data version and gets upgraded on newer Minecraft versions.
* Empty items are stored as null, items that can't be read are deserialized as null.
*/
public class ItemStackTypeAdapter extends TypeAdapter<ItemStack> {
@Override
public void write(JsonWriter out, ItemStack itemStack) throws IOException {
if (itemStack == null || itemStack.isEmpty()) {
out.nullValue();
return;
}
out.value(Base64.getEncoder().encodeToString(itemStack.serializeAsBytes()));
}
@Override
public ItemStack read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
String value = in.nextString();
try {
return ItemStack.deserializeBytes(Base64.getDecoder().decode(value));
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Could not deserialize ItemStack", e);
return null;
}
}
}
@@ -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
@@ -19,129 +19,77 @@
package de.steamwar.bausystem.configplayer;
import de.steamwar.bausystem.configplayer.serializer.ConfigurationSerializableSerializer;
import de.steamwar.linkage.Linked;
import de.steamwar.sql.UserConfig;
import com.google.gson.GsonBuilder;
import de.steamwar.bausystem.config.ConfigConverter;
import de.steamwar.bausystem.config.ConfigStore;
import de.steamwar.bausystem.config.VersionedConfig;
import de.steamwar.bausystem.config.serializer.ItemStackTypeAdapter;
import de.steamwar.bausystem.configplayer.converter.ConfigV1ToV2Converter;
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
import lombok.AccessLevel;
import lombok.Getter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import yapion.hierarchy.output.StringOutput;
import yapion.hierarchy.types.YAPIONObject;
import yapion.parser.YAPIONParser;
import yapion.serializing.SerializeManager;
import lombok.Setter;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
@Linked
public class Config implements Listener {
/**
* The current player config. It is stored as JSON, fields missing in the
* stored JSON keep the default value of their initializer, so adding a new
* field does not need a new version.
* <p>
* When a field gets removed, renamed or its meaning changes, copy this class
* to ConfigV{@link #VERSION} (without the {@link #STORE}), increase {@link #VERSION},
* write a {@link ConfigConverter} from the copy to this class and register it in the {@link #STORE}.
*/
@Getter
@Setter
public class Config implements VersionedConfig {
static {
SerializeManager.add(new ConfigurationSerializableSerializer());
}
public static final int VERSION = 2;
@Getter
private static Config instance;
public static final ConfigStore<Config> STORE = new ConfigStore<>(Config.class, VERSION, Config::new)
.gson(new GsonBuilder().registerTypeHierarchyAdapter(ItemStack.class, new ItemStackTypeAdapter()).create())
.legacy(s -> s.startsWith("{@version(1)"), ConfigV1::parse)
.converter(new ConfigV1ToV2Converter())
.userConfig("bausystem");
{
instance = this;
}
private final Map<UUID, YAPIONObject> playerConfigurations = new HashMap<>();
private static final Map<Integer, ConfigConverter> CONFIG_CONVERTER_MAP = new HashMap<>();
public static void addConfigConverter(ConfigConverter configConverter) {
CONFIG_CONVERTER_MAP.putIfAbsent(configConverter.version(), configConverter);
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
get(event.getPlayer());
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
save(event.getPlayer());
playerConfigurations.remove(event.getPlayer().getUniqueId());
}
@Setter(AccessLevel.NONE)
protected int version = VERSION;
/**
* Get a PlayerConfig, optionally loads it from the DataBase and migrates it if necessary.
*
* @param player the player from whom to get the config.
* @return the config object
* BauGui item id to inventory slot
*/
public YAPIONObject get(Player player) {
UUID uuid = player.getUniqueId();
if (!playerConfigurations.containsKey(uuid)) {
String s = UserConfig.getConfig(uuid, "bausystem");
YAPIONObject yapionObject;
if (s == null) {
yapionObject = ConfigCreator.createDefaultConfig();
} else {
yapionObject = YAPIONParser.parse(s);
}
yapionObject = update(yapionObject);
playerConfigurations.put(uuid, yapionObject);
return yapionObject;
}
return playerConfigurations.get(uuid);
}
public void saveAll() {
playerConfigurations.forEach((uuid, yapionObject) -> {
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\+", "\\");
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
});
playerConfigurations.clear();
}
protected Map<Integer, Integer> bauGui = defaultBauGui();
protected int bauGuiSize = 45;
/**
* Save a PlayerConfig, this does not remove the key value mapping from the map.
*
* @param player the player to save the config.
* Slots 0-8 are the hotbar, slots 9-12 the armor contents
*/
public void save(Player player) {
UUID uuid = player.getUniqueId();
if (playerConfigurations.containsKey(uuid)) {
YAPIONObject yapionObject = playerConfigurations.get(uuid);
String string = yapionObject.toYAPION(new StringOutput()).getResult().replaceAll("\\\\+", "\\\\");
UserConfig.updatePlayerConfig(uuid, "bausystem", string);
}
}
protected ItemStack[] hotbar = DefaultHotbar.defaultHotbar();
private YAPIONObject update(YAPIONObject yapionObject) {
int version = yapionObject.getPlainValue("@version");
while (version < ConfigCreator.currentVersion) {
ConfigConverter configConverter = CONFIG_CONVERTER_MAP.getOrDefault(version, null);
if (configConverter == null) {
Bukkit.getLogger().log(Level.SEVERE, "No updater found for version " + version);
return ConfigCreator.createDefaultConfig();
}
try {
configConverter.update(yapionObject);
} catch (Exception e) {
Bukkit.getLogger().log(Level.SEVERE, e.getMessage(), e);
return ConfigCreator.createDefaultConfig();
}
int newVersion = yapionObject.getPlainValue("@version");
if (version == newVersion) {
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was the same after conversion");
return ConfigCreator.createDefaultConfig();
}
if (newVersion < version) {
Bukkit.getLogger().log(Level.SEVERE, "Version Tag was earlier after conversion");
return ConfigCreator.createDefaultConfig();
}
version = newVersion;
}
return yapionObject;
protected boolean nightVision = false;
protected boolean tntClickDetails = true;
protected boolean detonatorAutostart = false;
protected boolean inventoryFill = false;
protected boolean rayVisualizer = false;
protected boolean smartPlace = false;
protected boolean blockCounter = false;
protected boolean depthMessage = true;
public static Map<Integer, Integer> defaultBauGui() {
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
Map<Integer, Integer> bauGui = new HashMap<>();
bauGui.put(10, 2); bauGui.put(3, 3); bauGui.put(7, 4); bauGui.put(17, 5); bauGui.put(15, 6);
bauGui.put(5, 9); bauGui.put(4, 18); bauGui.put(6, 27);
bauGui.put(16, 17); bauGui.put(11, 26); bauGui.put(18, 35);
bauGui.put(19, 20); bauGui.put(21, 21); bauGui.put(9, 22); bauGui.put(0, 23); bauGui.put(1, 24);
bauGui.put(23, 37); bauGui.put(20, 38); bauGui.put(8, 39); bauGui.put(22, 40); bauGui.put(26, 41); bauGui.put(12, 42); bauGui.put(14, 43);
return bauGui;
}
}
@@ -1,56 +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.bausystem.configplayer;
import yapion.hierarchy.types.YAPIONObject;
/**
* A new {@link ConfigConverter} should be written when you remove anything
* from the Config or modify any mayor part. When you move anything from
* any key to any other key you should write a new {@link ConfigConverter}.
* For adding any new key you should be able to get the default without
* having it in the Config. Anything you need to change you should also
* change the {@link ConfigCreator} accordingly, to produce the new Config.
*/
public interface ConfigConverter {
/**
* This describes the version this Converter can convert from. The version
* it should convert to is the version 1 above this number. But this is not
* a necessity. In the config Object as parameter given in {@link #update(YAPIONObject)}
* you should update the <b>@version</b> variable in the root object to the
* new version this converter produced.
*
* @return the version number
*/
int version();
/**
* This method should update everything needed to go from a lower config
* version to a higher. It should update the <b>@version</b> variable
* accordingly. Anything else is up the implementation. If anything goes wrong
* do not silently exit this method, throw an Exception. The updater Code will
* deal with it. Never leave the inputted object in a corrupted state.
*
* @param config the config object to update
*/
void update(YAPIONObject config);
}
@@ -1,61 +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.bausystem.configplayer;
import de.steamwar.bausystem.features.hotbar.DefaultHotbar;
import lombok.experimental.UtilityClass;
import yapion.hierarchy.types.YAPIONObject;
@UtilityClass
public class ConfigCreator {
public static final int currentVersion = 1;
public YAPIONObject createDefaultConfig() {
YAPIONObject yapionObject = new YAPIONObject();
// This call should never be touched
yapionObject.add("@version", currentVersion);
// Any initialising goes into here
yapionObject.add("baugui", defaultBauGui());
// Default Hotbar Gui
yapionObject.add("hotbar", DefaultHotbar.defaultHotbar());
return yapionObject;
}
private YAPIONObject defaultBauGui() {
YAPIONObject yapionObject = new YAPIONObject();
// 0: ? | 1: ? | 2: 10 | 3: 3 | 4: 7 | 5: 17 | 6: 15 | 7: ? | 8: ?
// 9: 5 | 10: ? | 11: ? | 12: ? | 13: ? | 14: ? | 15: ? | 16: ? | 17: 16
// 18: 4 | 19: ? | 20: 19 | 21: 21 | 22: 9 | 23: 0 | 24: 1 | 25: ? | 26: 11
// 27: 6 | 28: ? | 29: ? | 30: ? | 31: ? | 32: ? | 33: ? | 34: ? | 35: 18
// 36: ? | 37: 23 | 38: 20 | 39: 8 | 40: 22 | 41: 26 | 42: 12 | 43: 14 | 44: ?
yapionObject.add("10", 2).add("3", 3).add("7", 4).add("17", 5).add("15", 6);
yapionObject.add("5", 9).add("4", 18).add("6", 27);
yapionObject.add("16", 17).add("11", 26).add("18", 35);
yapionObject.add("19", 20).add("21", 21).add("9", 22).add("0", 23).add("1", 24);
yapionObject.add("23", 37).add("20", 38).add("8", 39).add("22", 40).add("26", 41).add("12", 42).add("14", 43);
yapionObject.add("size", 45);
return yapionObject;
}
}
@@ -0,0 +1,104 @@
/*
* 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.configplayer;
import de.steamwar.bausystem.config.VersionedConfig;
import de.steamwar.bausystem.config.legacy.YapionReader;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The legacy config that was stored in the YAPION format.
*/
@Getter
@Setter
public class ConfigV1 implements VersionedConfig {
public static final int VERSION = 1;
@Setter(AccessLevel.NONE)
protected int version = VERSION;
/**
* BauGui item id to inventory slot
*/
protected Map<Integer, Integer> bauGui = new HashMap<>();
protected int bauGuiSize = 45;
/**
* Minecraft version to the hotbar serialized by YAPION, read with {@link YapionReader}.
* Use {@link de.steamwar.bausystem.config.legacy.YapionItemDeserializer} to get the items.
*/
protected Map<Integer, List<?>> hotbars = new HashMap<>();
protected boolean nightVision = false;
protected boolean tntClickDetails = true;
protected boolean detonatorAutostart = false;
protected boolean inventoryFill = false;
protected boolean rayVisualizer = false;
protected boolean smartPlace = false;
protected boolean blockCounter = false;
protected boolean depthMessage = true;
public static ConfigV1 parse(String yapion) {
Map<String, Object> object = YapionReader.parse(yapion);
ConfigV1 config = new ConfigV1();
config.version = (Integer) object.get("@version");
if (object.get("baugui") instanceof Map<?, ?> bauGui) {
bauGui.forEach((key, value) -> {
if (key.equals("size")) {
config.bauGuiSize = (Integer) value;
} else {
config.bauGui.put(Integer.parseInt((String) key), (Integer) value);
}
});
}
object.forEach((key, value) -> {
if (!(value instanceof List<?> hotbar)) return;
if (key.equals("hotbar")) {
// Hotbars were stored without version prior to 1.19
config.hotbars.putIfAbsent(19, hotbar);
} else if (key.startsWith("hotbar-")) {
config.hotbars.put(Integer.parseInt(key.substring("hotbar-".length())), hotbar);
}
});
config.nightVision = getBoolean(object, "nightvision", config.nightVision);
config.tntClickDetails = getBoolean(object, "tnt_click_details", config.tntClickDetails);
config.detonatorAutostart = getBoolean(object, "detonator-autostart", config.detonatorAutostart);
config.inventoryFill = getBoolean(object, "inventoryfill", config.inventoryFill);
config.rayVisualizer = getBoolean(object, "rayvisualizer", config.rayVisualizer);
config.smartPlace = getBoolean(object, "smartPlace", config.smartPlace);
config.blockCounter = getBoolean(object, "blockCounter", config.blockCounter);
config.depthMessage = getBoolean(object, "depth_message", config.depthMessage);
return config;
}
private static boolean getBoolean(Map<String, Object> object, String key, boolean defaultValue) {
return object.get(key) instanceof Boolean value ? value : defaultValue;
}
}
@@ -0,0 +1,75 @@
/*
* 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.configplayer.converter;
import de.steamwar.bausystem.config.ConfigConverter;
import de.steamwar.bausystem.config.legacy.YapionItemDeserializer;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.bausystem.configplayer.ConfigV1;
import de.steamwar.core.Core;
import org.bukkit.Bukkit;
import org.bukkit.inventory.ItemStack;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
@Deprecated
public class ConfigV1ToV2Converter implements ConfigConverter<ConfigV1, Config> {
@Override
public int version() {
return ConfigV1.VERSION;
}
@Override
public Config convert(ConfigV1 old) {
Config config = new Config();
config.setBauGui(new HashMap<>(old.getBauGui()));
config.setBauGuiSize(old.getBauGuiSize());
List<?> hotbar = old.getHotbars().get(Core.getVersion());
if (hotbar != null) {
config.setHotbar(convertHotbar(hotbar));
}
config.setNightVision(old.isNightVision());
config.setTntClickDetails(old.isTntClickDetails());
config.setDetonatorAutostart(old.isDetonatorAutostart());
config.setInventoryFill(old.isInventoryFill());
config.setRayVisualizer(old.isRayVisualizer());
config.setSmartPlace(old.isSmartPlace());
config.setBlockCounter(old.isBlockCounter());
config.setDepthMessage(old.isDepthMessage());
return config;
}
private ItemStack[] convertHotbar(List<?> hotbar) {
ItemStack[] items = new ItemStack[13];
for (int i = 0; i < Math.min(hotbar.size(), items.length); i++) {
try {
items[i] = YapionItemDeserializer.deserializeItem(hotbar.get(i));
} catch (Exception e) {
Bukkit.getLogger().log(Level.WARNING, "Could not convert hotbar item " + i, e);
}
}
return items;
}
}
@@ -1,90 +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.bausystem.configplayer.serializer;
import org.bukkit.configuration.serialization.ConfigurationSerializable;
import org.bukkit.configuration.serialization.ConfigurationSerialization;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import yapion.hierarchy.api.groups.YAPIONAnyType;
import yapion.hierarchy.types.YAPIONObject;
import yapion.serializing.api.SerializerObject;
import yapion.serializing.data.DeserializeData;
import yapion.serializing.data.SerializeData;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static yapion.utils.IdentifierUtils.TYPE_IDENTIFIER;
public class ConfigurationSerializableSerializer extends SerializerObject<ConfigurationSerializable> {
@Override
public Class<ConfigurationSerializable> type() {
return ConfigurationSerializable.class;
}
@Override
public boolean isInterface() {
return true;
}
@Override
public YAPIONObject serialize(SerializeData<ConfigurationSerializable> serializeData) {
YAPIONObject yapionObject = new YAPIONObject();
yapionObject.add(TYPE_IDENTIFIER, serializeData.object.getClass().getTypeName());
if (serializeData.object instanceof ItemStack) {
yapionObject.add(TYPE_IDENTIFIER, ItemStack.class.getTypeName());
}
if (serializeData.object instanceof ItemMeta) {
yapionObject.add(TYPE_IDENTIFIER, ItemMeta.class.getTypeName());
}
Map<String, Object> serializeDataMap = serializeData.object.serialize();
serializeDataMap.forEach((s, o) -> {
YAPIONAnyType yapionAnyType = serializeData.serialize(o);
if (yapionAnyType instanceof YAPIONObject) {
YAPIONObject object = (YAPIONObject) yapionAnyType;
if (object.containsKey(TYPE_IDENTIFIER) && object.getPlainValue(TYPE_IDENTIFIER).equals("com.google.common.collect.RegularImmutableList")) {
object.put(TYPE_IDENTIFIER, ArrayList.class.getTypeName());
}
}
yapionObject.add(s, yapionAnyType);
});
return yapionObject;
}
@Override
public ConfigurationSerializable deserialize(DeserializeData<YAPIONObject> deserializeData) {
Map<String, Object> deserializeDataMap = new HashMap<>();
deserializeData.object.forEach((s, yapionAnyType) -> {
if (s.equals(TYPE_IDENTIFIER)) {
if (yapionAnyType.toString().equals("(org.bukkit.inventory.meta.ItemMeta)")) {
deserializeDataMap.put("==", "ItemMeta");
} else {
deserializeDataMap.put("==", deserializeData.deserialize(yapionAnyType));
}
return;
}
deserializeDataMap.put(s, deserializeData.deserialize(yapionAnyType));
});
return ConfigurationSerialization.deserializeObject(deserializeDataMap);
}
}
@@ -76,13 +76,21 @@ public class AttributesCopyCommand extends SWCommand {
if (itemStack.getType() == Material.ZOMBIE_HEAD && block.getType() == Material.ZOMBIE_WALL_HEAD) return true;
if (itemStack.getType() == Material.CREEPER_HEAD && block.getType() == Material.CREEPER_WALL_HEAD) return true;
if (itemStack.getType() == Material.DRAGON_HEAD && block.getType() == Material.DRAGON_WALL_HEAD) return true;
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) return true;
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) return true;
if (itemStack.getType() == Material.SKELETON_SKULL && block.getType() == Material.SKELETON_WALL_SKULL) {
return true;
}
if (itemStack.getType() == Material.WITHER_SKELETON_SKULL && block.getType() == Material.WITHER_SKELETON_WALL_SKULL) {
return true;
}
if (itemStack.getType() == Material.TORCH && block.getType() == Material.WALL_TORCH) return true;
if (itemStack.getType() == Material.SOUL_TORCH && block.getType() == Material.SOUL_WALL_TORCH) return true;
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) return true;
if (itemStack.getType() == Material.REDSTONE_TORCH && block.getType() == Material.REDSTONE_WALL_TORCH) {
return true;
}
if (itemStack.getType() == Material.WHEAT_SEEDS && block.getType() == Material.WHEAT) return true;
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) return true;
if (itemStack.getType().name().contains("_BANNER") && block.getType().name().contains("_WALL_BANNER")) {
return true;
}
return false;
}
}
@@ -41,7 +41,7 @@ public class AttributesPlaceListener implements Listener {
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
ItemStack itemStack = event.getItemInHand();
ItemMeta itemMeta = itemStack.getItemMeta();
if (itemMeta == null) return;
@@ -65,7 +65,7 @@ public class AutostartListener implements Listener {
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!ItemUtils.isItem(event.getItem(), "autostart")) {
return;
}
@@ -89,7 +89,7 @@ public class AutostartListener implements Listener {
if (!(event.getPlayer() instanceof Player)) {
return;
}
if(!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
if (!Permission.BUILD.hasPermission((Player) event.getPlayer())) return;
if (!ItemUtils.isItem(event.getPlayer().getInventory().getItemInMainHand(), "autostart")) {
return;
}
@@ -104,7 +104,8 @@ public class BackupCommand extends SWCommand {
List<String> lore = Arrays.asList(BauSystem.MESSAGE.parse("BACKUP_LORE", p));
for (int i = 0; i < backups.size(); i++) {
RegionBackups.Backup backup = backups.get(i);
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, backup.getName()), lore, false, clickType -> {});
SWItem swItem = new SWItem(Material.BRICK, BauSystem.MESSAGE.parse("BACKUP_ITEM_NAME", p, backup.getName()), lore, false, clickType -> {
});
swItem.getItemStack().setAmount(i + 1);
swListEntries.add(new SWListInv.SWListEntry<>(swItem, backup));
}
@@ -64,7 +64,7 @@ public class Depth {
dimensions.setZ(Math.abs(dimensions.getZ()));
RegionUtils.message(region, player -> {
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
if (Config.STORE.get(player).isDepthMessage()) {
player.spigot().sendMessage(getMessage(player, dimensions.getBlockX() + 1, dimensions.getBlockY() + 1, dimensions.getBlockZ() + 1, tntCount));
}
});
@@ -34,11 +34,11 @@ public class DepthCommand extends SWCommand {
@Register
public void toggle(Player player) {
if (Config.getInstance().get(player).getPlainValueOrDefault("depth_message", true)) {
Config.getInstance().get(player).put("depth_message", false);
if (Config.STORE.get(player).isDepthMessage()) {
Config.STORE.get(player).setDepthMessage(false);
BauSystem.MESSAGE.send("DEPTH_COUNTER_DISABLE", player);
} else {
Config.getInstance().get(player).put("depth_message", true);
Config.STORE.get(player).setDepthMessage(true);
BauSystem.MESSAGE.send("DEPTH_COUNTER_ENABLE", player);
}
}
@@ -21,9 +21,7 @@ package de.steamwar.bausystem.features.design.endstone;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.region.Region;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import de.steamwar.entity.*;
import net.md_5.bungee.api.ChatMessageType;
import org.bukkit.Bukkit;
import org.bukkit.Location;
@@ -59,15 +57,15 @@ public class DesignEndStone {
.filter(material -> material.getBlastResistance() > region.getGameModeConfig().Schematic.MaxDesignBlastResistance)
.collect(Collectors.toSet());
calculateFromBottom = region.getGameModeConfig().Arena.NoFloor;
}
entityServer.setCallback((player, rEntity, entityAction) -> {
if (entityAction != REntityServer.EntityAction.ATTACK) return;
Location location = new Location(WORLD, rEntity.getX(), rEntity.getY(), rEntity.getZ());
private void interact(Player player, RInteraction entity, REntityAction action) {
if (action != REntityAction.ATTACK) return;
Location location = new Location(WORLD, entity.getX(), entity.getY(), entity.getZ());
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
location.getBlock().breakNaturally();
calc();
}, 1);
});
}
public void calc() {
@@ -110,12 +108,15 @@ public class DesignEndStone {
Material material = WORLD.getBlockAt(cx, cy, cz).getType();
if (material != Material.WATER && material != Material.LAVA && limited.contains(material)) {
Location location = new Location(WORLD, cx + 0.5, cy, cz + 0.5);
Location location = new Location(WORLD, cx, cy, cz);
if (!locations.add(location)) break;
RFallingBlockEntity entity = new RFallingBlockEntity(entityServer, location, Material.RED_STAINED_GLASS);
entity.setNoGravity(true);
RBlockDisplay entity = new RBlockDisplay(entityServer, location);
entity.setBlock(Material.RED_STAINED_GLASS.createBlockData());
entity.setGlowing(true);
entities.add(entity);
RInteraction interaction = new RInteraction(entityServer, location);
interaction.setCallback(this::interact);
entities.add(interaction);
break;
} else if (!material.isAir() && material != Material.WATER && material != Material.LAVA) {
break;
@@ -26,8 +26,9 @@ import de.steamwar.bausystem.features.autostart.AutostartListener;
import de.steamwar.bausystem.features.detonator.storage.DetonatorStorage;
import de.steamwar.bausystem.features.detonator.storage.ItemStorage;
import de.steamwar.core.SWPlayer;
import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import de.steamwar.entity.RInteraction;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.UtilityClass;
@@ -58,10 +59,6 @@ public class Detonator {
@Override
public void onMount(SWPlayer player) {
entities.addPlayer(player.getPlayer());
entities.setCallback((player1, entity, action) -> {
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player1);
});
}
@Override
@@ -70,8 +67,6 @@ public class Detonator {
}
}
private static final Vector HALF = new Vector(0.5, 0, 0.5);
public static boolean isDetonator(ItemStack itemStack) {
return ItemStorage.isDetonator(itemStack);
}
@@ -79,8 +74,14 @@ public class Detonator {
public static void showDetonator(Player p, List<Location> locs) {
DetonatorComponent detonatorComponent = SWPlayer.of(p).getComponentOrDefault(DetonatorComponent.class, DetonatorComponent::new);
locs.forEach(location -> {
RFallingBlockEntity entity = new RFallingBlockEntity(detonatorComponent.entities, location.clone().add(HALF), Material.RED_STAINED_GLASS);
entity.setNoGravity(true);
RBlockDisplay blockDisplay = new RBlockDisplay(detonatorComponent.entities, location);
blockDisplay.setBlock(Material.RED_STAINED_GLASS.createBlockData());
RInteraction interaction = new RInteraction(detonatorComponent.entities, location);
interaction.setCallback((player, entity, action) -> {
Vector vector = new Vector(entity.getX(), entity.getY(), entity.getZ());
DetonatorListener.addLocationToDetonator(vector.toLocation(player.getWorld()).getBlock().getLocation(), player);
});
});
}
@@ -94,7 +95,7 @@ public class Detonator {
public static void activateDetonator(DetonatorStorage detonator) {
Player p = detonator.getPlayer();
if (Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false)) {
if (Config.STORE.get(p).isDetonatorAutostart()) {
AutostartListener.instance.activate(p);
}
@@ -76,8 +76,8 @@ public class DetonatorCommand extends SWCommand {
@Register(value = "autostart", description = "DETONATOR_HELP_AUTOSTART")
public void toggleAutostartTimer(Player p) {
boolean current = Config.getInstance().get(p).getPlainValueOrDefault("detonator-autostart", false);
Config.getInstance().get(p).put("detonator-autostart", !current);
boolean current = Config.STORE.get(p).isDetonatorAutostart();
Config.STORE.get(p).setDetonatorAutostart(!current);
if (!current) {
BauSystem.MESSAGE.send("DETONATOR_AUTOSTART_ENABLE", p);
} else {
@@ -0,0 +1,63 @@
/*
* 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.dev;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
@Linked
public class CreateKitCommand extends SWCommand {
public CreateKitCommand() {
super("createkit");
if (!BauSystem.DEV_SERVER) unregister();
}
@Register
public void onCommand(Player player, String name) {
YamlConfiguration yaml = new YamlConfiguration();
yaml.set("Items", player.getInventory().getContents());
yaml.set("Armor", player.getInventory().getArmorContents());
yaml.set("Effects", player.getActivePotionEffects());
yaml.set("LeaderAllowed", true);
yaml.set("MemberAllowed", true);
yaml.set("EnterStage", 0);
yaml.set("TNT", true);
YamlConfiguration kits = new YamlConfiguration();
kits.set("Kits." + name, yaml);
try {
kits.save(new File("new.kits.yaml"));
player.sendMessage("Kit created!");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@@ -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
@@ -17,15 +17,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package de.steamwar.bausystem.utils;
package de.steamwar.bausystem.features.experimental;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.core.VersionDependent;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
public interface TickListener {
@Linked
public class ExperimentalCommand extends SWCommand {
TickListener impl = VersionDependent.getVersionImpl(BauSystem.getInstance());
default void init() {
public ExperimentalCommand() {
super("experimental", "experiment");
}
}
@@ -0,0 +1,135 @@
/*
* 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.experimental.redstone_engine;
import de.steamwar.bausystem.features.experimental.ExperimentalCommand;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.command.AbstractSWCommand;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import io.papermc.paper.configuration.WorldConfiguration;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.title.TitlePart;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import java.util.Collection;
import java.util.List;
@AbstractSWCommand.PartOf(ExperimentalCommand.class)
@Linked
public class RedstoneEngine extends SWCommand implements Listener, ScoreboardElement {
public RedstoneEngine() {
super("");
}
private WorldConfiguration.Misc getConfig() {
return ((CraftWorld) Bukkit.getWorlds().get(0)).getHandle().paperConfig().misc;
}
@Register("redstone")
@Register("redstoneengine")
public void setRedstoneEngine(Player player, @StaticValue("alternate_current") String __, WorldConfiguration.Misc.AlternateCurrentUpdateOrder updateOrder) {
WorldConfiguration.Misc misc = getConfig();
misc.redstoneImplementation = WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT;
misc.alternateCurrentUpdateOrder = updateOrder;
broadcastTitle(Bukkit.getOnlinePlayers());
}
@Register("redstone")
@Register("redstoneengine")
public void setRedstoneEngine(Player player, WorldConfiguration.Misc.RedstoneImplementation implementation) {
getConfig().redstoneImplementation = implementation;
broadcastTitle(Bukkit.getOnlinePlayers());
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
WorldConfiguration.Misc misc = getConfig();
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.EIGENCRAFT) {
broadcastTitle(List.of(event.getPlayer()));
}
}
private void broadcastTitle(Collection<? extends Player> players) {
WorldConfiguration.Misc misc = getConfig();
Component title = switch (misc.redstoneImplementation) {
case VANILLA -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: Vanilla ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
case EIGENCRAFT -> Component.text("Redstone: Eigencraft");
case ALTERNATE_CURRENT -> Component.text("⚠").color(NamedTextColor.RED).append(Component.text(" Redstone: AC ").color(NamedTextColor.WHITE)).append(Component.text("⚠").color(NamedTextColor.RED));
};
Component subtitle;
if (misc.redstoneImplementation != WorldConfiguration.Misc.RedstoneImplementation.ALTERNATE_CURRENT) {
subtitle = Component.text().build();
} else {
subtitle = switch (misc.alternateCurrentUpdateOrder) {
case VERTICAL_FIRST_INWARD -> Component.text("Y first inwards"); // Y before XZ
case VERTICAL_FIRST_OUTWARD -> Component.text("Y first outwards"); // XZ before Y
case HORIZONTAL_FIRST_INWARD -> Component.text("XZ first inwards"); // Y before XZ
case HORIZONTAL_FIRST_OUTWARD -> Component.text("XZ first outwards"); // XZ before Y
};
}
players.forEach(player -> {
player.sendTitlePart(TitlePart.TITLE, title);
player.sendTitlePart(TitlePart.SUBTITLE, subtitle);
});
}
@Override
public ScoreboardGroup getGroup() {
return ScoreboardGroup.FOOTER;
}
@Override
public int order() {
return Integer.MAX_VALUE;
}
@Override
public String get(Region region, Player p) {
WorldConfiguration.Misc misc = getConfig();
switch (misc.redstoneImplementation) {
case ALTERNATE_CURRENT:
switch (misc.alternateCurrentUpdateOrder) {
case VERTICAL_FIRST_INWARD:
return "§eRedstone§8: §cAC §8(§7Y in§8)";
case VERTICAL_FIRST_OUTWARD:
return "§eRedstone§8: §cAC §8(§7Y out§8)";
case HORIZONTAL_FIRST_INWARD:
return "§eRedstone§8: §cAC §8(§7XZ in§8)";
case HORIZONTAL_FIRST_OUTWARD:
return "§eRedstone§8: §cAC §8(§7XZ out§8)";
}
return "§eRedstone§8: §cAC";
case EIGENCRAFT:
return null;
case VANILLA:
default:
return "§eRedstone§8: §cVanilla";
}
}
}
@@ -22,7 +22,6 @@ package de.steamwar.bausystem.features.gui.editor;
import de.steamwar.bausystem.BauSystem;
import de.steamwar.bausystem.features.gui.BauGUI;
import de.steamwar.bausystem.linkage.BauGuiItem;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.data.CMDs;
import de.steamwar.inventory.SWItem;
import de.steamwar.inventory.SWListInv;
@@ -74,7 +73,7 @@ public class BauGuiEditor implements Listener {
inv.setItem(mapping.getSize() + 5, new SWItem(Material.BARRIER, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH", p), Arrays.asList(BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_TRASH_LORE", p)), false, clickType -> {
}).getItemStack());
inv.setItem(mapping.getSize() + 6, new SWItem(TrickyTrialsWrapper.impl.getTurtleScute(), BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
inv.setItem(mapping.getSize() + 6, new SWItem(Material.TURTLE_SCUTE, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_MORE", p)).getItemStack());
inv.setItem(mapping.getSize() + 8, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("GUI_EDITOR_ITEM_CLOSE", p)).setCustomModelData(CMDs.BACK).getItemStack());
p.openInventory(inv);
@@ -28,7 +28,6 @@ import lombok.Setter;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
import yapion.hierarchy.types.YAPIONObject;
import java.util.*;
@@ -52,15 +51,15 @@ public class BauGuiMapping {
}
@Getter
private final YAPIONObject object;
private final Config config;
@Getter
private final Player owner;
@Getter
@Setter
private boolean saved;
protected BauGuiMapping(YAPIONObject object, Player p) {
this.object = object;
protected BauGuiMapping(Config config, Player p) {
this.config = config;
this.owner = p;
fromUUID.put(p.getUniqueId(), this);
mappings.add(this);
@@ -70,19 +69,18 @@ public class BauGuiMapping {
BauGuiMapping mapping = fromUUID.get(p.getUniqueId());
if (mapping == null) {
YAPIONObject yapionObject = Config.getInstance().get(p);
mapping = new BauGuiMapping(yapionObject.getObject("baugui"), p);
mapping = new BauGuiMapping(Config.STORE.get(p), p);
}
return mapping;
}
public boolean isShown(int id) {
return object.getPlainValueOrDefault(Integer.toString(id), -1) >= 0;
return config.getBauGui().getOrDefault(id, -1) >= 0;
}
public int getSlot(int id) {
return object.getPlainValue(Integer.toString(id));
return config.getBauGui().get(id);
}
public Map<Integer, Integer> getMapping() {
@@ -94,7 +92,7 @@ public class BauGuiMapping {
}
public int getSize() {
return object.getPlainValueOrDefault("size", 45);
return config.getBauGuiSize();
}
public void setSize(int size) {
@@ -102,7 +100,7 @@ public class BauGuiMapping {
return;
}
object.add("size", size);
config.setBauGuiSize(size);
}
private void tick() {
@@ -111,16 +109,17 @@ public class BauGuiMapping {
public void save() {
if (saved) return;
YAPIONObject config = Config.getInstance().get(owner);
config.add("baugui", object);
Config.getInstance().save(owner);
Config current = Config.STORE.get(owner);
current.setBauGui(config.getBauGui());
current.setBauGuiSize(config.getBauGuiSize());
Config.STORE.save(owner);
saved = true;
}
private Map<Integer, Integer> internalReadMap() {
Map<Integer, Integer> map = new HashMap<>();
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
Integer value = object.getPlainValueOrDefault(e.getKey().toString(), -1);
Integer value = config.getBauGui().getOrDefault(e.getKey(), -1);
if (value == -1) continue;
map.put(e.getKey(), value);
}
@@ -129,10 +128,10 @@ public class BauGuiMapping {
private void internalWriteMap(Map<Integer, Integer> map) {
for (Map.Entry<Integer, BauGuiItem> e : BauGUI.getITEMS().entrySet()) {
object.remove(e.getKey().toString());
config.getBauGui().remove(e.getKey());
Integer value = map.getOrDefault(e.getKey(), -1);
if (value == -1) continue;
object.add(e.getKey().toString(), value);
config.getBauGui().put(e.getKey(), value);
}
}
}
@@ -20,39 +20,23 @@
package de.steamwar.bausystem.features.hotbar;
import de.steamwar.bausystem.configplayer.Config;
import de.steamwar.core.Core;
import lombok.experimental.UtilityClass;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import yapion.hierarchy.types.YAPIONArray;
import yapion.hierarchy.types.YAPIONObject;
import yapion.hierarchy.types.YAPIONValue;
import yapion.parser.YAPIONParser;
import yapion.serializing.YAPIONDeserializer;
import yapion.serializing.YAPIONSerializer;
import org.bukkit.inventory.meta.ItemMeta;
import java.util.HashSet;
import java.util.Set;
import java.util.List;
@UtilityClass
public class DefaultHotbar {
private final YAPIONArray DEFAULT_HOTBAR = YAPIONParser.parse("{[{@type(org.bukkit.inventory.ItemStack)v(2230)type(WOODEN_AXE)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(WorldEdit Wand)lore{@type(java.util.ArrayList)values[Left click: select pos #1,Right click: select pos #2]}}},{@type(org.bukkit.inventory.ItemStack)v(2230)type(COMPASS)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(Navigation Wand)lore{@type(java.util.ArrayList)values[Left click: jump to location,Right click: pass through walls]}}},null,null,null,null,null,null,{@type(org.bukkit.inventory.ItemStack)v(2230)type(NETHER_STAR)meta{@type(org.bukkit.inventory.meta.ItemMeta)meta-type(UNSPECIFIC)display-name(§eBau GUI)}},null,null,{@type(org.bukkit.inventory.ItemStack)v(3117)type(ELYTRA)},null]}").getArray("");
public void updateHotbar(Player p) {
ItemStack[] hotbar = new ItemStack[13];
System.arraycopy(p.getInventory().getContents(), 0, hotbar, 0, 9);
System.arraycopy(p.getInventory().getArmorContents(), 0, hotbar, 9, 4);
YAPIONArray yapionArray = new YAPIONArray();
for (ItemStack itemStack : hotbar) {
if (itemStack != null) {
yapionArray.add(YAPIONSerializer.serialize(itemStack));
} else {
yapionArray.add(new YAPIONValue<>(null));
}
}
Config.getInstance().get(p).add("hotbar-" + Core.getVersion(), yapionArray);
Config.getInstance().save(p);
Config.STORE.get(p).setHotbar(copy(hotbar));
Config.STORE.save(p);
}
public void setHotbar(Player p) {
@@ -66,28 +50,34 @@ public class DefaultHotbar {
}
public ItemStack[] getItems(Player p) {
Config.getInstance().get(p).remap("hotbar", "hotbar-19");
YAPIONArray yapionArray = Config.getInstance().get(p).getYAPIONArrayOrSetDefault("hotbar-" + Core.getVersion(), defaultHotbar());
return copy(Config.STORE.get(p).getHotbar());
}
public ItemStack[] defaultHotbar() {
ItemStack[] hotbar = new ItemStack[13];
Set<Integer> invalid = new HashSet<>();
yapionArray.forEach((integer, yapionAnyType) -> {
if (yapionAnyType instanceof YAPIONValue) {
hotbar[integer] = null;
} else {
try {
hotbar[integer] = YAPIONDeserializer.deserialize((YAPIONObject) yapionAnyType);
} catch (Exception e) {
invalid.add(integer);
hotbar[integer] = null;
}
}
});
invalid.forEach(i -> yapionArray.set(i, new YAPIONValue<>(null)));
if (!invalid.isEmpty()) Config.getInstance().save(p);
hotbar[0] = item(Material.WOODEN_AXE, "WorldEdit Wand", "Left click: select pos #1", "Right click: select pos #2");
hotbar[1] = item(Material.COMPASS, "Navigation Wand", "Left click: jump to location", "Right click: pass through walls");
hotbar[8] = item(Material.NETHER_STAR, "§eBau GUI");
hotbar[11] = new ItemStack(Material.ELYTRA);
return hotbar;
}
public YAPIONArray defaultHotbar() {
return DEFAULT_HOTBAR;
private ItemStack item(Material material, String name, String... lore) {
ItemStack itemStack = new ItemStack(material);
ItemMeta meta = itemStack.getItemMeta();
meta.setDisplayName(name);
if (lore.length > 0) {
meta.setLore(List.of(lore));
}
itemStack.setItemMeta(meta);
return itemStack;
}
private ItemStack[] copy(ItemStack[] hotbar) {
ItemStack[] copy = new ItemStack[13];
for (int i = 0; i < Math.min(hotbar.length, copy.length); i++) {
copy[i] = hotbar[i] == null ? null : hotbar[i].clone();
}
return copy;
}
}
@@ -31,7 +31,7 @@ public class HotbarListener implements Listener {
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (allNull(event.getPlayer().getInventory().getContents()) && allNull(event.getPlayer().getInventory().getArmorContents())) {
DefaultHotbar.setHotbar(event.getPlayer());
}
@@ -49,8 +49,9 @@ public class InventoryFillBauGuiItem extends BauGuiItem {
@Override
public ItemStack getItem(Player player) {
String loreKey = Config.getInstance().get(player).getPlainValueOrDefault("inventoryfill", false) ? "OTHER_ITEMS_INVENTORY_FILL_LORE_ACTIVE" : "OTHER_ITEMS_INVENTORY_FILL_LORE_INACTIVE";
return new SWItem(Material.HOPPER, BauSystem.MESSAGE.parse("OTHER_ITEMS_INVENTORY_FILL_NAME", player), Collections.singletonList(BauSystem.MESSAGE.parse(loreKey, player)), false, clickType -> {}).getItemStack();
String loreKey = Config.STORE.get(player).isInventoryFill() ? "OTHER_ITEMS_INVENTORY_FILL_LORE_ACTIVE" : "OTHER_ITEMS_INVENTORY_FILL_LORE_INACTIVE";
return new SWItem(Material.HOPPER, BauSystem.MESSAGE.parse("OTHER_ITEMS_INVENTORY_FILL_NAME", player), Collections.singletonList(BauSystem.MESSAGE.parse(loreKey, player)), false, clickType -> {
}).getItemStack();
}
@Override
@@ -39,8 +39,8 @@ public class InventoryFiller implements Listener {
@EventHandler
public void onPlayerDropItem(PlayerDropItemEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("inventoryfill", false)) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Config.STORE.get(event.getPlayer()).isInventoryFill()) return;
if (!event.getPlayer().isSneaking()) return;
Block block = event.getPlayer().getTargetBlockExact(5);
if (block == null) return;
@@ -61,8 +61,8 @@ public class InventoryFiller implements Listener {
*/
@EventHandler
public void onPlayerItemHeld(PlayerItemHeldEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("inventoryfill", false)) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Config.STORE.get(event.getPlayer()).isInventoryFill()) return;
if (!event.getPlayer().isSneaking()) return;
ItemStack itemStack = event.getPlayer().getInventory().getItemInMainHand();
if (itemStack.getType() == Material.AIR) return;
@@ -68,8 +68,8 @@ public class InventoryFillerCommand extends SWCommand {
@Register(description = {"INVENTORY_FILL_HELP", "INVENTORY_FILL_INFO"})
public void toggle(Player player) {
boolean inventoryFill = Config.getInstance().get(player).getPlainValueOrDefault("inventoryfill", false);
Config.getInstance().get(player).put("inventoryfill", !inventoryFill);
boolean inventoryFill = Config.STORE.get(player).isInventoryFill();
Config.STORE.get(player).setInventoryFill(!inventoryFill);
if (!inventoryFill) {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("INVENTORY_FILL_ENABLE", player));
BauSystem.MESSAGE.send("INVENTORY_FILL_INFO", player);
@@ -24,9 +24,9 @@ import de.steamwar.bausystem.region.Point;
import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.utils.bossbar.BauSystemBossbar;
import de.steamwar.bausystem.utils.bossbar.BossBarService;
import de.steamwar.entity.RBlockDisplay;
import de.steamwar.entity.REntity;
import de.steamwar.entity.REntityServer;
import de.steamwar.entity.RFallingBlockEntity;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.World;
@@ -104,7 +104,9 @@ public class KillcheckerVisualizer {
Block block = WORLD.getBlockAt(x, y, z);
if (block.getType().isAir()) continue;
String name = block.getType().name();
if (!name.endsWith("_WOOL") && !name.endsWith("_STAINED_GLASS") && !name.endsWith("_CONCRETE") && !name.endsWith("_TERRACOTTA")) continue;
if (!name.endsWith("_WOOL") && !name.endsWith("_STAINED_GLASS") && !name.endsWith("_CONCRETE") && !name.endsWith("_TERRACOTTA")) {
continue;
}
if (name.equals("_GLAZED_TERRACOTTA")) continue;
Cuboid cuboid = create(block.getType(), x, y, z);
cuboids.add(cuboid);
@@ -283,11 +285,13 @@ public class KillcheckerVisualizer {
}
kill.forEach((point, count) -> {
if (rEntities.containsKey(point)) {
if (killCount.get(point) == count && outlinePoints.contains(point) == outlinePointsCacheLast.contains(point)) return;
if (killCount.get(point) == count && outlinePoints.contains(point) == outlinePointsCacheLast.contains(point)) {
return;
}
rEntities.get(point).die();
}
RFallingBlockEntity entity = new RFallingBlockEntity(outlinePoints.contains(point) ? outline : inner, point.toLocation(WORLD, 0.5, 0, 0.5), MATERIALS[Math.min(count - 1, MATERIALS.length) - 1]);
entity.setNoGravity(true);
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);
killCount.put(point, count);
@@ -71,7 +71,7 @@ public class Loader implements Listener, SWPlayer.Component {
BauSystem.runTaskTimer(BauSystem.getInstance(), () -> {
if (stage != Stage.RUNNING && stage != Stage.SINGLE) return;
if(!Permission.BUILD.hasPermission(p)) return;
if (!Permission.BUILD.hasPermission(p)) return;
if (waitTime > 0) {
waitTime--;
return;
@@ -213,7 +213,8 @@ public class Loader implements Listener, SWPlayer.Component {
};
updateRunnable.run();
SWListInv<LoaderElement> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("LOADER_GUI_TITLE", p), false, list, (clickType, loaderElement) -> {});
SWListInv<LoaderElement> swListInv = new SWListInv<>(p, BauSystem.MESSAGE.parse("LOADER_GUI_TITLE", p), false, list, (clickType, loaderElement) -> {
});
swListInv.setCallback((clickType, entry) -> entry.click(p, () -> {
updateRunnable.run();
swListInv.open();
@@ -363,7 +364,9 @@ public class Loader implements Listener, SWPlayer.Component {
public static int LENGTH = SettingsSorting.values().length;
public abstract Material getMaterial();
public abstract String getName();
public abstract boolean shouldShow(LoaderElement previous, LoaderElement current, LoaderElement next);
}
@@ -41,7 +41,7 @@ public class LoaderScoreboardElement implements ScoreboardElement {
@Override
public String get(Region region, Player p) {
if(!Permission.BUILD.hasPermission(p)) return null;
if (!Permission.BUILD.hasPermission(p)) return null;
Loader loader = Loader.getLoader(p);
if (loader == null) return null;
if (loader.getStage() == Loader.Stage.RUNNING) {
@@ -26,6 +26,8 @@ import java.util.function.Consumer;
public interface LoaderElement {
SWItem menu(Player player);
void execute(Consumer<Long> delay);
void click(Player player, Runnable backAction);
}
@@ -95,7 +95,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
};
updateRunnable.run();
SWListInv<Integer> listInv = new SWListInv<>(player, "Interaction Settings", false, entries, (clickType, entry) -> {});
SWListInv<Integer> listInv = new SWListInv<>(player, "Interaction Settings", false, entries, (clickType, entry) -> {
});
listInv.setCallback((clickType, entry) -> {
openIndividualSettingsMenu(player, entry, () -> {
updateRunnable.run();
@@ -150,7 +151,10 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
}
SWInventory swInventory = new SWInventory(player, guiSize, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_TITLE", player));
for (int i = guiSize - 9; i < guiSize; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7", clickType -> {}));
for (int i = guiSize - 9; i < guiSize; i++) {
swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7", clickType -> {
}));
}
swInventory.setItem(guiSize - 9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> back.run());
swInventory.setItem(guiSize - 5, new SWItem(Material.WOODEN_AXE, BauSystem.MESSAGE.parse("LOADER_GUI_SETTINGS_COPY", player)).getItemStack(), clickType -> {
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_GUI_COPY_TITLE", player), "1");
@@ -197,7 +201,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
for (int power = 0; power < 16; power++) {
int finalPowerPosition = power;
if (power >= 9) finalPowerPosition++;
SWItem powerItem = new SWItem(Material.REDSTONE, BauSystem.MESSAGE.parse("LOADER_SETTING_POWER", player, power), Arrays.asList(), false, clickType -> {});
SWItem powerItem = new SWItem(Material.REDSTONE, BauSystem.MESSAGE.parse("LOADER_SETTING_POWER", player, power), Arrays.asList(), false, clickType -> {
});
powerItem.getItemStack().setAmount(Math.max(power, 1));
if (extraPower.get(index) == power) powerItem.setEnchanted(true);
@@ -210,7 +215,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
}
if (currentElement.hasTicks(this)) {
swInventory.setItem(ticksStart + 3, new SWItem(SWItem.getDye(1), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
swInventory.setItem(ticksStart + 3, new SWItem(Material.RED_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {
}).getItemStack(), clickType -> {
long ticks = extraTicks.get(index);
ticks -= clickType.isShiftClick() ? 5 : 1;
if (ticks < 1) ticks = 1;
@@ -218,7 +224,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
openIndividualSettingsMenu(player, index, back, delete);
});
SWItem ticksItem = new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS", player, extraTicks.get(index)), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_GUI_CLICK_TO_EDIT", player)), false, clickType -> {});
SWItem ticksItem = new SWItem(Material.CLOCK, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS", player, extraTicks.get(index)), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_GUI_CLICK_TO_EDIT", player)), false, clickType -> {
});
ticksItem.getItemStack().setAmount((int) Math.min(extraTicks.get(index), 64));
swInventory.setItem(ticksStart + 4, ticksItem.getItemStack(), clickType -> {
SWAnvilInv swAnvilInv = new SWAnvilInv(player, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_NAME", player), extraTicks.get(index) + "");
@@ -234,7 +241,8 @@ public abstract class LoaderInteractionElement<T extends Enum<T> & LoaderSetting
swAnvilInv.open();
});
swInventory.setItem(ticksStart + 5, new SWItem(SWItem.getDye(10), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
swInventory.setItem(ticksStart + 5, new SWItem(Material.LIME_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {
}).getItemStack(), clickType -> {
long ticks = extraTicks.get(index);
ticks += clickType.isShiftClick() ? 5 : 1;
extraTicks.set(index, ticks);
@@ -28,10 +28,13 @@ import java.util.function.Consumer;
public interface LoaderSettingsEnum<T, P extends LoaderInteractionElement<E>, E extends Enum<E> & LoaderSettingsEnum<T, P, E>> {
int getPos();
SWItem menu(Player player, P parent, int power, long ticks);
default boolean hasPower(P parent) {
return false;
}
default boolean hasTicks(P parent) {
return false;
}
@@ -63,7 +63,8 @@ public class LoaderWait implements LoaderElement {
for (int i = 9; i < 18; i++) swInventory.setItem(i, new SWItem(Material.GRAY_STAINED_GLASS_PANE, "§7"));
swInventory.setItem(9, new SWItem(Material.ARROW, BauSystem.MESSAGE.parse("LOADER_GUI_WAIT_BACK", player)).setCustomModelData(CMDs.BACK).getItemStack(), clickType -> backAction.run());
swInventory.setItem(3, new SWItem(SWItem.getDye(1), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
swInventory.setItem(3, new SWItem(Material.RED_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_REMOVE_ONE_SHIFT", player)), false, clickType -> {
}).getItemStack(), clickType -> {
delay -= clickType.isShiftClick() ? 5 : 1;
if (delay < 0) delay = 0;
swInventory.setItem(4, menu(player));
@@ -80,7 +81,8 @@ public class LoaderWait implements LoaderElement {
});
swAnvilInv.open();
});
swInventory.setItem(5, new SWItem(SWItem.getDye(10), BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {}).getItemStack(), clickType -> {
swInventory.setItem(5, new SWItem(Material.LIME_DYE, BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE", player), Arrays.asList(BauSystem.MESSAGE.parse("LOADER_SETTING_TICKS_ADD_ONE_SHIFT", player)), false, clickType -> {
}).getItemStack(), clickType -> {
delay += clickType.isShiftClick() ? 5 : 1;
swInventory.setItem(4, menu(player));
});
@@ -146,8 +146,7 @@ public class Loadtimer implements Listener {
if ((stage == Stage.COUNTING || stage == Stage.ACTIVATED)) {
stage = Stage.IGNITION;
ignite = TPSUtils.currentRealTick.get();
if (activate == -1)
activate = TPSUtils.currentRealTick.get();
if (activate == -1) activate = TPSUtils.currentRealTick.get();
if (finishOnActive) {
stage = Stage.END;
print();
@@ -184,8 +183,7 @@ public class Loadtimer implements Listener {
long ignTime = ignite - activate;
long explTime = explode - ignTime - activate;
if (explTime < 0)
explTime = loadTime;
if (explTime < 0) explTime = loadTime;
int finalAllTnt = allTnt;
long finalExplTime = explTime;
@@ -40,17 +40,19 @@ public class LoadtimerCommand extends SWCommand {
public void start(@Validator Player p, TimerMode mode) {
Region r = Region.getRegion(p.getLocation());
if (r.getType().isGlobal()) return;
if (!Loadtimer.hasTimer(r))
if (!Loadtimer.hasTimer(r)) {
Loadtimer.createLoadtimer(r, mode == TimerMode.HALF);
}
}
@Register(value = "stop", description = "LOADTIMER_HELP_STOP")
public void stop(@Validator Player p) {
Region r = Region.getRegion(p.getLocation());
if (r.getType().isGlobal()) return;
if (Loadtimer.hasTimer(r))
if (Loadtimer.hasTimer(r)) {
Loadtimer.getTimer(r).delete();
}
}
public enum TimerMode {
FULL,
@@ -46,8 +46,9 @@ public class LoadtimerGuiItem extends BauGuiItem {
@Override
public ItemStack getItem(Player player) {
Region r = Region.getRegion(player.getLocation());
if (r.getType().isGlobal())
if (r.getType().isGlobal()) {
return new SWItem(Material.BOWL, BauSystem.MESSAGE.parse("LOADTIMER_GUI_GLOBAL", player)).getItemStack();
}
if (Loadtimer.hasTimer(r)) {
return new SWItem(Material.BOW, BauSystem.MESSAGE.parse("LOADTIMER_GUI_STOP", player)).getItemStack();
} else {
@@ -20,9 +20,9 @@
package de.steamwar.bausystem.features.loadtimer;
import de.steamwar.bausystem.region.Region;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Material;
import org.bukkit.entity.EntityType;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockPlaceEvent;
@@ -57,7 +57,7 @@ public class LoadtimerListener implements Listener {
@EventHandler
public void onEntitySpawn(EntitySpawnEvent event) {
if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
if (!getTimers().isEmpty() && event.getEntityType() == EntityType.TNT) {
Region r = Region.getRegion(event.getLocation());
if (hasTimer(r)) {
getTimer(r).onTntSpawn();
@@ -67,7 +67,7 @@ public class LoadtimerListener implements Listener {
@EventHandler
public void onEntityExplode(EntityExplodeEvent event) {
if (!getTimers().isEmpty() && event.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
if (!getTimers().isEmpty() && event.getEntityType() == EntityType.TNT) {
Region r = Region.getRegion(event.getLocation());
if (hasTimer(r)) {
getTimer(r).onTntExplode(event);
@@ -19,7 +19,6 @@
package de.steamwar.bausystem.features.observer;
import de.steamwar.Reflection;
import de.steamwar.bausystem.region.Point;
import de.steamwar.core.SWPlayer;
import org.bukkit.Location;
@@ -29,8 +28,9 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Observer;
import org.bukkit.block.data.type.*;
import org.bukkit.block.data.type.Observer;
import org.bukkit.craftbukkit.block.impl.CraftPoweredRail;
import org.bukkit.entity.Player;
import java.util.*;
@@ -171,7 +171,6 @@ public class ObserverTracer implements SWPlayer.Component {
}
}
private static final Class<?> craftPoweredRail = Reflection.getClass("org.bukkit.craftbukkit.block.impl.CraftPoweredRail");
private boolean checkAllowed(Block block, BlockData blockData) {
if (checkMaterial(block)) return true;
if (block.getType() == Material.BELL) {
@@ -180,7 +179,7 @@ public class ObserverTracer implements SWPlayer.Component {
return blockData instanceof Door
|| blockData instanceof Gate
|| craftPoweredRail.isInstance(blockData)
|| blockData instanceof CraftPoweredRail
|| blockData instanceof TrapDoor
|| blockData instanceof GlassPane;
}
@@ -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);
@@ -54,7 +54,7 @@ public class ObserverTracerListener implements Listener {
@EventHandler
public void onPlayerInteract(PlayerInteractEvent event) {
if(!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
if (!enabled.contains(event.getPlayer())) return;
if (event.getClickedBlock() == null) return;
ObserverTracer observerTracer = SWPlayer.of(event.getPlayer()).getComponent(ObserverTracer.class).orElse(null);
@@ -28,7 +28,6 @@ import de.steamwar.command.SWCommand;
import de.steamwar.entity.CRay;
import de.steamwar.entity.REntityServer;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.*;
import org.bukkit.block.data.BlockData;
import org.bukkit.entity.Player;
@@ -42,7 +41,6 @@ import org.bukkit.util.RayTraceResult;
import java.util.List;
@Linked
@MinVersion(20)
public class RayVisualizerCommand extends SWCommand implements Listener {
private BlockData VISIBLE = Material.LIME_CONCRETE.createBlockData();
@@ -63,9 +61,9 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
}
private boolean locEquals(Location loc1, Location loc2) {
if ((long)(loc1.getX() * 1000) != (long)(loc2.getX() * 1000)) return false;
if ((long)(loc1.getY() * 1000) != (long)(loc2.getY() * 1000)) return false;
if ((long)(loc1.getZ() * 1000) != (long)(loc2.getZ() * 1000)) return false;
if ((long) (loc1.getX() * 1000) != (long) (loc2.getX() * 1000)) return false;
if ((long) (loc1.getY() * 1000) != (long) (loc2.getY() * 1000)) return false;
if ((long) (loc1.getZ() * 1000) != (long) (loc2.getZ() * 1000)) return false;
return true;
}
@@ -169,7 +167,7 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if (!Permission.BUILD.hasPermission(event.getPlayer())) return;
boolean rayvisualizer = Config.getInstance().get(event.getPlayer()).getPlainValueOrDefault("rayvisualizer", false);
boolean rayvisualizer = Config.STORE.get(event.getPlayer()).isRayVisualizer();
if (rayvisualizer) server.addPlayer(event.getPlayer());
}
@@ -183,7 +181,7 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
for (Player player : Bukkit.getOnlinePlayers()) {
if (Permission.BUILD.hasPermission(player)) {
boolean rayvisualizer = Config.getInstance().get(player).getPlainValueOrDefault("rayvisualizer", false);
boolean rayvisualizer = Config.STORE.get(player).isRayVisualizer();
if (rayvisualizer) server.addPlayer(player);
} else {
server.removePlayer(player);
@@ -194,8 +192,8 @@ public class RayVisualizerCommand extends SWCommand implements Listener {
@Register
public void toggle(@Validator Player player) {
boolean rayvisualizer = Config.getInstance().get(player).getPlainValueOrDefault("rayvisualizer", false);
Config.getInstance().get(player).put("rayvisualizer", !rayvisualizer);
boolean rayvisualizer = Config.STORE.get(player).isRayVisualizer();
Config.STORE.get(player).setRayVisualizer(!rayvisualizer);
if (!rayvisualizer) {
SWUtils.sendToActionbar(player, BauSystem.MESSAGE.parse("RAY_VISUALIZER_ENABLE", player));
server.addPlayer(player);
@@ -36,12 +36,16 @@ public class FireListener implements Listener, ScoreboardElement {
@EventHandler
public void onFireDamage(BlockBurnEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) e.setCancelled(true);
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) {
e.setCancelled(true);
}
}
@EventHandler
public void onFireSpread(BlockSpreadEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) e.setCancelled(true);
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FIRE).isWithDefault(FireMode.DENY)) {
e.setCancelled(true);
}
}
@Override
@@ -44,11 +44,11 @@ public class FreezeCommand extends SWCommand {
}
}
private String getEnableMessage(){
private String getEnableMessage() {
return "REGION_FREEZE_ENABLED";
}
private String getDisableMessage(){
private String getDisableMessage() {
return "REGION_FREEZE_DISABLED";
}
@@ -24,8 +24,6 @@ import de.steamwar.bausystem.region.Region;
import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.FreezeMode;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.core.Core;
import de.steamwar.core.TrickyTrialsWrapper;
import de.steamwar.linkage.Linked;
import org.bukkit.Bukkit;
import org.bukkit.Material;
@@ -33,6 +31,7 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.type.NoteBlock;
import org.bukkit.block.data.type.Switch;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -48,7 +47,9 @@ public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler
public void onBlockExplode(BlockExplodeEvent e) {
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
return;
}
e.setCancelled(true);
BlockState state = e.getBlock().getState();
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
@@ -58,9 +59,11 @@ public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler
public void onEntitySpawn(EntitySpawnEvent e) {
if (Region.getRegion(e.getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
if (Region.getRegion(e.getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
return;
}
e.setCancelled(true);
if (e.getEntityType() == TrickyTrialsWrapper.impl.getTntEntityType()) {
if (e.getEntityType() == EntityType.TNT) {
Bukkit.getScheduler().runTaskLater(BauSystem.getInstance(), () -> {
e.getLocation().getBlock().setType(Material.TNT, false);
}, 1L);
@@ -70,7 +73,9 @@ public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler
public void onBlockCanBuild(BlockCanBuildEvent e) {
if (!e.isBuildable()) return;
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) return;
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.INACTIVE)) {
return;
}
if (e.getMaterial() == Material.TNT) {
e.setBuildable(false);
e.getBlock().setType(Material.TNT, false);
@@ -155,7 +160,6 @@ public class FreezeListener implements Listener, ScoreboardElement {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockBreak(BlockBreakEvent e) {
if (Core.getVersion() < 19) return;
if (e.getPlayer().getInventory().getItemInMainHand().getType() == Material.DEBUG_STICK) return;
if (Region.getRegion(e.getBlock().getLocation()).getRegionData().get(Flag.FREEZE).isWithDefault(FreezeMode.ACTIVE)) {
e.setCancelled(true);
@@ -25,11 +25,9 @@ import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.ItemMode;
import de.steamwar.command.SWCommand;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.entity.Player;
@Linked
@MinVersion(19)
public class ItemsCommand extends SWCommand {
public ItemsCommand() {
@@ -46,11 +44,11 @@ public class ItemsCommand extends SWCommand {
}
}
private String getEnableMessage(){
private String getEnableMessage() {
return "REGION_ITEMS_ENABLED";
}
private String getDisableMessage(){
private String getDisableMessage() {
return "REGION_ITEMS_DISABLED";
}
@@ -25,14 +25,12 @@ import de.steamwar.bausystem.region.flags.Flag;
import de.steamwar.bausystem.region.flags.ItemMode;
import de.steamwar.bausystem.utils.ScoreboardElement;
import de.steamwar.linkage.Linked;
import de.steamwar.linkage.MinVersion;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.ItemSpawnEvent;
@Linked
@MinVersion(19)
public class ItemsListener implements Listener, ScoreboardElement {
@EventHandler
@@ -97,7 +97,7 @@ public class RegionCommand extends SWCommand {
@Register(value = "restore", description = "REGION_REGION_HELP_RESTORE")
public void genericRestoreCommand(@Validator Player p) {
Region region = Region.getRegion(p.getLocation());
if(checkGlobalRegion(region, p)) return;
if (checkGlobalRegion(region, p)) return;
try {
PasteBuilder pasteBuilder = new PasteBuilder(new PasteBuilder.FileProvider(region.getArea().getResetFile()))
@@ -116,7 +116,7 @@ public class RegionCommand extends SWCommand {
Region region = Region.getRegion(p.getLocation());
if (checkGlobalRegion(region, p)) return;
if(node.isDir()) {
if (node.isDir()) {
BauSystem.MESSAGE.send("ONLY_SCHEMS", p);
return;
}
@@ -59,7 +59,9 @@ public class RegionListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockPhysics(final BlockPhysicsEvent event) {
if (event.getBlock().getType() != event.getChangedType()) RegionListener.tagChangedRegion(event.getBlock().getLocation());
if (event.getBlock().getType() != event.getChangedType()) {
RegionListener.tagChangedRegion(event.getBlock().getLocation());
}
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
@@ -67,11 +67,7 @@ public class TNTListener implements Listener, ScoreboardElement {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onExplode(EntityExplodeEvent event) {
if (!(event.getEntity() instanceof TNTPrimed)) {
event.blockList().clear();
return;
}
explode(event.blockList(), true);
explode(event.blockList(), event.getEntity() instanceof TNTPrimed);
}
@Override
@@ -72,7 +72,7 @@ public class TestblockCommand extends SWCommand {
resetRegion(p, node, isExtension ? RegionExtensionType.EXTENSION : RegionExtensionType.NORMAL, isIgnoreAir, isOnlyColor, replaceTNT, replaceWater);
}
@Register(value="default")
@Register(value = "default")
public void setTestblockDefault(Player p) {
Region region = regionCheck(p);
if (region == null) return;
@@ -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;
}
};

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