Пример #1
0
        public void Handle(IVoltronSession session, FindAvatarRequest packet)
        {
            if (session.IsAnonymous)
            {
                return;
            }
            using (var da = DAFactory.Get()) {
                var privacy = da.Avatars.GetPrivacyMode(packet.AvatarId);
                if (privacy > 0)
                {
                    session.Write(new FindAvatarResponse
                    {
                        AvatarId = packet.AvatarId,
                        LotId    = 0,
                        Status   = FindAvatarResponseStatus.PRIVACY_ENABLED
                    });
                    return;
                }
                //TODO: get ignore status

                var claim = da.AvatarClaims.GetByAvatarID(packet.AvatarId);
                //maybe check shard id against avatar in future. The client should do this anyways, and the server providing this functionality to everyone isnt a disaster.
                var location = claim?.location ?? 0;
                session.Write(new FindAvatarResponse
                {
                    AvatarId = packet.AvatarId,
                    LotId    = location,
                    Status   = (location == 0)?FindAvatarResponseStatus.NOT_ON_LOT:FindAvatarResponseStatus.FOUND
                });
            }
        }
Пример #2
0
 public void Handle(IVoltronSession session, FindPlayerPDU packet)
 {
     session.Write(new FindPlayerResponsePDU {
         StatusCode = 0x00,
         ReasonText = "uh"
     });
 }
Пример #3
0
        public async void Handle(IVoltronSession session, AvatarRetireRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

            try
            {
                using (var da = DA.Get)
                {
                    var avatar = da.Avatars.Get(session.AvatarId);
                    if (avatar == null)
                    {
                        return;
                    }

                    if (avatar.date > Epoch.Now - (60 * 60 * 24 * 7) && !da.Users.GetById(session.UserId).is_admin)
                    {
                        session.Write(new Protocol.Voltron.Packets.AnnouncementMsgPDU()
                        {
                            SenderID = "??" + "System",
                            Message  = "\r\n" + "You cannot delete a sim younger than a week old!",
                            Subject  = "Error"
                        });
                        LOG.Info("Avatar " + avatar.name + " under account " + avatar.user_id + " attempted to delete a less than week old account.");

                        session.Close();
                        return;
                    }
                    LOG.Info("Deleting avatar " + avatar.name + " under account " + avatar.user_id + ".");

                    var lots = da.Roommates.GetAvatarsLots(session.AvatarId);
                    foreach (var roomie in lots)
                    {
                        var lot = da.Lots.Get(roomie.lot_id);
                        if (lot == null)
                        {
                            continue;
                        }
                        var kickResult = await Kernel.Get <ChangeRoommateHandler>().TryKick(lot.location, session.AvatarId, session.AvatarId);

                        //if something goes wrong here, just return.
                        if (kickResult != Protocol.Electron.Model.ChangeRoommateResponseStatus.SELFKICK_SUCCESS)
                        {
                            return;
                        }
                    }

                    da.Avatars.Delete(session.AvatarId);
                }

                //now all our objects have null owner. objects with null owner will be cleaned out by the purge task (this needs to hit nfs & db).

                session.Close();
            } catch
            {
            }
        }
Пример #4
0
 public void Handle(IVoltronSession session, SetIgnoreListPDU packet)
 {
     session.Write(new SetIgnoreListResponsePDU {
         StatusCode         = 0,
         ReasonText         = "OK",
         MaxNumberOfIgnored = 50
     });
 }
Пример #5
0
 public void UserJoined(IVoltronSession session)
 {
     if (TuningCache == null)
     {
         UpdateTuningCache();
     }
     session.Write(new GlobalTuningUpdate()
     {
         Tuning = TuningCache, ObjectUpgrades = ObjectUpgradeData
     });
 }
Пример #6
0
 public void Send(uint avatarID, params object[] messages)
 {
     lock (_Visitors)
     {
         IVoltronSession visitor = null;
         if (_Visitors.TryGetValue(avatarID, out visitor))
         {
             visitor.Write(messages);
         }
     }
 }
Пример #7
0
 public void UserJoined(IVoltronSession session)
 {
     if (TuningCache == null)
     {
         UpdateTuningCache();
     }
     session.Write(new GlobalTuningUpdate()
     {
         Tuning = TuningCache
     });
 }
Пример #8
0
 public void WriteFail(IVoltronSession session, InstantMessage message, InstantMessageFailureReason fail)
 {
     session.Write(new InstantMessage
     {
         FromType = FSO.Common.Enum.UserReferenceType.AVATAR,
         From     = message.To,
         Type     = InstantMessageType.FAILURE_ACK,
         Message  = "",
         AckID    = message.AckID,
         Reason   = fail
     });
 }
Пример #9
0
        public bool TryJoin(IVoltronSession session)
        {
            if (Container.IsAvatarOnLot(session.AvatarId))
            {
                session.Write(new FSOVMProtocolMessage(true, "11", "12"));
                return(false); //already on the lot.
            }
            lock (_Visitors)
            {
                if (ShuttingDown || (_Visitors.Count >= ((Context.HighMax)?256:24)))
                {
                    if (ShuttingDown)
                    {
                        return(false);              //cannot join
                    }
                    //check if this user has special permissions. should only happen when a lot is full
                    //let them in anyways if they do
                    using (var da = DAFactory.Get())
                    {
                        var avatar = da.Avatars.Get(session.AvatarId);
                        if (avatar.moderation_level == 0 && !Context.JobLot)
                        {
                            if (da.Roommates.Get(session.AvatarId, Context.DbId) == null)
                            {
                                session.Write(new FSOVMProtocolMessage(true, "15", "16"));
                                return(false); //not a roommate
                            }
                        }
                    }
                }

                session.SetAttribute("currentLot", ((Context.Id & 0x40000000) > 0)?(int)Context.Id:Context.DbId);
                _Visitors.Add(session.AvatarId, session);

                SyncNumVisitors();

                InBackground(() => Container.AvatarJoin(session));
                return(true);
            }
        }
