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:
Is there any way to make it compatible with IPlayer ?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; }
For example, it will work with:
but not with something likeCode:void Example(BasePlayer player) { var example = 1.0; if ((bool)VipManager?.Call("IsPlayerVip", player) == true) example = 1.5; //[...] }
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.
Function compatible with both BasePlayer and IPlayer?
Discussion in 'Rust Development' started by Shytoos, Nov 10, 2016.
-
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)
-
Ok, but how can I get the SteamID from IPlayer, if I use something like:
Because the bool is actually stocked in, for example, playerVip[76561190000000000]Code:private bool IsPlayerVip(string playerID) { return playerVip[playerID]; }
So if I call it this way:
I will still have the same problem, I wouldn't be able to do that with IPlayer since there is no userID inside.Code:VipManager?.Call("IsPlayerVip", entity.userID.ToString())
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; } }); -
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; //[...] } -
Ok thank you for that, so now my function looks like that:
So I tried to call it from another plugin using IPlayer :Code:private bool IsPlayerVip(string playerID) { return playerVip[playerID]; }
And I get this error :Code:(bool)VipManager?.Call("IsPlayerVip", player.Id)
Code:Cannot cast from source type to destination type.
EDIT:
By the way, it's still working fine with BasePlayer using:
And with IPlayer I tried both :Code:(bool)VipManager?.Call("IsPlayerVip", player.userID.ToString()
Code:(bool)VipManager?.Call("IsPlayerVip", player.Id) (bool)VipManager?.Call("IsPlayerVip", player.Id.ToString()) -
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? -
Sure, I'm getting this error:
And I'm trying to call it from the PlaytimeTracker plugin :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
I'm going to add the verifications, but I thought using a question mark after "VipManager?" was something like "Only if declared".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; }
EDIT:
And yeah, I also tried ulong.Parse(player.Id).ToString() as you can see ^^ -
Wulf Community Admin
Why would you try converting a string to a ulong and back to a string?
Could I see the code for your IsPlayerVip? -
There are the parts you may want to see:
Everything around is just related to the Database connection which is working fineCode: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); }
It's working great with this function from GatherManager:
but not with this one, so I don't really understand ^^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); }
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; } -
@Wulf, Bump, I think you forgot about my thread ^^
-
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? -
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? -
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. -
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:
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.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); }
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 -
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.
