Author SHA1 Message Date
Lysandr0 a64a911486 Update poms
And a small cleanup
2026-11-06 19:17:05 +01:00
Xaw3ep 15ae1001ee Merge pull request #448 from Updated-NoCheatPlus/transposable
SurvivalFly 'design change
2026-11-06 15:46:52 +07:00
Xaw3ep 1ee3c1ff5e One more fine tune
Hidden motion recovery should no longer run after 1.18.2 although till ~1.21.2 has the real fix. From 1.18.2, the gap is small enough to be always sent
Align entities data from normal events and from packets
2026-11-06 15:40:41 +07:00
Xaw3ep a801091438 A bit refactoring
Allow operation logics can be swapped easily across versions.
Should behave the same before this commit although HiddenMotionReconstructor was not tested

Gliding changes allow boost to end both 1 tick late or immediately.
2026-11-05 01:40:58 +07:00
Xaw3ep 02abcfc1c9 Small tweaks
Correct firework ticking and correct hitbox on some blocks. That it.
2026-11-04 21:45:35 +07:00
Lysandr0 9ce8772fcf Add MC 26.3 blocks.
Not tested. Needs handling for the shelf mushroom bounce mechanic.
2026-10-28 21:04:38 +01:00
Xaw3ep 75ecd05ff3 Add basic velocity handler and entity tracker
Not tested much. Somewhere here and there left unoptimized or incompatible across versions.
2026-10-27 21:14:58 +07:00
Xaw3ep c67e4a4808 Fixes broken headObstructed detection 2026-05-29 23:09:39 +07:00
Xaw3ep 524a48dec3 Less voodoo on NoFall
Fixes fall damage is incorrectly dealt.
We can properly operate in non deal-damage mode when with ProtocolLib by later altering ground state.
2026-05-29 14:33:10 +07:00
Xaw3ep c96fdbb5aa Fixes stair and slime 2026-05-22 20:04:20 +07:00
Xaw3ep ee3078aafa Ops 2026-05-20 17:21:15 +07:00
Xaw3ep 6f6a1e717a Temporary fix for edge sneaking & clean up 2026-05-20 15:03:23 +07:00
Xaw3ep c8b3b14999 Merge pull request #440 from Inquisitors-transfers/bedrock-folia-compat-no-java-models
Compatibility with Folia, Start touching Bedrock a little bit
2026-05-18 17:30:55 +07:00
Git a10f890344 Add Bedrock-only SurvivalFly support envelopes 2026-05-14 23:20:43 -04:00
Git a5c174672a Strip Java movement model leftovers 2026-05-14 23:05:51 -04:00
Git ed210aea3f Split block environment compatibility foundations 2026-05-14 21:59:31 -04:00
Git 09a751eecc Split Folia and net synchronization fixes 2026-05-14 21:56:49 -04:00
Git 5ed24b6545 Split diagnostics config and documentation 2026-05-14 21:53:22 -04:00
Xaw3ep 4ecbdffa07 Start fixing false positives
Since was only tested on 1.20.6, so there might changes across versions might miss
2026-05-13 20:12:26 +07:00
Lysandr0 13a65cb9c4 Formatting, comments, rename some flags, add new MC 26 blocks. 2026-05-09 14:33:27 +02:00
Xaw3ep 9aef9c61cd Maybe final touch with split moves
Slight optimize split moves, do vertical hidden motion restoration too.
Upcoming commits will fix false positives
2026-04-29 14:27:12 +07:00
Lysandr0 46958110d2 Bump NCP to MC 26, Get rid of the legacy shape patch framework, comments/documentation, reduce memory footprint by keeping track of only 2 past moves.
More: get rid of legacy and commented out code (BlockProperties, BlockFlags, AxisAlignedBBUtils, MoveData); deprecate the legacy F_GROUND_HEIGHT flag; add golden dandelion flower; rename MaterialUtil.FULLY_PASSABLE_BLOCKS to NO_COLLISION_BOX
2026-04-05 15:25:48 +02:00
Xaw3ep 1dbae29c4b Tiny fix/cleanup, sync with local
Before I mess things up again
2026-03-29 01:06:49 +07:00
Lysandr0 4e4998e8ae Ops. 2026-03-27 17:15:40 +01:00
Lysandr0 991946290e Let some library methods use the block cache. 2026-03-27 17:07:01 +01:00
Xaw3ep 70a6e6d7ad Restore hidden moves
A prototype so might not fully efficient at some point:
+ Yaw is unknown, assumption was made that unchanged during hidden moves
+ Make sure vertical AND horizontal not larger than threshold
+ Haven't done for vertical
2026-03-23 08:27:10 +07:00
Lysandr0 5a5f20b459 Add copper torch model, don't wildcard lost ground with elytras, comments, throw in Optifine's trigonometric tables 2026-03-01 21:00:49 +01:00
Lysandr0 ddb128dbe8 Merge pull request #424 from Phoenix616/pr/fix-spears
Use correct itemInUse method (Fixes #423)
2026-02-06 08:32:28 +01:00
Xaw3ep f90a7c1b76 Fix exceptions
Fixed #421
Fixed #422
2026-02-04 23:24:01 +07:00
Phoenix616 cedb9710a0 Use correct itemInUse method (Fixes #423)
Also adjust documentation so the correct BridgeMisc method is used
 and prevent potential NPE in BridgeMisc#getItemInUse
2026-02-02 16:36:31 +01:00
Lysandr0 9048ea023b Refine shulker box shape.
More of a test than anything.
The shape is still "wrong" as the box is progressively increased vertically or horizontally (up to +0.5), when players open it. It is not instantly increased by 0.5 when opened.
2026-02-01 11:26:53 +01:00
Lysandr0 3ea3829ae9 Fix issues with block-breaking/shape-definition for 1.21.9 blocks. 2026-01-25 22:41:35 +01:00
Xaw3ep 20e5a7164e An attempt to fix build 2026-01-21 00:00:00 +07:00
Xaw3ep d886176eff Split bounding box for collision and visible check
Finally done the side quest! Add latency handler with overall stabilize should done most of rework
2026-01-20 23:24:20 +07:00
Lysandr0 402b4fd5c5 [blind] Add shelf model 2026-01-11 15:02:16 +01:00
Lysandr0 959f8151ab Apply stash@{0} from branch 1.21.11-update (recovered stash) 2026-01-10 11:05:30 +01:00
Xaw3ep a35d8ffe61 Fix ABI compatibility 2026-01-08 11:28:34 +07:00
Xaw3ep 5e6ee4b8cc Resolve collision shape for few last complex blocks 2026-01-08 04:49:12 +07:00
Xaw3ep 3601db801a Merge pull request #416 from Phoenix616/pr/copper-tools
Support copper tools & 1.21.11 ClientVersion
2026-01-07 20:55:07 +07:00
Phoenix616 066d0268a3 Bump ClientVersion to 1.21.11 2026-01-06 18:57:57 +01:00
Phoenix616 e469c6727c Support copper tools 2026-01-06 18:55:42 +01:00
Xaw3ep 3c54300831 Fix powder snow & correct some blocks' shape
* More or less preparation for splitting out using interaction shape and collision shape instead using collision for both.
* Also because quite hard to add NCP's shape inset exclude/include into RichEntityLocation#collide. Correct the shape, no more mid-way manipulation
* Still there fences, walls, glass panes, bars to go
* Visible checks might malfunction with changed blocks
* Cross-version blocks haven't been tested much from 1.5-1.12.2 as too many false positives from SurvivalFly
2025-12-20 21:29:17 +07:00
Lysandr0 042113e978 Comments, formatting and documentation…
Also, in SurvivalFly, fix minor oversight with the supporting block data passing yAllowedDistance instead of the actual yDistance as argument (horizontal) + check if a legacy player can actually climb upwards.
2025-12-14 21:46:16 +01:00
Lysandr0 2d021ded3a Bump ClientVersion to 1.21.9 2025-12-14 21:44:14 +01:00
Lysandr0 2e6babb977 Adjustments for levitation magic workarounds. 2025-12-14 21:43:04 +01:00
Lysandr0 369f190116 Be sure to set data on early return of movement processing.
This data is needed for powder snow's shape definition. As such, it needs to always be set.
Ideally, the shape should be independent from data set by checks… Needs some refactoring.
2025-12-14 21:42:34 +01:00
Lysandr0 7ef148301e Having a look at inventory-related stuff…
* Skip inv-move checking if moreInv already returned true.
* Do make use of the newer Bukkit API in Open for the invMove check: if the player#getCurrentInput() method isn't available, fall back to NCP's predicted movement.
This makes the check dependent on data set in SurvivalFly but I don't seen any other solution.
* Comment in fight-listener + balance Improbable weights out.
2025-12-14 21:39:32 +01:00
Lysandr0 1449067c17 Merge pull request #414 from Phoenix616/pr/fix-npe
Fix possible NPE and clean up more edge interaction checks (Fixes #409)
2025-12-13 21:01:35 +01:00
Phoenix616 127fbf725c Fix possible NPE and clean up more edge interaction checks (Fixes #409) 2025-12-11 23:57:50 +01:00
Xaw3ep 25b9d27646 First attempt to handle ground riptide
Also fix an error with old versions
2025-12-02 17:36:17 +07:00
Lysandr0 3198615873 Fix riptide-equipped trident release not being detected; fix elytra + riptide; attempt to fix illegalsprint false positives.
* Order of operations for gliding with an elytra while riptiding was wrong: when gliding, riptide motion is added before. Only question that remains is: before stuck speed or after?

* For the tridentRelease flag, the moving trace was resetting the flag too early: as a fix, simply reset the flag manually instead of in the resetBase.

* Some notes/comments
2025-11-08 10:32:25 +01:00
Lysandr0 125a23971a Update some comments and Javadocs
Remove references to ViaVersion's input emulation. It just tries to guess which input the player is moving with; totally unreliable.
2025-11-04 10:59:13 +01:00
Xaw3ep eff2d83139 Fix random liquid false positives 2025-11-04 16:42:04 +07:00
Lysandr0 e5df35dcce Adjustments for the vertical prediction (liquids) 2025-11-03 09:52:25 +01:00
Xaw3ep 5987b4d381 Another sound fix 2025-11-02 18:11:13 +07:00
Lysandr0 1beb1d188f Ops. 2025-11-02 11:37:49 +01:00
Lysandr0 6c1f3caf41 Some touch ups.
Change Vector parameters to BlockCoord ones in SupportingBlockUtils, as we're working with block positions here, not arbitrary Vectors

* Cleanup unused/mostly useless methods in RichBounds

* Avoid checking for a second collision in the "isSupportedBy" method (RichEntity)

* Don't set impulses to NONE in processGliding (SurvivalFly)

* Some cleanup for CreativeFly, MagicWorkarounds
2025-11-02 11:26:33 +01:00
Xaw3ep c8850e7b83 Now working supporting block 2025-11-01 22:25:14 +07:00
Xaw3ep dcdfbc83e0 [Deficient] Make supporting block works 2025-10-21 01:10:18 +07:00
Lysandr0 c4ab7560a4 Don't wildcard lost ground when checking for vertical collisions.
Only check for lost from-on-ground positions.

Do note that the dispatched "fromOnGround" argument takes into account block changes.
2025-10-19 11:13:26 +02:00
Lysandr0 5f26653c7f Fix yOnGround parameter for fastbreak; revise block push handling for SurvivalFly.
The ground-seeking parameter was abnormally large, and no information or documentation was left for us about it. However, it does seem to cause false positives when breaking blocks below, hence the fix.
We now just use the normal yOnGround parameter for movement checks.

Block push is now prioritized in predictions: the vertical one is skipped altogether, and the movement is simply allowed.
For the horizontal one, it’s a bit trickier: the prediction is skipped only if the push occurred on both axes at the same time, saving some resources. If the push occurred on only one axis, the prediction still runs for both, but the result is overridden for the axis on which the push occurred.
This is inefficient performance-wise; we’ll need a refactor to allow NCP to skip predictions on a single axis only.
2025-10-19 11:06:29 +02:00
Lysandr0 112bdaa043 More cleanup.
* Remove several unused methods in PhysicsEnvelope.
* Comments here and there to further clarify code.
* Remove left-over elytra strict mode for CreativeFly.
* Remove useless Magic values,
2025-10-19 11:00:08 +02:00
Lysandr0 108435fd86 Get rid of the void-to-void set back policy.
Questionable policy.
It was added by asofold as a very quick way of stopping players from abusing NCP's set back logic in specific game modes like SkyWars and SkyBlock.
NCP would/does set players back to their last valid ground position, which can be abused to not fall down into the void (though fall damage is still enforced).

We need to implement a "drag-down-to-ground" policy for this.
2025-10-13 19:26:06 +02:00
Xaw3ep 249da9c6e7 Tiny dig down fix
Left some random notes
2025-10-13 23:38:18 +07:00
Lysandr0 3817d568c6 Fix several false positives and bugs.
* Fix gravity being 0.0 at login.
* Re-add the Variable flag to pointed dripstone, as it seems needed for jumping on stacked dripstone for the ground judgement.
* Fix docs.
* Fix vdistrel and block-breaking (not definitive fix)
* Apply levitation workarounds from the last tick.
* Use the Bukkit-provided fall distance instead of ours in powder snow workarounds.
2025-10-12 09:59:11 +02:00
Lysandr0 a0e20f9c29 Fix levitation
Forgot to set the flag. Ops.
2025-10-11 16:29:53 +02:00
Lysandr0 91aa3a9f33 Clarify InputState's scope.
Renamed the class (once again) to better represent the scope of the class, which is storing data for key presses and releases NOT the current status of the player (which you can infer from the player's keyboard input)
2025-10-10 11:19:43 +02:00
Xaw3ep 7b1f19fc4b Set ClientVersion without ProtocolLib 2025-10-10 13:44:09 +07:00
Xaw3ep d84ea4dc92 Random infrastructure fixing
*Changes:
- Fixed infinite VLs for 1.5-1.6.4 lower with wrong attributes values
- Fixed some BukkitAPI problem with sound
- Handled properly Input listener on versions that not-exist such class
- Covered all NPE problems related to usage of PlayerData for block definition. If it null, a check is calling without setting it assume as latest server definition
- Removed safeguard for ClientVersion. It's our fault not setting version correctly not the lib. Also to tell that player is on very old versions
2025-10-10 11:58:21 +07:00
Lysandr0 1f0f9c972c Fix NPE with the Visible checks. 2025-10-09 15:53:41 +02:00
Lysandr0 c09af5be3b Add getLastStrafe(), get rid of sfDirty flag. 2025-10-09 12:22:22 +02:00
Lysandr0 4c86d0a8bf Fix several aspects for snow and powder snow collision.
Also, do set the client version before CNCP. If the setup is correct, CNCP will override what NCP has set.
2025-10-09 10:49:27 +02:00
Lysandr0 8f904387e2 Fix client version setting. 2025-10-09 09:35:19 +02:00
Xaw3ep e474df86f4 Fine
If failed one more time, won't rush
2025-10-08 23:38:05 +07:00
Xaw3ep 3703a51529 Oops 2025-10-08 23:34:23 +07:00
Xaw3ep c08cec4f9b Fixed 1.21.2 input 2025-10-08 23:21:18 +07:00
Lysandr0 da1058c7e4 Update ClientVersion to the latest protocol ID. 2025-10-08 18:05:43 +02:00
Lysandr0 c398a4988e Ops :) 2025-10-08 17:38:59 +02:00
Lysandr0 dcda38716b Refactor for InputState.
Later, we should merge input tracking fields in CombinedData with InputState
2025-10-08 17:36:32 +02:00
Lysandr0 5eafb1f506 Catch even more (literal) edge cases with lost ground. 2025-10-07 17:03:39 +02:00
Lysandr0 df4f2079b4 Fix several aspects of vdistrel; rename class; remove moving trace flags;
For lost ground, we know only (and always) check for the "from" position, since it is the one we're interested in, when checking if the momentum initialisation should be set to 0.0. The "to" position is irrelevant and should only be used to further confine workarounds and such.
As a result, the lost ground brute force has been removed from both predictions.
We require last y motion to be explicitly negative in such case.

The 0.2 motion ovveride was in the wrong place, so it should now be correct, however for lower versions (1.21.1-), we need to loop the space bar press.

Removed several flags from PlayerMoveData in favour of more simple flags in CombinedData, as we don't need to track more than the last state for these specific effects/status. Also, from 1.21.2 and onwards, the input data should be used to read sprinting and sneaking.

Adjusted lost ground conditions a bit (horizontal motion requirements, y acceleration condition)

Renamed InputDirection to InputState, as we now track more than just WASD impulses.

Fixed an NPE in SupportingBlockUtils.
2025-10-07 09:42:20 +02:00
Xaw3ep 264302636c Minor fixes 2025-10-01 21:55:50 +07:00
Lysandr0 ade49a577d Attempt to fix hidden micro moves, revert order of negligible momentum checking.
When the player comes to a stop, after several micro (and split) moves, the actual stop isn't sent to the server. The next move will yield a false positive due to the player moving off with motion based on a previous move of 0.0, which the client did not send.
There doesn't seem to be a way to detect this gap in movement, thus this brute-force case.

Bonus:
* Cleanup
* Comments
* Simplify sprinting checks.
2025-09-30 23:59:23 +02:00
Lysandr0 3e8566de2a Get rid of munchhausen.
The check has been irrelevant for a very long time, since asofold reworked the vertical handling with vDistRel.
It was coded as a preemptive measure for potential bypasses, back when NCP's vertical check was based on jump phases counting (more than a decade ago).
The fix was also questionable at best, as it basically interfered with a vanilla feature (hitting oneself with a rod).
2025-09-28 11:39:50 +02:00
Lysandr0 8bf59cd85b Misc. changes.
* Review improbable checking for fastplace.
* Several comments.
* Rename methods in PlayerData.
* Alter several listener in CombinedListener to be at MONITOR level.
* Request Improbable checking on sending an invalid flying packet.
* Get rid of legacy bloat (Sflegacy)
* SurvivalFly:
  - Attempt to reduce brute-forcing with the horizontal prediction by re-checking for lost ground only when a "from" case happens.
  - Re-order vertical negligible speed reset.
2025-09-26 17:18:50 +02:00
Xaw3ep 2839e6a40f Forgot that hspeed consumes Input data when use. Cloning!
Also fixed most weird hspeed falses due to wrong place for negligible speed.
2025-09-26 07:51:28 +07:00
Xaw3ep f2a8cc6f64 Correct collision block shapes, versions crossing compatible 2025-09-24 18:19:37 +07:00
Xaw3ep e3560651c1 Proper Input Implementation
And some random notes
2025-09-23 02:56:44 +07:00
Lysandr0 aa08284c03 Let it compile. 2025-09-15 18:03:40 +02:00
Lysandr0 60fa3bbdc7 Several changes.
* Attempt to model the correct/exact collision shape of Scaffolding. To be tested.
* Begin to lay out the groundwork for a flying packet-move event sync system.
* Get rid of the old vDistClimbable implementation, now that we have all shapes for climbables.
* Lots of cleanup here and there.
* Missing headers.
* Do request a set-back for ALL cancelled flying packets; even those awaiting for an ACK packet.
* Listen for RiptideEvent; not complete.
* Feed couldstep usage to lost ground (very low weight but might prevent repeated abuse).
* Remove unused variables from netdata.
* Refine trident velocity calculation to account for the 1.2 offset properly.
2025-09-15 15:40:14 +02:00
Lysandr0 7a8995cb2b Merge pull request #403 from Phoenix616/pr/hide-debug-messages-unless-enabled
Only print debug chat messages when debugging is enabled (#402)
2025-09-10 17:24:00 +02:00
Phoenix616 5a7a6cc76b Fix build by updating address of ProtocolLib repository 2025-09-10 12:36:07 +02:00
Phoenix616 91692d8a5e Only print debug chat messages when debugging is enabled (Fixes #402) 2025-09-10 12:26:16 +02:00
Xaw3ep 0ec5bd9439 Fix vertical prediction not working
Accidentally set vertical prediction on fire because of changing internal return value type but forgot to change outside calls. Should be fixed.

* Up coming(depend on priority and difficulty of doing):
- Complete Input tracking system
- Further refine isOnGround() shortcut and workarounds
- Add wall collision handler / affirmation of velocity usage
- Add minimal entities tracker to improve entity collision check
2025-09-06 10:10:08 +07:00
Lysandr0 a635fccd77 Update poms, fix drip leaf shape definition, review usage of the legacy F_VARIABLE flag, adjustments for powder snow's on-ground judgement.
Also add comments here and there.
Next up:
* Finish the Input tracking system.
* Fix vertical prediction not working, somehow.
2025-09-04 21:06:32 +02:00
Lysandr0 048ac8f84a [Bleeding][Broken] Sketch input-tracking on packet-level. 2025-09-02 17:45:26 +02:00
Lysandr0 02766a11d3 [Bleeding] Update reflection methods and fix bad version input error in GenericVersion. 2025-09-01 12:10:37 +02:00
Lysandr0 0623d7592f [Bleeding] Listen for impulses via PlayerInputEvent 2025-08-31 22:03:25 +02:00
Lysandr0 7e5c65b828 [Bleeding] Add 1.21.5/6 blocks.
Probably needs adjustments; especially for the hit/collision box definition of wildflowers and leaf litter.
2025-08-31 12:19:31 +02:00
Lysandr0 e14a49e6e3 Let it compile 2025-08-30 11:06:07 +02:00
Lysandr0 5b3bda5cb8 Merge branch 'dev' 2025-08-17 12:20:04 +02:00
Lysandr0 560ff53bac Moving random/small changes on remote. 2025-08-17 12:17:40 +02:00
Lysandr0 61d329edc5 Slowly getting back a bit…
* Do register 1.21 blocks - 1.21.5 blocks are still missing TBD;
* Sweep old/legacy isVelocityJumpPhase field - no longer needed with the upcoming velocity rework;
* Naming conventions, cleanup;
* Attempt to guess/brute-force when the 0.2 climbable speed should be applied when in powder snow.
* Remove redundant collision checking for bubble columns
2025-06-01 09:40:41 +02:00
Lysandr0 6a13a6b4ed Merge pull request #378 from TreemanKing/1214
fix: 1.21.3 new packet data for position
2025-03-18 10:39:37 +01:00
Lysandr0 ba2e189b8d Merge pull request #383 from PsychoHashMap/patch-1
Added better ProtocolLib compatibility for later versions.
2025-03-18 10:36:09 +01:00
Lysandr0 457284858e Complete the supporting block mechanic sketch; misc changes.
* Clarify and clean-up javadocs; add comments.
* RichBoundsLocation:
   - getTypeId/Above() -> getBlockType/Above().
   - getAABBCopy() -> getBoundingBox().
   - Align collision checkers to the other ones (do not check in a top-down way)
* Magic: move envelope methods to PhysicsEnvelope.
* PlayerEnvelopes -> PhysicsEnvelope.
* Remove unneeded method in TrigUtil.
* BlockProperties:
   - getBlockFrictionFactor() -> getHorizontalFrictionFactor().
   - Attempt to handle powder snow behaviour within the on ground judgement.
   - Remove unused World argument in isOnGround().
* DataManager: add getPlayerDataForEntity().
* PlayerMoveData: differentiate jumping from just pressing the space bar.
* AxisAlignedBBUtils:
   - Rename creation methods.
   - When converting a BoundingBox object to a double array, check it is null and create an "empty" box of all 0.0 if so.
* SurvivalFly:
   - Correct minor oversight with the gravity-reiteration fix.
2025-03-14 13:41:14 +01:00
PsychoHashMap 67dd4bccda Added better ProtocolLib compatibility for later versions.
Tested as working on 1.21.1.
2025-03-07 19:02:02 +00:00
Lysandr0 059727e2bd [Incomplete][Broken] Some refactoring.
* Split tracing stuff into more sub-packages (distinguish ray-tracing from axis-tracing);
* Move InventoryUtil to entity package.
* Begin sketching the supporting block mechanic introduced in 1.20 (correctly, this time); incomplete. Haven't implemented it yet into the prediction system.
* Correct an oversight in PlayerEnvelopes (jumpPhase for jump motion checking).
* One more tweak for powder snow collision (use BlockProperties.collidesBlock() directly, instead of collides()).
* Naming convention: Velocity -> VelocityAdapter.
2025-02-05 20:53:39 +01:00
Lysandr0 0694419f52 Ops…
Move out BlocksMC1.21 from special…
2025-01-30 10:14:06 +01:00
Lysandr0 6089ec3f7b More tweaks on powder snow collision.
* Powder snow doesn't exist on 1.16 and below, so make sure the isInsideBlock check returns false in that case (ViaVersion maps it to regular snow which has a solid collision box, which will be a problem with wall collision: NCP will see the abrupt deceleration without knowing that it was caused by the client seeing powder snow as a solid block.)

* Attempt to adjust the collision checking:  ensure that we only check the exact block the player is currently inside.

* Check for shift key toggles within the block-shape definition.

Bonus:
* Align naming convention for velocity flags.
* More comments
2025-01-30 09:55:22 +01:00
Lysandr0 2d51e4f8cb Add support for "weaving" effect, remove old explosion flags. 2025-01-28 14:53:01 +01:00
Lysandr0 3b60ae8aa9 Bump to 1.21.4, slight revision on powder snow collision (rich bounds), fix/adjust javadocs.
Side note: need to study how bundles work exactly, and evaluate cheating potential for this gameplay mechanic (namely, fast-clicking and inventory manipulation. FastClick may need to be updated).
2025-01-27 23:01:06 +01:00
Xaw3ep 1e75c342c7 Partly velocity processor rework 2025-01-27 05:45:10 +07:00
TreemanK 2ac8c27856 fix: 1.21.3 new packet data for position
HorizontalCollision was added as a new boolean. This caters for it
2024-12-13 12:28:20 +11:00
Lysandr0 4f9a3fb605 Sketch push effect for entities (horizontal speed).
+ random change to how h-offsets are calculated.
2024-12-11 10:09:11 +01:00
Xaw3ep 33a2b1c7fe Adjustment on legacy clients 2024-11-26 11:16:19 +07:00
Lysandr0 b173710280 More clean up and clarification of docs. 2024-11-23 14:41:45 +01:00
Lysandr0 04d8e6ccde More changes.
* Suppress some warnings
* Changed my mind: keep everything in one class for legacy input calculations.
* Remove inLiquid condition for levitation in the MovingListener.
* Add inLiquid condition for the jumping envelope.

Prediction for both vertical and horizontal seems to be broken for versions below 1.12. Still investigating why… Too tired to continue right now.
2024-11-12 18:54:31 +01:00
Lysandr0 0e802ca9de It's the actual distance, not the allowed one here :) 2024-11-08 08:56:31 +01:00
Lysandr0 26a053d6cf Make use of player#getCurrentInput(), fix a bunch of errors encountered on 1.8. 2024-11-07 21:52:21 +01:00
Xaw3ep a1f11aa32a Tweak on v_exiting_liquid 2024-11-07 22:45:19 +07:00
Xaw3ep f5ed107e2b Somewhat runnable 2024-11-07 14:56:28 +07:00
Xaw3ep 8b98ac72b9 An attempt to fix old unit tests
I have no idea why it still throw java.lang.NullPointerException although the build return success?
2024-11-01 00:01:10 +07:00
Lysandr0 80dc6bb8e0 Ops. 2024-10-30 08:39:27 +01:00
Lysandr0 3bfb217896 Attempt to track the obstruction flag with the past-move tracking system.
A really hacky way to do so. Since we need the Entity instance, we cannot use RichBoundsLocation.
2024-10-30 08:31:58 +01:00
Lysandr0 2e73401803 Move some classes around
Use the compat.bukkit pacakge for Bridge classes that have the specific purpose of solving API breakages between versions.
2024-10-30 08:09:45 +01:00
Lysandr0 d1a88dbc23 No spigot dependency here. 2024-10-29 14:04:42 +01:00
Lysandr0 0a56ded6d3 Adapt to 1.21.3 changes. 2024-10-29 13:33:39 +01:00
Lysandr0 f01bcefa58 Merge branch 'hspeed' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed 2024-10-27 19:43:35 +01:00
Lysandr0 c0a66a56ee Touch-ups here and there. 2024-10-27 19:17:55 +01:00
Xaw3ep 05f9b9f1de [Bleeding] Correct vertical liquid prediction 2024-10-27 23:36:03 +07:00
Lysandr0 53ff9d299d Revert the "noslow bypass" fix for the moment. 2024-10-14 16:38:23 +02:00
Lysandr0 32edebf3ba Ops. 2024-10-12 08:44:11 +02:00
Lysandr0 6c73899fa9 Throw more utility methods in AxisAlignedBBUtils 2024-10-12 08:36:24 +02:00
Lysandr0 9a9f195d03 Update several methods to 1.21 changes (collide(), maybeBackOffFromEdges()) 2024-10-04 14:27:38 +02:00
Lysandr0 e0fa64c213 Finish implementing modern attributes (+ more cleanup). 2024-10-04 13:59:09 +02:00
Lysandr0 a310b9ebef Implement (most of the) 1.20.5/1.21 attributes, continue working on the vertical liquid speed prediction, better documentation for some methods.
Attribute implementation is still missing for legacy modules… TBD at a later time.
2024-09-22 14:35:21 +02:00
Lysandr0 53d14f3a36 Merge pull request #372 from IAISI/master
Minor performance improvements
2024-09-15 08:59:13 +02:00
Dieu d4181ce990 Minor performance improvements 2024-09-10 00:40:14 +02:00
Lysandr0 38d0486279 Merge pull request #369 from EclipsesDev/fix-noslow
Fixed updatedncp switchitem bypass
2024-09-04 10:14:28 +02:00
Eclipses 6143288a88 Fixed updatedncp switchitem bypass
previous one fixes switchitem noslow if it is send constantly, but if it send once + c08 packet, previous fix will not work, so this one should patch it
2024-08-30 21:41:38 +07:00
Lysandr0 dd2136eea7 Merge pull request #367 from skbeh/fix-below-1-12-loading
Fix loading on below 1.12
2024-08-22 09:15:57 +02:00
skbeh a2c81f7d9b Fix loading on below 1.12 2024-08-20 10:04:38 +00:00
Lysandr0 f8502fe8e6 [Broken] Sketch an inside-liquid vertical prediction.
Lots of issues still remain (this is mostly a starting point).
Namely:
1) I can't seem to find how the game handles gravity in liquid (descending; not pressing the space bar);
2) It still doesn't account for all version-dependent nuances (i.e.: 1.12 and below clients not being able to swim up to the surface), because it is a major pain in the ass to: 1. download all NMS sources 2. research and note down what changed across versions… So, what we(I?)'ll do is to just account for 1.8 clients, since that is the most used (and relevant) legacy version (at least for publishing a beta in master);
3) Vertical medium-checking order is (currently) wrong: Minecraft checks for water first, then for lava, then gliding, and finally, it falls back to air (Source: EntityLiving.java -> travel() method).
For vertical predictions, NCP check for climbing first (odd one out, because we still use a limit-based implementation for it), then gliding, and then it falls back to vdistrel, which unifies air and liquids.
I chose to trade NMS logic for code readability within NCP. Having two, almost-identical vdistrel methods (one for liquid, one for air) would be extremely ugly.
Still, it'd be best to (pedantically) follow what NMS does.
This could be solved by unifying vertical and horizontal predictions. But… Willpower, I guess? :)

The code is starting to get harder to read too, so perhaps it’s time to merge vertical and horizontal predictions to reduce redundancy anyway.
2024-08-07 21:54:28 +02:00
Lysandr0 e4126cdfa8 Heavy core assigned to pickaxe. 2024-08-07 14:45:05 +02:00
Lysandr0 89643cc734 Streamline code, much better documentation for several parts of code, refactor ray-tracing/axis-tracing code to an extra package.
* Rename methods in ClientVersion for less verbosity.
* Add convenience methods to ClientVersion.
* Add method to get either the player's or the entity's version in GenericVersion (and make use of it in RichEntityLocation).
* New Class: AxisAlignedBBUtils. To contain all utility methods related to bounding boxes.
* Remove unused code in MathUtils and MovingUtil.
* Move some methods around classes (Visible, CollisionUtil, MathUtils…).
* Do cross-version checking for bouncy blocks in RichEntityLocation.
* More conditions for checking the legitimacy of toggle sprint.
* Check for client version in the maybeElytraBoost method.
* Attempt to fix bunnyhopping in low-ceiling areas (isVerticallyConstricted…)
2024-08-06 13:40:39 +02:00
Lysandr0 676dedb199 [Bleeding] Support wind charges. 2024-08-03 11:03:49 +02:00
Lysandr0 aa45920d88 Merge branch 'master' into hspeed 2024-08-03 09:12:42 +02:00
Lysandr0 6bb5820e3a Review usage of player#isSneaking() throughout the code. 2024-07-11 23:18:19 +02:00
Lysandr0 39dca7f8b8 Mark "dirty phase" (and related code) as deprecated.
Dirty phase = an air phase affected by velocity.
Very old code that will soon be phased out once we make vDistLiquid predictive as well.
2024-07-11 21:50:42 +02:00
Lysandr0 2e3c7244f7 One more iteration for crouching VS shift key press. 2024-07-11 21:25:21 +02:00
Xaw3ep 867a5b66b4 [Bleeding] Adjustments on snow blocks 2024-07-11 23:49:56 +07:00
Lysandr0 804d5964d6 Make use of findSupportingBlock method for grabbing the correct block-friction.
Also, fix an opsie with the sprinting detection :)
2024-07-11 13:32:17 +02:00
Lysandr0 0dfb553965 [blind] attempt to patch up maybeBackOffFromEdge()
As a bonus: keep track of negligible horizontal collisions; check for Improbable on fake-bed leave packets and do check for enough impulse for sprinting (apparently the game does have such condition).
2024-07-10 16:11:45 +02:00
Xaw3ep 814b48cc3c More adjustments 2024-07-10 19:40:22 +07:00
Lysandr0 dfe93bd98a Several movement-related fixes. 2024-07-10 07:33:07 +02:00
Lysandr0 07f7eba2f4 Further clarify crouching VS sneaking.
Fix some typos
2024-07-09 16:25:39 +02:00
Lysandr0 cceb7cfd30 Patch up vertical bouncing.
Also fix a compilation error.
2024-07-07 13:57:40 +02:00
Lysandr0 0cddcd1ff1 Merge branch 'hspeed' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed 2024-07-07 09:21:12 +02:00
Lysandr0 7cbd79789e Demote ImpossibleHit to boolean config options, cleanup VIII, fix some issues with Folia and teleportation. 2024-07-07 09:17:32 +02:00
Xaw3ep ea24fa1c57 Fix most horizontal movement calculation errors 2024-07-07 05:39:07 +07:00
Xaw3ep 71252d72cf Working on 1.21
Last version of NCP 3? Too many bugs can't be handle on current codebase. Will now focus on rework.
Changes:
+ Fix fall damage bug with folia on change world
+ Compatible with wind charge
2024-07-04 15:34:32 +07:00
Lysandr0 4a9bccd205 Merge pull request #352 from CMSMortal-chen/patch-1
Fix "Exception with AutoListener"(Maybe)
2024-06-15 23:12:32 +02:00
Mortal_chen 894f3b4779 Fix typo
zombeified_piglin to zombified_piglin
2024-06-01 23:09:16 +08:00
Lysandr0 6f25a0f0f8 Sketch "isSolidFace()" NMS method, change for some method signatures, Cleanup VII
Speed factor methods will now use LivingEntity instead of Player signatures, because they'll be used in the future for vehicles as well.

isSolidFace is untested.
2024-05-17 20:52:12 +02:00
Lysandr0 fd92cde1d9 Compile errors. 2024-05-15 14:05:28 +02:00
Lysandr0 11163230ac Merge branch 'master' into hspeed-collide 2024-05-13 21:54:50 +02:00
Lysandr0 c9741a3e33 Cleanup VI 2024-05-12 21:40:10 +02:00
Xaw3ep 9bb34f6f2d Core compatibility 1.20.5/1.20.6
+ Missing newly added attributes!
2024-05-13 00:15:11 +07:00
Xaw3ep cce1a0ef72 [Broken][Bleeding] Manually implement collide function 2024-04-24 01:20:13 +07:00
Lysandr0 9201ff03ec Ensure that players get the correct fall damage penalty for falling on stalagmites.
Vanilla mechanic: falling on stalagmites will roughly double the fall-distance that will be used to calculate the subsequent fall-damage.
Because the fall-distance (not damage(!)) is multiplied, this means that even just jumping on pointed dripstone can damage the player (half a heart)

+ random comments here and there.
2024-03-06 00:04:31 +01:00
Lysandr0 db3237f1ee Cleanup V: Post merge touch-ups.
+ update client version to 1.20.3/1.20.4 + explicitly state what kind of "step up" we are checking in vidstrel with the "isStep" method.
2024-02-20 17:28:45 +01:00
Lysandr0 957c1d8ea2 Merge branch 'master' into hspeed-collide 2024-02-15 22:09:20 +01:00
Lysandr0 5e1f775d59 Merge branch 'hspeed-collide' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed-collide 2024-02-15 22:01:49 +01:00
Lysandr0 14a19a9512 Cleanup IV 2024-02-15 21:57:43 +01:00
Xaw3ep a094328cde Small commit to practice reverse engineering
Add shape for bamboo and dripstone on bedrock
2024-02-13 13:52:31 +07:00
Xaw3ep 91b40d88f3 Fix #334 #333 2024-02-03 22:41:54 +07:00
Xaw3ep aad0e617dd Attempt to fix #331 and fix a false positive with Visible 2024-01-21 22:44:00 +07:00
Lysandr0 da64b55ec1 Cleanup III, don't apply the step-up fix if the client is too old, keep track of forward/strafe impulses with the move-tracking system
+ adjust workarounds + use
2024-01-12 15:44:24 +01:00
Lysandr0 dfa26533cb Merge branch 'hspeed-collide' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed-collide 2024-01-11 20:46:15 +01:00
Xaw3ep 2e172a4de7 Second attempt 2024-01-12 00:31:54 +07:00
Lysandr0 0665155d9f Merge branch 'hspeed-collide' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed-collide 2024-01-11 14:33:08 +01:00
Lysandr0 a87262f64b Cleanup II, adjust levitation, distinguish between "fromLostGround / toLostGround" and don't wildcard lostground anymore with workarounds. 2024-01-11 14:32:52 +01:00
Xaw3ep 5e857b225e Merge pull request #330 from skbeh/replace-random
Replace usage of java.util.Random
2024-01-11 18:21:07 +07:00
Xaw3ep c0578c52b6 Close inventory instead of cancelling hit 2024-01-11 18:19:58 +07:00
Xaw3ep 2ac54c712f Attempt to fix collisions 2024-01-11 17:38:45 +07:00
Lysandr0 a2bc2e5c58 Cleanup 2024-01-09 20:19:56 +01:00
skbeh f965f2ad3d Replace usage of java.util.Random
Replace usage of java.util.Random with java.util.concurrent.ThreadLocalRandom,
or java.util.SplittableRandom when setting seed is required. This provides better
performance and randomness.

Also do not manually generate seed when unnecessary since the Java runtime
mixes more bits into the automatically generated one.
2024-01-09 09:44:15 +00:00
Lysandr0 c4bd3f2e20 Refine step-up handling with vDistRel.
Also pass the horizontal (X/Z) motion to the collide method, in order to be able to judge if the player will be able to step-up with this vertical move, in case the current move doesn't fit into NCP's step-up definition (moving from ground to ground with 0.6 motion).
2024-01-08 21:36:59 +01:00
Lysandr0 bd501b6a68 Disambiguate the new headObstruction flag from the old isHeadObstructed method.
The old method's naming convention is now "seekHeadObstruction" because this is what the method essentially does: it uses a given margin (or a correction method, or both) to seek for collisions above, but it doesn't necessarily mean that the player does collide with something.
2024-01-07 23:26:43 +01:00
Lysandr0 e15d614bb8 Ensure that null bounds are returned only for truly passable blocks.
(Fix ported from the other branch)
2024-01-07 19:05:12 +01:00
Lysandr0 fd872fe26c Adjustments for head obstruction, fix first descending move after stepping down a bed for newer clients
Also, re-define head obstruction definition by using the collide method + blindly (and roughly) attempt to support horizontal collisions.
2024-01-07 18:37:33 +01:00
Xaw3ep 610b4b082c Correct height
Idiot me back then
2024-01-07 16:05:54 +07:00
Lysandr0 c163bbe76b Ops...?
Forgot to push this one on remote. Idiot me...
2024-01-05 22:07:07 +01:00
Lysandr0 b7b2a6d12a Ensure to use the bounding box of the "from" position when computing collisions. 2024-01-05 20:56:16 +01:00
Lysandr0 5877736f84 Fiddling around with Minecraft's collision method.
Attempt to actually predict collision movements, instead of resorting to workarounds (at least for the vertical part).

* Experiment with block change tracker and block breaking below...
2024-01-03 19:44:51 +01:00
Xaw3ep 126c135c0b Typo 2023-12-30 13:22:22 +07:00
Xaw3ep 7604b8601c Test collide 2023-12-29 19:55:00 +07:00
Xaw3ep ef4e959dfa Adjust to only add null bound to truly IGN_PASSABLE 2023-12-29 03:59:36 +07:00
Lysandr0 49ad9f9f41 Adjust touch down workaround.
Compare to predicted distance not actual one.
+ fix a compile error
2023-12-28 21:25:12 +01:00
Lysandr0 92f1c8ff78 Merge branch 'master' into hspeed 2023-12-28 17:29:36 +01:00
Lysandr0 15cc6e11e1 More refactoring and simplification for lost-ground workarounds.
Keep them minimal and use the interpolation method to catch most cases + adjust some workarounds.
2023-12-28 15:02:30 +01:00
Lysandr0 1c5d8ebb97 Rework gliding handling for the most part.
Consistency checks are done within the combined listener. The actual checking method is now done in SurvivalFly.
Fireworks are still a pain, however.

Also revert the arm-swing inventory-checking thing of the last commit (my bad ops).
2023-12-28 15:00:55 +01:00
Xaw3ep ae2ab3543f Do sort XZ when Y not possible to pass 2023-12-26 13:48:37 +07:00
Xaw3ep c56a33351d [Breaking] Update to visible
Should be last changes to fix previous known bypasses.
Remove passable_x4 from all trap door because it not the same behavior with gate.
And make passable blocks has no ground will be null bounding box from now on
2023-12-26 13:07:49 +07:00
Xaw3ep 6e88781512 Fully support 1.20.4 2023-12-26 12:33:36 +07:00
Lysandr0 d0015cb7c1 Merge branch 'master' into hspeed 2023-12-21 00:14:57 +01:00
Lysandr0 bd56b867af Handle lost-ground uncertainty in a cleaner way, move some of the vertical uncertanity in its own method.
Instead of proactively calculating speed with thisMove#touchedGroundWorkaround, let lost-ground be treated as an "after failure" check: if the player fails the horizontal prediction and a lost-ground case happened, force-set the ground flag and re-calculate (effect on performance needs be evaluated).
Same thing applies for vertical motion with the PlayerEnvelopes#isTouchDownMove thing.

More:
* At last, get rid of bunnyfly: with a stricter vertical monitoring this should not be needed anymore.

* On respawning: let the player decide if sneaking/sprinting should be reset.

* Clarify some stuff here and there.

* Unbind lost-ground from toIsValid check in AirWorkarounds (move validity is already checked in lost-ground)

* Do still register item-use events/adapters from 1.12 up to 1.17
2023-12-20 21:39:38 +01:00
Lysandr0 682240e8e7 Patch up bouncing (+ some more stuff).
* Move riptide force equation to BridgeEnchant.

* Do check for cached onGround within overloaded methods as well (RichBoundsLocation, prevents abuse with lost-ground + snow shoe cheats)

* Ensure to check for equality in the split move mechanic.

*Ensure to close inventories on swinging one's own arm.
2023-12-20 10:50:43 +01:00
Xaw3ep 785c19dfdc Comments & Javadoc
Also fix minor issue with carpet and close inventory when attack
2023-12-19 18:29:38 +07:00
Xaw3ep 9dc3e81f46 [Bleeding]Add fight.visible
Similar to blockinteract.visible, not a precise ray-cast but likely to provide more compatibility with bedrock later on. Look independent!
* Known bypass:
- Behind the door(at the door block)
- Bottom/behind slab and trapdoor
* Known false positive:
- ...Waiting for report!
* Might-Missing:
- BlockChangeTracker?
Will fix in next build or so, for now just rest a bit for fully update to 1.20.4.
2023-12-18 14:00:17 +07:00
Xaw3ep 349c96b9ef An attempt to avoid getting flag by AV
Don't know why!
2023-12-15 13:48:15 +07:00
Xaw3ep 2d8255400d [Bleeding][Breaking] Rewrite block interact visible 2023-12-14 22:18:30 +07:00
Xaw3ep 7cc3a81631 Merge pull request #328 from Brokkonaut/1.20.4
Quick fix for 1.20.4
2023-12-14 21:30:57 +07:00
Brokkonaut c00fc5c857 Quick fix for 1.20.4 2023-12-13 09:10:26 +01:00
Xaw3ep a212480ca1 Fix crash issue and false flag on leave vehicle 2023-11-22 18:19:41 +07:00
Lysandr0 47000d1061 Force-close inventories on switching items, attempt to fix gravity change when breaking blocks underneath.
(Also, more opsage)
2023-11-13 21:31:13 +01:00
Lysandr0 1da6229bef Resolve most issues related to sneaking.
Properly set the sneaking status with player-poses, instead of shift key presses (see comment in CombinedListener. Could be worthy of a ticket to Spigot).
1.14 sneaking mechanics have been refined, for the most part. There's still one nasty issue that I couldn't manage to fix: trying to jump in 1.5 blocks-high areas… Jump is seemingly undetectable, so we may have to brute-force speed there….

More:
*AirWorkarounds: tighten up touch-down workaround; test for the most frequent workarounds earlier.

* Adjust things (and jump definition) to take crawling into account.

* Just to be sure: seek for literal "releaseUsingItem" name as well when reflectively calling the method.
2023-11-12 21:51:33 +01:00
Lysandr0 1e8ad02740 Cleanup all imports. 2023-11-12 21:51:10 +01:00
Lysandr0 8d7f6573cf Ops. 2023-11-09 15:01:57 +01:00
Lysandr0 dd4492dca2 Revise item-use handling to use Bukkit's HumanEntity#getItemInUse()
After… 12 or so years, Bukkit finally has a method to know if the player is using an item (not just blocking(!)), thus, the adapter is not needed anymore.
(How have we not noticed it this whole time!?)

Also move the resetActiveItem stuff as a service in PlayerData.
2023-11-09 14:48:06 +01:00
Lysandr0 fdb2c7b42a First iteration for Mojang's block collision bug-fix.
+ some formatting and better compatibility with cross-version checking in RichEntityLocation
2023-11-09 14:41:57 +01:00
Lysandr0 50b9eae3fd More progress (implement maybeBackOffFromEdge method).
Works somewhat okay but it still throws false positives, will need more iterations.

More:
* "Properly" handle wall collision. Implementation is not necessarily the most elegant, but it is the most robust and exploit-free, judging from some testings (couldn't reproduce any more false positive with it).

* Adjust jump definition in PlayerEnvelopes.

* Formatting and adjustements for AirWorkarounds (add rule for wrong split move etc...).

* Confine stepdown-from to not having slowfall.

* Get rid of legacy riptide implementation with CreativeFly.

* Check for client-version in the getLookingDirection method (apparently 1.12 and below have a slightly different equation).

* Add a temporary non-vanilla friction library for vDistLiquid only in BlockProperties, which still uses the old style implementation.

* Comments, clarify docs, clarify debug format and style for movement (should be a bit more readable).

* Get rid of Critical's config. options.

* Move elytra gliding consistency checks in the CombinedListener.

* Throw in legacy liquid collision methods (especially for lava's, which is quite inconsistent throughout recent versions).

* Zero drip leaf's AABB if unstable (workaround, needs to be tested)

* Use Spigot's new PlayerSignOpenEvent to handle AutoSign with 1.20 signs.

* Prepare / sketch a first SurvivalFly-based prediction with the elytra.

* Properly return -1 if could not get the firework boost power (BridgeMisc).

* Update ClientVersion up to 1.20.2.

* Bridge 1.13: test if a server may have a built-in raytracing implementation (Bukkit did introduce it in 1.13.2)

* Get rid of jump-phase check.

* Open: use SurvivalFly's prediction to know if the inventory needs to be closed

* Target Spigot's 1.20.2 from now on (poms)
2023-11-03 15:13:34 +01:00
Lysandr0 64bf374fd3 [#322] Return the correct DamageCause for fall damage.
Caused by map/obfuscations changes.
2023-10-18 21:52:45 +02:00
Lysandr0 a3acd8d522 Sketch a first SurvivalFly-compatible riptide prediction, fix a logic issue with the fastclick.chest subcheck. 2023-09-23 13:15:27 +02:00
Lysandr0 edacb1a04f Ops.
Missed that one.
2023-09-20 16:35:12 +02:00
Lysandr0 b099ebd807 Merge branch 'master' into simplify-vdistrel 2023-09-20 16:23:43 +02:00
Lysandr0 a394b9e29a A whole lot of changes.
* Adjust stepping, jumping and bunnyhopping definitions to lost ground.
* Simplify AirWorkarounds (get rid of most of them, favouring a more coherent class).
* Re-add some lost ground cases; distinguish lost ground for vertical VS for horizontal motion (some cases won't apply to vertical but for horizontal and viceversa, see the "missedGroundCollision" comment) and format for much easier debugging (or at least look).
* Get rid of minJumpHeight method in LiftOffEnv.
* Move hasAttackSlowDown flag to the CombinedListener.
* Get rid of -now- unused sfZerovdistrepeat flag.
* Set sneaking, sprinting and use item status in PlayerData. See comments in the CombinedListener class as for why.

* CollisionUtil:
 - Some methods to get entities around players.

* RichEntityLocation:
 - As a bonus: selectively add cross-version compatibility with multi-protocol plugins in several places (honey blocks, berry bushes, levitation [...]).
 - Properly handle on-ground judgement with powder snow.
 - Implement a proper isSlidingDown method.

* RichBoundsLocation:
 - Format, order, remove redundant contraction of the bounding box with liquid checking (+ 0.001), fix bubble column collision and lastly, revert a change brought by @xaw3ep with the bounding box setting: using fullWidth / 2f is imprecise and will lead the isHeadObstructed method to return true when moving alongside walls, for now, the fix has been reverted to the  old resolution of Math.round((fullWidth * 500.0) / 1000).

* MovingListener:
 - Check for sneaking directly in the envelope method for bouncing and get rid of old stairs workaround.

* InventoryUtil:
 - Move the hasArrow method to the InventoryUtil class (+ some formatting).

* SurvivalFly:
 - Get rid of the now useless LIMIT_NEAR_GROUND envelope.
 - Adjust use of head obstruction checking.
 - Rough handling of slimce bounce mechanic; will need some adjustments down the road...
 - Somehow handle powder snow climbing.
 - Attempt to handle "unknown" horizontal movements: if we can't find a match (= a predicted speed having an offset smaller than 0.0001), set in this move the closest predicted speed to the actual one and adjust it through some kind of workaround.

Overall, we're reaching (and probably already stretching) NCP's infrastructure limitations.
This is especially noticeable with the on-ground judgment and collisions in general, which are the two main things that are preventing us from merging the branch in master (at least as a beta version).
Usually, NCP’s on-ground system is enough to get by even with more complex scenarios (i.e.: stepping), however the amount of edge cases to manage is (starting to be-) overwhelming: with predictions, we not only have to deal with lost ground -which already is a huge pain in the ass per se- but we also have to deal with the same issue on the opposite spectrum, or in other words, with “excessive ground” cases.
Just take a look at the LostGround class, PlayerEnvelopes.isJump()/Step() and all comments in AirWorkarounds.



Missing: 

Vertical:
 - In water/lava -> in air transitions
 - Jumping in waterlogged blocks
 - Implement the correct collision logic for 1.20 players (richentitylocation).
 - Fix insidePowderSnow checking (see notes in RichBoundsLoc).
 - Fix split move messing up when jumping in honey blocks.
 - Jumping on the very edge of chest lost ground case (completely misses the ground collision, player is seen as having 0.42 motion in air... Is it a shape issue rather?).
 - Wobbling up on slime blocks/beds (still need some adaptations to it. Getting sporadic false positives).

Horizontal:
 - Still false positives when moving against walls…
 - Lost ground still messing with prediction in general…
 - Still false positives when getting pushed…
 - Still missing that maybeBackOffFromEdge method…

IMPORTANT:
- We need to port / code / workaround Mojang’s new logic for moving along the edges of blocks with nothing else underneath (block properties are now properly applied even on the very edge)
2023-09-20 13:52:42 +02:00
Lysandr0 572a26ae3f Merge pull request #319 from Dreeam-qwq/tabcomplete-players
Add TabComplete players
2023-09-17 07:10:37 +02:00
Dreeam 35bee4cbef Add TabComplete players 2023-09-14 13:05:55 -04:00
Xaw3ep de0486cf6f An attempt to deal with #315, #310, #301 2023-08-12 08:55:20 +07:00
Lysandr0 9c96e3c6d8 Push piled up commits on remote. 2023-07-30 17:47:16 +02:00
Lysandr0 cb92b0eed7 Merge branch 'master' into simplify-vdistrel 2023-07-14 23:04:18 +02:00
Lysandr0 243cbe45d0 Merge master. 2023-07-14 23:03:23 +02:00
Lysandr0 ebd5bb84aa Fix 1.20 hanging signs, attempt to fix most Folia-related issues.
* #305 Another attempt at fixing AutoSign with the editing mechanic.
So far, we do not have a specific event for player-editing, so everything has to be manually detected.
Player-editing-speed cannot be monitored due to PlayerInteractEvents not being fired at all when "opening" a sign.

* Hanging WALL signs have a collision box for their post. Hanging signs don't, so they are treated like a normal sign would (fully passable)

* BlockPlaceListener: cleanup, don't use player#getLocation() for Scaffold; use PlayerMoveData instead

* (+ random cleanup in PassengerUtil)

Folia fix is provided by @xymb-endcrystalme
2023-07-09 21:10:02 +02:00
Lysandr0 0da57d8f77 Move PotionUtil to the utilities.entity package.
The effect is applied to entities after all.
2023-07-09 14:21:23 +02:00
Lysandr0 85f6305c9f Get rid of deprecated code. 2023-07-03 07:50:23 +02:00
Lysandr0 3fc2a499ec Get rid of legacy permissions. 2023-07-02 20:56:51 +02:00
Lysandr0 eeb55ad552 [#305] Do not check for sign hash if the block-placing hash is 0.
Fixes an AutoSign false positive with the new editing mechanic (1.20+ players can now edit signs that have already been placed down. Took long enough, Mojang)
2023-07-01 21:21:38 +02:00
Lysandr0 ebd4c02ec7 Clean-up.
Remove unused methods, unused data, unused variables:

* Get rid of the legacy low-jump check: redundant + less stuff to account for (consequently remove the allow_lowjump flag)

* Get rid of isWaterfall method and everything related to it.

* Get rid of the LiftOffEnvelope.LIMIT_SURFACE envelope

* Get rid of sprinting grace: with a prediction-based check, we need the exact, latency-compensated status, not a simple grace period.

* Get rid of the vEnvHack in AirWorkarounds.

* Get rid of vDistSB: redundancy with vdistrel + less workarounds to care for.

* RichEntityLocation:
 -Ensure that the head obstruction check does not yield true when moving inside powder snow or sliding down a wall of honey blocks
 -onGround: only check for powder snow, if there's other powder snow beneath.
 -Ensure that the isSlidingDown method collects block flags before (prevents some NPEs)
2023-07-01 07:51:21 +02:00
Lysandr0 2475e70d29 Handle powder snow onGround checking in a more clean way.
Well, not so clean, more of a less convoluted way.
We check for boots inside RichEntityLocation, instead of changing the flag on-the-fly in the MovingListener.

Bonus:
 * Remove confusing "|?" tag.
 * Merge upstream.
 * Remove F_GROUND_HEIGHT from powder snow: players are only allowed to stand on top of it.
2023-06-16 21:43:50 +02:00
Lysandr0 d98ccbe81e [#299] Add missing shape definition for calibrated sculk sensor. 2023-06-15 15:26:34 +02:00
Lysandr0 1defbc3305 Fix client-version setting fallback.
+ Re-order some stuff with vdistrel.
2023-06-13 22:15:40 +02:00
Lysandr0 012a1c45fd Better handling for the honey block.
Everything is moved to RichEntityLocation under the isSlidingDown method.
Properly handle sliding vertical speed in vDistRel instead of using magic.
2023-06-13 07:36:28 +02:00
Lysandr0 032731fc5a Merge branch 'hspeed' into simplify-vdistrel 2023-06-11 17:49:11 +02:00
Lysandr0 990a45b4a8 Merge branch 'master' into hspeed 2023-06-11 17:48:10 +02:00
Xaw3ep d6c1621e65 Restore old condition for split move
And fix a small false with breaking budding amethyst.
Just quick fix before I return to darkness
2023-06-11 19:02:48 +07:00
Lysandr0 4817eed02e Minor refactor for moving checks, rename Folia class, integrate Gutenberg as an ordinary check.
Move hard-coded magic into its own package (envelope); move checks.moving.magic class to the moving utilities package; split envelopes methods into its own class (PlayerEnvelopes); BounceUtil -> BounceHandler and to the envelope class; BounceType -> to the checks.moving.model package.

* Renamed Folia class to "SchedulerHelper" (name is up to debate, feel free to add)

* Gutenberg won't check for availability anymore. The event was introduced in 1.5 and NCP doesn't support versions lower than that anymore.

* Move "honeyBlockSidewayCollision" method to PlayerEnvelopes.

* Fix compilation errors in RichBoundsLocation and get rid of unused method.

* Get rid of the "split move" flag: too internal of an option and should never be disabled anyway.

* Clarify docs

* LiftOffEnvelope:
-Get rid of min/max jump distinction.
-Decrease normal jump height down to 1.26.

* SurvivalFly: various adjustments... Key change are:
 -The riddance of vAcc. Useless with the upcoming vDistRel rework;
-Unbind to the horizontal-push-speed mechanic from hard-coded magic. (Please Asofold for the love God why did you not document this kind of stuff... Why was it needed);
-Merge vDistWeb, vDistLevitation, vDistBush into vDistRel, climbables and powder snow are still handled in their respective methods because we are restricted by NCP's current  infrastructure and we cannot predict those two (powder snow in particular)
-Move honeyBlock collision to richboundslocation.

* RichEntityLocation:
-Force legacy players to have vines attached to a solid block to climb up.
-Check for client version for fullHeight setting as well.
-Move liquid pushing stuff to RuchEntityLocation
2023-06-10 22:11:23 +02:00
Lysandr0 1ae66d387b Merge branch 'master' into hspeed 2023-06-10 20:31:43 +02:00
Xaw3ep 25ae0a7cdc Update to support 1.20 2023-06-10 23:45:45 +07:00
Lysandr0 8ef0946234 Merge pull request #295 from Phoenix616/patch-1
Link updated CNCP repo instead of old site
2023-06-03 13:47:05 +02:00
Max Lee 3e64428d79 Link updated CNCP repo instead of old site 2023-06-01 21:54:27 +01:00
Lysandr0 4a985be6cf Merge branch 'hspeed' into simplify-vdistrel 2023-05-10 20:38:12 +02:00
Lysandr0 62b07535ad Rename some lift off envelopes. 2023-05-10 20:01:09 +02:00
Xaw3ep bd229b0621 Sync with local changes
Key changes:
+ Fix split-move system splits the look wrongly
+ Correct the bounding box of berry bush, cobweb, powder snow
+ Correct minor false positives when in liquid
2023-05-10 20:15:42 +07:00
Lysandr0 aaeeec8bf6 Attempt to simplify SurvivalFly (vertical)
Workarounds are just too stratified and convoluted to keep up with them.
Just to debug one of them might take a week or more; so, except for oddSlope, oddGravity and vEnvHacks, all the other ones have been removed.

Changes:
* Get rid of the now unused isDownStream() and isInOrAboveSouldSand() methods.
* Move InputDirection class to the model package.
* Lift off envelope: web jump speed is 0.021
* Check for client version in NoFall, as well as reset data upon sliding on a honey block inside the checking method (not in the collision method in movingutil).
* Prepare a velocity flags to distinguish real velocity from fake entries.
* Implement legacy liquid pushing (not tested).
* Friction/speed factors getting is ignored if flying or gliding (vanilla)
* Integrate FastConsume as an ordinary check (1.5 and above servers have the consume event, no need to test for availability anymore)
* If protocol-hack plugins are not present but protocol lib is, do still set the client version.
* Attempt to catch ominisprint if speed is (apparently) legit.
* Display at least 6 digits when debugging speed h/v (with the speed prediction, this is much needed)
* Revert accidental formatting change to GodMode
*The band-aid "lowjump post" subcheck has been removed as well, because the vDistRel rework will (soon) catch those as well. But first, we need to patch the first-move-after-landing false positive.
* Also get rid of bunnyslope, once and for all.

Missing:
vDistRel: handling of: leaving liquids, noob-towering up, landing-back-on-ground, medium transitions...
vDistPowderSnow: incomplete, due to not knowing how the game handles ascending motion here.
vDistLevitation: works fine with lower levels, but breaks with higher ones (above 20 or so) for whatever reason.

(Was meant to be split into different commits, but I fucked up a bunch of things. Oh well)
2023-05-09 14:13:20 +02:00
Lysandr0 05f7064866 FastConsume not so special anymore, do check for client version in some places.
Integrate FastConsume as an ordinary check without checking for specialities/availability
(PlayerItemConsumeEvent was introduced in 1.5 and we do not support versions lower than that anymore, so the availability check has no reason to still stay).

With the client-version hook, we can now finally check for client version in certain places. This isn't really possible for blocks as they are defined globally, and not per-player. Would require a big refactor to support it.

* Revert GodMode formatting and comments.

* Ensure ClientVersion is not set to UKNOWN if protcol-hack plugins are not present on the server, but ProtocolLib is.

* Document stuff
2023-05-07 18:43:15 +02:00
Xaw3ep 72f76d7f2c Fix false positives with medium transitions
Some blocks like web, berry bush, slime block might not done yet
2023-04-26 23:19:48 +07:00
Xaw3ep a6ef1b5251 Fix random things
Key changes:
+ Fix liquid height return incorrectly
+ Brute-force all input direction
+ Fix split-move system return incorrect pitch and yaw
2023-04-24 23:57:51 +07:00
Lysandr0 62bf94cf08 Merge branch 'master' into hspeed 2023-04-13 18:06:30 +02:00
Lysandr0 53f1642bff Merge master (1) 2023-04-13 17:59:54 +02:00
Xaw3ep dc3a487ca5 Beautify client version 2023-04-13 19:18:48 +07:00
Xaw3ep bef2c4e23b Folia support
First attempt to support Folia; Not fully tested, proceed with caution!
2023-04-13 09:31:40 +07:00
Lysandr0 c1a691baaf Attempt to get the client's protocol ID thorugh CompatNoCheatPlus
This should be done within NoCheatPlus rather.
It is also a bare-bone attempt: you'll need to look up the protocol ID table to know which version the player is on.
Later, some kind of translation method (from protocol to launcher version) might be done.

(PRs to improve this are most welcomed :p)
2023-04-11 20:59:03 +02:00
Xaw3ep fb5efa0d93 Fix #290
Also come with an small change allow using elytra in web and berrybush
2023-04-06 09:09:09 +07:00
Lysandr0 64a70f731c Merge branch 'master' into hspeed 2023-04-04 10:59:55 +02:00
Lysandr0 7d289a0ad1 First version of MC's liquid push mechanic.
Simply going in the same direction of a single stream of water works "fine". Moving around does throw false positives still.
The falling liquid bit needs to be implemented still.

* Also, properly set the aboveStairs property (get rid of the old stair workaround)
2023-04-04 08:18:03 +02:00
Lysandr0 10c50653e8 Cleanup for the chat listener, comments. 2023-04-04 08:18:03 +02:00
Lysandr0 96ac4df374 Update NCP to 1.19.4 and fix Against false positive with frogspawn. 2023-04-04 08:17:43 +02:00
Lysandr0 81cf339560 Some improvements to how NoCheat+ handles inventory-related checks
* Do not check for InventoryType.CREATIVE with the hasInventoryOpen check.

* Only display debug messages for Open if the inventory was actually closed

* Force-close inventories on BlockBreak and BlockPlace events

* Several listeners will now ignore cancelled events (won't register data if the event was cancelled)

* Inventory clicks are now always listened for, even if the click was cancelled (to register the opening time), but checks won't run still.

.
2023-04-04 08:17:43 +02:00
Lysandr0 98e96350d5 [#290] [#271] [Blind] Bump NCP to 1.19.4, fix NoSuchMethod error.
Should be done, more or less (?)

Also catch a false positive with frogspawn placement on water (like lily).
2023-04-01 13:21:07 +02:00
Lysandr0 095dc1a5ba [#289] Skip players trying to place seeds/plants on crops/plants with the Against check 2023-03-23 13:51:08 +01:00
Lysandr0 7b56ee4c40 Fix NPE. 2023-03-10 16:37:06 +01:00
Lysandr0 1c609e7e4a More changes (+)
* Further clarify docs and comments, cleanup.

* Reoder some event-listeners (especially in the movinglistener).

* Net checks: also request a setback on flyingfrequency violations (should prevent server-sided freeze [...]).

* Do still interpret packets for outgoing positions if flyingfrequency is disabled.

* Fix false positives with ImpossibleHit.

* Remove legacy boolean flag for 1.5 inventory tweaks (fastclick).

* Don't allow players to stand on tilted drip leaves (onGround judgement).

* SurvivalFly: reset bunnyhop delay on slopes and stairs, tweak slowfalling handling (only apply slowfall gravity if the player is actually falling [not coming from ground etc...]).

* Remove experimental Improbable feeding with VL frequency hook.

* Rework inventorymove:
Instead of checking during InventoryClickEvent(s), we check players on PlayerMoveEvents and if the inventory is open when it shouldn't be possible, it will be forcibly (and silently) closed, without generating any violation or alert .
This makes the check functionally identical to Open, so it has been merged in it.
Not 100% done. Still needs the speed prediction to function, in order to determine friction speeds.

* Set all config values to build 154 from now on.
2023-03-09 14:28:28 +01:00
Lysandr0 8c1fe17749 Much less leniency for fast-breaking, packed mud assigned to the pickaxe.
With the block-breaking time refactor, we can now be much less forgiving in checking for FastBreak.

Also attempt to fix false positives with packed mud.
2023-02-24 22:47:33 +01:00
Lysandr0 5429c8481e Merge branch 'master' into hspeed 2023-01-20 08:56:07 +01:00
Lysandr0 715491f1ec Comments, cleanup 2023-01-19 20:38:21 +01:00
Xaw3ep a36053faed Merge pull request #277 from Updated-NoCheatPlus/block-hardness-v2
Merge branch block-hardness
2023-01-19 20:49:15 +07:00
Xaw3ep 3ac7a45e67 Quick update to 1.19.3
Mostly aim to get rid of annoying messages on start and fix NoSlow not functioning properly
2023-01-19 20:37:07 +07:00
Lysandr0 2f267b5650 Confine lost-ground cases, fix errors, fixes for SurvivalFly
* LostGround:
 - Swap edgedesc with pyramid and put edgedesc as a special case in vAcc;
 - Confine all Edgeasc cases by having a minimum speed of 0.0001;
 - Confine noobtower by jumPhase between 1 and 7 inclusive;
 - Confine couldstep by speed <= estimatedSpeed * 1.1;
 - Edgeasc2 won't be applied on split move (following asofold's note here);
- All edgeasc cases won't be applied if a lost ground case was applied with the move before;
 - Update Improbable if a lost ground case is applied;
These have not been tested.
They are rather the most plausible confining conditions that I can think of currently; aim is to prevent to easy abuse with NoFall disabled to accumulate fall distance.

* SurvivalFly:
 - Sharpen bunnyhop conditions;
 - Remove omnisprint for the moment;
 - Increase the inaccuracy margin with levitation;
 - Possibly fix bunnyhopping on soul sand and blocking speed in 1.8;
 - Reduce the complexity of split moves workarounds with stuck-speed, courtesy of @xaw3ep 's rework on the mechanic;
 - Lower head obstruction margin for low-jumping;
 - Sharpen levitation handling;
 - Roughly make vAcc work with slowfall.

* Fix NSM errors with some packet listeners;

* Comments, formatting, clarify comments

* Improbable:
 - Increase thresholds for firing violations, since it gets fed by a lot more inputs now;

(Probably forgot some other stuff... Oh well. Happy new year)
2023-01-05 21:10:19 +01:00
Lysandr0 fc37194fd5 Ops.
Fix compilation errors.
2022-11-24 09:58:46 +01:00
Lysandr0 e3300f1e5c Merge branch 'hspeed' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed 2022-11-24 09:05:05 +01:00
Lysandr0 29f0ecdf36 Get rid of the horizontal buffer, adjustments. 2022-11-24 09:04:15 +01:00
Xaw3ep b36081fc6f I don't know what I'm doing
Just an attempt to fix wrong calculation in the first move after landing. Might wrong, but it give the idea why. Let understand client code different way. moveRelative() -> move() -> friction.
Assume everything after move() is the preparation for the next tick not the current one. So the right order is lastfriction -> moveRelative() -> move().
2022-11-24 04:21:43 +07:00
Xaw3ep d23161e1a6 Full split moves
Split the move properly, some minor adjustments and comments
2022-11-23 09:49:37 +07:00
Lysandr0 fcbe674233 Slowly getting there.
* Harmonize bukkit's walkspeed with attributes;

* Reset Improbable's data on certain events;

* Check for Improbable on fakefall and fakeground;

* SurvivalFly:
 - Unbound liquid workarounds from velocity jump phase, in the hope that it will fix issues regarding waterfalls
 - Throw in a placeholder estimation for the player movement inputs
 - Make the estimation work, for the most part (at least for just walking/sprinting on ground). Lots of issues still remain
 - vDistAir: switch to minJumpGain as maxJumpGain's motion is way too high with jump amplifier
 - Do bunnyfly after the estimation and sharpen bunnyslope
 - On using queued horizontal velocity entries, update Improbable
 - Remove a waterfall workaround (was ineffective)
 - Comments on vDistClimbable
2022-11-21 14:20:58 +01:00
Hulk c26fa72aaf Fix #251 2022-11-20 23:25:34 -06:00
Lysandr0 873139546f More adjustments.
* Fix some typos;
* Don't apply the bunnyhop mechanic on stepping;
* Rename some fields in MovingData;
* On no horizontal distance, also reset x/z allowed dist;
* Fix wrong permission being checked for using items;
* Split moves: Ignore stuck-speed. Do apply block-speed regardless;
* Floats -> doubles and viceversa;
* Re-introduce the bunnyslope mechanic;
* Prevent precision loss with the sprinting multiplier;
* Revert the maxphase detection: doesn't seem to work well (it may come back at a later moment, once there's enough time to test it);
* Potentially fix null pointer in Net_Moving;
* [Bleeding] First approach to an omnidirectional sprinting check.
2022-10-20 08:24:53 +02:00
Lysandr0 72df6a2f97 Ops.
Fix noob-tower conditions due the the new yOnGround value.
2022-09-30 21:27:52 +02:00
Lysandr0 441ab8871a Merge branch 'master' into block-hardness-v2 2022-09-30 19:54:20 +02:00
Lysandr0 b6d5c04d4d Adjustments for hspeed.
Keep track of both axis with the past move tracking. Will be useful to judge velocity and strafe cheats later on.

Also re-introduce NoCheat-style maxphase detection (only for descending and velocity), to be tested, but potentially more useful than the previous implementation.
2022-09-30 12:48:51 +02:00
Lysandr0 47b56fbf88 [Bleeding] Tweak NCP's y parameter for onGround seeking, random formatting for chat checks.
This is a small commit which could  actually change a lot of things.
The previous yOnGround value was too high, causing some moves to be detected as "on ground" earlier than expected.

This will affect all moving checks, including NoFall; workarounds which contain ground conditions may need to get reviewed; lowjump-post will likely be affected, also [To be tested]
2022-09-29 15:15:23 +02:00
Lysandr0 4db7e95dab Get rid of the bunnyvel workaround.
This of course means that exiting moves will now yield false positives. But this will be irrelevant anyway with the hSpeed branch.

Should address #255
2022-09-24 15:51:17 +02:00
Lysandr0 e4e8b0d90c Merge branch 'master' into hspeed 2022-09-19 14:18:37 +02:00
Lysandr0 8430404436 Merge pull request #243 from Dymeth/master
Fixed hidden commands usage from console on PurpurMC
2022-09-19 14:18:05 +02:00
Lysandr0 a9e693c730 (Hopefully) Clarify the VL frequency hook, refine levitation and prevent abuse of it(+)
The hook will now request an Improbable CHECK for too small and too recent repeated violations. This will make the likes of "Hypixel fly" even more expensive to use.

Levitation: the new handling will try to predict the allowed distance, just like vDistRel. Workarounds are in place for all those cases -that have been observed thus far- where the prediction fails.
Stuck-speed remains itchy: predicting speed is nearly impossible, without spending obscene amounts of time.

* NoFall: clear data directly into the checking method with Slowfall and Levitation;

* Throw in a sketch for the future riptide check (CreativeFly)

* Add more detailed about SurvivalFly's internals

* Format, tab->spaces, fix code order for hSpeed

* vDistRel: remove odd jump gain margin (what is it even used for?)

* Fix fuck up in Frequency's VL calculation

* Debug Net_moving

* Merge master

* Track teleports to untracked locations with cause PLUGIN

* Re-re-add headbangbunny, correctly this time :)

* Patch even more 1-block step(s)

* Don't allow jumping motion if the player is stepping down a block

* Extreme move: lower h-speed threshold

* MovingListener, onCancelledMove: fix NCP actually requesting a set-back only if the player was in debug mode (assuming a major oversight by asofold)

Note about the walkspeed-horizontal-fly exploit with slime block: NC+ keeps faking vertical velocity in the "onPreparedBounceSupport" method if altitude does not change.
For the method's calling, there are 2 pre-conditions:
1) The data.verticalBounce field needs to not be null;
2) No new To location where to setback the player to has been requested by checks.
This explains why:
1) Cheaters need to bounce on the block at least one time (otherwise the verticalBounce field will be null);
2) Cheaters cannot do anything else, besides air-walking, nor generate violations (Changing altitude will consume the vertical bounce, which will then yield a vDistRel violation, while going above walkspeed will generate a speed violation, causing SurvivalFly to request a new setback location)
Now, the question is then: why does NC+ need to keep the vertical bounce on not changing altitude? Was it intended to not reset the verticalBounce field or is it an actual bug?
In any case, safer resetting mechanics are required, provided we keep this odd fake velocity mechanic at all, which doesn't really seem to be needed (no tickets have been opened).
2022-09-19 08:50:24 +02:00
Nikolay Mitrofanov f42aafaa14 Fixed commands usage from console on PurpurMC 2022-09-02 02:25:16 +03:00
Lysandr0 c3fc896b3d Patch a (potential) fly exploit with the current config (read on)
Up until now, the default config has been clearing SurvivalFly and CreativeFly's data upon reaching the maximum interval.
When this happens, the setback position is also reset.

This can be exploited to fly and/or speed by generating extremely high VLs, forcing the Fly check to clear its data.
2022-08-28 22:19:58 +02:00
Lysandr0 9562a277ee Forgot about one mechanic. 2022-08-20 13:51:59 +02:00
Lysandr0 4029e6f4db Merge branch 'master' into hspeed 2022-08-20 09:13:56 +02:00
Lysandr0 410f88866e Revert back a few things
* Fix stepping while on climbable;
* oddSlope: skip if in lowjump;
* Revert back BCT changes;
* Revert back speed handling to check for axis individually;
* Potentially fix moving immediately after a teleport causing false positives due to the LiftOffEnvelope being set to UNKNOWN (MovingData);
* Account for attack slowdown;
* Catch criticals with slow fall active;
2022-08-20 09:09:33 +02:00
Hulk cfb83b4904 Patch a fly exploit which abused slime blocks 2022-08-19 15:33:00 -05:00
Lysandr0 b1c6258675 Update bug_report.md 2022-08-13 22:06:29 +02:00
Lysandr0 25242e13a9 Tabs->Spaces. 2022-08-13 17:22:53 +02:00
Lysandr0 6f670ce7c8 [Bleeding] Let Slowfall and Levitation be handled by SurvivalFly.
* Move Bridge1_17 stuff into BridgeMisc;
* Add a "hasGravity" method;
* Patch potential 1-block step bypass with lowvdistsb;
* Fix (for the most part) closing a shulker box while standing on top of it;
* Fix up a bit bubble columns handling;
* Fix false positives when exiting a bush or web from below;
* Cleanup and reduce signature for AirWorkarounds;
* Catch another trapfence lost ground case;
* Remove reminders of the old bunnyfly mechanic: all early-bunnyfly-reset cases can be omitted because those rely on the old condition "if (bunnyfly > 0 && hDistance > hAllowedDistanceBase)".
However with the current implementation, air / bunnyfly distance is already estimated and included;
* Use getLastJoinTime for Net_Moving and Net_KeepAliveFrequency, getting rid of the old listener workaround;
* Keep confining workarounds:
  -W_M_SF_ODDGRAVITY_3: one time use
  -W_M_SF_ODDLIQUID_13: one time use
  -W_M_SF_ODDLIQUID_7: one time use
  -W_M_SF_ODDLIQUID_5: 4 times use max
  -W_M_SF_ODDLIQUID_6: water-bound
  -W_M_SF_ODDLIQUID_12: one time use.
* Don’t ignore PVP and block-move velocity when in bushes and powder snow;
* Distinguish vertical friction factor by media (air, water, lava) and block (stuck-in-block);
* Slowfall:
  - Add workarounds for vDistRel where needed.
 - Adapt checking methods to it (modelling might be a little rough still).
  - Handle honey slide + slowfall.
  - Skip NoFall and fall damage with slowfall.
  - Handle with the BCT breaking blocks below with slowfall (false positives).
  - Skip vAcc: temporary. Needs a proper adaptation.
* Levitation:
  - Add checking method;
  - Add velocity when the effect wears off;
  - Skip NoFall;


Missing:
* InstantBow apparently always triggers with the first crossbow shot (why is it even enabled at all?);
* Major: players can stand on top of tilted drip leaves (!)(to avoid latency-based false positive, we might use the block change tracker system here)
* False positives when falling and breaking a block below with Efficiency enchant: issue with the server not keeping up with the client, might mitigate with the BCT [Does not seem to fix the issue, will need a ghost-block system fix];
* Bubble streams adjacent to each other drag/push: push prevails even if the box is in the column by pixels. Problem: we don’t get told if the column can also push the player;
* vAcc velocity downwards (old TODO);
* vAcc with snowfall (don’t skip, adapt rather);
* Still low-jump false positives when closing a shulker, with slowfall in particular;
* Low-jump false positive after jumping out of water and onto a water lily;
* Liquid modeling with slowfall is still quite rough;
* Levitation will need a refine later;
* Bubble columns ascend -> refine;
2022-08-13 14:46:17 +02:00
Lysandr0 d7fa6c1644 Merge pull request #224 from Toshimichi0915/fastclick
Fix / by zero with the chest subcheck for FastClick.
2022-08-10 16:22:50 +02:00
Toshimichi0915 f56e9a9dbc Fix FastClick NPE 2022-08-06 22:29:12 +09:00
Lysandr0 0c737f3c1e Let lowjump consume vertical velocity.
(Fix is already included in the hSpeed branch)
2022-07-29 00:39:38 +02:00
Xaw3ep 602199256a Fix false positives when leaving liquid 2022-07-28 13:46:57 +07:00
Lysandr0 d98c96c87b Merge branch 'hspeed' of https://github.com/Updated-NoCheatPlus/NoCheatPlus into hspeed 2022-07-23 20:25:42 +02:00
Lysandr0 1b795bb9ea Adjustments to hSpeed. 2022-07-23 20:25:30 +02:00
Xaw3ep 5713f956d9 Fix UseEntity 2022-07-23 14:08:21 +07:00
Lysandr0 c37908eec6 Move use-item data to CombinedData, debug hSpeed to begin testing, adjustments. 2022-07-17 17:54:32 +02:00
Xaw3ep 0fc194a17a Get rid of time map of breaking blocks
Use hardness instead of time map for easier debug, maintain and less false positive.
No time to test this out, put it here first.
2022-07-14 18:18:43 +07:00
Lysandr0 07bdc0ea10 Merge master, remove InstantEat and Items + minor improvements.
With the official drop of 1.4, these checks can be finally removed.

* Critical: use the maximum jump phase (should be stricter)
* Remove misleading "preventmisc" category
* Request an Inventory update on inventory checks VL.
2022-07-11 21:38:31 +02:00
Xaw3ep 91aca1e671 Fix the mud 2022-07-10 18:28:07 +07:00
Lysandr0 552fbb446e Ops. 2022-07-10 09:59:38 +02:00
Lysandr0 3bebafdbe8 Merge branch 'master' into hspeed 2022-07-09 20:18:01 +02:00
Lysandr0 3ea2dc46d8 Adjustments, rename boatsanywhere to boatsOnWaterOnly
* Better server-side lag adaptation for Angle, FlyingFrequency and ToggleFrequency
2022-07-09 20:10:35 +02:00
Xaw3ep 353969053d Step back to 1.5 and ascend to 1.19
! Not fully tested
Key changes include:
+ Update to 1.19
+ Fixed minor critical false
+ Fixed some backward compatibility issues from (1.5 to 1.6.4)
+ Drop 1.4 support
+ Attempt to catch #215
+ Bump version to 3.17.1 to further issue tracking
2022-07-09 16:45:50 +07:00
Lysandr0 d5d16d3db5 Yet another heterogeneous commit.
Lots of changes:
* [Bleeding] Add Net_toggleFrequency on packet level (needs to be tsted and adjusted, currently does not discern action types);
* [Bleeding] Add a quick check for no gravity when in webs;
* Formatting;
* Fix vDistBush + stepping;
* Fix Net_keepAliveFrequency/AttackFrequency/Moving not checking for the respective bypass permission;
* Fix Net_Moving always checking players, even if disabled;
* Fix Extreme_Move only running with CreativeFly;
* Fix low-jump detection not accounting for velocity;
* Fix a disabled Net_FlyingFrequency from crippling all other flying-packet checks;
* Remove redundant WrongTurn adapter;
* Remove legacy Fight_Speed check and keep AttackFrequency only (This means that servers older than 1.6.4 won't have attacking speed protection anymore. We need to put a halt on legacy-versions support at some point 😛);
* Remove legacy and unneeded mechanics: lost-sprint, assume sprint, slowness sprint hack, ground hop;
* Remove bubble-stream-horizontal-velocity workaround;
* Remove unimplemented FlyingFrequencyRedundant config;
* Rename compatibility dev module to -> NCPCompatSpigotCB1_12, since 1.12 is the last version to have a native module on its own;
* Rename NoSlow adapter to UseItemAdapter;
* Adjustments to vDistWeb and vDistBush;
2022-06-25 19:14:48 +02:00
Lysandr0 1e6c8e3780 Formatting for block models, config & checks' data. 2022-06-23 21:31:05 +02:00
Lysandr0 576379cd3e Merge branch 'master' into hspeed 2022-06-08 13:03:33 +02:00
Lysandr0 f8a5169a5a Comment on Scaffold.
God-bridge is a thing apparently + reminder for the future... :)
2022-06-07 21:09:36 +02:00
Lysandr0 804206bf22 Let the whole thing compile for the moment.
Direction factors are commented out for now, just to let the thing compile.

Key changes:
* Revert (!resetTo) condition for lost-ground testing, due to some false positives;
* Formatting;
* Test for block-change activity in more places (vDistWeb/Bush)
* Revert the fix for "too little h-vel validation counter" due to the hSpeed rework.
2022-06-07 20:31:49 +02:00
Lysandr0 13d80f3166 Let NCP load on 1.5 2022-05-30 23:16:33 +02:00
Lysandr0 02159d280d Merge branch 'master' into hspeed 2022-05-20 15:52:31 +02:00
Lysandr0 d2c8e080cd Patch-up previous commit.
+ more comments.

Only things missing for the hSpeed rework are:
* Movement direction handling;
* Fluid pushing speed;
* Stairs auto-jump speed
About stairs, COULD:
Trust the client's onGround status when on stairs, which will offer no protection.
OR
Simulate the auto-jump behaviour when on stairs only, and assume players have it enabled anyway.

Will try to do something about fluid pushing, unless someone else beats me to it (likely going to happen) :)

(Then, with workarounds. . .)
2022-05-20 15:49:03 +02:00
Lysandr0 e2dfa93fa2 Catch a low-jump false positive. 2022-05-16 19:22:14 +02:00
Lysandr0 78e6c4cede Misc changes (mostly lost-ground cases removal)
Very heterogeneous commit.
Key changes:
* Comment out LostGround_Step: not too sure about this one however why is it even considered a lost-ground case if the player did touch the ground (to.isOnGround())?
* Remove LostGround_EdgeAsc7: duplicate code;
* Remove LostrGround_Pyramid: doesn't seem to cause any issue with vertical motion and with the new hSpeed rework, momentum ticks don't exist anymore.
* Remove LostGround_MiniStep: not needed. Jumping around flower pots is fine even without the workaround.
* Remove LostGround_vCollide: again, doesn't seem to be needed anymore.
* Confine LostGround_Micro by head obstruction due to a lantern or currently respawning;
* Better on-ground support for bunnyfly: account for block-change activity where possible;
* Skip block-speed check if the player is in water or in bubble-stream (NMS);
* Implement getMovementSpeed;
* Get rid of hAllowedDistanceBase (not needed anymore) [Might return for later uses i.e.: getting the allowed speed before applying friction];
* Rename methods and get rid of VanillaMath (changed my mind, keep everything in TrigUtil and MathUtil :p)
* Correct a typo in Inventoryutil.
* Fix a rather embarrassing typo (Ground-seeking distance for getBlockFrictionFactor is 0.5000001, not 5000001 :) )
* Support bukkit's /walkspeed command;
* Random clean-up for old checks.

- Note: The 0.1 magic value can be found in Abilities.java (walkingspeed)
2022-05-13 17:53:20 +02:00
Lysandr0 4ae5b45972 Adjustments...
* Format
* Move getEntityPushSpeed to MovingUtil
2022-05-03 21:35:46 +02:00
Lysandr0 46da5e3654 Support entities push-speed, fix compilation errors.
Next, fluid pushing... Will be painful.
2022-04-29 15:55:09 +02:00
Lysandr0 aa13a825da Comments, put back double bunny, more improbable feeding on impossible moves. 2022-04-28 20:39:28 +02:00
Lysandr0 6264b5dc5c Quick refactor for resetFrom, remove "fastedge" lost-ground case, remove outdated fixes, remove workarounds
* The removed air-workarounds point to something that should be tackled differently: breaking a block underneath should cause the block-change tracker to catch such false positive. Why isn't it working here?

* Remove an old lost-ground case, as stated by asofold.

* Quick refactor for resetFrom: block-change activity is tested not only if the player is standing still... (Can't really pinpoint the reason behind such design...)

* Remove isOnIceLegacy thingy...
2022-04-28 16:16:59 +02:00
Lysandr0 dec3253416 Ensure lost-ground activity is tested only if the player didn't actually touch the ground
* Implemented an old TODO by asofold: skip checking for lostground cases if the player did land on ground (resetTo).
(1st step into the lost-ground review).

* Remove an old (likely irrelevant by now) fix (Infinite VLs ...).

To be tested, might have a lot of side-effects.
2022-04-27 21:10:44 +02:00
Lysandr0 664a901de9 Merge branch 'master' into hspeed 2022-04-26 16:10:42 +02:00
Lysandr0 abbd90e943 [Incomplete][Not compiling][Bleeding] First step into the hspeed rework.
Moving some stuff in remote.
* Rework horizontal friction system;
* Cleanup code: remove unused and/or unneeded variables, remove old bunnyhop mechanic;
* Throw in a sketch of the predictive horizontal speed handling [broken, will not compile due to some stuff still missing]

Missing:
* 3d Movement direction handling
* Test everything I guess
* getMovementSpeed stripped only of sprinting speed
* Correct stuff that is going to be inevitably wrong :)
2022-04-26 16:07:24 +02:00
Xaw3ep 2901f792a0 Miscellaneous changes
Key changes are:
- Correct cactus shape
- Further preparation for bedrock compatibility
Fixed #204

.. / .... .- - . / -. -.-. .--.
2022-04-26 06:37:51 +07:00
Lysandr0 e2e0b0dacd [Incomplete] [Bleeding] Throw in more utilities.
Sifted through client code for long enough. These methods should be correct to be put remotely, hopefully.
2022-04-18 11:08:32 +02:00
Lysandr0 4a42adf93b Move more classes around and reorder imports.
Move MovingUtils into... The utilities package
2022-04-13 22:43:23 +02:00
Lysandr0 5883a28948 Fail.
(Remove redundant stuff)
2022-04-13 19:48:18 +02:00
Lysandr0 e1399ddf3b Merge remote-tracking branch 'origin/block-hardness' into hspeed 2022-04-13 15:46:39 +02:00
Lysandr0 320adc16bc Compile fix. 2022-04-13 15:46:01 +02:00
Lysandr0 cbdc63e746 Move class around.
Let math-related utilities have their own package
2022-04-13 15:28:36 +02:00
Lysandr0 dcd5e1f96f Prepare utility methods for the upcoming predictive horizontal speed.
* Also cleanup, remove non-effective fixes for NET_MOVING, skip collision check for stairs due to the new BB rework and check for ground in isOnHoneyBlock, distinguish above soul sand VS in soul sand.
2022-04-13 15:08:04 +02:00
Xaw3ep 0bc27d83e3 Update BlockProperties.java 2022-04-12 22:52:12 +07:00
Xaw3ep 9293cde9ed Yet another cleanup
Key changes include:
+ Correct liquid
+ Reverse `boatanywhere` logic to avoid misunderstanding

Fixes #182
Fixes #169
2022-04-12 22:44:26 +07:00
Lysandr0 a4dda13e8c Multiprotocol plugins are a thing...
Should get the client version in some way. Another reason to hook into PS/VV I guess.
2022-03-30 12:32:55 +02:00
Lysandr0 9069b86c86 Spaghetti.
Formatting/Order.
2022-03-30 09:43:07 +02:00
Lysandr0 c69e62fc18 Merge branch 'Testing' 2022-03-30 09:06:54 +02:00
Xaw3ep 5a7fc17183 Patch boat fly and random clean up 2022-03-29 18:46:25 +07:00
Xaw3ep 95b3405356 Merge pull request #146 from adampoulson/test
improve boat speed checks
2022-03-29 18:44:14 +07:00
Xaw3ep 37c0db896d Eradicates a tiny bug 2022-03-28 08:29:47 +07:00
Lysandr0 8c00cb5936 Let it compile. 2022-03-27 14:51:55 +02:00
Lysandr0 7d7a0a6bad Merge branch 'master' into Testing 2022-03-27 14:44:17 +02:00
Lysandr0 7f13311ec4 Partly fix up the low-jump detection
* Fix low-jump triggering when jumping 1 block up (slope, player touches ground while still ascending causing a setback update [...]);
* Fix noobtowering triggering a low-jump (similar reason as above);
* If in low-jump:
    + deny bunnyfly;
    + feed Improbable;
    + throw a VL;
    + deny buffer regain (do however allow
        use)
2022-03-27 14:18:04 +02:00
Xaw3ep 3dff8c5b78 Forgot climbable 2022-03-27 19:07:28 +07:00
Xaw3ep ae62126479 Restore lost commits (part 2)
Ok ok, you defeated me, but I still have backup, see you next time!

Key changes include:
- Correct most blocks shape(both for legacy and news versions); less misuse workarounds
- Fixes message on death
- Clear redundant patches
2022-03-27 16:31:25 +07:00
Lysandr0 3f5f64396b Merge branch 'master' into Testing 2022-03-07 08:32:07 +01:00
Xaw3ep 2cff2963c9 Restore lost commits (part 1)
Fix #150
Fix #155
And some other forgotten bugs
2022-03-05 18:40:08 +07:00
Lysandr0 78526facf6 Cleanup 2022-03-05 09:44:32 +01:00
Lysandr0 939fe1fa55 Having a look at air workarounds, fix ascending in waterfalls after a bunnyhop, reorganise vDistWeb and vDistBush.
* Add LiftOffEnvelope.LIMIT_SURFACE instead of resorting to more workarounds for vDistSB (keep the waterfall workaround);
* Throw in more comments;
* Adjust horizontal magic values;
* Remove berry bushes compatibility flag with lower clients (We'll blame players for using outdated client versions :))

- Several more workarounds to go: oddLiquid workarounds need to be simplified and reduced too, possibly.
2022-02-23 08:24:40 +01:00
Lysandr0 b58c24e2bf Re-group air workarounds, comment on Extreme move, bug fixes, scrap stepAcc in favour of a new vDistSBLow check.
List of changes:
* Typo;
* Fix momentum ticks never being added after lost ground pyramid;
* Attempt to support bubble column's horizontal bounce effect via velocity (coarse...);
* Allow walk speed on waterlogged blocks when landing or lifting off from ground (provided all conditions are met [no head obstruction, not submerged etc..]);
* Re-group all liquid workarounds into oddLiquid to keep a better overview of all of them and for easier debugging (Also rename for the umpteenth time because I'm an idiot who can't decide);
* Lower y margin for ground collision in liquid (lift-off envelope, should help with hopping in shallow water);
* Add more confined workarounds for moving on the surface with 1.13+ clients. (vDistSB) [Likely not all cases have been covered yet (!) ];
* Allow honey block limit to consume velocity (false positives).
* [Fail] Remove lava workarounds because those cases had been tested with god-mode on... Idiot me.
* Better naming: bunnyhoptick -> momentumTick;
* Conduit assigned to pickaxe only from 1.18 and later.
2022-01-31 19:59:14 +01:00
Lysandr0 b61607a4ba [Bleeding] Changes (read on)
Sf:
* Take care of the last left-over from asofold -> Xaw3ep/CaptainObvious transition: add limits for moving in bubble columns, distinguish drag/push, deny ascension if getting dragged or descend if getting pushed.
* Bunny + headbang: add velocity on certain transitions. Modelling is too much of a hassle here.
* Alter hAcc limit slightly;
* Confine liquid workarounds a bit more;
* Modify speed limits when moving on surface while bouncing on bubble column;
* Deny ascension in liquid if sneaking;
* Waterwalk: fix potential "bypass" by checking with lower hDistance (using 2 moves to prevent false positives).

[Experimental] Sf velocity:
If strict invalidation is set to true, *ALL* horizontal velocity is cleared (queued as well, not only active) with no hDistance. Effects on actual cheats remain to be seen, but this should prevent cheaters from turning on anti-knockback hacks to conveniently collect velocity entries for a one time cheat attempt (longjump). Coarse, would be better to get the location at which a velocity entry was collected/queued and compare it to the location at which the entry was used instead.

Sf, Lava:
* Lava, horizontal move: bunnyhopping on//near lava's 6th level doesn’t slow the player down enough, it also won’t break the player’s sprint like water does. This will cause false positive as NCP will apply the liquid speed limit regardless. Also the bunnyhop mechanic won’t apply due to the change of envelope. Occasional false positives might still appear but it should be *a lot* better now.
* Lava, vertical move:
Add a vDistRel case, rather rare, was able to observe it just one time (not sure if it happens with legacy clients);
Add LiquidWorkaround case: jumping with normal gravity on the lowest lava level.

Block flags:
* Add bouncing flag to beds only from MC 1.12 and on;
* Remove the F_HEIGHT_8SIM_DEC flag from lava only from MC 1.13 and on, re-add it back from 1.16 because Mojang reverted lava movement back to pre 1.13 behaviour; however at the lowest level one can now jump up and down normally: resolved with adding the flag back up.

Blockplace:
* Re-balance Improbable feeding.

Missing:
* Launch effect for bubble streams;
* Sneaking modifier: Odd false positives, not sure what's going on here.
* Bubble columns are still horrendously buggy.
2022-01-14 11:20:50 +01:00
Lysandr0andMarkElf 69a088bdcc Fix conduit breaking times. #188
Co-Authored-By: MarkElf <13339283+MarkElf@users.noreply.github.com>
2022-01-12 20:13:48 +01:00
Lysandr0 1957f6ff0a Trash 11 year old checks. Move bedleave to SurvivalFly. Tweak MorePackets further. 2022-01-05 21:44:06 +01:00
Lysandr0 9582d4260a [Breaking] Move block flags out of BlockProperties.
+ Formatting.
2021-12-27 23:04:51 +01:00
Lysandr0 bee2c1e349 First steps into 1.18
(No new blocks with this update. Thank god)
+ Re-arrange lost ground fencestep
2021-12-18 10:37:42 +01:00
Lysandr0 5b4dc5afe9 See details.
* InAirRules: confine specific workaround to Normal env;
* Readability: iusingitem -> isUsingItem(...) | F_COBWEB2 -> F_BERRY_BUSH | typo | Order in MCAccessBukkitModern;
* Do prevent players from faking critical hits in media where they can be faked;
* Open check: test on player sleep and death;
* Sharpen stepAcc;
* Slopes: skip on jump potions, let lowjump catch the reset;
* Bunny: on slope-jumping, demand distance higher than the y on ground, at least;
* Remove legacy bullshit (awkward snowfix);
* Demand yDistance greater than minimum gravity for maxphase.
* Remove left-overs from previous bunnyhop-related commits (simply increasing speed on slope-jumping should suffice).
* Fix 1.8 chests with ice underneath.
2021-12-16 09:32:28 +01:00
Lysandr0 03dd91c49b Bug fixing, add lostground_edgefence.
* Inventory is closed if player is not air  clicking #180 ;
* Model with lost ground server-sided trapdoor touch miss #178 ;
* Add to lift off envelope minimum jump height;
* Cleanup critical;
* Switch for step-acc, currently disabled as it needs some testing.
* Alter tags.
2021-12-03 13:44:56 +01:00
Lysandr0 d40090def0 Merge branch 'master' of https://github.com/Updated-NoCheatPlus/NoCheatPlus 2021-12-03 13:38:34 +01:00
Lysandr0 28504d4891 Merge pull request #179 from bmack94/master
Fix several edge case involving climbable blocks, webs and bubble streams.
2021-12-02 17:08:54 +01:00
bmack94 ce6d0bd42c move workaround into vDistWeb 2021-12-01 20:08:26 +01:00
Lysandr0 d3594c3d75 [Experimental] Throw in a step-accounting subcheck, action accumulator based hAcc
Idea is simple (and currently bare-bone): on slope-jumping yDistance is added to to the bucket, or subtracted from it if negative. A direction change to descend phase will reset the bucket and start over (Legit players will perform a LEGIT lowjump after jumping up a slope).
If the accumulated jumping distance exceeds legit step height a VL is thrown (Setback distance did not decrease at all/enough: player did not descend enough after stepping up).
Current implementation is rather meant to fill in the gaps left by MorePackets, since continuous stepping will eventually go over its limit, thus it will trigger on early attempts of cheating (1/2 blocks, enough to let the bucket accumulate data).

* Switch hAcc to use ActionAccumulator as base.

* [Not tested] No horizontal distance = no freedom given.
2021-11-30 17:32:16 +01:00
bmack94 3a4a3ae3e0 fix issue with bubblestream & cobweb and climbing vines/ladder & inWeb 2021-11-30 11:01:40 +01:00
Lysandr0 1e2015fa56 Merge pull request #177 from RoccoDev/fix/inventory-item-drop
Don't drop items in MoreInventory
2021-11-29 15:10:12 +01:00
RoccoDev 45b196c47b Don't drop items in MoreInventory
Let Bukkit handle that instead. By closing the player's inventory, we can make sure the drop events are fired in case other plugins want to cancel them. If they do, the items are simply added back to the main inventory.
2021-11-27 00:34:01 +01:00
Lysandr0 c4949ac0ac Spin-off of previous commit, tighten workarounds.
The resetbunny case poses issues with slopes as it can prematurely reset a legit bunnyfly phase, the current workaround does work fine but it's quite convoluted: a more elegant solution could be either to remove resetbunny or relate to fall distance instead of yDistance (?) since the latter can vary too much if colliding with just about anything.
Account for ice slide downs: sprintjump on a single block the trying to fall back down will result in a single speed increase which is now covered by the bunnyhop mechanism (should be :p) .
(Who even bothers to read this stuff?)

* Fix descending in liquid while on climbable on newer servers (absolute distance).
* Possibly fixed #171 .
* Confine slope speed increase to speeds greater than walking.
* Fix lift off envelope not being updated after a powder snow setback.
* Format, comment on NoFall.
* Review some workarounds: confine slime workarounds by actually having been on slime
2021-11-16 13:21:34 +01:00
Lysandr0 3695671d3b [Bleeding] Bunnyhop, bunnyfly, bug fixes.
Several/Major bunny adjustments (+ on the fly bug fixes)

1) Bunnyhop and slopes:
a) Let bunnyhop apply on yDistance
slopes (the jumping envelope is never hit: gravity hits harder here).
b) Grounded acceleration case (air-ground(landing), 0 hDist diff  ->
ground-ground,  0 hDist diff-> ground-ground, sudden mini burst of speed with no yDistance.
For this phase, we simply give players more momentum via bunnyhop ticks and increase speed slightly.
c) Continuous slope-jumping on ice will still fail  as speed  will keep increasing with each hop (Slime and normal ground seems fine)
d) Observed: edge case where bunnyfly speed decreases extremely little (in-air), thus, if the player has recently jumped up a slope and the hDist difference is small enough, the movement is allowed (should be confined more perhaps).