Пример #10
0
        private void HandleNetMessage(IVoltronSession session, cTSONetMessageStandard msg, DBRequestWrapperPDU packet)
        {
            if (!msg.DatabaseType.HasValue)
            {
                return;
            }
            var requestType = DBRequestTypeUtils.FromRequestID(msg.DatabaseType.Value);

            object response = null;

            switch (requestType)
            {
            case DBRequestType.LoadAvatarByID:
                response = HandleLoadAvatarById(session, msg);
                break;

            case DBRequestType.SearchExactMatch:
                response = HandleSearchExact(session, msg);
                break;

            case DBRequestType.Search:
                response = HandleSearchWildcard(session, msg);
                break;

            case DBRequestType.GetTopResultSetByID:
                response = HandleGetTop100(session, msg);
                break;
            }

            if (response != null)
            {
                session.Write(new DBRequestWrapperPDU {
                    SendingAvatarID = packet.SendingAvatarID,
                    Badge           = packet.Badge,
                    IsAlertable     = packet.IsAlertable,
                    Sender          = packet.Sender,
                    Body            = response
                });
            }
        }
Пример #11
0
        /// <summary>
        /// The user is asking for some in RAM data
        /// </summary>
        /// <param name="session"></param>
        /// <param name="packet"></param>
        public async void Handle(IVoltronSession session, DataServiceWrapperPDU packet)
        {
            try //data service throws exceptions (SecurityException, etc) when invalid requests are made. These should not crash the server...
            {
                if (packet.Body is cTSONetMessageStandard)
                {
                    var msg = (cTSONetMessageStandard)packet.Body;
                    if (msg.ComplexParameter is cTSOTopicUpdateMessage)
                    {
                        var update = msg.ComplexParameter as cTSOTopicUpdateMessage;
                        DataService.ApplyUpdate(update, session);
                        return;
                    }

                    var type = MaskedStructUtils.FromID(packet.RequestTypeID);

                    if (!msg.Parameter.HasValue)
                    {
                        return;
                    }

                    //if (type == MaskedStruct.MapView_NearZoom_Lot_Thumbnail || type == MaskedStruct.Thumbnail_Lot || type == MaskedStruct.MapView_NearZoom_Lot) { }

                    if (type != MaskedStruct.MyAvatar && type != MaskedStruct.SimPage_Main && type != MaskedStruct.MapView_RollOverInfo_Lot_Price &&
                        type != MaskedStruct.MapView_RollOverInfo_Lot && type != MaskedStruct.Unknown &&
                        type != MaskedStruct.SimPage_DescriptionPanel && type != MaskedStruct.PropertyPage_LotInfo &&
                        type != MaskedStruct.Messaging_Message_Avatar && type != MaskedStruct.Messaging_Icon_Avatar &&
                        type != MaskedStruct.MapView_NearZoom_Lot_Thumbnail && type != MaskedStruct.Thumbnail_Lot &&
                        type != MaskedStruct.CurrentCity && type != MaskedStruct.MapView_NearZoom_Lot &&
                        type != MaskedStruct.Thumbnail_Avatar && type != MaskedStruct.SimPage_MyLot &&
                        type != MaskedStruct.SimPage_JobsPanel && type != MaskedStruct.FriendshipWeb_Avatar &&
                        type != MaskedStruct.SimPage_SkillsPanel && type != MaskedStruct.AdmitInfo_Lot)
                    {
                        //Currently broken for some reason
                        return;
                    }

                    //Lookup the entity, then process the request and send the response
                    var task = DataService.Get(type, msg.Parameter.Value);
                    if (task != null)
                    {
                        var entity = await task;

                        var serialized = DataService.SerializeUpdate(type, entity, msg.Parameter.Value);
                        for (int i = 0; i < serialized.Count; i++)
                        {
                            object serial = serialized[i];
                            session.Write(new DataServiceWrapperPDU()
                            {
                                SendingAvatarID = packet.SendingAvatarID,
                                RequestTypeID   = packet.RequestTypeID,
                                Body            = serial
                            });
                        }
                    }
                }
                else if (packet.Body is cTSOTopicUpdateMessage)
                {
                    //Client wants to update a value in the data service
                    var update = packet.Body as cTSOTopicUpdateMessage;
                    DataService.ApplyUpdate(update, session);

                    List <uint> resultDotPath = new List <uint>();
                    foreach (var item in update.DotPath)
                    {
                        var ires = item;
                        if (ires == 0x1095C1E1)
                        {
                            ires = 0x7EA285CD;                     //rewrite: filter id -> returns -> result list
                        }
                        resultDotPath.Add(ires);

                        if (ires == packet.RequestTypeID)
                        {
                            break;
                        }
                    }

                    var result = await DataService.SerializePath(resultDotPath.ToArray());

                    if (result != null)
                    {
                        session.Write(new DataServiceWrapperPDU()
                        {
                            SendingAvatarID = packet.SendingAvatarID,
                            RequestTypeID   = packet.RequestTypeID,
                            Body            = result
                        });
                    }

                    /*var task = DataService.Get(update.DotPath[0], update.DotPath[1]);
                     * if(task != null)
                     * {
                     *  var entity = await task;
                     *
                     *  var serialized = DataService.SerializeUpdate(type, entity, msg.Parameter.Value);
                     * }*/
                    /**/
                }
            }
            catch (Exception e)
            {
                //SerializePath throws generic exceptions.
                //plus we don't want weird special cases crashing the whole server.
                LOG.Error(e, "Voltron DataService request failed!");
            }
        }
