示例#1
0
        //LotAllocation
        public bool TryClaim(DbLot lot)
        {
            Lot = lot;

            //Write a db record to claim the lot
            using (var db = DAFactory.Get())
            {
                var claim = db.LotClaims.TryCreate(new Database.DA.LotClaims.DbLotClaim
                {
                    shard_id = Context.ShardId,
                    lot_id   = lot.lot_id,
                    owner    = Context.Config.Call_Sign
                });

                ClaimId = claim;

                if (claim.HasValue)
                {
                    return(true);
                }
                else
                {
                    return(false);
                }
            }
        }
        protected override Avatar LazyLoad(uint key, Avatar oldVal)
        {
            using (var db = DAFactory.Get)
            {
                var avatar = db.Avatars.Get(key);
                if (avatar == null)
                {
                    return(null);
                }
                if (avatar.shard_id != ShardId)
                {
                    return(null);
                }

                var   myLots = db.Roommates.GetAvatarsLots(avatar.avatar_id);
                DbLot lot    = null;
                if (myLots.Count > 0 && myLots.FirstOrDefault()?.is_pending == 0)
                {
                    lot = db.Lots.Get(myLots.FirstOrDefault().lot_id);
                }
                //List<DbJobLevel> levels = db.Avatars.GetJobLevels(key);
                //List<DbRelationship> rels = db.Relationships.GetBidirectional(key);
                //List<DbBookmark> bookmarks = db.Bookmarks.GetByAvatarId(key);

                var ava = HydrateOne(avatar, lot);
                if (oldVal != null)
                {
                    ava.Avatar_IsOnline = oldVal.Avatar_IsOnline;
                }
                return(ava);
            }
        }
示例#3
0
        private Avatar HydrateOne(DbAvatar dbAvatar, DbLot dbLot)
        {
            var result = new Avatar();

            result.Avatar_Id          = dbAvatar.avatar_id;
            result.Avatar_Name        = dbAvatar.name;
            result.Avatar_IsOnline    = false;
            result.Avatar_Description = dbAvatar.description;
            result.Avatar_Appearance  = new AvatarAppearance
            {
                AvatarAppearance_BodyOutfitID = dbAvatar.body,
                AvatarAppearance_HeadOutfitID = dbAvatar.head,
                AvatarAppearance_SkinTone     = dbAvatar.skin_tone
            };
            var now = Epoch.Now;

            result.FetchTime     = now;
            result.Avatar_Age    = (uint)((now - dbAvatar.date) / ((long)60 * 60 * 24));
            result.Avatar_Skills = new AvatarSkills
            {
                AvatarSkills_Body              = dbAvatar.skill_body,
                AvatarSkills_LockLv_Body       = dbAvatar.lock_body,
                AvatarSkills_Charisma          = dbAvatar.skill_charisma,
                AvatarSkills_LockLv_Charisma   = dbAvatar.lock_charisma,
                AvatarSkills_Cooking           = dbAvatar.skill_cooking,
                AvatarSkills_LockLv_Cooking    = dbAvatar.lock_cooking,
                AvatarSkills_Creativity        = dbAvatar.skill_creativity,
                AvatarSkills_LockLv_Creativity = dbAvatar.lock_creativity,
                AvatarSkills_Logic             = dbAvatar.skill_logic,
                AvatarSkills_LockLv_Logic      = dbAvatar.lock_logic,
                AvatarSkills_Mechanical        = dbAvatar.skill_mechanical,
                AvatarSkills_LockLv_Mechanical = dbAvatar.lock_mechanical
            };
            result.Avatar_PrivacyMode      = dbAvatar.privacy_mode;
            result.Avatar_SkillsLockPoints = (ushort)(20 + result.Avatar_Age / 7);
            result.Avatar_ModerationLevel  = dbAvatar.moderation_level;
            result.Avatar_MayorNhood       = (uint)(dbAvatar.mayor_nhood ?? 0);

            result.JobLevelProvider  = JobLevelProvider;
            result.RatingProvider    = RatingProvider;
            result.AvgRatingProvider = AvgRatingProvider;
            result.Avatar_CurrentJob = dbAvatar.current_job;

            result.Avatar_Top100ListFilter = new Top100ListFilter()
            {
                Top100ListFilter_ResultsVec   = ImmutableList.Create <uint>(),
                Top100ListFilter_Top100ListID = 0,
            };

            result.RelationshipProvider = RelationshipProvider;

            if (dbLot != null)
            {
                result.Avatar_LotGridXY = dbLot.location;
            }

            result.BookmarkProvider = BookmarkProvider;

            return(result);
        }
示例#4
0
        //LotAllocation
        public bool TryClaim(DbLot lot)
        {
            Lot = lot;

            //Write a db record to claim the lot
            using (var db = DAFactory.Get)
            {
                var claim = db.LotClaims.TryCreate(new Database.DA.LotClaims.DbLotClaim
                {
                    shard_id = Context.ShardId,
                    lot_id   = lot.lot_id,
                    owner    = Context.Config.Call_Sign
                });

                ClaimId = claim;

                if (claim.HasValue)
                {
                    return(true);
                }
                else
                {
                    var oldClaim = db.LotClaims.GetByLotID(lot.lot_id);
                    if (oldClaim == null)
                    {
                        return(false);                  //what?
                    }
                    else if (oldClaim.owner == Context.Config.Call_Sign)
                    {
                        //something went wrong and this lot claim did not get freed... but the city does own it.
                        //if we got here, then there was no allocation in the city before now.
                        //therefore the only way the city could own a lot claim and not an allocation is if it got stuck somehow
                        db.LotClaims.Delete((uint)oldClaim.claim_id, oldClaim.owner);
                        claim = db.LotClaims.TryCreate(new Database.DA.LotClaims.DbLotClaim
                        {
                            shard_id = Context.ShardId,
                            lot_id   = lot.lot_id,
                            owner    = Context.Config.Call_Sign
                        });
                        ClaimId = claim;

                        if (claim.HasValue)
                        {
                            return(true);
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        return(false);
                    }
                }
            }
        }
示例#5
0
        public LotContainer(IDAFactory da, LotContext context, ILotHost host, IKernel kernel, LotServerConfiguration config, IRealestateDomain realestate)
        {
            VM.UseWorld = false;
            DAFactory   = da;
            Host        = host;
            Context     = context;
            Kernel      = kernel;
            Config      = config;

            JobLot = (context.Id & 0x40000000) > 0;
            if (JobLot)
            {
                var jobPacked = Context.DbId - 0x200;
                var jobLevel  = (short)((jobPacked - 1) & 0xF);
                var jobType   = (short)((jobPacked - 1) / 0xF);
                LotPersist = new DbLot
                {
                    lot_id     = Context.DbId,
                    location   = Context.Id,
                    category   = LotCategory.money,
                    name       = "{job:" + jobType + ":" + jobLevel + "}",
                    admit_mode = 4
                };
                LotAdj       = new List <DbLot>();
                LotRoommates = new List <DbRoommate>();
                Terrain      = new VMTSOSurroundingTerrain();

                for (int y = 0; y < 3; y++)
                {
                    for (int x = 0; x < 3; x++)
                    {
                        Terrain.Roads[x, y] = 0xF; //crossroads everywhere
                    }
                }
            }
            else
            {
                using (var db = DAFactory.Get())
                {
                    LotPersist   = db.Lots.Get(context.DbId);
                    LotAdj       = db.Lots.GetAdjToLocation(context.ShardId, LotPersist.location);
                    LotRoommates = db.Roommates.GetLotRoommates(context.DbId);
                }
                Realestate = realestate.GetByShard(LotPersist.shard_id);
                GenerateTerrain();
            }
        }
示例#6
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;
            }
        }
