static bool Prefix(RaycastHit hit, ref Vector3 position, ref Quaternion rotation)
        {
            if (!SnapBuilder.Config.Snapping.Enabled)
            {
                return(true); // Pass to the original function if SnapBuilder is disabled
            }

            Vector3 localPoint  = hit.transform.InverseTransformPoint(hit.point);                 // Get the hit point localised relative to the hit transform
            Vector3 localNormal = hit.transform.InverseTransformDirection(hit.normal).normalized; // Get the hit normal localised to the hit transform

            // Set the localised normal to absolute values for comparison
            localNormal.x = Mathf.Abs(localNormal.x);
            localNormal.y = Mathf.Abs(localNormal.y);
            localNormal.z = Mathf.Abs(localNormal.z);
            localNormal   = localNormal.normalized; // For sanity's sake, make sure the normal is normalised

            // Get the rounding factor from user options based on whether the fine snapping key is held or not
            float roundFactor = SnapBuilder.Config.FineSnapping.Enabled ? SnapBuilder.Config.FineSnapRounding : SnapBuilder.Config.SnapRounding;

            // Round (snap) the localised hit point coords only on axes where the corresponding normal axis is less than 1
            if (localNormal.x < 1)
            {
                localPoint.x = SnapBuilder.RoundToNearest(localPoint.x, roundFactor);
            }
            if (localNormal.y < 1)
            {
                localPoint.y = SnapBuilder.RoundToNearest(localPoint.y, roundFactor);
            }
            if (localNormal.z < 1)
            {
                localPoint.z = SnapBuilder.RoundToNearest(localPoint.z, roundFactor);
            }

            // Now, perform a new raycast so that we can get the normal of the new position
            Transform aimTransform = Builder.GetAimTransform();

            if (!Physics.Raycast(aimTransform.position,
                                 hit.transform.TransformPoint(localPoint) - aimTransform.position, // direction from the aim transform to the new world space position of the rounded/snapped position
                                 out hit,                                                          // overwrite hit
                                 Builder.placeMaxDistance,
                                 Builder.placeLayerMask.value,
                                 QueryTriggerInteraction.Ignore))
            {   // If there is no new hit, then the position we're snapping to isn't valid and we can just return false
                // without setting the position or rotation and it will be treated as if no hit occurred
                return(false);
            }

            // Set the position equal to the new hit point
            position = hit.point;

            Vector3 hitNormal = hit.normal; // Store the hit.normal as we may need to change this in certain circumstances

            // If the hit.collider is a MeshCollider and has a sharedMesh, it is a surface like the ground or the roof of a multipurpose room,
            // in which case we want a more accurate normal where possible
            MeshCollider meshCollider = hit.collider as MeshCollider;

            if (meshCollider?.sharedMesh != null)
            {
                // Set up the offsets for raycasts around the point
                Vector3[] offsets = new Vector3[]
                {
                    Vector3.forward,
                    Vector3.back,
                    Vector3.left,
                    Vector3.right,
                    (Vector3.forward + Vector3.right) * .707f,
                    (Vector3.forward + Vector3.left) * .707f,
                    (Vector3.back + Vector3.right) * .707f,
                    (Vector3.back + Vector3.left) * .707f
                };

                List <Vector3> normals = new List <Vector3>();
                // Perform a raycast from each offset, pointing down toward the surface
                foreach (Vector3 offset in offsets)
                {
                    Physics.Raycast(position + Vector3.up * .1f + offset * .2f,
                                    Vector3.down,
                                    out RaycastHit offsetHit,
                                    Builder.placeMaxDistance,
                                    Builder.placeLayerMask.value,
                                    QueryTriggerInteraction.Ignore);
                    if (offsetHit.transform == hit.transform) // If we hit the same object, add the hit normal
                    {
                        normals.Add(offsetHit.normal);
                    }
                }

                foreach (Vector3 normal in normals)
                {
                    if (normal != hit.normal)
                    {   // If the normal is not the same as the original, add it to the normal and average
                        hitNormal += normal / 2;
                    }
                }

                // For sanity's sake, make sure the normal is normalised after summing & averaging
                hitNormal = hitNormal.normalized;
            }

            if (Builder.rotationEnabled)
            {   // New calculation of the rotation
                // Get the rotation factor from user options based on whether the fine snapping key is held or not
                float rotationFactor = SnapBuilder.Config.FineRotation.Enabled ? SnapBuilder.Config.FineRotationRounding : SnapBuilder.Config.RotationRounding;

                // If the user is rotating, apply the additive rotation
                if (GameInput.GetButtonHeld(Builder.buttonRotateCW)) // Clockwise
                {
                    if (SnapBuilder.LastButton != Builder.buttonRotateCW)
                    {   // Clear previous rotation held time
                        SnapBuilder.LastButton         = Builder.buttonRotateCW;
                        SnapBuilder.LastButtonHeldTime = -1f;
                    }

                    float buttonHeldTime = SnapBuilder.FloorToNearest(GameInput.GetButtonHeldTime(Builder.buttonRotateCW), 0.15f);
                    if (buttonHeldTime > SnapBuilder.LastButtonHeldTime)
                    {                                                    // Store rotation held time
                        SnapBuilder.LastButtonHeldTime = buttonHeldTime;
                        Builder.additiveRotation      -= rotationFactor; // Decrement rotation
                    }
                }
                else if (GameInput.GetButtonHeld(Builder.buttonRotateCCW)) // Counter-clockwise
                {
                    if (SnapBuilder.LastButton != Builder.buttonRotateCCW)
                    {   // Clear previous rotation held time
                        SnapBuilder.LastButton         = Builder.buttonRotateCCW;
                        SnapBuilder.LastButtonHeldTime = -1f;
                    }

                    float buttonHeldTime = SnapBuilder.FloorToNearest(GameInput.GetButtonHeldTime(Builder.buttonRotateCCW), 0.15f);
                    if (buttonHeldTime > SnapBuilder.LastButtonHeldTime)
                    {                                                    // Store rotation held time
                        SnapBuilder.LastButtonHeldTime = buttonHeldTime;
                        Builder.additiveRotation      += rotationFactor; // Increment rotation
                    }
                }
                else if (GameInput.GetButtonUp(Builder.buttonRotateCW) || GameInput.GetButtonUp(Builder.buttonRotateCCW))
                {   // User is not rotating, clear rotation held time
                    SnapBuilder.LastButtonHeldTime = -1f;
                }

                // Round to the nearest rotation factor for rotation snapping
                Builder.additiveRotation = SnapBuilder.RoundToNearest(Builder.additiveRotation, rotationFactor) % 360;

                Transform hitTransform = hit.transform;
                if (!Player.main.IsInside())
                {   // If the player is outside, get the root transform if there is one, otherwise default to the original
                    hitTransform = UWE.Utils.GetEntityRoot(hit.transform.gameObject)?.transform ?? hit.transform;
                }

                // Instantiate empty game objects for applying rotations
                GameObject empty = new GameObject();
                GameObject child = new GameObject();
                child.transform.parent        = empty.transform; // parent the child to the empty
                child.transform.localPosition = Vector3.zero;    // Make sure the child's local position is Vector3.zero
                empty.transform.position      = position;        // Set the parent transform's position to our chosen position

                empty.transform.forward = hitTransform.forward;  // Set the parent transform's forward to match the forward of the hit.transform
                if (!Builder.forceUpright)
                {                                                // Rotate the parent transform so that it's Y axis is aligned with the hit.normal, but only when if it isn't forced upright
                    empty.transform.rotation = Quaternion.FromToRotation(Vector3.up, hitNormal) * empty.transform.rotation;
                }

                child.transform.LookAt(Player.main.transform); // Rotate the child transform to look at the player (so that the object will face the player by default, as in the original)
                child.transform.localEulerAngles
                    = new Vector3(0,
                                  SnapBuilder.RoundToNearest(child.transform.localEulerAngles.y + Builder.additiveRotation, rotationFactor) % 360,
                                  0);                // Round/snap the Y axis of the child transform's local rotation based on the user's rotation factor, after adding the additiveRotation

                rotation = child.transform.rotation; // Our final rotation

                // Clean up after ourselves
                GameObject.DestroyImmediate(child);
                GameObject.DestroyImmediate(empty);
            }
            else
            {   // Calculate rotation in the same manner as the original method
                Vector3 vector  = Vector3.forward;
                Vector3 vector2 = Vector3.up;

                if (Builder.forceUpright)
                {
                    vector   = -aimTransform.forward;
                    vector.y = 0f;
                    vector.Normalize();
                    vector2 = Vector3.up;
                }
                else
                {
                    switch (Builder.GetSurfaceType(hitNormal))
                    {
                    case SurfaceType.Ground:
                        vector2   = hitNormal;
                        vector    = -aimTransform.forward;
                        vector.y -= Vector3.Dot(vector, vector2);
                        vector.Normalize();
                        break;

                    case SurfaceType.Wall:
                        vector  = hitNormal;
                        vector2 = Vector3.up;
                        break;

                    case SurfaceType.Ceiling:
                        vector     = hitNormal;
                        vector2    = -aimTransform.forward;
                        vector2.y -= Vector3.Dot(vector2, vector);
                        vector2.Normalize();
                        break;
                    }
                }

                rotation = Quaternion.LookRotation(vector, vector2);
            }

            return(false); // Do not run the original method
        }