1. So some time ago I wanted to write a small plugin for a server that would have a global Dictionary. My problem was and is that Hooks in Oxide are, expectedly, called in an asynchronous/multithreaded kind of way. To still be able to write/add keys to a Dictionary one would usually use a lock or a static ReaderWriterLockSlim so that access is synchronized across multiple threads.

    Problem is this: Oxide throws UnauthorizedAccessException when using lock or ReaderWriterLockSlim · Issue #8 · OxideMod/Oxide.CSharp · GitHub

    And I don't understand how the developer expects someone to work around this. I also have not found that omnious whitelist.

    I would also like to know how blocking access to those two functions is helping with Sandboxing. I guess I never took a look at these two from a security POV.
     
  2. I think you totally misunderstood how Rust/Unity works.
    There's actually no multithreading nor asynchronous hooks.

    It looks like you went on "premature optimization" way.
    What's your reason for use locks, are you encountered a race condition?
    I would be interested in looking at such code.
     
    Last edited by a moderator: Mar 11, 2018
  3. Code:
    using System;
    using System.Collections.Generic;
    using Oxide.Core;
    using System.Threading;namespace Oxide.Plugins
    {
        [Info("Tester", "CommanderStrax", 0.2)]
        [Description("Multithread/Async test!")]
        class Blamer : RustPlugin
        {
            static Blamer instance;        void Init()
            {
            }        void Loaded()
            {
                instance = this;
            }        int a;
            static int b;
            bool CanLootPlayer(BasePlayer target, BasePlayer looter)
            {
                a++;
                b++;
                Puts("A:" + a);
                Puts("B:" + b);
                Puts("InstanceA" + instance.a);
                return true;        }
    }
    }
    A server admin executed that for me and a few people opened 'bodies' of sleeping people. The output was completely jumbled up (as in: A: 1 B:1 A:2 InstanceA:1 B:2) that can, from my knowledge, only be explained by multithreading/async calls.

    Oh...I didn't think about that: Obviously it could, in theory, also mean that the Puts function is async.

    Curiously I never had exceptions like 'The collection was changed while iterating over it' even though that should have plopped up.
     
    Last edited by a moderator: Mar 11, 2018
  4. Wulf

    Wulf Community Admin

    Everything is generally in a single thread, this includes the console. Oxide hooks are called when the game calls them, there is no threading or hanged being made. You do have to be very careful when trying to use threading though, as it is easy to corrupt things when more than one plugin would be trying to access the same thing.

    Your issue is because you can’t iterate over something and also modify it. Instead, store the list in a variable and iterate over that, then store the new values. This isn’t really unique to Oxide. Just generally what you have to do.
     
  5. @Wulf you are talking about doing something like changing a collection while iterating over it which I'm not doing. Not in the sample code and not in my 'real' code.
     
  6. Wulf

    Wulf Community Admin

    You mentioned storing the sleepers; that would be the iterating over something. That list changes, so it needs to be stored as a list or in a variable as the values will change otherwise as players may wake and such.
     
  7. @Wulf ah, sorry. I misunderstood you. Yes that could happen which is one of two reasons why I wanted to use lock/ReaderWriterLockSlim.

    Also I'm a bit confused by
    and

    To me those two things contradict eachother and I'm trying to understand what is going on. Are the hooks triggered asynchronously/put in tasks?
     
  8. I have to apologize for my not-so-nice way of phrasing things above. I also am obviously in the wrong here as I have read up a bit on Unity and it's single-threadedness.

    However, I'm still confused about the output and the original problems I had. So my final question still stands: When a hook function in a C# script is called by Oxide, does Oxide wait for that method to return (synchronous) or does it proceed to call other hooks(asynchronous)?
     
  9. Wulf

    Wulf Community Admin

    A hook is called when the game hits that spot where it is located. Oxide calls all plugins that are using that hook and each plugin processes whatever is in that hook in the plugin. There is no waiting. If the hook is called again, then it will go through the same process and may even have overlap if for some reason your code is being slow.
     
  10. @Wulf thank you for answering so quickly and also (sort of) confirming the async part (at least to me that is async behaviour). How would I go about having a global Dictionary<uint, string> where I want to save the ID of the player that did something and a message, consisting among other things out of a date and time? Usually I would use lock for that...
     
  11. Wulf

    Wulf Community Admin

    Just as you normally would with C#, there isn't anything unique about it. The only issue/error you posted previous was related to using a list from Rust that changed while you were looping it; which you can resolve using the method I posted previously.