init.lua 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. afk = {}
  2. -- Interval between movement checks (in seconds).
  3. local INTERVAL = 15
  4. -- Minimum distance to move to register as not AFK (in blocks).
  5. local MINDIST = 0.4
  6. -- If player does not move within this time, 'sit' player (in seconds) and label them as afk.
  7. local TIMEOUT = 900
  8. local time_afk = {} -- a table indexed by plname that indicates the approximate time since last moved
  9. local last_pos = {} -- a table of position vectors that are indexed by plname
  10. local chat_afk = {} -- a table of booleans indexed by plname that indicate if players are afk, used to indicate if we have placed a chat message that indicates them as afk
  11. local chat_noafk = {} -- a table of booleans indexed by plname that indicate if players are not afk
  12. afk.afk_count = 0
  13. local beds_path = minetest.get_modpath("beds")
  14. local attached_before_afk = {}
  15. -- Function to check if the player is afk.
  16. local function check_moved()
  17. for _, p in ipairs(minetest.get_connected_players()) do
  18. local plname = p:get_player_name()
  19. local in_bed = false
  20. if beds_path then
  21. if beds.player[plname] then
  22. in_bed = true
  23. end
  24. end
  25. local pos = p:get_pos()
  26. local sit = false -- for now, assume that they are not afk. Well change that if we need to later on in this function
  27. -- (below) if the player is not registered on the afk and no afk list, add them with them not being afk
  28. if chat_noafk[plname] == nil then
  29. attached_before_afk[plname] = default.player_attached[plname]
  30. chat_afk[plname] = false
  31. chat_noafk[plname] = true
  32. end
  33. -- if the plname index can be found on the last_pos table then: (the plname index would not be found if they joined since the last interval afk check... we'll get them next time around bc of setting thire name o the table)
  34. if last_pos[plname] then
  35. --get the distance between their current position and their last postion, d is distance
  36. local d = vector.distance(last_pos[plname], pos)
  37. -- print("Player: "..plname..", Dist: "..d)
  38. if d < MINDIST then -- if d is less than minimum distance then
  39. time_afk[plname] = (time_afk[plname] or 0) + INTERVAL -- add the checking interval to the player's time afk (eg not moved) number
  40. --(below)and if the time not moved (time_afk at index plname) is more than the timeout time then sit them and post afk message to chat if we haven't already
  41. if time_afk[plname] >= TIMEOUT then --if we've reached timeout on the afk time table or are beyond that timeout then
  42. default.player_set_animation(p, "sit") -- make sure that the player is sitting
  43. sit = true --indicate that the player is sitting and that we have caused the sitting, for this iteration (used to keep player's animation as lay if they are dead)
  44. chat_noafk[plname] = false --take them off the list of players that are not afk
  45. if chat_afk[plname] == false then -- so they ARE afk after the timeout, but if they are not on the list of players that we have given an afk chat message about, then give the chat message now, and then indicate that we have given an afk message about them, so that we don't do it again.
  46. minetest.chat_send_all("*** "..plname.." is AFK.") -- changed the number of stars to differentiate it from user-generated messages
  47. chat_afk[plname] = true
  48. attached_before_afk[plname] = default.player_attached[plname] -- for first time afk, the attached state has not been messed with yet by this mod. Save its state now to know whether to unattach the player when they come back
  49. afk.afk_count = afk.afk_count + 1
  50. end
  51. default.player_attached[plname] = true --I switched this in its order to be after the test for first time afk, so we could determine the original attached state
  52. end
  53. else -- oh, wait, if they have moved more than the minumum distance, then reset their afk time
  54. time_afk[plname] = 0
  55. end
  56. end
  57. if not sit then --if we have not made them sit this iteration then
  58. last_pos[plname] = pos --set their last postion indicator to their current position for next iteration so we can detect movement
  59. chat_afk[plname] = false --make sure we know that they are not afk for future reference
  60. -- If a player returns and the status changes, we print a message to chat.
  61. if chat_noafk[plname] == false then --if we didn't make them sit this iteration, its bc they are active. If their index on the not_afk list says that they ARE afk, then we haven't updated that info. SO,
  62. minetest.chat_send_all("*** "..plname.." came back from AFK.") --let everyone know
  63. afk.afk_count = afk.afk_count - 1
  64. chat_noafk[plname] = true --and update their status
  65. if not(attached_before_afk[plname]) then -- only change animation and attached state to false IF they were not attached before they went afk. Let other mods handle setting them to not attached if they caused it
  66. default.player_attached[plname] = false -- let the server know that they are not attached anymore - the server will stand them up.
  67. default.player_set_animation(p, "stand") -- and make them stand up. I moved this from where it was setting the stand animation every check, to where it sets it only when coming back from afk
  68. end
  69. end
  70. end
  71. -- If players are dead and AFK or if they are in bed, keep their model in the lay position, not sit. Spawn particles
  72. if (p:get_hp() == 0 or in_bed) and sit then --if they are dead or are lying in bed and would otherwise be sitting bc of afk, revoke the sit anim command, instead set it to lay
  73. default.player_set_animation(p, "lay")
  74. if p:get_hp() == 0 then
  75. --spawn fly and stink particles here if they are afk and dead
  76. minetest.add_particlespawner({
  77. amount = 15,
  78. time = INTERVAL,
  79. minpos = {x=pos.x -.8 , y=pos.y + .1, z=pos.z -.8},
  80. maxpos = {x=pos.x +.8 , y=pos.y + 1, z=pos.z +.8},
  81. minvel = {x=0, y=0, z=0},
  82. maxvel = {x=-.1, y=-.1, z=-0.1},
  83. minacc = {x=0, y=0, z=0},
  84. maxacc = {x=0, y=0, z=0},
  85. minexptime = INTERVAL- .5*INTERVAL,
  86. maxexptime = INTERVAL,
  87. minsize = 4,
  88. maxsize = 4,
  89. collisiondetection = true,
  90. vertical = false,
  91. texture = "afk_fly_anim.png",
  92. animation = {
  93. type = "vertical_frames",
  94. aspect_w = 16,
  95. -- ^ specify width of a frame in pixels
  96. aspect_h = 16,
  97. -- ^ specify height of a frame in pixels
  98. length = .2,
  99. -- ^ specify full loop length
  100. },
  101. })
  102. end
  103. end
  104. if (sit and not(p:get_hp() == 0)) or (in_bed and (not(p:get_hp() == 0))) then-- if they are afk and not dead then
  105. -- spawn zzz particles here
  106. local bed_offset = 0
  107. if in_bed then
  108. bed_offset = -1
  109. end
  110. minetest.add_particlespawner({
  111. amount = 5,
  112. time = INTERVAL,
  113. minpos = {x=pos.x -.4 , y=pos.y + 1.2 + bed_offset, z=pos.z -.4},
  114. maxpos = {x=pos.x +.4 , y=pos.y + 1.5 + bed_offset, z=pos.z +.4},
  115. minvel = {x=0, y=.1, z=0},
  116. maxvel = {x=0.1, y=.3, z=0.1},
  117. minacc = {x=0, y=.1, z=0},
  118. maxacc = {x=0.01, y=.3, z=0.01},
  119. minexptime = INTERVAL- .5*INTERVAL,
  120. maxexptime = INTERVAL,
  121. minsize = 1,
  122. maxsize = 5,
  123. collisiondetection = true,
  124. vertical = false,
  125. texture = "afk_z_anim.png",
  126. animation = {
  127. type = "vertical_frames",
  128. aspect_w = 16,
  129. -- ^ specify width of a frame in pixels
  130. aspect_h = 16,
  131. -- ^ specify height of a frame in pixels
  132. length = INTERVAL,
  133. -- ^ specify full loop length
  134. },
  135. })
  136. end
  137. end
  138. minetest.after(INTERVAL, check_moved)
  139. end
  140. minetest.after(INTERVAL, check_moved)
  141. minetest.register_on_leaveplayer(function(player) -- clean things up
  142. --If player is AFK the count should be lowered!!!!!!!!!!!!!!!!!
  143. local plname = player:get_player_name()
  144. if chat_afk[plname] then
  145. afk.afk_count = afk.afk_count - 1
  146. end
  147. time_afk[plname] = nil
  148. last_pos[plname] = nil
  149. chat_afk[plname] = nil
  150. chat_noafk[plname] = nil
  151. attached_before_afk[plname] = nil
  152. end)