165 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using FishNet.CodeGenerating.Helping;
 | |
| using FishNet.CodeGenerating.Helping.Extension;
 | |
| using FishNet.CodeGenerating.Processing.Rpc;
 | |
| using FishNet.Configuring;
 | |
| using FishNet.Managing.Logging;
 | |
| using MonoFN.Cecil;
 | |
| using MonoFN.Cecil.Cil;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| 
 | |
| namespace FishNet.CodeGenerating.Processing
 | |
| {
 | |
|     internal class QolAttributeProcessor : CodegenBase
 | |
|     {
 | |
| 
 | |
|         internal bool Process(TypeDefinition typeDef, bool moveStrippedCalls)
 | |
|         {
 | |
|             bool modified = false;
 | |
|             List<MethodDefinition> methods = typeDef.Methods.ToList();
 | |
| 
 | |
|             
 | |
| 
 | |
|             foreach (MethodDefinition md in methods)
 | |
|             {
 | |
|                 //Has RPC attribute, doesn't quality for a quality of life attribute.
 | |
|                 if (base.GetClass<RpcProcessor>().Attributes.HasRpcAttributes(md))
 | |
|                     continue;
 | |
| 
 | |
|                 QolAttributeType qolType;
 | |
|                 CustomAttribute qolAttribute = GetQOLAttribute(md, out qolType);
 | |
|                 if (qolAttribute == null)
 | |
|                     continue;
 | |
| 
 | |
|                 /* This is a one time check to make sure the qolType is
 | |
|                  * a supported value. Multiple methods beyond this rely on the
 | |
|                  * value being supported. Rather than check in each method a
 | |
|                  * single check is performed here. */
 | |
|                 if (qolType != QolAttributeType.Server && qolType != QolAttributeType.Client)
 | |
|                 {
 | |
|                     base.LogError($"QolAttributeType of {qolType.ToString()} is unhandled.");
 | |
|                     continue;
 | |
|                 }
 | |
| 
 | |
|                 CreateAttributeMethod(md, qolAttribute, qolType);
 | |
|                 modified = true;
 | |
|             }
 | |
| 
 | |
|             return modified;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Returns the RPC attribute on a method, if one exist. Otherwise returns null.
 | |
|         /// </summary>
 | |
|         /// <param name="methodDef"></param>
 | |
|         /// <param name="rpcType"></param>
 | |
|         /// <returns></returns>
 | |
|         private CustomAttribute GetQOLAttribute(MethodDefinition methodDef, out QolAttributeType qolType)
 | |
|         {
 | |
|             CustomAttribute foundAttribute = null;
 | |
|             qolType = QolAttributeType.None;
 | |
|             //Becomes true if an error occurred during this process.
 | |
|             bool error = false;
 | |
|             //Nothing to check.
 | |
|             if (methodDef == null || methodDef.CustomAttributes == null)
 | |
|                 return null;
 | |
| 
 | |
|             foreach (CustomAttribute customAttribute in methodDef.CustomAttributes)
 | |
|             {
 | |
|                 QolAttributeType thisQolType = base.GetClass<AttributeHelper>().GetQolAttributeType(customAttribute.AttributeType.FullName);
 | |
|                 if (thisQolType != QolAttributeType.None)
 | |
|                 {
 | |
|                     //A qol attribute already exist.
 | |
|                     if (foundAttribute != null)
 | |
|                     {
 | |
|                         base.LogError($"{methodDef.Name} {thisQolType.ToString()} method cannot have multiple quality of life attributes.");
 | |
|                         error = true;
 | |
|                     }
 | |
|                     ////Static method.
 | |
|                     //if (methodDef.IsStatic)
 | |
|                     //{
 | |
|                     //    CodegenSession.AddError($"{methodDef.Name} {thisQolType.ToString()} method cannot be static.");
 | |
|                     //    error = true;
 | |
|                     //}
 | |
|                     //Abstract method.
 | |
|                     if (methodDef.IsAbstract)
 | |
|                     {
 | |
|                         base.LogError($"{methodDef.Name} {thisQolType.ToString()} method cannot be abstract.");
 | |
|                         error = true;
 | |
|                     }
 | |
| 
 | |
|                     //If all checks passed.
 | |
|                     if (!error)
 | |
|                     {
 | |
|                         foundAttribute = customAttribute;
 | |
|                         qolType = thisQolType;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             //If an error occurred then reset results.
 | |
|             if (error)
 | |
|             {
 | |
|                 foundAttribute = null;
 | |
|                 qolType = QolAttributeType.None;
 | |
|             }
 | |
| 
 | |
|             return foundAttribute;
 | |
|         }
 | |
| 
 | |
|         /// <summary>
 | |
|         /// Modifies the specified method to use QolType.
 | |
|         /// </summary>
 | |
|         private void CreateAttributeMethod(MethodDefinition methodDef, CustomAttribute qolAttribute, QolAttributeType qolType)
 | |
|         {
 | |
|             bool inheritsNetworkBehaviour = methodDef.DeclaringType.InheritsNetworkBehaviour(base.Session);
 | |
| 
 | |
|             //True to use InstanceFInder.
 | |
|             bool useStatic = (methodDef.IsStatic || !inheritsNetworkBehaviour);
 | |
| 
 | |
|             if (qolType == QolAttributeType.Client)
 | |
|             {
 | |
|                 if (!StripMethod(methodDef))
 | |
|                 {
 | |
|                     LoggingType logging = qolAttribute.GetField("Logging", LoggingType.Warning);
 | |
|                     /* Since isClient also uses insert first
 | |
|                      * it will be put ahead of the IsOwner check, since the
 | |
|                      * codegen processes it after IsOwner. EG... 
 | |
|                      * IsOwner will be added first, then IsClient will be added first over IsOwner. */
 | |
|                     bool requireOwnership = qolAttribute.GetField("RequireOwnership", false);
 | |
|                     if (requireOwnership && useStatic)
 | |
|                     {
 | |
|                         base.LogError($"Method {methodDef.Name} has a [Client] attribute which requires ownership but the method may not use this attribute. Either the method is static, or the script does not inherit from NetworkBehaviour.");
 | |
|                         return;
 | |
|                     }
 | |
|                     //If (!base.IsOwner);
 | |
|                     if (requireOwnership)
 | |
|                         base.GetClass<NetworkBehaviourHelper>().CreateLocalClientIsOwnerCheck(methodDef, logging, true, false, true);
 | |
|                     //Otherwise normal IsClient check.
 | |
|                     else
 | |
|                         base.GetClass<NetworkBehaviourHelper>().CreateIsClientCheck(methodDef, logging, useStatic, true);
 | |
|                 }
 | |
|             }
 | |
|             else if (qolType == QolAttributeType.Server)
 | |
|             {
 | |
|                 if (!StripMethod(methodDef))
 | |
|                 {
 | |
|                     LoggingType logging = qolAttribute.GetField("Logging", LoggingType.Warning);
 | |
|                     base.GetClass<NetworkBehaviourHelper>().CreateIsServerCheck(methodDef, logging, useStatic, true);
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             bool StripMethod(MethodDefinition md)
 | |
|             {
 | |
|                 
 | |
| 
 | |
|                 //Fall through.
 | |
|                 return false;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         
 | |
|     }
 | |
| 
 | |
| }
 |