예제 #1
0
        public void SendStateEmail(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle, uint avatarID)
        {
            if (!da.Elections.TryRegisterMail(new DbElectionCycleMail()
            {
                avatar_id = avatarID,
                cycle_id = cycle.cycle_id,
                cycle_state = cycle.current_state
            }))
            {
                return;
            }

            var endDate = cycle.end_date;

            switch (cycle.current_state)
            {
            case DbElectionCycleState.nomination:
                endDate -= 60 * 60 * 24 * 3;     //nomination ends 3 days before end of cycle
                mail.SendSystemEmail("f116", (int)NeighMailStrings.NominateSubject, (int)NeighMailStrings.Nominate,
                                     1, MessageSpecialType.Nominate, endDate, avatarID, nhood.name, endDate.ToString());
                break;

            case DbElectionCycleState.election:
                mail.SendSystemEmail("f116", (int)NeighMailStrings.VoteSubject, (int)NeighMailStrings.Vote,
                                     1, MessageSpecialType.Vote, endDate, avatarID, nhood.name, endDate.ToString());
                break;

            case DbElectionCycleState.failsafe:
                mail.SendSystemEmail("f116", (int)NeighMailStrings.FailsafeSubject, (int)NeighMailStrings.Failsafe,
                                     1, MessageSpecialType.Normal, endDate, avatarID, nhood.name);
                break;

            case DbElectionCycleState.shutdown:
                if (Context.Config.Neighborhoods.Election_Free_Vote)
                {
                    mail.SendSystemEmail("f116", (int)NeighMailStrings.FreeVoteSubject, (int)NeighMailStrings.FreeVote,
                                         1, MessageSpecialType.FreeVote, endDate, avatarID, nhood.name, endDate.ToString());
                }
                break;

            case DbElectionCycleState.ended:
                var winner = da.Avatars.Get(nhood.mayor_id ?? 0)?.name;
                if (winner == null)
                {
                    return;
                }

                mail.SendSystemEmail("f116", (int)NeighMailStrings.ElectionOverSubject, (int)NeighMailStrings.ElectionOver,
                                     1, MessageSpecialType.Normal, endDate, avatarID, winner, nhood.name, "someone else idk");
                break;
            }
        }
        public static void SetElectionCycle(Neighborhood nhood, DbElectionCycle cycle)
        {
            if (cycle == null)
            {
                return;
            }
            var result = new ElectionCycle()
            {
                ElectionCycle_CurrentState = (byte)cycle.current_state,
                ElectionCycle_ElectionType = (byte)cycle.election_type,
                ElectionCycle_EndDate      = cycle.end_date,
                ElectionCycle_StartDate    = cycle.start_date
            };

            nhood.Neighborhood_ElectionCycle = result;
        }
예제 #3
0
        public void BroadcastNhoodState(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle)
        {
            var all = Sessions.Clone();

            foreach (var session in all.OfType <IVoltronSession>())
            {
                if (session.IsAnonymous)
                {
                    continue;
                }

                var myLotID = da.Roommates.GetAvatarsLots(session.AvatarId).FirstOrDefault();
                var myLot   = (myLotID == null) ? null : da.Lots.Get(myLotID.lot_id);

                if (myLot != null && myLot.neighborhood_id == nhood.neighborhood_id)
                {
                    SendStateEmail(da, mail, nhood, cycle, session.AvatarId);
                }
            }
        }
