protected override void PreLoad(Callback <uint, Neighborhood> appender)
        {
            using (var db = DAFactory.Get())
            {
                var nhoods = db.Neighborhoods.All(ShardId);

                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 visits     = db.LotVisits.StreamBetweenPlusNhood(ShardId, activityBeginning, midnight).ToList();
                var enumerator = visits.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 order = nhoodHours.OrderByDescending(x => x.Value).ToList();
                WorstRating = nhoods.Count;
                foreach (var item in nhoods)
                {
                    var lots      = db.Lots.GetLocationsInNhood((uint)item.neighborhood_id);
                    var avatars   = db.Avatars.GetLivingInNhood((uint)item.neighborhood_id);
                    var townHall  = db.Lots.Get(item.town_hall_id ?? 0)?.location ?? 0;
                    var cycle     = (item.election_cycle_id == null) ? null : db.Elections.GetCycle(item.election_cycle_id.Value);
                    var converted = HydrateOne(item, avatars, lots, townHall, cycle, visits, order);
                    var intId     = (uint)item.neighborhood_id;
                    appender(intId, converted);
                }

                //
                var neighObj = nhoods.Select(x =>
                {
                    var loc    = MapCoordinates.Unpack(x.location);
                    var result = new CityNeighbourhood()
                    {
                        Name        = x.name,
                        Color       = new Color(x.color),
                        Description = x.description,
                        GUID        = x.guid,
                        Location    = new Point(loc.X, loc.Y),
                        ID          = x.neighborhood_id
                    };
                    return(result);
                }).ToList();

                Lots.CityRepresentation.City_NeighJSON = JsonConvert.SerializeObject(neighObj);
            }
        }
Esempio n. 2
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());
                            }
                        }
                    }
                }
            }
        }
        public void SetTop10s(Neighborhood nhood, List <uint> avatars, List <DbLotVisitNhood> visits, List <KeyValuePair <uint, double> > order)
        {
            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 index = order.FindIndex(x => x.Key == nhood.Id);

            nhood.Neighborhood_ActivityRating = (uint)((index == -1) ? WorstRating : (index + 1));
            var subset = visits.Where(x => x.neighborhood_id == nhood.Id && x.type == DbLotVisitorType.visitor);

            //get the total hours for all lots in the nhood
            var enumerator = subset.GetEnumerator();
            var lotHours   = new Dictionary <uint, double>();
            var cats       = new Dictionary <uint, LotCategory>();

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

            var ordered = lotHours.OrderByDescending(x => x.Value);

            //TOP 10 OVERALL
            nhood.Neighborhood_TopLotOverall = ImmutableList.Create(ordered.Take(10).Select(x => x.Key).ToArray());

            //TOP 10 CATEGORIES
            var categories = Enum.GetValues(typeof(LotCategory)).Cast <LotCategory>().Skip(1).Take(10);

            nhood.Neighborhood_TopLotCategory = ImmutableList.Create(categories.Select(x => ordered.FirstOrDefault(y => cats[y.Key] == x).Key).ToArray());

            //avatars activity outwith their neighbourhood still counts - so we need to take another subset.
            var avas    = new HashSet <uint>(avatars); //faster if this is a hashset
            var subset2 = visits.Where(x => avas.Contains(x.avatar_id));

            //TOP 10 ACTIVITY
            enumerator = subset2.GetEnumerator();
            var avaHours = 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 (avaHours.ContainsKey((uint)visit.avatar_id))
                {
                    avaHours[(uint)visit.avatar_id] += span.TotalMinutes;
                }
                else
                {
                    avaHours.Add((uint)visit.avatar_id, span.TotalMinutes);
                }
            }
            ordered = avaHours.OrderByDescending(x => x.Value);

            nhood.Neighborhood_TopAvatarActivity = ImmutableList.Create(ordered.Take(10).Select(x => x.Key).ToArray());
        }
Esempio n. 4
0
        public void Run(TaskContext context)
        {
            Running = true;
            var tuning = Tuning.Bonus;

            if (tuning == null)
            {
                tuning = new BonusTaskTuning();
            }

            if (context.ShardId == null || !context.ShardId.HasValue)
            {
                throw new Exception("Top 100 must be given a shard_id to process");
            }

            using (var db = DAFactory.Get())
            {
                var endTime = LotVisitUtils.Midnight();
                var endDay  = endTime.Subtract(TimeSpan.FromMilliseconds(1));
                endDay = new DateTime(endDay.Year, endDay.Month, endDay.Day);

                var startTime = endTime.Subtract(TimeSpan.FromDays(4));
                var shardId   = context.ShardId;

                var vistorHourScale = db.Tuning.AllCategory("category_mul", 2).ToDictionary(x => x.tuning_index); //0: relationship, 1: skill/money, 2: visitor hour scale

                while (startTime < endTime)
                {
                    var dayStart = startTime;
                    var dayEnd   = dayStart.Add(TimeSpan.FromDays(1));

                    var stream     = db.LotVisits.StreamBetween(shardId.Value, dayStart, dayEnd);
                    var enumerator = stream.GetEnumerator();

                    var hours = new Dictionary <int, double>();

                    while (Running && enumerator.MoveNext())
                    {
                        var visit = enumerator.Current;
                        var span  = LotVisitUtils.CalculateDateOverlap(dayStart, dayEnd, visit.time_created, visit.time_closed.Value);
                        if (hours.ContainsKey(visit.lot_id))
                        {
                            hours[visit.lot_id] += span.TotalMinutes;
                        }
                        else
                        {
                            hours.Add(visit.lot_id, span.TotalMinutes);
                        }
                    }

                    db.LotVisitTotals.Insert(hours.Where(x => x.Value > 0).Select(x =>
                    {
                        return(new DbLotVisitTotal()
                        {
                            lot_id = x.Key, date = dayStart, minutes = (int)x.Value
                        });
                    }));

                    startTime = startTime.Add(TimeSpan.FromDays(1));
                }

                var top100Calculated = db.LotTop100.Calculate(endTime, context.ShardId.Value);
                if (!top100Calculated)
                {
                    throw new Exception("Unknown error while calculating top 100 lots");
                }

                var bonusMetrics = db.Bonus.GetMetrics(endDay, context.ShardId.Value).ToList(); //force this as a list. if we lazy evaluate it, an exception will be thrown.

                db.Bonus.Insert(bonusMetrics.Select(x =>
                {
                    int?bonus_property = null;
                    int?bonus_visitor  = null;
                    int?bonus_sim      = null;

                    float multiplier = 1;
                    DbTuning cattuning;
                    if (vistorHourScale.TryGetValue((int)x.category, out cattuning))
                    {
                        multiplier = cattuning.value;
                    }

                    if (x.visitor_minutes != null && x.visitor_minutes >= 60)
                    {
                        bonus_visitor = (int)(Math.Floor((double)x.visitor_minutes / (double)60) * tuning.visitor_bonus.per_unit * multiplier);
                    }

                    if (x.property_rank != null)
                    {
                        bonus_property = (100 - x.property_rank.Value + 1) * tuning.property_bonus.per_unit;

                        if (tuning.property_bonus.overrides != null &&
                            tuning.property_bonus.overrides.ContainsKey(x.property_rank.Value))
                        {
                            bonus_property = tuning.property_bonus.overrides[x.property_rank.Value];
                        }
                    }

                    return(new DbBonus()
                    {
                        avatar_id = x.avatar_id,
                        period = endDay,
                        bonus_property = bonus_property,
                        bonus_visitor = bonus_visitor,
                        bonus_sim = bonus_sim
                    });
                }));
            }
        }