Пример #12
0
        /// <summary>
        /// Register a new avatar
        /// </summary>
        /// <param name="session"></param>
        /// <param name="packet"></param>
        public void Handle(IVoltronSession session, RSGZWrapperPDU packet)
        {
            PurchasableOutfit head = null;
            PurchasableOutfit body = null;

            switch (packet.Gender)
            {
            case Protocol.Voltron.Model.Gender.FEMALE:
                head = ValidFemaleOutfits[packet.HeadOutfitId];
                body = ValidFemaleOutfits[packet.BodyOutfitId];
                break;

            case Protocol.Voltron.Model.Gender.MALE:
                head = ValidMaleOutfits[packet.HeadOutfitId];
                body = ValidMaleOutfits[packet.BodyOutfitId];
                break;
            }

            if (head == null)
            {
                session.Write(new CreateASimResponse {
                    Status = CreateASimStatus.FAILED,
                    Reason = CreateASimFailureReason.HEAD_VALIDATION_ERROR
                });
                return;
            }

            if (body == null)
            {
                session.Write(new CreateASimResponse
                {
                    Status = CreateASimStatus.FAILED,
                    Reason = CreateASimFailureReason.BODY_VALIDATION_ERROR
                });
                return;
            }

            if (!NAME_VALIDATION.IsMatch(packet.Name))
            {
                session.Write(new CreateASimResponse
                {
                    Status = CreateASimStatus.FAILED,
                    Reason = CreateASimFailureReason.NAME_VALIDATION_ERROR
                });
                return;
            }

            if (!DESC_VALIDATION.IsMatch(packet.Description))
            {
                session.Write(new CreateASimResponse
                {
                    Status = CreateASimStatus.FAILED,
                    Reason = CreateASimFailureReason.DESC_VALIDATION_ERROR
                });
                return;
            }

            uint newId = 0;

            using (var db = DAFactory.Get)
            {
                var newAvatar = new DbAvatar
                {
                    shard_id    = Context.ShardId,
                    name        = packet.Name,
                    description = packet.Description,
                    date        = Epoch.Now,
                    head        = head.OutfitID,
                    body        = body.OutfitID,
                    skin_tone   = (byte)packet.SkinTone,
                    gender      = packet.Gender == Protocol.Voltron.Model.Gender.FEMALE ? DbAvatarGender.female : DbAvatarGender.male,
                    user_id     = session.UserId,
                    budget      = 0
                };

                if (packet.Gender == Protocol.Voltron.Model.Gender.MALE)
                {
                    newAvatar.body_swimwear  = 0x5470000000D;
                    newAvatar.body_sleepwear = 0x5440000000D;
                }
                else
                {
                    newAvatar.body_swimwear  = 0x620000000D;
                    newAvatar.body_sleepwear = 0x5150000000D;
                }

                var user = db.Users.GetById(session.UserId);
                if ((user?.is_moderator) ?? false)
                {
                    newAvatar.moderation_level = 1;
                }

                try
                {
                    newId = db.Avatars.Create(newAvatar);
                } catch (Exception e)
                {
                    //unique name error or avatar limit exceeded.
                    //todo: special error for avatar limit? exception is thrown from BEFORE INSERT trigger.
                    session.Write(new CreateASimResponse
                    {
                        Status = CreateASimStatus.FAILED,
                        Reason = CreateASimFailureReason.NAME_TAKEN
                    });
                    return;
                }

                //create clothes
                try
                {
                    db.Outfits.Create(new Database.DA.Outfits.DbOutfit {
                        avatar_owner   = newId,
                        asset_id       = newAvatar.body,
                        purchase_price = 0,
                        sale_price     = 0,
                        outfit_type    = (byte)VMPersonSuits.DefaultDaywear,
                        outfit_source  = Database.DA.Outfits.DbOutfitSource.cas
                    });

                    db.Outfits.Create(new Database.DA.Outfits.DbOutfit
                    {
                        avatar_owner   = newId,
                        asset_id       = newAvatar.body_sleepwear,
                        purchase_price = 0,
                        sale_price     = 0,
                        outfit_type    = (byte)VMPersonSuits.DefaultSleepwear,
                        outfit_source  = Database.DA.Outfits.DbOutfitSource.cas
                    });

                    db.Outfits.Create(new Database.DA.Outfits.DbOutfit
                    {
                        avatar_owner   = newId,
                        asset_id       = newAvatar.body_swimwear,
                        purchase_price = 0,
                        sale_price     = 0,
                        outfit_type    = (byte)VMPersonSuits.DefaultSwimwear,
                        outfit_source  = Database.DA.Outfits.DbOutfitSource.cas
                    });
                }
                catch (Exception e) {
                    session.Write(new CreateASimResponse
                    {
                        Status = CreateASimStatus.FAILED,
                        Reason = CreateASimFailureReason.NONE
                    });
                    return;
                }
            }

            ((VoltronSession)session).AvatarId = newId;

            session.Write(new CreateASimResponse {
                Status      = CreateASimStatus.SUCCESS,
                NewAvatarId = newId
            });
            session.Write(new TransmitCreateAvatarNotificationPDU {
            });
        }