예제 #4
0
        public async Task ChangeElectionState(IDA da, DbNeighborhood nhood, DbElectionCycle cycle, DbElectionCycleState state)
        {
            var now  = Epoch.Now;
            var mail = Kernel.Get <MailHandler>();

            switch (state)
            {
            case DbElectionCycleState.nomination:
                //start nominations for this cycle.
                var endDate = cycle.end_date - 60 * 60 * 24 * 3;     //nomination ends 3 days before end of cycle
                SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.NominateSubject, (int)NeighBulletinStrings.Nominate, endDate,
                                 nhood.name, endDate.ToString());

                break;

            case DbElectionCycleState.election:
                //end nominations. choose the candidate sims.
                var cycleNoms = da.Elections.GetCycleVotes(cycle.cycle_id, DbElectionVoteType.nomination);
                var toRemove  = da.Elections.GetCandidates(cycle.cycle_id).ToDictionary(x => x.candidate_avatar_id);
                if (cycleNoms.Count > 0)
                {
                    var grouped  = cycleNoms.GroupBy(x => x.target_avatar_id).OrderByDescending(x => x.Count());
                    var selected = 0;

                    var candidates = new List <IGrouping <uint, DbElectionVote> >();

                    foreach (var winner in grouped)
                    {
                        //verify the winners are still alive and still in this neighborhood
                        string name = null;
                        DbElectionCandidate cand;
                        if (toRemove.TryGetValue(winner.Key, out cand) && VerifyCanBeMayor(da, winner.Key, (uint)nhood.neighborhood_id, now, ref name))
                        {
                            if (cand.state != DbCandidateState.running)
                            {
                                continue;                                             //user must have accepted their nomination
                            }
                            toRemove.Remove(winner.Key);

                            mail.SendSystemEmail("f116", (int)NeighMailStrings.RunningForMayorSubject, (int)NeighMailStrings.RunningForMayor,
                                                 1, MessageSpecialType.Normal, cycle.end_date, winner.Key, nhood.name, cand.comment, cycle.end_date.ToString());

                            candidates.Add(winner);

                            if (++selected >= 5)
                            {
                                break;
                            }
                        }
                    }

                    foreach (var remove in toRemove)
                    {
                        da.Elections.DeleteCandidate(remove.Value.election_cycle_id, remove.Value.candidate_avatar_id);

                        if (remove.Value.state == DbCandidateState.running)
                        {
                            mail.SendSystemEmail("f116", (int)NeighMailStrings.TooFewNominationsSubject, (int)NeighMailStrings.TooFewNominations,
                                                 1, MessageSpecialType.Normal, cycle.end_date, remove.Key, nhood.name, cycle.end_date.ToString());
                        }
                        else
                        {
                            mail.SendSystemEmail("f116", (int)NeighMailStrings.NominationNotAcceptedSubject, (int)NeighMailStrings.NominationNotAccepted,
                                                 1, MessageSpecialType.Normal, cycle.end_date, remove.Key, nhood.name, cycle.end_date.ToString());
                        }
                    }

                    if (selected == 0)
                    {
                        state = DbElectionCycleState.failsafe;
                        break;
                    }

                    //email will be sent by event system. make a bulletin post too
                    SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.VoteSubject, (int)NeighBulletinStrings.Vote, cycle.end_date,
                                     nhood.name, string.Join("\n", candidates.Select(x => "- " + (da.Avatars.Get(x.Key)?.name ?? "(unknown)"))), cycle.end_date.ToString());
                }
                else
                {
                    state = DbElectionCycleState.failsafe;
                }
                break;

            case DbElectionCycleState.ended:
                //end election. if there are any candidates, set the mayor to the one that recieved the most votes.
                var cycleVotes = da.Elections.GetCycleVotes(cycle.cycle_id, DbElectionVoteType.vote);
                if (cycleVotes.Count > 0)
                {
                    var grouped = cycleVotes.GroupBy(x => x.target_avatar_id).OrderByDescending(x => x.Count()).ToList();

                    //verify the winner is still alive and still in this neighborhood
                    string name = "";
                    while (grouped.Count > 0 && !VerifyCanBeMayor(da, grouped[0].Key, (uint)nhood.neighborhood_id, now, ref name))
                    {
                        grouped.RemoveAt(0);
                    }

                    if (grouped.Count == 0)
                    {
                        state = DbElectionCycleState.failsafe;
                        if (nhood.mayor_id != null)
                        {
                            await SetMayor(da, 0, (uint)nhood.neighborhood_id);
                        }
                        break;
                    }

                    var winner = grouped[0];
                    //we have a winner
                    da.Elections.SetCandidateState(new DbElectionCandidate()
                    {
                        election_cycle_id   = cycle.cycle_id,
                        candidate_avatar_id = winner.Key,
                        state = DbCandidateState.won
                    });
                    await SetMayor(da, winner.Key, (uint)nhood.neighborhood_id);

                    mail.SendSystemEmail("f116", (int)NeighMailStrings.YouWinSubject, (int)NeighMailStrings.YouWin,
                                         1, MessageSpecialType.Normal, 0, winner.Key, nhood.name, winner.Count().ToString());

                    //tell the losers they lost
                    grouped.RemoveAt(0);
                    var placement = 2;
                    foreach (var loser in grouped)
                    {
                        da.Elections.SetCandidateState(new DbElectionCandidate()
                        {
                            election_cycle_id   = cycle.cycle_id,
                            candidate_avatar_id = loser.Key,
                            state = DbCandidateState.lost
                        });
                        placement++;
                    }

                    int runnerI = 2;
                    SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.ElectionOverSubject, (int)NeighBulletinStrings.ElectionOver, cycle.end_date,
                                     (da.Avatars.Get(winner.Key)?.name ?? "(unknown)"),
                                     nhood.name,
                                     string.Join("\n", grouped.Select(x => (runnerI++).ToString() + ". " + (da.Avatars.Get(x.Key)?.name ?? "(unknown)"))));
                }
                else
                {
                    state = DbElectionCycleState.failsafe;
                    if (nhood.mayor_id != null)
                    {
                        await SetMayor(da, 0, (uint)nhood.neighborhood_id);
                    }
                }
                break;
            }

            da.Elections.UpdateCycleState(cycle.cycle_id, state);
            if (state == DbElectionCycleState.failsafe && state != cycle.current_state)
            {
                SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.FailsafeSubject, (int)NeighBulletinStrings.Failsafe,
                                 0, nhood.name);
            }
            cycle.current_state = state;

            if (StateHasEmail(state))
            {
                BroadcastNhoodState(da, mail, nhood, cycle);
            }
        }
