/** * Add exact coordinates and pitch/yaw, multiple lines. No leading/trailing new lines. * * @param from * @param to * @param loc Reference location for from, usually Player.getLocation(). * @param builder */ public static void addMove( final Location from, final Location to, final Location loc, final StringBuilder builder) { if (loc != null && !TrigUtil.isSamePos(from, loc)) { builder.append("Location: "); addLocation(loc, builder); builder.append("\n"); } addMove(from, to, builder); }
/** * @param player * @param from * @param to * @param data * @param cc * @param time Milliseconds. * @return */ public Location check( final Player player, final PlayerLocation from, final PlayerLocation to, final MovingData data, final MovingConfig cc, final long time, final boolean useBlockChangeTracker) { // Reset tags, just in case. tags.clear(); // Some edge data for this move. final GameMode gameMode = player.getGameMode(); final ModelFlying model = cc.getModelFlying(player, from); final PlayerMoveData thisMove = data.playerMoves.getCurrentMove(); // if (!data.thisMove.from.extraPropertiesValid) { // // TODO: Confine by model config flag or just always do [if the latter: do it in // the listener]? // data.thisMove.setExtraProperties(from, to); // } thisMove.modelFlying = model; final PlayerMoveData lastMove = data.playerMoves.getFirstPastMove(); // Calculate some distances. final double yDistance = thisMove.yDistance; final double hDistance = thisMove.hDistance; final boolean flying = gameMode == BridgeMisc.GAME_MODE_SPECTATOR || player.isFlying(); final boolean sprinting = time <= data.timeSprinting + cc.sprintingGrace; // Lost ground, if set so. if (model.ground) { MovingUtil.prepareFullCheck(from, to, thisMove, Math.max(cc.yOnGround, cc.noFallyOnGround)); if (!thisMove.from.onGroundOrResetCond) { if (from.isSamePos(to)) { if (lastMove.toIsValid && lastMove.hDistance > 0.0 && lastMove.yDistance < -0.3 // Copy and paste from sf. && LostGround.lostGroundStill( player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, tags)) { // Nothing to do. } } else if (LostGround.lostGround( player, from, to, hDistance, yDistance, sprinting, lastMove, data, cc, useBlockChangeTracker ? blockChangeTracker : null, tags)) { // Nothing to do. } } } // Horizontal distance check. double[] resH = hDist( player, from, to, hDistance, yDistance, sprinting, flying, lastMove, time, model, data, cc); double limitH = resH[0]; double resultH = resH[1]; // Check velocity. if (resultH > 0) { double hFreedom = data.getHorizontalFreedom(); if (hFreedom < resultH) { // Use queued velocity if possible. hFreedom += data.useHorizontalVelocity(resultH - hFreedom); } if (hFreedom > 0.0) { resultH = Math.max(0.0, resultH - hFreedom); if (resultH <= 0.0) { limitH = hDistance; } tags.add("hvel"); } } else { data.clearActiveHorVel(); // TODO: test/check ! } resultH *= 100.0; // Normalize to % of a block. if (resultH > 0.0) { tags.add("hdist"); } // Vertical move. double limitV = 0.0; // Limit. double resultV = 0.0; // Violation (normalized to 100 * 1 block, applies if > 0.0). // Distinguish checking method by y-direction of the move. if (yDistance > 0.0) { // Ascend. double[] res = vDistAscend(from, to, yDistance, flying, thisMove, lastMove, model, data, cc); resultV = Math.max(resultV, res[1]); limitV = res[0]; } else if (yDistance < 0.0) { // Descend. double[] res = vDistDescend(from, to, yDistance, flying, lastMove, model, data, cc); resultV = Math.max(resultV, res[1]); limitV = res[0]; } else { // Keep altitude. double[] res = vDistZero(from, to, yDistance, flying, lastMove, model, data, cc); resultV = Math.max(resultV, res[1]); limitV = res[0]; } // Velocity. if (resultV > 0.0 && data.getOrUseVerticalVelocity(yDistance) != null) { resultV = 0.0; tags.add("vvel"); } // Add tag for maximum height check (silent set back). final double maximumHeight = model.maxHeight + player.getWorld().getMaxHeight(); if (to.getY() > maximumHeight) { // TODO: Allow use velocity there (would need a flag to signal the actual check below)? tags.add("maxheight"); } resultV *= 100.0; // Normalize to % of a block. if (resultV > 0.0) { tags.add("vdist"); } final double result = Math.max(0.0, resultH) + Math.max(0.0, resultV); if (data.debug) { outpuDebugMove(player, hDistance, limitH, yDistance, limitV, model, tags, data); } // Violation handling. Location setBack = null; // Might get altered below. if (result > 0.0) { // Increment violation level. data.creativeFlyVL += result; // Execute whatever actions are associated with this check and the violation level and find // out if we // should cancel the event. final ViolationData vd = new ViolationData(this, player, data.creativeFlyVL, result, cc.creativeFlyActions); if (vd.needsParameters()) { vd.setParameter( ParameterName.LOCATION_FROM, String.format(Locale.US, "%.2f, %.2f, %.2f", from.getX(), from.getY(), from.getZ())); vd.setParameter( ParameterName.LOCATION_TO, String.format(Locale.US, "%.2f, %.2f, %.2f", to.getX(), to.getY(), to.getZ())); vd.setParameter( ParameterName.DISTANCE, String.format(Locale.US, "%.2f", TrigUtil.distance(from, to))); if (!tags.isEmpty()) { vd.setParameter(ParameterName.TAGS, StringUtil.join(tags, "+")); } } if (executeActions(vd).willCancel()) { // Compose a new location based on coordinates of "newTo" and viewing direction of // "event.getTo()" // to allow the player to look somewhere else despite getting pulled back by NoCheatPlus. setBack = data.getSetBack(to); } } else { // Maximum height check (silent set back). if (to.getY() > maximumHeight) { setBack = data.getSetBack(to); } if (setBack == null) { // Slowly reduce the violation level with each event. data.creativeFlyVL *= 0.97; } } // Return setBack, if set. if (setBack != null) { // Check for max height of the set-back. if (setBack.getY() > maximumHeight) { // Correct the y position. setBack.setY(getCorrectedHeight(maximumHeight, setBack.getWorld())); if (data.debug) { debug(player, "Maximum height exceeded by set-back, correct to: " + setBack.getY()); } } data.sfJumpPhase = 0; return setBack; } else { // Adjust the set-back and other last distances. data.setSetBack(to); // Adjust jump phase. if (!thisMove.from.onGroundOrResetCond && !thisMove.to.onGroundOrResetCond) { data.sfJumpPhase++; } else if (thisMove.touchedGround && !thisMove.to.onGroundOrResetCond) { data.sfJumpPhase = 1; } else { data.sfJumpPhase = 0; } return null; } }