예제 #1
0
        private bool VerifyCanBeMayor(IDA da, uint avatar_id, uint nhood_id, uint now, ref string name)
        {
            //avatar must exist, their lot must be in the neighbourhood. time since moving is checked when sims try to nominate in the first place

            var ava = da.Avatars.Get(avatar_id);

            name = ava.name;
            if (ava == null)
            {
                return(false);
            }
            var lotid = da.Roommates.GetAvatarsLots(avatar_id).FirstOrDefault();

            if (lotid == null)
            {
                return(false);
            }
            var lot = da.Lots.Get(lotid.lot_id);

            if (lot == null || lot.neighborhood_id != nhood_id)
            {
                return(false);
            }

            var nhoodBan = da.Neighborhoods.GetNhoodBan(ava.user_id);

            if (nhoodBan != null)
            {
                return(false);                  //neighborhood banned user cannot be mayor.
            }
            return(true);
        }
예제 #2
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);
                }
            }
        }
예제 #3
0
        private uint RemapAvatarID(IDA da, uint avatarID)
        {
            if (avatarID == 0)
            {
                return(0);
            }
            uint remapped;

            if (!AvatarIDs.TryGetValue(avatarID, out remapped))
            {
                var ava = da.Avatars.Get(avatarID);
                if (ava == null)
                {
                    Console.WriteLine($"(could not find avatar {avatarID}, replacing with owner id {OwnerID})");
                    AvatarIDs[avatarID] = OwnerID;
                    remapped            = OwnerID;
                }
                else
                {
                    AvatarIDs[avatarID] = avatarID;
                    remapped            = avatarID;
                }
            }
            return(remapped);
        }
예제 #4
0
        public void ActivateEvents(IDA da, List <DbEvent> evts)
        {
            //ensure events that have not started

            int[] activeIDs;
            lock (ActiveEvents) {
                activeIDs = ActiveEvents.Select(x => x.event_id).ToArray();
            }
            bool changed = false;

            try
            {
                changed = da.Tuning.ClearInactiveTuning(activeIDs);
            }
            catch (Exception e)
            {
                LOG.Error(e, "Failed to clear inactive tuning!");
            }

            foreach (var evt in evts)
            {
                switch (evt.type)
                {
                case DbEventType.obj_tuning:
                    try
                    {
                        da.Tuning.ActivatePreset(evt.value, evt.event_id);
                    }
                    catch (Exception e)
                    {
                        LOG.Error(e, $"Failed to activate preset {evt.value}!");
                    }
                    changed = true;
                    break;
                }
            }

            if (changed)
            {
                TuningDomain.BroadcastTuningUpdate(true);
            }

            var all = Sessions.Clone();

            foreach (var session in all.OfType <IVoltronSession>())
            {
                foreach (var evt in evts)
                {
                    if (session.IsAnonymous)
                    {
                        continue;
                    }
                    UserJoinedEvent(session, evt, true);
                }
            }
        }
예제 #5
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;
            }
        }
        private void RetrieveDbObject(VM vm, IDA db, DbObject obj, uint ownerID, bool setOnLot, VMAsyncInventoryRetrieveCallback callback)
        {
            var objectPID = obj.object_id;
            var result    = new VMInventoryRestoreObject();

            result.PersistID    = obj.object_id;
            result.GUID         = obj.type;
            result.UpgradeLevel = (byte)obj.upgrade_level;
            result.Wear         = 0;
            if (setOnLot) //if we should set this object as on this lot. false means we're getting the info for trade
            {
                if (!db.Objects.SetInLot(objectPID, (uint)Context.DbId))
                {
                    callback(new VMInventoryRestoreObject()); //object is already on a lot. we cannot load it!
                    return;
                }
            }
            else if (obj.lot_id != null)
            {
                callback(new VMInventoryRestoreObject()); //object is already on a lot, don't load it for trading.
                return;
            }

            byte[] dat = null;
            try
            {
                var objStr = objectPID.ToString("x8");
                var path   = Path.Combine(Config.SimNFS, "Objects/" + objStr + "/inventoryState.fsoo");

                //if path does not exist, will throw FileNotFoundException
                using (var file = File.Open(path, FileMode.Open))
                {
                    dat = new byte[file.Length];
                    file.Read(dat, 0, dat.Length);
                }
            }
            catch (Exception e)
            {
                //todo: specific types of exception that can be thrown here? instead of just catching em all
                if (!(e is FileNotFoundException))
                {
                    LOG.Error(e, "Failed to load inventory state for object " + objectPID.ToString("x8") + "!");
                }
            }

            if (dat != null && dat.Length == 0)
            {
                dat = null;                                 //treat empty files as if no state were available.
            }
            result.Data = dat;
            callback(result);
        }