示例#7
0
 public void SetLot(DbLot lot, uint specialId, ClaimAction openAction)
 {
     Lot        = lot;
     SpecialId  = specialId;
     OpenAction = openAction;
 }
示例#8
0
        /// <summary>
        /// Tasks we handle are:
        ///   1) Asking a server to host the lot
        ///   2) Telling users which server is hosting the lot
        ///
        /// It is then up to the client and server to connect to each other. This is a bit crappy because it means you
        /// must open a connection to the lot server before you can find out if there is room for you to join. But this removes
        /// a lot of complexity.
        ///
        /// In the future we may move the person claiming logic to city if it causes problems. One problem I can see is there is a possible
        /// race condition in which the lot could fill up before the owner gets in. The lot would then automatically shut down
        ///
        /// </summary>
        /// <param name="lotId"></param>
        /// <param name="avatarId">The id of the avatar opening this lot. If 0, we're opening for a scheduled cleanup. (lot start fresh)</param>
        /// <param name="openIfClosed"></param>
        /// <returns></returns>

        Task <TryFindLotResult> TryFind(uint lotId, uint avatarId, bool openIfClosed, ISecurityContext security)
        {
            bool jobLot     = false;
            var  originalId = lotId;

            if (lotId > 0x200 && lotId < 0x300)
            {
                //special: join available job lot instance
                var result = Matchmaker.TryGetJobLot(lotId, avatarId);
                lotId      = result.Item1 ?? 0;
                lotId     |= 0x40000000;
                originalId = result.Item2;
                jobLot     = true;
                if (lotId == 0)
                {
                    return(Immediate(new TryFindLotResult
                    {
                        Status = FindLotResponseStatus.NO_CAPACITY
                    }));
                }
            }
            else if (lotId > 0x200 && lotId < 0x10000)
            { //job lot range
                if (!Matchmaker.TryJoinExisting(lotId, avatarId))
                {
                    return(Immediate(new TryFindLotResult
                    {
                        Status = FindLotResponseStatus.NO_ADMIT
                    }));
                }
                lotId |= 0x40000000;
                jobLot = true;
            }

            var allocation = Get(lotId);

            lock (allocation)
            {
                switch (allocation.State)
                {
                case LotAllocationState.NOT_ALLOCATED:
                    //We need to pick a server to run this lot
                    if (!openIfClosed)
                    {
                        //Sorry, cant do this
                        Remove(lotId);
                        return(Immediate(new TryFindLotResult
                        {
                            Status = FindLotResponseStatus.NOT_OPEN
                        }));
                    }

                    if (!jobLot)
                    {
                        DbLot lot = null;
                        using (var db = DAFactory.Get)
                        {
                            //Convert the lot location into a lot db id
                            lot = db.Lots.GetByLocation(Context.ShardId, lotId);
                            if (lot == null)
                            {
                                Remove(lotId);
                                return(Immediate(new TryFindLotResult
                                {
                                    Status = FindLotResponseStatus.NO_SUCH_LOT
                                }));
                            }

                            if (avatarId != 0)
                            {
                                var roomies  = db.Roommates.GetLotRoommates(lot.lot_id);
                                var modState = db.Avatars.GetModerationLevel(avatarId);
                                var avatars  = new List <uint>();
                                foreach (var roomie in roomies)
                                {
                                    if (roomie.is_pending == 0)
                                    {
                                        avatars.Add(roomie.avatar_id);
                                    }
                                }

                                try
                                {
                                    if (lot.admit_mode < 4 && modState == 0)
                                    {
                                        security.DemandAvatars(avatars, AvatarPermissions.WRITE);
                                    }
                                }
                                catch (Exception ex)
                                {
                                    Remove(lotId);
                                    return(Immediate(new TryFindLotResult
                                    {
                                        Status = FindLotResponseStatus.NOT_PERMITTED_TO_OPEN
                                    }));
                                }
                            }
                        }

                        if (!allocation.TryClaim(lot))
                        {
                            Remove(lotId);
                            return(Immediate(new TryFindLotResult
                            {
                                Status = FindLotResponseStatus.CLAIM_FAILED
                            }));
                        }
                        allocation.SetLot(lot, 0,
                                          (avatarId == 0) ? ClaimAction.LOT_CLEANUP : ClaimAction.LOT_HOST);
                    }
                    else
                    {
                        allocation.SetLot(new DbLot()
                        {
                            lot_id = (int)lotId
                        }, originalId,
                                          (avatarId == 0)? ClaimAction.LOT_CLEANUP : ClaimAction.LOT_HOST);
                    }

                    var pick = PickingEngine.PickServer();
                    if (pick.Success == false)
                    {
                        //Release claim
                        allocation.TryUnclaim();
                        Remove(lotId);
                        return(Immediate(new TryFindLotResult
                        {
                            Status = FindLotResponseStatus.NO_CAPACITY
                        }));
                    }
                    else
                    {
                        return(allocation.BeginPick(pick).ContinueWith(x => {
                            if (x.IsFaulted || x.IsCanceled || x.Result.Accepted == false)
                            {
                                Remove(lotId);
                                return new TryFindLotResult
                                {
                                    Status = FindLotResponseStatus.NO_CAPACITY
                                };
                            }

                            return new TryFindLotResult {
                                Status = FindLotResponseStatus.FOUND,
                                Server = allocation.Server,
                                LotDbId = allocation.LotDbId,
                                LotId = lotId,
                            };
                        }));
                    }
                    break;

                case LotAllocationState.ALLOCATING:
                    break;

                case LotAllocationState.ALLOCATED:
                    if (!jobLot && avatarId != 0)
                    {
                        //check admit type (might be expensive?)
                        using (var db = DAFactory.Get)
                        {
                            var lot = db.Lots.GetByLocation(Context.ShardId, lotId);
                            if (lot != null)
                            {
                                if (lot.admit_mode > 0 && lot.admit_mode < 4)
                                {
                                    //special admit mode

                                    var roomies  = db.Roommates.GetLotRoommates(lot.lot_id);
                                    var modState = db.Avatars.GetModerationLevel(avatarId);
                                    var avatars  = new List <uint>();
                                    foreach (var roomie in roomies)
                                    {
                                        avatars.Add(roomie.avatar_id);
                                    }

                                    try
                                    {
                                        if (modState == 0)
                                        {
                                            security.DemandAvatars(avatars, AvatarPermissions.WRITE);
                                        }
                                    }
                                    catch (Exception ex)
                                    {
                                        //if we're not a roommate, check admit rules
                                        if ((lot.admit_mode == 1 && !db.LotAdmit.GetLotAdmitDeny(lot.lot_id, 0).Contains(avatarId)) ||  //admit list
                                            (lot.admit_mode == 2 && db.LotAdmit.GetLotAdmitDeny(lot.lot_id, 1).Contains(avatarId)) ||     //ban list
                                            (lot.admit_mode == 3))        //ban all
                                        {
                                            return(Immediate(new TryFindLotResult
                                            {
                                                Status = FindLotResponseStatus.NO_ADMIT
                                            }));
                                        }
                                    }
                                }
                            }
                        }
                    }

                    return(Immediate(new TryFindLotResult
                    {
                        Status = FindLotResponseStatus.FOUND,
                        Server = allocation.Server,
                        LotDbId = allocation.LotDbId,
                        LotId = lotId
                    }));

                //Should never get here..
                case LotAllocationState.FAILED:
                    Remove(lotId);
                    return(Immediate(new TryFindLotResult {
                        Status = FindLotResponseStatus.UNKNOWN_ERROR
                    }));
                }

                return(Immediate(new TryFindLotResult
                {
                    Status = FindLotResponseStatus.UNKNOWN_ERROR
                }));
            }
        }