예제 #5
0
        public async Task TickNeighborhoods(DateTime now)
        {
            var config = Context.Config.Neighborhoods;
            //process the neighbourhoods for this city
            var endDate = new DateTime(now.Year, now.Month, 1).AddMonths(1);

            if (config.Election_Week_Align)
            {
                endDate = FindLastWeek(endDate);
            }
            var timeToNextMonth = (endDate - now);
            var ds = Kernel.Get <IDataService>();

            var epochNow = Epoch.FromDate(now);

            using (var da = DAFactory.Get())
            {
                var midnight          = LotVisitUtils.Midnight(); //gets this morning's midnight (basically current date, with day reset)
                var activityBeginning = midnight - new TimeSpan(7, 0, 0, 0);

                var range      = da.LotVisits.StreamBetweenPlusNhood(Context.ShardId, activityBeginning, midnight);
                var enumerator = range.GetEnumerator();

                var nhoodHours = new Dictionary <uint, double>();

                while (enumerator.MoveNext())
                {
                    var visit = enumerator.Current;
                    var span  = LotVisitUtils.CalculateDateOverlap(activityBeginning, midnight, visit.time_created, visit.time_closed.Value);
                    if (nhoodHours.ContainsKey(visit.neighborhood_id))
                    {
                        nhoodHours[visit.neighborhood_id] += span.TotalMinutes;
                    }
                    else
                    {
                        nhoodHours.Add(visit.neighborhood_id, span.TotalMinutes);
                    }
                }

                //
                var nhoodOrder = nhoodHours.OrderByDescending(x => x.Value);

                var nhoods = da.Neighborhoods.All(Context.ShardId);

                foreach (var nhood in nhoods)
                {
                    var nhoodDS = await ds.Get <Neighborhood>((uint)nhood.neighborhood_id);

                    if (nhoodDS == null)
                    {
                        continue;
                    }
                    //placement within the top neighbourhoods for activity
                    var placement = nhoodOrder.ToList().FindIndex(x => x.Key == nhood.neighborhood_id);
                    if (placement == -1)
                    {
                        placement = nhoods.Count;
                    }

                    nhoodDS.Neighborhood_ActivityRating = (uint)placement + 1;

                    //is there an active cycle for this neighbourhood?
                    var stillActive = false;
                    if (nhood.election_cycle_id != null)
                    {
                        var cycle = da.Elections.GetCycle(nhood.election_cycle_id.Value);
                        if (cycle != null)
                        {
                            if (cycle.current_state == DbElectionCycleState.shutdown ||
                                cycle.current_state == DbElectionCycleState.failsafe)
                            {
                                long timeToEnd = (long)cycle.end_date - epochNow;
                                if (timeToEnd <= 0 && nhood.mayor_id != null)
                                {
                                    await SetMayor(da, 0, (uint)nhood.neighborhood_id);
                                }
                                stillActive = epochNow < cycle.end_date; //can't switch eligibility til we end
                            }
                            else if (cycle.current_state < DbElectionCycleState.ended)
                            {
                                var active = (epochNow >= cycle.start_date && epochNow < cycle.end_date);

                                long timeToEnd = (long)cycle.end_date - epochNow;

                                DbElectionCycleState targetState;
                                if (timeToEnd <= 0)
                                {
                                    targetState = DbElectionCycleState.ended;
                                }
                                else if (timeToEnd <= 60 * 60 * 24 * 3) //last 3 days are the full election
                                {
                                    targetState = DbElectionCycleState.election;
                                }
                                else //all other time is the nomination
                                {
                                    targetState = DbElectionCycleState.nomination;
                                }

                                if (targetState != cycle.current_state)
                                {
                                    await ChangeElectionState(da, nhood, cycle, targetState);

                                    nhoodDS.Neighborhood_ElectionCycle.ElectionCycle_CurrentState = (byte)targetState;
                                }
                                //important: if we are in failsafe mode we can't switch eligibility or start a new cycle.
                                if (cycle.current_state != DbElectionCycleState.ended)
                                {
                                    stillActive = true;
                                }
                            }
                        }
                    }

                    //do we need to start a new cycle?
                    if (!stillActive && timeToNextMonth.TotalDays < 7 && (nhood.flag & 1) == 0)
                    {
                        //update eligibility
                        if ((nhood.flag & 2) > 0)
                        {
                            //not eligibile for elections (temp)
                            //is our placement within bounds?
                            if (placement != -1 && placement < config.Mayor_Elegibility_Limit)
                            {
                                //make us eligible.
                                nhood.flag &= ~(uint)2;
                                nhoodDS.Neighborhood_Flag = nhood.flag;
                                da.Neighborhoods.UpdateFlag((uint)nhood.neighborhood_id, nhood.flag);

                                SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.ElectionBeginSubject, (int)NeighBulletinStrings.ElectionBegin,
                                                 0, nhood.name, config.Mayor_Elegibility_Limit.ToString());
                            }
                        }
                        else
                        {
                            //is our placement outwith bounds?
                            if (placement == -1 || placement >= config.Mayor_Elegilility_Falloff)
                            {
                                //make us ineligible.
                                nhood.flag |= 2;
                                nhoodDS.Neighborhood_Flag = nhood.flag;
                                da.Neighborhoods.UpdateFlag((uint)nhood.neighborhood_id, nhood.flag);

                                //start a shutdown cycle
                                var dbCycle = new DbElectionCycle
                                {
                                    current_state = DbElectionCycleState.shutdown,
                                    election_type = DbElectionCycleType.shutdown,
                                    start_date    = Epoch.FromDate(midnight),
                                    end_date      = Epoch.FromDate(endDate)
                                };
                                var cycleID = da.Elections.CreateCycle(dbCycle);
                                nhoodDS.Neighborhood_ElectionCycle = new ElectionCycle()
                                {
                                    ElectionCycle_CurrentState = (byte)dbCycle.current_state,
                                    ElectionCycle_ElectionType = (byte)dbCycle.election_type,
                                    ElectionCycle_StartDate    = dbCycle.start_date,
                                    ElectionCycle_EndDate      = dbCycle.end_date
                                };
                                da.Neighborhoods.UpdateCycle((uint)nhood.neighborhood_id, cycleID);

                                SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.ElectionCancelledSubject, (int)NeighBulletinStrings.ElectionCancelled,
                                                 0, nhood.name);
                            }
                        }

                        var eligible = (nhood.flag & 2) == 0;

                        if (eligible || nhood.election_cycle_id == null)
                        {
                            //yes
                            var dbCycle = new DbElectionCycle
                            {
                                current_state = (eligible) ? DbElectionCycleState.nomination : DbElectionCycleState.shutdown,
                                election_type = (eligible) ? DbElectionCycleType.election : DbElectionCycleType.shutdown,
                                start_date    = Epoch.FromDate(midnight),
                                end_date      = Epoch.FromDate(endDate)
                            };
                            var cycleID = da.Elections.CreateCycle(dbCycle);

                            nhoodDS.Neighborhood_ElectionCycle = new ElectionCycle()
                            {
                                ElectionCycle_CurrentState = (byte)dbCycle.current_state,
                                ElectionCycle_ElectionType = (byte)dbCycle.election_type,
                                ElectionCycle_StartDate    = dbCycle.start_date,
                                ElectionCycle_EndDate      = dbCycle.end_date
                            };
                            da.Neighborhoods.UpdateCycle((uint)nhood.neighborhood_id, cycleID);

                            if (eligible)
                            {
                                //notify current mayor
                                if (nhood.mayor_id != null)
                                {
                                    var mail = Kernel.Get <MailHandler>();
                                    mail.SendSystemEmail("f116", (int)NeighMailStrings.TermLengthSubject, (int)NeighMailStrings.TermLength,
                                                         1, MessageSpecialType.Nominate, dbCycle.end_date, nhood.mayor_id.Value, nhood.name, dbCycle.end_date.ToString());
                                }

                                //post to bulletin
                                var nomEndDate = dbCycle.end_date - 60 * 60 * 24 * 3; //nomination ends 3 days before end of cycle
                                SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.NominateSubject, (int)NeighBulletinStrings.Nominate, nomEndDate,
                                                 nhood.name, nomEndDate.ToString());
                            }
                        }
                    }
                }
            }
        }
