private static void HandleClaimReward(GameSession session, PacketReader packet)
    {
        int rewardTier = packet.ReadInt();

        RPS rpsEvent = DatabaseManager.Events.FindRockPaperScissorsEvent();

        if (rpsEvent is null)
        {
            return;
        }

        GameEventUserValue rewardsAccumulatedValue = GameEventHelper.GetUserValue(session.Player, rpsEvent.Id,
                                                                                  TimeInfo.Tomorrow(), GameEventUserValueType.RPSRewardsClaimed);
        List <string> rewardsClaimedStrings = rewardsAccumulatedValue.EventValue.Split(",").ToList();

        foreach (string rewardString in rewardsClaimedStrings)
        {
            // User has not claimed any rewards
            if (rewardString == "")
            {
                break;
            }

            if (int.TryParse(rewardString, out int rewardInt) && rewardInt == rewardTier)
            {
                return;
            }
        }

        RPSTier tier = rpsEvent.Tiers.ElementAtOrDefault(rewardTier);

        if (tier is null)
        {
            return;
        }

        foreach (RPSReward reward in tier.Rewards)
        {
            Item item = new(reward.ItemId, reward.ItemAmount, reward.ItemRarity);

            session.Player.Inventory.AddItem(session, item, true);
        }

        // update event value
        rewardsClaimedStrings.Add(rewardTier.ToString());
        rewardsAccumulatedValue.UpdateValue(session, string.Join(",", rewardsClaimedStrings));
    }
    private static void HandleBeginTimer(GameSession session)
    {
        AttendGift attendanceEvent = DatabaseManager.Events.FindAttendGiftEvent();

        if (attendanceEvent is null)
        {
            return;
        }

        GameEventUserValue accumulatedTime = GameEventHelper.GetUserValue(session.Player, attendanceEvent.Id,
                                                                          TimeInfo.Tomorrow(), GameEventUserValueType.AttendanceAccumulatedTime);

        if (accumulatedTime.ExpirationTimestamp < TimeInfo.Now())
        {
            accumulatedTime.ExpirationTimestamp = TimeInfo.Tomorrow();
            accumulatedTime.EventValue          = "0";
            DatabaseManager.GameEventUserValue.Update(accumulatedTime);
        }
    }
    private static void HandleClaim(GameSession session)
    {
        AttendGift attendanceEvent = DatabaseManager.Events.FindAttendGiftEvent();

        if (attendanceEvent is null || attendanceEvent.EndTimestamp < TimeInfo.Now())
        {
            session.Send(AttendancePacket.Notice((int)AttendanceNotice.EventNotFound));
            return;
        }

        GameEventUserValue timeValue = GameEventHelper.GetUserValue(session.Player, attendanceEvent.Id,
                                                                    TimeInfo.Tomorrow(), GameEventUserValueType.AttendanceAccumulatedTime);

        long.TryParse(timeValue.EventValue, out long accumulatedTime);
        if (TimeInfo.Now() - session.Player.LastLogTime + accumulatedTime <
            attendanceEvent.TimeRequired)
        {
            return;
        }

        GameEventUserValue completeTimestampValue = GameEventHelper.GetUserValue(session.Player, attendanceEvent.Id,
                                                                                 attendanceEvent.EndTimestamp, GameEventUserValueType.AttendanceCompletedTimestamp);

        long.TryParse(completeTimestampValue.EventValue, out long completedTimestamp);

        DateTimeOffset savedTime = DateTimeOffset.FromUnixTimeSeconds(completedTimestamp);

        if (DateTimeOffset.Now.UtcDateTime < savedTime.UtcDateTime && DateTimeOffset.Now.Date != savedTime.Date)
        {
            session.Send(AttendancePacket.Notice((int)AttendanceNotice.EventHasAlreadyBeenCompleted));
            return;
        }

        // get current day value
        UpdateRewardsClaimed(session, attendanceEvent);

        // update completed timestamp
        long convertedValue2 = TimeInfo.Now();

        completeTimestampValue.UpdateValue(session, convertedValue2);
    }
    private static void HandleSelectRpsChoice(GameSession session, PacketReader packet)
    {
        session.Player.RPSSelection = (RpsChoice)packet.ReadInt();

        // delay for 1 sec for opponent to update their selection
        Task.Run(async() =>
        {
            await Task.Delay(1000);
        });

        // confirm if opponent is still in the map
        Player opponent = session.FieldManager.State.Players
                          .FirstOrDefault(x => x.Value.Value.CharacterId == session.Player.RPSOpponentId).Value?.Value;

        if (opponent == null)
        {
            return;
        }

        // handle choices
        RpsResult[,] resultMatrix =
        {
            {
                RpsResult.Draw, RpsResult.Lose, RpsResult.Win
            },
            {
                RpsResult.Win, RpsResult.Draw, RpsResult.Lose
            },
            {
                RpsResult.Lose, RpsResult.Win, RpsResult.Draw
            }
        };

        RpsResult result = resultMatrix[(int)session.Player.RPSSelection, (int)opponent.RPSSelection];

        RPS rpsEvent = DatabaseManager.Events.FindRockPaperScissorsEvent();

        if (rpsEvent is null)
        {
            return;
        }

        Item voucher = session.Player.Inventory.GetById(rpsEvent.VoucherId);

        if (voucher is null)
        {
            return;
        }

        session.Player.Inventory.ConsumeItem(session, voucher.Uid, 1);

        GameEventUserValue dailyMatches = GameEventHelper.GetUserValue(session.Player, rpsEvent.Id,
                                                                       TimeInfo.Tomorrow(), GameEventUserValueType.RPSDailyMatches);

        int.TryParse(dailyMatches.EventValue, out int dailyMatchCount);

        dailyMatchCount++;

        dailyMatches.UpdateValue(session, dailyMatchCount);
        session.Send(RockPaperScissorsPacket.MatchResults(result, session.Player.RPSSelection, opponent.RPSSelection));
    }