示例#9
0
        protected Lot HydrateOne(DbLot lot, List <DbRoommate> roommates, List <DbLotAdmit> admit)
        {
            var location = MapCoordinates.Unpack(lot.location);

            /* **experimental** we're leaving this up to ASP.NET api for now (behind cloudflare)
             * //attempt to load the lot's thumbnail.
             * var path = Path.Combine(NFS.GetBaseDirectory(), "Lots/" + lot.lot_id.ToString("x8") + "/thumb.png");
             * cTSOGenericData thumb = null;
             * try
             * {
             *  using (FileStream fs = File.Open(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
             *  {
             *      int numBytesToRead = Convert.ToInt32(fs.Length);
             *      var file = new byte[(numBytesToRead)];
             *      fs.Read(file, 0, numBytesToRead);
             *      thumb = new cTSOGenericData(file);
             *  }
             * }
             * catch (Exception) {
             *  thumb = new cTSOGenericData(new byte[0]);
             * }
             */

            var result = new Lot
            {
                DbId = lot.lot_id,
                Id   = lot.location,

                Lot_Name     = lot.name,
                Lot_IsOnline = false,
                Lot_Location = new Location {
                    Location_X = location.X, Location_Y = location.Y
                },
                Lot_Price        = (uint)Realestate.GetPurchasePrice(location.X, location.Y),
                Lot_LeaderID     = lot.owner_id ?? 0,
                Lot_OwnerVec     = ImmutableList.Create(lot.owner_id ?? 0),
                Lot_RoommateVec  = ImmutableList.Create <uint>(),
                Lot_LotAdmitInfo = new LotAdmitInfo()
                {
                    LotAdmitInfo_AdmitMode = lot.admit_mode
                },
                Lot_NumOccupants  = 0,
                Lot_Category      = (byte)lot.category,
                Lot_SkillGamemode = lot.skill_mode,
                Lot_LastCatChange = lot.category_change_date,
                Lot_Description   = lot.description,
                Lot_Thumbnail     = new cTSOGenericData(new byte[0]),
            };

            foreach (var roomie in roommates)
            {
                if (roomie.is_pending == 0)
                {
                    result.Lot_RoommateVec = result.Lot_RoommateVec.Add(roomie.avatar_id);
                }
            }

            var admitL = new List <uint>();
            var banL   = new List <uint>();

            foreach (var item in admit)
            {
                if (item.admit_type == 0)
                {
                    admitL.Add(item.avatar_id);
                }
                else
                {
                    banL.Add(item.avatar_id);
                }
            }
            result.Lot_LotAdmitInfo.LotAdmitInfo_AdmitList = ImmutableList.ToImmutableList(admitL);
            result.Lot_LotAdmitInfo.LotAdmitInfo_BanList   = ImmutableList.ToImmutableList(banL);

            return(result);
        }
