1. Hello, how to get result from .Call function what used for PluginReference in csharp?

    Code:
            [PluginReference]
            private static Plugin Test;            var test = Test.Call("GetInfo",player);
                Puts(test.ToString());
    I'm getting
    Code:
    [Oxide] 11:25 PM [Error] Failed to call hook 'OnPlayerChat' on plugin 'Test Core' (ArgumentException: failed to convert parameters)
    [Oxide] 11:25 PM [Debug]  at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0
      at System.Reflection.MethodBase.Invoke (System.Object obj, System.Object[] parameters) [0x00000] in <filename unknown>:0
      at Oxide.Core.Plugins.CSPlugin.OnCallHook (System.String name, System.Object[] args) [0x00000] in <filename unknown>:0
      at Oxide.Core.Plugins.Plugin.CallHook (System.String hookname, System.Object[] args) [0x00000] in <filename unknown>:0
    So what i'm doing wrong? It should return bool but i cannot get result...
     
  2. Your problem isn't with the test call it is with your plugin Test Core having a problem with its OnPlayerChat hook and from the looks of it you have a bad method signature.
     
  3. Test Core is using code what i quoted and actually tries to get result in OnPlayerChat hook, so problem with code what i wrote. Other plugin called just "Test" and i'm using reference from it.
     
  4. Try it:
    Code:
    var test = Test.Call("GetInfo", new object[] { player });
     
  5. What does the GetInfo method look like in Test.cs?
     
  6. Same result.

    For now it just bool what always return true, just want actually get this "true", but in future there will be another data. In Test plugin itself this function works fine and always return true like should.
     
  7. Does GetInfo take a BasePlayer argument? Might help if you'd actually post that method even if it's just returning true as a test
     
  8. Ah, sorry, yes it take player argument and trying get steamid by player.userID.ToString();
    Code:
            public bool GetInfo(BasePlayer ply) {
                if (ply==null) return false;
                var sid = ply.userID.ToString();
                return true;
            }
    just forgot that i use ply in this function (need for future thing).
     
  9. Okay so the call should to GetInfo should actually work like you're doing it but are you sure that you have gotten the BasePlayer from
    ConsoleSystem.Arg because the error you are receiving is an ArgumentException. Can't really tell from the code you gave us if you have a valid player argument for the Call.
     
  10. Hm, you was right about ConsoleSystem.Arg, i have wrong paramether in OnPlayerChat (just forgot about this), but i still can't understand how to use result from Call function.

    Code:
                var test = TestExt.Call("GetInfo",arg.Player());
                Puts(test.ToString());
    With this code i'm getting:
    Code:
    [Oxide] 11:42 PM [Error] Failed to call hook 'OnPlayerChat' on plugin 'Test Ext' (NullReferenceException: Object reference not set to an instance of an object)
    [Oxide] 11:42 PM [Debug]   at Oxide.Plugins.TestExt.OnPlayerChat (.Arg arg) [0x00000] in <filename unknown>:0
      at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&)
      at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
    Whats wrong? Inside https://github.com/OxideMod/Oxide/blob/master/Oxide.Ext.CSharp/CSharpPlugin.cs i found this:

    Code:
                public object Call(string method_name, params object[] args)
                {
                    MethodInfo method;
                    if (!Methods.TryGetValue(method_name, out method))
                    {
                        method = FieldType.GetMethod(method_name, BindingFlags.Instance | BindingFlags.Public);
                        Methods[method_name] = method;
                    }
                    if (method == null) throw new MissingMethodException(FieldType.Name, method_name);
                    return method.Invoke(Value, args);
                }
    What return method.Invoke(Value, args); means and how to use it?
     
    Last edited by a moderator: Apr 13, 2015
  11. We can't do anything without seeing your entire method, there could be something wrong before your call to the other plugin as well but because you are only showing use the call we can't see that
     
  12. Ok here full test code (with some "using" garbage)

    TestCore.cs
    Code:
    // Reference: Oxide.Ext.Rust
    // Reference: Newtonsoft.Json
    using System.Collections.Generic;
    using System.Linq;
    using Oxide.Core;
    using Oxide.Core.Plugins;
    using Oxide.Core.Configuration;
    using Oxide.Plugins;
    using UnityEngine;
    using System;
    using Newtonsoft.Json;namespace Oxide.Plugins
    {
        [Info("Test Core", "AlexALX", "0.0.1")]
        public class TestCore : RustPlugin
        {
       
            public TestCore()
            {
                //HasConfig = true;
            }        public bool GetInfo(BasePlayer ply) {
                if (ply==null) return false;
                var sid = ply.userID.ToString();
                return true;
            }
           
            [HookMethod("OnPlayerChat")]
            void OnPlayerSpawned(ConsoleSystem.Arg arg)
            {
                var test = GetInfo(arg.Player());
                Puts("[TEST CORE] "+test.ToString());
            }
       
        }
       
    }
    TestExt.cs
    Code:
    // Reference: Oxide.Ext.Rust
    // Reference: Newtonsoft.Json
    using System.Collections.Generic;
    using System.Linq;
    using Oxide.Core;
    using Oxide.Core.Plugins;
    using Oxide.Core.Configuration;
    using Oxide.Plugins;
    using UnityEngine;
    using System;
    using Newtonsoft.Json;namespace Oxide.Plugins
    {
        [Info("Test Ext", "AlexALX", "0.0.1")]
        public class TestExt : RustPlugin
        {
            [PluginReference] Plugin TestCore;
       
            public TestExt()
            {
                //HasConfig = true;
            }
           
            [HookMethod("OnPlayerChat")]
            void OnPlayerSpawned(ConsoleSystem.Arg arg)
            {
                var test = TestCore.Call("GetInfo",arg.Player());
                Puts("[TEST EXT] "+test.ToString());
            }
       
        }
       
    }
    What i'm getting when say anything in chat:

    Code:
    [Oxide] 12:14 AM [Info] [TEST CORE] True
    [Oxide] 12:14 AM [Error] Failed to call hook 'OnPlayerChat' on plugin 'Test Ext' (NullReferenceException: Object reference not set to an instance of an object)
    [Oxide] 12:14 AM [Debug]   at Oxide.Plugins.TestExt.OnPlayerSpawned (.Arg arg) [0x00000] in <filename unknown>:0
      at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&)
      at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00000] in <filename unknown>:0 
    [DOUBLEPOST=1428960286][/DOUBLEPOST]Oh, it seems get it finally working by remove "public" from "GetInfo" function. Didn't know that this can cause problem.
    Thank you for help anyway.
     
  13. I figured out why this is happening.

    If you look into the RustPlugin source, you can see that it inherits from CSPlugin which then inherits from BasePlugin. The BasePlugin class implements the plain and generic Call functions, but both then call CallHook, which is abstract. The implementation of CallHook is in CSPlugin, and it reads from a private field called "hooks", which is a dictionary with value type MethodInfo.

    Looking a little further, I found the culprit inside the CSPlugin constructor, which populates the hooks:

    Code:
    // ... snipped
                for (int i = types.Count - 1; i >= 0; i--)
                {
                    MethodInfo[] methods = types[i].GetMethods(BindingFlags.Instance | BindingFlags.NonPublic);
                    for (int j = 0; j < (int)methods.Length; j++)
                    {
                        MethodInfo methodInfo = methods[j];
                        object[] customAttributes = methodInfo.GetCustomAttributes(typeof(HookMethod), true);
                        if ((int)customAttributes.Length >= 1)
                        {
                            this.AddHookMethod((customAttributes[0] as HookMethod).Name, methodInfo);
                        }
                    }
                }
    As you can see, it only looks for non-public instance methods, hence why it ignored your public method. This is potentially a bug in Oxide, depending on how you look at it. It can be resolved by passing Instance, NonPublic, and Public together.
     
  14. Was done on purpose actually.
     
  15. Any particular reason? Seems odd (or backwards, at least) that private methods would be exclusively selected, while public methods would be ignored.