Can't do much better than being there already. Thinkable trouble could
be with high latency and multiple teleports to different locations in
quick succession, so that cancelling the teleport will lead to the
player violating survivalfly again in the future, which means longer
freezing/rubberbanding than if we teleport now. However, current
assumption is, that it's better not to keep teleporting players around.
Instead of maps for each individual purpose, and the rather expensive
TickListener adding and removing, player specific task will be done via
one PlayerTickListener that can be registered with the TickTask. Thus
PlayerData has the access methods requestUpdateInventory and
requestPlayerSetBack, and so on, later more. For the
DataManager.playerData map it'll be UUID first now.
Consequently some calls have been altered to prefer passing Player or
UUID for PlayerData getting.
Breaks: DataManager.getPlayerData(String, boolean) has been removed, new
methods added to do the same without boolean or with UUID passed extra.
Following changes may repeatedly/randomly break PlayerData and check
data access (unless you use CheckType.getDataFactory), this may not
follow directly, but more or less soon. Even Later, CheckType will get
broken too :), in favor of class instances with dynamic registration
ability.
Basic direction is to concentrate stuff in PlayerData, getting rid of
all the static data stores, but also making access to shared data
more efficient (e.g. store last world id + name and permission cache in
PlayerData). Access will be more thread safe (only for PlayerData,
permissions cache, likely for fetching check data too, however returned
objects may have their own contracts).
* The player is at the coordinates.
* The last received ACK for an outgoing teleport has been received on
packet level. This is experimental, to be confirmed to a) do something
b) not allow abuse.
We do need to fix behavior to move on, so the intention rather is to
react more flexibly towards debugging results, rather than having people
use random configurations early on. Still this does allow for fall-back
configuration, e.g. for live servers.
NOTES:
* Later we will make the configuration set at 'default' adjust to server
mod and version.
* Overriding checks.moving.setback.method with SET_TO can lead to
PlayerTeleportEvents with TeleportCause.PLUGIN on newer versions of
Spigot, which may conflict with other plugins assuming feature-based
teleportation (possibly resulting in /back locations getting overridden
wrongly). For legacy setups this will be similar to restoring the state
of build 1066 for most.
There could still be places where distinction of the used method is
necessary, which would mean bugs.
* Don't unset teleported, if event.getTo is the same position as the
teleported (set back) location.
* Prepare (with) comments.
(Main driver is to be able to adjust quickly without shifting code
to-fro legacy etc., while dealing with much differing side conditions
for server mod + version, client versions with multi protocol support,
and other like bungee or not bungee.)
* MovingListener.prepareSetBack makes more sense than the previous
ambiguous naming.
* On confirming a set back, don't update the setBack field, only set if
null.
The aim is to have a more consistent handling and naming for set back
stages.
Both schedule a set back and update PlayerMoveEvent.getFrom() with the
set back location coordinates. This way, either the next incoming move
or a teleport event can confirm the set back location.
When a set back is scheduled:
* Cancel other teleports early. (x)
* Prevent Portal use. (x)
* Vehicle enter (not on vehicle set back). (x)
* Prevent attacking.
* Interact block. (x)
* Break block.
* Damage block. (x)
* Launch projectile.
* Place Block.
* Interact entity.
* Open inventory. (x)
The list is incomplete and adding/removing items remains subject to
discussion, having differing impact/severity for different actions. As
long as setting back rolls back to last ground, it might be better to
prevent some type of actions. Not all cancelling is logged.
(x) Probably most important for consistency, avoiding some types of
potential abuse.
A common framework
for "prevent types of action" during whatever-handling also is something
to consider.
Optimizations:
* Move handling some rare cases to methods (MovingListener,
PlayerTeleportEvent handling).
When the captain leaves the boat, the vehicle data of a passive player
passenger may be set now, so it won't set them back to where they
entered the vehicle.
Likely other places still need adjusting.
Tested with a pig. It's not nice.
* Vehicle envelope needs a lot of overhaul.
* Force fall set backs may be more nice to have for in-air downwards.
* The set back locations can be from seconds ago, with different
passengers than at the time of the set-back.
Because Spigot changed to fire the teleport following an altered move
end point with TeleportCause.PLUGIN, we have to alter set back handling,
so we can ensure to keep TeleportCause.UNKNOWN for setting back players.
Instead of altering the move end point, the event is just cancelled, and
a teleport is scheduled (with a dedicated TickTask method). Uncancelled
moving events mean removing scheduled teleports.
[BLEEDING]
* Comparably simple change - more places and special cases may still be
uncovered.
[BREAKING]
* Plugins that may rely on the exact sequence of things within NCP, as
it used to be.
Random
* Change "set-back" to "set back" everywhere for simplicity, and to
obfuscate the actual code changes.
* Set backs are now going through MovingListener.onCancelledMove instead
of MovingListener.onMoveMonitorNotCancelled.
* Illegal move handling would still use event.setTo.
* Split log messages: ingame vs. console+file
* Alter flylong to contain tags.
Performance-wise, it's not optimal that flylong is the same as flyfile
at this stage. Not sure if to remove flylong in favor of using flyfile,
to indicate it means details - main objective is to get minimal details
into the violation log, even if people edit it out of the ingame chat
messages.
Players and vehicles:
Instead always use UNKNOWN, as that is what results from
PlayerMoveEvent.setTo(newTo), as we use it for setting back players.
This should break functionality that relies on TeleportCause.PLUGIN
being used, possibly more likely with vehicles.
Internally, the tick is stored with a change id, so we can reuse a
changeId, if the tick is still the same, preserving rough order, as the
changeId should at least increase with the tick.
This isn't the last word on a public API, there likely will be the
following additions.
* One more simplified method with a minimal signature for simple
(non-push) entries (worldId, x, y, z, previousState).
* Optimized methods for adding multiple entries at once. Likely for
adding multiple entries of the same type/data/shape. Plus perhaps
simplified signatures to do without changeId and tick.
(Not sure if there will be need for a method allowing for a collection
of a to be defined class combining x+y+z+previousState.)
This will evolve based on feedback from GitHub issues.
Lots of issues remain with elytra, with and without boost. Selection:
* maxheight will trigger with the rocket feature, naturally. Mendable by
increasing it via configuration
(checks.moving.creativelfly.model.elytra.vertical.maxheight). Not sure
we'll just increase the limit or alter how it's dealt with (e.g. also
for sf: lock to a max / high slope value, independently of the set-back
and world height, alter as necessary).
* All sorts of transitions, e.g. onto ground, into water.
* Loss of boost right after adding (not sure if already fixed).
* What with hover, actually?
* Is the flight duration infinite with power 127?
* Issues with ascending after descending, even without boost?
Changes contain:
* MCAccess.dealFallDamageFiresAnEvent -> true
* Always log basic data on (handled) fall damage events.
* Add a tag for the cancel reason with NoFall. Alter the default alert
message.
* Move 3.0 to Magic.
* Set the skipping flag correctly on allowFlight being set.
Fall damage is adjusted or cancelled, if the Minecraft fall distance is
greater than the distance(s) tracked by NCP (per move diffs, maximum y).
Intention is to prevent (speeding by) self damage by abusing Minecraft
dealing fall for untracked moves.
Issue: https://github.com/NoCheatPlus/Issues/issues/338
Steps done:
* Add more velocity with less preconditions.
* Handle push with the player being just above the block where a slime
block is pushed to.
* Exception for vdistrel.
* Breaking:Move verVelUsed from MovingData to PlayerMoveData.
Gameplay issues remaining:
* Still too often fall damage is dealt.
* Friction envelope gets hidden with past-ground being set too often
(vdistsb).
* Potential for more edge cases.
Missing abuse prevention:
* Reinstate invalidation of past entries (currently turned off to
progress at all, will need another iteration).
* More confined preconditions.
* More/better invalidation conditions for velocity set for bounce
effects.
* Less fall damage.
* Flag all velocity added due to slime bouncing appropriately.
* Experimental concept for splitting up velocity, likely to be altered /
removed.
* Add a flag for (faked) pvp velocity.
NOTE: Invalidation of past entries has been deactivated to progress on detecting the stupid past bouncing at all. This will need another iteration.
Lots of issues remain, but vertical push/bounce with pistons is much
improved. Still there are show stoppers (false positives remain, as well
as occasional fall damage).
Use same/similar entry points, like static/classic bounce checking in
MovingListener. SurvivalFly still keeps one exception with the
after-failure Y_POS block move check.
Also check: https://github.com/NoCheatPlus/Issues/issues/5
There are typical cases to cover:
* Extra falling height.
* Fall damage where a slime block had been.
Thus adding a specialized method for bounce (just foot position) instead
of using the full bounds would be better, preferably just check within
the MovingListener (set bounce / adjust velocity there).
Still incomplete, could contain bugs (endless loops, perhaps).
Invalidation
mechanics may need to be refined.
Not covered:
* Exemption for moves resulting from horizontal push/pull.
*
* In case of non-full bounds + variable, allow ground to be found
underneath. Can concern fences (tested on 1.11).
* There has been a probably misplaced/leftover check assuming the block
above to be passable, without checking for it (iMaxY). Since the
access.getMaxBlockY() has already been checked, this part appears to be
not of use, thus iMaxY has been removed from the signature together with
this exception.
If this causes something, please provide debug logs / circumstances :).
This is unfinished, but gives an outlook on what we may be able to do
with this.
* Double doors are not covered (upper/lower half are).
* Interaction with levers / directly with doors is not covered.
* Only doors + gates (not sure what else there is).
* More fine grained configurability is missing (+ only register
listeners if needed).
* Possibly other things.
Tracking BlockRedstone seems to be more promising than BlockPhysics, as
long as we don't have to inspect neighbour blocks to check for door like
blocks at all.
Currently the oldest available entries are used, as if the player had
the maximum allowed latency always. Later on, at least attempting to hit
a global latency estimate (+window) should be attempted.
We'll still have a (moderate) fast-forward implementation to see what
opportunistic checking can do on live servers (elevators, doors etc.).
Intention is to work towards passing stored IBlockCacheNode instances to
methods in BlockProperties, i.e. to have
isOnGroundInAnOverlyOpportunisticWay implemented.
If you need one of the old BlockProperties signatures (or a more
simplified one), just open a GitHub issue.
This is a slightly peculiar change.
* Passing node and nodeAbove is a little bit odd, despite seemingly
efficient at present.
* Later we might need a BlockCache instance that busies about past
states (currently too complicated to implement).
* Uncertain impact (could perform better, could perform worse).
* Possibly left out a couple of places.
* Might have introduced bugs (fast forward).
On the other hand there may be a lot of other types of changes, if we
ever go for a less opportunistic implementation, which can not be
estimated simply, so this may be about the best that can be done, to get
a quick step in.
Already have the signature use IBlockCacheNode for node+nodeAbove, like
it will be done with other methods like collidesBlock.
This will allow calling this with past block states, once other methods
have been adapted as well.
Within BlockProperties BlockCache and IBlockCacheNode ("read only") get
passed, removing id/data/shape from arguments. If a property is not set
in the node, it'll be fetched from the block cache, but the node is not
updated from outside the BlockCache. For subsequent calls, the node
would be updated by the block cache, if it isn't a node stored by the
BlockChangeTracker from an earlier time, and similar.
This way, opportunistic passable checking can be implemented, by
switching to cached nodes instead of id/data/shape arguments with lazy
fetching from BlockCache.
The name IBlockCacheNode seems to be appropriate, since we'll pass it
alongside with a BlockCache anyway.
Cross-world teleport to the end issue: set back hard, if the player
moves to the position they set off from the last world, which seems to
be a bug with some server types/versions at present (!?).
Some packets arrive with a null world for a player, possibly sent by
plugins - thus attempt to use a stored world name.
This is just a hot fix attempt.
Attempt to enable workarounds for lily pads with servers that support
multiple client versions. Add to the configuration at
compatibility.blocks.overrideflags:
WATER_LILY: default+ign_passable+ground_height+height8_1
HEIGHT8_1 just means 1/8 height (0.125).
The ALLOW_LOWJUMP flag was intended to be used in case of
ground_height+height100 or the like leading to issues with
sprint-jumping due to the low jump detection, however other special
casing checks for bunny hopping let this still fail (less than before,
but still), thus this flag might get removed. Keeping it for now, to
provide some kind of toolkit.
Technically, tracking actual speed / base speed seems promising, done
here via using the liftOffEnvelope that is maintained anyway, adding a
counter and sum value. [Base speed is something like the allowed speed,
without accounting for specialties like bunny hopping.]
Limits are checked for moving in ground+air or water+air and are
currently hard-coded. This simplistic first-step-in may easily yield all
sorts of false positives and other random issues, handle with care.
Can't judge side effects, concerning other passable like tests telling
the head to be inside a block by the micro margin, while passable allows
such a move now.
Not sure if this really pays, if most people use protocol-support
plugins that limit packets anyway. There could be some future use, e.g.
generic rate limiting with configurable implementation.
Other:
* New methods for RawConfigFile+ConfigManager to check for
AlmostBooleanS.
* Add all net check permissions to plugin.yml.
* ICollideBlocks matches the interface better. If we ever need ICollide
for something common (e.g. set(ICollisionSetup) allows to fetch
information about start conditions and run generic tests !? not really
sure if such will happen...)
* Add ICollideRayVsAABB, to prepare other types of direction/visible
checking (enable more precision, but also configurable leniency).
This time the focus is on the utilities package.
Possibly used, but not really official API:
* Move block cache to a 'map' sub-package.
* Move RichBounds/RichEntity/Player-Location and TrigUtil to a location
sub-package.
Not really official API, likely not used:
* Move AttribUtil to compat, since it belongs there.
* Split off direction check methods to collision.CollisionUtil.
* Move static BlockCache methods to map.MapUtil.
* Move food related methods from CheckUtils to InventoryUtil.
* Move vehicle/passenger related methods from CheckUtils to
PassengerUtil.
Not breaking:
* Move IdUtil to commons.
registry.feature is rather meant for stuff that registers automatically
with adding as a component to the NoCheatPlus API.
Package organization isn't done in a very consistent way, this is just
taking a step into looking at how it would/could look like.
Likely that kind of separation can't be kept, so things will in the end
be organized by their main topic perhaps, and a registry implementation
will have to state what will be registered in what way, and possibly
have a method to allow checking what's possible to register.
Main objective is to get rid of too complex setMCAccess methods and to
be able to store handles rather permanently instead.
* Remove MCAccessHolder.
* Add/refine interfaces and implementations.
* Change constructors.
The idea is to change internals towards having a 'default'
DisableListener executing onDisable before the data removal of checks
and DataManager have been called, thus plugins or even checks might
still access all sorts data with disabling the plugin.
* Only load chunks, if there is no illegal coordinates.
* If there is no valid set-back on receiving illegal coordinates,
attempt to recover from past move / current (bug), or kick.
* Add a way to stay updated about the latest registration state for a
class.
* Add a class for the registry.
* Let the registry log all registrations.
* Make super interfaces for LogManager (simple logging of
String/Throwable).
Missing:
* More streams (REGISTRY, PLAYER/CHECK_STATUS/EVENTS or just CHECKS at
least). Make status rather the plugin status. Registry could have an
extra file.
* More efficient IGenericInstanceHandle use (wrap + reference counting).
Attempt to treat fake players less Concept is subject to change, might
want fall-back methods or skipping native access in general where it's
not needed (thus not need to check for native entities).
Other
* Don't insert dataMan into disableListeners twice.
This is neither complete nor final. Intentions are to group interfaces
better, rather organizing packages in a flat way.
At some point there will be other major move-arounds, but that'll
hopefully be a point where we have a better idea of where to put what
(...). For now the approach is to move interfaces/things rather where
it's not interfering with profane exemption API use, preferably neither
taking down the top level API layer
(NoCheatPlusAPI).
Added deprecated interfaces to prevent cncp to break too quickly.
Outlook:
* Classes that are rather only expected to be used internally for setup
will likely get moved around freely.
* Classes that have been added since last release might also get moved
around freely.
Configurable. Falling blocks, piston, end portal, roughly. Destructive:
the entity is removed.
(In addition some of the feature tags are added regardless activation
flags, because 'ncp reload' could change things anyway.)
Feel free to suggest alternatives/variations...
Except with join/respawn, the methods will not load chunks if close by
past moves have extra properties set, assuming the chunks are already
loaded then.
Change to 'ignoreInitiallyColliding' and only ignore the first block, if
it really is colliding right now. The flag is not resetting with
set(...) anymore.
* Make RayTracing and PassableRayTracing implement interfaces. (rough,
not used in tests yet etc.).
* Optimize ray tracing use in BlockProperties.
* Add an axis-wise implementation (buggy, hardly tested, thus not used
yet).
MCAccess will be split into smaller providers with time, so do expect
more breaking changes of this type. If this is an issue, please contact
us, so we can see how to smoothen things. E.g. we could still make
MCAccess an aggregate, that just delegates to the more fine grained
providers, or we could provide other
(default) aggregates.
This also adds a Bukkit-based provider for future updates.
* Call removeInvalid if many elements are queued on add (cheat not
sending moving events, player takes damage), and on clear, in order to
allow detection of unused velocity with not sending moves.
* Add get+set for unusedActive.
Simplistic unused vertical velocity tracking for starters. Only
activates with debugging set.
Needs on-the-fly debugging (all) or at least debug set for moving
(config: checks.moving.debug: true), and needs debug set for fight to
check on damage/attack (config: checks.fight.debug).
Method is simple, roughly: Keep track when the player has last been on
ground, or when their head had been blocked. Based on that, we can
attempt to judge if invalidated velocity entries might be cheating.
There is more aspects to cover, and this is not a check, it just will
debug information to the log file. Would appreciate feedback on if/what
this will log with noknockback cheats on :) (false positives are most
welcome as well).
* Account for off hand in more places.
* Use bridge methods to get rid of warnings for now.
* Adds utility methods to CheckUtils.
* Do not allow left click on off hand (knockback).
Since merging by distance only creates false positives (one would have
to increase the bounding box for an entry, but the angles would never be
100% right), we never merge, instead we don't add a new entry if the
position is the same, the time value is not updated in this case. For
validity of an entry you always have to consider the time span until the
previous (younger) entry or until now for the latest entry.
Rough changes:
* Use an interface for accessing trace entries.
* Use a linked structure for the actual trace.
* Use maximum age and size to limit the number of stored entries.
* Use a pool to somewhat limit object creation (size may need
configuration or scaling with number of players).
* Since the trace starts empty, have the field be final.
* Keep trace elements if settings are changed, cut size if necessary.
* Remove obsolete tests.
Potentially missing:
* Usage of LocationTrace has not been checked if we need to account for
the time of the latest entry not necessarily being updated (!).
* New tests, e.g. accounting for the expiration of entries.
Follow ups:
* (Extend fight/loop checks to a latency window mechanism.)
Upcoming changes will roughly be:
* Change implementation to a double linked structure.
* Implement/use something like ListIterator.
* Never merge entries, instead use some pool and time/extre-n as limits.
* A basic latency window implementation just for the LocationTrace for
preliminary experiments. [Track hit/miss all time + recent so and so
seconds, some extra cancelling/invalidation mechanics, allow to test
complement 0->window start and possibly window-end-> max latency for
some cases, cancelling mechanics may contain a buffer or a mixture of a
buffer relating to average miss rate]
Wild card exempt NPCs by default, encapsulate meta data checks here (if
exempted, if is NPC).
With these default settings Citizens NPCs should be exempted by default,
also all custom Player implementations that extend the Bukkit interface
NPC (not sure if such still exists).
Follow ups:
* Configurability.
* Exemption tickets to prevent others overriding your exemptions
(later).
Kept configurable to enable increasing difficulty for fly plugins use,
e.g. to allow players to fly within certain regions, but still deal fall
damage on falling.
Section at: checks.moving.vehicle.envelope.hdistcap
Default is 4 (extreme move fall-back) at 'default'.
Other entries by bukkit entity type name, if desired.
This allows forcing set backs for testing in a convenient way, e.g. with
setting the value to 0.3 for boat/default.
Main objective was to not reset the set-backs on setting back a vehicle
with a player, plus data resetting cleanup.
Specific changes:
* Prefer an existing set-back, in case the default one has been
invalidated.
* Do not cancel a vehicle set back task, in case no set-back is present.
* Avoid multiple resetting and redundant calls for resetting positions.
* Ensure the location set back to is set as a set-back location after
set back.
* Skip changing vehicle data with player moving resetting (e.g. player
teleport, player morepackets disabled).
Review and possibly correct/alter use of:
* MovingData.vehicleMoves.invalidate
* MovingData.vehicleSetBacks
* MovingData.clearMostMovingData
* AuxMoving.resetXYPositions
* MovingData.clearVehicleData
* MovingData.clearVehicleMorePacketsData
* MovingData.clearAllMorePacketsData
* MovingData|AuxMoving.resetVehiclePositions
* Fix scheduling vehicle set-backs: disabled by default.
* Adjust detecting already set set back in morepackets (vehicle).
* Always warn if a set-back gets overridden.
* Adjust debug logging and comments.
* Some data loss.
Looks like we're running into set-back loops, unless we can control this
otherwise. It's more safe and consistent for our context, however it
leads to nested events. Vehicle exit, player teleport and vehicle enter
will fire from within handling whichever event the vehicle checks got
called from, such as vehicle update, player move, vehicle move.
Possibly some justTeleported flag helps us here. Likely there is no
similar switch that we could use with scheduled set-backs. The proper
option would otherwise be, to use packet sending and/or even cancelling
packets selectively, which would more or less force us to hard depend on
ProtocolLib for supporting basic features of Minecraft, despite possibly
a
sensible move anyway.