/// <summary> /// Checks both directions of a diagonal movement /// to see if movement or a bump resulting in an interaction is possible. Modifies /// the move action to switch to that direction, otherwise leaves it unmodified. /// Prioritizes the following when there are multiple options: /// 1. Move into empty space if either direction has it /// 2. Push an object if either direction has it /// 3. Open a door if either direction has it /// /// When both directions have the same condition (both doors or pushable objects), x will be preferred to y /// </summary> /// <param name="state">current state to try to slide from</param> /// <param name="action">current player action (which should have a diagonal movement). Will be modified if a slide is performed</param> /// <returns>bumptype of the final direction of movement if action is modified. Null otherwise</returns> private BumpType?TrySlide(PlayerState state, ref PlayerAction action) { Vector2Int direction = action.Direction(); if (Math.Abs(direction.x) + Math.Abs(direction.y) < 2) { //not diagonal, do nothing return(null); } Vector2Int xDirection = new Vector2Int(direction.x, 0); Vector2Int yDirection = new Vector2Int(0, direction.y); BumpType xBump = MatrixManager.GetBumpTypeAt(state.WorldPosition.RoundToInt(), xDirection, gameObject); BumpType yBump = MatrixManager.GetBumpTypeAt(state.WorldPosition.RoundToInt(), yDirection, gameObject); MoveAction?newAction = null; BumpType? newBump = null; if (xBump == BumpType.None) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.None) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } else if (xBump == BumpType.Push) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.Push) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } else if (xBump == BumpType.ClosedDoor) { newAction = PlayerAction.GetMoveAction(xDirection); newBump = xBump; } else if (yBump == BumpType.ClosedDoor) { newAction = PlayerAction.GetMoveAction(yDirection); newBump = yBump; } if (newAction.HasValue) { action.moveActions = new int[] { (int)newAction }; return(newBump); } else { return(null); } }
private IEnumerator DoProcess(PlayerAction action) { MoveCooldown = true; //experiment: not enqueueing or processing action if floating. //arguably it shouldn't really be like that in the future bool isGrounded = !IsNonStickyClient; // bool isAroundPushables = IsAroundPushables( predictedState ); //? trying to remove this because of garbage /*(isGrounded || isAroundPushables ) &&*/ if (!blockClientMovement && (!isPseudoFloatingClient && !isFloatingClient || playerMove.isGhost)) { // Logger.LogTraceFormat( "{0} requesting {1} ({2} in queue)", Category.Movement, gameObject.name, action.Direction(), pendingActions.Count ); if (isGrounded && playerState.Active) { //RequestMoveMessage.Send(action); // Fix for #900 BumpType clientBump = CheckSlideAndBump(predictedState, ref action); if (clientBump == BumpType.None || playerMove.isGhost) { //move freely pendingActions.Enqueue(action); LastDirection = action.Direction(); UpdatePredictedState(); } else { //cannot move -> tell server we're just bumping in that direction action.isBump = true; if (pendingActions == null || pendingActions.Count == 0) { PredictiveBumpInteract(Vector3Int.RoundToInt((Vector2)predictedState.WorldPosition + action.Direction()), action.Direction()); } if (PlayerManager.LocalPlayer == gameObject) { playerSprites.CmdChangeDirection(Orientation.From(action.Direction())); // Prediction: playerSprites.FaceDirection(Orientation.From(action.Direction())); } //cooldown is longer when humping walls or pushables // yield return YieldHelper.DeciSecond; // yield return YieldHelper.DeciSecond; } } else { action.isNonPredictive = true; } //Sending action for server approval CmdProcessAction(action); } yield return(YieldHelper.DeciSecond); MoveCooldown = false; }
/// <summary> /// Checks if any bump would occur with the movement in the specified action. /// If a BumpType.Blocked occurs, attempts to slide (if movement is diagonal). Updates /// playerAction's movement if slide occurs. /// </summary> /// <param name="playerState">state moving from</param> /// <param name="playerAction">action indicating the movement, will be modified if slide occurs</param> /// <returns>the type of bump that occurs at the final destination (after sliding has been attempted)</returns> private BumpType CheckSlideAndBump(PlayerState playerState, ref PlayerAction playerAction) { BumpType bump = MatrixManager.GetBumpTypeAt(playerState, playerAction, gameObject); // if movement is blocked, try to slide if (bump == BumpType.Blocked) { return(TrySlide(playerState, ref playerAction) ?? bump); } return(bump); }
private PlayerState NextStateServer(PlayerState state, PlayerAction action) { //Check if there is a bump interaction according to the server BumpType serverBump = CheckSlideAndBump(state, ref action); //Client only needs to check whether movement was prevented, specific type of bump doesn't matter bool isClientBump = action.isBump; //we only lerp back if the client thinks it's passable but server does not...if client //thinks it's not passable and server thinks it's passable, then it's okay to let the client continue if (!isClientBump && serverBump != BumpType.None) { Logger.LogWarningFormat("isBump mismatch, resetting: C={0} S={1}", Category.Movement, isClientBump, serverBump != BumpType.None); RollbackPosition(); } if (isClientBump || serverBump != BumpType.None) { // we bumped something, an interaction might occur // try pushing things / opening doors BumpInteract(state.WorldPosition, (Vector2)action.Direction()); playerSprites.FaceDirection(Orientation.From(action.Direction())); return(state); } if (IsNonStickyServer) { PushPull pushable; if (IsAroundPushables(serverState, out pushable)) { StartCoroutine(InteractSpacePushable(pushable, action.Direction())); } return(state); } if (action.isNonPredictive) { Logger.Log("Ignored action marked as Non-predictive while being indoors", Category.Movement); return(state); } bool matrixChangeDetected; PlayerState nextState = NextState(state, action, out matrixChangeDetected); if (!matrixChangeDetected) { return(nextState); } return(nextState); }
// --------------------------------------------------------------------------- private IEnumerator Bump(BumpType bumpType) { float sign = (bumpType == BumpType.Stone ? 1 : -1); float time = 0; while (time < bumpDuration) { float angle = time / bumpDuration * Mathf.PI; bumpComponent = new Vector3(0, Mathf.Sin(angle) * bumpIntensity * sign, 0); yield return(new WaitForEndOfFrame()); time += Time.deltaTime; } }
static void TestBump(BumpType bumpType, string fileContainingExpectedContents) { // Arrange File.Delete(Config.Releases.Files.AssemblyInfo.After); File.Copy(Config.Releases.Files.AssemblyInfo.Before, Config.Releases.Files.AssemblyInfo.After); var bump = Task.New<BumpAssemblyInfo>(); bump.In.FileName = Config.Releases.Files.AssemblyInfo.After; bump.In.BumpType = bumpType; // Act bump.Execute(); // Assert var afterContents = File.ReadAllText(Config.Releases.Files.AssemblyInfo.After); var expectedContents = File.ReadAllText(fileContainingExpectedContents); Assert.That(afterContents, Is.EqualTo(expectedContents)); }
static void TestBump(BumpType bumpType, string fileContainingExpectedContents) { // Arrange File.Delete(Config.Releases.Files.AssemblyInfo.After); File.Copy(Config.Releases.Files.AssemblyInfo.Before, Config.Releases.Files.AssemblyInfo.After); var bump = Task.New <BumpAssemblyInfo>(); bump.In.FileName = Config.Releases.Files.AssemblyInfo.After; bump.In.BumpType = bumpType; // Act bump.Execute(); // Assert var afterContents = File.ReadAllText(Config.Releases.Files.AssemblyInfo.After); var expectedContents = File.ReadAllText(fileContainingExpectedContents); Assert.That(afterContents, Is.EqualTo(expectedContents)); }
// Methods for car // ---------------------------------------------------------------------------- public void DoBump(BumpType bumpType) { StartCoroutine(Bump(bumpType)); }
private PlayerState NextStateServer(PlayerState state, PlayerAction action) { //Check if there is a bump interaction according to the server BumpType serverBump = CheckSlideAndBump(state, ref action); //Client only needs to check whether movement was prevented, specific type of bump doesn't matter bool isClientBump = action.isBump; //we only lerp back if the client thinks it's passable but server does not...if client //thinks it's not passable and server thinks it's passable, then it's okay to let the client continue if (!isClientBump && serverBump != BumpType.None) { Logger.LogWarningFormat("isBump mismatch, resetting: C={0} S={1}", Category.Movement, isClientBump, serverBump != BumpType.None); RollbackPosition(); } if (isClientBump || serverBump != BumpType.None) { // we bumped something, an interaction might occur // try pushing things / opening doors BumpInteract(state.WorldPosition, (Vector2)action.Direction()); playerSprites.FaceDirection(Orientation.From(action.Direction())); return(state); } if (IsNonStickyServer) { PushPull pushable; if (IsAroundPushables(serverState, out pushable)) { StartCoroutine(InteractSpacePushable(pushable, action.Direction())); } return(state); } if (action.isNonPredictive) { Logger.Log("Ignored action marked as Non-predictive while being indoors", Category.Movement); return(state); } bool matrixChangeDetected; PlayerState nextState = NextState(state, action, out matrixChangeDetected); if (!matrixChangeDetected) { return(nextState); } //todo: subscribe to current matrix rotations on spawn var newMatrix = MatrixManager.Get(nextState.MatrixId); Logger.Log($"Matrix will change to {newMatrix}", Category.Movement); if (newMatrix.MatrixMove) { //Subbing to new matrix rotations newMatrix.MatrixMove.OnRotate.AddListener(OnRotation); // Logger.Log( $"Registered rotation listener to {newMatrix.MatrixMove}" ); } //Unsubbing from old matrix rotations MatrixMove oldMatrixMove = MatrixManager.Get(Matrix).MatrixMove; if (oldMatrixMove) { // Logger.Log( $"Unregistered rotation listener from {oldMatrixMove}" ); oldMatrixMove.OnRotate.RemoveListener(OnRotation); } return(nextState); }
public DateTime BumpDate(DateTime date, BumpType bumpType) { throw new NotImplementedException(); }