示例#10
0
        public async void Handle(IVoltronSession session, ChangeRoommateRequest packet)
        {
            try
            {
                if (session.IsAnonymous)
                {
                    return;
                }
                using (var da = DAFactory.Get())
                {
                    if (packet.Type == ChangeRoommateType.POLL)
                    {
                        var lots = da.Roommates.GetAvatarsLots(session.AvatarId);
                        foreach (var lot in lots)
                        {
                            if (lot.is_pending == 1)
                            {
                                var lotdb = da.Lots.Get(lot.lot_id);
                                if (lotdb == null)
                                {
                                    return;
                                }
                                session.Write(new ChangeRoommateRequest
                                {
                                    Type        = ChangeRoommateType.INVITE,
                                    AvatarId    = lotdb.owner_id ?? 0,
                                    LotLocation = lotdb.location
                                });
                            }
                        }
                    }
                    else if (packet.Type == ChangeRoommateType.ACCEPT)
                    {
                        var lot = da.Lots.GetByLocation(Context.ShardId, packet.LotLocation);
                        if (lot == null)
                        {
                            Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); return;
                        }
                        if (da.Roommates.AcceptRoommateRequest(session.AvatarId, lot.lot_id))
                        {
                            var lotDS = await DataService.Get <FSO.Common.DataService.Model.Lot>(packet.LotLocation);

                            if (lotDS != null)
                            {
                                lotDS.Lot_RoommateVec = lotDS.Lot_RoommateVec.Add(session.AvatarId);
                            }

                            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 = session.AvatarId,
                                        LotId    = lot.lot_id,
                                        Change   = Protocol.Gluon.Model.ChangeType.ADD_ROOMMATE
                                    });
                                }
                            }

                            var avatar = await DataService.Get <Avatar>(session.AvatarId);

                            if (avatar != null)
                            {
                                avatar.Avatar_LotGridXY = packet.LotLocation;
                            }
                            Status(session, ChangeRoommateResponseStatus.ACCEPT_SUCCESS); return;
                        }
                        else
                        {
                            Status(session, ChangeRoommateResponseStatus.NO_INVITE_PENDING); return;
                        }
                    }
                    else if (packet.Type == ChangeRoommateType.DECLINE)
                    {
                        var lot = da.Lots.GetByLocation(Context.ShardId, packet.LotLocation);
                        if (lot == null)
                        {
                            Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); return;
                        }
                        if (da.Roommates.DeclineRoommateRequest(session.AvatarId, lot.lot_id))
                        {
                            Status(session, ChangeRoommateResponseStatus.DECLINE_SUCCESS); return;
                        }
                        else
                        {
                            Status(session, ChangeRoommateResponseStatus.NO_INVITE_PENDING); return;
                        }
                    }
                    else
                    {
                        //verify that requester is definitely a roommate in the target lot

                        var ownedLot = da.Lots.GetByOwner(session.AvatarId);
                        var myLots   = da.Roommates.GetAvatarsLots(session.AvatarId);

                        if (packet.Type == ChangeRoommateType.INVITE)
                        {
                            //is invitee roommate somewhere else? count lot roommates and check for max
                            var targ = da.Avatars.Get(packet.AvatarId);
                            if (targ == null)
                            {
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
                            }
                            var targLots = da.Roommates.GetAvatarsLots(packet.AvatarId);
                            if (targLots.Count > 0)
                            {
                                Status(session, ChangeRoommateResponseStatus.ROOMIE_ELSEWHERE); //request already pending or otherwise
                                return;
                            }
                            var   lotr = myLots.FirstOrDefault();
                            DbLot lot  = null;
                            if (lotr != null)
                            {
                                lot = da.Lots.Get(lotr.lot_id);
                            }
                            if (lotr == null || lot == null)
                            {
                                Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); //what??
                                return;
                            }
                            if (lot.owner_id != session.AvatarId) //only an owner can add roommates
                            {
                                Status(session, ChangeRoommateResponseStatus.YOU_ARE_NOT_OWNER);
                                return;
                            }
                            var myLotRoomies = da.Roommates.GetLotRoommates(lotr.lot_id);
                            if (myLotRoomies.Count >= 8)
                            {
                                //if pending roommates put us over, cancel some of them.
                                //assume first is oldest request
                                var pending = myLotRoomies.FirstOrDefault(x => x.is_pending == 1);
                                if (pending == null)
                                {
                                    Status(session, ChangeRoommateResponseStatus.TOO_MANY_ROOMMATES);
                                    return;
                                }
                                else
                                {
                                    da.Roommates.DeclineRoommateRequest(pending.avatar_id, pending.lot_id);
                                }
                            }
                            //create roommate request in database

                            if (!da.Roommates.Create(new DbRoommate
                            {
                                avatar_id = packet.AvatarId,
                                lot_id = lotr.lot_id,
                                is_pending = 1,
                                permissions_level = 0
                            }))
                            {
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
                                return;
                            }

                            //if online, notify roommate of pending request.
                            var targetSession = Sessions.GetByAvatarId(packet.AvatarId);
                            if (targetSession != null)
                            {
                                targetSession.Write(new ChangeRoommateRequest()
                                {
                                    Type        = ChangeRoommateType.INVITE,
                                    AvatarId    = session.AvatarId,
                                    LotLocation = lot.location
                                });
                            }

                            Status(session, ChangeRoommateResponseStatus.INVITE_SUCCESS);
                            return;
                            //if not, we'll catch them when they log in later.
                        }
                        else if (packet.Type == ChangeRoommateType.KICK)
                        {
                            var result = await TryKick(packet.LotLocation, session.AvatarId, packet.AvatarId);

                            Status(session, result);
                        }
                    }
                }
            }
            catch (Exception e) {
                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
            }
        }