2) Get rid of that bloody sfOnIce legacy counter, at last.

3) Patch unintentional bypass with ice and headobstr.(bunnyhop -> drop speed below allowed to force set allowHop to true and to increase allowed friction speed -> bunnyhop again with higher speed (yOnGround case applies).

4) Cleanup, "simplify" (Where possible. Still too much spaghetti. Perhaps it's time for a rework :p).

5) Headbangbunny:
a) Don't wildcard; model should be decent enough now.
b) Observed: yet another case where clients can reach increasingly higher speed on ground: Touching ground in bunnyfriction with 0.3 speed -> ground-ground acceleration with 0.4 speed (bunnyhop) -> lifting off with increasing speed 0.5 (subsequent bunnyhop).

6) Hotfix for #171 : Allow bunny to consume the buffer.

7) Always clear hAcc on headbang.

8) On the fly:
a) sfVLTime -> sfVLMoveCount: we count moves, not time here.
b) Fix hopping right into a web (vertical).
c) Distinguish body in water VS body out of water when enforcing liquid->liquid speed limit: Magic has been warped for some time, how did we not get buried with reports about this !?
(Revert value to this commit: https://github.com/Updated-NoCheatPlus/NoCheatPlus/commit/c4331e1ffd4c7c17c43dba03f98f6feb875ada5b#diff-4adf02d4661b4aa4c5031880e2dd87200601581264a6d62eb56ce8c4b1606040 ).
d) Don't allow players to stand anywhere between minimum ground height and block height on ladders: fixes some fastladder bypasses (For @xaw3ep  is the Ground_Height flag still necessary? Seems like it's safe to remove)
Also slightly stricter climbable checking (step).

