//todo xml // if the given initiative is still being used by any EventScheduling, throws, unless forceCancelEvents is true. // ...if forceCancelEvents is true, all events using this initiative will first be canceled and removed. // also throws if the currently executing one is using this initiative. public bool UnregisterInitiative(Initiative initiative, bool forceCancelEvents = false) { if (initiative == null) { throw new ArgumentNullException(nameof(initiative)); } if (!oc.Contains(initiative)) { return(false); } if (currentlyExecuting?.Initiative == initiative) { throw new InvalidOperationException("Can't unregister an initiative while the currently executing EventScheduling is still using it"); } EventScheduling[] schedulings = scheduledEventsForInitiatives[initiative].ToArray(); if (schedulings.Length > 0) { if (!forceCancelEvents) { throw new InvalidOperationException("Can't unregister an initiative while an EventScheduling is still using it"); } foreach (EventScheduling eventScheduling in schedulings) { InternalEventScheduling es = eventScheduling as InternalEventScheduling; if (!es.IsLive) { continue; } es.Canceled = true; } scheduledEventsForInitiatives.Clear(initiative); } return(oc.Remove(initiative)); }
/// <summary> Creates the InternalEventScheduling, adds it to the list of events for its initiative, adds it to the PQ, and returns it. </summary> private InternalEventScheduling CreateAndSchedule(IEvent scheduledEvent, long ticksInFuture, Initiative init) { var es = new InternalEventScheduling(scheduledEvent, currentTick, ticksInFuture, init); scheduledEventsForInitiatives.Add(init, es); pq.Enqueue(es); return(es); }
private void RemoveSchedulingForInitiative(InternalEventScheduling es) { if (es?.Initiative is InternalInitiative init) { scheduledEventsForInitiatives.Remove(init, es); if (init.AutoRemove && !scheduledEventsForInitiatives.AnyValues(init)) { // Get rid of an AutoRemove Initiative when there are no more scheduled events referencing it scheduledEventsForInitiatives.Clear(init); oc.Remove(init); } } }
private int CompareEventSchedulings(InternalEventScheduling first, InternalEventScheduling second) { int tickCompare = first.ExecutionTick.CompareTo(second.ExecutionTick); if (tickCompare != 0) { return(tickCompare); } else { return(oc.Compare(first.Initiative, second.Initiative)); } }
public void ExecuteNextEvent() { InternalEventScheduling es = pq.Dequeue(); while (es.Canceled) { es = pq.Dequeue(); } currentTick = es.ExecutionTick; currentlyExecuting = es; currentlyExecuting.Event.ExecuteEvent(); currentlyExecuting = null; es.Executed = true; RemoveSchedulingForInitiative(es); }
public static EventScheduler Deserialize(BinaryReader reader, Action <EventScheduling, BinaryReader> onLoadEventScheduling, Action <Initiative, BinaryReader> onLoadInitiative, Func <BinaryReader, IEvent> loadIEvent) { if (loadIEvent == null) { throw new ArgumentNullException(nameof(loadIEvent)); } if (reader == null) { throw new ArgumentNullException(nameof(reader)); } //dict of id -> obj this time... var objectsById = new Dictionary <int, object>(); //read OC count...for each one... int ocCount = reader.ReadInt32(); var inits = new List <Initiative>(); for (int i = 0; i < ocCount; ++i) { int id = reader.ReadInt32(); bool isAuto = reader.ReadBoolean(); Initiative init = new InternalInitiative { AutoRemove = isAuto }; if (!isAuto) { onLoadInitiative?.Invoke(init, reader); } objectsById.Add(id, init); inits.Add(init); } // 'inits' now ready for use // (the OC should now be complete, and all non-auto inits have been associated with their user-assigned IDs again) //read PQ count...for each... int pqCount = reader.ReadInt32(); var events = new List <InternalEventScheduling>(); for (int i = 0; i < pqCount; ++i) { //read the ID... int id = reader.ReadInt32(); //call loadIEvent... IEvent ievent = loadIEvent(reader); //read creation tick, delay, and init ID. long creationTick = reader.ReadInt64(); long delay = reader.ReadInt64(); int initId = reader.ReadInt32(); Initiative init = (objectsById[initId] as Initiative) ?? throw new Exception("Initiative not loaded properly"); var es = new InternalEventScheduling(ievent, creationTick, delay, init); objectsById.Add(id, es); // then call onLoadEventScheduling. onLoadEventScheduling?.Invoke(es, reader); events.Add(es); } // 'events' now ready for use // (the PQ should now be complete) // finally, the MVD: //read a count of groups... int eventsForInitsCount = reader.ReadInt32(); var eventsForInits = new List <IGrouping <Initiative, InternalEventScheduling> >(); for (int i = 0; i < eventsForInitsCount; ++i) { //read an init ID for each group... int initId = reader.ReadInt32(); var init = (objectsById[initId] as Initiative) ?? throw new Exception("Initiative not loaded correctly"); //read a count for each group... int groupCount = reader.ReadInt32(); var esGroup = new List <InternalEventScheduling>(); //read ES ids for (int j = 0; j < groupCount; ++j) { int esId = reader.ReadInt32(); var es = (objectsById[esId] as InternalEventScheduling) ?? throw new Exception("Event scheduling not loaded correctly"); esGroup.Add(es); } eventsForInits.Add(new Grouping <Initiative, InternalEventScheduling>(init, esGroup)); } // 'eventsForInits' now ready for use return(new EventScheduler(inits, events, eventsForInits)); }