Пример #13
0
        public async void Handle(IVoltronSession session, NhoodRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

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

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

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

                    //are we nhood gameplay banned?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        //ok, we're all good.

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

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

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

                                //send back the candidate list


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                        break;
                    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                    default:
                        session.Write(Code(NhoodResponseCode.UNKNOWN_ERROR)); return;
                    }
                }
            } catch (Exception e)
            {
                LOG.Error(e.ToString());
                session?.Write(Code(NhoodResponseCode.UNKNOWN_ERROR));
            }
        }
Пример #14
0
        public async void Handle(IVoltronSession session, PurchaseLotRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

            var isPurchasable = Realestate.IsPurchasable(packet.LotLocation_X, packet.LotLocation_Y);

            if (!isPurchasable)
            {
                session.Write(new PurchaseLotResponse()
                {
                    Status = PurchaseLotStatus.FAILED,
                    Reason = PurchaseLotFailureReason.LOT_NOT_PURCHASABLE
                });
                return;
            }

            var packedLocation = MapCoordinates.Pack(packet.LotLocation_X, packet.LotLocation_Y);
            var price          = Realestate.GetPurchasePrice(packet.LotLocation_X, packet.LotLocation_Y);
            int resultFunds;

            uint lotId = 0;

            using (var db = DA.Get())
            {
                var ownedLot = db.Lots.GetByOwner(session.AvatarId);
                if (ownedLot != null)
                {
                    //we own the lot we are roomie of.
                    var roommates = db.Roommates.GetLotRoommates(ownedLot.lot_id);
                    var ds        = await DataService.Get <FSO.Common.DataService.Model.Lot>(ownedLot.location);

                    if (ds.Lot_IsOnline)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.NOT_OFFLINE_FOR_MOVE //TODO: race condition might make this possible?
                        });
                        return;
                    }

                    if (roommates.Count > 1)
                    {
                        //cannot start fresh with roommates for now.
                        packet.StartFresh = false;
                    }

                    var oldLoc   = MapCoordinates.Unpack(ownedLot.location);
                    var moveCost = price - Realestate.GetPurchasePrice(oldLoc.X, oldLoc.Y);
                    moveCost += 2000;                                                                             //flat rate for moving location

                    var transactionResult = db.Avatars.Transaction(session.AvatarId, uint.MaxValue, moveCost, 5); //expenses misc... maybe add specific for lot
                    resultFunds = transactionResult.source_budget;
                    if (!transactionResult.success)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status   = PurchaseLotStatus.FAILED,
                            Reason   = PurchaseLotFailureReason.INSUFFICIENT_FUNDS,
                            NewFunds = resultFunds
                        });
                        return;
                    }
                    db.Lots.UpdateLocation(ownedLot.lot_id, packedLocation, packet.StartFresh);

                    DataService.Invalidate <FSO.Common.DataService.Model.Lot>(ownedLot.location); //nullify old lot
                    DataService.Invalidate <FSO.Common.DataService.Model.Lot>(packedLocation);    //update new lot
                }
                else
                {
                    //we may still be roomie in a lot. If we are, we must be removed from that lot.
                    var myLots = db.Roommates.GetAvatarsLots(session.AvatarId);
                    if (myLots.Count > 0)
                    {
                        //we can't be in the lot when this happens. Make sure city owns avatar.
                        bool canEvict = session.AvatarClaimId != 0;
                        if (!canEvict)
                        {
                            var claim = db.AvatarClaims.Get(session.AvatarClaimId);
                            if (claim.owner == Context.Config.Call_Sign)
                            {
                                db.Roommates.RemoveRoommate(session.AvatarId, myLots[0].lot_id);
                                canEvict = true;
                            }
                            else
                            {
                                canEvict = false;
                            }
                        }

                        if (!canEvict)
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status = PurchaseLotStatus.FAILED,
                                Reason = PurchaseLotFailureReason.IN_LOT_CANT_EVICT
                            });
                            return;
                        }
                    }

                    var name = packet.Name;
                    if (!GlobalRealestate.ValidateLotName(name))
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.NAME_VALIDATION_ERROR
                        });
                        return;
                    }

                    var transactionResult = db.Avatars.Transaction(session.AvatarId, uint.MaxValue, price, 5); //expenses misc... maybe add specific for lot
                    resultFunds = transactionResult.source_budget;
                    if (!transactionResult.success)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status   = PurchaseLotStatus.FAILED,
                            Reason   = PurchaseLotFailureReason.INSUFFICIENT_FUNDS,
                            NewFunds = resultFunds
                        });
                        return;
                    }

                    try
                    {
                        lotId = db.Lots.Create(new DbLot
                        {
                            name     = name,
                            shard_id = Context.ShardId,

                            location             = packedLocation,
                            owner_id             = session.AvatarId,
                            created_date         = Epoch.Now,
                            category_change_date = Epoch.Default,
                            category             = LotCategory.none,

                            buildable_area = 1,
                            description    = ""
                        });

                        DataService.Invalidate <FSO.Common.DataService.Model.Lot>(packedLocation);
                    }
                    catch (Exception ex)
                    {
                        var returnMoney = db.Avatars.Transaction(uint.MaxValue, session.AvatarId, price, 5); //refund
                        //Name taken
                        if (ex.Message == "NAME")
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status   = PurchaseLotStatus.FAILED,
                                Reason   = PurchaseLotFailureReason.NAME_TAKEN, //TODO: this can also happen if the location was taken. (location is a UNIQUE row)
                                NewFunds = returnMoney.dest_budget
                            });
                        }
                        else
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status   = PurchaseLotStatus.FAILED,
                                Reason   = PurchaseLotFailureReason.UNKNOWN, //likely already roommate somewhere else, or we got race condition'd by another roomie request
                                NewFunds = returnMoney.dest_budget
                            });
                        }
                        return;
                    }
                }
            }

            //lot init happens on first join, as part of the loading process. If the lot somehow crashes before first save, it'll just be a blank slate again.

            //TODO: Broadcast to the world a new lot exists. i think we do this?

            //Update my sim's lot
            var avatar = await DataService.Get <Avatar>(session.AvatarId);

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

            session.Write(new PurchaseLotResponse()
            {
                Status   = PurchaseLotStatus.SUCCESS,
                NewLotId = lotId,
                NewFunds = resultFunds
            });
        }