示例#11
0
        public async void Handle(IVoltronSession session, ChangeRoommateRequest packet)
        {
            try
            {
                if (session.IsAnonymous)
                {
                    return;
                }
                using (var da = DAFactory.Get())
                {
                    if (packet.Type == ChangeRoommateType.POLL)
                    {
                        var lots = da.Roommates.GetAvatarsLots(session.AvatarId);
                        foreach (var lot in lots)
                        {
                            if (lot.is_pending == 1)
                            {
                                var lotdb = da.Lots.Get(lot.lot_id);
                                if (lotdb == null)
                                {
                                    return;
                                }
                                session.Write(new ChangeRoommateRequest
                                {
                                    Type        = ChangeRoommateType.INVITE,
                                    AvatarId    = lotdb.owner_id,
                                    LotLocation = lotdb.location
                                });
                            }
                        }
                    }
                    else if (packet.Type == ChangeRoommateType.ACCEPT)
                    {
                        var lot = da.Lots.GetByLocation(Context.ShardId, packet.LotLocation);
                        if (lot == null)
                        {
                            Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); return;
                        }
                        if (da.Roommates.AcceptRoommateRequest(session.AvatarId, lot.lot_id))
                        {
                            var lotDS = await DataService.Get <FSO.Common.DataService.Model.Lot>(packet.LotLocation);

                            if (lotDS != null)
                            {
                                lotDS.Lot_RoommateVec = lotDS.Lot_RoommateVec.Add(session.AvatarId);
                            }

                            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 = session.AvatarId,
                                        LotId    = lot.lot_id,
                                        Change   = Protocol.Gluon.Model.ChangeType.ADD_ROOMMATE
                                    });
                                }
                            }

                            var avatar = await DataService.Get <Avatar>(session.AvatarId);

                            if (avatar != null)
                            {
                                avatar.Avatar_LotGridXY = packet.LotLocation;
                            }
                            Status(session, ChangeRoommateResponseStatus.ACCEPT_SUCCESS); return;
                        }
                        else
                        {
                            Status(session, ChangeRoommateResponseStatus.NO_INVITE_PENDING); return;
                        }
                    }
                    else if (packet.Type == ChangeRoommateType.DECLINE)
                    {
                        var lot = da.Lots.GetByLocation(Context.ShardId, packet.LotLocation);
                        if (lot == null)
                        {
                            Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); return;
                        }
                        if (da.Roommates.DeclineRoommateRequest(session.AvatarId, lot.lot_id))
                        {
                            Status(session, ChangeRoommateResponseStatus.DECLINE_SUCCESS); return;
                        }
                        else
                        {
                            Status(session, ChangeRoommateResponseStatus.NO_INVITE_PENDING); return;
                        }
                    }
                    else
                    {
                        //verify that requester is definitely a roommate in the target lot

                        var ownedLot = da.Lots.GetByOwner(session.AvatarId);
                        var myLots   = da.Roommates.GetAvatarsLots(session.AvatarId);

                        if (packet.Type == ChangeRoommateType.INVITE)
                        {
                            //is invitee roommate somewhere else? count lot roommates and check for max
                            var targ = da.Avatars.Get(packet.AvatarId);
                            if (targ == null)
                            {
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
                            }
                            var targLots = da.Roommates.GetAvatarsLots(packet.AvatarId);
                            if (targLots.Count > 0)
                            {
                                Status(session, ChangeRoommateResponseStatus.ROOMIE_ELSEWHERE); //request already pending or otherwise
                                return;
                            }
                            var   lotr = myLots.FirstOrDefault();
                            DbLot lot  = null;
                            if (lotr != null)
                            {
                                lot = da.Lots.Get(lotr.lot_id);
                            }
                            if (lotr == null || lot == null)
                            {
                                Status(session, ChangeRoommateResponseStatus.LOT_DOESNT_EXIST); //what??
                                return;
                            }
                            if (lot.owner_id != session.AvatarId) //only an owner can add roommates
                            {
                                Status(session, ChangeRoommateResponseStatus.YOU_ARE_NOT_OWNER);
                                return;
                            }
                            var myLotRoomies = da.Roommates.GetLotRoommates(lotr.lot_id);
                            if (myLotRoomies.Count >= 8)
                            {
                                //if pending roommates put us over, cancel some of them.
                                //assume first is oldest request
                                var pending = myLotRoomies.FirstOrDefault(x => x.is_pending == 1);
                                if (pending == null)
                                {
                                    Status(session, ChangeRoommateResponseStatus.TOO_MANY_ROOMMATES);
                                    return;
                                }
                                else
                                {
                                    da.Roommates.DeclineRoommateRequest(pending.avatar_id, pending.lot_id);
                                }
                            }
                            //create roommate request in database

                            if (!da.Roommates.Create(new DbRoommate
                            {
                                avatar_id = packet.AvatarId,
                                lot_id = lotr.lot_id,
                                is_pending = 1,
                                permissions_level = 0
                            }))
                            {
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
                                return;
                            }

                            //if online, notify roommate of pending request.
                            var targetSession = Sessions.GetByAvatarId(packet.AvatarId);
                            if (targetSession != null)
                            {
                                targetSession.Write(new ChangeRoommateRequest()
                                {
                                    Type        = ChangeRoommateType.INVITE,
                                    AvatarId    = session.AvatarId,
                                    LotLocation = lot.location
                                });
                            }

                            Status(session, ChangeRoommateResponseStatus.INVITE_SUCCESS);
                            return;
                            //if not, we'll catch them when they log in later.
                        }
                        else if (packet.Type == ChangeRoommateType.KICK)
                        {
                            var lot = da.Lots.GetByLocation(Context.ShardId, packet.LotLocation);
                            if (lot == null)
                            {
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN); return;
                            }

                            var roommates = da.Roommates.GetLotRoommates(lot.lot_id);
                            if (roommates.Count(x => x.is_pending == 0) <= 1)
                            {
                                //we're the last roommate here. the lot must be closed. This will cause the lot to fall off-map.
                                if (lot.owner_id != session.AvatarId)
                                {
                                    //only the owner can delete their lot
                                    Status(session, ChangeRoommateResponseStatus.UNKNOWN); return;
                                }

                                //TODO: let user do this with their lot falling off map. for now they must use start fresh mode.
                                Status(session, ChangeRoommateResponseStatus.UNKNOWN); return;
                            }
                            else if (roommates.Any(x => x.avatar_id == packet.AvatarId && x.is_pending == 0))
                            {
                                //avatar can be removed from the lot.
                                var selfDelete = false;
                                if (session.AvatarId == packet.AvatarId)
                                {
                                    //self deletes are allowed
                                    selfDelete = true;
                                }
                                else if (lot.owner_id != session.AvatarId)
                                {
                                    //only the owner can kickout other roommates
                                    Status(session, ChangeRoommateResponseStatus.YOU_ARE_NOT_OWNER); return;
                                }

                                if (da.Roommates.RemoveRoommate(packet.AvatarId, lot.lot_id) == 0)
                                {
                                    //nothing happened when we tried to remove this user's roommate status.
                                    Status(session, ChangeRoommateResponseStatus.YOU_ARE_NOT_ROOMMATE); return;
                                }

                                if (selfDelete && lot.owner_id == session.AvatarId)
                                {
                                    //lot needs a new owner
                                    da.Lots.ReassignOwner(lot.lot_id); //database will assign oldest roommate as owner.
                                }

                                var lotDS = await DataService.Get <FSO.Common.DataService.Model.Lot>(packet.LotLocation);

                                if (lotDS != null)
                                {
                                    lotDS.Lot_RoommateVec = lotDS.Lot_RoommateVec.Remove(packet.AvatarId);
                                    var newLot = da.Lots.Get(lot.lot_id);
                                    lotDS.Lot_OwnerVec = ImmutableList.Create(newLot.owner_id);
                                }

                                //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 = packet.AvatarId,
                                            LotId    = lot.lot_id,
                                            Change   = Protocol.Gluon.Model.ChangeType.REMOVE_ROOMMATE
                                        });
                                    }
                                }
                                else
                                {
                                    //try force the lot open
                                    var result = await Lots.TryFindOrOpen(lot.location, 0, session);
                                }

                                //TODO: if offline, force the lot to open so we can remove the kicked out roommate's objects.

                                var avatar = await DataService.Get <Avatar>(packet.AvatarId);

                                if (avatar != null)
                                {
                                    avatar.Avatar_LotGridXY = 0;
                                }

                                //try to notify roommates
                                foreach (var roomie in roommates)
                                {
                                    var kickedMe = roomie.avatar_id == packet.AvatarId;
                                    if (roomie.is_pending == 0 && !(kickedMe && selfDelete) && session.AvatarId != roomie.avatar_id)
                                    {
                                        var targetSession = Sessions.GetByAvatarId(roomie.avatar_id);
                                        if (targetSession != null)
                                        {
                                            targetSession.Write(new ChangeRoommateResponse()
                                            {
                                                Type  = (kickedMe)?ChangeRoommateResponseStatus.GOT_KICKED:ChangeRoommateResponseStatus.ROOMMATE_LEFT,
                                                Extra = packet.AvatarId
                                            });
                                        }
                                    }
                                }

                                if (selfDelete)
                                {
                                    Status(session, ChangeRoommateResponseStatus.SELFKICK_SUCCESS); return;
                                }
                                else
                                {
                                    Status(session, ChangeRoommateResponseStatus.KICK_SUCCESS); return;
                                }
                            }
                            else
                            {
                                //not roommate??
                                Status(session, ChangeRoommateResponseStatus.YOU_ARE_NOT_ROOMMATE); return;
                            }
                            //if target avatar is our avatar, we are moving out

                            //if we are owner of the lot, set the new owner to the first (earliest) roommate entry in the database.
                            //if we are the last person in the lot, the lot must be closed before doing this.
                            //make sure all references are set to new owner!

                            //remove roommate entry for target avatar.
                            //update lot data service and avatar data service for targets.

                            //if lot open, notify lot server of change (roommate add/remove AND new/same owner)
                            //the lot will remove objects as necessary

                            //future: if lot closed, special request to a lot server to quickly open an unjoinable instance of the lot to remove our objects.
                        }
                    }
                }
            }
            catch (Exception e) {
                Status(session, ChangeRoommateResponseStatus.UNKNOWN);
            }
        }
