1. Greetings,


    I made a small plugin to be able to use my automated VIP WebPanel on Rust, so people can buy the VIP rank for a limited time.

    The problem is that, it's using the user's SteamID to identify him, so I can get the SteamID from a BasePlayer object, but not from IPlayer.

    Here is the interesting part from my Plugin:

    Code:
    private bool IsPlayerVip(object player) {
        if (player == null)
            throw new ArgumentException("player");    if (player is ulong)
            return playerVip[((ulong)player).ToString()];
        else if (player is BasePlayer)
            return playerVip[(player as BasePlayer).userID.ToString()];
        
        return false;
    }
    Is there any way to make it compatible with IPlayer ?
    For example, it will work with:

    Code:
    void Example(BasePlayer player)
    {
        var example = 1.0;    if ((bool)VipManager?.Call("IsPlayerVip", player) == true)
            example = 1.5;    //[...]
    }
    but not with something like

    Code:
    void Example(IPlayer player)
    {
        var example = 1.0;    if ((bool)VipManager?.Call("IsPlayerVip", player) == true)
            example = 1.5;    //[...]
    }

    Could anyone help me?

    Thanks for reading.
     
  2. Wulf

    Wulf Community Admin

    Pass something generic like a string or ulong, not the entire object. Return true or false based on if they are VIP or not. There's no need to pass the entire object for a method like that.

    Example of usage:
    Code:
    bool IsPlayerVip(string id) => playerVip.Contains(id)
     
  3. Ok, but how can I get the SteamID from IPlayer, if I use something like:

    Code:
    private bool IsPlayerVip(string playerID) {
        return playerVip[playerID];
    }
    Because the bool is actually stocked in, for example, playerVip[76561190000000000]

    So if I call it this way:

    Code:
    VipManager?.Call("IsPlayerVip", entity.userID.ToString())
    I will still have the same problem, I wouldn't be able to do that with IPlayer since there is no userID inside.


    Thanks for your fast answer by the way!

    EDIT:

    That may help, it's how the variable is defined according to the MySQL result:

    Code:
    var sql = Sql.Builder.Append("SELECT * FROM vip_users WHERE steamid = @0 AND vip_date > @1", player.userID, DateTime.UtcNow);_mySql.Query(sql, _mySqlConnection, list =>
    {
        if (list.Count > 0) {
            playerVip[player.userID.ToString()] = true;
        } else {
            playerVip[player.userID.ToString()] = false;
        }
    });
     
  4. IPlayer contains the steamid (as a string) in the `Id` field so taking your IPlayer example:
    Code:
    void Example(IPlayer player)
    {
        var example = 1.0;
        //------------------------------------------------v
        if ((bool)VipManager?.Call("IsPlayerVip", player.Id) == true)
            example = 1.5;    //[...]
    }
     
  5. Ok thank you for that, so now my function looks like that:

    Code:
    private bool IsPlayerVip(string playerID) {
        return playerVip[playerID];
    }
    So I tried to call it from another plugin using IPlayer :

    Code:
    (bool)VipManager?.Call("IsPlayerVip", player.Id)
    And I get this error :

    Code:
    Cannot cast from source type to destination type.

    EDIT:

    By the way, it's still working fine with BasePlayer using:

    Code:
    (bool)VipManager?.Call("IsPlayerVip", player.userID.ToString()
    And with IPlayer I tried both :

    Code:
    (bool)VipManager?.Call("IsPlayerVip", player.Id)
    (bool)VipManager?.Call("IsPlayerVip", player.Id.ToString())
     
  6. Wulf

    Wulf Community Admin

    Firstly, I'd check if the playerVip.Contains it before trying to return a bool, otherwise you'll run into NREs. I'd also check if VipManager is null before trying to cast to bool, else you'll also get NREs if someone doesn't have it installed. Could you post the full error as well along with the full code snippet you are using the call in?
     
  7. Sure, I'm getting this error:

    Code:
    [Oxide] 15:21 [Error] Failed to call hook 'IsPlayerVip' on plugin 'VipManager v1.0.0' (InvalidCastException: Cannot cast from source type to destination type.)
    [Oxide] 15:21 [Debug]   at Oxide.Plugins.VipManager.DirectCallHook (System.String name, System.Object& ret, System.Object[] args) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.CSharpPlugin.InvokeMethod (HookMethod method, System.Object[] args) [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 name, System.Object[] args) [0x00000] in <filename unknown>:0
    [Oxide] 15:21 [Error] Failed to call hook 'Unload' on plugin 'PlaytimeTracker v0.1.31' (NullReferenceException: Object reference not set to an instance of an object)
    [Oxide] 15:21 [Debug]   at Oxide.Plugins.PlaytimeTracker.GetRewardMultiplier (IPlayer player) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.AddPoints (IPlayer player, Int32 amount) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.CheckForReward (IPlayer player) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.AddTime (IPlayer player) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.OnUserDisconnected (IPlayer player) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.Unload () [0x00000] in <filename unknown>:0
      at Oxide.Plugins.PlaytimeTracker.DirectCallHook (System.String name, System.Object& ret, System.Object[] args) [0x00000] in <filename unknown>:0
      at Oxide.Plugins.CSharpPlugin.InvokeMethod (HookMethod method, System.Object[] args) [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 name, System.Object[] args) [0x00000] in <filename unknown>:0 
    And I'm trying to call it from the PlaytimeTracker plugin :

    Code:
    object GetRewardMultiplier(IPlayer player)
    {
        if ((bool)VipManager?.Call("IsPlayerVip", ulong.Parse(player.Id).ToString()) == true)
            return 2f;    foreach (var perm in permData.permissions)
            if (permission.UserHasPermission(player.Id, perm.Key))
                return perm.Value;
        return null;
    }
    I'm going to add the verifications, but I thought using a question mark after "VipManager?" was something like "Only if declared".


    EDIT:

    And yeah, I also tried ulong.Parse(player.Id).ToString() as you can see ^^
     
  8. Wulf

    Wulf Community Admin

    Why would you try converting a string to a ulong and back to a string? :p

    Could I see the code for your IsPlayerVip?
     
  9. There are the parts you may want to see:

    Code:
    private List<string> playerVip = new List<string>();public void refreshUser(BasePlayer player)
    {
        var sql = Sql.Builder.Append("SELECT * FROM vip_users WHERE steamid = @0 AND vip_date > @1", player.userID, DateTime.UtcNow);    _mySql.Query(sql, _mySqlConnection, list =>
        {
            var playerID = player.userID.ToString();
            if (list.Count > 0 && !playerVip.Contains(playerID)) {
                playerVip.Add(playerID);
            } else if (list.Count == 0 && playerVip.Contains(playerID)) {
                playerVip.Remove(playerID);
            }
        });
    }[HookMethod("IsPlayerVip")]
    private bool IsPlayerVip(string playerID) {
        return (bool)playerVip.Contains(playerID);
    }
    Everything around is just related to the Database connection which is working fine :)

    It's working great with this function from GatherManager:

    Code:
    private void OnCollectiblePickup(Item item, BasePlayer player)
    {
        var vipMult = 1.0;    if (VipManager && (bool)VipManager?.Call("IsPlayerVip", player.userID.ToString()) == true)
            vipMult = 1.5;
                  
        if (PickupResourceModifiers.ContainsKey(item.info.displayName.english))
            item.amount = (int)(item.amount * PickupResourceModifiers[item.info.displayName.english] * vipMult);
        else if (PickupResourceModifiers.ContainsKey("*"))
            item.amount = (int)(item.amount * PickupResourceModifiers["*"] * vipMult);
    }
    but not with this one, so I don't really understand ^^

    Code:
    object GetRewardMultiplier(IPlayer player)
    {
        if (VipManager && (bool)VipManager?.Call("IsPlayerVip", player.Id) == true)
            return 2.0f;    foreach (var perm in permData.permissions)
            if (permission.UserHasPermission(player.Id, perm.Key))
                return perm.Value;
        return null;
    }
     
  10. @Wulf, Bump, I think you forgot about my thread ^^
     
  11. Wulf

    Wulf Community Admin

    Rust has player.UserIDString by the way, I'd use that over ToString(). You also do not need [HookMethod("IsPlayerVip")].

    Is player.Id showing as a string in Visual Studio?
     
  12. It's okay thank you, I removed the HookMethod and I turned userID.ToString() into UserIDString, and it's working fine.

    But that still doesn't fix the problem with the IPlayer function from PlaytimeTracker, how can I see if it's showing up as a string?
     
  13. Wulf

    Wulf Community Admin

    Visual Studio should show you, otherwise try printing ToString() and see if it makes a difference. The player.Id from IPlayer should be a string though.
     
  14. Sorry for the late answer, I've been really busy these days.

    Oh hum.. I'm not using Visual Studio, but I really don't understand, I don't have any error anymore, but it still doesn't work, and we all get the default amount of RP every X minutes.

    Here's what the function looks like:

    Code:
    void AddPoints(IPlayer player, int amount)
    {
        object multiplier = GetRewardMultiplier(player);
        if (multiplier == null) multiplier = 1f;
        var vipMult = 1f;
        if (VipManager && (bool)VipManager?.Call("IsPlayerVip", player.Id) == true)
            vipMult = 2f;
        amount = Convert.ToInt32(Math.Floor(amount * (float)multiplier) * (float)vipMult);
        #if RUST
        if (ServerRewards && configData.RewardSystem.RewardPlugins.Rust.ServerRewards)
            ServerRewards?.Call("AddPoints", ulong.Parse(player.Id), amount);    if (Economics && configData.RewardSystem.RewardPlugins.Rust.Economics)
            Economics?.Call("Deposit", ulong.Parse(player.Id), (double)amount);
        #endif    #if HURTWORLD
        if (Economy && configData.RewardSystem.RewardPlugins.Hurtworld.Economy)
            Economy?.Call("AddMoney", player.Object as PlayerSession, (double)amount);
        #endif
        if (UEconomics && configData.RewardSystem.RewardPlugins.Universal.UEconomics)         
            UEconomics?.Call("Deposit", player.Id, amount);         
    }
    amount is equal to "500", multiplier is null, so set to "1f", and vipMult should be set to 2f if the Call returns true (called function can be seen above), and it is called the same way as it is called in the Gather plugin, and it works in it.

    By the way, I edited BetterChat to show a star symbol in front of the VIP players name, and it's working great, even if it is calling the function with as an arg player.Id, so why it's not working with PlaytimeTracker, I'm confused :S
     
  15. Wulf

    Wulf Community Admin

    All I can suggest is to add some debug output to see what the Call returns, what vipMult ends up being, etc.