Пример #15
0
        public async void Handle(IVoltronSession session, MailRequest message)
        {
            if (session.IsAnonymous)  //CAS users can't do this.
            {
                return;
            }

            try
            {
                switch (message.Type)
                {
                case MailRequestType.POLL_INBOX:
                    //when a user logs in they will send this request to recieve all messages after their last recieved message.
                    using (var da = DA.Get())
                    {
                        var msgs = da.Inbox.GetMessagesAfter(session.AvatarId, new DateTime(message.TimestampID));
                        session.Write(new MailResponse()
                        {
                            Type     = MailResponseType.POLL_RESPONSE,
                            Messages = msgs.Select(x => ToItem(x)).ToArray()
                        });
                        return;
                    }

                case MailRequestType.DELETE:
                    //when a user deletes a message from their pc, it should also be deleted from the server.
                    using (var da = DA.Get())
                    {
                        da.Inbox.DeleteMessage((int)message.TimestampID, session.AvatarId);
                        return;
                    }

                case MailRequestType.SEND:
                    using (var da = DA.Get())
                    {
                        //admins get to change their message type, source, etc, and are never throttled.
                        var modLevel = da.Avatars.GetModerationLevel(session.AvatarId);

                        var them = await DataService.Get <FSO.Common.DataService.Model.Avatar>(message.Item.TargetID);

                        var toName = them.Avatar_Name;

                        if (modLevel == 0)
                        {
                            var bookmarks = them.Avatar_BookmarksVec;
                            if (bookmarks.Any(x => x.Bookmark_Type == 5 && x.Bookmark_TargetID == session.AvatarId))
                            {
                                session.Write(new MailResponse()
                                {
                                    Type = MailResponseType.SEND_IGNORING_YOU,
                                });
                                return;
                            }

                            var you = await DataService.Get <FSO.Common.DataService.Model.Avatar>(session.AvatarId);

                            bookmarks = you.Avatar_BookmarksVec;
                            if (bookmarks.Any(x => x.Bookmark_Type == 5 && x.Bookmark_TargetID == message.Item.TargetID))
                            {
                                session.Write(new MailResponse()
                                {
                                    Type = MailResponseType.SEND_IGNORING_THEM,
                                });
                                return;
                            }
                            message.Item.Type       = 0;
                            message.Item.SenderID   = session.AvatarId;
                            message.Item.SenderName = you.Avatar_Name;
                        }
                        message.Item.ReplyID = null;     //currently unused, but may be used in future to track conversations.

                        var body = BBCodeParser.SanitizeBB(message.Item.Body);
                        if (body.Length > 1500)
                        {
                            body = body.Substring(0, 1500);
                        }
                        message.Item.Body = body;

                        if (SendEmail(message.Item, true))
                        {
                            //give the sent message back to the sender for safe keeping.
                            if (toName != null)
                            {
                                message.Item.SenderName = "To: " + toName;
                                message.Item.SenderID   = message.Item.TargetID;
                                message.Item.ReadState  = 1;
                            }
                            session.Write(new MailResponse()
                            {
                                Type     = MailResponseType.SEND_SUCCESS,
                                Messages = new MessageItem[] { message.Item }
                            });
                            return;
                        }
                        else
                        {
                            session.Write(new MailResponse()
                            {
                                Type     = MailResponseType.SEND_FAILED,
                                Messages = new MessageItem[] { message.Item }
                            });
                            return;
                        }
                    }
                }
            } catch
            {
                if (message.Type == MailRequestType.SEND)
                {
                    session.Write(new MailResponse()
                    {
                        Type     = MailResponseType.SEND_FAILED,
                        Messages = new MessageItem[] { message.Item }
                    });
                }
                return;
            }
        }
