private Avatar HydrateOne(DbAvatar dbAvatar, DbLot dbLot) { var result = new Avatar(); result.Avatar_Id = dbAvatar.avatar_id; result.Avatar_Name = dbAvatar.name; result.Avatar_IsOnline = false; result.Avatar_Description = dbAvatar.description; result.Avatar_Appearance = new AvatarAppearance { AvatarAppearance_BodyOutfitID = dbAvatar.body, AvatarAppearance_HeadOutfitID = dbAvatar.head, AvatarAppearance_SkinTone = dbAvatar.skin_tone }; var now = Epoch.Now; result.FetchTime = now; result.Avatar_Age = (uint)((now - dbAvatar.date) / ((long)60 * 60 * 24)); result.Avatar_Skills = new AvatarSkills { AvatarSkills_Body = dbAvatar.skill_body, AvatarSkills_LockLv_Body = dbAvatar.lock_body, AvatarSkills_Charisma = dbAvatar.skill_charisma, AvatarSkills_LockLv_Charisma = dbAvatar.lock_charisma, AvatarSkills_Cooking = dbAvatar.skill_cooking, AvatarSkills_LockLv_Cooking = dbAvatar.lock_cooking, AvatarSkills_Creativity = dbAvatar.skill_creativity, AvatarSkills_LockLv_Creativity = dbAvatar.lock_creativity, AvatarSkills_Logic = dbAvatar.skill_logic, AvatarSkills_LockLv_Logic = dbAvatar.lock_logic, AvatarSkills_Mechanical = dbAvatar.skill_mechanical, AvatarSkills_LockLv_Mechanical = dbAvatar.lock_mechanical }; result.Avatar_PrivacyMode = dbAvatar.privacy_mode; result.Avatar_SkillsLockPoints = (ushort)(20 + result.Avatar_Age / 7); result.Avatar_ModerationLevel = dbAvatar.moderation_level; result.Avatar_MayorNhood = (uint)(dbAvatar.mayor_nhood ?? 0); result.JobLevelProvider = JobLevelProvider; result.RatingProvider = RatingProvider; result.AvgRatingProvider = AvgRatingProvider; result.Avatar_CurrentJob = dbAvatar.current_job; result.Avatar_Top100ListFilter = new Top100ListFilter() { Top100ListFilter_ResultsVec = ImmutableList.Create <uint>(), Top100ListFilter_Top100ListID = 0, }; result.RelationshipProvider = RelationshipProvider; if (dbLot != null) { result.Avatar_LotGridXY = dbLot.location; } result.BookmarkProvider = BookmarkProvider; return(result); }
public DbAvatar StateToDb(VMNetAvatarPersistState avatar) { var state = new DbAvatar(); state.body = avatar.DefaultSuits.Daywear.ID; state.body_sleepwear = avatar.DefaultSuits.Sleepwear.ID; state.body_swimwear = avatar.DefaultSuits.Swimwear.ID; state.body_current = avatar.BodyOutfit; state.skilllock = (byte)avatar.SkillLock; state.lock_body = (ushort)(avatar.SkillLockBody / 100); state.lock_charisma = (ushort)(avatar.SkillLockCharisma / 100); state.lock_cooking = (ushort)(avatar.SkillLockCooking / 100); state.lock_creativity = (ushort)(avatar.SkillLockCreativity / 100); state.lock_logic = (ushort)(avatar.SkillLockLogic / 100); state.lock_mechanical = (ushort)(avatar.SkillLockMechanical / 100); state.skill_body = (ushort)avatar.BodySkill; state.skill_charisma = (ushort)avatar.CharismaSkill; state.skill_cooking = (ushort)avatar.CookingSkill; state.skill_creativity = (ushort)avatar.CreativitySkill; state.skill_logic = (ushort)avatar.LogicSkill; state.skill_mechanical = (ushort)avatar.MechanicalSkill; state.is_ghost = (ushort)avatar.IsGhost; state.ticker_death = (ushort)avatar.DeathTicker; state.ticker_gardener = (ushort)avatar.GardenerRehireTicker; state.ticker_maid = (ushort)avatar.MaidRehireTicker; state.ticker_repairman = (ushort)avatar.RepairmanRehireTicker; state.current_job = (ushort)avatar.OnlineJobID; var motives = new byte[32]; for (int i = 0; i < 16; i++) { var twoi = i + i; motives[twoi] = (byte)(avatar.MotiveData[i] >> 8); motives[twoi + 1] = (byte)avatar.MotiveData[i]; } state.motive_data = motives; return(state); }
private VMNetAvatarPersistState StateFromDB(DbAvatar avatar, List <DbRelationship> rels, List <DbJobLevel> jobs, List <DbRoommate> myRoomieLots, List <uint> ignored) { var state = new VMNetAvatarPersistState(); state.Name = avatar.name; state.PersistID = avatar.avatar_id; state.DefaultSuits = new SimAntics.VMAvatarDefaultSuits(avatar.gender == DbAvatarGender.female); state.DefaultSuits.Daywear.ID = avatar.body; state.DefaultSuits.Swimwear.ID = avatar.body_swimwear; state.DefaultSuits.Sleepwear.ID = avatar.body_sleepwear; state.BodyOutfit = (avatar.body_current == 0)?avatar.body:avatar.body_current; state.HeadOutfit = avatar.head; state.Gender = (short)avatar.gender; state.Budget = (uint)avatar.budget; state.SkinTone = avatar.skin_tone; var now = Epoch.Now; var age = (uint)((now - avatar.date) / ((long)60 * 60 * 24)); state.SkillLock = (short)(20 + age / 7); state.SkillLockBody = (short)(avatar.lock_body * 100); state.SkillLockCharisma = (short)(avatar.lock_charisma * 100); state.SkillLockCooking = (short)(avatar.lock_cooking * 100); state.SkillLockCreativity = (short)(avatar.lock_creativity * 100); state.SkillLockLogic = (short)(avatar.lock_logic * 100); state.SkillLockMechanical = (short)(avatar.lock_mechanical * 100); state.BodySkill = (short)avatar.skill_body; state.CharismaSkill = (short)avatar.skill_charisma; state.CookingSkill = (short)avatar.skill_cooking; state.CreativitySkill = (short)avatar.skill_creativity; state.LogicSkill = (short)avatar.skill_logic; state.MechanicalSkill = (short)avatar.skill_mechanical; state.IsGhost = (short)avatar.is_ghost; state.DeathTicker = (short)avatar.ticker_death; state.GardenerRehireTicker = (short)avatar.ticker_gardener; state.MaidRehireTicker = (short)avatar.ticker_maid; state.RepairmanRehireTicker = (short)avatar.ticker_repairman; state.OnlineJobID = (short)avatar.current_job; state.IgnoredAvatars = new HashSet <uint>(ignored); foreach (var job in jobs) { state.OnlineJobInfo[(short)job.job_type] = new VMTSOJobInfo() { Experience = (short)job.job_experience, Level = (short)job.job_level, SickDays = (short)job.job_sickdays, StatusFlags = (short)job.job_statusflags }; } if (myRoomieLots.Count == 0) { state.AvatarFlags |= VMTSOAvatarFlags.CanBeRoommate; //we're not roommate anywhere, so we can be here. } var roomieStatus = myRoomieLots.FindAll(x => x.lot_id == Context.DbId).FirstOrDefault(); if (roomieStatus != null && roomieStatus.is_pending == 0) { switch (roomieStatus.permissions_level) { case 0: state.Permissions = VMTSOAvatarPermissions.Roommate; break; case 1: state.Permissions = VMTSOAvatarPermissions.BuildBuyRoommate; break; case 2: state.Permissions = VMTSOAvatarPermissions.Owner; break; } } else { state.Permissions = VMTSOAvatarPermissions.Visitor; } if (avatar.moderation_level > 0) { state.Permissions = VMTSOAvatarPermissions.Admin; } var motives = new short[16]; for (int i = 0; i < 16; i++) { var twoi = i + i; motives[i] = (short)((avatar.motive_data[twoi] << 8) | avatar.motive_data[twoi + 1]); } state.MotiveData = motives; var relDict = new Dictionary <uint, List <int> >(); foreach (var rel in rels) { if (!relDict.ContainsKey(rel.to_id)) { relDict[rel.to_id] = new List <int>(); } var list = relDict[rel.to_id]; while (list.Count <= rel.index) { list.Add(0); } list[(int)rel.index] = rel.value; } state.Relationships = new VMEntityPersistRelationshipMarshal[relDict.Count]; for (int i = 0; i < relDict.Count; i++) { var dictItem = relDict.ElementAt(i); var marshal = new VMEntityPersistRelationshipMarshal(); marshal.Target = dictItem.Key; marshal.Values = dictItem.Value.ConvertAll(x => (short)x).ToArray(); state.Relationships[i] = marshal; } return(state); }
/// <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 { }); }
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)); } }
private Avatar HydrateOne(DbAvatar dbAvatar, DbLot dbLot, List <DbJobLevel> levels, List <DbRelationship> rels, List <DbBookmark> bookmarks) { var result = new Avatar(); result.Avatar_Id = dbAvatar.avatar_id; result.Avatar_Name = dbAvatar.name; result.Avatar_IsOnline = false; result.Avatar_Description = dbAvatar.description; result.Avatar_Appearance = new AvatarAppearance { AvatarAppearance_BodyOutfitID = dbAvatar.body, AvatarAppearance_HeadOutfitID = dbAvatar.head, AvatarAppearance_SkinTone = dbAvatar.skin_tone }; var now = Epoch.Now; result.FetchTime = now; result.Avatar_Age = (uint)((now - dbAvatar.date) / ((long)60 * 60 * 24)); result.Avatar_Skills = new AvatarSkills { AvatarSkills_Body = dbAvatar.skill_body, AvatarSkills_LockLv_Body = dbAvatar.lock_body, AvatarSkills_Charisma = dbAvatar.skill_charisma, AvatarSkills_LockLv_Charisma = dbAvatar.lock_charisma, AvatarSkills_Cooking = dbAvatar.skill_cooking, AvatarSkills_LockLv_Cooking = dbAvatar.lock_cooking, AvatarSkills_Creativity = dbAvatar.skill_creativity, AvatarSkills_LockLv_Creativity = dbAvatar.lock_creativity, AvatarSkills_Logic = dbAvatar.skill_logic, AvatarSkills_LockLv_Logic = dbAvatar.lock_logic, AvatarSkills_Mechanical = dbAvatar.skill_mechanical, AvatarSkills_LockLv_Mechanical = dbAvatar.lock_mechanical }; result.Avatar_PrivacyMode = dbAvatar.privacy_mode; result.Avatar_SkillsLockPoints = (ushort)(20 + result.Avatar_Age / 7); var jobs = new List <JobLevel>(); foreach (var level in levels) { jobs.Add(new JobLevel { JobLevel_JobType = level.job_type, JobLevel_JobExperience = level.job_experience, JobLevel_JobGrade = level.job_level }); } result.Avatar_JobLevelVec = ImmutableList.ToImmutableList(jobs); result.Avatar_CurrentJob = dbAvatar.current_job; result.Avatar_Top100ListFilter = new Top100ListFilter() { Top100ListFilter_ResultsVec = ImmutableList.Create <uint>(), Top100ListFilter_Top100ListID = 0, }; var fvec = new Dictionary <Tuple <uint, bool>, Relationship>(); foreach (var rel in rels) { bool outgoing = false; uint target = 0; if (rel.from_id == dbAvatar.avatar_id) { outgoing = true; target = rel.to_id; } else { target = rel.from_id; } var tuple = new Tuple <uint, bool>(target, outgoing); Relationship relObj = null; if (!fvec.TryGetValue(tuple, out relObj)) { relObj = new Relationship { Relationship_IsOutgoing = outgoing, Relationship_TargetID = target, Relationship_CommentID = rel.comment_id ?? 0 }; fvec.Add(tuple, relObj); } if (rel.index == 0) { relObj.Relationship_STR = (sbyte)rel.value; } else { relObj.Relationship_LTR = (sbyte)rel.value; } } result.Avatar_FriendshipVec = ImmutableList.ToImmutableList(fvec.Values); if (dbLot != null) { result.Avatar_LotGridXY = dbLot.location; } result.Avatar_BookmarksVec = ImmutableList.ToImmutableList(bookmarks.Select(x => { return(new Bookmark { Bookmark_Type = x.type, Bookmark_TargetID = x.target_id }); })); return(result); }