/// <summary> /// Removes an element from the music stack. If this was the top element, this will trigger a transition to the next element. /// </summary> public void RemoveFromMusicStack(PrioritySortingKey key) { Asserts.AssertTrue(musicStack.ContainsKey(key), "This key is not in the music stack!"); var keyMusic = musicStack[key]; bool wasPlayingKeyMusic = keyMusic == currentMusic; musicStack.Remove(key); if (wasPlayingKeyMusic) { TransitionToMusic(keyMusic, currentMusic, keyMusic.GetReleaseControlTransition()); } }
/// <summary> /// Adds an elment to the music stack. If this becomes the top element, it will transition to these music settings. /// </summary> public PrioritySortingKey AddToMusicStack(IMusicStackElement addedMusic) { var prevMusic = currentMusic; var newKey = new PrioritySortingKey((int)addedMusic.GetPriority()); musicStack.Add(newKey, addedMusic); if (currentMusic != prevMusic) { Asserts.AssertTrue(addedMusic == currentMusic, "Somehow we added to the music stack and yet a different music rose to the top?"); TransitionToMusic(prevMusic, currentMusic, currentMusic.GetTakeControlTransition()); } return(newKey); }
private FieldReference FixFieldReference(FieldReference yourFieldRef) { if (yourFieldRef == null) { Log_called_to_fix_null("field"); return(null); } Log_fixing_reference("field", yourFieldRef); Asserts.AssertTrue(yourFieldRef.DeclaringType != null); var yourFieldDef = yourFieldRef.Resolve(); if (yourFieldDef.IsDisablePatching()) { Log_trying_to_fix_disabled_reference("field", yourFieldRef); } var targetType = FixTypeReference(yourFieldRef.DeclaringType); var targetBaseFieldDef = yourFieldRef; if (yourFieldDef.Module.Assembly.IsPatchingAssembly()) { //additional checking var targetFieldDef = targetType.Resolve().GetField(yourFieldDef.Name); if (targetFieldDef == null) { throw Errors.Could_not_resolve_reference("field", yourFieldRef); } targetBaseFieldDef = targetFieldDef; } else { //we assume that types that aren't in a patching assembly will never reference types in a patching assembly targetBaseFieldDef = yourFieldRef; } var newMethodRef = targetBaseFieldDef.MakeReference(); newMethodRef.DeclaringType = targetType; newMethodRef.FieldType = FixTypeReference(newMethodRef.FieldType); var targetFieldRef = TargetAssembly.MainModule.Import(newMethodRef); Log_fixed_reference("field", yourFieldRef, targetFieldRef); targetFieldRef.Module.Assembly.AssertEqual(TargetAssembly); return(targetFieldRef); }
/// <summary> /// Fixes the method reference. /// </summary> /// <param name="yourMethodRef">The method reference.</param> /// <param name="isFixTypeCalling">This parameter is sort of a hack that lets FixType call FixMethod to fix MVars, without infinite recursion. If set to false, it avoids fixing some types.</param> /// <returns></returns> /// <exception cref="Exception">Method isn't part of a patching type in this assembly...</exception> private MethodReference FixMethodReference(MethodReference yourMethodRef, bool isFixTypeCalling = true) { //Fixes reference like YourAssembly::PatchingClass::Method to TargetAssembly::PatchedClass::Method if (yourMethodRef == null) { Log_called_to_fix_null("method"); return(null); } Log_fixing_reference("method", yourMethodRef); Asserts.AssertTrue(yourMethodRef.DeclaringType != null); var yourMethodDef = yourMethodRef.Resolve(); if (yourMethodDef.IsDisablePatching()) { Log_trying_to_fix_disabled_reference("method", yourMethodDef); } /* * In comparison to types, method references to methods are pretty simple. There are only two kinds: * 1. A regular method reference * 2. A reference to an instantiated generic method, e.g. Create<int> * * 3. As a special case, any method reference (assume non-generic) that has a generic DeclaringType. */ int hadGenericParams = yourMethodRef.GenericParameters.Count; MethodReference targetMethodRef; var memberAlias = yourMethodDef.GetCustomAttribute <MemberAliasAttribute>(); if (yourMethodRef.IsGenericInstance) { var yourGeneric = (GenericInstanceMethod)yourMethodRef; var targetBaseMethod = FixMethodReference(yourGeneric.ElementMethod); var targetGenericInstMethod = new GenericInstanceMethod(targetBaseMethod); foreach (var arg in yourGeneric.GenericArguments) { var targetGenericArg = FixTypeReference(arg); targetGenericInstMethod.GenericArguments.Add(targetGenericArg); } targetMethodRef = targetGenericInstMethod; } else { TypeReference typeToFix = yourMethodRef.DeclaringType; if (memberAlias != null && memberAlias.AliasedMemberDeclaringType != null) { typeToFix = (TypeReference)memberAlias.AliasedMemberDeclaringType; } var targetType = FixTypeReference(typeToFix); var targetBaseMethodDef = yourMethodRef; if (yourMethodDef.Module.Assembly.IsPatchingAssembly()) { //additional checking var methodName = memberAlias == null || memberAlias.AliasedMemberName == null ? yourMethodRef.Name : memberAlias.AliasedMemberName; var targetMethodDef = targetType.Resolve().GetMethods(methodName, yourMethodRef.Parameters.Select(x => x.ParameterType)).SingleOrDefault (); var debugOverloads = targetType.Resolve().Methods.Where(x => x.Name == yourMethodRef.Name).ToArray(); if (targetMethodDef == null) { throw Errors.Could_not_resolve_reference("method", yourMethodRef); } targetBaseMethodDef = targetMethodDef; } else { targetBaseMethodDef = yourMethodRef; } var newMethodRef = targetBaseMethodDef.MakeReference(); newMethodRef.DeclaringType = targetType; targetMethodRef = newMethodRef; } if (isFixTypeCalling) { targetMethodRef = ManualImportMethod(targetMethodRef); } targetMethodRef = TargetAssembly.MainModule.Import(targetMethodRef); //for good measure... targetMethodRef.Module.Assembly.AssertEqual(TargetAssembly); Log_fixed_reference("method", yourMethodRef, targetMethodRef); return(targetMethodRef); }
/// <summary> /// Fixes the method reference. /// </summary> /// <param name="yourMethodRef">The method reference.</param> /// <param name="isntFixTypeCall">This parameter is sort of a hack that lets FixType call FixMethod to fix MVars, without infinite recursion. If set to false, it avoids fixing some types.</param> /// <returns></returns> /// <exception cref="Exception">Method isn't part of a patching type in this assembly...</exception> private MethodReference FixMethodReference(MethodReference yourMethodRef, bool isntFixTypeCall = true) { //Fixes reference like YourAssembly::PatchingClass::Method to TargetAssembly::PatchedClass::Method if (yourMethodRef == null) { Log_called_to_fix_null("method"); return(null); } Log_fixing_reference("method", yourMethodRef); Asserts.AssertTrue(yourMethodRef.DeclaringType != null); var yourMethodDef = yourMethodRef.Resolve(); if (yourMethodDef.IsDisablePatching()) { Log_trying_to_fix_disabled_reference("method", yourMethodDef); } /* * In comparison to types, method references to methods are pretty simple. There are only two kinds: * 1. A regular method reference * 2. A reference to an instantiated generic method, e.g. Create<int> * * 3. As a special case, any method reference (assume non-generic) that has a generic DeclaringType. */ MethodReference targetMethodRef; if (yourMethodRef.IsGenericInstance) { var yourGeneric = (GenericInstanceMethod)yourMethodRef; var targetBaseMethod = FixMethodReference(yourGeneric.ElementMethod); var targetGenericInstMethod = new GenericInstanceMethod(targetBaseMethod); foreach (var arg in yourGeneric.GenericArguments) { var targetGenericArg = FixTypeReference(arg); targetGenericInstMethod.GenericArguments.Add(targetGenericArg); } targetMethodRef = targetGenericInstMethod; } else { TypeReference typeToFix = yourMethodRef.DeclaringType; var action = CurrentMemberCache.Methods.TryGet(yourMethodDef); var memberAlias = action?.ActionAttribute as MemberAliasAttribute; if (memberAlias?.AliasedMemberDeclaringType != null) { typeToFix = (TypeReference)memberAlias.AliasedMemberDeclaringType; } var targetType = FixTypeReference(typeToFix); var targetBaseMethodDef = yourMethodRef; if (yourMethodDef.Module.Assembly.IsPatchingAssembly()) { var targetMethodDef = action?.TargetMember; if (targetMethodDef == null) { throw Errors.Could_not_resolve_reference("method", yourMethodRef); } targetBaseMethodDef = targetMethodDef; } else { targetBaseMethodDef = yourMethodRef; } var newMethodRef = targetBaseMethodDef.CloneReference(); newMethodRef.DeclaringType = targetType; targetMethodRef = newMethodRef; if (isntFixTypeCall) { targetMethodRef = ManualImportMethod(targetMethodRef); } } targetMethodRef.Module.Assembly.AssertEqual(TargetAssembly); Log_fixed_reference("method", yourMethodRef, targetMethodRef); return(targetMethodRef); }