Пример #16
0
        public async void Handle(IVoltronSession session, PurchaseLotRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

            var isPurchasable = Realestate.IsPurchasable(packet.LotLocation_X, packet.LotLocation_Y);

            if (!isPurchasable)
            {
                session.Write(new PurchaseLotResponse()
                {
                    Status = PurchaseLotStatus.FAILED,
                    Reason = PurchaseLotFailureReason.LOT_NOT_PURCHASABLE
                });
                return;
            }

            var packedLocation = MapCoordinates.Pack(packet.LotLocation_X, packet.LotLocation_Y);
            var price          = Realestate.GetPurchasePrice(packet.LotLocation_X, packet.LotLocation_Y);

            if (packet.MayorMode)
            {
                price = 2000;
            }
            int resultFunds;

            uint lotId = 0;

            using (var db = DA.Get())
            {
                if (db.Lots.GetByLocation(Context.ShardId, packedLocation) != null)
                {
                    session.Write(new PurchaseLotResponse()
                    {
                        Status = PurchaseLotStatus.FAILED,
                        Reason = PurchaseLotFailureReason.LOT_TAKEN,
                    });
                    return;
                }

                var targNhood = db.Neighborhoods.GetByLocation(packedLocation);
                var nhoodDS   = await DataService.Get <Neighborhood>((uint)targNhood.neighborhood_id);

                DbLot ownedLot;
                if (packet.MayorMode)
                {
                    // we want to move or place the town hall lot for the neighbourhood we're mayor of.
                    // 1. find what neighbourhood we are mayor of. fail if none.
                    // 2. verify the chosen location is in the correct neighborhood. fail if not
                    // 3. get the town hall lot for our nhood. exists = move, doesn't = new
                    var nhood = db.Neighborhoods.GetByMayor(session.AvatarId);
                    if (nhood == null)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.TH_NOT_MAYOR
                        });
                        return;
                    }

                    //verify the neighbourhood makes sense
                    if (nhood.neighborhood_id != (targNhood?.neighborhood_id ?? 0))
                    {
                        //we can't put this neighbourhood's town hall in another neighbourhood.
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.TH_INCORRECT_NHOOD
                        });
                        return;
                    }

                    //find the town hall property
                    if (nhood.town_hall_id == null)
                    {
                        ownedLot = null;
                    }
                    else
                    {
                        ownedLot = db.Lots.Get(nhood.town_hall_id.Value);
                    }
                }
                else
                {
                    if ((targNhood.flag & 1) > 0)
                    {
                        var me = db.Avatars.Get(session.AvatarId);
                        if (me == null || me.moderation_level == 0)
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status = PurchaseLotStatus.FAILED,
                                Reason = PurchaseLotFailureReason.NHOOD_RESERVED,
                            });
                            return;
                        }
                    }

                    ownedLot = db.Lots.GetByOwner(session.AvatarId);
                }

                if (ownedLot != null)
                {
                    //we own the lot we are roomie of.
                    var roommates = db.Roommates.GetLotRoommates(ownedLot.lot_id);
                    var ds        = await DataService.Get <FSO.Common.DataService.Model.Lot>(ownedLot.location);

                    if (ds.Lot_IsOnline)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.NOT_OFFLINE_FOR_MOVE //TODO: race condition might make this possible?
                        });
                        return;
                    }

                    if (roommates.Count > 1)
                    {
                        //cannot start fresh with roommates for now.
                        packet.StartFresh = false;
                    }

                    var oldLoc   = MapCoordinates.Unpack(ownedLot.location);
                    var moveCost = price - Realestate.GetPurchasePrice(oldLoc.X, oldLoc.Y);
                    moveCost += 2000; //flat rate for moving location
                    if (packet.MayorMode)
                    {
                        moveCost = 2000;
                    }

                    var transactionResult = db.Avatars.Transaction(session.AvatarId, uint.MaxValue, moveCost, 5); //expenses misc... maybe add specific for lot
                    resultFunds = transactionResult.source_budget;
                    if (!transactionResult.success)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status   = PurchaseLotStatus.FAILED,
                            Reason   = PurchaseLotFailureReason.INSUFFICIENT_FUNDS,
                            NewFunds = resultFunds
                        });
                        return;
                    }

                    if (!db.Lots.UpdateLocation(ownedLot.lot_id, packedLocation, packet.StartFresh))
                    {
                        //needs to refund the player.
                        var transactionResult2 = db.Avatars.Transaction(uint.MaxValue, session.AvatarId, moveCost, 5);
                        session.Write(new PurchaseLotResponse()
                        {
                            Status   = PurchaseLotStatus.FAILED,
                            Reason   = PurchaseLotFailureReason.LOT_TAKEN,
                            NewFunds = transactionResult2.source_budget
                        });
                        return;
                    }

                    DataService.Invalidate <FSO.Common.DataService.Model.Lot>(ownedLot.location); //nullify old lot
                    DataService.Invalidate <FSO.Common.DataService.Model.Lot>(packedLocation);    //update new lot

                    if (packet.MayorMode)
                    {
                        if (nhoodDS != null)
                        {
                            nhoodDS.Neighborhood_TownHallXY = packedLocation;
                        }
                    }
                    if (nhoodDS != null)
                    {
                        nhoodDS.Neighborhood_LotCount    = (uint)db.Lots.GetLocationsInNhood(nhoodDS.Id).Count;
                        nhoodDS.Neighborhood_AvatarCount = (uint)db.Avatars.GetLivingInNhood(nhoodDS.Id).Count;
                    }

                    var oldNhood = await DataService.Get <Neighborhood>(ownedLot.neighborhood_id);

                    if (oldNhood != null)
                    {
                        oldNhood.Neighborhood_LotCount    = (uint)db.Lots.GetLocationsInNhood(oldNhood.Id).Count;
                        oldNhood.Neighborhood_AvatarCount = (uint)db.Avatars.GetLivingInNhood(oldNhood.Id).Count;
                    }

                    //update nhood move date for all roommates
                    if (ownedLot.neighborhood_id != targNhood.neighborhood_id)
                    {
                        foreach (var roomie in roommates)
                        {
                            db.Avatars.UpdateMoveDate(roomie.avatar_id, Epoch.Now);
                        }
                    }
                }
                else
                {
                    //we may still be roomie in a lot. If we are, we must be removed from that lot.
                    if (!packet.MayorMode)
                    {
                        var myLots = db.Roommates.GetAvatarsLots(session.AvatarId);
                        if (myLots.Count > 0)
                        {
                            if (myLots[0].permissions_level > 1)
                            {
                                //owner should not be able to move out of a lot implicitly
                                session.Write(new PurchaseLotResponse()
                                {
                                    Status = PurchaseLotStatus.FAILED,
                                    Reason = PurchaseLotFailureReason.UNKNOWN
                                });
                                return;
                            }
                            var lot = db.Lots.Get(myLots[0].lot_id);
                            if (lot != null)
                            {
                                var kickResult = await Kernel.Get <ChangeRoommateHandler>().TryKick(lot.location, session.AvatarId, session.AvatarId);

                                if (kickResult != Protocol.Electron.Model.ChangeRoommateResponseStatus.SELFKICK_SUCCESS)
                                {
                                    session.Write(new PurchaseLotResponse()
                                    {
                                        Status = PurchaseLotStatus.FAILED,
                                        Reason = PurchaseLotFailureReason.IN_LOT_CANT_EVICT
                                    });
                                    return;
                                }
                            }

                            /*
                             * //we can't be in the lot when this happens. Make sure city owns avatar.
                             * bool canEvict = session.AvatarClaimId != 0;
                             * if (!canEvict)
                             * {
                             *  var claim = db.AvatarClaims.Get(session.AvatarClaimId);
                             *  if (claim.owner == Context.Config.Call_Sign)
                             *  {
                             *      db.Roommates.RemoveRoommate(session.AvatarId, myLots[0].lot_id);
                             *      canEvict = true;
                             *  }
                             *  else canEvict = false;
                             * }
                             *
                             * if (!canEvict)
                             * {
                             *  session.Write(new PurchaseLotResponse()
                             *  {
                             *      Status = PurchaseLotStatus.FAILED,
                             *      Reason = PurchaseLotFailureReason.IN_LOT_CANT_EVICT
                             *  });
                             *  return;
                             * }
                             */
                        }
                    }

                    var name = packet.Name;
                    if (!GlobalRealestate.ValidateLotName(name))
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status = PurchaseLotStatus.FAILED,
                            Reason = PurchaseLotFailureReason.NAME_VALIDATION_ERROR
                        });
                        return;
                    }

                    var transactionResult = db.Avatars.Transaction(session.AvatarId, uint.MaxValue, price, 5); //expenses misc... maybe add specific for lot
                    resultFunds = transactionResult.source_budget;
                    if (!transactionResult.success)
                    {
                        session.Write(new PurchaseLotResponse()
                        {
                            Status   = PurchaseLotStatus.FAILED,
                            Reason   = PurchaseLotFailureReason.INSUFFICIENT_FUNDS,
                            NewFunds = resultFunds
                        });
                        return;
                    }

                    try
                    {
                        lotId = db.Lots.Create(new DbLot
                        {
                            name     = name,
                            shard_id = Context.ShardId,

                            location             = packedLocation,
                            owner_id             = session.AvatarId,
                            created_date         = Epoch.Now,
                            category_change_date = Epoch.Default,
                            category             = (packet.MayorMode) ? LotCategory.community : LotCategory.none,
                            neighborhood_id      = (uint)targNhood.neighborhood_id,

                            buildable_area = 1,
                            description    = ""
                        });

                        DataService.Invalidate <FSO.Common.DataService.Model.Lot>(packedLocation);

                        if (packet.MayorMode)
                        {
                            db.Neighborhoods.UpdateTownHall((uint)targNhood.neighborhood_id, lotId);
                            if (nhoodDS != null)
                            {
                                nhoodDS.Neighborhood_TownHallXY = packedLocation;
                            }
                        }
                        if (nhoodDS != null)
                        {
                            nhoodDS.Neighborhood_LotCount    = (uint)db.Lots.GetLocationsInNhood(nhoodDS.Id).Count;
                            nhoodDS.Neighborhood_AvatarCount = (uint)db.Avatars.GetLivingInNhood(nhoodDS.Id).Count;
                            db.Avatars.UpdateMoveDate(session.AvatarId, Epoch.Now);
                        }
                    }
                    catch (Exception ex)
                    {
                        var returnMoney = db.Avatars.Transaction(uint.MaxValue, session.AvatarId, price, 5); //refund
                        //Name taken
                        if (ex.Message == "NAME")
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status   = PurchaseLotStatus.FAILED,
                                Reason   = PurchaseLotFailureReason.NAME_TAKEN, //TODO: this can also happen if the location was taken. (location is a UNIQUE row)
                                NewFunds = returnMoney.dest_budget
                            });
                        }
                        else
                        {
                            session.Write(new PurchaseLotResponse()
                            {
                                Status   = PurchaseLotStatus.FAILED,
                                Reason   = PurchaseLotFailureReason.UNKNOWN, //likely already roommate somewhere else, or we got race condition'd by another roomie request
                                NewFunds = returnMoney.dest_budget
                            });
                        }
                        return;
                    }
                }
            }

            //lot init happens on first join, as part of the loading process. If the lot somehow crashes before first save, it'll just be a blank slate again.

            //Update my sim's lot
            var avatar = await DataService.Get <Avatar>(session.AvatarId);

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

            session.Write(new PurchaseLotResponse()
            {
                Status   = PurchaseLotStatus.SUCCESS,
                NewLotId = lotId,
                NewFunds = resultFunds
            });
        }
