예제 #1
0
        public void RequestRoommate(VM vm, uint avatarID, int mode, byte permissions)
        {
            //0 = initiate. 1 = accept. 2 = reject.
            //we have the "initiate" step so that users are reminded if they somehow dc before the transaction completes.
            //users will be reminded of their in-progress roommate request every time they log in or leave a lot. (potentially check on most server actions)
            var lotID = Context.DbId;

            Host.InBackground(() =>
            {
                //TODO: use results in meaningful fashion
                using (var db = DAFactory.Get())
                {
                    bool queryResult;
                    switch (mode)
                    {
                    case 1:
                        queryResult = db.Roommates.Create(new DbRoommate()
                        {
                            avatar_id         = avatarID,
                            lot_id            = lotID,
                            is_pending        = 0,
                            permissions_level = 0
                        });
                        if (queryResult)
                        {
                            vm.ForwardCommand(new VMChangePermissionsCmd()
                            {
                                TargetUID = avatarID,
                                Level     = VMTSOAvatarPermissions.Roommate,
                                Verified  = true
                            });
                        }
                        break;

                    //the following code enables pending requests, like in the original game. I decided they only really make sense for requests initiated from city.

                    /*
                     * case 0:
                     *  queryResult = db.Roommates.Create(new DbRoommate()
                     *  {
                     *      avatar_id = avatarID,
                     *      lot_id = lotID,
                     *      is_pending = 1,
                     *      permissions_level = 0
                     *  });
                     *  // dont do anything if we fail. I can see on-lot roommate requests having precedence over off-lot ones though,
                     *  // so forcing a wipe of old pending requests might make sense.
                     *  break;
                     * case 1:
                     *  //accept
                     *  queryResult = db.Roommates.AcceptRoommateRequest(avatarID, lotID);
                     *  //if it worked, tell everyone in the lot that there's a new roommate.
                     *  if (queryResult)
                     *  {
                     *      vm.ForwardCommand(new VMChangePermissionsCmd()
                     *      {
                     *          TargetUID = avatarID,
                     *          Level = VMTSOAvatarPermissions.Roommate,
                     *          Verified = true
                     *      });
                     *  }
                     *  //todo: error feedback. I think the global call is meant to block for an answer and possibly return false.
                     *  break;
                     * case 2:
                     *  queryResult = db.Roommates.RemoveRoommate(avatarID, lotID) > 0;
                     *  break;
                     */
                    case 3:     //FSO specific mode: switch permissions.
                        queryResult = db.Roommates.UpdatePermissionsLevel(avatarID, lotID, permissions);
                        if (queryResult)
                        {
                            vm.ForwardCommand(new VMChangePermissionsCmd()
                            {
                                TargetUID = avatarID,
                                Level     = (permissions == 0)?VMTSOAvatarPermissions.Roommate:VMTSOAvatarPermissions.BuildBuyRoommate,
                                Verified  = true
                            });
                        }
                        break;
                    }
                    Host.SyncRoommates();
                }
            });
        }
