1. Hi, I own a small server and would like to make a stats plugin written in JavaScript. I started out by reading the documentation and trying out cool print() commands. Then from a couple of forum posts here I got the methods to send chat message replies for commands and managed to write some code related to that.

    So my primary aim was to find who did the longest kill and show it to users when they type in a command. I got all the event listeners right but the data structures were nowhere to be found and using JSON.stringify(arguments) gave nothing. So I managed to write a custom call hook in the DeathNotes plugin to manually wrap their processed data and send it as a json string.
    Code:
    plugins.CallHook("OnDeathNoticeMsg", newData.JSON.Replace(Environment.NewLine, ""));
    So that lead me to write the following small plugin which just records the longest kill someone made.
    Code:
    var DistanceData = {
        longest: {
            victim: {},
            attacker: {},
            reason: 0,
            damageType: "",
            weapon: "",
            attachments: [],
            bodypart: "",
            distance: 0
        }
    }, longestKill = function () {
        return "Longest kill by <color=#C4FF00>" + DistanceData.longest.attacker.name + "</color> at <color=#C4FF00>" + Math.round(DistanceData.longest.distance) + "m</color> using a <color=#C4FF00>" + DistanceData.longest.weapon + "</color>";
    }, sendMessageToPlayer = function (player, message) {
        rust.SendChatMessage(player, "KappaStats", message, "0");
    }, KappaStats = {
        Title: "KappaStats",
        Author: "",
        Version: V(0, 0, 1),
        Init: function () {
            print("KappaStats: Init");
        },
        OnServerInitialized: function () {
            command.AddChatCommand("kappastats", this.Plugin, "killStats");
            print("KappaStats: " + Object.keys(this).join(", "));
        },
        killStats: function (player, cmd, args) {
            sendMessageToPlayer(player, longestKill());
        },
        OnDeathNoticeMsg: function (data) {
            try {
                data = JSON.parse(data);
                if (data.distance >= DistanceData.longest.distance) {
                    DistanceData.longest = data;
                }
            } catch (err) {
                print(JSON.stringify(err));
            }
        }
    };
    Now I want to extend this to a better one and possibly remove the dependency on DeathNotes. As someone else pointed out, I went to install JustDecompile but didn't because it asks me to signup. I then tried a free decompiler but searching for the object types and method names give me nothing(or I'm doing it wrong, which is more likely). I do not even know the basics of C# but I speak JS fluently. Please give me some directions. I just really don't like shady installers(you can't convince me otherwise, please understand).
     
  2. If you're looking to decompile stuff and not looking to install Visual Studio and other big software, try ILSpy, I've been using it for a while.
    It's open source.
    I've also installed a Reflexil mod for ILSpy.
    Installing ILSpy is as simple as unzipping the binaries archive. Modding it with Reflexil is as simple as copying the DLLs into the ILSpy directory.

    In regards to removing the dependency, just read the source code of DeathNotes on how it retrieves the distance.
     
  3. Haha yes, I actually did use ILSpy, but my C# reading skills are horrible(just started with it). I've been doing JS for so long that typed languages makes me scared now. Will read more on C# and return later. Meanwhile if you could tell me how to get the argument data structures for an Oxide event listener it would be so great!
     
  4. Check the type name (e.g. BasePlayer) and enter it into the search function of ILSpy after loading the DLL. You can open the search function via View > Search and selecting "Search for: Type" on the right of the search input bar. Enter BasePlayer, the selector should return the BasePlayer type. Double click it and the source will get decompiled for you to view.
     
  5. Ah yes got them. So I should be looking at the C# types from documentation and use the public properties defined in it I suppose?
     
  6. You can use whatever is public in any of those types or any of the properties of these types. Doesn't matter whether it's an attribute or a method.
    You can obviously access static methods or attributes of any other type as well (e.g. ConVar.Server), as long as you import them (not sure how it's handled in the JS extension).
    Here's a list of things that Oxide exposes: Classes | Oxide
     
  7. I saw this fragment in one of the examples here:
    Code:
    var global = importNamespace("");
    print(global.BasePlayer.activePlayerList.Count);
    Anything related?
     
  8. No clue, sorry.
     
  9. I don't recommend using JS for plugin development, the reason is it apparently can't store the player steamids directly because of the way JS treats numbers. I ran into this issue myself in testing when I was writing js plugins and found no reasonable solution googling. Here's more on it.

    JavaScript plugin reference | Oxide
     
    Last edited by a moderator: Jul 10, 2016
  10. Wulf

    Wulf Community Admin

    You'd have to use a library helper provided by Oxide to convert them from a ulong to a string. Rust also provides a string in most instances as well via player.UserIDString.
     
  11. To extend on this: JavaScript and Lua both had the brilliant idea to represent all numbers as doubles, which causes loads of problems. Doubles have limited precision - and steam ids are too large to be stored precisely.
    As Wulf mentioned, you can convert every ID to strings and then work with that.

    That being said, the lack of plugins using JavaScript, Python (and arguably to some extent Lua as well) makes it harder to get into plugin development, because there are less examples. I think in that sense, JavaScript and Python are only useful to more experienced devs.
     
  12. Why do we have to store it as a number? It's a unique value right and unless we do some arithmetic on it, can't it be just a string?

    Was thinking of making some documentation along with my plugin and some sort of a library/wrapper for doing these kinds of stuff. I'm sure we can utilize build scripts/tools to automate the conversion of SteamIDs. Gonna re-write this in ES6 and see if I can match the type names that you see in C#

    P.s. the pain of handling real numbers in JavaScript is real...
     
  13. There's no real benefit of using JS for oxide plugin development only downsides, and this is coming from someone who uses JS tremendously with websites and server side via node.js. I didn't know C# a week ago, but looking at enough plugin sources, decompiling some .net dll's and playing around got me writing some pretty in-depth plugins that my friends are excited about. I google anything I get stumped on and it usually provides answers. Wulf mentioned in the release notes that C# plugins compile to practically native as well, so you get that extra execution speed.
     
  14. You don't have to store it as a number. Storing it as a number is merely more efficient.
    Storing it as a string takes around 48 or 60 bytes (depending on the arch), while storing it as a long takes 8 bytes.
    Comparing two strings is O(n), while comparing two longs is O(1).
    In addition to that accessing strings likely results in a cache miss, while accessing numbers normally doesn't.

    There is a library, atleast for Rust (see: Oxide/Rust.cs at develop · OxideMod/Oxide · GitHub).
    There certainly isn't a need for build scripts/tools (why?).
     
  15. Ah yes I understand that while writing plugins we should make it as efficient as possible but I wans't planning on making it public or release it here(just a small plugin for private use). This is like my first try in modding a game, never done it before. I've been doing JS all my life so it felt a lot easier to implement it using what I know. I do own a Windows phone so learning C# is not really a bummer after all. Let me see if I can do some real OOP :D

    Build scripts to generate the final concatenated .js plugin file that may be developed using mock classes(my plan was to create those for argument types) in an IDE and also cases where we need to use external libraries to handle long-ints?

    p.s. death to typed languages!