1. Is it possible to make players sleep?
    I know there is the console command "sleep",
    but that one doesn't accept args like a playername. So you can only use that in the ingame console to make yourself sleep.
    Is it Possible to make players sleep via a plugin?
    Im planning to make an afk plugin with that.
    Im also interested if there is a way to detect inactivity.
    Thanks
    -Laser
     
  2. To have a player start sleeping you just need the BasePlayer and use the method StartSleeping, silly example:
    Code:
    function PLUGIN:cmdSleep(player, cmd, args)
        player:StartSleeping()
    end
    Detecting inactivity however is a bit different but I suppose an easy way to do it is just to have a timer running which checks the position of each player on a set interval and if that position hasn't changed after x minutes you can set them afk.
     
  3. Thanks, imma try working with it.
     
  4. If you want to see few different things with their explanation I could recommend having a look at the code of the teleportation plugin. I wrote that with loads of comments explaining every single thing, even the StartSleeping is in there ;) and it has a lot of different things in it so it might be good practice.

    I can also recommend downloading a program to decompile the Assembly-CSharp.dll server file so you can find functions you can use on specific objects (like StartSleeping for BasePlayer). One of those programs (and free) is JustDecompile.

    Also nice is this website: http://www.lua.org/pil/contents.html it has a lot of information on Lua as a programming language so it might be worth checking out as well.
     
  5. Thanks a lot :)
    Imma get onto that if im searching for something.
    -Laser
    [DOUBLEPOST=1427496884][/DOUBLEPOST]Also is there a possibility like to do like
    Code:
    function PLUGIN:cmdAfk(player)
    -- Set Player as afk anyhow idk how so:
    player = afk
    player:StartSleeping()
    rust.BroadcastChat("AFK", player , " is now afk!")
    endfunction PLUGIN:OnPlayerWakeup(player)
    if player = afk then
    rust.BroadcastChat("AFK", player.displayName, " Isn't afk anymore!")
    else end
    end
    -laser
    [DOUBLEPOST=1427496919][/DOUBLEPOST]Lel how to do that LUA code? :v that doesnt work and if I use the interface its just a normal code...
     
    Last edited by a moderator: Mar 28, 2015
  6. Wulf

    Wulf Community Admin

    I've updated your post to show you how to post Lua code in tags.
     
  7. kk thanks... Do you got an ansewer for my question tho? XD Mughisi is offline :v
    -Laser
     
  8. To mark a player as afk you will need to store them in a list of sorts, or for Lua, in a table (http://lua-users.org/wiki/TablesTutorial). You don't generally want to modify the player in the case of your code as the player there is actually the BasePlayer. Also you are using PLUGIN:OnPlayerWakeup which actually is not a hook so you will need to use the OnRunCommand hook and listen for the wakeup command.

    I wrote you an example which basically does all these things you describe. I haven't actually tested it but it should work more or less :p
    It has a bit of everything in it, working with tables, timers, if statements, ... a bit of all what you need to write your own version of it :p

    Code:
    PLUGIN.Title       = "AFK"
    PLUGIN.Description = "Sets afk mode for players."
    PLUGIN.Version     = V( 1, 0, 0 )
    PLUGIN.HasConfig   = true
    PLUGIN.Author      = "Mughisi"local afkplayers = {}local afkcheckinterval = 30
    local timeUntilAfk = 600
    local timeUntilDisconnect = 1200
    local afktimers = {}
    local afkbypassadmins = true
    local afkchecks = {}function PLUGIN:Init()
        command.AddChatCommand("afk", self.Plugin, "cmdAfk")
        command.AddChatCommand("afklist", self.Plugin, "cmdAfkList")    local itPlayerList = global.BasePlayer.activePlayerList:GetEnumerator()
        while itPlayerList:MoveNext() do
            local player = itPlayerList.Current
            self:OnPlayerInit(player)
        end
    endfunction PLUGIN:cmdAfk(player, cmd, args)
        self:SetAfk(player)
    endfunction PLUGIN:cmdAfkList(player, cmd, args)
        if player.net.connection.authLevel == 2 then
            self:SendMessage(player, "The following players are afk:")
            for id, name in pairs(afkplayers) do
                self:SendMessage(player, name)
            end
        else
            self:SendMessage(player, "You are not allowed to use this command.")
        end
    endfunction PLUGIN:OnPlayerInit(player)
        if afkbypassadmins then
            if player.net.connection.authLevel > 0 then return end
        end    local steamid = rust.UserIDFromPlayer(player)    afktimers[steamid] = timer.Repeat(afkcheckinterval, 0, function() self:AfkCheck(player) end, self.Plugin)
    endfunction PLUGIN:OnPlayerDisconnected(player)
        local steamid = rust.UserIDFromPlayer(player)
        if afktimers[steamid] then
            afktimers[steamid]:Destroy()
        end
    endfunction PLUGIN:Afkcheck(player)
        local steamid = rust.UserIDFromPlayer(player)
        local position = player.transform.position    if afkchecks[steamid] then
            if afkchecks[steamid].x ~= position.x or afkchecks[steamid].y ~= position.y or afkchecks[steamid].z ~= position.z then
                if afkchecks[steamid].counter then
                    afkchecks[steamid].counter = 1
                else
                    afkchecks[steamid].counter = afkchecks[steamid].counter + 1
                end            if afkchecks[steamid].counter >= (timeUntilAfk / afkcheckinterval) then
                    self:SetAfk(player)
                end            if afkchecks[steamid].counter >= (timeUntilDisconnect / afkcheckinterval) then
                    self:Disconnect(player)
                end
            else
                afkchecks[steamid] = { x = position.x, y = position.y, z = position.z }
                afkchecks[steamid].counter = 0
            end
        else
            afkchecks[steamid] = { x = position.x, y = position.y, z = position.z }
        end
    endfunction PLUGIN:SetAfk(player)
        local steamid = rust.UserIDFromPlayer(player)
        afkplayers[steamid] = player.displayName
        self:SendMessage(player, "You are now afk.")
        player:StartSleeping()
    endfunction PLUGIN:Disconnect(player)
        Network.Net.sv:Kick(targetPlayer.net.connection, "You have been kicked due to inactivity.")
    endfunction PLUGIN:OnRunCommand( arg )
        if not arg then return end
        if not arg.cmd then return end
        if not arg.cmd.name then return end
        if not arg.connection then return end
        if not arg.connection.player then return end    if arg.cmd.name == "wakeup" then
            local steamid = rust.UserIDFromPlayer(arg.connection.player)
            if afkplayers[steamid] then
                afkplayers[steamid] = nil
            end
        end
    endfunction PLUGIN:SendMessage(target, message)
        if not target then return end
        if not target:IsConnected() then return end
        message = UnityEngine.StringExtensions.QuoteSafe( message )
        target:SendConsoleCommand( "chat.add \"" .. self.Config.Settings.ChatName .. "\""  .. message );
    end
     
  9. Thanks a lot, imma see that I can work with that.. Its more code that I tought tho ^^
    -Laser
    [DOUBLEPOST=1427549201][/DOUBLEPOST]
    Well now its more likeley that im just nearly coping that code... Because most of that im not really in to... like itPlayerList:MoveNext() or stuff. I just don't know what that should mean so.. ^_^
    I just only understand parts of for example the function AfkCheck()
    :eek:
     
    Last edited by a moderator: Mar 28, 2015
  10. That part is to handle the afk timers when the plugin is reloaded. In case the plugin is reloaded all temporary stored data (in those tables) is lost including the timers so if this happens with players online they won't have a timer running for them unless you loop the activePlayerList which contains the online players and start the timer for them.
    I also stored everything in temp variables, including the config, so if you are going to make this into an actual plugin you'll still have to handle the config part so it is more configurable :) Also the example I made is really basic, you could also modify the player's name and <AFK> on the end.
    Ideally though this should be created in C# using the OnPlayerInput hook that listens for the player pressing keys which is a better way to check if the player is afk or not instead of checking the current position against the previous position on a set interval.
     
  11. That OnPlayerInput hook doesn't work in lua, does it?
    Because in C# i would need to start from Zero up again ^^
    [DOUBLEPOST=1427551078][/DOUBLEPOST]
    Also: You didn't add in a message if a player is back, did you?
    Should it me added into this?
    Code:
    function PLUGIN:OnRunCommand( arg )
        if not arg then return end
        if not arg.cmd then return end
        if not arg.cmd.name then return end
        if not arg.connection then return end
        if not arg.connection.player then return end
       
        if arg.cmd.name == "wakeup" then
            local steamid = rus.UserIDDromPlayer(arg.connection.player)
            if afkplayers[steamid] then
                afkplayers[steamid] = nil
            end
        end
    end
    
    after line 11?
     
  12. While it is possible to use this hook in the other supported programming languages, it however is much much slower for them because .Net will need to call into lua 30 times per player per second which will most likely result in a measurable amount of overhead.
     
  13. Well now I just made it into a plugin and customited and added config stuff but its not working...
    Code:
    PLUGIN.Title        = "AFK"
    PLUGIN.Description  = "AFK System"
    PLUGIN.Author       = "LaserHydra // a lot help by Mughisi"
    PLUGIN.Version      = V(1,0,0)
    PLUGIN.HasConfig    = truelocal afkplayers = {}local afkcheckinterval = 30
    local timeUntilAfk = 600
    local timeUntilDisconnect = 1200
    local afktimers = {}
    local afkbypassadmin = true
    local afkchecks = {}function PLUGIN:Init()
        command.AddChatCommand("afk", self.Object, "cmdAfk")
        command.AddChatCommand("afklist", self.Object, "cmdAfkList")
      
        self:LoadDefaultConfig()
      
        local itPlayerList = global.BasePlayer.activePlayerList:GetEnumerator()
        while itPlayerList:MoveNext() do
            local player = itPlayerList.Current
            self:OnPlayerInit(player)
        end
    end
          
    function PLUGIN:LoadDefaultConfig()
        self.Config.AfkListMsg = self.Config.AfkListMsg or {"Currently AFK:"}
        self.Config.NotAllowedMsg = self.Config.NotAllowedMsg or {"You are not allowed to use this command."}
        self.Config.PlayerAfkMsg = self.Config.PlayerAfkMsg or {"is now AFK!"}
        self.Config.PlayerAfkPrivateMsg = self.Config.PlayerAfkPrivateMsg or {"You are now AFK!"}
        self:SaveConfig()
    end
          
    function PLUGIN:cmdAfk(player)
        self:SetAfk(player)
    endfunction PLUGIN:OnPlayerInit(player)
        if afkbypassadmins then
            if player.net.connection.authLevel > 0 then return end
        end
      
        local steamid = rust.UserIDFromPlayer(player)
      
        afktimers[steamid] = timer.Repeat(afkcheckinterval, 0, function() self:AfkCheck(player) end, self.Plugin)
    endfunction OnPlayerDisconnected(player)
        local steamid = rust.UserIDFromPlayer(player)
        if afktimers[steamid] then
            afktimers[steamid]:Destroy()
        end
    endfunction PLUGIN:AfkCheck()
        local steamid = rust.UserIDFromPlayer(player)
        local position = player.transform.position
      
        if afkchecks[steamid] then
            if afkchecks[steamid].x ~= position.x or afkchecks[steamidk].y ~= position.y or afkchecks[steamid].z ~= position.z then
                if afkchecks[steamid].counter then
                    afkchecks[steamid].counter = 1
                else
                    afkchecks[steamid].counter = afkchecks[steamid].counter + 1
                end
              
                if afkchecks[steamid].counter >= (timeUntilAfk / afkcheckinterval) then  
                    self:SetAfk(player)
                end
              
                if afkchecks[steamid].counter >= (timeUntilDisconnect / afkcheckinterval) then
                    self:Disconnect(player)
                end
            else
                afkchecks[steamid] = { x = position.x, y = position.y, z = position.z }
                afkchecks[steamid].counter = 0
            end
        else
            afkchecks[steamid] = { x = position.x, y = position.y, z = position.z }
        end
    endfunction PLUGIN:SetAfk(player)
        local steamid = rust.UserIDFromPlayer(player)
        afkplayers[steamid] = player.displayName
        self:SendMessage(player, "AFK", "" .. self.Config.PlayerAfkPrivateMsg)
        player:StartSleeping()
    endfunction PLUGIN:OnRunCommand( arg )
        if not arg then return end
        if not arg.cmd then return end
        if not arg.cmd.name then return end
        if not arg.connection then return end
        if not arg.connection.player then return end
      
        if arg.cmd.name == "wakeup" then
            local steamid = rus.UserIDFromPlayer(arg.connection.player)
            if afkplayers[steamid] then
                afkplayers[steamid] = nil
            end
        end
    endfunction PLUGIN:SendMessage(target, message)
        if not target then return end
        if not target.IsConnected() then return end
        message = UnityEngine.StringExtensions.QuoteSafe( message )
        target:SendConsoleCommand( "chat.add \"" .. "AFK" .. "\"" .. message )
    end
    
    Im getting those errors:

    Code:
    [Oxide] 3:19 PM [Error] Failed to run a 30.00 timer in afk
    File: afk.lua Line: 59 Object reference not set to an instance of an object:
    at System.UInt64.ToString () [0x00000] in :0
    at Oxide.Rust.Libraries.Rust.UserIDFromPlayer (.BasePlayer player) [0x00000] in :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 :0 
    and

    Code:
    [Oxide] 3:17 PM [Error] Failed to call hook 'cmdAfk' on plugin 'AFK'
    File: afk.lua Line: 89 attempt to concatenate field 'PlayerAfkPrivateMsg' (a table value):
    at NLua.Lua.ThrowExceptionFromError (Int32 oldTop) [0x00000] in :0
    at NLua.Lua.CallFunction (System.Object function, System.Object[] args, System.Type[] returnTypes) [0x00000] in :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 :0 
    -laser
     
  14. function PLUGIN:Afkcheck(player) instead of function PLUGIN:Afkcheck() on line 59
    And for the config values, you have put everything between { } which indicates it is a table but that isn't necessary, just as string will suffice here. (This is why you get that second error)
     
  15. What exactly to put between {} ?
     
  16. When you use { } you are actually creating a table
    local tableEx = { "value 1", "value 2", "value 3" }

    and then you can print those by using []
    print(tableEx[1]) -- value 1
    print(tableEx[2]) -- value 2
    print(tableEx[3]) -- value 3

    to store a string you only use the quotes:
    local stringEx = "This is my string"
    print(stringEx)
     
  17. so what do I need to put in {} in this case?
    Which Line and what? ^^
    in line 89 where it has that error, it says
    Code:
        self:SendMessage(player, "AFK", "" .. self.Config.PlayerAfkPrivateMsg)
    
    you mean to change it to:
    Code:
        self:SendMessage(player, "AFK", "" .. {self.Config.PlayerAfkPrivateMsg})
    
    I didn't really understand it... :v
     
  18. The error is triggered on line 89 yes but the actual problem is where you set your config values lines 30 and some. You actually set the value for self.Config.PlayerAfkPrivateMsg to a table with that string as value so you can't just print or send it by calling it like that. You will technically need the [1] as described in my previous post. But because you only use one string it is pointless to store it in a table and it should just be a string so you can print it like you are doing it so I recommend to just remove the { } in the 4 lines where you set your config values like so:
    Code:
        self.Config.AfkListMsg = self.Config.AfkListMsg or "Currently AFK:"
        self.Config.NotAllowedMsg = self.Config.NotAllowedMsg or "You are not allowed to use this command."
        self.Config.PlayerAfkMsg = self.Config.PlayerAfkMsg or "is now AFK!"
        self.Config.PlayerAfkPrivateMsg = self.Config.PlayerAfkPrivateMsg or "You are now AFK!"
    You don't really need to change anything to line 89, just that you do not need the , there as it is using my sendmessage function that only takes 2 arguments :p
    self:SendMessage(player, "AFK: " .. self.Config.PlayerAfkPrivateMsg)

    Also keep in mind that you will probably have to delete the already created config file first.
     
  19. now it gives me an error here:
    Code:
    function PLUGIN:SendMessage(target, message)
        if not target then return end
        if not target.IsConnected() then return end
        message = UnityEngine.StringExtensions.QuoteSafe( message )
        target:SendConsoleCommand( "chat.add \"" .. "AFK" .. "\"" .. message )
    end
    
    The error is:

    Code:
    [Error] Failed to call hook 'cmdAfk' on plugin 'AFK' 
    File: afk_new.lua Line: 110 instance method 'IsConnected' requires a non null target object: 
    at NLua.Lua.ThrowExceptionFromError (Int32 oldTop) [0x00000] in :0 
    at NLua.Lua.CallFunction (System.Object function, System.Object[] args, System.Type[] returnTypes) [0x00000] in :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 :0 
    
    And the error with the timer is still there... :eek:
     
  20. That's my bad, used to do this in C#, the . between target and IsConnected() should be a :
    so switch out that line for
    if not target:IsConnected() then return end