如何在Rage MP C#服务器中实现带权限校验的事件回调处理
Rage MP C#服务器实现带权限校验的客户端事件
1. 定义自定义Authorized属性
先创建标记用的属性类,用于标记需要权限校验的事件方法:
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] public sealed class AuthorizedAttribute : Attribute { // 可扩展添加权限等级参数,比如: // public string RequiredRole { get; set; } = "Admin"; }
2. 实现全局事件中转处理器
因为NAPI.ClientEvent.Register仅支持传入MethodInfo,我们需要一个统一的处理方法,负责权限校验和目标方法调用:
public static class EventAuthorizationHandler { private static readonly Dictionary<string, (MethodInfo TargetMethod, bool RequiresAuth, object ScriptInstance)> _eventMappings = new(); // 初始化:扫描所有脚本类中的标记方法并完成注册 public static void Initialize() { // 扫描所有继承自RageScript的类 var scriptTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(asm => asm.GetTypes()) .Where(t => typeof(RageScript).IsAssignableFrom(t) && !t.IsAbstract); foreach (var type in scriptTypes) { // 实例化脚本(符合Rage MP的脚本加载规则) var scriptInstance = Activator.CreateInstance(type); // 筛选带[EventHandler]标记的公开实例方法 var eventMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(m => m.GetCustomAttribute<EventHandlerAttribute>() != null); foreach (var method in eventMethods) { var eventAttr = method.GetCustomAttribute<EventHandlerAttribute>(); var eventName = eventAttr.Name; var requiresAuth = method.GetCustomAttribute<AuthorizedAttribute>() != null; // 注册事件到NAPI,指向统一处理方法 NAPI.ClientEvent.Register(eventName, typeof(EventAuthorizationHandler).GetMethod(nameof(HandleClientEvent))); // 保存事件与目标方法、权限要求、脚本实例的映射 _eventMappings[eventName] = (method, requiresAuth, scriptInstance); } } } // NAPI会调用此方法处理所有注册的客户端事件 public static void HandleClientEvent(Player player, params object[] args) { var eventName = NAPI.CallContext.CurrentEventName; if (!_eventMappings.TryGetValue(eventName, out var mapping)) return; // 权限校验逻辑 if (mapping.RequiresAuth && !IsPlayerAuthorized(player)) { NAPI.Chat.SendChatMessageToPlayer(player, "~r~你没有权限执行该操作!"); return; } // 调用目标事件方法 try { // 拼接参数:第一个参数是Player,后面是客户端传递的参数 var methodParams = new object[] { player }.Concat(args).ToArray(); mapping.TargetMethod.Invoke(mapping.ScriptInstance, methodParams); } catch (Exception ex) { Console.WriteLine($"执行事件{eventName}时出错: {ex.Message}"); } } // 自定义权限校验逻辑,根据业务需求实现 private static bool IsPlayerAuthorized(Player player) { // 示例:检查玩家是否携带管理员标记 return player.HasData("IsAdmin") && (bool)player.GetData("IsAdmin"); } }
3. 启动时初始化处理器
在服务器启动脚本中调用初始化方法,确保所有事件被正确注册:
public class ServerStartup : RageScript { public override void Start() { EventAuthorizationHandler.Initialize(); Console.WriteLine("权限校验事件处理器已完成初始化"); } }
4. 权限标记使用示例
按照你期望的方式标记事件方法即可:
namespace SomeScripts2 { class AdminEvents : RageScript { [EventHandler("create_vehicle")] [Authorized] // 未授权玩家触发此事件会被拦截 public void OnCreateVehicle(Player player, string nameVehicle) { // 车辆创建逻辑示例 var vehicleHash = NAPI.Util.GetHashKey(nameVehicle); var vehicle = NAPI.Vehicle.CreateVehicle(vehicleHash, player.Position, player.Heading, 0, 0); NAPI.Chat.SendChatMessageToPlayer(player, $"~g~已成功创建车辆: {nameVehicle}"); } } }
注意事项
- 脚本实例缓存:初始化时已缓存每个脚本的实例,避免每次调用方法时重复创建,符合Rage MP的脚本生命周期规则。
- 权限扩展:可在
AuthorizedAttribute中添加RequiredRole等参数,在IsPlayerAuthorized中实现更细粒度的角色校验。 - 异常处理:可根据需求扩展日志记录逻辑,便于排查事件调用错误。
内容的提问来源于stack exchange,提问作者Locker
相关产品推荐
相关产品推荐

