private bool VerifyCanBeMayor(IDA da, uint avatar_id, uint nhood_id, uint now, ref string name) { //avatar must exist, their lot must be in the neighbourhood. time since moving is checked when sims try to nominate in the first place var ava = da.Avatars.Get(avatar_id); name = ava.name; if (ava == null) { return(false); } var lotid = da.Roommates.GetAvatarsLots(avatar_id).FirstOrDefault(); if (lotid == null) { return(false); } var lot = da.Lots.Get(lotid.lot_id); if (lot == null || lot.neighborhood_id != nhood_id) { return(false); } var nhoodBan = da.Neighborhoods.GetNhoodBan(ava.user_id); if (nhoodBan != null) { return(false); //neighborhood banned user cannot be mayor. } return(true); }
public void BroadcastNhoodState(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle) { var all = Sessions.Clone(); foreach (var session in all.OfType <IVoltronSession>()) { if (session.IsAnonymous) { continue; } var myLotID = da.Roommates.GetAvatarsLots(session.AvatarId).FirstOrDefault(); var myLot = (myLotID == null) ? null : da.Lots.Get(myLotID.lot_id); var free = da.Elections.GetFreeVote(session.AvatarId); var nhoodID = (int)(myLot?.neighborhood_id ?? 0); if (free != null) { nhoodID = free.neighborhood_id; //enrolled to a free vote. receive vote mail for that neighborhood } if (myLot != null && nhoodID == nhood.neighborhood_id) { SendStateEmail(da, mail, nhood, cycle, session.AvatarId); } } }
private uint RemapAvatarID(IDA da, uint avatarID) { if (avatarID == 0) { return(0); } uint remapped; if (!AvatarIDs.TryGetValue(avatarID, out remapped)) { var ava = da.Avatars.Get(avatarID); if (ava == null) { Console.WriteLine($"(could not find avatar {avatarID}, replacing with owner id {OwnerID})"); AvatarIDs[avatarID] = OwnerID; remapped = OwnerID; } else { AvatarIDs[avatarID] = avatarID; remapped = avatarID; } } return(remapped); }
public void ActivateEvents(IDA da, List <DbEvent> evts) { //ensure events that have not started int[] activeIDs; lock (ActiveEvents) { activeIDs = ActiveEvents.Select(x => x.event_id).ToArray(); } bool changed = false; try { changed = da.Tuning.ClearInactiveTuning(activeIDs); } catch (Exception e) { LOG.Error(e, "Failed to clear inactive tuning!"); } foreach (var evt in evts) { switch (evt.type) { case DbEventType.obj_tuning: try { da.Tuning.ActivatePreset(evt.value, evt.event_id); } catch (Exception e) { LOG.Error(e, $"Failed to activate preset {evt.value}!"); } changed = true; break; } } if (changed) { TuningDomain.BroadcastTuningUpdate(true); } var all = Sessions.Clone(); foreach (var session in all.OfType <IVoltronSession>()) { foreach (var evt in evts) { if (session.IsAnonymous) { continue; } UserJoinedEvent(session, evt, true); } } }
public void SendStateEmail(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle, uint avatarID) { if (!da.Elections.TryRegisterMail(new DbElectionCycleMail() { avatar_id = avatarID, cycle_id = cycle.cycle_id, cycle_state = cycle.current_state })) { return; } var endDate = cycle.end_date; switch (cycle.current_state) { case DbElectionCycleState.nomination: endDate -= 60 * 60 * 24 * 3; //nomination ends 3 days before end of cycle mail.SendSystemEmail("f116", (int)NeighMailStrings.NominateSubject, (int)NeighMailStrings.Nominate, 1, MessageSpecialType.Nominate, endDate, avatarID, nhood.name, endDate.ToString()); break; case DbElectionCycleState.election: mail.SendSystemEmail("f116", (int)NeighMailStrings.VoteSubject, (int)NeighMailStrings.Vote, 1, MessageSpecialType.Vote, endDate, avatarID, nhood.name, endDate.ToString()); break; case DbElectionCycleState.failsafe: mail.SendSystemEmail("f116", (int)NeighMailStrings.FailsafeSubject, (int)NeighMailStrings.Failsafe, 1, MessageSpecialType.Normal, endDate, avatarID, nhood.name); break; case DbElectionCycleState.shutdown: if (Context.Config.Neighborhoods.Election_Free_Vote) { mail.SendSystemEmail("f116", (int)NeighMailStrings.FreeVoteSubject, (int)NeighMailStrings.FreeVote, 1, MessageSpecialType.FreeVote, endDate, avatarID, nhood.name, endDate.ToString()); } break; case DbElectionCycleState.ended: var winner = da.Avatars.Get(nhood.mayor_id ?? 0)?.name; if (winner == null) { return; } mail.SendSystemEmail("f116", (int)NeighMailStrings.ElectionOverSubject, (int)NeighMailStrings.ElectionOver, 1, MessageSpecialType.Normal, endDate, avatarID, winner, nhood.name, "someone else idk"); break; } }
private void RetrieveDbObject(VM vm, IDA db, DbObject obj, uint ownerID, bool setOnLot, VMAsyncInventoryRetrieveCallback callback) { var objectPID = obj.object_id; var result = new VMInventoryRestoreObject(); result.PersistID = obj.object_id; result.GUID = obj.type; result.UpgradeLevel = (byte)obj.upgrade_level; result.Wear = 0; if (setOnLot) //if we should set this object as on this lot. false means we're getting the info for trade { if (!db.Objects.SetInLot(objectPID, (uint)Context.DbId)) { callback(new VMInventoryRestoreObject()); //object is already on a lot. we cannot load it! return; } } else if (obj.lot_id != null) { callback(new VMInventoryRestoreObject()); //object is already on a lot, don't load it for trading. return; } byte[] dat = null; try { var objStr = objectPID.ToString("x8"); var path = Path.Combine(Config.SimNFS, "Objects/" + objStr + "/inventoryState.fsoo"); //if path does not exist, will throw FileNotFoundException using (var file = File.Open(path, FileMode.Open)) { dat = new byte[file.Length]; file.Read(dat, 0, dat.Length); } } catch (Exception e) { //todo: specific types of exception that can be thrown here? instead of just catching em all if (!(e is FileNotFoundException)) { LOG.Error(e, "Failed to load inventory state for object " + objectPID.ToString("x8") + "!"); } } if (dat != null && dat.Length == 0) { dat = null; //treat empty files as if no state were available. } result.Data = dat; callback(result); }
public void SendBulletinPost(IDA da, int nhoodID, string cst, int subjectIndex, int msgIndex, uint expireDate, params string[] args) { for (int i = 0; i < args.Length; i++) { args[i] = args[i].Replace(';', ':'); } var item = new DbBulletinPost() { neighborhood_id = nhoodID, title = ";" + cst + ";" + subjectIndex, body = ";" + expireDate + ";" + cst + ";" + msgIndex + ';' + string.Join(";", args), date = Epoch.Now, flags = 0, type = DbBulletinType.system }; da.BulletinPosts.Create(item); }
public void BroadcastNhoodState(IDA da, MailHandler mail, DbNeighborhood nhood, DbElectionCycle cycle) { var all = Sessions.Clone(); foreach (var session in all.OfType <IVoltronSession>()) { if (session.IsAnonymous) { continue; } var myLotID = da.Roommates.GetAvatarsLots(session.AvatarId).FirstOrDefault(); var myLot = (myLotID == null) ? null : da.Lots.Get(myLotID.lot_id); if (myLot != null && myLot.neighborhood_id == nhood.neighborhood_id) { SendStateEmail(da, mail, nhood, cycle, session.AvatarId); } } }
private void CreateDbObject(IDA da, VMEntityMarshal entity, DbLot lot) { var ownerID = ((VMTSOObjectState)entity.PlatformState).OwnerID; var obj = new DbObject() { budget = (int)((VMTSOEntityState)entity.PlatformState).Budget.Value, type = (entity.MasterGUID == 0) ? entity.GUID : entity.MasterGUID, lot_id = lot.lot_id, owner_id = (ownerID == 0) ? (uint?)null : ownerID, shard_id = lot.shard_id, dyn_obj_name = "", //get from multitile? value = 0 //get from multitile? }; if (!Options.Report) { uint id = da.Objects.Create(obj); PersistRemap[entity.PersistID] = id; entity.PersistID = id; } }
public async Task SetMayor(IDA da, uint avatarID, uint nhoodID) { //what we need to do: // set the mayor in the database // set the mayor in the data service // if there is a town hall, set us as its owner // if it's open, inform it of the owner change // if it isn't, open the lot to vacate the old mayor's objects // send an award email to the winner // (optionally) send emails to the voters telling them the result var mail = Kernel.Get <MailHandler>(); var ds = Kernel.Get <IDataService>(); var nhood = await ds.Get <Neighborhood>(nhoodID); if (nhood == null) { return; } var oldMayorID = nhood.Neighborhood_MayorID; var oldMayor = (oldMayorID != 0) ? da.Avatars.Get(oldMayorID) : null; nhood.Neighborhood_MayorID = avatarID; nhood.Neighborhood_ElectedDate = Epoch.Now; uint?nAvatarID = (avatarID == 0) ? null : (uint?)avatarID; da.Neighborhoods.UpdateMayor(nhoodID, nAvatarID); if (avatarID != 0) { da.Avatars.UpdateMayorNhood(avatarID, nhoodID); } var dbNhood = da.Neighborhoods.Get(nhoodID); if (dbNhood == null) { return; } if (dbNhood.town_hall_id != null) { var lot = da.Lots.Get(dbNhood.town_hall_id.Value); if (lot != null) { var lots = Kernel.Get <LotAllocations>(); var lotServers = Kernel.Get <LotServerPicker>(); da.Lots.UpdateOwner(lot.lot_id, nAvatarID); //this invalidation handles a few things... any changes to the roommates vector, and the possibility of the lot being deleted //(when owner id is null, the lot disappears from the city until it is deleted) ds.Invalidate <FSO.Common.DataService.Model.Lot>(lot.location); //if online, notify the lot var lotOwned = da.LotClaims.GetByLotID(lot.lot_id); if (lotOwned != null) { var lotServer = lotServers.GetLotServerSession(lotOwned.owner); if (lotServer != null) { //immediately notify lot of new roommate lotServer.Write(new NotifyLotRoommateChange() { AvatarId = avatarID, LotId = lot.lot_id, Change = Protocol.Gluon.Model.ChangeType.BECOME_OWNER }); } } else { //try force the lot open var result = await lots.TryFindOrOpen(lot.location, 0, NullSecurityContext.INSTANCE); } } } if (oldMayor != null) { da.Avatars.UpdateMayorNhood(oldMayor.avatar_id, null); if (avatarID != 0) { var replaced = da.Avatars.Get(avatarID); if (replaced != null) { mail.SendSystemEmail("f116", (int)NeighMailStrings.NoLongerMayorSubject, (int)NeighMailStrings.NoLongerMayor, 1, MessageSpecialType.Normal, 0, oldMayorID, replaced.name, dbNhood.name); } } else { //replaced with nobody. This happens at the end of an election cycle where this neighborhood is no longer eligible. mail.SendSystemEmail("f116", (int)NeighMailStrings.NoLongerMayorModSubject, (int)NeighMailStrings.NoLongerMayorMod, 1, MessageSpecialType.Normal, 0, oldMayorID, dbNhood.name); } } }
public async Task ChangeElectionState(IDA da, DbNeighborhood nhood, DbElectionCycle cycle, DbElectionCycleState state) { var now = Epoch.Now; var mail = Kernel.Get <MailHandler>(); switch (state) { case DbElectionCycleState.nomination: //start nominations for this cycle. var endDate = cycle.end_date - 60 * 60 * 24 * 3; //nomination ends 3 days before end of cycle SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.NominateSubject, (int)NeighBulletinStrings.Nominate, endDate, nhood.name, endDate.ToString()); break; case DbElectionCycleState.election: //end nominations. choose the candidate sims. var cycleNoms = da.Elections.GetCycleVotes(cycle.cycle_id, DbElectionVoteType.nomination); var toRemove = da.Elections.GetCandidates(cycle.cycle_id).ToDictionary(x => x.candidate_avatar_id); if (cycleNoms.Count > 0) { var grouped = cycleNoms.GroupBy(x => x.target_avatar_id).OrderByDescending(x => x.Count()); var selected = 0; var candidates = new List <IGrouping <uint, DbElectionVote> >(); foreach (var winner in grouped) { //verify the winners are still alive and still in this neighborhood string name = null; DbElectionCandidate cand; if (toRemove.TryGetValue(winner.Key, out cand) && VerifyCanBeMayor(da, winner.Key, (uint)nhood.neighborhood_id, now, ref name)) { if (cand.state != DbCandidateState.running) { continue; //user must have accepted their nomination } toRemove.Remove(winner.Key); mail.SendSystemEmail("f116", (int)NeighMailStrings.RunningForMayorSubject, (int)NeighMailStrings.RunningForMayor, 1, MessageSpecialType.Normal, cycle.end_date, winner.Key, nhood.name, cand.comment, cycle.end_date.ToString()); candidates.Add(winner); if (++selected >= 5) { break; } } } foreach (var remove in toRemove) { da.Elections.DeleteCandidate(remove.Value.election_cycle_id, remove.Value.candidate_avatar_id); if (remove.Value.state == DbCandidateState.running) { mail.SendSystemEmail("f116", (int)NeighMailStrings.TooFewNominationsSubject, (int)NeighMailStrings.TooFewNominations, 1, MessageSpecialType.Normal, cycle.end_date, remove.Key, nhood.name, cycle.end_date.ToString()); } else { mail.SendSystemEmail("f116", (int)NeighMailStrings.NominationNotAcceptedSubject, (int)NeighMailStrings.NominationNotAccepted, 1, MessageSpecialType.Normal, cycle.end_date, remove.Key, nhood.name, cycle.end_date.ToString()); } } if (selected == 0) { state = DbElectionCycleState.failsafe; break; } //email will be sent by event system. make a bulletin post too SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.VoteSubject, (int)NeighBulletinStrings.Vote, cycle.end_date, nhood.name, string.Join("\n", candidates.Select(x => "- " + (da.Avatars.Get(x.Key)?.name ?? "(unknown)"))), cycle.end_date.ToString()); } else { state = DbElectionCycleState.failsafe; } break; case DbElectionCycleState.ended: //end election. if there are any candidates, set the mayor to the one that recieved the most votes. var cycleVotes = da.Elections.GetCycleVotes(cycle.cycle_id, DbElectionVoteType.vote); if (cycleVotes.Count > 0) { var grouped = cycleVotes.GroupBy(x => x.target_avatar_id).OrderByDescending(x => x.Count()).ToList(); //verify the winner is still alive and still in this neighborhood string name = ""; while (grouped.Count > 0 && !VerifyCanBeMayor(da, grouped[0].Key, (uint)nhood.neighborhood_id, now, ref name)) { grouped.RemoveAt(0); } if (grouped.Count == 0) { state = DbElectionCycleState.failsafe; if (nhood.mayor_id != null) { await SetMayor(da, 0, (uint)nhood.neighborhood_id); } break; } var winner = grouped[0]; //we have a winner da.Elections.SetCandidateState(new DbElectionCandidate() { election_cycle_id = cycle.cycle_id, candidate_avatar_id = winner.Key, state = DbCandidateState.won }); await SetMayor(da, winner.Key, (uint)nhood.neighborhood_id); mail.SendSystemEmail("f116", (int)NeighMailStrings.YouWinSubject, (int)NeighMailStrings.YouWin, 1, MessageSpecialType.Normal, 0, winner.Key, nhood.name, winner.Count().ToString()); //tell the losers they lost grouped.RemoveAt(0); var placement = 2; foreach (var loser in grouped) { da.Elections.SetCandidateState(new DbElectionCandidate() { election_cycle_id = cycle.cycle_id, candidate_avatar_id = loser.Key, state = DbCandidateState.lost }); placement++; } int runnerI = 2; SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.ElectionOverSubject, (int)NeighBulletinStrings.ElectionOver, cycle.end_date, (da.Avatars.Get(winner.Key)?.name ?? "(unknown)"), nhood.name, string.Join("\n", grouped.Select(x => (runnerI++).ToString() + ". " + (da.Avatars.Get(x.Key)?.name ?? "(unknown)")))); } else { state = DbElectionCycleState.failsafe; if (nhood.mayor_id != null) { await SetMayor(da, 0, (uint)nhood.neighborhood_id); } } break; } da.Elections.UpdateCycleState(cycle.cycle_id, state); if (state == DbElectionCycleState.failsafe && state != cycle.current_state) { SendBulletinPost(da, nhood.neighborhood_id, "f123", (int)NeighBulletinStrings.FailsafeSubject, (int)NeighBulletinStrings.Failsafe, 0, nhood.name); } cycle.current_state = state; if (StateHasEmail(state)) { BroadcastNhoodState(da, mail, nhood, cycle); } }