예제 #6
0
        public async void Handle(IVoltronSession session, NhoodRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

            var config       = Context.Config.Neighborhoods;
            var moveTime     = config.Election_Move_Penalty * 24 * 60 * 60; //24 * 60 * 60 * 30; //must live in an nhood 30 days before participating in an election
            var rateMoveTime = config.Rating_Move_Penalty * 24 * 60 * 60;   //24 * 60 * 60 * 30; //must live in an nhood 30 days before participating in an election
            var mail         = Kernel.Get <MailHandler>();

            try
            {
                using (var da = DA.Get())
                {
                    var myAva = da.Avatars.Get(session.AvatarId);
                    if (myAva == null)
                    {
                        Code(NhoodResponseCode.UNKNOWN_ERROR);
                    }

                    if (packet.Type >= NhoodRequestType.DELETE_RATE)
                    {
                        if (myAva.moderation_level == 0)
                        {
                            session.Write(Code(NhoodResponseCode.NOT_MODERATOR));
                            return;
                        }
                    }

                    //are we nhood gameplay banned?

                    var ban = da.Neighborhoods.GetNhoodBan(myAva.user_id);
                    if (ban != null)
                    {
                        session.Write(new NhoodResponse
                        {
                            Code       = NhoodResponseCode.NHOOD_GAMEPLAY_BAN,
                            Message    = ban.ban_reason,
                            BanEndDate = ban.end_date
                        });
                        return;
                    }

                    //common info used by most requests
                    var myLotID = da.Roommates.GetAvatarsLots(session.AvatarId).FirstOrDefault();
                    var myLot   = (myLotID == null) ? null : da.Lots.Get(myLotID.lot_id);

                    var freeVote  = da.Elections.GetFreeVote(session.AvatarId);
                    var freeNhood = (int)(myLot?.neighborhood_id ?? 0);
                    var voteValue = (freeVote == null) ? config.Vote_Normal_Value : config.Vote_Free_Value;
                    if (freeVote != null)
                    {
                        freeNhood = freeVote.neighborhood_id;
                    }

                    switch (packet.Type)
                    {
                    //user requests
                    case NhoodRequestType.CAN_RATE:
                    case NhoodRequestType.RATE:
                    {
                        if (packet.Value > 10 || packet.Value < 0 || packet.Message == null || packet.Message.Length > 200)
                        {
                            session.Write(Code(NhoodResponseCode.INVALID_RATING));
                            return;
                        }
                        if (myLot == null || myLot.neighborhood_id != packet.TargetNHood)
                        {
                            session.Write(Code(NhoodResponseCode.NOT_IN_NHOOD));
                            return;
                        }
                        if (session.AvatarId == packet.TargetAvatar)
                        {
                            session.Write(Code(NhoodResponseCode.CANT_RATE_AVATAR));         //you can't rate yourself...
                            return;
                        }
                        if (Epoch.Now - myAva.move_date < rateMoveTime)
                        {
                            session.Write(Code(NhoodResponseCode.YOU_MOVED_RECENTLY)); return;
                        }
                        //verify the target avatar is the current mayor
                        var rateNhood = da.Neighborhoods.Get(packet.TargetNHood);
                        //user check: ratings are technically towards individual avatars, but are shared between the same user.
                        var avaFrom = da.Avatars.Get(session.AvatarId);
                        var avaTo   = da.Avatars.Get(packet.TargetAvatar);
                        if (rateNhood == null || avaFrom == null || avaTo == null)
                        {
                            session.Write(Code(NhoodResponseCode.UNKNOWN_ERROR));         //shouldn't happen, but just in case
                            return;
                        }
                        if (rateNhood.mayor_id != packet.TargetAvatar)
                        {
                            session.Write(Code(NhoodResponseCode.NOT_YOUR_MAYOR));         //you can't rate yourself...
                            return;
                        }

                        if (packet.Type == NhoodRequestType.RATE)
                        {
                            //insert or replace rating
                            var id = da.Elections.SetRating(new DbMayorRating()
                                {
                                    from_avatar_id = avaFrom.avatar_id,
                                    to_avatar_id   = avaTo.avatar_id,
                                    from_user_id   = avaFrom.user_id,
                                    to_user_id     = avaTo.user_id,
                                    comment        = packet.Message,
                                    rating         = packet.Value,
                                    neighborhood   = packet.TargetNHood,
                                    date           = Epoch.Now,
                                    anonymous      = 1,
                                });

                            var ds = Kernel.Get <IDataService>();
                            if (id != 0)
                            {
                                ds.Invalidate <MayorRating>(id);        //update this rating in data service
                            }
                            ds.Invalidate <Avatar>(packet.TargetAvatar);
                        }

                        session.Write(Code(NhoodResponseCode.SUCCESS)); return;
                    }

                    case NhoodRequestType.CAN_NOMINATE:
                    case NhoodRequestType.NOMINATE:
                    case NhoodRequestType.CAN_VOTE:
                    case NhoodRequestType.VOTE:
                    {
                        if (freeVote != null)
                        {
                            packet.TargetNHood = (uint)freeNhood;
                        }
                        if (myLot == null || freeNhood != packet.TargetNHood)
                        {
                            session.Write(Code(NhoodResponseCode.NOT_IN_NHOOD)); return;
                        }

                        var now = Epoch.Now;
                        if (now - myAva.move_date < moveTime)
                        {
                            session.Write(Code(NhoodResponseCode.YOU_MOVED_RECENTLY)); return;
                        }

                        //check if voting cycle in correct state
                        var nhood = da.Neighborhoods.Get(packet.TargetNHood);
                        if (nhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }
                        var cycle = (nhood.election_cycle_id == null) ? null : da.Elections.GetCycle(nhood.election_cycle_id.Value);
                        if (cycle == null)
                        {
                            session.Write(Code(NhoodResponseCode.ELECTION_OVER)); return;
                        }

                        var nominations = packet.Type == NhoodRequestType.CAN_NOMINATE || packet.Type == NhoodRequestType.NOMINATE;
                        if ((nominations && cycle.current_state != DbElectionCycleState.nomination) ||
                            (!nominations && cycle.current_state != DbElectionCycleState.election))
                        {
                            session.Write(Code(NhoodResponseCode.BAD_STATE)); return;
                        }

                        DbAvatar targetAva = null;
                        if (packet.Type != NhoodRequestType.CAN_NOMINATE && packet.Type != NhoodRequestType.CAN_VOTE)
                        {
                            //when we are actually nominating or voting, we have a target avatar in mind.

                            targetAva = da.Avatars.Get(packet.TargetAvatar);
                            if (targetAva == null)
                            {
                                session.Write(Code(NhoodResponseCode.INVALID_AVATAR)); return;
                            }
                            var targLotID = da.Roommates.GetAvatarsLots(packet.TargetAvatar).FirstOrDefault();
                            var targLot   = (targLotID == null) ? null : da.Lots.Get(targLotID.lot_id);

                            if (targLot == null || targLot.neighborhood_id != packet.TargetNHood)
                            {
                                session.Write(Code(NhoodResponseCode.CANDIDATE_NOT_IN_NHOOD)); return;
                            }

                            var targBan = da.Neighborhoods.GetNhoodBan(targetAva.user_id);
                            if (targBan != null)
                            {
                                session.Write(Code(NhoodResponseCode.CANDIDATE_NHOOD_GAMEPLAY_BAN)); return;
                            }

                            if (now - targetAva.move_date < moveTime)
                            {
                                session.Write(Code(NhoodResponseCode.CANDIDATE_MOVED_RECENTLY)); return;
                            }
                        }

                        //ok, we're all good.

                        if (!nominations)
                        {
                            //have we already voted?
                            //note: this should be double checked with a BEFORE INSERT on the table.
                            //just in case there's some kind of race condition due to this request being duplicated.
                            //this check is therefore just to get a better voting error message.
                            DbElectionVote existing = da.Elections.GetMyVote(session.AvatarId, cycle.cycle_id, DbElectionVoteType.vote);

                            if (existing != null)
                            {
                                if (existing.from_avatar_id != session.AvatarId)
                                {
                                    session.Write(Code(NhoodResponseCode.ALREADY_VOTED_SAME_IP));         //couldn't vote due to relation
                                }
                                else
                                {
                                    session.Write(Code(NhoodResponseCode.ALREADY_VOTED));
                                }
                            }

                            if (packet.Type == NhoodRequestType.CAN_VOTE)
                            {
                                //we are allowed to vote

                                //send back the candidate list


                                var sims   = da.Elections.GetCandidates(cycle.cycle_id);
                                var result = new List <NhoodCandidate>();

                                foreach (var x in sims)
                                {
                                    if (x.state != DbCandidateState.running)
                                    {
                                        continue;
                                    }
                                    var ava = (await DataService.Get <Avatar>(x.candidate_avatar_id));
                                    if (ava == null)
                                    {
                                        continue;
                                    }

                                    var win = da.Elections.FindLastWin(x.candidate_avatar_id);
                                    result.Add(new NhoodCandidate()
                                        {
                                            ID            = x.candidate_avatar_id,
                                            Name          = ava.Avatar_Name,
                                            Rating        = ava.Avatar_MayorRatingHundredth,
                                            Message       = x.comment,
                                            LastNhoodName = win?.nhood_name ?? "",
                                            LastNhoodID   = win?.nhood_id ?? 0,
                                            TermNumber    = (uint)((nhood.mayor_id == x.candidate_avatar_id) ? GetTermsSince(nhood.mayor_elected_date) : 0)
                                        });
                                }

                                session.Write(new NhoodCandidateList()
                                    {
                                        NominationMode = false,
                                        Candidates     = result.ToList()
                                    });

                                session.Write(Code(NhoodResponseCode.SUCCESS)); return;
                            }

                            //extra checks. has the target user been nominated?
                            if (!da.Elections.GetCandidates(cycle.cycle_id, DbCandidateState.running).Any(x => x.candidate_avatar_id == packet.TargetAvatar))
                            {
                                session.Write(Code(NhoodResponseCode.CANDIDATE_NOT_NOMINATED)); return;
                            }

                            //put our vote through! democracy is great.
                            var success = da.Elections.CreateVote(new DbElectionVote()
                                {
                                    date = Epoch.Now,
                                    election_cycle_id = cycle.cycle_id,
                                    from_avatar_id    = session.AvatarId,
                                    target_avatar_id  = packet.TargetAvatar,
                                    type  = DbElectionVoteType.vote,
                                    value = voteValue
                                });
                            if (!success)
                            {
                                session.Write(Code(NhoodResponseCode.ALREADY_VOTED));
                                return;
                            }

                            mail.SendSystemEmail("f116", (int)NeighMailStrings.VoteCountedSubject, (int)NeighMailStrings.VoteCounted,
                                                 1, MessageSpecialType.Normal, cycle.end_date, session.AvatarId, targetAva.name, nhood.name);
                            session.Write(Code(NhoodResponseCode.SUCCESS));
                        }
                        else
                        {
                            //have we already nominated?
                            DbElectionVote existing = da.Elections.GetMyVote(session.AvatarId, cycle.cycle_id, DbElectionVoteType.nomination);

                            if (existing != null)
                            {
                                if (existing.from_avatar_id != session.AvatarId)
                                {
                                    session.Write(Code(NhoodResponseCode.ALREADY_VOTED_SAME_IP));         //couldn't nominate due to relation
                                }
                                else
                                {
                                    session.Write(Code(NhoodResponseCode.ALREADY_VOTED));
                                }
                            }

                            if (packet.Type == NhoodRequestType.CAN_NOMINATE)
                            {
                                //we are allowed to nominate.

                                //send back the list of sims in nhood
                                var sims   = da.Avatars.GetPossibleCandidatesNhood((uint)packet.TargetNHood);
                                var result = sims.Select(x => new NhoodCandidate()
                                    {
                                        ID     = x.avatar_id,
                                        Name   = x.name,
                                        Rating = (x.rating == null) ? uint.MaxValue : (uint)((x.rating / 2) * 100)
                                    });

                                session.Write(new NhoodCandidateList()
                                    {
                                        NominationMode = true,
                                        Candidates     = result.ToList()
                                    });

                                session.Write(Code(NhoodResponseCode.SUCCESS)); return;
                            }

                            //do the nomination.
                            var success = da.Elections.CreateVote(new DbElectionVote()
                                {
                                    date = Epoch.Now,
                                    election_cycle_id = cycle.cycle_id,
                                    from_avatar_id    = session.AvatarId,
                                    target_avatar_id  = packet.TargetAvatar,
                                    type  = DbElectionVoteType.nomination,
                                    value = voteValue
                                });
                            if (!success)
                            {
                                session.Write(Code(NhoodResponseCode.ALREADY_VOTED));
                                return;
                            }

                            //if >= 3 nominations, allow the player to run for election.
                            var noms = da.Elections.GetCycleVotesForAvatar(packet.TargetAvatar, cycle.cycle_id, DbElectionVoteType.nomination);
                            if (noms.Count() >= config.Min_Nominations)
                            {
                                var created = da.Elections.CreateCandidate(new DbElectionCandidate()
                                    {
                                        candidate_avatar_id = packet.TargetAvatar,
                                        election_cycle_id   = cycle.cycle_id,
                                        comment             = packet.Message,
                                        state = DbCandidateState.informed
                                    });
                                //only send the mail if they have not accepted.
                                if (created)
                                {
                                    mail.SendSystemEmail("f116", (int)NeighMailStrings.NominationQuerySubject, (int)NeighMailStrings.NominationQuery,
                                                         1, MessageSpecialType.AcceptNomination, cycle.end_date, packet.TargetAvatar, nhood.name, cycle.end_date.ToString());
                                }
                            }

                            mail.SendSystemEmail("f116", (int)NeighMailStrings.NominationCountedSubject, (int)NeighMailStrings.NominationCounted,
                                                 1, MessageSpecialType.Normal, cycle.end_date, session.AvatarId, targetAva.name, nhood.name);

                            session.Write(Code(NhoodResponseCode.SUCCESS));
                        }

                        break;
                    }

                    case NhoodRequestType.NOMINATION_RUN:
                    case NhoodRequestType.CAN_RUN:
                    {
                        //if a user has been nominated 3 or more times, they will be asked if they would like to run for mayor by email.
                        //the email will contain a button that lets the user accept the nomination.
                        //this doesn't immediately get them running for mayor, it means that they are a valid selection from
                        //the top nominated candidates when the nominations are finalized.

                        //first check if we have the three required nominations
                        if (myLot == null || myLot.neighborhood_id != packet.TargetNHood)
                        {
                            session.Write(Code(NhoodResponseCode.NOT_IN_NHOOD)); return;
                        }

                        var nhood = da.Neighborhoods.Get(packet.TargetNHood);
                        if (nhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }
                        var cycle = (nhood.election_cycle_id == null) ? null : da.Elections.GetCycle(nhood.election_cycle_id.Value);
                        if (cycle == null)
                        {
                            session.Write(Code(NhoodResponseCode.ELECTION_OVER)); return;
                        }

                        if (cycle.current_state != DbElectionCycleState.nomination)
                        {
                            session.Write(Code(NhoodResponseCode.BAD_STATE)); return;
                        }

                        //have we been nominated the minimum number of times? (3)
                        var noms = da.Elections.GetCycleVotesForAvatar(session.AvatarId, cycle.cycle_id, DbElectionVoteType.nomination);
                        if (noms.Count < config.Min_Nominations)
                        {
                            session.Write(Code(NhoodResponseCode.NOBODY_NOMINATED_YOU_IDIOT)); return;
                        }

                        if (packet.Type == NhoodRequestType.CAN_RUN)
                        {
                            if (da.Elections.GetCandidate(session.AvatarId, cycle.cycle_id, DbCandidateState.informed) == null)
                            {
                                session.Write(Code(NhoodResponseCode.ALREADY_RUNNING));
                            }
                            else
                            {
                                session.Write(Code(NhoodResponseCode.SUCCESS));
                            }
                        }
                        else
                        {
                            var success = da.Elections.SetCandidateState(new DbElectionCandidate()
                                {
                                    candidate_avatar_id = session.AvatarId,
                                    election_cycle_id   = cycle.cycle_id,
                                    comment             = packet.Message,
                                    state = DbCandidateState.running
                                });

                            if (success)
                            {
                                mail.SendSystemEmail("f116", (int)NeighMailStrings.NominationAcceptedSubject, (int)NeighMailStrings.NominationAccepted,
                                                     1, MessageSpecialType.Normal, cycle.end_date, session.AvatarId, nhood.name, cycle.end_date.ToString());

                                session.Write(Code(NhoodResponseCode.SUCCESS));
                            }
                            else
                            {
                                session.Write(Code(NhoodResponseCode.ALREADY_RUNNING));
                            }
                        }
                        return;
                    }

                    case NhoodRequestType.CAN_FREE_VOTE:
                    case NhoodRequestType.FREE_VOTE:
                    {
                        //should live somewhere:
                        if (myLot == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }

                        //we shouldn't already be enrolled
                        if (freeNhood != myLot.neighborhood_id)
                        {
                            session.Write(Code(NhoodResponseCode.ALREADY_ENROLLED_FOR_FREE_VOTE)); return;
                        }

                        //our nhood needs to be ineligible
                        var ourNhood = da.Neighborhoods.Get(myLot.neighborhood_id);
                        if (ourNhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }

                        var cycle = (ourNhood.election_cycle_id == null) ? null : da.Elections.GetCycle(ourNhood.election_cycle_id.Value);
                        if (cycle != null && cycle.current_state != DbElectionCycleState.shutdown)
                        {
                            session.Write(Code(NhoodResponseCode.FREE_VOTE_ALREADY_ELIGIBLE)); return;
                        }

                        //get eligible nhoods
                        var eligible = da.Elections.GetActiveCycles(Context.ShardId);

                        if (eligible.Count == 0)
                        {
                            session.Write(Code(NhoodResponseCode.FREE_VOTE_ELECTION_OVER)); return;
                        }

                        //our last move needs to have been before the nhood cycle started
                        var now = Epoch.Now;
                        if (eligible.All(x => x.start_date < myAva.move_date))
                        {
                            session.Write(Code(NhoodResponseCode.FREE_VOTE_MOVE_DATE)); return;
                        }

                        if (packet.Type == NhoodRequestType.CAN_FREE_VOTE)
                        {
                            //send the eligible nhoods
                            var result = eligible.Select(x => new NhoodCandidate()
                                {
                                    ID     = (uint)x.nhood_id,
                                    Name   = x.name,
                                    Rating = uint.MaxValue
                                });

                            session.Write(new NhoodCandidateList()
                                {
                                    NominationMode = true,
                                    Candidates     = result.ToList()
                                });

                            session.Write(Code(NhoodResponseCode.SUCCESS));
                            return;
                        }

                        //the target nhood needs to be eligible, and have an ongoing election
                        var targ = da.Neighborhoods.Get(packet.TargetNHood);
                        if (targ == null || targ.election_cycle_id == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY));
                            return;
                        }

                        var targCycle = da.Elections.GetCycle((uint)targ.election_cycle_id);
                        if (targCycle == null || targCycle.current_state == DbElectionCycleState.shutdown)
                        {
                            session.Write(Code(NhoodResponseCode.NHOOD_NO_ELECTION));
                            return;
                        }

                        var fVote = new DbElectionFreeVote()
                        {
                            avatar_id       = session.AvatarId,
                            cycle_id        = targCycle.cycle_id,
                            neighborhood_id = targ.neighborhood_id,
                            date            = Epoch.Now,
                            expire_date     = targCycle.end_date
                        };
                        if (!da.Elections.EnrollFreeVote(fVote))
                        {
                            session.Write(Code(NhoodResponseCode.ALREADY_ENROLLED_FOR_FREE_VOTE));
                            return;
                        }

                        mail.SendSystemEmail("f116", (int)NeighMailStrings.FreeVoteConfirmationSubject, (int)NeighMailStrings.FreeVoteConfirmation,
                                             1, MessageSpecialType.Normal, targCycle.end_date, session.AvatarId, targ.name);

                        Nhoods.SendStateEmail(da, mail, targ, targCycle, session.AvatarId);

                        session.Write(Code(NhoodResponseCode.SUCCESS));
                        return;
                    }

                    // ======= management =======
                    case NhoodRequestType.DELETE_RATE:
                        var beforeDelete = da.Elections.GetRating(packet.Value);
                        if (da.Elections.DeleteRating(packet.Value))
                        {
                            var ds = Kernel.Get <IDataService>();
                            try
                            {
                                ds.Invalidate <Avatar>(beforeDelete.from_avatar_id);
                                ds.Invalidate <MayorRating>(packet.Value);    //update this rating in data service
                            } catch (Exception)
                            {
                            }

                            session.Write(new NhoodResponse()
                            {
                                Code    = NhoodResponseCode.SUCCESS,
                                Message = (beforeDelete?.from_avatar_id ?? 0).ToString()
                            });
                        }
                        else
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY));
                        }
                        return;

                    case NhoodRequestType.FORCE_MAYOR:
                        //set the mayor.
                        await Nhoods.SetMayor(da, packet.TargetAvatar, packet.TargetNHood);

                        session.Write(Code(NhoodResponseCode.SUCCESS));
                        return;

                    case NhoodRequestType.ADD_CANDIDATE:
                        //check if voting cycle in correct state
                    {
                        var nhood = da.Neighborhoods.Get(packet.TargetNHood);
                        if (nhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }
                        var cycle = (nhood.election_cycle_id == null) ? null : da.Elections.GetCycle(nhood.election_cycle_id.Value);
                        if (cycle == null)
                        {
                            session.Write(Code(NhoodResponseCode.ELECTION_OVER)); return;
                        }
                        //while candidates DO have a use in nominations, adding them is largely pointless before the elections have begun
                        //(because they will likely be removed when choosing the top 5 anyways)
                        if (cycle.current_state != DbElectionCycleState.election)
                        {
                            session.Write(Code(NhoodResponseCode.BAD_STATE)); return;
                        }
                    }
                    break;

                    case NhoodRequestType.REMOVE_CANDIDATE:
                        //get current cycle
                    {
                        var nhood = da.Neighborhoods.Get(packet.TargetNHood);
                        if (nhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }
                        var cycle = (nhood.election_cycle_id == null) ? null : da.Elections.GetCycle(nhood.election_cycle_id.Value);
                        if (cycle == null)
                        {
                            session.Write(Code(NhoodResponseCode.ELECTION_OVER)); return;
                        }

                        if (da.Elections.DeleteCandidate(cycle.cycle_id, packet.TargetAvatar))
                        {
                            session.Write(Code(NhoodResponseCode.SUCCESS));
                        }
                        else
                        {
                            session.Write(Code(NhoodResponseCode.INVALID_AVATAR));
                        }
                    }
                    break;

                    case NhoodRequestType.TEST_ELECTION:
                        //create an election cycle
                    {
                        var nhood = da.Neighborhoods.Get(packet.TargetNHood);
                        if (nhood == null)
                        {
                            session.Write(Code(NhoodResponseCode.MISSING_ENTITY)); return;
                        }

                        var cycle = new DbElectionCycle()
                        {
                            current_state = DbElectionCycleState.nomination,
                            election_type = DbElectionCycleType.election,
                            start_date    = Epoch.Now,
                            end_date      = packet.Value
                        };
                        var cycleID = da.Elections.CreateCycle(cycle);
                        if (cycleID == 0)
                        {
                            session.Write(Code(NhoodResponseCode.UNKNOWN_ERROR));
                            return;
                        }
                        cycle.cycle_id          = cycleID;
                        nhood.election_cycle_id = cycleID;
                        da.Neighborhoods.UpdateCycle((uint)nhood.neighborhood_id, cycleID);

                        await Nhoods.ChangeElectionState(da, nhood, cycle, (DbElectionCycleState)packet.TargetAvatar);

                        session.Write(Code(NhoodResponseCode.SUCCESS));
                        return;
                    }

                    case NhoodRequestType.PRETEND_DATE:
                        try
                        {
                            uint day = 60 * 60 * 24;
                            Nhoods.SaveCheatOffset((((packet.Value - Epoch.Now) + day - 1) / day) * day);
                            await Nhoods.TickNeighborhoods(Epoch.ToDate(packet.Value));

                            session.Write(Code(NhoodResponseCode.SUCCESS));
                        }
                        catch (Exception e)
                        {
                            session.Write(new NhoodResponse()
                            {
                                Code    = NhoodResponseCode.UNKNOWN_ERROR,
                                Message = e.ToString()
                            });
                        }
                        return;

                    case NhoodRequestType.NHOOD_GAMEPLAY_BAN:
                    {
                        var targetAva = da.Avatars.Get(packet.TargetAvatar);
                        if (targetAva == null)
                        {
                            session.Write(Code(NhoodResponseCode.INVALID_AVATAR));
                        }
                        var success = da.Neighborhoods.AddNhoodBan(new DbNhoodBan()
                            {
                                user_id    = targetAva.user_id,
                                ban_reason = packet.Message,
                                end_date   = packet.Value
                            });
                        if (success)
                        {
                            mail.SendSystemEmail("f116", (int)NeighMailStrings.NeighGameplayBanSubject, (int)NeighMailStrings.NeighGameplayBan,
                                                 1, MessageSpecialType.Normal, packet.Value, packet.TargetAvatar, packet.Message, packet.Value.ToString());
                        }
                        session.Write(Code(NhoodResponseCode.SUCCESS));
                        return;
                    }

                    default:
                        session.Write(Code(NhoodResponseCode.UNKNOWN_ERROR)); return;
                    }
                }
            } catch (Exception e)
            {
                LOG.Error(e.ToString());
                session?.Write(Code(NhoodResponseCode.UNKNOWN_ERROR));
            }
        }
