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;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|