示例#12
0
        private Avatar HydrateOne(DbAvatar dbAvatar, DbLot dbLot, List <DbJobLevel> levels, List <DbRelationship> rels, List <DbBookmark> bookmarks)
        {
            var result = new Avatar();

            result.Avatar_Id          = dbAvatar.avatar_id;
            result.Avatar_Name        = dbAvatar.name;
            result.Avatar_IsOnline    = false;
            result.Avatar_Description = dbAvatar.description;
            result.Avatar_Appearance  = new AvatarAppearance
            {
                AvatarAppearance_BodyOutfitID = dbAvatar.body,
                AvatarAppearance_HeadOutfitID = dbAvatar.head,
                AvatarAppearance_SkinTone     = dbAvatar.skin_tone
            };
            var now = Epoch.Now;

            result.FetchTime     = now;
            result.Avatar_Age    = (uint)((now - dbAvatar.date) / ((long)60 * 60 * 24));
            result.Avatar_Skills = new AvatarSkills
            {
                AvatarSkills_Body              = dbAvatar.skill_body,
                AvatarSkills_LockLv_Body       = dbAvatar.lock_body,
                AvatarSkills_Charisma          = dbAvatar.skill_charisma,
                AvatarSkills_LockLv_Charisma   = dbAvatar.lock_charisma,
                AvatarSkills_Cooking           = dbAvatar.skill_cooking,
                AvatarSkills_LockLv_Cooking    = dbAvatar.lock_cooking,
                AvatarSkills_Creativity        = dbAvatar.skill_creativity,
                AvatarSkills_LockLv_Creativity = dbAvatar.lock_creativity,
                AvatarSkills_Logic             = dbAvatar.skill_logic,
                AvatarSkills_LockLv_Logic      = dbAvatar.lock_logic,
                AvatarSkills_Mechanical        = dbAvatar.skill_mechanical,
                AvatarSkills_LockLv_Mechanical = dbAvatar.lock_mechanical
            };
            result.Avatar_PrivacyMode      = dbAvatar.privacy_mode;
            result.Avatar_SkillsLockPoints = (ushort)(20 + result.Avatar_Age / 7);

            var jobs = new List <JobLevel>();

            foreach (var level in levels)
            {
                jobs.Add(new JobLevel
                {
                    JobLevel_JobType       = level.job_type,
                    JobLevel_JobExperience = level.job_experience,
                    JobLevel_JobGrade      = level.job_level
                });
            }
            result.Avatar_JobLevelVec = ImmutableList.ToImmutableList(jobs);
            result.Avatar_CurrentJob  = dbAvatar.current_job;

            result.Avatar_Top100ListFilter = new Top100ListFilter()
            {
                Top100ListFilter_ResultsVec   = ImmutableList.Create <uint>(),
                Top100ListFilter_Top100ListID = 0,
            };

            var fvec = new Dictionary <Tuple <uint, bool>, Relationship>();

            foreach (var rel in rels)
            {
                bool outgoing = false;
                uint target   = 0;
                if (rel.from_id == dbAvatar.avatar_id)
                {
                    outgoing = true;
                    target   = rel.to_id;
                }
                else
                {
                    target = rel.from_id;
                }

                var          tuple  = new Tuple <uint, bool>(target, outgoing);
                Relationship relObj = null;
                if (!fvec.TryGetValue(tuple, out relObj))
                {
                    relObj = new Relationship
                    {
                        Relationship_IsOutgoing = outgoing,
                        Relationship_TargetID   = target,
                        Relationship_CommentID  = rel.comment_id ?? 0
                    };
                    fvec.Add(tuple, relObj);
                }

                if (rel.index == 0)
                {
                    relObj.Relationship_STR = (sbyte)rel.value;
                }
                else
                {
                    relObj.Relationship_LTR = (sbyte)rel.value;
                }
            }
            result.Avatar_FriendshipVec = ImmutableList.ToImmutableList(fvec.Values);

            if (dbLot != null)
            {
                result.Avatar_LotGridXY = dbLot.location;
            }

            result.Avatar_BookmarksVec = ImmutableList.ToImmutableList(bookmarks.Select(x =>
            {
                return(new Bookmark {
                    Bookmark_Type = x.type,
                    Bookmark_TargetID = x.target_id
                });
            }));

            return(result);
        }