9) Move bunny stuff into its own workaround class (Coherence).

Missing:
1) Transitions stay problematic:
headobstructed -> head free / headobstructed on ice -> headobstructed on normal ground.

2) Bunnyhop while skimming over the edges of blocks. (video: https://www.dropbox.com/s/tdk1rdf9r3xwz5l/Edge_test.mov?dl=0 )
It does look like it's a problem with ice only (likely due to past moves being updated to not being on ice when touching the ground, the "lowjump problem" contributes as well).

3) Random setbacks when moving off from ice. Couldn't nail down the reason, let the buffer deal with this bullshit for now. Hopefully the higher modifier aids a little...

4) Hacc needs adjustments to take into account all illustrated cases.

5) Hop-after-velocity #171
Also applies when stopping to fly in air at high speed and falling. Looks like velocity isn't extended for long enough?
2021-11-10 16:31:30 +01:00
Lysandr0 31bbfcff7d Adjust speed effect calculations
MC formula doesn't match too well with NCP's. Speed is increased by too much.

On the fly:
Comments.
2021-10-29 20:19:09 +02:00
Lysandr0 f1cb04a485 Declutter the moving listener.
Move all the bounce stuff to its own package/class.
2021-10-25 13:04:43 +02:00
Lysandr0 12ae08f21d Comment out climbclick for now.
Can't test it currently.
(Reminder for #170)
2021-10-19 17:59:41 +02:00
Lysandr0 8ea9b33bc9 Ops... 2021-10-19 10:47:58 +02:00
Lysandr0 b9f78ab326 More bunnies (+)
Changes:
* Fix a minor derp in FightListener: Improbable was being fed even with fight.speed disabled;
* isOnBouncyBlock environmental property, accounting for beds too;
* SurvivalFly:
   - Increase hAcc limit for headobstr
      with ice;
   - Move honey block collision to
      MovingUtil;
   - Fix head obstructed + bunny with
      lower block;
   - Reset hAcc in ediblebunny as well
      if head is obstructed;
* Add wasOnIceRecently method. Uses past move tracking;
* Move Extreme_move subcheck for flying packets into its own check. Also (potentially) fix some false positives;
* Remove WrongPacket. Useless;
* Only feed Improbable in Impossiblehit (no check);
* Tweaks for default config.
2021-10-19 10:28:32 +02:00
Lysandr0 7098895eda Last clean-up.
Hopefully... :)
Add more comments and notes.
2021-10-08 22:00:18 +02:00
Lysandr0 6b8087c380 Bunnyslide: switch to a flag, remove unneeded conditions.
Fix slime edge case, cleanup.
2021-10-06 20:50:11 +02:00
Lysandr0 b82b898695 [Bleeding] Kill all bunnies.
Just kidding. Only two more remain.

 Changes:
* Only apply ice/slime properties if the box is at least half on the block (Respect Minecraft's mechanics).
* Adjust use of blocking/sneaking modifiers;
* Model:
 -Bunnyhopping on ice/slime (see below);
 -Generalize and fix bunnyhopping with head obstructed (ice/slime);
 -Let friction apply when walking on
ice;
-Introduced a "bunnyslide" phase alongside bunnyfly, which does the same job except bunnyslide ticks are used to determine by how much bunny friction speed needs to be decreased  when bunnyhopping on slippery blocks.
It will essentially increase friction multipliers, allowing players to have a higher bunny friction speed.
-After a bunnyslide phase has ended we give players a little time window by which the allowed speed is increased, since the client can retain ice-air speed for a bit after sliding back on ground. Done here via increasing bunnyhopTick.
* The legacy sfOnIce counter has been dropped entirely. Kept only for one edge case (head obstructed on ice with trapdoors underneath. We cannot detect server-side if the player is jumping. Thank MC for that :p)

Missing:
* Bunnyhopping with lower blocks and head obstructed;
* Bunnyhopping out of a 2-blocks high area, resulting in a higher in-air speed. This is especially noticeable/severe with ice. Not sure on what direction we should take here (Grace counter? Prolong bunnyslide/fly?)
* At some point, hAcc will kick in with head obstructed... Needs to be adjusted
* False positives with head obstr. and ice/slime might still be present, since I'm not a tryhard and I can't spam space-bar fast enough to see the maximum speed clients can achieve during this scenario :)
* Cleanup, bunnyhop multipliers could be stricter.

Effects on bunnyhop speeding remains to be seen. However this commit should patch ice speeding, rather.
2021-10-06 12:07:12 +02:00
Lysandr0 f56b9375f0 Generalize headbangbunny.
Lift off envelope for stairs: to be implemented.
2021-10-04 08:55:52 +02:00
Lysandr0 01780f936f Merge branch 'master' into ImpossibleHit-WrongPacket 2021-09-21 16:37:14 +02:00
Lysandr0 41c798f26e Catch #160, comments, rename stuff
* Renamed old/confusing F_NEWLIQ to be better reflect what it is supposed to represent.
* More comments !
* Swiftly throw in a method to check  for step-like movements (magic).
* Allow stepping in waterlogged blocks
2021-09-21 16:33:45 +02:00
Lysandr0 fffb1f4fde Having a look at fastclick's chest limit.
Mainly clean things up.
* Cooldown fastclick violations if legit;
* Do feed Improbable for fastclickchest;
* Comments, mainly reminders for the future;
* Update readme;
* Limit bhop speeding on ice;
2021-09-14 10:38:01 +02:00
Lysandr0 83d3da960d Further fiddle with ImpossibleHit.
* Added a method to retrieve a past flying packet, will be useful for #150
2021-09-10 13:25:32 +02:00
Lysandr0 8af2853bdd Forgot about this one. 2021-09-07 22:50:46 +02:00
Lysandr0 fbafbdbbf2 Adjustments to previous commit.
Also fix some fuck ups. More comments.
2021-09-07 21:06:11 +02:00
Lysandr0 4687a96543 Add net.wrongpacket and fight.impossiblehit, convenience method to see if players may have their own inv open
+ Comments/Document stuff and format, as always.
For now wrongpacket only checks for invalid abilities packet;

