/// <summary>Perform removal of the specified thing from our Children.</summary> /// <param name="thingToRemove">The thing to remove from our Children.</param> /// <param name="removalEvent">The removal event to work with; must have previously been sent as the request.</param> /// <param name="multipleParentsBehavior">The multipleParentsBehavior, if applicable.</param> /// <returns>True if the thing has been successfully removed, else false.</returns> private bool PerformRemoval(Thing thingToRemove, RemoveChildEvent removalEvent, MultipleParentsBehavior multipleParentsBehavior) { if (removalEvent.IsCancelled) { return(false); } // Send the removal event. this.Eventing.OnMovementEvent(removalEvent, EventScope.SelfDown); // If the thing to remove was in our Children collection, remove it. if (this.Children.Contains(thingToRemove)) { this.Children.Remove(thingToRemove); } // If we don't have a MultipleParentsBehavior, directly remove the one-allowed // parent ourselves, else use the behavior's logic for adjusting the parents. if (multipleParentsBehavior == null) { thingToRemove.Parent = null; } else { multipleParentsBehavior.RemoveParent(this); } return(true); }
private RemoveChildEvent RequestRemoval(Thing thingToRemove) { // Create and raise a removal event request. var removeChildEvent = new RemoveChildEvent(thingToRemove); this.Eventing.OnMovementRequest(removeChildEvent, EventScope.SelfDown); return(removeChildEvent); }
// TODO: All things (world, room, item, mob, etc), should all potentially have sub-things // but it should be up to the code which moves things about to do so intelligently // (IE should not allow adding an Area inside a Room, etc.) These can be prevented // either explicitly here, or preferably via event request cancellation. public bool Add(Thing thing) { // No two threads may add/remove any combination of the parent/sub-thing at the same time, // in order to prevent race conditions resulting in thing-disconnection/duplication/etc. // TODO: May need to pick a consistent order to apply the locks (like locking the lowest // alphabetical thing ID's lock first) to prevent possible deadlocks. // TODO: The whole MultipleParentsBehavior may be too complicated for our actual use cases, // and we should consider a lighter approach that doesn't track multiple parents, but // simply lets the thing be a child of multiple locations. lock (lockObject) { lock (thing.lockObject) { // If the thing already has a parent, ensure we have permission to continue. // Presence of MultipleParentsBehavior means we can always add more parents, but // if it's not present, we have to see if removal would be accepted first. var multipleParentsBehavior = thing.Behaviors.FindFirst <MultipleParentsBehavior>(); RemoveChildEvent removalRequest = null; var oldParent = thing.Parent; if (oldParent != null && multipleParentsBehavior == null) { removalRequest = oldParent.RequestRemoval(thing); if (removalRequest.IsCancelled) { return(false); } } var addRequest = RequestAdd(thing); if (addRequest.IsCancelled) { return(false); } // If we got this far, both removal (if needed) and add requests were accepted, so // perform both now and send the confirmation events for any listeners. Removal is // first, since we don't want to risk accidentally removing from the new parent, etc. if (removalRequest != null) { oldParent.PerformRemoval(thing, removalRequest, multipleParentsBehavior); } PerformAdd(thing, addRequest, multipleParentsBehavior); } return(true); } }
// @@@ All things (world, room, item, mob, etc), should all potentially have sub-things // but it should be up to the code which moves things about to do so intelligently // (IE should not allow adding an Area inside a Room, etc.) These can be prevented // either explicitly here, or preferably via event request cancellation. public bool Add(Thing thing) { // No two threads may add/remove any combination of the parent/sub-thing at the same time, // in order to prevent race conditions resulting in thing-disconnection/duplication/etc. lock (this.lockObject) { lock (thing.lockObject) { // If the thing already has a parent, ensure we have permission to continue. // Presence of MultipleParentsBehavior means we can always add more parents, but // if it's not present, we have to see if removal would be accepted first. var multipleParentsBehavior = thing.Behaviors.FindFirst <MultipleParentsBehavior>(); RemoveChildEvent removalRequest = null; var oldParent = thing.Parent; if (oldParent != null && multipleParentsBehavior == null) { removalRequest = oldParent.RequestRemoval(thing); if (removalRequest.IsCancelled) { return(false); } } var addRequest = this.RequestAdd(thing); if (addRequest.IsCancelled) { return(false); } // If we got this far, both removal (if needed) and add requests were accepted, so // perform both now and send the confirmation events for any listeners. Removal is // first, since we don't want to risk accidentally removing from the new parent, etc. if (removalRequest != null) { oldParent.PerformRemoval(thing, removalRequest, multipleParentsBehavior); } this.PerformAdd(thing, addRequest, multipleParentsBehavior); } return(true); } }