示例#13
0
        public int Run()
        {
            if (Options.RestoreFolder == null)
            {
                Console.WriteLine("Please pass: <shard id> <lot folder path>");
                return(1);
            }
            Console.WriteLine("Scanning content, please wait...");

            VMContext.InitVMConfig(false);
            Content.Content.Init(Config.GameLocation, Content.ContentMode.SERVER);

            Console.WriteLine($"Starting property restore - scanning { Options.RestoreFolder }...");

            if (!Directory.Exists(Options.RestoreFolder))
            {
                Console.WriteLine($"Could not find the given directory: { Options.RestoreFolder }");
                return(1);
            }

            var files = Directory.EnumerateFiles(Options.RestoreFolder).Where(x => x.ToLowerInvariant().EndsWith(".fsov")).ToList();

            if (files.Count == 0)
            {
                Console.WriteLine($"Specified folder did not contain any lot saves (*.fsov). Note that blueprint .xmls are not supported.");
                return(1);
            }

            using (var da = DAFactory.Get())
            {
                foreach (var file in files)
                {
                    Console.WriteLine($"===== { Path.GetFileName(file) } =====");

                    var data = File.ReadAllBytes(file);

                    var           vm = new VMMarshal();
                    VMTSOLotState state;
                    try
                    {
                        using (var mem = new MemoryStream(data))
                        {
                            vm.Deserialize(new BinaryReader(mem));
                        }
                        state = (VMTSOLotState)vm.PlatformState;
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine($"Could not read FSOV. ({e.Message}) Continuing...");
                        continue;
                    }

                    var lot = new DbLot();
                    lot.name        = state.Name;
                    lot.location    = state.LotID;
                    lot.description = "Restored from FSOV";
                    if (state.PropertyCategory == 255)
                    {
                        state.PropertyCategory = 11;
                    }
                    lot.category        = (LotCategory)state.PropertyCategory;
                    lot.owner_id        = RemapAvatarID(da, state.OwnerID);
                    lot.neighborhood_id = state.NhoodID;
                    lot.ring_backup_num = 0;
                    lot.shard_id        = Options.ShardId;
                    lot.skill_mode      = state.SkillMode;
                    var random = new Random();

                    OwnerID = lot.owner_id ?? 0;
                    if (lot.owner_id == 0)
                    {
                        lot.owner_id = null;
                    }

                    Console.WriteLine($"Attempting to restore '{state.Name}', at location {lot.location}.");
                    var originalName = lot.name;
                    int addedOffset  = 1;
                    var existingName = da.Lots.GetByName(lot.shard_id, lot.name);
                    while (existingName != null)
                    {
                        lot.name = originalName + " (" + (addedOffset++) + ")";
                        Console.WriteLine($"Lot already exists with name {originalName}. Trying with name {lot.name}.");
                        existingName = da.Lots.GetByName(lot.shard_id, lot.name);
                    }

                    var existingLocation = da.Lots.GetByLocation(Options.ShardId, lot.location);
                    while (existingLocation != null)
                    {
                        lot.location = (uint)(random.Next(512) | (random.Next(512) << 16));
                        Console.WriteLine($"Lot already exists at location {existingLocation.location}. Placing at random location {lot.location}.");
                        existingLocation = da.Lots.GetByLocation(Options.ShardId, lot.location);
                    }

                    var objectFromInventory = 0;
                    var objectFromLot       = 0;
                    var objectCreate        = 0;
                    var objectIgnore        = 0;

                    string lotFolder = "./";
                    if (!Options.Report)
                    {
                        Console.WriteLine($"Creating database entry for lot...");
                        try
                        {
                            lot.lot_id = (int)da.Lots.Create(lot);
                            Console.WriteLine($"Database entry for lot created! (ID {lot.lot_id})");
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("FATAL! Could not create lot in database.");
                            Console.WriteLine(e.ToString());
                            continue;
                        }

                        Console.WriteLine($"Creating and populating data folder for lot...");
                        try
                        {
                            lotFolder = Path.Combine(Config.SimNFS, $"Lots/{lot.lot_id.ToString("x8")}/");
                            Directory.CreateDirectory(lotFolder);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("FATAL! Could not create lot data in NFS.");
                            Console.WriteLine(e.ToString());
                            continue;
                        }
                    }

                    foreach (var obj in vm.Entities)
                    {
                        var estate = obj.PlatformState as VMTSOObjectState;
                        if (estate != null)
                        {
                            estate.OwnerID = RemapAvatarID(da, estate.OwnerID); //make sure the owners exist
                        }
                    }

                    //check the objects
                    var processed = new HashSet <uint>();
                    foreach (var obj in vm.Entities)
                    {
                        if (obj.PersistID == 0 || processed.Contains(obj.PersistID) || obj is VMAvatarMarshal)
                        {
                            if (PersistRemap.ContainsKey(obj.PersistID))
                            {
                                obj.PersistID = PersistRemap[obj.PersistID];
                            }
                            continue;
                        }
                        processed.Add(obj.PersistID);

                        try
                        {
                            //does this object exist in the database?
                            var dbObj = da.Objects.Get(obj.PersistID);
                            var guid  = (obj.MasterGUID == 0) ? obj.GUID : obj.MasterGUID;
                            if (dbObj == null)
                            {
                                Console.Write("++");
                                Console.Write(guid);
                                Console.Write(": Does not exist in DB. Creating new entry...");
                                objectCreate++;
                                CreateDbObject(da, obj, lot);
                                Done();
                            }
                            else
                            {
                                if (dbObj.lot_id != null)
                                {
                                    Console.Write("!!");
                                    Console.Write(dbObj.dyn_obj_name ?? dbObj.type.ToString());
                                    Console.Write(": In another property! ");
                                    if (Options.Safe || Options.Objects)
                                    {
                                        if (Options.Objects)
                                        {
                                            Console.Write("Creating a new entry...");
                                            objectCreate++;
                                            CreateDbObject(da, obj, lot);
                                            Done();
                                        }
                                        else
                                        {
                                            Console.WriteLine("Object will be ignored.");
                                            objectIgnore++;
                                        }
                                    }
                                    else
                                    {
                                        Console.Write("Taking the object back...");
                                        objectFromLot++;
                                        if (!Options.Report)
                                        {
                                            da.Objects.SetInLot(obj.PersistID, (uint)lot.lot_id);
                                        }
                                        Done();
                                    }
                                }
                                else
                                {
                                    Console.Write("~~");
                                    Console.Write(dbObj.dyn_obj_name ?? dbObj.type.ToString());
                                    Console.Write(": In a user's inventory. ");
                                    if (dbObj.type != guid)
                                    {
                                        Console.Write("(WRONG GUID - MAKING NEW OBJECT) ");
                                    }
                                    if (Options.Objects || dbObj.type != guid)
                                    {
                                        Console.Write("Creating a new entry...");
                                        objectCreate++;
                                        CreateDbObject(da, obj, lot);
                                        Done();
                                    }
                                    else
                                    {
                                        Console.Write("Taking the object back...");
                                        objectFromInventory++;
                                        if (!Options.Report)
                                        {
                                            da.Objects.SetInLot(obj.PersistID, (uint)lot.lot_id);
                                        }
                                        Done();
                                    }
                                }
                            }
                        } catch (Exception e)
                        {
                            Console.WriteLine($"Failed - {e.Message}. Continuing...");
                        }
                    }

                    Console.WriteLine($"Objects created: {objectCreate}, Objects from inventory: {objectFromInventory}, Objects from other lot: {objectFromLot}, Objects ignored: {objectIgnore}");
                    Console.WriteLine($"Object/lot owner avatars missing (replaced with lot owner): {AvatarIDs.Count(x => x.Key != x.Value)}");
                    Console.WriteLine("Object scan complete! Serializing restored state...");
                    byte[] newData;
                    using (var mem = new MemoryStream())
                    {
                        using (var writer = new BinaryWriter(mem))
                        {
                            vm.SerializeInto(writer);
                            newData = mem.ToArray();
                        }
                    }
                    Console.WriteLine("New FSOV created. Finalizing restore...");

                    if (!Options.Report)
                    {
                        File.WriteAllBytes(Path.Combine(lotFolder, "state_0.fsov"), newData);
                        Console.WriteLine($"Restoring {Path.GetFileName(file)} complete!");
                        da.Lots.UpdateRingBackup(lot.lot_id, 0);
                    }
                    else
                    {
                        Console.WriteLine($"Report for {Path.GetFileName(file)} complete!");
                    }
                }
            }
            Console.WriteLine("All properties processed. Press any key to exit.");
            Console.ReadKey();
            return(0);
        }