예제 #7
0
        public void SendBulletinPost(IDA da, int nhoodID, string cst, int subjectIndex, int msgIndex, uint expireDate, params string[] args)
        {
            for (int i = 0; i < args.Length; i++)
            {
                args[i] = args[i].Replace(';', ':');
            }

            var item = new DbBulletinPost()
            {
                neighborhood_id = nhoodID,
                title           = ";" + cst + ";" + subjectIndex,
                body            = ";" + expireDate + ";" + cst + ";" + msgIndex + ';' + string.Join(";", args),
                date            = Epoch.Now,
                flags           = 0,
                type            = DbBulletinType.system
            };

            da.BulletinPosts.Create(item);
        }
예제 #8
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);
                }
            }
        }
예제 #9
0
        private void CreateDbObject(IDA da, VMEntityMarshal entity, DbLot lot)
        {
            var ownerID = ((VMTSOObjectState)entity.PlatformState).OwnerID;
            var obj     = new DbObject()
            {
                budget       = (int)((VMTSOEntityState)entity.PlatformState).Budget.Value,
                type         = (entity.MasterGUID == 0) ? entity.GUID : entity.MasterGUID,
                lot_id       = lot.lot_id,
                owner_id     = (ownerID == 0) ? (uint?)null : ownerID,
                shard_id     = lot.shard_id,
                dyn_obj_name = "", //get from multitile?
                value        = 0   //get from multitile?
            };

            if (!Options.Report)
            {
                uint id = da.Objects.Create(obj);
                PersistRemap[entity.PersistID] = id;
                entity.PersistID = id;
            }
        }
예제 #10
0
        public async Task SetMayor(IDA da, uint avatarID, uint nhoodID)
        {
            //what we need to do:

            // set the mayor in the database
            // set the mayor in the data service

            // if there is a town hall, set us as its owner
            //   if it's open, inform it of the owner change
            //   if it isn't, open the lot to vacate the old mayor's objects

            // send an award email to the winner
            // (optionally) send emails to the voters telling them the result
            var mail = Kernel.Get <MailHandler>();

            var ds    = Kernel.Get <IDataService>();
            var nhood = await ds.Get <Neighborhood>(nhoodID);

            if (nhood == null)
            {
                return;
            }

            var oldMayorID = nhood.Neighborhood_MayorID;
            var oldMayor   = (oldMayorID != 0) ? da.Avatars.Get(oldMayorID) : null;

            nhood.Neighborhood_MayorID     = avatarID;
            nhood.Neighborhood_ElectedDate = Epoch.Now;
            uint?nAvatarID = (avatarID == 0) ? null : (uint?)avatarID;

            da.Neighborhoods.UpdateMayor(nhoodID, nAvatarID);
            if (avatarID != 0)
            {
                da.Avatars.UpdateMayorNhood(avatarID, nhoodID);
            }

            var dbNhood = da.Neighborhoods.Get(nhoodID);

            if (dbNhood == null)
            {
                return;
            }
            if (dbNhood.town_hall_id != null)
            {
                var lot = da.Lots.Get(dbNhood.town_hall_id.Value);
                if (lot != null)
                {
                    var lots       = Kernel.Get <LotAllocations>();
                    var lotServers = Kernel.Get <LotServerPicker>();
                    da.Lots.UpdateOwner(lot.lot_id, nAvatarID);

                    //this invalidation handles a few things... any changes to the roommates vector, and the possibility of the lot being deleted
                    //(when owner id is null, the lot disappears from the city until it is deleted)
                    ds.Invalidate <FSO.Common.DataService.Model.Lot>(lot.location);

                    //if online, notify the lot
                    var lotOwned = da.LotClaims.GetByLotID(lot.lot_id);
                    if (lotOwned != null)
                    {
                        var lotServer = lotServers.GetLotServerSession(lotOwned.owner);
                        if (lotServer != null)
                        {
                            //immediately notify lot of new roommate
                            lotServer.Write(new NotifyLotRoommateChange()
                            {
                                AvatarId = avatarID,
                                LotId    = lot.lot_id,
                                Change   = Protocol.Gluon.Model.ChangeType.BECOME_OWNER
                            });
                        }
                    }
                    else
                    {
                        //try force the lot open
                        var result = await lots.TryFindOrOpen(lot.location, 0, NullSecurityContext.INSTANCE);
                    }
                }
            }

            if (oldMayor != null)
            {
                da.Avatars.UpdateMayorNhood(oldMayor.avatar_id, null);
                if (avatarID != 0)
                {
                    var replaced = da.Avatars.Get(avatarID);
                    if (replaced != null)
                    {
                        mail.SendSystemEmail("f116", (int)NeighMailStrings.NoLongerMayorSubject, (int)NeighMailStrings.NoLongerMayor,
                                             1, MessageSpecialType.Normal, 0, oldMayorID, replaced.name, dbNhood.name);
                    }
                }
                else
                {
                    //replaced with nobody. This happens at the end of an election cycle where this neighborhood is no longer eligible.
                    mail.SendSystemEmail("f116", (int)NeighMailStrings.NoLongerMayorModSubject, (int)NeighMailStrings.NoLongerMayorMod,
                                         1, MessageSpecialType.Normal, 0, oldMayorID, dbNhood.name);
                }
            }
        }
예제 #11
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);
            }
        }