Пример #17
0
        public async void Handle(IVoltronSession session, FindLotRequest packet)
        {
            if (session.IsAnonymous) //CAS users can't do this.
            {
                return;
            }

            try
            {
                //special modes at 0x200-0x1000
                //0x200: join my job lot
                //0x201-0x2FF: create job lot of type/lotgroup (client CANNOT join on demand.)
                //   0x01-0x10: Robot Factory
                //   0x11-0x20: Restaurant
                //   0x21-0x30: DJ/Dancer
                //0x300+: instanced lots (client CAN join on demand, and appear in data service)

                //note: lotgroup is not the same as a grade. eg. restaurant grade 5+6 share a lot. (zero based grade)
                //nightclub 7-10 share a lot group. (two lots, one chosen randomly)

                if (packet.LotId >= 0x200 && packet.LotId < 0x300)
                {
                    //join my job lot.
                    //look up our avatar's current job and attempt to match them to a job lot with <max players, or a new one.

                    using (var db = DAFactory.Get)
                    {
                        var job = db.Avatars.GetCurrentJobLevel(session.AvatarId);
                        if (job == null)
                        {
                            session.Write(new FindLotResponse
                            {
                                Status = Protocol.Electron.Model.FindLotResponseStatus.UNKNOWN_ERROR,
                                LotId  = packet.LotId
                            });
                        }
                        //ok, choose the correct type/lotgroup combo
                        var type = job.job_type;
                        //if (type > 2) type--; //cook and waiter share job lot
                        //if (type > 3) type--; //dj and dancer share job lot
                        packet.LotId = (uint)(0x201 + (type - 1) * 0x10 + job.job_level);
                    }
                }

                var find = await Lots.TryFindOrOpen(packet.LotId, session.AvatarId, session); //null reference exception possible here

                if (find.Status == Protocol.Electron.Model.FindLotResponseStatus.FOUND)
                {
                    DbLotServerTicket ticket = null;

                    using (var db = DAFactory.Get)
                    {
                        //I need a shard ticket so I can connect to the lot server and assume the correct avatar
                        ticket = new DbLotServerTicket
                        {
                            ticket_id          = Guid.NewGuid().ToString().Replace("-", ""),
                            user_id            = session.UserId,
                            avatar_id          = session.AvatarId,
                            lot_owner          = find.Server.CallSign,
                            date               = Epoch.Now,
                            ip                 = session.IpAddress,
                            lot_id             = find.LotDbId,
                            avatar_claim_id    = session.AvatarClaimId,
                            avatar_claim_owner = Context.Config.Call_Sign
                        };

                        db.Lots.CreateLotServerTicket(ticket);
                    }

                    session.Write(new FindLotResponse
                    {
                        Status          = find.Status,
                        LotId           = find.LotId, //can be modified by job matchmaker
                        LotServerTicket = ticket.ticket_id,
                        Address         = find.Server.PublicHost,
                        User            = session.UserId.ToString()
                    });
                }
                else
                {
                    session.Write(new FindLotResponse
                    {
                        Status = find.Status,
                        LotId  = packet.LotId
                    });
                }
            } catch (Exception e)
            {
                LOG.Error(e);
            }
        }