예제 #2
0
        /// <summary>
        /// Load and initialize everything to start up the lot
        /// </summary>
        public void Run()
        {
            try
            {
                try
                {
                    ResetVM();
                }
                catch (Exception e)
                {
                    LOG.Info("LOT " + Context.DbId + " LOAD EXECPTION:" + e.ToString());
                    Host.Shutdown();
                    return;
                }
                LOG.Info("Starting to host lot with dbid = " + Context.DbId);
                Host.SetOnline(true);

                var timeKeeper = new Stopwatch(); //todo: smarter timing
                timeKeeper.Start();
                long lastTick = 0;

                LotSaveTicker    = LOT_SAVE_PERIOD;
                AvatarSaveTicker = AVATAR_SAVE_PERIOD;
                while (true)
                {
                    bool noRemainingUsers = ClientCount == 0;
                    lastTick++;
                    //sometimes avatars can be killed immediately after their kill timer starts (this frame will run the leave lot interaction)
                    //this works around that possibility.
                    var preTickAvatars = Lot.Context.ObjectQueries.AvatarsByPersist.Values.Select(x => x).ToList();
                    var noRoomies      = !(preTickAvatars.Any(x => ((VMTSOAvatarState)x.TSOState).Permissions > VMTSOAvatarPermissions.Visitor)) && LotPersist.admit_mode < 4;

                    try
                    {
                        Lot.Tick();
                    }
                    catch (Exception e)
                    {
                        //something bad happened. not entirely sure how we should deal with this yet
                        LOG.Error("VM ERROR: " + e.StackTrace);
                        Host.Shutdown();
                        return;
                    }

                    if (noRoomies)
                    {
                        //no roommates are here, so all visitors must be kicked out.
                        foreach (var avatar in preTickAvatars)
                        {
                            if (avatar.KillTimeout == -1)
                            {
                                avatar.UserLeaveLot();
                            }
                            VMDriver.DropAvatar(avatar);
                        }
                    }

                    if (noRemainingUsers)
                    {
                        if (TimeToShutdown == -1)
                        {
                            //lot shuts down 20 seconds after everyone leaves
                            //if we're doing a cleanup action, it closes immediately
                            TimeToShutdown = (Context.Action == ClaimAction.LOT_CLEANUP) ? 1 : TICKRATE * 20;
                        }
                        else
                        {
                            if (--TimeToShutdown == 0 || (ShuttingDown && TimeToShutdown < (TICKRATE * 20 - 10)))
                            {
                                Shutdown();
                                return; //kill the lot
                            }
                        }
                    }
                    else if (!noRoomies && TimeToShutdown != -1)
                    {
                        TimeToShutdown = -1;
                    }

                    if (--LotSaveTicker <= 0)
                    {
                        SaveRing();
                        LotSaveTicker = LOT_SAVE_PERIOD;

                        Host.UpdateActiveVisitRecords();
                    }

                    var beingKilled = preTickAvatars.Where(x => x.KillTimeout == 1);
                    if (beingKilled.Count() > 0)
                    {
                        //avatars that are being killed could die before their user disconnects. It's important to save them immediately.
                        LOG.Info("Avatar Kill Save");
                        SaveAvatars(beingKilled, true);
                    }

                    foreach (var avatar in Lot.Context.ObjectQueries.AvatarsByPersist)
                    {
                        if (avatar.Value.KillTimeout == 1)
                        {
                            //this avatar has begun being killed. Save them immediately.
                            SaveAvatar(avatar.Value);
                        }
                    }

                    if (--AvatarSaveTicker <= 0)
                    {
                        //save all avatars
                        SaveAvatars(Lot.Context.ObjectQueries.Avatars.Cast <VMAvatar>(), false);
                        AvatarSaveTicker = AVATAR_SAVE_PERIOD;
                    }

                    lock (SessionsToRelease)
                    {
                        //save avatar state, then release their avatar claims afterwards.
                        //SaveAvatars(SessionsToRelease.Select(x => Lot.GetAvatarByPersist(x.AvatarId)), true); //todo: is this performed by the fact that we started the persist save above?
                        foreach (var session in SessionsToRelease)
                        {
                            LOG.Info("Avatar Session Release");
                            Host.ReleaseAvatarClaim(session);
                        }
                        SessionsToRelease.Clear();
                    }

                    lock (LotThreadActions)
                    {
                        while (LotThreadActions.Count > 0)
                        {
                            LotThreadActions.Dequeue()();
                        }
                    }

                    if (--KeepAliveTicker <= 0)
                    {
                        Host.InBackground(null);
                        KeepAliveTicker = KEEP_ALIVE_PERIOD;
                    }

                    Thread.Sleep((int)Math.Max(0, (((lastTick + 1) * 1000) / TICKRATE) - timeKeeper.ElapsedMilliseconds));
                }
            }
            catch (Exception e)
            {
                LOG.Info("Fatal exception on lot " + Context.DbId + ":" + e.ToString());
                Host.Shutdown();
                return;
            }
        }