(Not pushed in master because it contains (rather) important changes and I'd prefer it to be reviewed by @xaw3ep :) )
2021-09-06 09:19:16 +02:00
Lysandr0 0951915aa1 Attempt to catch #154
Commented out the reset condition for now: let the bunnyhop model apply when moving on stairs.
Can't test further conditions to limit it currently.
2021-08-27 17:20:53 +02:00
Lysandr0 a1c652f2ab Fix NPE in MovingData, more bug fixes
* Against: null = air :)
* InventoryMove: safety check for the case users input a too low value;
* Scaffold: only feed Improbable if the placement is scaffold-like;
* Alter config values;
* FastPlace: only feed Improbable for higher violations.
2021-08-24 12:57:39 +02:00
Lysandr0 a5dfaa4c58 Do monitor the yaw speed rate when scaffolding. 2021-08-21 12:56:58 +02:00
Lysandr0 a3ea9dec8d Allow Scaffold/AttackClick to feed Improbable.
* Clear Improbable's data if leaving the server;
* Correct permission for Scaffold;
* Top/InfoCommand: format;
* Restore BlockPlace debug info,
2021-08-19 19:43:05 +02:00
Lysandr0 07fb893d65 Simplify InventoryMove, detect click+attack.
Too tired(+tedious) to fix all false positive for now.
2021-08-18 21:00:48 +02:00
adampoulson 980a58e570 Merge branch 'master' into test 2021-08-18 20:41:49 +04:30
Lysandr0 a684a107f0 Drop client-mods support, changes
The MOTD implementation is severely outdated (it's been a decade since it was first introduced), mostly unused and actually caused more issues than anything (blank message on join) :)

Changes:
* Sweep old Critical workaround for lowjumping;
* InAirRules: match format style, move more workarounds into the class;
* CreativeFly: remove ascending slowfall handling as well as riptide->other model velocity transition;
* Extend riptide model for 1 second after the riptide phase has finished;
* SurvivalFly cleanup, yet again;
* Typos in WRPT;
* Attempt to make MorePackets stricter;
* Order in MovingData.
* Allow movetrace to keep track of aboveStairs property;
* Move setNextFriction to MovingData;
* Inflate MoveTrace to keep track of 4 moves from now on;
2021-08-18 13:30:09 +02:00
adampoulson 79ecc18778 fix a typo 2021-08-17 18:45:20 +04:30
adampoulson ed4e682d9b improve boat speed checks
added speed check for water and ground.
fixed false positives that caused by them.
2021-08-13 02:00:56 +04:30
Lysandr0 7ef94a5339 Update bug_report.md 2021-08-09 16:28:54 +02:00
xaw3ep 7ef4f3a1e5 Too rush 2021-08-08 20:06:01 +07:00
xaw3ep ba59a57dc7 Resolve issues
Fixes #139, #126 by having safer setback ?
Fixes #142 and mostly #141
2021-08-08 15:50:13 +07:00
xaw3ep aeaabcd6a4 Blocks, again
Bugs everywhere!
*Changes:
 + Fix false positive with deepslate
 + Recalculate properly with tool efficiency
 + Correct some minor wall bugs
2021-08-02 23:05:00 +07:00
xaw3ep c995139c3a Random things
Mixed of many fixes
* Change:
 + Fix null model?
 + Comment out IEntityAccessLastPositionAndLook. Nothing need
 + Improve elytra handle?
 + Fix false using shulker in narrow space
2021-08-02 22:53:56 +07:00
Lysandr0 7a00d4a308 Usual cleanup
* Alter one magic value
* Add shulker boxes to the change tracker (not tested)
* Cleanup
* Comment out packet type
2021-07-28 18:07:06 +02:00
481 changed files with 40941 additions and 25072 deletions

No files matched your search

+9 -5
View File
@@ -6,13 +6,17 @@ labels: ''
assignees: ''
---
#### *Complete* output of the `ncp version` command
### Full output of /ncp version
### Output of the `ncp inspect [playername]` command for in-game issues
### Describe the issue
#### Short description of the issue and how to reproduce
### How to reproduce the issue
#### Have you made any (noteworthy) changes to the default configuration of NCP?
### Extra links/Videos (Including debug logs)
#### Do you run any other special plugins that affect game mechanics next to NC+ (skills, machines, adding/changing blocks, other anti-cheating)?
#### Do you use **client-side** mods that could interfere with vanilla game mechanics **_(such as Optifine's FastMath)_**?
#### Provide additional information: for bypasses, vulnerabilities and reproducible issues, we request a [debug log. ](https://github.com/Updated-NoCheatPlus/Docs/blob/master/Development/Debugging.md#on-the-fly-debug-output-for-individual-players) Use [GitHub gists](https://gist.github.com/) or [PasteBin](http://pastebin.com/) or similar for errors and huge logs, or attach a (zip-) file here.
### Any possible config options changed or plugins that may cause interference?
@@ -40,10 +40,10 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
protected int maxQueueSize = 5000;
/**
* Task id, -1 means the asynchronous task is not running. Synchronize over
* Task id, null means the asynchronous task is not running. Synchronize over
* queueAsynchronous. Must be maintained.
*/
protected int taskAsynchronousID = -1;
protected Object taskAsynchronousID = null;
/**
* Optional implementation for an asynchronous task, using the
* taskAsynchronousID, synchronized over queueAsynchronous.
@@ -57,7 +57,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
while (i < 3) {
if (runLogsAsynchronous()) {
i = 0;
if (taskAsynchronousID == -1) {
if (!isTaskScheduled(taskAsynchronousID)) {
// Shutdown, hard return;
return;
}
@@ -69,7 +69,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
} catch (InterruptedException e) {
synchronized (queueAsynchronous) {
// Ensure re-scheduling can happen.
taskAsynchronousID = -1;
taskAsynchronousID = null;
}
// TODO: throw?
return;
@@ -79,7 +79,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
if (queueAsynchronous.isEmpty()) {
if (i >= 3) {
// Ensure re-scheduling can happen.
taskAsynchronousID = -1;
taskAsynchronousID = null;
}
} else {
i = 0;
@@ -134,10 +134,10 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
// Cancel task.
synchronized (queueAsynchronous) {
if (taskAsynchronousID != -1) {
if (isTaskScheduled(taskAsynchronousID)) {
// TODO: Allow queues to set to "no more input" ?
cancelTask(taskAsynchronousID);
taskAsynchronousID = -1;
taskAsynchronousID = null;
} else {
// No need to wait.
ms = 0L;
@@ -184,7 +184,7 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
if (queueAsynchronous.add(record) > maxQueueSize) {
reduceQueue(queueAsynchronous);
}
if (taskAsynchronousID == -1) { // Works, due to add being synchronized (not sure it's really better than full sync).
if (!isTaskScheduled(taskAsynchronousID)) { // Works, due to add being synchronized (not sure it's really better than full sync).
scheduleAsynchronous();
}
break;
@@ -242,6 +242,8 @@ public abstract class AbstractLogNodeDispatcher implements LogNodeDispatcher { /
protected abstract void scheduleAsynchronous();
protected abstract void cancelTask(int taskId);
protected abstract void cancelTask(Object taskInfo);
protected abstract boolean isTaskScheduled(Object taskInfo);
}
@@ -43,5 +43,15 @@ public class Misc {
}
list.add(0, item);
}
/**
* Flooring method copied from the BukkitAPI (locToBlock)
* @param num
* @return
*/
public static int floor(double num) {
final int floor = (int) num;
return floor == num ? floor : floor - (int) (Double.doubleToRawLongBits(num) >>> 63);
}
}
@@ -32,12 +32,19 @@ public class StringUtil {
/** Decimal format for "#.###" */
public static final DecimalFormat fdec3 = new DecimalFormat();
/** Decimal format for "#.#" */
/** Decimal format for "#.######" */
public static final DecimalFormat fdec1 = new DecimalFormat();
public static final DecimalFormat fdec6 = new DecimalFormat();
static {
DecimalFormatSymbols sym = fdec6.getDecimalFormatSymbols();
// 6 digits
sym.setDecimalSeparator('.');
fdec6.setDecimalFormatSymbols(sym);
fdec6.setMaximumFractionDigits(6);
fdec6.setMinimumIntegerDigits(1);
// 3 digits.
DecimalFormatSymbols sym = fdec3.getDecimalFormatSymbols();
sym = fdec6.getDecimalFormatSymbols();
sym.setDecimalSeparator('.');
fdec3.setDecimalFormatSymbols(sym);
fdec3.setMaximumFractionDigits(3);
@@ -401,7 +408,7 @@ public class StringUtil {
}
/**
* Format to maximally 3 digits after the comma, always show the sign,
* Format to maximally 6 digits after the comma, always show the sign,
* unless equal.
*
* @param current
@@ -409,7 +416,7 @@ public class StringUtil {
* @return
*/
public static String formatDiff(final double current, final double previous) {
return current == previous ? "0" : ((current > previous ? "+" : "-") + fdec3.format(Math.abs(current - previous)));
return current == previous ? "0" : ((current > previous ? "+" : "-") + fdec6.format(Math.abs(current - previous)));
}
public static boolean startsWithAnyOf(final String input, final String... startsWith) {
@@ -15,7 +15,7 @@
package fr.neatmonster.nocheatplus.utilities;
/**
* Simple parameter/thing validation.
* Simple parameter/thing for recurring validation.
*
* @author asofold
*
@@ -36,5 +36,26 @@ public class Validate {
}
}
}
/**
* Validates that the given double array's length: is a multiple of 6, does contain at least 1 bounding box and is not null.
*
* <p>Currently, this is rather meant to validate double arrays containing multiple bounding boxes, each defined by six consecutive elements
* [minX, minY, minZ, maxX, maxY, maxZ].<br>
*
* @param array The double array to validate.
*
* @throws IllegalArgumentException If the array length is not a multiple of 6, null or empty.
*/
public static void validateAABB(final double[] array) {
if (array == null) {
throw new NullPointerException("The array is null.");
}
if (array.length == 0) {
throw new IllegalArgumentException("The array is empty.");
}
if (array.length % 6 != 0) {
throw new IllegalArgumentException("Array length is not a multiple of 6. Actual length: " + array.length);
}
}
}
@@ -16,9 +16,9 @@ package fr.neatmonster.nocheatplus.utilities.ds.bktree;
import java.util.Collection;
import fr.neatmonster.nocheatplus.utilities.ds.bktree.BKModTree.LookupEntry;
import fr.neatmonster.nocheatplus.utilities.ds.bktree.SimpleTimedBKLevenshtein.STBKLResult;
import fr.neatmonster.nocheatplus.utilities.ds.bktree.TimedBKLevenshtein.SimpleTimedLevenNode;
import fr.neatmonster.nocheatplus.utilities.ds.bktree.BKModTree.LookupEntry;
public class SimpleTimedBKLevenshtein extends TimedBKLevenshtein<SimpleTimedLevenNode, STBKLResult> {
@@ -17,99 +17,153 @@ package fr.neatmonster.nocheatplus.utilities.ds.count;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
/**
* This class is meant to accumulate actions similar to ActionFrequency. In contrast to ActionFrequency, this class will accumulate values grouped by number of events instead of real-time intervals.
* @author mc_dev
* This class is meant to accumulate actions similar to ActionFrequency.
* In contrast to ActionFrequency, this class will accumulate values grouped by number of events instead of real-time intervals.
* @author asofold
*
*/
public class ActionAccumulator {
/** Event count. */
private final int[] counts;
/** Value accumulation. */
private final float[] buckets;
/** Capacity of each bucket. */
private final int bucketCapacity;
public ActionAccumulator(final int nBuckets, final int bucketCapacity){
this.counts = new int[nBuckets];
this.buckets = new float[nBuckets];
this.bucketCapacity = bucketCapacity;
}
public void add(float value){
if (counts[0] >= bucketCapacity){
shift();
}
counts[0] ++;
buckets[0] += value;
}
private void shift() {
for (int i = buckets.length - 1; i > 0 ; i--){
counts[i] = counts[i - 1];
buckets[i] = buckets[i - 1];
}
counts[0] = 0;
buckets[0] = 0;
}
/** Counter of added events for each bucket. */
private final int[] valueCounter;
/** Value accumulation (sum). */
private final float[] buckets;
/** How many events can a bucket hold. */
private final int bucketCapacity;
/**
* Create a new ActionAccumulator instance
*
* @param nBuckets Number of buckets to hold values with
* @param bucketCapacity How many events can a bucket hold
*/
public ActionAccumulator(final int nBuckets, final int bucketCapacity) {
this.valueCounter = new int[nBuckets];
this.buckets = new float[nBuckets];
this.bucketCapacity = bucketCapacity;
}
/**
* Add value to accumulation (starting to the first bucket, shifting into the other ones if present)
* See shift()
*/
public void add(float value) {
if (valueCounter[0] >= bucketCapacity) {
// First bucket is full, shift data into the next one .
shift();
}
// Each time a value is added, the event counter for this bucket increases.
valueCounter[0]++ ;
// Accumulate the value
buckets[0] += value;
}
/**
* On reaching the maximum capacity of the first bucket,
* shift data into the next one and empty the first (which will be ready to accumulate values again).
*/
private void shift() {
// Start from the last bucket and decrease
for (int bucketIndex = buckets.length - 1; bucketIndex > 0; bucketIndex--) {
// Shift counted events to the next bucket
valueCounter[bucketIndex] = valueCounter[bucketIndex - 1];
// Shift accumulated values to the next bucket
buckets[bucketIndex] = buckets[bucketIndex - 1];
}
// Reset event counter of the first bucket
valueCounter[0] = 0;
// Empty the bucket (accumulated values)
buckets[0] = 0;
}
/**
* Total score.
* @return
*/
public float score(){
float score = 0;
for (int i = 0; i < buckets.length; i++){
score += buckets[i];
}
return score;
}
/**
* Total count.
* @return
*/
public int count(){
int count = 0;
for (int i = 0; i < counts.length; i++){
count += counts[i];
}
return count;
}
public void clear(){
for (int i = 0; i < buckets.length; i++){
counts[i] = 0;
buckets[i] = 0;
}
}
public int bucketCount(final int bucket){
return counts[bucket];
}
public float bucketScore(final int bucket){
return buckets[bucket];
}
public int numberOfBuckets(){
return buckets.length;
}
public int bucketCapacity(){
return bucketCapacity;
}
/**
* Simple display of bucket contents, no class name.
* @return
*/
public String toInformalString(){
StringBuilder b = new StringBuilder(buckets.length * 10);
b.append("|");
for (int i = 0; i < buckets.length; i++){
b.append(StringUtil.fdec3.format(buckets[i]) + "/" + counts[i] + "|");
}
return b.toString();
}
}
/**
* Get the total accumulation value of this accumulator (values of all buckets)
*/
public float score() {
float score = 0;
for (int i = 0; i < buckets.length; i++) {
score += buckets[i];
}
return score;
}
/**
* Get the total events of the whole accumulator (of all buckets)
*/
public int count() {
int globalCounter = 0;
for (int i = 0; i < valueCounter.length; i++) {
globalCounter += valueCounter[i];
}
return globalCounter;
}
/**
* Reset all
*/
public void clear() {
for (int i = 0; i < buckets.length; i++) {
valueCounter[i] = 0;
buckets[i] = 0;
}
}
/**
* Get the events counted for this bucket
* @param bucket
* @return how many events have been added(counted) to the bucket
*/
public int bucketCount(final int bucket) {
return valueCounter[bucket];
}
/**
* Get the accumulation value of this bucket (sum of all values added to this bucket)
* @param bucket
* @return accumulation value of this bucket
*/
public float bucketScore(final int bucket) {
return buckets[bucket];
}
/**
* Get the mean of this bucket
* @param bucket
* @return the mean of this bucket
*/
public float mean(final int bucket) {
return bucketScore(bucket) / bucketCount(bucket);
}
/**
* Get the mean of the whole accumulator
*/
public float mean() {
return score() / count();
}
/**
* How many buckets does the ActionAccumulator instance have
*/
public int numberOfBuckets() {
return buckets.length;
}
/**
* How many events(count) can each bucket of the ActionAccumulator instance have
*/
public int bucketCapacity() {
return bucketCapacity;
}
/**
* Simple display of bucket contents, no class name.
*/
public String toInformalString() {
StringBuilder b = new StringBuilder(buckets.length * 10);
b.append("|");
for (int i = 0; i < buckets.length; i++){
b.append(StringUtil.fdec3.format(buckets[i]) + "/" + valueCounter[i] + "|");
}
return b.toString();
}
}
@@ -139,24 +139,6 @@ public class ActionFrequency {
time = lastUpdate = now;
}
/**
* @deprecated Use instead: score(float).
* @param factor
* @return
*/
public final float getScore(final float factor) {
return score(factor);
}
/**
* @deprecated Use instead: score(float).
* @param factor
* @return
*/
public final float getScore(final int bucket) {
return bucketScore(bucket);
}
/**
* Get a weighted sum score, weight for bucket i: w(i) = factor^i.
* @param factor
@@ -0,0 +1,196 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.utilities.ds.map;
import fr.neatmonster.nocheatplus.utilities.Misc;
/**
* Integer block coordinate with support for in-place mutation.
*/
public class BlockCoord implements Cloneable {
/*
* NOTE: This class is now mutable to allow in-place addition/subtraction
* operations that do not create new instances. Because instances are
* mutable they are NOT safe to use as keys in hash-based collections if
* their coordinates may change while stored; use {@link #copy()} to get an
* immutable snapshot when needed.
*/
private int x;
private int y;
private int z;
/**
* Constructs a BlockCoord with integer coordinates.
*
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param z The z-coordinate.
*/
public BlockCoord(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
/**
* Constructs a BlockCoord from double coordinates by converting them
* to block integer coordinates using the same method as Bukkit's Location#locToBlock().
*
* @param x The x-coordinate.
* @param y The y-coordinate.
* @param z The z-coordinate.
*/
public BlockCoord(double x, double y, double z) {
this.x = Misc.floor(x);
this.y = Misc.floor(y);
this.z = Misc.floor(z);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getZ() {
return z;
}
@Override
public int hashCode() {
return CoordHash.hashCode3DPrimes(x, y, z);
}
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null || getClass() != obj.getClass()) return false;
BlockCoord bc = (BlockCoord) obj;
return bc.getX() == x && bc.getY() == y && bc.getZ() == z;
}
/**
* Add the given BlockCoord to this one.
*
* @param other the other BlockCoord to add to this one
* @return this (after modification)
*/
public BlockCoord add(BlockCoord other) {
return add(other.x, other.y, other.z);
}
/**
* Add the given integers to this BlockCoord.
*
* @param dx delta x
* @param dy delta y
* @param dz delta z
* @return this (after modification)
*/
public BlockCoord add(int dx, int dy, int dz) {
this.x += dx;
this.y += dy;
this.z += dz;
return this;
}
/**
* Subtract the given BlockCoord from this one.
*
* @param other the other BlockCoord to subtract
* @return this (after modification)
*/
public BlockCoord subtract(BlockCoord other) {
return subtract(other.x, other.y, other.z);
}
/**
* Subtract the given integers from this BlockCoord.
*
* @param dx delta x
* @param dy delta y
* @param dz delta z
* @return this (after modification)
*/
public BlockCoord subtract(int dx, int dy, int dz) {
this.x -= dx;
this.y -= dy;
this.z -= dz;
return this;
}
/**
* Returns the squared Euclidean distance between this block coordinate
* and another BlockCoord (integer arithmetic). Returns a double to match
* common expectations and avoid overflow for large distances.
*
* @param other the other block coordinate
* @return squared distance as a double
*/
public double distanceSquared(BlockCoord other) {
long dx = this.x - other.x;
long dy = this.y - other.y;
long dz = this.z - other.z;
return dx * dx + dy * dy + dz * dz;
}
/**
* Returns the squared Euclidean distance between this block coordinate
* and the specified integer coordinates.
*
* @param x x coordinate to compare to
* @param y y coordinate to compare to
* @param z z coordinate to compare to
* @return squared distance as a double
*/
public double distanceSquared(int x, int y, int z) {
long dx = this.x - x;
long dy = this.y - y;
long dz = this.z - z;
return dx * dx + dy * dy + dz * dz;
}
/**
* Create a copy of this BlockCoord. Returns a new independent instance
* with the same coordinates (useful when you need an immutable snapshot
* while mutating the original).
*
* @return a new BlockCoord with identical coordinates
*/
public BlockCoord copy() {
return new BlockCoord(x, y, z);
}
/**
* Clone this BlockCoord.
* <p>
* This implementation attempts to use Object#clone() (via
* super.clone()). If, for some reason,
* cloning via super is not supported (CloneNotSupportedException), we
* fall back to creating a manual copy via {@link #copy()}.
*
* @return a new BlockCoord with identical coordinates
*/
@Override
public BlockCoord clone() {
try {
return (BlockCoord) super.clone();
} catch (CloneNotSupportedException e) {
return copy();
}
}
}
@@ -14,9 +14,9 @@
*/
package fr.neatmonster.nocheatplus.utilities.ds.prefixtree;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.CharPrefixTree.CharLookupEntry;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.CharPrefixTree.SimpleCharNode;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.SimpleCharPrefixTree.SimpleCharLookupEntry;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.CharPrefixTree.CharLookupEntry;
/**
* Adding some convenience methods.
@@ -14,9 +14,9 @@
*/
package fr.neatmonster.nocheatplus.utilities.ds.prefixtree;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.PrefixTree.LookupEntry;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.PrefixTree.SimpleNode;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.SimplePrefixTree.SimpleLookupEntry;
import fr.neatmonster.nocheatplus.utilities.ds.prefixtree.PrefixTree.LookupEntry;
/**
* Simple prefix tree, for one given key type.
@@ -14,7 +14,7 @@
*/
package fr.neatmonster.nocheatplus.test;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
import org.junit.Test;
@@ -14,7 +14,7 @@
*/
package fr.neatmonster.nocheatplus.test;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
import org.junit.Test;
@@ -14,7 +14,7 @@
*/
package fr.neatmonster.nocheatplus.test;
import static org.junit.Assert.*;
import static org.junit.Assert.fail;
import org.junit.Test;
@@ -21,8 +21,8 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.SplittableRandom;
import org.junit.Test;
@@ -30,8 +30,8 @@ import fr.neatmonster.nocheatplus.utilities.build.BuildParameters;
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordHashMap;
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordMap;
import fr.neatmonster.nocheatplus.utilities.ds.map.CoordMap.Entry;
import fr.neatmonster.nocheatplus.utilities.ds.map.LinkedCoordHashMap.MoveOrder;
import fr.neatmonster.nocheatplus.utilities.ds.map.LinkedCoordHashMap;
import fr.neatmonster.nocheatplus.utilities.ds.map.LinkedCoordHashMap.MoveOrder;
public class TestCoordMap {
@@ -74,7 +74,7 @@ public class TestCoordMap {
private final boolean extraTesting = BuildParameters.testLevel > 0;
private final int suggestedSamples = extraTesting ? 40000 : 1250;
public int[][] getRandomCoords(int n, int max, Random random) {
private static int[][] getRandomCoords(int n, int max, SplittableRandom random) {
final int [][] coords = new int[n][3];
for (int i = 0; i < n; i++){
for (int j = 0; j < 3 ; j++){
@@ -84,7 +84,7 @@ public class TestCoordMap {
return coords;
}
public int[][] getUniqueRandomCoords(int n, int max, Random random) {
private static int[][] getUniqueRandomCoords(int n, int max, SplittableRandom random) {
Set<Pos> present = new HashSet<Pos>();
int failures = 0;
final int [][] coords = new int[n][3];
@@ -311,7 +311,7 @@ public class TestCoordMap {
@Test
public void testIntegrity() {
final Random random = new Random(System.nanoTime() - (System.currentTimeMillis() % 2 == 1 ? 37 : 137));
final SplittableRandom random = new SplittableRandom();
final int n = suggestedSamples; // Number of coordinates.
final int max = 800; // Coordinate maximum.
@@ -333,7 +333,7 @@ public class TestCoordMap {
@Test
public void testLinkedCoordHashMap() {
final Random random = new Random(System.nanoTime() - (System.currentTimeMillis() % 2 == 1 ? 37 : 137));
final SplittableRandom random = new SplittableRandom();
final int n = suggestedSamples; // Number of coordinates.
final int max = 800; // Coordinate maximum.
+2 -1
View File
@@ -19,7 +19,8 @@
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.17.1-R0.1-SNAPSHOT</version>
<!-- Do not increase. 1.12 was the last version having its own native module -->
<version>1.21.11-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -1,169 +0,0 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.checks.inventory;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.ItemStack;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.actions.ParameterName;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.checks.ViolationData;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.components.config.value.OverrideType;
import fr.neatmonster.nocheatplus.components.registry.feature.INotifyReload;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.stats.Counters;
import fr.neatmonster.nocheatplus.utilities.InventoryUtil;
import fr.neatmonster.nocheatplus.utilities.TickTask;
/**
* Quick replacement for InstantEat, partly reusing InstantEat data.<br>
* This check is added by fr.neatmonster.nocheatplus.compat.DefaultComponentFactory.
* @author mc_dev
*
*/
public class FastConsume extends Check implements Listener, INotifyReload {
public static void testAvailability(){
if (!PlayerItemConsumeEvent.class.getSimpleName().equals("PlayerItemConsumeEvent")){
throw new RuntimeException("This exception should not even get thrown.");
}
}
private final Counters counters = NCPAPIProvider.getNoCheatPlusAPI().getGenericInstance(Counters.class);
private final int idCancelDead = counters.registerKey("cancel.dead");
public FastConsume() {
super(CheckType.INVENTORY_FASTCONSUME);
// Overrides the instant-eat check.
disableInstantEat();
}
private void disableInstantEat() {
// TODO: Do this kind of thing via registries later on.
//ConfigManager.setForAllConfigs(ConfPaths.INVENTORY_INSTANTEAT_CHECK, false);
NCPAPIProvider.getNoCheatPlusAPI().getWorldDataManager().overrideCheckActivation(
CheckType.INVENTORY_INSTANTEAT, AlmostBoolean.NO,
OverrideType.PERMANENT, true);
StaticLog.logInfo("Inventory checks: FastConsume is available, disabled InstantEat.");
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onItemConsume(final PlayerItemConsumeEvent event){
final Player player = event.getPlayer();
if (player.isDead() && BridgeHealth.getHealth(player) <= 0.0) {
// Eat after death.
event.setCancelled(true);
counters.addPrimaryThread(idCancelDead, 1);
return;
}
final IPlayerData pData = DataManager.getPlayerData(player);
if (!pData.isCheckActive(type, player)) {
return;
}
final InventoryData data = pData.getGenericInstance(InventoryData.class);
final long time = System.currentTimeMillis();
if (check(player, event.getItem(), time, data, pData)){
event.setCancelled(true);
DataManager.getPlayerData(player).requestUpdateInventory();
}
}
private boolean check(final Player player, final ItemStack stack,
final long time, final InventoryData data, final IPlayerData pData){
// Uses the instant-eat data for convenience.
// Consistency checks...
if (stack == null){ // || stack.getType() != data.instantEatFood){
// TODO: Strict version should prevent other material (?).
return false;
}
final long ref = data.instantEatInteract == 0 ? 0 : Math.max(data.instantEatInteract, data.lastClickTime);
if (time < ref){
// Time ran backwards.
data.instantEatInteract = data.lastClickTime = time;
return false;
}
// Check exceptions.
final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class);
final Material mat = stack == null ? null : stack.getType();
if (mat != null){
if (cc.fastConsumeWhitelist){
if (!cc.fastConsumeItems.contains(mat)){
return false;
}
}
else if (cc.fastConsumeItems.contains(mat)){
return false;
}
}
// Actually check.
final long timeSpent = ref == 0 ? 0 : (time - ref); // Not interact = instant.
final long expectedDuration = cc.fastConsumeDuration;
boolean cancel = false;
if (timeSpent < expectedDuration){
// TODO: Might have to do a specialized check for lag spikes here instead.
final float lag = TickTask.getLag(expectedDuration, true);
if (timeSpent * lag < expectedDuration){
final double difference = (expectedDuration - timeSpent * lag) / 100.0;
data.instantEatVL += difference;
final ViolationData vd = new ViolationData(this, player, data.instantEatVL, difference, cc.fastConsumeActions);
vd.setParameter(ParameterName.FOOD, "" + mat);
if (data.instantEatFood != mat){
vd.setParameter(ParameterName.TAGS, "inconsistent(" + data.instantEatFood + ")");
}
else{
vd.setParameter(ParameterName.TAGS, "");
}
if (executeActions(vd).willCancel()){
cancel = true;
}
}
}
else{
data.instantEatVL *= 0.6;
}
// Reset interaction.
if (cancel) {
// Fake interaction to prevent violation loops with false positives.
final ItemStack actualStack = InventoryUtil.getFirstConsumableItemInHand(player);
data.instantEatFood = actualStack == null ? null : actualStack.getType();
// TODO: Allows some abuse: 1. try instantly eat (cancelled) 2. consume item directly when needed.
}
else {
if (pData.isDebugActive(type)) {
debug(player, "PlayerItemConsumeEvent, reset fastconsume: " + data.instantEatFood);
}
data.instantEatFood = null;
}
data.instantEatInteract = time;
return cancel;
}
@Override
public void onReload() {
disableInstantEat();
}
}
@@ -1,64 +0,0 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.checks.inventory;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerEditBookEvent;
import org.bukkit.inventory.meta.BookMeta;
import fr.neatmonster.nocheatplus.checks.Check;
import fr.neatmonster.nocheatplus.checks.CheckType;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.IPlayerData;
public class Gutenberg extends Check implements Listener {
public static void testAvailability(){
if (!PlayerEditBookEvent.class.getSimpleName().equals("PlayerEditBookEvent")){
throw new RuntimeException("This exception should not even get thrown.");
}
}
public Gutenberg() {
super(CheckType.INVENTORY_GUTENBERG);
}
@EventHandler(priority = EventPriority.LOWEST, ignoreCancelled = true)
public void onEditBook(final PlayerEditBookEvent event) {
final Player player = event.getPlayer();
if (!isEnabled(player)) {
return;
}
final IPlayerData pData = DataManager.getPlayerData(player);
final InventoryConfig cc = pData.getGenericInstance(InventoryConfig.class);
final InventoryData data = pData.getGenericInstance(InventoryData.class);
final BookMeta newMeta = event.getNewBookMeta();
final int pages = newMeta.getPageCount();
if (pages <= cc.gutenbergPageLimit) {
// Legitimate.
return;
}
// Violation.
final int vl = pages - cc.gutenbergPageLimit;
data.gutenbergVL += vl;
if (executeActions(player, data.gutenbergVL, vl, cc.gutenbergActions).willCancel()) {
event.setCancelled(true);
}
}
}
@@ -26,7 +26,7 @@ import org.bukkit.event.Listener;
import org.bukkit.event.entity.EntityPortalEnterEvent;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.compat.BridgeMaterial;
import fr.neatmonster.nocheatplus.compat.bukkit.BridgeMaterial;
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion;
import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
@@ -14,6 +14,10 @@
*/
package fr.neatmonster.nocheatplus.compat.bukkit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
@@ -21,11 +25,21 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.compat.SchedulerHelper;
import fr.neatmonster.nocheatplus.utilities.CheckUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
public class BlockCacheBukkit extends BlockCache {
private static final long FOLIA_FALLBACK_LOG_INTERVAL_MS = 10000L;
private static final int FOLIA_FALLBACK_CONSOLE_LOG_MIN_COUNT = 2;
private static final AtomicInteger foliaFallbackCount = new AtomicInteger();
private static final AtomicInteger foliaFallbackResolvedCount = new AtomicInteger();
private static final AtomicLong nextFoliaFallbackLog = new AtomicLong();
protected World world;
/** Temporary use. Use LocUtil.clone before passing on. Call setWorld(null) after use. */
@@ -48,20 +62,99 @@ public class BlockCacheBukkit extends BlockCache {
@Override
public Material fetchTypeId(final int x, final int y, final int z) {
// TODO: consider setting type id and data at once.
return world.getBlockAt(x, y, z).getType();
if (world == null) {
return Material.AIR;
}
if (SchedulerHelper.isOwnedByCurrentRegion(world, x, z)) {
return world.getBlockAt(x, y, z).getType();
}
final Material fallbackType = fetchTypeIdWithLocationFallback(x, y, z);
return fallbackType == null ? Material.AIR : fallbackType;
}
@SuppressWarnings("deprecation")
@Override
public int fetchData(final int x, final int y, final int z) {
// TODO: consider setting type id and data at once.
return Bridge1_13.hasIsSwimming() ? 0 : world.getBlockAt(x, y, z).getData();
if (world == null) {
return 0;
}
if (SchedulerHelper.isOwnedByCurrentRegion(world, x, z)) {
return Bridge1_13.hasIsSwimming() ? 0 : world.getBlockAt(x, y, z).getData();
}
final Integer fallbackData = fetchDataWithLocationFallback(x, y, z);
return fallbackData == null ? 0 : fallbackData.intValue();
}
private Material fetchTypeIdWithLocationFallback(final int x, final int y, final int z) {
// Folia compatibility: if the chunk-level ownership check cannot prove safety, retry the exact location.
// If that also fails, keep AIR as the safe final fallback instead of touching another region's block state.
boolean resolved = false;
try {
if (SchedulerHelper.isOwnedByCurrentRegion(new Location(world, x, y, z))) {
resolved = true;
return world.getBlockAt(x, y, z).getType();
}
}
catch (Throwable t) {
// Keep the final AIR fallback for servers that throw while checking ownership or block state.
}
finally {
logFoliaBlockFallback("type", resolved);
}
return null;
}
@SuppressWarnings("deprecation")
private Integer fetchDataWithLocationFallback(final int x, final int y, final int z) {
// Folia compatibility: retry exact-location ownership before returning legacy data 0 as the final fallback.
boolean resolved = false;
try {
if (SchedulerHelper.isOwnedByCurrentRegion(new Location(world, x, y, z))) {
resolved = true;
return Integer.valueOf(Bridge1_13.hasIsSwimming() ? 0 : world.getBlockAt(x, y, z).getData());
}
}
catch (Throwable t) {
// Keep the final data 0 fallback for servers that throw while checking ownership or block state.
}
finally {
logFoliaBlockFallback("data", resolved);
}
return null;
}
private static void logFoliaBlockFallback(final String kind, final boolean resolved) {
if (!CheckUtils.shouldLogDebugToConsole()) {
return;
}
final int count = foliaFallbackCount.incrementAndGet();
if (resolved) {
foliaFallbackResolvedCount.incrementAndGet();
}
final long now = System.currentTimeMillis();
final long next = nextFoliaFallbackLog.get();
if (now < next || !nextFoliaFallbackLog.compareAndSet(next, now + FOLIA_FALLBACK_LOG_INTERVAL_MS)) {
return;
}
final int resolvedCount = foliaFallbackResolvedCount.getAndSet(0);
final int periodCount = foliaFallbackCount.getAndSet(0);
// Folia diagnostic: a single safe fallback during teleport/chunk handoff is expected and not useful console noise.
if (periodCount < FOLIA_FALLBACK_CONSOLE_LOG_MIN_COUNT) {
return;
}
Bukkit.getLogger().info("[NCP][Folia][BlockCache] safe " + kind + " block fallback used "
+ periodCount + " times in the last 10s, resolved=" + resolvedCount
+ ", finalSafeFallback=" + (periodCount - resolvedCount) + ".");
}
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// minX, minY, minZ, maxX, maxY, maxZ
Material mat = getType(x, y, z);
long flags = BlockFlags.getBlockFlags(mat);
if (flags == BlockFlags.F_IGN_PASSABLE_CHECK) {
return null;
}
// TODO: Want to maintain a list with manual entries or at least half / full blocks ?
// Always return full bounds, needs extra adaption to BlockProperties (!).
return new double[]{0D, 0D, 0D, 1D, 1D, 1D};
@@ -69,21 +162,24 @@ public class BlockCacheBukkit extends BlockCache {
@Override
public boolean standsOnEntity(final Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ){
if (!SchedulerHelper.isOwnedByCurrentRegion(entity)) {
return false;
}
try{
// TODO: Probably check other ids too before doing this ?
for (final Entity other : entity.getNearbyEntities(2.0, 2.0, 2.0)){
if (!SchedulerHelper.isOwnedByCurrentRegion(other)) {
continue;
}
final EntityType type = other.getType();
if (type != EntityType.BOAT && type != EntityType.SHULKER){ // && !(other instanceof Minecart))
continue;
if (!MaterialUtil.isBoat(type) && type != EntityType.SHULKER){ // && !(other instanceof Minecart))
continue;
}
final double locY = entity.getLocation(useLoc).getY();
useLoc.setWorld(null);
if (Math.abs(locY - minY) < 0.7){
// TODO: A "better" estimate is possible, though some more tolerance would be good.
return true;
}
else return false;
}
// TODO: A "better" estimate is possible, though some more tolerance would be good.
return Math.abs(locY - minY) < 0.7;
}
}
catch (Throwable t){
// Ignore exceptions (Context: DisguiseCraft).
@@ -100,4 +196,25 @@ public class BlockCacheBukkit extends BlockCache {
world = null;
}
}
@Override
public double[] fetchVisualBounds(int x, int y, int z) {
Material mat = getType(x, y, z);
long flags = BlockFlags.getBlockFlags(mat);
if (flags == BlockFlags.F_IGN_PASSABLE_CHECK) {
return null;
}
// TODO: Want to maintain a list with manual entries or at least half / full blocks ?
// Always return full bounds, needs extra adaption to BlockProperties (!).
return new double[]{0D, 0D, 0D, 1D, 1D, 1D};
}
@Override
public boolean isCollisionSameVisual(int x, int y, int z) {
return true;
}
@Override
public long fetchExtendedData(int x, int y, int z) {
return 0;
}
}
@@ -16,10 +16,20 @@ package fr.neatmonster.nocheatplus.compat.bukkit;
import java.util.Map;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import fr.neatmonster.nocheatplus.compat.SchedulerHelper;
import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitShapeModel;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
/**
@@ -29,22 +39,21 @@ import fr.neatmonster.nocheatplus.compat.bukkit.model.BukkitShapeModel;
*
*/
public class BlockCacheBukkitModern extends BlockCacheBukkit {
private Map<Material, BukkitShapeModel> shapeModels;
public BlockCacheBukkitModern(Map<Material, BukkitShapeModel> shapeModels) {
super(null);
this.shapeModels = shapeModels;
}
public BlockCacheBukkitModern(World world) {
super(world);
}
@Override
public int fetchData(int x, int y, int z) {
Material mat = getType(x, y, z);
final BukkitShapeModel shapeModel = shapeModels.get(mat);
if (shapeModel != null) {
final int data = shapeModel.getFakeData(this, world, x, y, z);
@@ -55,29 +64,93 @@ public class BlockCacheBukkitModern extends BlockCacheBukkit {
return super.fetchData(x, y, z);
}
@Override
public long fetchExtendedData(final int x, final int y, final int z) {
if (world == null) {
return 0L;
}
// Folia support: only query live Bukkit block data from the owning region thread.
if (SchedulerHelper.isOwnedByCurrentRegion(world, x, z)) {
return fetchWaterloggedFlags(x, y, z);
}
try {
if (SchedulerHelper.isOwnedByCurrentRegion(new Location(world, x, y, z))) {
return fetchWaterloggedFlags(x, y, z);
}
} catch (Throwable ignored) {
// Keep the cache fallback conservative if the scheduler API is unavailable.
}
return 0L;
}
private long fetchWaterloggedFlags(final int x, final int y, final int z) {
final IPlayerData pData = getPlayerData();
if (pData != null && pData.getClientVersion().isLowerThan(ClientVersion.V_1_13)) {
return 0L;
}
final BlockData data = world.getBlockAt(x, y, z).getBlockData();
if (data instanceof Waterlogged && ((Waterlogged) data).isWaterlogged()) {
return BlockFlags.F_WATER | BlockFlags.F_LIQUID | BlockFlags.F_WATERLOGGED;
}
return 0L;
}
@Override
public double[] fetchBounds(int x, int y, int z) {
// minX, minY, minZ, maxX, maxY, maxZ
// TODO: Fetch what's possible to fetch/guess (...).
// TODO: Consider to store the last used block/stuff within BlockCacheBukkit already.
//final Block block = world.getBlockAt(x, y, z);
//final BlockState state = block.getState();
//final MaterialData materialData = state.getData();
//final BlockData blockData = state.getBlockData();
Material mat = getType(x, y, z);
final BukkitShapeModel shapeModel = shapeModels.get(mat);
if (shapeModel == null) {
return super.fetchBounds(x, y, z);
}
else {
return shapeModel.getShape(this, world, x, y, z);
}
return shapeModel.getShape(this, world, x, y, z);
}
// TODO: Might refine standsOnEntity as well.
@Override
public double[] fetchVisualBounds(int x, int y, int z) {
Material mat = getType(x, y, z);
final BukkitShapeModel shapeModel = shapeModels.get(mat);
if (shapeModel == null) {
return super.fetchVisualBounds(x, y, z);
}
return shapeModel.getVisualShape(this, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(int x, int y, int z) {
Material mat = getType(x, y, z);
final BukkitShapeModel shapeModel = shapeModels.get(mat);
if (shapeModel == null) {
return super.isCollisionSameVisual(x, y, z);
}
return shapeModel.isCollisionSameVisual(this, world, x, y, z);
}
@Override
public boolean standsOnEntity(final Entity entity, final double minX, final double minY, final double minZ, final double maxX, final double maxY, final double maxZ) {
if (!SchedulerHelper.isOwnedByCurrentRegion(entity)) {
return false;
}
try {
// TODO: Probably check vehicle ids too before doing this ?
for (final Entity vehicle : entity.getNearbyEntities(0.1, 2.0, 0.1)) {
if (!SchedulerHelper.isOwnedByCurrentRegion(vehicle)) {
continue;
}
final EntityType type = vehicle.getType();
if (!MaterialUtil.isBoat(type) && type != EntityType.SHULKER) { // && !(vehicle instanceof Minecart))
continue;
}
final double vehicleY = vehicle.getLocation(useLoc).getY() + vehicle.getHeight();
final double entityY = entity.getLocation(useLoc).getY();
useLoc.setWorld(null);
// TODO: A "better" estimate is possible, though some more tolerance would be good.
return vehicleY < entityY + 0.1 && Math.abs(vehicleY - entityY) < 0.7;
}
} catch (Throwable t) {
// Ignore exceptions (Context: DisguiseCraft).
}
return false;
}
}
@@ -16,15 +16,27 @@ package fr.neatmonster.nocheatplus.compat.bukkit;
import java.util.UUID;
import org.bukkit.attribute.Attribute;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.attribute.AttributeModifier.Operation;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData;
import fr.neatmonster.nocheatplus.compat.AttribUtil;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
import fr.neatmonster.nocheatplus.compat.registry.BukkitAPIAccessFactory;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion;
import fr.neatmonster.nocheatplus.components.modifier.IAttributeAccess;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
import fr.neatmonster.nocheatplus.utilities.math.MathUtil;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class BukkitAttributeAccess implements IAttributeAccess {
@@ -55,6 +67,7 @@ public class BukkitAttributeAccess implements IAttributeAccess {
* @param id
* @return
*/
@SuppressWarnings({"deprecation", "removal"})
private AttributeModifier getModifier(final AttributeInstance attrInst, final UUID id) {
for (final AttributeModifier mod : attrInst.getModifiers()) {
if (id.equals(mod.getUniqueId())) {
@@ -67,20 +80,208 @@ public class BukkitAttributeAccess implements IAttributeAccess {
private double getMultiplier(final AttributeModifier mod) {
return AttribUtil.getMultiplier(operationToInt(mod.getOperation()), mod.getAmount());
}
@Override
public double getSpeedAttributeMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getSpeedMultiplier(final Player player) {
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getSpeedAttributeInstance(player);
final double val = attrInst.getValue() / attrInst.getBaseValue();
final AttributeModifier mod = getModifier(attrInst, AttribUtil.ID_SPRINT_BOOST);
return mod == null ? val : (val / getMultiplier(mod));
}
@Override
public double getSprintAttributeMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(Attribute.GENERIC_MOVEMENT_SPEED);
public double getSprintMultiplier(final Player player) {
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getSpeedAttributeInstance(player);
final AttributeModifier mod = getModifier(attrInst, AttribUtil.ID_SPRINT_BOOST);
return mod == null ? 1.0 : getMultiplier(mod);
}
@Override
public double getGravity(Player player) {
double gravity;
final PlayerMoveData thisMove = DataManager.getPlayerData(player).getGenericInstance(MovingData.class).playerMoves.getCurrentMove();
if (!BridgeMisc.hasGravity(player)) {
return 0.0;
}
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
gravity = thisMove.yDistance <= 0.0 && !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player)) ? Magic.SLOW_FALL_GRAVITY : Magic.DEFAULT_GRAVITY;
}
else {
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getGravityAttributeInstance(player);
// Fail-safe.
if (attrInst == null) {
gravity = thisMove.yDistance <= 0.0 && !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player)) ? Magic.SLOW_FALL_GRAVITY : Magic.DEFAULT_GRAVITY;
}
else gravity = MathUtil.clamp(attrInst.getValue(), -1.0, 1.0);
if (thisMove.yDistance <= 0.0 && !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player))) {
gravity = Math.min(gravity, Magic.SLOW_FALL_GRAVITY);
}
}
return gravity;
}
@Override
public double getSafeFallDistance(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return Magic.FALL_DAMAGE_DIST;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getSafeFallAttributeInstance(player);
// Fail-safe
if (attrInst == null) return Magic.FALL_DAMAGE_DIST;
return MathUtil.clamp(attrInst.getValue(), -1024.0, 1024.0);
}
@Override
public double getFallDamageMultiplier(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return 1.0;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getFallMultAttributeInstance(player);
// Fail-safe
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 1.0, 100.0);
}
@Override
public double getBreakingSpeedMultiplier(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return 1.0;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getBreakSpeedAttributeInstance(player);
// Fail-safe
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 1.0, 1024.0);
}
@Override
public double getJumpGainMultiplier(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return 1.0;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getJumpPowerAttributeInstance(player);
// Fail-safe
if (attrInst == null) return 1.0;
final double val = attrInst.getValue() / attrInst.getBaseValue();
return MathUtil.clamp(val, 0.0, 76.19047619047619); // MathUtil.clamp(attrInst.getValue(), 0.0, 32.0);
}
@Override
public double getPlayerSneakingFactor(Player player) {
// Not available. 1.21 and above only.
return Magic.SNEAK_MULTIPLIER + BridgeEnchant.getSwiftSneakIncrement(player);
}
@Override
public double getPlayerMaxBlockReach(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return 4.5;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getBlockInteractionRangeAttributeInstance(player);
// Fail-safe
if (attrInst == null) return 4.5;
return MathUtil.clamp(attrInst.getValue(), 0.0, 64.0);
}
@Override
public double getPlayerMaxAttackReach(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Doesn't exist. Calculate manually.
return 3.0;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getEntityInteractionRangeAttributeInstance(player);
// Fail-safe
if (attrInst == null) return 3.0;
return MathUtil.clamp(attrInst.getValue(), 0.0, 64.0);
}
@Override
public double getMaxStepUp(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
// Does not exist, calculate manually.
if (player.isInsideVehicle()) {
if (player.getVehicle() != null && MaterialUtil.isBoat(player.getVehicle().getType())) {
// Boats are unable to step.
return 0.0;
}
// All other vehicles have a step value of 1.0
return 1.0;
}
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getStepHeightAttributeInstance(player);
if (attrInst == null) {
// Fail-safe.
if (player.isInsideVehicle()) {
if (player.getVehicle() != null && MaterialUtil.isBoat(player.getVehicle().getType())) {
return 0.0;
}
return 1.0;
}
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
return MathUtil.clamp(attrInst.getValue(), 0.0, 10.0);
}
@Override
public float getWaterMovementEfficiency(Player player) {
final IPlayerData pData = DataManager.getPlayerData(player);
if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_8)) {
// Doesn't exist.
return 0f;
}
final float depthStrider = BridgeEnchant.getDepthStriderLevel(player);
if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_21)) {
// Use the legacy method.
return depthStrider;
}
if (ServerVersion.isLowerThan("1.21")) {
// Simulate what ViaVersion does for newer (1.21 clients) on older (1.21-) servers.
return depthStrider / 3.0f;
}
// Unsupported. Only since 1.21.
return depthStrider;
}
@Override
public float getMovementEfficiency(Player player) {
// Not available. 1.21 and above only.
return 0.0f;
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
// Not available. 1.21 and above only.
return 1.0;
}
@Override
public double getMiningEfficiency(Player player) {
// Not available. 1.21 and above only.
return 0.0;
}
@Override
public double getEntityScale(Player player) {
if (ServerVersion.isLowerThan("1.20.5")) {
return 1.0;
}
final AttributeInstance attrInst = BukkitAPIAccessFactory.getBukkitAccess().getScaleAttributeInstance(player);
// Fail-safe.
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 0.0625, 16.0);
}
}
@@ -25,7 +25,6 @@ import fr.neatmonster.nocheatplus.config.WorldConfigProvider;
import fr.neatmonster.nocheatplus.logging.StaticLog;
import fr.neatmonster.nocheatplus.utilities.StringUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
public class MCAccessBukkit extends MCAccessBukkitBase implements BlockPropertiesSetup {
@@ -42,10 +41,10 @@ public class MCAccessBukkit extends MCAccessBukkitBase implements BlockPropertie
}
else if (guessItchyBlock(mat)) {
// Uncertain bounding-box, allow passing through.
long flags = BlockProperties.F_IGN_PASSABLE;
long flags = BlockFlags.F_IGN_PASSABLE_CHECK;
if ((BlockFlags.hasAnyFlag(flags, BlockFlags.SOLID_GROUND))) {
// Block can be ground, so allow standing on any height.
flags |= BlockProperties.F_GROUND | BlockProperties.F_GROUND_HEIGHT;
flags |= BlockFlags.F_GROUND | BlockFlags.F_GROUND_HEIGHT;
}
/*
* TODO: Might have to set all blocks to ground here, rather
@@ -32,10 +32,10 @@ import org.bukkit.entity.Slime;
import org.bukkit.potion.PotionEffectType;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.compat.MCAccess;
import fr.neatmonster.nocheatplus.utilities.PotionUtil;
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.entity.PotionUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
@@ -75,17 +75,17 @@ public class MCAccessBukkitBase implements MCAccess {
return false;
}
// Fully solid/ground blocks.
final long flags = BlockProperties.getBlockFlags(mat);
final long flags = BlockFlags.getBlockFlags(mat);
/*
* Skip fully passable blocks (partially passable blocks may be itchy,
* though slabs will be easy to handle).
*/
if (BlockFlags.hasAnyFlag(flags, BlockProperties.F_IGN_PASSABLE)) {
if (BlockFlags.hasAnyFlag(flags, BlockFlags.F_IGN_PASSABLE_CHECK)) {
// TODO: Blocks with min_height may actually be ok, if xz100 and some height are set.
if (BlockFlags.hasNoFlags(flags,
BlockProperties.F_GROUND_HEIGHT
| BlockProperties.F_GROUND
| BlockProperties.F_SOLID)) {
BlockFlags.F_GROUND_HEIGHT
| BlockFlags.F_GROUND
| BlockFlags.F_SOLID)) {
// Explicitly passable.
return false;
}
@@ -94,11 +94,10 @@ public class MCAccessBukkitBase implements MCAccess {
return true;
}
}
long testFlags1 = (BlockProperties.F_SOLID | BlockProperties.F_XZ100);
long testFlags2 = (BlockProperties.F_HEIGHT100
| BlockProperties.F_HEIGHT16_15);
if (BlockFlags.hasAllFlags(flags, testFlags1)
&& BlockFlags.hasAnyFlag(flags, testFlags2)) {
long testFlags1 = (BlockFlags.F_SOLID | BlockFlags.F_XZ100);
long testFlags2 = (BlockFlags.F_HEIGHT100);
if (BlockFlags.hasAllFlags(flags, testFlags1) && BlockFlags.hasAnyFlag(flags, testFlags2)) {
// Solid blocks with explicitly set bounds.
return false;
}
@@ -114,9 +113,9 @@ public class MCAccessBukkitBase implements MCAccess {
@Override
public String getMCVersion() {
// Bukkit API.
// Bukkit API. Versions lower than MC 1.13 have their own module.
// TODO: maybe output something else.
return "1.4.6-1.15.2|?"; // uh oh
return "1.13-1.20"; // uh oh
}
@Override
@@ -175,12 +174,16 @@ public class MCAccessBukkitBase implements MCAccess {
// TODO: For height too. [Automatize most by spawning + checking?]
// Values taken from 1.7.10.
final EntityType type = entity.getType();
Double width = BridgeEntityType.LEGACY_ENTITY_WIDTH.get(type);
if (width != null) {
return width;
}
switch(type){
// TODO: case COMPLEX_PART:
case ENDER_SIGNAL: // this.a(0.25F, 0.25F);
case FIREWORK: // this.a(0.25F, 0.25F);
case FISHING_HOOK: // this.a(0.25F, 0.25F);
case DROPPED_ITEM: // this.a(0.25F, 0.25F);
//case ENDER_SIGNAL: // this.a(0.25F, 0.25F);
//case FIREWORK: // this.a(0.25F, 0.25F);
//case FISHING_HOOK: // this.a(0.25F, 0.25F);
//case DROPPED_ITEM: // this.a(0.25F, 0.25F);
case SNOWBALL: // (projectile) this.a(0.25F, 0.25F);
return 0.25;
case CHICKEN: // this.a(0.3F, 0.7F);
@@ -190,7 +193,7 @@ public class MCAccessBukkitBase implements MCAccess {
case WITHER_SKULL: // this.a(0.3125F, 0.3125F);
return 0.3125f;
case GHAST: // this.a(4.0F, 4.0F);
case SNOWMAN: // this.a(0.4F, 1.8F);
//case SNOWMAN: // this.a(0.4F, 1.8F);
return 0.4f;
case ARROW: // this.a(0.5F, 0.5F);
case BAT: // this.a(0.5F, 0.9F);
@@ -212,24 +215,24 @@ public class MCAccessBukkitBase implements MCAccess {
case CAVE_SPIDER: // this.a(0.7F, 0.5F);
return 0.7f;
case COW: // this.a(0.9F, 1.3F);
case MUSHROOM_COW: // this.a(0.9F, 1.3F);
//case MUSHROOM_COW: // this.a(0.9F, 1.3F);
case PIG: // this.a(0.9F, 0.9F);
case SHEEP: // this.a(0.9F, 1.3F);
case WITHER: // this.a(0.9F, 4.0F);
return 0.9f;
case SQUID: // this.a(0.95F, 0.95F);
return 0.95f;
case PRIMED_TNT: // this.a(0.98F, 0.98F);
return 0.98f;
//case PRIMED_TNT: // this.a(0.98F, 0.98F);
// return 0.98f;
case FIREBALL: // (EntityFireball) this.a(1.0F, 1.0F);
return 1.0f;
case IRON_GOLEM: // this.a(1.4F, 2.9F);
case SPIDER: // this.a(1.4F, 0.9F);
return 1.4f;
case BOAT: // this.a(1.5F, 0.6F);
return 1.5f;
case ENDER_CRYSTAL: // this.a(2.0F, 2.0F);
return 2.0f;
// case BOAT: // this.a(1.5F, 0.6F);
// return 1.5f;
//case ENDER_CRYSTAL: // this.a(2.0F, 2.0F);
// return 2.0f;
case GIANT: // this.height *= 6.0F; this.a(this.width * 6.0F, this.length * 6.0F);
return 3.6f; // (Better than nothing.)
case ENDER_DRAGON: // this.a(16.0F, 8.0F);
@@ -244,6 +247,9 @@ public class MCAccessBukkitBase implements MCAccess {
default:
break;
}
if (MaterialUtil.isBoat(entity.getType())) {
return ServerVersion.isHigherThan("1.8") ? 1.3964844f : 1.4f;
}
// Check by instance for minecarts (too many).
if (entity instanceof Minecart) {
return 0.98f; // this.a(0.98F, 0.7F);
@@ -251,8 +257,8 @@ public class MCAccessBukkitBase implements MCAccess {
// Latest Bukkit API.
try {
switch (type) {
case LEASH_HITCH: // hanging: this.a(0.5F, 0.5F);
return 0.5f;
//case LEASH_HITCH: // hanging: this.a(0.5F, 0.5F);
// return 0.5f;
case HORSE: // this.a(1.4F, 1.6F);
return 1.4f;
// 1.8
@@ -309,7 +315,7 @@ public class MCAccessBukkitBase implements MCAccess {
@Override
public double getJumpAmplifier(final Player player) {
return PotionUtil.getPotionEffectAmplifier(player, PotionEffectType.JUMP);
return PotionUtil.getPotionEffectAmplifier(player, BridgePotionEffect.JUMP_BOOST);
}
@Override
@@ -21,130 +21,116 @@ import org.bukkit.Material;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.BridgeHealth;
import fr.neatmonster.nocheatplus.compat.BridgeMaterial;
import fr.neatmonster.nocheatplus.compat.blocks.init.BlockInit;
import fr.neatmonster.nocheatplus.compat.bukkit.model.*;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectBase;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectDamageSource;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectDamageSources;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectLivingEntity;
import fr.neatmonster.nocheatplus.config.WorldConfigProvider;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
import fr.neatmonster.nocheatplus.utilities.map.BlockProperties;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
public class MCAccessBukkitModern extends MCAccessBukkit {
protected ReflectBase reflectBase = null;
protected ReflectDamageSource reflectDamageSource = null;
protected ReflectDamageSources reflectDamageSources = null;
protected ReflectLivingEntity reflectLivingEntity = null;
protected final Map<Material, BukkitShapeModel> shapeModels = new HashMap<Material, BukkitShapeModel>();
// Blocks that can automatic fetch bounding box from API
private static final BukkitShapeModel MODEL_AUTO_FETCH = new BukkitFetchableBound();
// Blocks that can be fetched automatically from the Bukkit API
private static final BukkitShapeModel MODEL_AUTO_FETCH = new BukkitFetchableBounds();
private static final BukkitShapeModel MODEL_AUTO_FETCH_LEGACY = new BukkitFetchableBound();
// Blocks that form from multi-bounds
// Blocks that are formed from multiple bounding boxes
private static final BukkitShapeModel MODEL_BREWING_STAND = new BukkitStatic(
// Bottom rod
0.0625, 0.0, 0.0625, 0.9375, 0.125, 0.9375,
// Rod
0.4375, 0.125, 0.4375, 0.5625, 0.8749, 0.5625);
// Bottom rod
0.0625, 0.0, 0.0625, 0.9375, 0.125, 0.9375,
// Rod
0.4375, 0.125, 0.4375, 0.5625, 0.875, 0.5625
);
private static final BukkitShapeModel MODEL_CANDLE_CAKE = new BukkitStatic(
// Cake
0.0625, 0.0, 0.0625, 0.9375, 0.5, 0.9375,
// Candle
0.4375, 0.5, 0.4375, 0.5625, 0.875, 0.5625);
// Cake
0.0625, 0.0, 0.0625, 0.9375, 0.5, 0.9375,
// Candle
0.4375, 0.5, 0.4375, 0.5625, 0.875, 0.5625
);
private static final BukkitShapeModel MODEL_LECTERN = new BukkitStatic(
0.0, 0.0, 0.0, 1.0, 0.125, 1.0,
0.25, 0.125, 0.25, 0.75, 0.875, 0.75);
// Post
0.0, 0.0, 0.0, 1.0, 0.125, 1.0,
// Lectern
0.25, 0.125, 0.25, 0.75, 0.875, 0.75
);
private static final BukkitShapeModel MODEL_HOPPER = new BukkitHopper();
private static final BukkitShapeModel MODEL_CAULDRON = new BukkitCauldron(0.1875, 0.125, 0.8125, 0.0625);
private static final BukkitShapeModel MODEL_COMPOSTER = new BukkitCauldron(0.0, 0.125, 1.0, 0.125);
private static final BukkitShapeModel MODEL_CAULDRON = new BukkitCauldron();
private static final BukkitShapeModel MODEL_COMPOSTER = new BukkitComposter(0.0, 0.125, 1.0, 0.125);
private static final BukkitShapeModel MODEL_PISTON_HEAD = new BukkitPistonHead();
private static final BukkitShapeModel MODEL_BELL = new BukkitBell();
private static final BukkitShapeModel MODEL_ANVIL = new BukkitAnvil();
private static final BukkitShapeModel MODEL_GRIND_STONE = new BukkitGrindStone();
// Blocks that change shape based on interaction or redstone.
private static final BukkitShapeModel MODEL_DOOR = new BukkitDoor();
private static final BukkitShapeModel MODEL_TRAP_DOOR = new BukkitTrapDoor();
private static final BukkitShapeModel MODEL_GATE = new BukkitGate(
0.375, 1.5);
private static final BukkitShapeModel MODEL_GATE = new BukkitGate(0.375, 1.5);
private static final BukkitShapeModel MODEL_SHULKER_BOX = new BukkitShulkerBox();
private static final BukkitShapeModel MODEL_CHORUS_PLANT = new BukkitChorusPlant();
private static final BukkitShapeModel MODEL_DRIP_LEAF = new BukkitDripLeaf();
// Blocks with different heights based on whatever.
private static final BukkitShapeModel MODEL_END_PORTAL_FRAME = new BukkitEndPortalFrame();
private static final BukkitShapeModel MODEL_SEA_PICKLE = new BukkitSeaPickle();
private static final BukkitShapeModel MODEL_COCOA = new BukkitCocoa();
private static final BukkitShapeModel MODEL_TURTLE_EGG = new BukkitTurtleEgg();
private static final BukkitShapeModel MODEL_POWDER_SNOW = new BukkitPowderSnow();
// Blocks that have a different shape, based on how they have been placed.
private static final BukkitShapeModel MODEL_CAKE = new BukkitCake();
private static final BukkitShapeModel MODEL_SLAB = new BukkitSlab();
private static final BukkitShapeModel MODEL_STAIRS = new BukkitStairs();
private static final BukkitShapeModel MODEL_SNOW = new BukkitSnow();
private static final BukkitShapeModel MODEL_PISTON = new BukkitPiston();
private static final BukkitShapeModel MODEL_LEVELLED = new BukkitLevelled();
private static final BukkitShapeModel MODEL_LADDER = new BukkitLadder();
private static final BukkitShapeModel MODEL_RAIL = new BukkitRail();
private static final BukkitShapeModel MODEL_END_ROD = new BukkitDirectionalCentered(
0.375, 1.0, false);
private static final BukkitShapeModel MODEL_END_ROD = new BukkitDirectionalCentered(0.375, 1.0, false);
// Blocks that have a different shape with neighbor blocks (bukkit takes care though).
private static final BukkitShapeModel MODEL_THIN_FENCE = new BukkitFence(
0.4375, 1.0);
private static final BukkitShapeModel MODEL_THICK_FENCE = new BukkitFence(
0.375, 1.5);
private static final BukkitShapeModel MODEL_THICK_FENCE2 = new BukkitWall(
0.25, 1.5, 0.3125);
// .75 .25 0 max: .25 .75 .5
private static final BukkitShapeModel MODEL_THIN_FENCE = new BukkitFence(0.4375, 1.0, true);
private static final BukkitShapeModel MODEL_THICK_FENCE = new BukkitFence(0.375, 1.5, false);
private static final BukkitShapeModel MODEL_THICK_FENCE2 = new BukkitWall(0.25, 1.5, 0.3125); // .75 .25 0 max: .25 .75 .5
private static final BukkitShapeModel MODEL_WALL_HEAD = new BukkitWallHead();
// Static blocks (various height and inset values).
private static final BukkitShapeModel MODEL_CAMPFIRE = new BukkitStatic(0.0, 0.4375);
private static final BukkitShapeModel MODEL_BAMBOO = new BukkitBamboo();
private static final BukkitShapeModel MODEL_LILY_PAD = new BukkitStatic(
0.09375);
private static final BukkitShapeModel MODEL_FLOWER_POT = new BukkitStatic(
0.33, 0.375); // TODO: XZ really?
private static final BukkitShapeModel MODEL_POINTED_DRIPSTONE = new BukkitDripStone();
private static final BukkitShapeModel MODEL_SCAFFOLDING = new BukkitScaffolding();
private static final BukkitShapeModel MODEL_WATER_PLANTS = new BukkitWaterPlant();
private static final BukkitShapeModel MODEL_LILY_PAD = new BukkitLilyPad();
private static final BukkitShapeModel MODEL_FLOWER_POT = new BukkitStatic(0.3125, 0.375);
private static final BukkitShapeModel MODEL_LANTERN = new BukkitLantern();
private static final BukkitShapeModel MODEL_CONDUIT = new BukkitStatic(
0.33, 0.6875);
private static final BukkitShapeModel MODEL_GROUND_HEAD= new BukkitStatic(
0.25, 0.5); // TODO: XZ-really? 275 ?
private static final BukkitShapeModel MODEL_SINGLE_CHEST = new BukkitStatic(
0.0625, 0.875);
private static final BukkitShapeModel MODEL_HONEY_BLOCK = new BukkitStatic(
0.0625, 0.9375);
private static final BukkitShapeModel MODEL_CONDUIT = new BukkitStatic(0.3125, 0.3125, 0.3125, 0.6875, 0.6875, 0.6875);
private static final BukkitShapeModel MODEL_GROUND_HEAD = new BukkitStatic(0.25, 0.5);
private static final BukkitShapeModel MODEL_CHEST = new BukkitChest();
private static final BukkitShapeModel MODEL_HONEY_BLOCK = new BukkitStatic(0.0625, 0.9375);
private static final BukkitShapeModel MODEL_SCULK_SHRIEKER = new BukkitStatic(0.0, 0.5);
private static final BukkitShapeModel MODEL_DRIED_GHAST = new BukkitStatic(0.1875f, 0.0f, 0.1875f, 0.8125f, 0.625f, 0.8125f); // NMS bounds: x1,y1,z1,x2,y2,y2 (y2 = 10/16 = 0.625)
// Static blocks with full height sorted by inset.
private static final BukkitShapeModel MODEL_INSET16_1_HEIGHT100 = new BukkitStatic(
0.0625, 1.0);
private static final BukkitShapeModel MODEL_INSET16_1_HEIGHT100 = new BukkitStatic(0.0625, 1.0);
// Static blocks with full xz-bounds sorted by height.
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_1 = new BukkitStatic(
0.0625);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_1 = new BukkitStatic(
0.125);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_3 = new BukkitStatic(
0.375);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_9 = new BukkitStatic(
0.5625);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT4_3 = new BukkitStatic(
0.75);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_15 = new BukkitStatic(
0.9375);
/*
* TODO:
* CONDUIT
*/
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_1 = new BukkitStatic(0.0625);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_1 = new BukkitStatic(0.125);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_3 = new BukkitStatic(0.375);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_9 = new BukkitStatic(0.5625);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT4_3 = new BukkitStatic(0.75);
private static final BukkitShapeModel MODEL_XZ100_HEIGHT16_15 = new BukkitDirtLike();
private static final BukkitShapeModel MODEL_XZ100_HEIGHT8_7 = new BukkitStatic(0.875);
public MCAccessBukkitModern() {
super();
@@ -155,14 +141,15 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
this.reflectBase = new ReflectBase();
this.reflectDamageSource = new ReflectDamageSource(this.reflectBase);
this.reflectLivingEntity = new ReflectLivingEntity(this.reflectBase, null, this.reflectDamageSource);
} catch(ClassNotFoundException ex) {
}
// Can be null
this.reflectDamageSources = new ReflectDamageSources(this.reflectBase, this.reflectDamageSource);
}
catch (ClassNotFoundException ex) {}
}
@Override
public String getMCVersion() {
return "1.13-1.17|?";
return "1.13-26";
}
@Override
@@ -177,33 +164,53 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
@Override
public void setupBlockProperties(final WorldConfigProvider<?> worldConfigProvider) {
/*
* TODO: Incomplete blocks bounds still use workarounds(not affect movement):
* All fences, glass pane, iron bar, chorus plant, hopper
*
* Legacy blocks still use workarounds(not affect movement):
* All fences, glass pane, iron bar, chorus plant, hopper, cauldron
*
* Scaffolding(affect fall dmg)
*
*/
// TODO: Also consider removing flags (passable_x4 etc).
// Variables for repeated flags (Temporary flags, these should be fixed later so that they are not added here)
final long blockFix = BlockFlags.SOLID_GROUND;
// Adjust flags for individual blocks.
BlockProperties.setBlockFlags(Material.COCOA, blockFix);
BlockProperties.setBlockFlags(Material.TURTLE_EGG, blockFix);
BlockProperties.setBlockFlags(Material.CHORUS_PLANT, blockFix);
BlockProperties.setBlockFlags(Material.CREEPER_WALL_HEAD, blockFix);
BlockProperties.setBlockFlags(Material.ZOMBIE_WALL_HEAD, blockFix);
BlockProperties.setBlockFlags(Material.PLAYER_WALL_HEAD, blockFix);
BlockProperties.setBlockFlags(Material.DRAGON_WALL_HEAD, blockFix);
BlockProperties.setBlockFlags(Material.WITHER_SKELETON_WALL_SKULL, blockFix);
BlockProperties.setBlockFlags(Material.SKELETON_WALL_SKULL, blockFix);
// Variables for repeated flags (Temporary flags, these should be fixed later so that they are not added here)
final long blockFix = BlockFlags.SOLID_GROUND;
// Adjust flags for individual blocks.
BlockFlags.setBlockFlags(Material.COCOA, blockFix);
BlockFlags.setBlockFlags(Material.TURTLE_EGG, blockFix);
BlockFlags.setBlockFlags(Material.CHORUS_PLANT, blockFix);
BlockFlags.setBlockFlags(Material.CREEPER_WALL_HEAD, blockFix);
BlockFlags.setBlockFlags(Material.ZOMBIE_WALL_HEAD, blockFix);
BlockFlags.setBlockFlags(Material.PLAYER_WALL_HEAD, blockFix);
BlockFlags.setBlockFlags(Material.DRAGON_WALL_HEAD, blockFix);
BlockFlags.setBlockFlags(Material.WITHER_SKELETON_WALL_SKULL, blockFix);
BlockFlags.setBlockFlags(Material.SKELETON_WALL_SKULL, blockFix);
// Directly keep blocks as is.
for (final Material mat : new Material[] {
BridgeMaterial.COBWEB,
BridgeMaterial.MOVING_PISTON,
Material.SNOW,
Material.BEACON,
Material.VINE,
Material.CHORUS_FLOWER
}) {
BridgeMaterial.COBWEB,
BridgeMaterial.MOVING_PISTON,
Material.SNOW,
Material.BEACON,
Material.VINE,
Material.CHORUS_FLOWER}) {
processedBlocks.add(mat);
}
for (final Material mat : BridgeMaterial.getAllBlocks(
"light", "glow_lichen", "big_dripleaf_stem")) {
processedBlocks.add(mat);
}
// Shelf mushrooms
for (final Material mat : BridgeMaterial.getAllBlocks("shelf_mushroom")) {
addModel(mat, MODEL_AUTO_FETCH);
}
for (Material mat : MaterialUtil.STRAW_BEDS) {
addModel(mat, MODEL_AUTO_FETCH);
}
// Candle
for (Material mat : MaterialUtil.ALL_CANDLES) {
@@ -214,36 +221,71 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
for (Material mat : MaterialUtil.AMETHYST) {
addModel(mat, MODEL_AUTO_FETCH);
}
// Shelves
for (Material mat : MaterialUtil.WOODEN_SHELVES) {
addModel(mat, MODEL_AUTO_FETCH);
}
// new flower, and others
for (Material mat : BridgeMaterial.getAllBlocks(
"azalea", "flowering_azalea",
"big_dripleaf", "sculk_sensor", "pointed_dripstone",
"stonecutter", "chain"
)) {
"azalea", "flowering_azalea",
"sculk_sensor", "frogspawn",
"sniffer_egg", "decorated_pot", "pitcher_crop", "calibrated_sculk_sensor",
"closed_eyeblossom", "open_eyeblossom", "pale_hanging_moss", "resin_clump","cactus_flower",
"short_dry_grass", "tall_dry_grass", "golden_dandelion")) {
addModel(mat, MODEL_AUTO_FETCH);
}
for (final Material mat : BridgeMaterial.getAllBlocks("pale_moss_carpet")) {
addModel(mat, MODEL_AUTO_FETCH);
}
// *WALL* hanging signs have a collision box. Simple hanging signs don't, so they are treated as an ordinary sign.
for (Material mat : MaterialUtil.WALL_HANGING_SIGNS) {
// Only the post has an actual collision box, the rest is all hit box.
addModel(mat, MODEL_AUTO_FETCH);
}
// Stonecutter and legacy chains
for (Material mat : BridgeMaterial.getAllBlocks(
"stonecutter", "chain")) {
addModel(mat, MODEL_AUTO_FETCH_LEGACY);
}
// Modern iron chains
if (BridgeMaterial.IRON_CHAIN != null) {
addModel(BridgeMaterial.IRON_CHAIN, MODEL_AUTO_FETCH);
}
// Copper chains
for (Material mat : MaterialUtil.COPPER_CHAINS) {
addModel(mat, MODEL_AUTO_FETCH_LEGACY);
}
// Copper golem statues.
for (Material mat : MaterialUtil.COPPER_GOLEM_STATUES) {
addModel(mat, MODEL_AUTO_FETCH);
}
// Camp fire
for (Material mat : BridgeMaterial.getAllBlocks(
"campfire", "soul_campfire"
)) {
"campfire", "soul_campfire")) {
addModel(mat, MODEL_CAMPFIRE);
}
// Cauldron
for (Material mat : MaterialUtil.CAULDRON) {
BlockProperties.setBlockFlags(mat, BlockFlags.SOLID_GROUND);
BlockFlags.setBlockFlags(mat, BlockFlags.SOLID_GROUND);
addModel(mat, MODEL_CAULDRON);
}
//Anvil
for (Material mat : new Material[] {
Material.ANVIL,
Material.CHIPPED_ANVIL,
Material.DAMAGED_ANVIL
}) {
addModel(mat, MODEL_ANVIL);
Material.ANVIL,
Material.CHIPPED_ANVIL,
Material.DAMAGED_ANVIL}) {
addModel(mat, MODEL_ANVIL);
}
// Lily pad
@@ -256,6 +298,7 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
addModel(BridgeMaterial.CAKE, MODEL_CAKE);
// End Rod / Lightning Rod.
// Do they actually have the same model? Doesn't the lightning rod have a slightly different box/bulb at the top? <- No, purely visual.
for (Material mat : MaterialUtil.RODS) {
addModel(mat, MODEL_END_ROD);
}
@@ -266,57 +309,57 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
// Ladder
addModel(Material.LADDER, MODEL_LADDER);
// 1/16 inset at full height.
for (Material mat : new Material[] {
Material.CACTUS,
Material.DRAGON_EGG
}) {
addModel(mat, MODEL_INSET16_1_HEIGHT100);
}
// BrewingStand
addModel(Material.BREWING_STAND, MODEL_BREWING_STAND);
// 1/8 height.
// 1/16 inset at full height blocks.
addModel(Material.DRAGON_EGG, MODEL_INSET16_1_HEIGHT100);
addModel(Material.CACTUS, MODEL_HONEY_BLOCK);
// 1/8 height blocks.
for (Material mat : new Material[] {
BridgeMaterial.REPEATER,
Material.COMPARATOR
}) {
BridgeMaterial.REPEATER,
Material.COMPARATOR }) {
addModel(mat, MODEL_XZ100_HEIGHT8_1);
}
// 3/8 height.
// 3/8 height blocks.
for (Material mat : new Material[] {
Material.DAYLIGHT_DETECTOR
}) {
Material.DAYLIGHT_DETECTOR}) {
addModel(mat, MODEL_XZ100_HEIGHT8_3);
}
// 3/4 height.
// 3/4 height blocks.
for (Material mat : new Material[] {
BridgeMaterial.ENCHANTING_TABLE
}) {
BridgeMaterial.ENCHANTING_TABLE}) {
addModel(mat, MODEL_XZ100_HEIGHT4_3);
}
// All candle cakes
for (Material mat : MaterialUtil.ALL_CANDLE_CAKE) {
addModel(mat, MODEL_CANDLE_CAKE);
}
// 7/8 height.
for (Material mat : new Material[] {
Material.BREWING_STAND
}) {
addModel(mat, MODEL_BREWING_STAND);
Material.SOUL_SAND}) {
addModel(mat, MODEL_XZ100_HEIGHT8_7);
}
// 16/15 height, full xz bounds.
for (Material mat : new Material[] {
BridgeMaterial.GRASS_PATH, BridgeMaterial.FARMLAND
}) {
BridgeMaterial.GRASS_PATH,
BridgeMaterial.FARMLAND}) {
addModel(mat, MODEL_XZ100_HEIGHT16_15);
}
// Thin fence: Glass panes, iron bars.
// Thin fence: Glass panes, iron bars, copper bars.
for (final Material mat : MaterialUtil.addBlocks(
MaterialUtil.GLASS_PANES, BridgeMaterial.IRON_BARS)) {
MaterialUtil.GLASS_PANES,
BridgeMaterial.IRON_BARS)) {
addModel(mat, MODEL_THIN_FENCE);
}
for (final Material mat : MaterialUtil.COPPER_BARS) {
addModel(mat, MODEL_THIN_FENCE);
}
@@ -331,12 +374,12 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
}
// Chests.
// TOOD: Might add a facing/directional extension for double chests.
for (Material mat : BridgeMaterial.getAllBlocks(
"chest", "trapped_chest",
"ender_chest"
)) {
addModel(mat, MODEL_SINGLE_CHEST);
"chest", "trapped_chest", "ender_chest")) {
addModel(mat, MODEL_CHEST);
}
for (Material mat : MaterialUtil.COPPER_CHESTS) {
addModel(mat, MODEL_CHEST);
}
// Beds
@@ -351,30 +394,26 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
// Turtle Eggs.
for (Material mat : new Material[] {
Material.TURTLE_EGG
}) {
addModel(mat, MODEL_TURTLE_EGG);
Material.TURTLE_EGG}) {
addModel(mat, MODEL_TURTLE_EGG);
}
// Conduit
for (Material mat : new Material[] {
Material.CONDUIT
}) {
addModel(mat, MODEL_CONDUIT);
Material.CONDUIT}) {
addModel(mat, MODEL_CONDUIT);
}
// Cocoa
for (Material mat : new Material[] {
Material.COCOA
}) {
addModel(mat, MODEL_COCOA);
Material.COCOA}) {
addModel(mat, MODEL_COCOA);
}
// Sea Pickles
for (Material mat : new Material[] {
Material.SEA_PICKLE
}) {
addModel(mat, MODEL_SEA_PICKLE);
Material.SEA_PICKLE}) {
addModel(mat, MODEL_SEA_PICKLE);
}
// Carpets.
@@ -386,8 +425,10 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
for (final Material mat : MaterialUtil.HEADS_GROUND) {
addModel(mat, MODEL_GROUND_HEAD);
}
// Heads on walls.
for (final Material mat : MaterialUtil.HEADS_WALL) {
addModel(mat, MODEL_WALL_HEAD);
addModel(mat, MODEL_WALL_HEAD);
}
// Doors.
@@ -402,84 +443,131 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
// Chorus Plant.
for (Material mat : new Material[] {
Material.CHORUS_PLANT
}) {
addModel(mat, MODEL_CHORUS_PLANT);
Material.CHORUS_PLANT}) {
addModel(mat, MODEL_CHORUS_PLANT);
}
//Lantern
// Lantern.
for (Material mat : BridgeMaterial.getAllBlocks(
"lantern", "soul_lantern"
)) {
"lantern", "soul_lantern")) {
addModel(mat, MODEL_LANTERN);
}
for (Material mat : MaterialUtil.COPPER_LANTERNS) {
addModel(mat, MODEL_LANTERN);
}
// Piston
// Piston.
for (Material mat : BridgeMaterial.getAllBlocks(
"piston", "sticky_piston", "piston_base", "piston_sticky_base"
)) {
"piston", "sticky_piston", "piston_base", "piston_sticky_base")) {
addModel(mat, MODEL_PISTON);
}
// Piston Head
// Piston Head.
addModel(BridgeMaterial.PISTON_HEAD, MODEL_PISTON_HEAD);
// Levelled blocks
for (Material mat : BridgeMaterial.getAllBlocks(
"snow", "water", "lava"
)) {
// Snow.
addModel(Material.SNOW, MODEL_SNOW);
// Levelled blocks.
for (Material mat : MaterialUtil.WATER) {
addModel(mat, MODEL_LEVELLED);
}
for (Material mat : MaterialUtil.LAVA) {
addModel(mat, MODEL_LEVELLED);
}
// All water plants
for (Material mat : MaterialUtil.WATER_PLANTS) {
addModel(mat, MODEL_WATER_PLANTS);
}
// Rails
// Rails.
for (final Material mat : MaterialUtil.RAILS) {
addModel(mat, MODEL_RAIL);
}
// Walls
// Walls.
for (Material mat : MaterialUtil.ALL_WALLS) {
BlockFlags.setBlockFlags(mat, BlockFlags.SOLID_GROUND | BlockFlags.F_VARIABLE);
addModel(mat, MODEL_THICK_FENCE2);
}
// Lectern
// Lectern.
Material mt = BridgeMaterial.getBlock("lectern");
if (mt != null) addModel(mt, MODEL_LECTERN);
// Bamboo
// PowderSnow.
mt = BridgeMaterial.getBlock("powder_snow");
if (mt != null) addModel(mt, MODEL_POWDER_SNOW);
// Bamboo.
mt = BridgeMaterial.getBlock("bamboo");
if (mt != null) addModel(mt, MODEL_BAMBOO);
// Bell
// Scaffolding
mt = BridgeMaterial.getBlock("scaffolding");
if (mt != null) addModel(mt, MODEL_SCAFFOLDING);
// Dripstone.
mt = BridgeMaterial.getBlock("pointed_dripstone");
if (mt != null) addModel(mt, MODEL_POINTED_DRIPSTONE);
// Sulfur spike
mt = BridgeMaterial.getBlock("sulfur_spike");
if (mt != null) addModel(mt, MODEL_POINTED_DRIPSTONE);
// Bell.
mt = BridgeMaterial.getBlock("bell");
if (mt != null) addModel(mt, MODEL_BELL);
// Composter
// Composter.
mt = BridgeMaterial.getBlock("composter");
if (mt != null) addModel(mt, MODEL_COMPOSTER);
// Honey Block
// Honey Block.
mt = BridgeMaterial.getBlock("honey_block");
if (mt != null) addModel(mt, MODEL_HONEY_BLOCK);
// Big DripLeaf.
mt = BridgeMaterial.getBlock("big_dripleaf");
if (mt != null) addModel(mt, MODEL_DRIP_LEAF);
// Grindstone.
mt = BridgeMaterial.getBlock("grindstone");
if (mt != null) addModel(mt, MODEL_GRIND_STONE);
// Sculk Shrieker
mt = BridgeMaterial.getBlock("sculk_shrieker");
if (mt != null) addModel(mt, MODEL_SCULK_SHRIEKER);
// Mud
mt = BridgeMaterial.getBlock("mud");
if (mt != null) addModel(mt, MODEL_XZ100_HEIGHT8_7);
// Heavy core
mt = BridgeMaterial.getBlock("heavy_core");
if (mt != null) addModel(mt, MODEL_GROUND_HEAD);
// Dried ghast
mt = BridgeMaterial.getBlock("dried_ghast");
if (mt != null) addModel(mt, MODEL_DRIED_GHAST);
// Sort to processed by flags.
for (final Material mat : Material.values()) {
final long flags = BlockProperties.getBlockFlags(mat);
final long flags = BlockFlags.getBlockFlags(mat);
// Stairs.
if (BlockFlags.hasAnyFlag(flags, BlockProperties.F_STAIRS)) {
if (BlockFlags.hasAnyFlag(flags, BlockFlags.F_STAIRS)) {
addModel(mat, MODEL_STAIRS);
}
// Fences.
if (BlockFlags.hasAnyFlag(flags, BlockProperties.F_THICK_FENCE)) {
if (BlockFlags.hasAnyFlag(flags, BlockProperties.F_PASSABLE_X4)) {
if (BlockFlags.hasAnyFlag(flags, BlockFlags.F_THICK_FENCE)) {
if (BlockFlags.hasAnyFlag(flags, BlockFlags.F_PASSABLE_X4)) {
// TODO: Perhaps another model flag.
addModel(mat, MODEL_GATE);
}
else {
addModel(mat, MODEL_THICK_FENCE);
}
else addModel(mat, MODEL_THICK_FENCE);
}
}
super.setupBlockProperties(worldConfigProvider);
}
@@ -488,12 +576,12 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
if (this.reflectLivingEntity == null || this.reflectLivingEntity.obcGetHandle == null) {
return null;
}
Object handle = ReflectionUtil.invokeMethodNoArgs(this.reflectLivingEntity.obcGetHandle, player);
return handle;
return ReflectionUtil.invokeMethodNoArgs(this.reflectLivingEntity.obcGetHandle, player);
}
private boolean canDealFallDamage() {
return this.reflectLivingEntity != null && this.reflectLivingEntity.nmsDamageEntity != null && this.reflectDamageSource.nmsFALL != null;
return this.reflectLivingEntity != null && this.reflectLivingEntity.nmsDamageEntity != null
&& (this.reflectDamageSource.nmsFALL != null || this.reflectDamageSources != null);
}
@Override
@@ -505,22 +593,35 @@ public class MCAccessBukkitModern extends MCAccessBukkit {
public void dealFallDamage(Player player, double damage) {
if (canDealFallDamage()) {
Object handle = getHandle(player);
if (handle != null)
ReflectionUtil.invokeMethod(this.reflectLivingEntity.nmsDamageEntity, handle, this.reflectDamageSource.nmsFALL, (float) damage);
} else BridgeHealth.damage(player, damage);
if (handle != null) {
// Direct accessing DamageSource
Object damageSource = this.reflectDamageSource.nmsFALL;
if (damageSource == null) {
// Fail, second attempt
damageSource = this.reflectDamageSources.getDamageSource(handle);
if (damageSource == null) {
// Fail, deal generic damage
BridgeHealth.damage(player, damage);
// Disable class to prevent continuous damage
reflectDamageSources = null;
return;
}
}
ReflectionUtil.invokeMethod(this.reflectLivingEntity.nmsDamageEntity, handle, damageSource, (float) damage);
}
}
else BridgeHealth.damage(player, damage);
}
@Override
public boolean resetActiveItem(Player player) {
if (this.reflectLivingEntity != null && this.reflectLivingEntity.nmsclearActiveItem != null) {
Object handle = getHandle(player);
if (handle != null) {
ReflectionUtil.invokeMethodNoArgs(this.reflectLivingEntity.nmsclearActiveItem, handle);
return true;
}
Object handle = getHandle(player);
if (handle != null) {
ReflectionUtil.invokeMethodNoArgs(this.reflectLivingEntity.nmsclearActiveItem, handle);
return true;
}
}
return false;
}
}
@@ -0,0 +1,249 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.attribute.AttributeInstance;
import org.bukkit.attribute.AttributeModifier;
import org.bukkit.attribute.AttributeModifier.Operation;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.checks.moving.model.PlayerMoveData;
import fr.neatmonster.nocheatplus.compat.AttribUtil;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.compat.BridgeMisc;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion;
import fr.neatmonster.nocheatplus.components.modifier.IAttributeAccess;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
import fr.neatmonster.nocheatplus.utilities.math.MathUtil;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class NSBukkitAttributeAccess implements IAttributeAccess {
public NSBukkitAttributeAccess() {
if (ReflectionUtil.getClass("org.bukkit.attribute.AttributeInstance") == null) {
throw new RuntimeException("Service not available.");
}
}
private int operationToInt(final Operation operation) {
switch (operation) {
case ADD_NUMBER:
return 0;
case ADD_SCALAR:
return 1;
case MULTIPLY_SCALAR_1:
return 2;
default:
throw new RuntimeException("Unknown operation: " + operation);
}
}
/**
* The first modifier with the given id that can be found, or null if none
* is found.
*
* @param attrInst
* @param id
* @return
*/
private AttributeModifier getModifier(final AttributeInstance attrInst, final NamespacedKey id) {
for (final AttributeModifier mod : attrInst.getModifiers()) {
if (id.equals(mod.getKey())) {
return mod;
}
}
return null;
}
private double getMultiplier(final AttributeModifier mod) {
return AttribUtil.getMultiplier(operationToInt(mod.getOperation()), mod.getAmount());
}
@Override
public double getSpeedMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.MOVEMENT_SPEED);
final double val = attrInst.getValue() / attrInst.getBaseValue();
final AttributeModifier mod = getModifier(attrInst, AttribUtil.NSID_SPRINT_BOOST);
return mod == null ? val : (val / getMultiplier(mod));
}
@Override
public double getSprintMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.MOVEMENT_SPEED);
final AttributeModifier mod = getModifier(attrInst, AttribUtil.NSID_SPRINT_BOOST);
return mod == null ? 1.0 : getMultiplier(mod);
}
@Override
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getGravity(final Player player) {
double gravity;
if (!BridgeMisc.hasGravity(player)) {
return 0.0;
}
final PlayerMoveData thisMove = DataManager.getPlayerData(player).getGenericInstance(MovingData.class).playerMoves.getCurrentMove();
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.GRAVITY);
// Fail-safe.
if (attrInst == null) {
gravity = thisMove.yDistance <= 0.0 && !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player)) ? Magic.SLOW_FALL_GRAVITY : Magic.DEFAULT_GRAVITY;
}
else gravity = MathUtil.clamp(attrInst.getValue(), -1.0, 1.0);
if (thisMove.yDistance <= 0.0 && !Double.isInfinite(Bridge1_13.getSlowfallingAmplifier(player))) {
gravity = Math.min(gravity, Magic.SLOW_FALL_GRAVITY);
}
return gravity;
}
@Override
public double getSafeFallDistance(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.SAFE_FALL_DISTANCE);
// Fail-safe
if (attrInst == null) return Magic.FALL_DAMAGE_DIST;
return MathUtil.clamp(attrInst.getValue(), -1024.0, 1024.0);
}
@Override
public double getFallDamageMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.FALL_DAMAGE_MULTIPLIER);
// Fail-safe
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 1.0, 100.0);
}
@Override
public double getBreakingSpeedMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.BLOCK_BREAK_SPEED);
// Fail-safe
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 1.0, 1024.0);
}
@Override
public double getJumpGainMultiplier(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.JUMP_STRENGTH);
// Fail-safe
if (attrInst == null) return 1.0;
// Convert it to a multiplier, because we use our own handling for jumping motion.
final double toMultiplier = attrInst.getValue() / attrInst.getBaseValue();
return MathUtil.clamp(toMultiplier, 0.0, 76.19047619047619); // MathUtil.clamp(attrInst.getValue(), 0.0, 32.0);
}
@Override
public double getPlayerSneakingFactor(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.SNEAKING_SPEED);
// Fail-safe.
if (attrInst == null) return Magic.SNEAK_MULTIPLIER + BridgeEnchant.getSwiftSneakIncrement(player);
return MathUtil.clamp(attrInst.getValue(), 0.0, 1.0);
}
@Override
public double getPlayerMaxBlockReach(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.INTERACTION_RANGE);
// Fail-safe
if (attrInst == null) return 4.5;
return MathUtil.clamp(attrInst.getValue(), 0.0, 64.0);
}
@Override
public double getPlayerMaxAttackReach(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.ATTACK_RANGE);
// Fail-safe
if (attrInst == null) return 3.0;
return MathUtil.clamp(attrInst.getValue(), 0.0, 64.0);
}
@Override
public double getMaxStepUp(final Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.STEP_HEIGHT);
if (attrInst == null) {
// Fail-safe.
if (player.isInsideVehicle()) {
if (player.getVehicle() != null && MaterialUtil.isBoat(player.getVehicle().getType())) {
return 0.0;
}
return 1.0;
}
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
return MathUtil.clamp(attrInst.getValue(), 0.0, 10.0);
}
@Override
public float getMovementEfficiency(Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.MOVEMENT_EFFICIENCY);
// Fail-safe.
if (attrInst == null) return 0.0f;
return (float) MathUtil.clamp(attrInst.getValue(), 0.0, 1.0);
}
@Override
public float getWaterMovementEfficiency(Player player) {
final IPlayerData pData = DataManager.getPlayerData(player);
if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_8)) {
// Doesn't exist.
return 0f;
}
final float depthStrider = BridgeEnchant.getDepthStriderLevel(player);
if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_21)) {
// Use the legacy method.
return depthStrider;
}
if (ServerVersion.isLowerThan("1.21")) {
// Simulate what ViaVersion does for newer (1.21 clients) on older (1.21-) servers.
return depthStrider / 3.0f;
}
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.WATER_MOVEMENT_EFFICIENCY);
if (attrInst == null) return 0.0f;
return (float) MathUtil.clamp(attrInst.getValue(), 0.0f, 1.0f);
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.SUBMERGED_MINING_SPEED);
// Fail-safe.
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 0.0, 20.0);
}
@Override
public double getMiningEfficiency(Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.MINING_EFFICIENCY);
// Fail-safe.
if (attrInst == null) return 0.0;
return MathUtil.clamp(attrInst.getValue(), 0.0, 1024.0);
}
@Override
public double getEntityScale(Player player) {
final AttributeInstance attrInst = player.getAttribute(BridgeAttribute.SCALE);
// Fail-safe.
if (attrInst == null) return 1.0;
return MathUtil.clamp(attrInst.getValue(), 0.0625, 16.0);
}
}
@@ -35,8 +35,7 @@ public abstract class AbstractBukkitCentered implements BukkitShapeModel {
private final double length;
protected final boolean invertFace;
public AbstractBukkitCentered(double inset, double length,
boolean invertFace) {
public AbstractBukkitCentered(double inset, double length, boolean invertFace) {
// TODO: Might add a signature to specify minY and maxY (attach NWSE only).
this.minDist = inset;
this.maxDist = 1.0 - inset;
@@ -47,47 +46,44 @@ public abstract class AbstractBukkitCentered implements BukkitShapeModel {
protected abstract BlockFace getFacing(BlockData blockData);
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
final BlockFace facing = invertFace
? getFacing(blockData).getOppositeFace()
: getFacing(blockData);
// TODO: Evaluate if (some) faces need to be inverted.
// End rod facing: the direction it points to.
switch (facing) {
case EAST:
return new double[] {0.0, minDist, minDist,
length, maxDist, maxDist};
case WEST:
return new double[] {1.0 - length, minDist, minDist,
1.0, maxDist, maxDist};
case SOUTH:
return new double[] {minDist, minDist, 0.0,
maxDist, maxDist, length};
case NORTH:
return new double[] {minDist, minDist, 1.0 - length,
maxDist, maxDist, 1.0};
case DOWN:
return new double[] {minDist, 1.0 - length, minDist,
maxDist, 1.0, maxDist};
case UP:
return new double[] {minDist, 0.0, minDist,
maxDist, length, maxDist};
default:
break;
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
final BlockFace facing = invertFace ? getFacing(blockData).getOppositeFace() : getFacing(blockData);
// TODO: Evaluate if (some) faces need to be inverted.
// End rod facing: the direction it points to.
switch (facing) {
case EAST:
return new double[] {0.0, minDist, minDist, length, maxDist, maxDist};
case WEST:
return new double[] {1.0 - length, minDist, minDist, 1.0, maxDist, maxDist};
case SOUTH:
return new double[] {minDist, minDist, 0.0, maxDist, maxDist, length};
case NORTH:
return new double[] {minDist, minDist, 1.0 - length, maxDist, maxDist, 1.0};
case DOWN:
return new double[] {minDist, 1.0 - length, minDist, maxDist, 1.0, maxDist};
case UP:
return new double[] {minDist, 0.0, minDist, maxDist, length, maxDist};
default:
break;
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -20,48 +20,60 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitAnvil implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
final IPlayerData data = blockCache.getPlayerData();
final boolean legacy = data != null && data.getClientVersion().isLowerThan(ClientVersion.V_1_13);
if (blockData instanceof Directional) {
BlockFace face = ((Directional) blockData).getFacing();
switch (face) {
case NORTH:
case SOUTH:
return new double[] {
// Bottom
0.125, 0.0, 0.125, 0.875, 0.25, 0.875,
// Top
0.1875, 0.625, 0.0, 0.8125, 1.0, 1.0
// Body... maybe not need
};
case WEST:
case EAST:
return new double[] {
// Bottom
0.125, 0.0, 0.125, 0.875, 0.25, 0.875,
// Top
0.0, 0.625, 0.1875, 1.0, 1.0, 0.8125
// Body... maybe not need
};
default:
break;
case NORTH:
case SOUTH:
if (legacy) return new double[] {0.125, 0.0, 0.0, 0.875, 1.0, 1.0};
return new double[] {
// Bottom
0.125, 0.0, 0.125, 0.875, 0.25, 0.875,
// Top
0.1875, 0.625, 0.0, 0.8125, 1.0, 1.0
// Body... maybe not need
};
case WEST:
case EAST:
if (legacy) return new double[] {0.0, 0.0, 0.125, 1.0, 1.0, 0.875};
return new double[] {
// Bottom
0.125, 0.0, 0.125, 0.875, 0.25, 0.875,
// Top
0.0, 0.625, 0.1875, 1.0, 1.0, 0.8125
// Body... maybe not need
};
default:
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -14,39 +14,63 @@
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import java.text.DecimalFormat;
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
import org.bukkit.World;
import org.bukkit.block.Block;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Bamboo;
public class BukkitBamboo implements BukkitShapeModel {
//private DecimalFormat df = new DecimalFormat("#.000");
//private final double xz = 0.375;
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
if (blockCache.getPlayerData() != null && blockCache.getPlayerData().isBedrockPlayer()) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof Bamboo) {
Bamboo b = (Bamboo) blockData;
double thickness = 0.125;
if (b.getAge() > 0) thickness += 0.0625;
long a = LocUtil.randomSeedBedrock(x, 0, z);
long a1 = a * 2863311531L;
long rdx = (a1 >> 32) & 0xFFFFFFFFL;
//long rax = a1 & 0xFFFFFFFFL;
rdx >>=3;rdx *=3;
rdx = (rdx << 2) & 0xFFFFFFFFL;
double xOffset = a - rdx + 1;
//final Block block = world.getBlockAt(x, y, z);
//double minX = Math.abs(block.getBoundingBox().getMinX()) - Math.abs((int) block.getBoundingBox().getMinX());
//double minZ = Math.abs(block.getBoundingBox().getMinZ()) - Math.abs((int) block.getBoundingBox().getMinZ());
//minX = Double.parseDouble(df.format(minX));
//minZ = Double.parseDouble(df.format(minZ));
//return new double[] {1.0 - minX + 0.09, 0.0, minZ + 0.09, 1.0 - minX + xz - 0.09, 1.0, minZ + xz - 0.09}; (1)
//return new double[] {minX + 0.09, 0.0, 1.0 - minZ + 0.09, minX + xz - 0.09, 1.0, 1.0 - minZ + xz - 0.09}; (2)
// (1) + (2) =>
//return new double[] {1.0 - minX + 0.09, 0.0, 1.0 - minZ + 0.09, 1.0 - minX + xz - 0.09, 1.0, 1.0 - minZ + xz - 0.09};
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
a >>=8;
long a2 = a;
a *= 2863311531L;
rdx = (a >> 32) & 0xFFFFFFFFL;
rdx >>=3;rdx *=3;
rdx = (rdx << 2) & 0xFFFFFFFFL;
double zOffset = a2 - rdx +1;
xOffset *= 0.0625;
zOffset *= 0.0625;
return new double[] {xOffset, 0, zOffset, xOffset + thickness, 1.0, zOffset + thickness};
}
}
long i = LocUtil.randomSeedJava(x, 0, z);
final double xOffset = (((i & 15L) / 15.0F) - 0.5D) * 0.5D;
final double zOffset = (((i >> 8 & 15L) / 15.0F) - 0.5D) * 0.5D;
return new double[] {0.40625 + xOffset, 0.0, 0.40625 + zOffset, 0.59375 + xOffset, 1.0, 0.59375 + zOffset};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -25,91 +25,94 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitBell implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof Bell) {
Bell b = (Bell) blockData;
BlockFace face = b.getFacing();
switch (b.getAttachment()) {
case CEILING: return new double[] {0.25, 1-0.75, 0.25, 0.75, 1.0, 0.75};
case CEILING:
return new double[] {0.25, 1 - 0.75, 0.25, 0.75, 1.0, 0.75};
case DOUBLE_WALL:
switch (face) {
case NORTH:
case SOUTH:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
0.4375, 0.8125, 0.0, 0.5625, 0.9375, 1.0
//0.0, 0.8125, 0.4375, 1.0, 0.9375, 0.5625
};
case WEST:
case EAST:
return new double[] {
case NORTH:
case SOUTH:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
// Stick holding the bell
0.4375, 0.8125, 0.0, 0.5625, 0.9375, 1.0
//0.0, 0.8125, 0.4375, 1.0, 0.9375, 0.5625
};
case WEST:
case EAST:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick holding the bell
0.0, 0.8125, 0.4375, 1.0, 0.9375, 0.5625
};
default:
break;
default:
break;
}
break;
case FLOOR:
switch (face) {
case NORTH:
case SOUTH:
return new double[] {0.0, 0.0, 0.25, 1.0, 1.0, 0.75};
case WEST:
case EAST:
return new double[] {0.25, 0.0, 0.0, 0.75, 1.0, 1.0};
default:
break;
case NORTH:
case SOUTH:
return new double[] {0.0, 0.0, 0.25, 1.0, 1.0, 0.75};
case WEST:
case EAST:
return new double[] {0.25, 0.0, 0.0, 0.75, 1.0, 1.0};
default:
break;
}
break;
case SINGLE_WALL:
switch (face) {
case NORTH: return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
0.4375, 0.8125, 0.0, 0.5625, 0.9375, 0.8125
};
case SOUTH: return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
0.4375, 0.8125, 0.1875, 0.5625, 0.9375, 1.0
};
case WEST: return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
0.0, 0.8125, 0.4375, 0.8125, 0.9375, 0.5625
};
case EAST: return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick hold the bell
0.1875, 0.8125, 0.4375, 1.0, 0.9375, 0.5625
};
default:
break;
case NORTH:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick holding the bell
0.4375, 0.8125, 0.0, 0.5625, 0.9375, 0.8125
};
case SOUTH:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick holding the bell
0.4375, 0.8125, 0.1875, 0.5625, 0.9375, 1.0
};
case WEST:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick holding the bell
0.0, 0.8125, 0.4375, 0.8125, 0.9375, 0.5625
};
case EAST:
return new double[] {
// Bottom bell
0.25, 0.25, 0.25, 0.75, 0.375, 0.75,
// Body
0.3125, 0.375, 0.3125, 0.6875, 0.8125, 0.6875,
// Stick holding the bell
0.1875, 0.8125, 0.4375, 1.0, 0.9375, 0.5625
};
default:
break;
}
}
}
@@ -117,9 +120,17 @@ public class BukkitBell implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -26,15 +26,14 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitCake implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
BoundingBox bd = block.getBoundingBox();
return new double[] {bd.getMinX()-x, bd.getMinY()-y, bd.getMinZ()-z, bd.getMaxX()-x, bd.getMaxY()-y, bd.getMaxZ()-z};
}
final BlockData blockData = block.getState().getBlockData();
final BlockData blockData = block.getState().getBlockData();
if (blockData instanceof Cake) {
final Cake cake = (Cake) blockData;
return new double[] {0.0625 + cake.getBites() * 0.125, 0.0, 0.0625, 0.9375, 0.5, 0.9375};
@@ -43,9 +42,17 @@ public class BukkitCake implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -16,13 +16,32 @@ package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitCauldron implements BukkitShapeModel {
private final double[] bounds;
private final static double[] new1_13_2Bounds = {
0.0, 0.0, 0.0, 0.125, 1.0, 0.25,
0.0, 0.0, 0.75, 0.125, 1.0, 1.0,
0.125, 0.0, 0.0, 0.25, 1.0, 0.125,
0.125, 0.0, 0.875, 0.25, 1.0, 1.0,
0.75, 0.0, 0.0, 1.0, 1.0, 0.125,
0.75, 0.0, 0.875, 1.0, 1.0, 1.0,
0.875, 0.0, 0.125, 1.0, 1.0, 0.25,
0.875, 0.0, 0.75, 1.0, 1.0, 0.875,
0.0, 0.1875, 0.25, 1.0, 0.25, 0.75,
0.125, 0.1875, 0.125, 0.875, 0.25, 0.25,
0.125, 0.1875, 0.75, 0.875, 0.25, 0.875,
0.25, 0.1875, 0.0, 0.75, 1.0, 0.125,
0.25, 0.1875, 0.875, 0.75, 1.0, 1.0,
0.0, 0.25, 0.25, 0.125, 1.0, 0.75,
0.875, 0.25, 0.25, 1.0, 1.0, 0.75};
private final static double[] new1_13Bounds = makeCauldron(0.1875, 0.125, 0.8125, 0.0625);
private final static double[] legacyBounds = makeCauldron(0.0, 0.125, 1.0, 0.3125);
public BukkitCauldron(double minY, double sideWidth, double sideHeight, double coreHeight) {
bounds = new double[] {
private static double[] makeCauldron(double minY, double sideWidth, double sideHeight, double coreHeight) {
return new double[] {
// Core
sideWidth, minY, sideWidth, 1 - sideWidth, minY + coreHeight, 1 - sideWidth,
// 4 side
@@ -35,7 +54,15 @@ public class BukkitCauldron implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
return bounds;
IPlayerData pData = blockCache.getPlayerData();
if (pData != null) {
if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_13)) {
return legacyBounds;
} else if (pData.getClientVersion().isLowerThan(ClientVersion.V_1_13_2)) {
return new1_13Bounds;
} else return new1_13_2Bounds;
}
return new1_13Bounds;
}
@Override
@@ -43,4 +70,15 @@ public class BukkitCauldron implements BukkitShapeModel {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return new double[] {0.0, 0.1875, 0.0, 1.0, 1.0, 1.0};
//return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
// Should be true , but current implementation of Visible check of NCP can't do complex ray-trace for performance wise and technical limitations
return false;
}
}
@@ -0,0 +1,99 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Chest;
import org.bukkit.block.data.type.Chest.Type;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitChest implements BukkitShapeModel {
//TODO: With/without this, NCP still throw false when nearby doubled chest. Something else was wrong. Do note flags are correct too: (CHEST / SOLID+GROUND) BlockProps(2.5 / ToolProps(AXE/WOOD) / [3750, 1900, 950, 750, 600, 450, 400])
private final double[] NORTH_AABB = new double[] {0.0625, 0.0, 0.0, 0.9375, 0.875, 0.9375};
private final double[] SOUTH_AABB = new double[] {0.0625, 0.0, 0.0625, 0.9375, 0.875, 1.0};
private final double[] WEST_AABB = new double[] {0.0, 0.0, 0.0625, 0.9375, 0.875, 0.9375};
private final double[] EAST_AABB = new double[] {0.0625, 0.0, 0.0625, 1.0, 0.875, 0.9375};
private final double[] SINGLE = new double[] {0.0625, 0.0, 0.0625, 0.9375, 0.875, 0.9375};
public static BlockFace getConnectedDirection(BlockFace facing, Type chestType) {
return chestType == Type.LEFT ? getClockWise(facing) : getCounterClockWise(facing);
}
public static BlockFace getCounterClockWise(BlockFace dir) {
switch (dir) {
case NORTH: return BlockFace.WEST;
case SOUTH: return BlockFace.EAST;
case WEST: return BlockFace.SOUTH;
case EAST: return BlockFace.NORTH;
default: throw new IllegalStateException("Unable to get CCW facing of " + dir);
}
}
public static BlockFace getClockWise(BlockFace dir) {
switch (dir) {
case NORTH: return BlockFace.EAST;
case SOUTH: return BlockFace.WEST;
case WEST: return BlockFace.NORTH;
case EAST: return BlockFace.SOUTH;
default: throw new IllegalStateException("Unable to get Y-rotated facing of " + dir);
}
}
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Chest) {
final Chest chest = (Chest) blockData;
final Type chestType = chest.getType();
if (chestType == Type.SINGLE) {
return SINGLE;
}
switch (getConnectedDirection(chest.getFacing(), chestType)) {
case NORTH:
default:
return NORTH_AABB;
case SOUTH:
return SOUTH_AABB;
case WEST:
return WEST_AABB;
case EAST:
return EAST_AABB;
}
}
return SINGLE;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
@@ -14,6 +14,10 @@
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
@@ -22,56 +26,117 @@ import org.bukkit.block.data.MultipleFacing;
import org.bukkit.util.BoundingBox;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.utilities.collision.AxisAlignedBBUtils;
import fr.neatmonster.nocheatplus.utilities.collision.ShapeUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitChorusPlant implements BukkitShapeModel {
private static final BlockFace[] directions = new BlockFace[]{BlockFace.NORTH, BlockFace.EAST, BlockFace.SOUTH, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN};
private static final double[][] modernShapes = makeShapes();
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
BoundingBox bd = block.getBoundingBox();
return new double[] {bd.getMinX()-x, 0.1875, bd.getMinZ()-z, bd.getMaxX()-x, bd.getMaxY()-y, bd.getMaxZ()-z};
}
final BlockData blockData = block.getBlockData();
double[] res = new double[] {0.187, 0.188, 0.187, 1.0 - 0.187, 0.8125, 1.0 - 0.187};
if (blockData instanceof MultipleFacing) {
final MultipleFacing chorusplant = (MultipleFacing) blockData;
for (final BlockFace face : chorusplant.getFaces()) {
switch (face) {
//case DOWN:
// res[1]=0.0;
// break;
case UP:
res[4]=1.0;
break;
case SOUTH:
res[5]=1.0;
break;
case NORTH:
res[2]=0.0;
break;
case WEST:
res[0]=0.0;
break;
case EAST:
res[3]=1.0;
break;
default:
break;
}
}
// Server is 1.13.2 higher
if (Bridge1_13.hasBuiltInRayTracing()) {
double[] res = {};
for (BoundingBox box : block.getCollisionShape().getBoundingBoxes()) {
res = ShapeUtils.add(res, AxisAlignedBBUtils.toArray(box));
}
if (res.length == 0) return null;
return res;
} else {
// Server is 1.13
final BlockData blockData = block.getBlockData();
if (blockData instanceof MultipleFacing) {
final MultipleFacing chorusplant = (MultipleFacing) blockData;
return modernShapes[getAABBIndex(chorusplant.getFaces())];
}
}
return res;
return new double[] {0,0,0,1.0,1.0,1.0};
}
private static double[][] makeShapes() {
float min = 0.5F - (float) 0.3125;
float max = 0.5F + (float) 0.3125;
double[] base = {min, min, min, max, max, max};
double[][] cs = new double[directions.length][];
for (int i = 0; i < directions.length; i++) {
BlockFace dir = directions[i];
cs[i] = new double[] {0.5D + Math.min(-(float) 0.3125, (double) dir.getModX() * 0.5D), 0.5D + Math.min(-(float) 0.3125, (double) dir.getModY() * 0.5D), 0.5D + Math.min(-(float) 0.3125, (double) dir.getModZ() * 0.5D),
0.5D + Math.max((float) 0.3125, (double) dir.getModX() * 0.5D), 0.5D + Math.max((float) 0.3125, (double) dir.getModY() * 0.5D), 0.5D + Math.max((float) 0.3125, (double) dir.getModZ() * 0.5D)
};
}
double[][] cs2 = new double[64][];
for (int k = 0; k < 64; k++) {
double[] tmp = base;
for (int j = 0; j < directions.length; j++) {
if ((k & 1 << j) != 0) {
tmp = ShapeUtils.merge(tmp, cs[j]);
}
}
cs2[k] = tmp;
}
return cs2;
}
private Set<BlockFace> getLegacyFaces(BlockCache blockCache, World world, int x, int y, int z) {
Set<BlockFace> faces = new HashSet<>();
Material upBlock = blockCache.getType(x, y+1, z);
Material downBlock = blockCache.getType(x, y-1, z);
Material northBlock = blockCache.getType(x, y, z-1);
Material southBlock = blockCache.getType(x, y, z+1);
Material westBlock = blockCache.getType(x-1, y, z);
Material eastBlock = blockCache.getType(x+1, y, z);
if (downBlock == Material.CHORUS_PLANT || downBlock == Material.END_STONE || downBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.DOWN);
}
if (upBlock == Material.CHORUS_PLANT || upBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.UP);
}
if (northBlock == Material.CHORUS_PLANT || northBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.NORTH);
}
if (southBlock == Material.CHORUS_PLANT || southBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.SOUTH);
}
if (westBlock == Material.CHORUS_PLANT || westBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.WEST);
}
if (eastBlock == Material.CHORUS_PLANT || eastBlock == Material.CHORUS_FLOWER) {
faces.add(BlockFace.EAST);
}
return faces;
}
private int getAABBIndex(Set<BlockFace> faces) {
int i = 0;
for (int j = 0; j < directions.length; ++j) {
if (faces.contains(directions[j])) {
i |= 1 << j;
}
}
return i;
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -29,70 +29,78 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitCocoa implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
BoundingBox bd = block.getBoundingBox();
return new double[] {bd.getMinX()-x, bd.getMinY()-y, bd.getMinZ()-z, bd.getMaxX()-x, bd.getMaxY()-y, bd.getMaxZ()-z};
}
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Cocoa && blockData instanceof Directional) {
BlockFace face = ((Directional) blockData).getFacing();
final Cocoa cocoa = (Cocoa) blockData;
switch (cocoa.getAge()) {
case 0: // .625 .4375 .0625 max: .375 .75 .3125
switch (face) {
case NORTH:
return new double[] {0.375, 0.4375, 0.0, 0.625, 0.75, 0.315};
case SOUTH:
return new double[] {0.375, 0.4375, 0.685, 0.625, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.4375, 0.375, 0.315, 0.75, 0.625};
case EAST:
return new double[] {0.685, 0.4375, 0.375, 1.0, 0.75, 0.625};
default:
break;
case NORTH:
return new double[] {0.375, 0.4375, 0.0, 0.625, 0.75, 0.315};
case SOUTH:
return new double[] {0.375, 0.4375, 0.685, 0.625, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.4375, 0.375, 0.315, 0.75, 0.625};
case EAST:
return new double[] {0.685, 0.4375, 0.375, 1.0, 0.75, 0.625};
default:
break;
}
break;
case 1: // .6875 .3125 .0625 max: .3125 .75 .4375
switch (face) {
case NORTH:
return new double[] {0.3125, 0.3125, 0.0, 0.6875, 0.75, 0.4375};
case SOUTH:
return new double[] {0.3125, 0.3125, 0.5625, 0.6875, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.3125, 0.3125, 0.4375, 0.75, 0.6875};
case EAST:
return new double[] {0.5625, 0.3125, 0.3125, 1.0, 0.75, 0.6875};
default:
break;
case NORTH:
return new double[] {0.3125, 0.3125, 0.0, 0.6875, 0.75, 0.4375};
case SOUTH:
return new double[] {0.3125, 0.3125, 0.5625, 0.6875, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.3125, 0.3125, 0.4375, 0.75, 0.6875};
case EAST:
return new double[] {0.5625, 0.3125, 0.3125, 1.0, 0.75, 0.6875};
default:
break;
}
break;
case 2: // .75 .1875 .0625 max: .25 .75 .5625
switch (face) {
case NORTH:
return new double[] {0.25, 0.1875, 0.0, 0.75, 0.75, 0.5625};
case SOUTH:
return new double[] {0.25, 0.1875, 0.4375, 0.75, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.1875, 0.25, 0.5625, 0.75, 0.75};
case EAST:
return new double[] {0.4375, 0.1875, 0.25, 1.0, 0.75, 0.75};
default:
break;
case NORTH:
return new double[] {0.25, 0.1875, 0.0, 0.75, 0.75, 0.5625};
case SOUTH:
return new double[] {0.25, 0.1875, 0.4375, 0.75, 0.75, 1.0};
case WEST:
return new double[] {0.0, 0.1875, 0.25, 0.5625, 0.75, 0.75};
case EAST:
return new double[] {0.4375, 0.1875, 0.25, 1.0, 0.75, 0.75};
default:
break;
}
//break; ?
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -0,0 +1,54 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitComposter implements BukkitShapeModel {
private final double[] bounds;
public BukkitComposter(double minY, double sideWidth, double sideHeight, double coreHeight) {
bounds = new double[] {
// Core
sideWidth, minY, sideWidth, 1 - sideWidth, minY + coreHeight, 1 - sideWidth,
// 4 side
0.0, minY, 0.0, 1.0, minY + sideHeight, sideWidth,
0.0, minY, 1.0 - sideWidth, 1.0, minY + sideHeight, 1.0,
0.0, minY, 0.0, sideWidth, minY + sideHeight, 1.0,
1.0 - sideWidth, minY, 0.0, 1.0, minY + sideHeight, 1.0
};
}
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
return bounds;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
}
@@ -30,9 +30,6 @@ public class BukkitDirectionalCentered extends AbstractBukkitCentered {
if (blockData instanceof Directional) {
return ((Directional) blockData).getFacing();
}
else {
return BlockFace.SELF;
}
return BlockFace.SELF;
}
}
}
@@ -0,0 +1,51 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
/**
* Grass path and farm land shape model.
*/
public class BukkitDirtLike implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
// Farmland changed the height from 1.10 but too lazy and not many clients on this version. Taking shortcut!
final IPlayerData data = blockCache.getPlayerData();
if (data != null && data.getClientVersion().isLowerThan(ClientVersion.V_1_9)) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
return new double[] {0.0, 0.0, 0.0, 1.0, 0.9375, 1.0};
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -34,9 +34,7 @@ public class BukkitDoor implements BukkitShapeModel {
* @return The block face of the block the door is standing on, indicating
* where the door is.
*/
private static final BlockFace getWhereTheDoorIsFace(
final BlockFace facing, final Hinge hinge,
final boolean isOpen) {
private static final BlockFace getWhereTheDoorIsFace(final BlockFace facing, final Hinge hinge, final boolean isOpen) {
// For idiots:
/*
* Facing: Door is closing the opposite side of the block, so the
@@ -45,9 +43,6 @@ public class BukkitDoor implements BukkitShapeModel {
/*
* Hinge: Looking into the facing direction, hinge is left or right.
*/
// Bukkit.getServer().broadcastMessage("hinge=" + hinge
// + " / facing=" + facing
// + " / open=" + isOpen);
// Let's play north and south:
switch (facing) {
case NORTH:
@@ -55,49 +50,33 @@ public class BukkitDoor implements BukkitShapeModel {
if (hinge == Hinge.LEFT) {
return BlockFace.WEST;
}
else {
return BlockFace.EAST;
}
}
else {
return BlockFace.SOUTH;
return BlockFace.EAST;
}
return BlockFace.SOUTH;
case SOUTH:
if (isOpen) {
if (hinge == Hinge.LEFT) {
return BlockFace.EAST;
}
else {
return BlockFace.WEST;
}
}
else {
return BlockFace.NORTH;
return BlockFace.WEST;
}
return BlockFace.NORTH;
case EAST:
if (isOpen) {
if (hinge == Hinge.LEFT) {
return BlockFace.NORTH;
}
else {
return BlockFace.SOUTH;
}
}
else {
return BlockFace.WEST;
return BlockFace.SOUTH;
}
return BlockFace.WEST;
case WEST:
if (isOpen) {
if (hinge == Hinge.LEFT) {
return BlockFace.SOUTH;
}
else {
return BlockFace.NORTH;
}
}
else {
return BlockFace.EAST;
return BlockFace.NORTH;
}
return BlockFace.EAST;
default:
// Invalid
return BlockFace.SELF;
@@ -108,8 +87,7 @@ public class BukkitDoor implements BukkitShapeModel {
private static final double doorWidthOpen = 0.1875;
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
@@ -117,28 +95,34 @@ public class BukkitDoor implements BukkitShapeModel {
final Door door = (Door) blockData;
final boolean isOpen = door.isOpen();
final double doorWidth = doorWidthOpen; // isOpen ? doorWidthOpen : doorWidthClosed;
switch(getWhereTheDoorIsFace(door.getFacing(),
door.getHinge(), isOpen)) {
case NORTH:
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, doorWidth};
case SOUTH:
return new double[] {0.0, 0.0, 1.0 - doorWidth, 1.0, 1.0, 1.0};
case EAST:
return new double[] {1.0 - doorWidth, 0.0, 0.0, 1.0, 1.0, 1.0};
case WEST:
return new double[] {0.0, 0.0, 0.0, doorWidth, 1.0, 1.0};
default:
break;
switch (getWhereTheDoorIsFace(door.getFacing(), door.getHinge(), isOpen)) {
case NORTH:
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, doorWidth};
case SOUTH:
return new double[] {0.0, 0.0, 1.0 - doorWidth, 1.0, 1.0, 1.0};
case EAST:
return new double[] {1.0 - doorWidth, 0.0, 0.0, 1.0, 1.0, 1.0};
case WEST:
return new double[] {0.0, 0.0, 0.0, doorWidth, 1.0, 1.0};
default:
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -0,0 +1,61 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.BigDripleaf;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitDripLeaf implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getState().getBlockData();
double[] res = {0.0, 0.6875, 0.0, 1.0, 0.9375, 1.0};
if (blockData instanceof BigDripleaf) {
final BigDripleaf dripLeaf = (BigDripleaf) blockData;
switch(dripLeaf.getTilt()) {
case PARTIAL:
res[4] -= 0.125;
return res;
case NONE:
case UNSTABLE:
return res;
default:
return new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
}
}
return null;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -0,0 +1,98 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.PointedDripstone;
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import fr.neatmonster.nocheatplus.utilities.math.MathUtil;
public class BukkitDripStone implements BukkitShapeModel {
private static final double[] TIP_MERGE = {0.3125, 0.0, 0.3125, 0.6875, 1.0, 0.6875};
private static final double[] TIP_DOWN = {0.3125, 0.3125, 0.3125, 0.6875, 1.0, 0.6875};
private static final double[] TIP_UP = {0.3125, 0.0, 0.3125, 0.6875, 0.6875, 0.6875};
private static final double[] FRUSTUM = {0.25, 0.0, 0.25, 0.75, 1.0, 0.75};
private static final double[] MIDDLE = {0.1875, 0.0, 0.1875, 0.8125, 1.0, 0.8125};
private static final double[] BASE = {0.125, 0.0, 0.125, 0.875, 1.0, 0.875};
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof PointedDripstone) {
boolean bedrock = blockCache.getPlayerData() != null && blockCache.getPlayerData().isBedrockPlayer();
final long randomseed = bedrock ? LocUtil.randomSeedBedrock(x, 0, z) : LocUtil.randomSeedJava(x, 0, z);
double xOffset = MathUtil.clamp(calcOffset(randomseed, false, bedrock), -0.125, 0.125);
double zOffset = MathUtil.clamp(calcOffset(randomseed, true, bedrock), -0.125, 0.125);
PointedDripstone pds = (PointedDripstone) blockData;
switch (pds.getThickness()) {
case TIP_MERGE:
return offset(TIP_MERGE, xOffset, 0, zOffset);
case TIP:
if (pds.getVerticalDirection() == BlockFace.DOWN) {
return offset(TIP_DOWN, xOffset, 0, zOffset);
} else {
return offset(TIP_UP, xOffset, 0, zOffset);
}
case FRUSTUM:
return offset(FRUSTUM, xOffset, 0, zOffset);
case MIDDLE:
return offset(MIDDLE, xOffset, 0, zOffset);
default:
return offset(BASE, xOffset, 0, zOffset);
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
private float calcOffset(long x, boolean shift, boolean bedrock) {
if (shift) x >>=8;
x &= 0xFL;
float b = x;
if (bedrock) {
b *= 0.0333333f;
b -= 0.25f;
} else {
b /= 15f;
b -= 0.5f;
b *= 0.5f;
}
return b;
}
private double[] offset(double[] input, double x, double y, double z) {
return new double[] {input[0] + x, input[1] + y, input[2] + z, input[3] + x, input[4] + y, input[5] + z};
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -25,33 +25,33 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitEndPortalFrame implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof EndPortalFrame) {
return ((EndPortalFrame) blockData).hasEye()
? new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0}
: new double[] {0.0, 0.0, 0.0, 1.0, 0.8125, 1.0};
}
else {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
return getShape(((EndPortalFrame) blockData).hasEye());
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof EndPortalFrame) {
return ((EndPortalFrame) blockData).hasEye() ? 0x4 : 0;
}
else {
return 0;
}
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
private double[] getShape(boolean hasEye) {
return hasEye ? new double[] {0.0, 0.0, 0.0, 1.0, 0.8125, 1.0, 0.25, 0.8125, 0.25, 0.75, 1.0, 0.75}
: new double[] {0.0, 0.0, 0.0, 1.0, 0.8125, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -20,72 +20,142 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.util.BoundingBox;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.collision.AxisAlignedBBUtils;
import fr.neatmonster.nocheatplus.utilities.collision.ShapeUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitFence implements BukkitShapeModel {
private final double[] northplane;
private final double[] southplane;
private final double[] westplane;
private final double[] eastplane;
private final double[] northplaneB;
private final double[] southplaneB;
private final double[] westplaneB;
private final double[] eastplaneB;
private final double[] fullplane;
private final double[] eastwest;
private final double[] southnorth;
private final double[] baseState;
private final boolean cutEdgeOnLowVersions;
private final double minXZ;
private final double maxXZ;
private final double height;
public BukkitFence(double inset, double height) {
this(inset, 1.0 - inset, height);
public BukkitFence(double inset, double height, boolean cutEdgeOnLowVersions) {
this(inset, 1.0 - inset, height, cutEdgeOnLowVersions);
}
public BukkitFence(double minXZ, double maxXZ, double height) {
this.minXZ = minXZ;
this.maxXZ = maxXZ;
this.height = height;
public BukkitFence(double minXZ, double maxXZ, double height, boolean cutEdgeOnLowVersions) {
this.cutEdgeOnLowVersions = cutEdgeOnLowVersions;
this.northplane = new double[] {minXZ, 0.0, 0.0, maxXZ, height, maxXZ};
this.southplane = new double[] {minXZ, 0.0, minXZ, maxXZ, height, 1.0};
this.westplane = new double[] {0.0, 0.0, minXZ, maxXZ, height, maxXZ};
this.eastplane = new double[] {minXZ, 0.0, minXZ, 1.0, height, maxXZ};
this.northplaneB = new double[] {minXZ, 0.0, 0.0, maxXZ, height, maxXZ - 0.0625};
this.southplaneB = new double[] {minXZ, 0.0, minXZ + 0.0625, maxXZ, height, 1.0};
this.westplaneB = new double[] {0.0, 0.0, minXZ, maxXZ - 0.0625, height, maxXZ};
this.eastplaneB = new double[] {minXZ + 0.0625, 0.0, minXZ, 1.0, height, maxXZ};
this.eastwest = ShapeUtils.merge(westplane, eastplane);
this.southnorth = ShapeUtils.merge(southplane, northplane);
this.fullplane = ShapeUtils.add(eastwest, southnorth);
this.baseState = new double[] {minXZ, 0.0, minXZ, maxXZ, height, maxXZ};
}
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
// 13749998807909
// 86250001192093
// 0.1375, 0.8625
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof MultipleFacing) {
// Note isPassableWorkaround for these (no voxel shapes / multi cuboid yet).
final MultipleFacing fence = (MultipleFacing) blockData;
// TODO: If height > 1.0, check if it needs to be capped, provided relevant.
double[] res = new double[] {minXZ, 0.0, minXZ, maxXZ, height, maxXZ};
for (final BlockFace face : fence.getFaces()) {
switch (face) {
case EAST:
res[3] = 1.0;
break;
case NORTH:
res[2] = 0.0;
break;
case WEST:
res[0] = 0.0;
break;
case SOUTH:
res[5] = 1.0;
break;
default:
break;
final IPlayerData data = blockCache.getPlayerData();
final boolean cutEdge = data != null && cutEdgeOnLowVersions && data.getClientVersion().isLowerThan(ClientVersion.V_1_9);
// Server is 1.13.2 higher and player not on 1.8
if (Bridge1_13.hasBuiltInRayTracing() && !cutEdge) {
double[] res = {};
for (BoundingBox box : block.getCollisionShape().getBoundingBoxes()) {
res = ShapeUtils.add(res, AxisAlignedBBUtils.toArray(box));
}
if (res.length == 0) return null;
return res;
} else {
boolean east = false;
boolean north = false;
boolean west = false;
boolean south = false;
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof MultipleFacing) {
final MultipleFacing fence = (MultipleFacing) blockData;
for (final BlockFace face : fence.getFaces()) {
switch (face) {
case EAST:
east = true;
break;
case NORTH:
north = true;
break;
case WEST:
west = true;
break;
case SOUTH:
south = true;
break;
default:
break;
}
}
}
return res;
if (east && north && west && south) {
return fullplane;
}
double tmp[] = new double[0];
if (east && west) {
tmp = eastwest;
east = west = false;
} else if (south && north) {
tmp = southnorth;
south = north = false;
}
if (south) {
tmp = ShapeUtils.add(tmp, cutEdge && isNextDir(east, north, west, south) ? southplaneB : southplane);
}
if (north) {
tmp = ShapeUtils.add(tmp, cutEdge && isNextDir(east, north, west, south) ? northplaneB : northplane);
}
if (east) {
tmp = ShapeUtils.add(tmp, cutEdge && isNextDir(east, north, west, south) ? eastplaneB : eastplane);
}
if (west) {
tmp = ShapeUtils.add(tmp, cutEdge && isNextDir(east, north, west, south) ? westplaneB : westplane);
}
if (tmp.length == 0) {
tmp = ShapeUtils.add(tmp, cutEdge ? fullplane : baseState);
}
return tmp;
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
private boolean isNextDir(boolean east, boolean north, boolean west, boolean south) {
return (north || south) && (west || east);
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
double a[] = getShape(blockCache, world, x, y, z);
for (int i = 1; i < (int)a.length / 6; i++) a[i*6-2] = 1.0;
return a;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
// TODO: Which one is better, return true and cap the height or return false and fetch twice?
// NOTE: Should be no different as current implementation doesn't do exact ray trace check
return true;
}
}
@@ -20,6 +20,14 @@ import org.bukkit.util.BoundingBox;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
/**
* Fetches a single BoundingBox from Bukkit's Block#getBoundingBox().
* Returns a six-element double[] {minX, minY, minZ, maxX, maxY, maxZ}
* relative to the block position (world coords minus the block's x,y,z).
*
* This class returns one bounding box; BukkitFetchableBounds reads the VoxelShape and may return multiple boxes for complex
* collision shapes.
*/
public class BukkitFetchableBound implements BukkitShapeModel {
@Override
@@ -29,8 +37,18 @@ public class BukkitFetchableBound implements BukkitShapeModel {
return new double[] {box.getMinX()-x, box.getMinY()-y, box.getMinZ()-z, box.getMaxX()-x, box.getMaxY()-y, box.getMaxZ()-z};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -0,0 +1,63 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.VoxelShape;
import fr.neatmonster.nocheatplus.utilities.collision.AxisAlignedBBUtils;
import fr.neatmonster.nocheatplus.utilities.collision.ShapeUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
/**
* Fetches the block's collision VoxelShape and returns one or more bounding boxes
* as a concatenated double[] containing {minX,minY,minZ,maxX,maxY,maxZ} for each
* box. Coordinates are expressed relative to the block position.
*
* Difference from BukkitFetchableBound: this class may return multiple boxes
* (preserving complex/multi-part collision geometry); BukkitFetchableBound
* returns a single BoundingBox from Block#getBoundingBox().
*/
public class BukkitFetchableBounds implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final VoxelShape blockShape = block.getCollisionShape();
double[] res = {};
for (BoundingBox box : blockShape.getBoundingBoxes()) {
res = ShapeUtils.add(res, AxisAlignedBBUtils.toArray(box));
}
if (res.length == 0) return null;
return res;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -40,8 +40,7 @@ public class BukkitGate implements BukkitShapeModel {
}
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
@@ -63,17 +62,23 @@ public class BukkitGate implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Openable) {
return ((Openable) blockData).isOpen() ? 0x4 : 0;
}
else {
return 0;
}
return 0;
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -0,0 +1,123 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Grindstone;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitGrindStone implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getState().getBlockData();
if (blockData instanceof Grindstone) {
final Grindstone grindstone = (Grindstone) blockData;
final BlockFace facing = grindstone.getFacing();
switch (grindstone.getAttachedFace()) {
case CEILING:
switch (facing) {
case NORTH:
case SOUTH:
return new double[] {0.125, 0.5625, 0.375, 0.25, 1.0, 0.625,
0.75, 0.5625, 0.375, 0.875, 1.0, 0.625,
0.125, 0.1875, 0.3125, 0.25, 0.5625, 0.6875,
0.75, 0.1875, 0.3125, 0.875, 0.5625, 0.6875,
0.25, 0.0, 0.125, 0.75, 0.75, 0.875};
case EAST:
case WEST:
return new double[] {0.375, 0.5625, 0.125, 0.625, 1.0, 0.25,
0.375, 0.5625, 0.75, 0.625, 1.0, 0.875,
0.3125, 0.1875, 0.125, 0.6875, 0.5625, 0.25,
0.3125, 0.1875, 0.75, 0.6875, 0.5625, 0.875,
0.125, 0.0, 0.25, 0.875, 0.75, 0.75};
default:
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
case FLOOR:
switch (facing) {
case NORTH:
case SOUTH:
return new double[] {0.125, 0.0, 0.375, 0.25, 0.4375, 0.625,
0.75, 0.0, 0.375, 0.875, 0.4375, 0.625,
0.125, 0.4375, 0.3125, 0.25, 0.8125, 0.6875,
0.75, 0.4375, 0.3125, 0.875, 0.8125, 0.6875,
0.25, 0.25, 0.125, 0.75, 1.0, 0.875};
case EAST:
case WEST:
return new double[] {0.375, 0.0, 0.125, 0.625, 0.4375, 0.25,
0.375, 0.0, 0.75, 0.625, 0.4375, 0.875,
0.3125, 0.4375, 0.125, 0.6875, 0.8125, 0.25,
0.3125, 0.4375, 0.75, 0.6875, 0.8125, 0.875,
0.125, 0.25, 0.25, 0.875, 1.0, 0.75};
default:
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
case WALL:
switch (facing) {
case NORTH:
return new double[] {0.125, 0.375, 0.4375, 0.25, 0.625, 1.0,
0.75, 0.375, 0.4375, 0.875, 0.625, 1.0,
0.125, 0.3125, 0.1875, 0.25, 0.6875, 0.5625,
0.75, 0.3125, 0.1875, 0.875, 0.6875, 0.5625,
0.25, 0.125, 0.0, 0.75, 0.875, 0.75};
case SOUTH:
return new double[] {0.125, 0.375, 0.0, 0.25, 0.625, 0.4375,
0.75, 0.375, 0.0, 0.875, 0.625, 0.4375,
0.125, 0.3125, 0.4375, 0.25, 0.6875, 0.8125,
0.75, 0.3125, 0.4375, 0.875, 0.6875, 0.8125,
0.25, 0.125, 0.25, 0.75, 0.875, 1.0};
case EAST:
return new double[] {0.0, 0.375, 0.125, 0.5625, 0.625, 0.25,
0.0, 0.375, 0.75, 0.5625, 0.625, 0.875,
0.4375, 0.3125, 0.125, 0.8125, 0.6875, 0.25,
0.4375, 0.3125, 0.75, 0.8125, 0.6875, 0.875,
0.25, 0.125, 0.25, 1.0, 0.875, 0.75};
case WEST:
return new double[] {0.4375, 0.375, 0.125, 1.0, 0.625, 0.25,
0.4375, 0.375, 0.75, 1.0, 0.625, 0.875,
0.1875, 0.3125, 0.125, 0.5625, 0.6875, 0.25,
0.1875, 0.3125, 0.75, 0.5625, 0.6875, 0.875,
0.0, 0.125, 0.25, 0.75, 0.875, 0.75};
default:
break;
}
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -20,108 +20,124 @@ import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitHopper implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
IPlayerData pData = blockCache.getPlayerData();
if (pData != null && pData.getClientVersion().isLowerThan(ClientVersion.V_1_13)) {
return new double[] {
0, 0, 0, 1, 0.625, 1,
0, 0.625, 0, 0.125, 1, 1,
0.875, 0.625, 0, 1, 1, 1,
0, 0.625, 0, 1, 1, 0.125,
0, 0.625, 0.875, 1, 1, 1
};
}
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof Directional) {
Directional b = (Directional) blockData;
BlockFace face = b.getFacing();
switch (face) {
case NORTH:
return new double[] {
case NORTH:
return new double[] {
// Standing inside
0.0, 0.625, 0.0, 1.0, 0.6875, 1.0,
// Middle
0.25, 0.25, 0.25, 0.75, 0.625, 0.75,
// Bottom
0.375, 0.25, 0.0, 0.625, 0.5, 0.25,
// Top
0.0, 0.6875, 0.0, 1.0, 1.0, 1.0
// 4 sides of hopper (top)
//0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
//0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
//0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
//0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
};
case SOUTH:
return new double[] {
case SOUTH:
return new double[] {
// Standing inside
0.0, 0.625, 0.0, 1.0, 0.6875, 1.0,
// Middle
0.25, 0.25, 0.25, 0.75, 0.625, 0.75,
// Bottom
0.375, 0.25, 0.75, 0.625, 0.5, 1.0,
// Top
0.0, 0.6875, 0.0, 1.0, 1.0, 1.0
// 4 sides of hopper (top)
//0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
//0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
//0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
//0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
};
case WEST:
return new double[] {
case WEST:
return new double[] {
// Standing inside
0.0, 0.625, 0.0, 1.0, 0.6875, 1.0,
// Middle
0.25, 0.25, 0.25, 0.75, 0.625, 0.75,
// Bottom
0.0, 0.25, 0.375, 0.25, 0.5, 0.625,
// Top
0.0, 0.6875, 0.0, 1.0, 1.0, 1.0
// 4 sides of hopper (top)
//0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
//0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
//0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
//0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
};
case EAST:
return new double[] {
case EAST:
return new double[] {
// Standing inside
0.0, 0.625, 0.0, 1.0, 0.6875, 1.0,
// Middle
0.25, 0.25, 0.25, 0.75, 0.625, 0.75,
// Bottom
0.75, 0.25, 0.375, 1.0, 0.5, 0.625,
// Top
0.0, 0.6875, 0.0, 1.0, 1.0, 1.0
// 4 sides of hopper (top)
//0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
//0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
//0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
//0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
};
case DOWN:
return new double[] {
case DOWN:
return new double[] {
// Standing inside
0.0, 0.625, 0.0, 1.0, 0.6875, 1.0,
// Middle
0.25, 0.25, 0.25, 0.75, 0.625, 0.75,
// Bottom
0.375, 0.0, 0.375, 0.625, 0.25, 0.625,
// Top
0.0, 0.6875, 0.0, 1.0, 1.0, 1.0
// 4 sides of hopper (top)
//0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
//0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
//0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
//0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 1.0, 1.0, 0.125,
0.0, 0.6875, 0.875, 1.0, 1.0, 1.0,
0.0, 0.6875, 0.0, 0.125, 1.0, 1.0,
0.875, 0.6875, 0.0, 1.0, 1.0, 1.0,
};
default:
break;
default:
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
IPlayerData pData = blockCache.getPlayerData();
if (pData != null && pData.getClientVersion().isLowerThan(ClientVersion.V_1_13)) {
return new double[] {0, 0, 0, 1, 1, 1};
}
return new double[] {0.0, 0.625, 0.0, 1.0, 1.0, 1.0, 0.25, 0.25, 0.25, 0.75, 0.625, 0.75};
//return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
}
@@ -19,38 +19,49 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.util.BoundingBox;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitLadder implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
BoundingBox box = block.getBoundingBox();
return new double[] {box.getMinX()-x, box.getMinY()-y, box.getMinZ()-z, box.getMaxX()-x, box.getMaxY()-y, box.getMaxZ()-z};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Directional) {
final Directional ladder = (Directional) blockData;
switch(ladder.getFacing()) {
case EAST:
return 5;
case NORTH:
return 6;
case SOUTH:
return 3;
case WEST:
return 4;
default:
break;
case EAST:
return 5;
case NORTH:
return 6;
case SOUTH:
return 3;
case WEST:
return 4;
default:
break;
}
}
return 0;
}
}
}
@@ -24,26 +24,32 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitLantern implements BukkitShapeModel {
private double xz = 0.3125;
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof Lantern) {
Lantern lantern = (Lantern) blockData;
if (lantern.isHanging()) return new double[] {
xz, 0.0625, xz, 1-xz, 0.5, 1-xz,
0.375, 0.5, 0.375, 0.625, 0.625, 0.625};
if (lantern.isHanging())
return new double[] {xz, 0.0625, xz, 1-xz, 0.5, 1-xz, 0.375, 0.5, 0.375, 0.625, 0.625, 0.625};
}
return new double[] {xz, 0.0, xz, 1.0-xz, 0.4375, 1.0-xz,
0.375, 0.4375, 0.375, 0.625, 0.5625, 0.625};
return new double[] {xz, 0.0, xz, 1.0-xz, 0.4375, 1.0-xz, 0.375, 0.4375, 0.375, 0.625, 0.5625, 0.625};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -19,15 +19,32 @@ import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Levelled;
import org.bukkit.block.data.type.Snow;
import org.bukkit.block.data.Waterlogged;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import fr.neatmonster.nocheatplus.utilities.map.BlockFlags;
public class BukkitLevelled implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
final Block blockAbove = world.getBlockAt(x, y + 1, z);
final BlockData blockDataAbove = blockAbove.getBlockData();
if ((BlockFlags.getBlockFlags(world.getBlockAt(x, y, z).getType()) & BlockFlags.F_WATER) != 0
&& (blockDataAbove instanceof Waterlogged && ((Waterlogged)blockDataAbove).isWaterlogged())) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
return new double[] {0.0, 0.0, 0.0, 1.0, 8 / 9f, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return null;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
@Override
@@ -35,13 +52,9 @@ public class BukkitLevelled implements BukkitShapeModel {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Snow) {
return ((Snow)blockData).getLayers() - 1;
}
if (blockData instanceof Levelled) {
return ((Levelled)blockData).getLevel();
}
return 0;
}
}
}
@@ -0,0 +1,50 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
/**
* Water Lily shape model.
*/
public class BukkitLilyPad implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final IPlayerData data = blockCache.getPlayerData();
if (data != null && data.getClientVersion().isLowerThan(ClientVersion.V_1_9)) {
return new double[] {0.0625, 0.0, 0.0625, 0.9375, 0.125, 0.9375};
}
return new double[] {0.0625, 0.0, 0.0625, 0.9375, 0.09375, 0.9375};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
@@ -28,8 +28,7 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitPiston implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
@@ -41,7 +40,9 @@ public class BukkitPiston implements BukkitShapeModel {
double[] res = new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
if (blockData instanceof Piston) {
final Piston piston = (Piston) blockData;
if (!piston.isExtended()) return res;
if (!piston.isExtended()) {
return res;
}
final BlockFace face = piston.getFacing();
switch (face) {
case NORTH:
@@ -71,9 +72,17 @@ public class BukkitPiston implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -32,52 +32,67 @@ public class BukkitPistonHead implements BukkitShapeModel {
Directional b = (Directional) blockData;
BlockFace face = b.getFacing();
switch (face) {
case UP: return new double[] {
// Shaft
0.375, 0.0, 0.375, 0.625, 1.0, 0.625,
// Plank
0.0, 0.75, 0.0, 1.0, 1.0, 1.0
};
case DOWN: return new double[] {
// Shaft
0.375, 0.0, 0.375, 0.625, 1.0, 0.625,
// Plank
0.0, 0.0, 0.0, 1.0, 0.25, 1.0
};
case NORTH: return new double[] {
// Shaft
0.375, 0.375, 0.0, 0.625, 0.625, 1.0,
// Plank
0.0, 0.0, 0.0, 1.0, 1.0, 0.25
};
case SOUTH: return new double[] {
// Shaft
0.375, 0.375, 0.0, 0.625, 0.625, 1.0,
// Plank
0.0, 0.0, 0.75, 1.0, 1.0, 1.0
};
case WEST: return new double[] {
// Shaft
0.0, 0.375, 0.375, 1.0, 0.625, 0.625,
// Plank
0.0, 0.0, 0.0, 0.25, 1.0, 1.0
};
case EAST: return new double[] {
// Shaft
0.0, 0.375, 0.375, 1.0, 0.625, 0.625,
// Plank
0.75, 0.0, 0.0, 1.0, 1.0, 1.0
};
default:
break;
case UP:
return new double[] {
// Shaft
0.375, 0.0, 0.375, 0.625, 1.0, 0.625,
// Plank
0.0, 0.75, 0.0, 1.0, 1.0, 1.0
};
case DOWN:
return new double[] {
// Shaft
0.375, 0.0, 0.375, 0.625, 1.0, 0.625,
// Plank
0.0, 0.0, 0.0, 1.0, 0.25, 1.0
};
case NORTH:
return new double[] {
// Shaft
0.375, 0.375, 0.0, 0.625, 0.625, 1.0,
// Plank
0.0, 0.0, 0.0, 1.0, 1.0, 0.25
};
case SOUTH:
return new double[] {
// Shaft
0.375, 0.375, 0.0, 0.625, 0.625, 1.0,
// Plank
0.0, 0.0, 0.75, 1.0, 1.0, 1.0
};
case WEST:
return new double[] {
// Shaft
0.0, 0.375, 0.375, 1.0, 0.625, 0.625,
// Plank
0.0, 0.0, 0.0, 0.25, 1.0, 1.0
};
case EAST:
return new double[] {
// Shaft
0.0, 0.375, 0.375, 1.0, 0.625, 0.625,
// Plank
0.75, 0.0, 0.0, 1.0, 1.0, 1.0
};
default:
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
}
@@ -0,0 +1,58 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitPowderSnow implements BukkitShapeModel {
// Some what behave like ladder
double[] REDUCED_HEIGHT = {0.0, 0.0, 0.0, 1.0, 0.9, 1.0};
double[] FULL_HEIGHT = {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
IPlayerData pData = blockCache.getPlayerData();
if (pData != null) {
MovingData data = pData.getGenericInstance(MovingData.class);
if (data.noFallFallDistance > 2.5) {
return REDUCED_HEIGHT;
} else if (data.lastY > y + 1 - 1e-5 && data.hasLeatherBoots && !pData.isShiftKeyPressed()) {
return FULL_HEIGHT;
}
}
return null;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return FULL_HEIGHT;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
@@ -40,4 +40,14 @@ public class BukkitRail implements BukkitShapeModel {
return 0;
}
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
// TODO Hold on, this model doesn't seem right, will fix later
return null;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
}
@@ -0,0 +1,123 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Scaffolding;
import fr.neatmonster.nocheatplus.checks.moving.MovingData;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
/**
* Scaffolding shape model.
*/
public class BukkitScaffolding implements BukkitShapeModel {
// Stable visual shape (top slab + four posts)
private static final double[] STABLE_SHAPE = new double[] {
// top slab: 0,14,0 -> 16,16,16
0.0, 0.875, 0.0, 1.0, 1.0, 1.0,
// post (0..2 x, 0..2 z)
0.0, 0.0, 0.0, 0.125, 1.0, 0.125,
// post (14..16 x, 0..2 z)
0.875, 0.0, 0.0, 1.0, 1.0, 0.125,
// post (0..2 x, 14..16 z)
0.0, 0.0, 0.875, 0.125, 1.0, 1.0,
// post (14..16 x, 14..16 z)
0.875, 0.0, 0.875, 1.0, 1.0, 1.0
};
// Unstable visual shape includes a thin bottom plate plus the stable parts
private static final double[] UNSTABLE_SHAPE = new double[] {
// bottom full thin plate: 0,0,0 -> 16,2,16
0.0, 0.0, 0.0, 1.0, 0.125, 1.0,
// include the stable shape boxes as well
0.0, 0.875, 0.0, 1.0, 1.0, 1.0,
0.0, 0.0, 0.0, 0.125, 1.0, 0.125,
0.875, 0.0, 0.0, 1.0, 1.0, 0.125,
0.0, 0.0, 0.875, 0.125, 1.0, 1.0,
0.875, 0.0, 0.875, 1.0, 1.0, 1.0
};
// Just define ground plate, no need full boxes as Minecraft handle climbable if player within 0.3125 inset to the center, and was handled by NCP somewhere else
private static final double[] BOTTOM_PLATE = new double[] {0.0, 0.0, 0.0, 1.0, 0.125, 1.0};
private static final double[] UPPER_PLATE = new double[] {0.0, 0.875, 0.0, 1.0, 1.0, 1.0};
private static final double[] ALL_PLATE = new double[] {0.0, 0.875, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.125, 1.0};
// (empty box)
private static final double[] NO_COLLISION = null;
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData data = block.getBlockData();
// If the player is above the block and not sneaking, return the stable full shape.
IPlayerData pData = blockCache.getPlayerData();
if (data instanceof Scaffolding) {
Scaffolding scaff = (Scaffolding) data;
if (pData != null) {
MovingData mData = pData.getGenericInstance(MovingData.class);
boolean hasbottom = false;
// If scaffolding has distance != 0 and is bottom, and player is just above or within tolerance return bottom plate collision
if (scaff.getDistance() != 0 && scaff.isBottom()) {
hasbottom = true;
}
// If player was above the block and not sneaking -> stable collision
// Vanilla: return full stable collision only when the entity is above the block AND not descending.
// 'isDescending' in vanilla is actually the entity's "isShiftKeyDown" (sneak) flag, not a vertical-velocity test.
//System.out.println("scf 1 " + mData.lastY + ">" + (y + 1 - 1e-5) + " " + !pData.isShiftKeyPressed() + " " + y);
if (mData.lastY > (y + 1 - 1e-5) // p_56071_.isAbove(Shapes.block(), p_56070_, true)
&& !pData.isShiftKeyPressed()) {
return hasbottom ? ALL_PLATE : UPPER_PLATE;
}
if (hasbottom && mData.lastY > y + 0.125 - 1e-5) {
//System.out.println("scf 2");
return BOTTOM_PLATE;
}
//System.out.println("scf 3");
return NO_COLLISION;
// TODO: This should be the VISUAL shape (aka: hitbox), not the COLLISION shape.
// We need to distinguish shapes from collision shapes in the API.
// return scaff.isBottom() ? UNSTABLE_SHAPE : STABLE_SHAPE;
}
// Shortcut Visible haven't set pData...
return (scaff.getDistance() != 0 && scaff.isBottom()) ? UNSTABLE_SHAPE : STABLE_SHAPE;
}
// Fallback to a full block. Should never happen.
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData data = block.getBlockData();
if (data instanceof Scaffolding) {
Scaffolding scaff = (Scaffolding) data;
return (scaff.getDistance() != 0 && scaff.isBottom()) ? UNSTABLE_SHAPE : STABLE_SHAPE;
}
return null;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return false;
}
}
@@ -27,8 +27,7 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitSeaPickle implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
BoundingBox bd = block.getBoundingBox();
@@ -56,9 +55,17 @@ public class BukkitSeaPickle implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -16,33 +16,87 @@ package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Container;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitShulkerBox implements BukkitShapeModel {
double FULL_BLOCK[] = {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
//final BlockData blockData = state.getBlockData();
if (state instanceof Container) {
if (!((Container) state).getInventory().getViewers().isEmpty()) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.5, 1.0};
// Base full block
double minX = 0.0, minY = 0.0, minZ = 0.0;
double maxX = 1.0, maxY = 1.0, maxZ = 1.0;
if ((state instanceof ShulkerBox)) {
final ShulkerBox shulker = (ShulkerBox) state;
// Closed shulker. Return full block
if (shulker.getInventory().getViewers().isEmpty()) {
return FULL_BLOCK;
}
// Facing is stored in BlockData, not in ShulkerBox
BlockFace face = BlockFace.UP;
BlockData data = block.getBlockData();
if (data instanceof Directional) {
face = ((Directional) data).getFacing();
}
// Open shulker: extend 0.5 blocks in facing direction
switch (face) {
case UP:
maxY = 1.5;
break;
case DOWN:
minY = -0.5;
break;
case NORTH:
minZ = -0.5;
break;
case SOUTH:
maxZ = 1.5;
break;
case WEST:
minX = -0.5;
break;
case EAST:
maxX = 1.5;
break;
default:
// Should not happen, but just in case... Treat as UP
maxY = 1.5;
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
return new double[]{minX, minY, minZ, maxX, maxY, maxZ};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
}
@@ -25,8 +25,7 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitSlab implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
@@ -48,9 +47,17 @@ public class BukkitSlab implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -0,0 +1,71 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Snow;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitSnow implements BukkitShapeModel {
private static final double[][] SNOW_LAYERS = {
null,
{0.0, 0.0, 0.0, 1.0, 0.125, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.250, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.375, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.5, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.625, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.75, 1.0},
{0.0, 0.0, 0.0, 1.0, 0.875, 1.0},
{0.0, 0.0, 0.0, 1.0, 1.0, 1.0}
};
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
// TODO: Backward Handling
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Snow) {
return SNOW_LAYERS[((Snow)blockData).getLayers() - 1];
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof Snow) {
return ((Snow)blockData).getLayers() - 1;
}
return 0;
}
}
@@ -14,65 +14,128 @@
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import java.util.stream.IntStream;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.data.Bisected;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.Bisected.Half;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.type.Stairs;
import fr.neatmonster.nocheatplus.utilities.collision.ShapeUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitStairs implements BukkitShapeModel {
// Taken from NMS - StairBlock.java
private final double[] topslabs = new double[] {0.0, 0.5, 0.0, 1.0, 1.0, 1.0};
private final double[] bottomslabs = new double[] {0.0, 0.0, 0.0, 1.0, 0.5, 1.0};
private final double[] octet_nnn = new double[] {0.0, 0.0, 0.0, 0.5, 0.5, 0.5};
private final double[] octet_nnp = new double[] {0.0, 0.0, 0.5, 0.5, 0.5, 1.0};
private final double[] octet_pnn = new double[] {0.5, 0.0, 0.0, 1.0, 0.5, 0.5};
private final double[] octet_pnp = new double[] {0.5, 0.0, 0.5, 1.0, 0.5, 1.0};
private final double[] octet_npn = new double[] {0.0, 0.5, 0.0, 0.5, 1.0, 0.5};
private final double[] octet_npp = new double[] {0.0, 0.5, 0.5, 0.5, 1.0, 1.0};
private final double[] octet_ppn = new double[] {0.5, 0.5, 0.0, 1.0, 1.0, 0.5};
private final double[] octet_ppp = new double[] {0.5, 0.5, 0.5, 1.0, 1.0, 1.0};
private final double[][] top_stairs = makeshape(topslabs, octet_nnn, octet_pnn, octet_nnp, octet_pnp);
private final double[][] bottom_stairs = makeshape(bottomslabs, octet_npn, octet_ppn, octet_npp, octet_ppp);
private final int[] shape_by_state = new int[]{12, 5, 3, 10, 14, 13, 7, 11, 13, 7, 11, 14, 8, 4, 1, 2, 4, 1, 2, 8};
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
// TODO: With fake data, this could simply return full bounds.
// final Block block = world.getBlockAt(x, y, z);
// final BlockState state = block.getState();
// final BlockData blockData = state.getBlockData();
//
// if (blockData instanceof Stairs) {
// final Stairs stairs = (Stairs) blockData;
// final Half half = stairs.getHalf();
// //final Shape shape = stairs.getShape();
// // TODO: Refine later, with sub shapes.
// switch (half) {
// case BOTTOM:
// return new double[] {0.0, 0.0, 0.0, 1.0, 0.5, 1.0};
// case TOP:
// return new double[] {0.0, 0.5, 0.0, 1.0, 1.0, 1.0};
// default:
// break;
//
// }
// }
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getState().getBlockData();
if (blockData instanceof Stairs) {
final Stairs stairs = (Stairs) blockData;
final Half half = stairs.getHalf();
switch (half) {
case BOTTOM:
return bottom_stairs[shape_by_state[getShapeStateIndex(stairs)]];
case TOP:
return top_stairs[shape_by_state[getShapeStateIndex(stairs)]];
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
if (blockData instanceof Bisected) {
final Bisected stairs = (Bisected) blockData;
final Half half = stairs.getHalf();
//final Shape shape = stairs.getShape();
// TODO: Refine later, with sub shapes.
switch (half) {
case TOP:
return 0x4;
default:
break;
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
//final Block block = world.getBlockAt(x, y, z);
//final BlockState state = block.getState();
//final BlockData blockData = state.getBlockData();
//if (blockData instanceof Bisected) {
// final Bisected stairs = (Bisected) blockData;
// final Half half = stairs.getHalf();
// switch (half) {
// case TOP:
// return 0x4;
// default:
// break;
// }
//}
return 0;
}
private double[][] makeshape(double[] slab, double[] octet_nn, double[] octet_pn, double[] octet_np, double[] octet_pp) {
return IntStream
.range(0, 16)
.mapToObj((flags) -> makeStairShape(flags, slab, octet_nn, octet_pn, octet_np, octet_pp))
.toArray(double[][]::new);
}
private double[] makeStairShape(int flags, double[] slab, double[] octet_nn, double[] octet_pn, double[] octet_np, double[] octet_pp) {
double[] res = slab;
if ((flags & 1) != 0) {
res = ShapeUtils.merge(res, octet_nn);
}
if ((flags & 2) != 0) {
res = ShapeUtils.merge(res, octet_pn);
}
if ((flags & 4) != 0) {
res = ShapeUtils.merge(res, octet_np);
}
if ((flags & 8) != 0) {
res = ShapeUtils.merge(res, octet_pp);
}
return res;
}
private int getShapeStateIndex(Stairs stair) {
return stair.getShape().ordinal() * 4 + directionToValue(stair.getFacing());
}
private int directionToValue(BlockFace face) {
switch (face) {
default:
case UP:
case DOWN:
return -1;
case NORTH:
return 2;
case SOUTH:
return 0;
case WEST:
return 1;
case EAST:
return 3;
}
}
}
@@ -23,27 +23,34 @@ public class BukkitStatic implements BukkitShapeModel {
private final double[] bounds;
/**
* Initialize with the given height and with full xz-bounds.
*
* @param height
* Constructs a {@code BukkitStatic} block model with full width (no inset) and the specified height.
* This is typically used for regular blocks that occupy the entire block space in the X and Z axes.
*
* @param height the height of the block, corresponding to the Y axis
*/
public BukkitStatic(double height) {
this(0.0, height);
}
/**
* Initialize with the given height and xz-inset.
*
* @param xzInset
* @param height
* Constructs a {@code BukkitStatic} block model with a specified inset on the X and Z axes and the given height.
* This is useful for blocks that do not occupy the full width and height of a block.
*
* @param xzInset the inset on the X and Z axes, reducing the block's width and height
* @param height the height of the block, corresponding to the Y axis
*/
public BukkitStatic(double xzInset, double height) {
this(xzInset, 0.0, xzInset, 1.0 - xzInset, height, 1.0 - xzInset);
}
/**
* Initialize with the given bounds
*
* Constructs a {@code BukkitStatic} block model using explicit bounding box values.
* The {@code bounds} array must have a length that is a multiple of six, where each group of six values
* represents the minimum and maximum coordinates for X, Y, and Z ({@code minX, minY, minZ, maxX, maxY, maxZ}).
* This constructor allows for the definition of complex or custom-shaped blocks.
*
* @param bounds the bounding box values, in groups of six for each box: minX, minY, minZ, maxX, maxY, maxZ
* @throws IllegalArgumentException if the length of {@code bounds} is not a multiple of six
*/
public BukkitStatic(double ...bounds) {
if (bounds.length % 6 != 0) {
@@ -54,15 +61,22 @@ public class BukkitStatic implements BukkitShapeModel {
}
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return bounds;
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -29,15 +29,14 @@ public class BukkitTrapDoor implements BukkitShapeModel {
private static final double openWidth = 0.1875;
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof TrapDoor) {
final TrapDoor trapDoor = (TrapDoor) blockData;
if (trapDoor.isOpen()) {
switch(trapDoor.getFacing()) {
switch (trapDoor.getFacing()) {
case NORTH:
return new double[] {0.0, 0.0, 1.0 - openWidth, 1.0, 1.0, 1.0};
case SOUTH:
@@ -50,19 +49,24 @@ public class BukkitTrapDoor implements BukkitShapeModel {
break;
}
}
else {
return trapDoor.getHalf() == Half.BOTTOM
? new double[] {0.0, 0.0, 0.0, 1.0, closedHeight, 1.0}
: new double[] {0.0, 1.0 - closedHeight, 0.0, 1.0, 1.0, 1.0};
}
return trapDoor.getHalf() == Half.BOTTOM ? new double[] {0.0, 0.0, 0.0, 1.0, closedHeight, 1.0}
: new double[] {0.0, 1.0 - closedHeight, 0.0, 1.0, 1.0, 1.0};
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
@@ -85,4 +89,4 @@ public class BukkitTrapDoor implements BukkitShapeModel {
}
return 0;
}
}
}
@@ -27,16 +27,15 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitTurtleEgg implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
if (Bridge1_13.hasBoundingBox()) {
BoundingBox bd = block.getBoundingBox();
return new double[] {bd.getMinX()-x, bd.getMinY()-y, bd.getMinZ()-z, bd.getMaxX()-x, bd.getMaxY()-y, bd.getMaxZ()-z};
}
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof TurtleEgg) {
final TurtleEgg egg = (TurtleEgg) blockData;
switch (egg.getEggs()) {
@@ -54,9 +53,17 @@ public class BukkitTurtleEgg implements BukkitShapeModel {
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -23,108 +23,184 @@ import org.bukkit.block.BlockState;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.MultipleFacing;
import org.bukkit.block.data.type.Wall;
import org.bukkit.util.BoundingBox;
import fr.neatmonster.nocheatplus.compat.Bridge1_13;
import fr.neatmonster.nocheatplus.compat.versions.ClientVersion;
import fr.neatmonster.nocheatplus.players.IPlayerData;
import fr.neatmonster.nocheatplus.utilities.collision.AxisAlignedBBUtils;
import fr.neatmonster.nocheatplus.utilities.collision.ShapeUtils;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitWall implements BukkitShapeModel {
private final double minXZ;
private final double maxXZ;
private final double height;
private final double sideInset;
private final double[] east;
private final double[] north;
private final double[] west;
private final double[] south;
private final double[] eastB;
private final double[] northB;
private final double[] westB;
private final double[] southB;
private final double[] eastwest;
private final double[] southnorth;
private final double[] baseState;
public BukkitWall(double inset, double height) {
this(inset, 1.0 - inset, height, 0.0);
this(inset, height, inset);
}
public BukkitWall(double inset, double height, double sideInset) {
this(inset, 1.0 - inset, height, sideInset);
this(inset, 1.0 - inset, height, sideInset, 1.0 - sideInset);
}
public BukkitWall(double minXZ, double maxXZ, double height, double sideInset) {
this.minXZ = minXZ;
this.maxXZ = maxXZ;
this.height = height;
this.sideInset = sideInset;
east = new double[] {maxXZ, 0.0, sideInset, 1.0, height, 1.0 - sideInset};
north = new double[] {sideInset, 0.0, 0.0, 1.0 - sideInset, height, minXZ};
west = new double[] {0.0, 0.0, sideInset, minXZ, height, 1.0 - sideInset};
south = new double[] {sideInset, 0.0, maxXZ, 1.0 - sideInset, height, 1.0};
public BukkitWall(double minXZ, double maxXZ, double height, double minSideXZ, double maxSideXZ) {
east = new double[] {maxXZ, 0.0, minSideXZ, 1.0, height, maxSideXZ};
north = new double[] {minSideXZ, 0.0, 0.0, maxSideXZ, height, minXZ};
west = new double[] {0.0, 0.0, minSideXZ, minXZ, height, maxSideXZ};
south = new double[] {minSideXZ, 0.0, maxXZ, maxSideXZ, height, 1.0};
eastB = new double[] {maxXZ, 0.0, minXZ, 1.0, height, maxXZ};
northB = new double[] {minXZ, 0.0, 0.0, maxXZ, height, minXZ};
westB = new double[] {0.0, 0.0, minXZ, minXZ, height, maxXZ};
southB = new double[] {minXZ, 0.0, maxXZ, maxXZ, height, 1.0};
eastwest = new double[] {0.0, 0.0, minSideXZ, 1.0, height, maxSideXZ};
southnorth = new double[] {minSideXZ, 0.0, 0.0, maxSideXZ, height, 1.0};
baseState = new double[] {minXZ, 0.0, minXZ, maxXZ, height, maxXZ};
}
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
// Relevant: https://bugs.mojang.com/browse/MC-9565
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
if (blockData instanceof MultipleFacing) {
final MultipleFacing fence = (MultipleFacing) blockData;
double[] res = new double[] {minXZ, 0.0, minXZ, maxXZ, height, maxXZ};
final Set<BlockFace> a = fence.getFaces();
if (!a.contains(BlockFace.UP) && a.size() == 2) {
if (a.contains(BlockFace.SOUTH)) {
return new double[] {sideInset, 0.0, 0.0, 1.0 - sideInset, height, 1.0};
}
if (a.contains(BlockFace.WEST)) {
return new double[] {0.0, 0.0, sideInset, 1.0, height, 1.0 - sideInset};
}
}
for (final BlockFace face : fence.getFaces()) {
switch (face) {
case EAST:
res = add(res, east);
break;
case NORTH:
res = add(res, north);
break;
case WEST:
res = add(res, west);
break;
case SOUTH:
res = add(res, south);
break;
default:
break;
}
final IPlayerData data = blockCache.getPlayerData();
final boolean legacy = data != null && data.getClientVersion().isLowerThan(ClientVersion.V_1_13);
if (Bridge1_13.hasBuiltInRayTracing() && !legacy) {
double[] res = {};
for (BoundingBox box : block.getCollisionShape().getBoundingBoxes()) {
res = ShapeUtils.add(res, AxisAlignedBBUtils.toArray(box));
}
if (res.length == 0) return null;
return res;
} else if (blockData instanceof Wall) {
final Wall wall = (Wall) blockData;
if (wall.isUp()) {
double[] res = new double[] {minXZ, 0.0, minXZ, maxXZ, height, maxXZ};
if (!wall.getHeight(BlockFace.WEST).equals(Wall.Height.NONE)) res = add(res, west);
if (!wall.getHeight(BlockFace.EAST).equals(Wall.Height.NONE)) res = add(res, east);
if (!wall.getHeight(BlockFace.NORTH).equals(Wall.Height.NONE)) res = add(res, north);
if (!wall.getHeight(BlockFace.SOUTH).equals(Wall.Height.NONE)) res = add(res, south);
return res;
} else {
if (!wall.getHeight(BlockFace.WEST).equals(Wall.Height.NONE) && !wall.getHeight(BlockFace.EAST).equals(Wall.Height.NONE)) {
return new double[] {0.0, 0.0, sideInset, 1.0, height, 1.0 - sideInset};
} else {
final BlockState state = block.getState();
final BlockData blockData = state.getBlockData();
boolean east = false;
boolean north = false;
boolean west = false;
boolean south = false;
boolean up = false;
if (blockData instanceof MultipleFacing) {
MultipleFacing fence = (MultipleFacing) blockData;
Set<BlockFace> faces = fence.getFaces();
up = faces.contains(BlockFace.UP);
for (final BlockFace face : fence.getFaces()) {
switch (face) {
case EAST:
east = true;
break;
case NORTH:
north = true;
break;
case WEST:
west = true;
break;
case SOUTH:
south = true;
break;
default:
break;
}
}
if (!wall.getHeight(BlockFace.NORTH).equals(Wall.Height.NONE) && !wall.getHeight(BlockFace.SOUTH).equals(Wall.Height.NONE)) {
return new double[] {sideInset, 0.0, 0.0, 1.0 - sideInset, height, 1.0};
}
else if (blockData instanceof Wall) {
final Wall wall = (Wall) blockData;
up = wall.isUp();
if (!wall.getHeight(BlockFace.WEST).equals(Wall.Height.NONE)) {
west = true;
}
if (!wall.getHeight(BlockFace.EAST).equals(Wall.Height.NONE)) {
east = true;
}
if (!wall.getHeight(BlockFace.NORTH).equals(Wall.Height.NONE)) {
north = true;
}
if (!wall.getHeight(BlockFace.SOUTH).equals(Wall.Height.NONE)) {
south = true;
}
}
if (legacy && east && west && south && north) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.5, 1.0};
}
double tmp[] = new double[0];
if (east && west) {
if (legacy) {
if (south) {
return new double[] {0.0, 0.0, 0.25, 1.0, 1.5, 1.0};
}
if (north) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.5, 0.75};
}
}
tmp = eastwest;
east = west = false;
} else if (south && north) {
if (legacy) {
if (west) {
return new double[] {0.0, 0.0, 0.0, 0.75, 1.5, 1.0};
}
if (east) {
return new double[] {0.25, 0.0, 0.0, 1.0, 1.5, 1.0};
}
}
tmp = southnorth;
south = north = false;
}
if (legacy) {
if (south && west) {return new double[] {0.0, 0.0, 0.25, 0.75, 1.5, 1.0};}
if (south && east) {return new double[] {0.25, 0.0, 0.25, 1.0, 1.5, 1.0};}
if (north && west) {return new double[] {0.0, 0.0, 0.0, 0.75, 1.5, 0.75};}
if (north && east) {return new double[] {0.25, 0.0, 0.0, 1.0, 1.5, 0.75};}
}
if (south) {
tmp = ShapeUtils.add(tmp, legacy ? this.southB : this.south);
}
if (north) {
tmp = ShapeUtils.add(tmp, legacy ? this.northB : this.north);
}
if (east) {
tmp = ShapeUtils.add(tmp, legacy ? this.eastB : this.east);
}
if (west) {
tmp = ShapeUtils.add(tmp, legacy ? this.westB : this.west);
}
if (tmp.length == 0 || up) {
tmp = ShapeUtils.add(tmp, this.baseState);
}
return tmp;
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
double a[] = getShape(blockCache, world, x, y, z);
for (int i = 1; i < (int)a.length / 6; i++) a[i*6-2] = 1.0;
return a;
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
// TODO: Which one is better, return true and cap the height or return false and fetch twice?
// NOTE: Should be no different as current implementation doesn't do exact ray trace check
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
private double[] add(final double[] array1, final double[] array2) {
final double[] newArray = new double[array1.length + array2.length];
System.arraycopy(array1, 0, newArray, 0, array1.length);
System.arraycopy(array2, 0, newArray, array1.length, array2.length);
return newArray;
}
}
}
@@ -25,33 +25,40 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitWallHead implements BukkitShapeModel {
@Override
public double[] getShape(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
public double[] getShape(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
final Block block = world.getBlockAt(x, y, z);
final BlockData blockData = block.getBlockData();
if (blockData instanceof Directional) {
BlockFace face = ((Directional) blockData).getFacing();
switch (face) {
case NORTH:
return new double[] {0.25, 0.25, 0.5, 0.75, 0.75, 1.0};
case SOUTH:
return new double[] {0.25, 0.25, 0.0, 0.75, 0.75, 0.5};
case WEST:
return new double[] {0.5, 0.25, 0.25, 1.0, 0.75, 0.75};
case EAST:
return new double[] {0.0, 0.25, 0.25, 0.5, 0.75, 0.75};
default:
break;
case NORTH:
return new double[] {0.25, 0.25, 0.5, 0.75, 0.75, 1.0};
case SOUTH:
return new double[] {0.25, 0.25, 0.0, 0.75, 0.75, 0.5};
case WEST:
return new double[] {0.5, 0.25, 0.25, 1.0, 0.75, 0.75};
case EAST:
return new double[] {0.0, 0.25, 0.25, 0.5, 0.75, 0.75};
default:
break;
}
}
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
@Override
public int getFakeData(final BlockCache blockCache,
final World world, final int x, final int y, final int z) {
return 0;
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(final BlockCache blockCache, final World world, final int x, final int y, final int z) {
return 0;
}
}
@@ -0,0 +1,50 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.bukkit.model;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Waterlogged;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class BukkitWaterPlant implements BukkitShapeModel {
@Override
public double[] getShape(BlockCache blockCache, World world, int x, int y, int z) {
final Block blockAbove = world.getBlockAt(x, y + 1, z);
final BlockData blockDataAbove = blockAbove.getBlockData();
if (blockDataAbove instanceof Waterlogged && ((Waterlogged)blockDataAbove).isWaterlogged()) {
return new double[] {0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
}
return new double[] {0.0, 0.0, 0.0, 1.0, 8 / 9f, 1.0};
}
@Override
public double[] getVisualShape(BlockCache blockCache, World world, int x, int y, int z) {
return getShape(blockCache, world, x, y, z);
}
@Override
public boolean isCollisionSameVisual(BlockCache blockCache, World world, int x, int y, int z) {
return true;
}
@Override
public int getFakeData(BlockCache blockCache, World world, int x, int y, int z) {
return 0;
}
}
@@ -19,10 +19,51 @@ import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public interface ShapeModel<W> {
// TODO: Rather fill in all into node directly (data as well), avoid redundant casting etc.
// TODO: Best route passable workaround through here too (base on a flag), + getGroundMinHeight?.
// TODO: Refine +- might have BukkitBlockCacheNode etc.
/**
* Get the <i>collision</i> shape of the block at the given position. <br>
* <strong> Do note that not all blocks have a collision shape, like all plants/farmable blocks, which do have a visual shape that can be interacted with, but don't have a collision one;
* other have a collision shape that exceeds their visual one, like fences, which have a height of 1.0 block visually, but 1.5 collision-wise and such. </strong> <br>
* Most of the time, the collision shape will be the same as its visual shape, but not always. <br>
* To check for any divergence, use {@link #isCollisionSameVisual(BlockCache, W, int, int, int)}. <br>
*
* @param blockCache The block cache.
* @param world The world.
* @param x The x coordinate of the block.
* @param y The y coordinate of the block.
* @param z The z coordinate of the block.
* @return An array of doubles representing the collision shape, in the format
* {minX, minY, minZ, maxX, maxY, maxZ, ...} for each box in the shape.
* Coordinates are in the range [0.0, 1.0].
*/
public double[] getShape(BlockCache blockCache, W world, int x, int y, int z);
/**
* Tell if collision shape is the same as visual shape <br>
*
* @param blockCache
* @param world
* @param x
* @param y
* @param z
* @return if true
*/
public boolean isCollisionSameVisual(BlockCache blockCache, W world, int x, int y, int z);
/**
* Get the visual shape of the block at the given position. <br>
* Call this method if dealing with visual interactions, like ray tracing for line of sight, block targeting, etc. <br>
* @See {@link #getShape(BlockCache, W, int, int, int)} for collision shape. <br>
*
* @param blockCache
* @param world
* @param x
* @param y
* @param z
* @return
*/
public double[] getVisualShape(BlockCache blockCache, W world, int x, int y, int z);
/**
* Allow faking data.
@@ -17,6 +17,7 @@ package fr.neatmonster.nocheatplus.compat.cbreflect;
import org.bukkit.World;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.compat.bukkit.BlockCacheBukkit;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectHelper;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectHelper.ReflectFailureException;
@@ -44,8 +45,30 @@ public class BlockCacheCBReflect extends BlockCacheBukkit {
@Override
public double[] fetchBounds(int x, int y, int z) {
final org.bukkit.Material mat = getType(x, y, z);
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
try {
return helper.nmsWorld_fetchBlockShape(this.nmsWorld, this.getType(x, y, z), x, y, z);
return LegacyBlocks.adjustBounds(this, mat, x, y, z, helper.nmsWorld_fetchBlockShape(this.nmsWorld, this.getType(x, y, z), x, y, z));
}
catch (ReflectFailureException ex) {
return super.fetchBounds(x, y, z);
}
}
@Override
public boolean isCollisionSameVisual(int x, int y, int z) {
final org.bukkit.Material mat = getType(x, y, z);
return LegacyBlocks.isCollisionSameVisual(this, mat, x, y, z);
}
@Override
public double[] fetchVisualBounds(int x, int y, int z) {
final org.bukkit.Material mat = getType(x, y, z);
final double[] shape = LegacyBlocks.getVisualShape(this, mat, x, y, z);
if (shape != null) return shape;
try {
return LegacyBlocks.adjustBounds(this, mat, x, y, z, helper.nmsWorld_fetchBlockShape(this.nmsWorld, this.getType(x, y, z), x, y, z));
}
catch (ReflectFailureException ex) {
return super.fetchBounds(x, y, z);
@@ -22,7 +22,7 @@ import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.NCPAPIProvider;
import fr.neatmonster.nocheatplus.compat.AlmostBoolean;
import fr.neatmonster.nocheatplus.compat.bukkit.BlockCacheBukkit;
import fr.neatmonster.nocheatplus.compat.bukkit.MCAccessBukkitModern;
import fr.neatmonster.nocheatplus.compat.bukkit.MCAccessBukkit;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectHelper;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectHelper.ReflectFailureException;
import fr.neatmonster.nocheatplus.compat.versions.GenericVersion;
@@ -31,7 +31,7 @@ import fr.neatmonster.nocheatplus.logging.Streams;
import fr.neatmonster.nocheatplus.utilities.location.LocUtil;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
public class MCAccessCBReflect extends MCAccessBukkitModern {
public class MCAccessCBReflect extends MCAccessBukkit {
protected final ReflectHelper helper;
@@ -49,11 +49,11 @@ public class MCAccessCBReflect extends MCAccessBukkitModern {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.INIT, "The Minecraft version could not be detected, Compat-CB-Reflect might or might not work.");
this.knownSupportedVersion = false;
}
else if (GenericVersion.compareVersions(mcVersion, "1.4.5") < 0) {
else if (GenericVersion.compareVersions(mcVersion, "1.5") < 0) {
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.INIT, "The Minecraft version seems to be older than what Compat-CB-Reflect can support.");
this.knownSupportedVersion = false;
}
else if (GenericVersion.compareVersions(mcVersion, "1.14.4") > 0) {
else if (GenericVersion.compareVersions(mcVersion, "1.12.2") > 0) {
this.knownSupportedVersion = false;
NCPAPIProvider.getNoCheatPlusAPI().getLogManager().warning(Streams.INIT, "The Minecraft version seems to be more recent than the one Compat-CB-Reflect has been built with - this might work, but there could be incompatibilities.");
} else {
@@ -70,8 +70,7 @@ public class MCAccessCBReflect extends MCAccessBukkitModern {
@Override
public String getMCVersion() {
// Potentially all :p.
return "1.7-1.14.4|?";
return "1.5-1.12.2";
}
@Override
@@ -20,9 +20,13 @@ import java.util.UUID;
import org.bukkit.entity.Player;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.compat.AttribUtil;
import fr.neatmonster.nocheatplus.components.modifier.IAttributeAccess;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import fr.neatmonster.nocheatplus.utilities.map.MaterialUtil;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class ReflectAttributeAccess implements IAttributeAccess {
@@ -146,17 +150,7 @@ public class ReflectAttributeAccess implements IAttributeAccess {
throw new RuntimeException("Not available.");
}
}
@Override
public double getSpeedAttributeMultiplier(Player player) {
return getSpeedAttributeMultiplier(player, true);
}
@Override
public double getSprintAttributeMultiplier(Player player) {
return nmsAttributeInstance_getSprintAttributeModifierMultiplier(getMovementSpeedAttributeInstance(player));
}
/**
* Get the speed attribute (MOVEMENT_SPEED) for a player.
* @param handle EntityPlayer
@@ -165,9 +159,9 @@ public class ReflectAttributeAccess implements IAttributeAccess {
private Object getMovementSpeedAttributeInstance(Player player) {
return ReflectionUtil.invokeMethod(this.reflectPlayer.nmsGetAttributeInstance, getHandle(player), this.reflectGenericAttributes.nmsMOVEMENT_SPEED);
}
/**
*
*
* @param player
* @param removeSprint If to calculate away the sprint boost modifier.
* @return
@@ -188,7 +182,7 @@ public class ReflectAttributeAccess implements IAttributeAccess {
}
}
}
/**
* (Not an existing method.)
* @param attributeInstance
@@ -202,10 +196,102 @@ public class ReflectAttributeAccess implements IAttributeAccess {
return AttribUtil.getMultiplier((Integer) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeModifier.nmsGetOperation, mod), (Double) ReflectionUtil.invokeMethodNoArgs(this.reflectAttributeModifier.nmsGetValue, mod));
}
}
private Object getHandle(Player player) {
Object handle = ReflectionUtil.invokeMethodNoArgs(this.reflectPlayer.obcGetHandle, player);
return handle;
}
@Override
public double getSpeedMultiplier(Player player) {
return getSpeedAttributeMultiplier(player, true);
}
@Override
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getSprintMultiplier(Player player) {
return nmsAttributeInstance_getSprintAttributeModifierMultiplier(getMovementSpeedAttributeInstance(player));
}
@Override
public double getGravity(Player player) {
return Magic.DEFAULT_GRAVITY;
}
@Override
public double getSafeFallDistance(Player player) {
return Magic.FALL_DAMAGE_DIST;
}
@Override
public double getFallDamageMultiplier(Player player) {
return 1.0;
}
@Override
public double getBreakingSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getJumpGainMultiplier(Player player) {
return 1.0;
}
@Override
public double getPlayerSneakingFactor(Player player) {
return Magic.SNEAK_MULTIPLIER;
}
@Override
public double getPlayerMaxBlockReach(Player player) {
return 4.5;
}
@Override
public double getPlayerMaxAttackReach(Player player) {
return 3.0;
}
@Override
public double getMaxStepUp(Player player) {
if (player.isInsideVehicle()) {
if (player.getVehicle() != null && MaterialUtil.isBoat(player.getVehicle().getType())) {
return 0.0;
}
return 1.0;
}
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
@Override
public float getMovementEfficiency(Player player) {
return 0f;
}
@Override
public float getWaterMovementEfficiency(Player player) {
return 0f;
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getMiningEfficiency(Player player) {
return 0f;
}
@Override
public double getEntityScale(Player player) {
return 1.0;
}
}
@@ -17,10 +17,11 @@ package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.bukkit.Material;
import fr.neatmonster.nocheatplus.compat.cbreflect.reflect.ReflectHelper.ReflectFailureException;
import fr.neatmonster.nocheatplus.compat.versions.ServerVersion;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import org.bukkit.Material;
/**
* Reflection for block shape getting (latest).
@@ -14,6 +14,8 @@
*/
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
@@ -55,6 +57,7 @@ public class ReflectBlockSix implements IReflectBlock {
/** (static) */
public final Method nmsGetById;
public final Object nmsById;
public final Method nmsGetMaterial;
public final boolean useBlockPosition;
@@ -75,6 +78,11 @@ public class ReflectBlockSix implements IReflectBlock {
final Class<?> clazz = Class.forName(base.nmsPackageName + ".Block");
// byID (static)
nmsGetById = ReflectionUtil.getMethod(clazz, "getById", int.class);
final Class<?> blockArray = Array.newInstance(clazz, 0).getClass();
final Field byIdField = ReflectionUtil.getField(clazz, "byId", blockArray);
nmsById = byIdField == null ? null : ReflectionUtil.get(byIdField, blockArray, null);
// getMaterial
nmsGetMaterial = ReflectionUtil.getMethodNoArgs(clazz, "getMaterial");
// updateShape
@@ -215,6 +223,9 @@ public class ReflectBlockSix implements IReflectBlock {
@SuppressWarnings("deprecation")
@Override
public Object nms_getByMaterial(final Material id) {
if (this.nmsById != null) {
return Array.get(nmsById, id.getId());
}
if (this.nmsGetById == null) {
fail();
}
@@ -258,7 +269,7 @@ public class ReflectBlockSix implements IReflectBlock {
@Override
public boolean isFetchBoundsAvailable() {
return nmsGetById != null && nmsUpdateShape != null && nmsGetMinX != null;
return (nmsGetById != null || nmsById != null) && nmsUpdateShape != null && nmsGetMinX != null;
}
}
@@ -0,0 +1,77 @@
/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.neatmonster.nocheatplus.compat.cbreflect.reflect;
import java.lang.reflect.Method;
import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
public class ReflectDamageSources {
public Class<?> nmsClass;
public Method nmsDamageSources;
public Method nmsfall;
public ReflectDamageSources(ReflectBase base, ReflectDamageSource reflectDamageSource) throws ClassNotFoundException {
this(base, reflectDamageSource, Class.forName(base.nmsPackageName + ".Entity"));
}
public ReflectDamageSources(ReflectBase base, ReflectDamageSource reflectDamageSource, Class<?> nmsEntityClass) throws ClassNotFoundException {
nmsClass = Class.forName("net.minecraft.world.damagesource.DamageSources");
nmsfall = ReflectionUtil.getMethodNoArgs(nmsClass, "k", reflectDamageSource.nmsClass);
// 1.19 Entity.damageSources()
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dG", nmsClass);
// 1.20
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dJ", nmsClass);
}
// 1.20.2
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dM", nmsClass);
}
// 1.20.4
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dN", nmsClass);
}
// 1.20.5-1.20.6
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dQ", nmsClass);
}
// 1.21
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dP", nmsClass);
nmsfall = ReflectionUtil.getMethodNoArgs(nmsClass, "l", reflectDamageSource.nmsClass);
}
// 1.21.2-1.21.3
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "dX", nmsClass);
nmsfall = ReflectionUtil.getMethodNoArgs(nmsClass, "l", reflectDamageSource.nmsClass);
}
// 1.21.8 and possibly earlier down to .4
if (nmsDamageSources == null) {
nmsDamageSources = ReflectionUtil.getMethodNoArgs(nmsEntityClass, "ea", nmsClass);
// TODO: Check
// nmsfall = ReflectionUtil.getMethodNoArgs(nmsClass, "l", reflectDamageSource.nmsClass);
}
}
public Object getDamageSource(Object handle) {
if (nmsDamageSources == null || nmsfall == null) return null;
Object damageSources = ReflectionUtil.invokeMethodNoArgs(nmsDamageSources, handle);
return ReflectionUtil.invokeMethodNoArgs(nmsfall, damageSources);
}
}
@@ -40,6 +40,8 @@ public class ReflectEntity extends ReflectGetHandleBase<Entity> {
public final Method nmsDamageEntity;
private final Method nmsDamageEntityNew;
@MostlyHarmless()
public final Method nmsclearActiveItem;
@@ -62,14 +64,17 @@ public class ReflectEntity extends ReflectGetHandleBase<Entity> {
nmsDead = ReflectionUtil.getField(nmsClass, "dead", boolean.class);
// damageEntity(...)
nmsDamageEntity = ReflectionUtil.getMethod(nmsClass, "damageEntity",
new Class<?>[]{damageSource.nmsClass, float.class}, new Class<?>[]{damageSource.nmsClass, int.class});
// boolean hurt(net.minecraft.world.damagesource.DamageSource,float) -> a
nmsDamageEntityNew = ReflectionUtil.getMethod(nmsClass, "a", new Class<?>[]{damageSource.nmsClass, float.class});
nmsDamageEntity = nmsDamageEntityNew != null ? nmsDamageEntityNew :
ReflectionUtil.getMethod(nmsClass, "damageEntity",
new Class<?>[]{damageSource.nmsClass, float.class}, new Class<?>[]{damageSource.nmsClass, int.class});
if (nmsDamageEntity != null) {
nmsDamageEntityInt = nmsDamageEntity.getParameterTypes()[1] == int.class;
} else {
nmsDamageEntityInt = true; // Uncertain.
}
nmsclearActiveItem = ReflectionUtil.getMethodNoArgs(nmsClass, "clearActiveItem");
nmsclearActiveItem = seekClearActiveItemMethod(nmsClass);
// getBoundingBox
if (reflectAxisAlignedBB == null) {
@@ -80,6 +85,25 @@ public class ReflectEntity extends ReflectGetHandleBase<Entity> {
}
}
private Method seekClearActiveItemMethod(Class<?> nmsClass) {
// void releaseUsingItem() -> fL (1.21.8 and possibly down to .4)
// fE(1.21.2-1.21.3)
// fw(1.21-1.21.1)
// fA(1.20.5-1.20.6)
// fs(1.20.4)
// fr(1.20.2)
// fn(1.20)
// fj(1.19-19.4)
// eR(???)
// clearActiveItem(1.13-???)
String[] methodname = {"fL", "fE", "fw", "fA", "fs", "fr", "fn", "fj", "eR", "clearActiveItem", "releaseUsingItem"};
for (String name : methodname) {
Method method = ReflectionUtil.getMethodNoArgs(nmsClass, name);
if (method != null) return method;
}
return null;
}
@Override
protected void fail() {
// Unused.
+9 -20
View File
@@ -24,7 +24,7 @@
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcbdev</artifactId>
<artifactId>ncpcompatspigotcb1_12_r1</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<!-- ... -->
@@ -133,23 +133,12 @@
</dependencies>
</profile>
<profile>
<id>cbdev</id>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcbdev</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>spigot1_12_r1</id>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcbdev</artifactId>
<artifactId>ncpcompatspigotcb1_12_r1</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
@@ -221,10 +210,14 @@
</dependencies>
</profile>
<!-- Legacy, unsupported
<profile>
<id>cblegacy</id>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb3100</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb3043</artifactId>
@@ -270,16 +263,12 @@
<artifactId>ncpcompatcb2645</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<!-- Legacy, unsupported
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2602</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb3100</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2545</artifactId>
@@ -290,9 +279,9 @@
<artifactId>ncpcompatcb2512</artifactId>
<version>1.1-SNAPSHOT</version>
</dependency>
-->
</dependencies>
</profile>
-->
</profiles>
</project>
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2645</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2645</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2645</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB 2645 (MC 1.5).
</description>
<name>NCPCompatCB2645</name>
<description>Compatibility for CB2645 (MC 1.5).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5-R0.1</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.5-R0.1-20130317.180842-21.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -22,6 +22,7 @@ import org.bukkit.craftbukkit.v1_5_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_5_R1.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_5_R1.AxisAlignedBB;
import net.minecraft.server.v1_5_R1.EntityBoat;
@@ -109,10 +110,13 @@ public class BlockCacheCB2645 extends BlockCache {
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final org.bukkit.Material mat = getType(x, y, z);
@SuppressWarnings("deprecation")
final int id = getType(x, y, z).getId();
final int id = mat.getId();
final net.minecraft.server.v1_5_R1.Block block = net.minecraft.server.v1_5_R1.Block.byId[id];
if (block == null) return null;
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
block.updateShape(iBlockAccess, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
@@ -183,6 +183,11 @@ public class MCAccessCB2645 implements MCAccess {
return AlmostBoolean.NO;
}
@Override
public boolean resetActiveItem(Player player) {
return false;
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2691</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2691</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5.1-R0.3-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2691</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB2691 (1.5.1-R0.1 beta release).
</description>
<name>NCPCompatCB2691</name>
<description>Compatibility for CB2691 (MC 1.5.1-R0.2 beta release).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5.1-R0.2</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.5.1-R0.2-SNAPSHOT.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -22,6 +22,7 @@ import org.bukkit.craftbukkit.v1_5_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_5_R2.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_5_R2.AxisAlignedBB;
import net.minecraft.server.v1_5_R2.EntityBoat;
@@ -109,10 +110,13 @@ public class BlockCacheCB2691 extends BlockCache {
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final org.bukkit.Material mat = getType(x, y, z);
@SuppressWarnings("deprecation")
final int id = getType(x, y, z).getId();
final int id = mat.getId();
final net.minecraft.server.v1_5_R2.Block block = net.minecraft.server.v1_5_R2.Block.byId[id];
if (block == null) return null;
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
block.updateShape(iBlockAccess, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
@@ -185,6 +185,11 @@ public class MCAccessCB2691 implements MCAccess{
return AlmostBoolean.NO;
}
@Override
public boolean resetActiveItem(Player player) {
return false;
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2763</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2763</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5.2-R1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2763</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB 2763 (MC 1.5.2).
</description>
<name>NCPCompatCB2763</name>
<description>Compatibility for CB2763 (MC 1.5.2).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.5.2-R1.0</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.5.2-R1.0.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -22,6 +22,7 @@ import org.bukkit.craftbukkit.v1_5_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_5_R3.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_5_R3.AxisAlignedBB;
import net.minecraft.server.v1_5_R3.EntityBoat;
@@ -107,11 +108,13 @@ public class BlockCacheCB2763 extends BlockCache {
@Override
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final org.bukkit.Material mat = getType(x, y, z);
final int id = iBlockAccess.getTypeId(x, y, z);
final net.minecraft.server.v1_5_R3.Block block = net.minecraft.server.v1_5_R3.Block.byId[id];
if (block == null) return null;
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
block.updateShape(iBlockAccess, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
@@ -184,6 +184,11 @@ public class MCAccessCB2763 implements MCAccess{
return AlmostBoolean.NO;
}
@Override
public boolean resetActiveItem(Player player) {
return false;
}
// @Override
// public void correctDirection(final Player player) {
// final EntityPlayer mcPlayer = ((CraftPlayer) player).getHandle();
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2794</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2794</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2794</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB 2794 (MC 1.6.1).
</description>
<name>NCPCompatCB2794</name>
<description>Compatibility for CB2794 (MC 1.6.1).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.1-R0.1</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.6.1-R0.1-SNAPSHOT.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -23,6 +23,10 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import net.minecraft.server.v1_6_R1.AttributeInstance;
import net.minecraft.server.v1_6_R1.AttributeModifier;
import net.minecraft.server.v1_6_R1.GenericAttributes;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class AttributeAccess implements IAttributeAccess {
@@ -33,25 +37,106 @@ public class AttributeAccess implements IAttributeAccess {
}
@Override
public double getSpeedAttributeMultiplier(Player player) {
public double getSpeedMultiplier(Player player) {
final AttributeInstance attr = ((CraftLivingEntity) player).getHandle().a(GenericAttributes.d);
double val = attr.e() / attr.b();
final AttributeModifier mod = attr.a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return val;
} else {
}
else {
return val / AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
@Override
public double getSprintAttributeMultiplier(Player player) {
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getSprintMultiplier(Player player) {
final AttributeModifier mod = ((CraftLivingEntity) player).getHandle().a(GenericAttributes.d).a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return 1.0;
} else {
}
else {
return AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
////////////////////////////////////////////////////////////////
// Modern attributes. Not available for legacy versions. //
////////////////////////////////////////////////////////////////
@Override
public double getGravity(Player player) {
return Magic.DEFAULT_GRAVITY;
}
@Override
public double getSafeFallDistance(Player player) {
return Magic.FALL_DAMAGE_DIST;
}
@Override
public double getFallDamageMultiplier(Player player) {
return 1.0;
}
@Override
public double getBreakingSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getJumpGainMultiplier(Player player) {
return 1.0;
}
@Override
public double getPlayerSneakingFactor(Player player) {
return Magic.SNEAK_MULTIPLIER;
}
@Override
public double getPlayerMaxBlockReach(Player player) {
return 4.5;
}
@Override
public double getPlayerMaxAttackReach(Player player) {
return 3.0;
}
@Override
public double getMaxStepUp(Player player) {
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
@Override
public float getMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public float getWaterMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getMiningEfficiency(Player player) {
return 0.0;
}
@Override
public double getEntityScale(Player player) {
return 1.0;
}
}
@@ -22,6 +22,7 @@ import org.bukkit.craftbukkit.v1_6_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_6_R1.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_6_R1.AxisAlignedBB;
import net.minecraft.server.v1_6_R1.EntityBoat;
@@ -109,10 +110,13 @@ public class BlockCacheCB2794 extends BlockCache {
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final org.bukkit.Material mat = getType(x, y, z);
@SuppressWarnings("deprecation")
final int id = getType(x, y, z).getId();
final int id = mat.getId();
final net.minecraft.server.v1_6_R1.Block block = net.minecraft.server.v1_6_R1.Block.byId[id];
if (block == null) return null;
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
block.updateShape(iBlockAccess, x, y, z);
// minX, minY, minZ, maxX, maxY, maxZ
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2808</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2808</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.2-R1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2808</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB2808 (MC 1.6.2).
</description>
<name>NCPCompatCB2808</name>
<description>Compatibility for CB2808 (MC 1.6.2).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.2-R0.1</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.6.2-R0.1-SNAPSHOT.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -23,6 +23,9 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import net.minecraft.server.v1_6_R2.AttributeInstance;
import net.minecraft.server.v1_6_R2.AttributeModifier;
import net.minecraft.server.v1_6_R2.GenericAttributes;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class AttributeAccess implements IAttributeAccess {
@@ -33,25 +36,107 @@ public class AttributeAccess implements IAttributeAccess {
}
@Override
public double getSpeedAttributeMultiplier(Player player) {
public double getSpeedMultiplier(Player player) {
final AttributeInstance attr = ((CraftLivingEntity) player).getHandle().getAttributeInstance(GenericAttributes.d);
final double val = attr.getValue() / attr.b();
final AttributeModifier mod = attr.a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return val;
} else {
}
else {
return val / AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
@Override
public double getSprintAttributeMultiplier(Player player) {
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getSprintMultiplier(Player player) {
final AttributeModifier mod = ((CraftLivingEntity) player).getHandle().getAttributeInstance(GenericAttributes.d).a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return 1.0;
} else {
}
else {
return AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
////////////////////////////////////////////////////////////////
// Modern attributes. Not available for legacy versions. //
////////////////////////////////////////////////////////////////
@Override
public double getGravity(Player player) {
return Magic.DEFAULT_GRAVITY;
}
@Override
public double getSafeFallDistance(Player player) {
return Magic.FALL_DAMAGE_DIST;
}
@Override
public double getFallDamageMultiplier(Player player) {
return 1.0;
}
@Override
public double getBreakingSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getJumpGainMultiplier(Player player) {
return 1.0;
}
@Override
public double getPlayerSneakingFactor(Player player) {
return Magic.SNEAK_MULTIPLIER;
}
@Override
public double getPlayerMaxBlockReach(Player player) {
return 4.5;
}
@Override
public double getPlayerMaxAttackReach(Player player) {
return 3.0;
}
@Override
public double getMaxStepUp(Player player) {
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
@Override
public float getMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public float getWaterMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getMiningEfficiency(Player player) {
return 0.0;
}
@Override
public double getEntityScale(Player player) {
return 1.0;
}
}
@@ -22,6 +22,7 @@ import org.bukkit.craftbukkit.v1_6_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_6_R2.entity.CraftEntity;
import org.bukkit.entity.Entity;
import fr.neatmonster.nocheatplus.compat.blocks.LegacyBlocks;
import fr.neatmonster.nocheatplus.utilities.map.BlockCache;
import net.minecraft.server.v1_6_R2.AxisAlignedBB;
import net.minecraft.server.v1_6_R2.EntityBoat;
@@ -109,10 +110,13 @@ public class BlockCacheCB2808 extends BlockCache {
public double[] fetchBounds(final int x, final int y, final int z){
// TODO: change api for this / use nodes (!)
final org.bukkit.Material mat = getType(x, y, z);
@SuppressWarnings("deprecation")
final int id = getType(x, y, z).getId();
final int id = mat.getId();
final net.minecraft.server.v1_6_R2.Block block = net.minecraft.server.v1_6_R2.Block.byId[id];
if (block == null) return null;
final double[] shape = LegacyBlocks.getShape(this, mat, x, y, z, true);
if (shape != null) return shape;
block.updateShape(iBlockAccess, x, y, z); // TODO: use THIS instead of world.
// minX, minY, minZ, maxX, maxY, maxZ
+28 -40
View File
@@ -1,46 +1,34 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatcb2882</artifactId>
<packaging>jar</packaging>
<name>NCPCompatCB2882</name>
<version>1.1-SNAPSHOT</version>
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>nocheatplus-parent</artifactId>
<version>1.1-SNAPSHOT</version>
</parent>
<parent>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcompatnonfree</artifactId>
<version>1.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
<artifactId>ncpcompatcb2882</artifactId>
<version>1.1-SNAPSHOT</version>
<description>Compatibility for CB2882 (MC 1.6.4).
</description>
<name>NCPCompatCB2882</name>
<description>Compatibility for CB2882 (MC 1.6.4).</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>fr.neatmonster</groupId>
<artifactId>ncpcore</artifactId>
<version>1.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
<version>1.6.4-R2.0</version>
<scope>system</scope>
<systemPath>${basedir}/libs/craftbukkit-1.6.4-R2.0.jar</systemPath>
</dependency>
</dependencies>
</project>
</project>
@@ -23,6 +23,9 @@ import fr.neatmonster.nocheatplus.utilities.ReflectionUtil;
import net.minecraft.server.v1_6_R3.AttributeInstance;
import net.minecraft.server.v1_6_R3.AttributeModifier;
import net.minecraft.server.v1_6_R3.GenericAttributes;
import fr.neatmonster.nocheatplus.checks.moving.MovingConfig;
import fr.neatmonster.nocheatplus.players.DataManager;
import fr.neatmonster.nocheatplus.utilities.moving.Magic;
public class AttributeAccess implements IAttributeAccess {
@@ -33,25 +36,107 @@ public class AttributeAccess implements IAttributeAccess {
}
@Override
public double getSpeedAttributeMultiplier(Player player) {
public double getSpeedMultiplier(Player player) {
final AttributeInstance attr = ((CraftLivingEntity) player).getHandle().getAttributeInstance(GenericAttributes.d);
final double val = attr.getValue() / attr.b();
final AttributeModifier mod = attr.a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return val;
} else {
}
else {
return val / AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
@Override
public double getSprintAttributeMultiplier(Player player) {
public float getMovementSpeed(final Player player) {
// / by 2 to get the base value 0.1f
return (player.getWalkSpeed() / 2f) * (float) getSpeedMultiplier(player);
}
@Override
public double getSprintMultiplier(Player player) {
final AttributeModifier mod = ((CraftLivingEntity) player).getHandle().getAttributeInstance(GenericAttributes.d).a(AttribUtil.ID_SPRINT_BOOST);
if (mod == null) {
return 1.0;
} else {
}
else {
return AttribUtil.getMultiplier(mod.c(), mod.d());
}
}
////////////////////////////////////////////////////////////////
// Modern attributes. Not available for legacy versions. //
////////////////////////////////////////////////////////////////
@Override
public double getGravity(Player player) {
return Magic.DEFAULT_GRAVITY;
}
@Override
public double getSafeFallDistance(Player player) {
return Magic.FALL_DAMAGE_DIST;
}
@Override
public double getFallDamageMultiplier(Player player) {
return 1.0;
}
@Override
public double getBreakingSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getJumpGainMultiplier(Player player) {
return 1.0;
}
@Override
public double getPlayerSneakingFactor(Player player) {
return Magic.SNEAK_MULTIPLIER;
}
@Override
public double getPlayerMaxBlockReach(Player player) {
return 4.5;
}
@Override
public double getPlayerMaxAttackReach(Player player) {
return 3.0;
}
@Override
public double getMaxStepUp(Player player) {
final MovingConfig cc = DataManager.getPlayerData(player).getGenericInstance(MovingConfig.class);
return cc.sfStepHeight;
}
@Override
public float getMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public float getWaterMovementEfficiency(Player player) {
return 0.0f;
}
@Override
public double getSubmergedMiningSpeedMultiplier(Player player) {
return 1.0;
}
@Override
public double getMiningEfficiency(Player player) {
return 0.0;
}
@Override
public double getEntityScale(Player player) {
return 1.0;
}
}
Loaded 100 of 481 files, more files were not shown because too many files have changed in this diff. Show more