Пример #18
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);
            }
        }
Пример #19
0
        /// <summary>
        /// The user is asking for some in RAM data
        /// </summary>
        /// <param name="session"></param>
        /// <param name="packet"></param>
        public async void Handle(IVoltronSession session, DataServiceWrapperPDU packet)
        {
            try //data service throws exceptions (SecurityException, etc) when invalid requests are made. These should not crash the server...
            {
                if (packet.Body is cTSONetMessageStandard)
                {
                    var msg = (cTSONetMessageStandard)packet.Body;
                    if (msg.ComplexParameter is cTSOTopicUpdateMessage)
                    {
                        var update = msg.ComplexParameter as cTSOTopicUpdateMessage;
                        DataService.ApplyUpdate(update, session);
                        return;
                    }

                    var type = MaskedStructUtils.FromID(packet.RequestTypeID);

                    if (!msg.Parameter.HasValue)
                    {
                        return;
                    }

                    //Lookup the entity, then process the request and send the response
                    var task = DataService.Get(type, msg.Parameter.Value);
                    if (task != null)
                    {
                        var entity = await task;

                        var serialized = DataService.SerializeUpdate(type, entity, msg.Parameter.Value);
                        for (int i = 0; i < serialized.Count; i++)
                        {
                            object serial = serialized[i];
                            session.Write(new DataServiceWrapperPDU()
                            {
                                SendingAvatarID = packet.SendingAvatarID,
                                RequestTypeID   = packet.RequestTypeID,
                                Body            = serial
                            });
                        }
                    }
                }
                else if (packet.Body is cTSOTopicUpdateMessage)
                {
                    //Client wants to update a value in the data service
                    var update = packet.Body as cTSOTopicUpdateMessage;
                    DataService.ApplyUpdate(update, session);

                    List <uint> resultDotPath = new List <uint>();
                    foreach (var item in update.DotPath)
                    {
                        var ires = item;
                        if (ires == 0x1095C1E1)
                        {
                            ires = 0x7EA285CD;                     //rewrite: filter id -> returns -> result list
                        }
                        resultDotPath.Add(ires);

                        if (ires == packet.RequestTypeID)
                        {
                            break;
                        }
                    }

                    var result = await DataService.SerializePath(resultDotPath.ToArray());

                    if (result != null)
                    {
                        session.Write(new DataServiceWrapperPDU()
                        {
                            SendingAvatarID = packet.SendingAvatarID,
                            RequestTypeID   = packet.RequestTypeID,
                            Body            = result
                        });
                    }

                    /*var task = DataService.Get(update.DotPath[0], update.DotPath[1]);
                     * if(task != null)
                     * {
                     *  var entity = await task;
                     *
                     *  var serialized = DataService.SerializeUpdate(type, entity, msg.Parameter.Value);
                     * }*/
                    /**/
                }
            }
            catch (Exception e)
            {
                //SerializePath throws generic exceptions.
                //plus we don't want weird special cases crashing the whole server.
                LOG.Error(e, "Voltron DataService request failed: from avatar " + session.AvatarId + ", \n" + e.ToString());
            }
        }
Пример #20
0
 private void Status(IVoltronSession session, ChangeRoommateResponseStatus status)
 {
     session.Write(new ChangeRoommateResponse {
         Type = status
     });
 }
Пример #21
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);
            }
        }
Пример #22
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;
            }
        }