示例#14
0
        public void Handle(IVoltronSession session, BulletinRequest message)
        {
            if (session.IsAnonymous)  //CAS users can't do this.
            {
                return;
            }

            try
            {
                using (var da = DA.Get())
                {
                    switch (message.Type)
                    {
                    case BulletinRequestType.GET_MESSAGES:
                        //when a user logs in they will send this request to recieve all messages after their last recieved message.
                    {
                        var msgs = da.BulletinPosts.GetByNhoodId(message.TargetNHood, 0);
                        session.Write(new BulletinResponse()
                            {
                                Type     = BulletinResponseType.MESSAGES,
                                Messages = msgs.Select(x => ToItem(x)).ToArray()
                            });
                        return;
                    }

                    case BulletinRequestType.DELETE_MESSAGE:
                        //delete bulletin message
                    {
                        //check if either we own this post or we're admin
                        var post = da.BulletinPosts.Get(message.Value);
                        if (post == null)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_MESSAGE_DOESNT_EXIST));
                            return;         //doesn't exist
                        }
                        if (post.avatar_id != session.AvatarId)
                        {
                            //not the owner of this post. are we an admin?
                            var myAva = da.Avatars.Get(session.AvatarId);
                            if (myAva == null || myAva.moderation_level == 0)
                            {
                                session.Write(Code(BulletinResponseType.FAIL_CANT_DELETE));
                                return;
                            }
                        }

                        da.BulletinPosts.SoftDelete(message.Value);
                        session.Write(Code(BulletinResponseType.SUCCESS));
                        return;
                    }

                    case BulletinRequestType.PROMOTE_MESSAGE:
                        //promote message to the mayor channel
                    {
                        //check if either we're mayor of this post's nhood or we're admin
                        //also the post should like, exist.
                        var post = da.BulletinPosts.Get(message.Value);
                        if (post == null)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_MESSAGE_DOESNT_EXIST));
                            return;
                        }
                        if ((post.flags & 1) > 0)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_ALREADY_PROMOTED));
                            return;         //already promoted.
                        }
                        if (post.type != DbBulletinType.community)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_BAD_PERMISSION));
                            return;
                        }
                        var postNhood = da.Neighborhoods.Get((uint)post.neighborhood_id);
                        if (postNhood == null || postNhood.mayor_id != session.AvatarId)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_NOT_MAYOR));
                            return;         //no permission
                        }
                        post.flags |= 1;

                        da.BulletinPosts.SetTypeFlag(message.Value, DbBulletinType.mayor, (int)post.flags);
                        session.Write(Code(BulletinResponseType.SUCCESS));
                        return;
                    }

                    case BulletinRequestType.CAN_POST_MESSAGE:
                    case BulletinRequestType.CAN_POST_SYSTEM_MESSAGE:
                    case BulletinRequestType.POST_SYSTEM_MESSAGE:
                    case BulletinRequestType.POST_MESSAGE:
                    {
                        var type  = (message.Type == BulletinRequestType.POST_SYSTEM_MESSAGE) ? DbBulletinType.system : DbBulletinType.community;
                        var myAva = da.Avatars.Get(session.AvatarId);
                        if (myAva == null)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_UNKNOWN));
                            return;
                        }

                        var now = Epoch.Now;
                        if (now - myAva.move_date < MOVE_LIMIT_PERIOD && myAva.moderation_level == 0)
                        {
                            session.Write(Code(BulletinResponseType.SEND_FAIL_JUST_MOVED)); return;
                        }

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

                        if (myLot == null || myLot.neighborhood_id != message.TargetNHood ||
                            message.Type == BulletinRequestType.POST_SYSTEM_MESSAGE || message.Type == BulletinRequestType.CAN_POST_SYSTEM_MESSAGE)
                        {
                            //need to live in this nhood to post
                            //if we're an admin we can ignore this
                            if (myAva.moderation_level == 0)
                            {
                                session.Write(Code(BulletinResponseType.SEND_FAIL_NON_RESIDENT));
                                return;
                            }
                        }

                        var postNhood = da.Neighborhoods.Get((uint)message.TargetNHood);
                        if (postNhood == null)
                        {
                            session.Write(Code(BulletinResponseType.FAIL_UNKNOWN));
                            return;
                        }
                        if (session.AvatarId == postNhood.mayor_id && type == DbBulletinType.community)
                        {
                            type = DbBulletinType.mayor;
                        }

                        //are we nhood gameplay banned?

                        var ban = da.Neighborhoods.GetNhoodBan(myAva.user_id);
                        if (ban != null)
                        {
                            session.Write(new BulletinResponse
                                {
                                    Type       = BulletinResponseType.SEND_FAIL_GAMEPLAY_BAN,
                                    Message    = ban.ban_reason,
                                    BanEndDate = ban.end_date
                                });
                            return;
                        }

                        //verify post frequency
                        var last      = da.BulletinPosts.LastUserPost(myAva.user_id, message.TargetNHood);
                        int frequency = 0;
                        switch (type)
                        {
                        case DbBulletinType.mayor:
                            frequency = POST_FREQ_LIMIT_MAYOR; break;

                        case DbBulletinType.community:
                            frequency = POST_FREQ_LIMIT; break;
                        }
                        if (Epoch.Now - (last?.date ?? 0) < frequency)
                        {
                            session.Write(Code(BulletinResponseType.SEND_FAIL_TOO_FREQUENT));
                            return;
                        }

                        if (message.Type == BulletinRequestType.CAN_POST_MESSAGE || message.Type == BulletinRequestType.CAN_POST_SYSTEM_MESSAGE)
                        {
                            session.Write(Code(BulletinResponseType.SUCCESS));
                            return;
                        }

                        int?lotID = null;
                        if (message.LotID != 0)
                        {
                            //verify the lot ID if one is included
                            var lot = da.Lots.GetByLocation(Context.ShardId, message.LotID);
                            if (lot == null)
                            {
                                session.Write(Code(BulletinResponseType.SEND_FAIL_INVALID_LOT));
                                return;
                            }
                            lotID = (int)message.LotID;
                        }

                        if (message.Message.Length == 0 || message.Message.Length > 1000)
                        {
                            session.Write(Code(BulletinResponseType.SEND_FAIL_INVALID_MESSAGE));
                            return;
                        }
                        if (message.Title.Length == 0 || message.Title.Length > 64)
                        {
                            session.Write(Code(BulletinResponseType.SEND_FAIL_INVALID_TITLE));
                            return;
                        }

                        var db = new DbBulletinPost()
                        {
                            avatar_id       = session.AvatarId,
                            date            = Epoch.Now,
                            title           = message.Title,
                            body            = message.Message,
                            flags           = 0,
                            lot_id          = lotID,
                            neighborhood_id = (int)message.TargetNHood,
                            type            = type
                        };
                        try
                        {
                            db.bulletin_id = da.BulletinPosts.Create(db);
                        }
                        catch (Exception e)
                        {
                            LOG.Error(e.ToString());
                            session.Write(Code(BulletinResponseType.FAIL_UNKNOWN));
                            return;
                        }

                        session.Write(new BulletinResponse()
                            {
                                Type     = BulletinResponseType.SEND_SUCCESS,
                                Messages = new BulletinItem[] { ToItem(db) }
                            });
                    }
                    break;
                    }
                }
            }
            catch (Exception e)
            {
                LOG.Error(e.ToString());
                session.Write(Code(BulletinResponseType.FAIL_UNKNOWN));
                return;
            }
        }