예제 #7
0
        public void BroadcastNhoodState(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle)
        {
            var all = Sessions.Clone();

            foreach (var session in all.OfType <IVoltronSession>())
            {
                if (session.IsAnonymous)
                {
                    continue;
                }

                var myLotID = da.Roommates.GetAvatarsLots(session.AvatarId).FirstOrDefault();
                var myLot   = (myLotID == null) ? null : da.Lots.Get(myLotID.lot_id);

                var free    = da.Elections.GetFreeVote(session.AvatarId);
                var nhoodID = (int)(myLot?.neighborhood_id ?? 0);
                if (free != null)
                {
                    nhoodID = free.neighborhood_id; //enrolled to a free vote. receive vote mail for that neighborhood
                }

                if (myLot != null && nhoodID == nhood.neighborhood_id)
                {
                    SendStateEmail(da, mail, nhood, cycle, session.AvatarId);
                }
            }
        }
        protected Neighborhood HydrateOne(DbNeighborhood nhood, List <uint> avatars, List <uint> lots, uint townHallLoc, DbElectionCycle cycle,
                                          List <DbLotVisitNhood> visits, List <KeyValuePair <uint, double> > order)
        {
            var rand = new Random();

            var result = new Neighborhood
            {
                Id = (uint)nhood.neighborhood_id,

                Neighborhood_ActivityRating = 1,
                Neighborhood_AvatarCount    = (uint)avatars.Count,
                Neighborhood_CenterGridXY   = nhood.location,
                Neighborhood_Color          = nhood.color,
                Neighborhood_Description    = nhood.description,
                Neighborhood_ElectedDate    = nhood.mayor_elected_date,
                Neighborhood_ElectionCycle  = new ElectionCycle(),
                Neighborhood_Flag           = nhood.flag,
                Neighborhood_IconURL        = nhood.icon_url ?? "",
                Neighborhood_LotCount       = (uint)lots.Count,
                Neighborhood_MayorID        = nhood.mayor_id ?? 0,
                Neighborhood_Name           = nhood.name,
                Neighborhood_TownHallXY     = townHallLoc,
            };

            SetElectionCycle(result, cycle);
            SetTop10s(result, avatars, visits, order);

            return(result);
        }