init.lua 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. if not minetest.global_exists("exile") then exile = {} end
  2. exile.modpath = minetest.get_modpath("exile")
  3. exile.eviction_notices = exile.eviction_notices or {}
  4. -- Localize for performance.
  5. local vector_distance = vector.distance
  6. local vector_normalize = vector.normalize
  7. local vector_subtract = vector.subtract
  8. local vector_multiply = vector.multiply
  9. local vector_round = vector.round
  10. local vector_add = vector.add
  11. local math_random = math.random
  12. -- Helper to query whether there is a nearby non-cheating player (also not self)
  13. -- within a certain range.
  14. local function nearby_noncheater(pname, pos, range)
  15. local players = minetest.get_connected_players()
  16. for i=1, #players, 1 do
  17. local pref = players[i]
  18. local pn = pref:get_player_name()
  19. if pn ~= pname then
  20. if vector_distance(pref:get_pos(), pos) < range then
  21. if not sheriff.is_suspected_cheater(pn) then
  22. if not gdac.player_is_admin(pn) then
  23. return true
  24. end
  25. end
  26. end
  27. end
  28. end
  29. end
  30. local function move_player_to_exile(pname, target)
  31. local minp = vector.add(target, {x=-8, y=-100, z=-8})
  32. local maxp = vector.add(target, {x=8, y=100, z=8})
  33. local function callback(blockpos, action, calls_remaining, param)
  34. -- We don't do anything until the last callback.
  35. if calls_remaining ~= 0 then
  36. return
  37. end
  38. -- Check if there was an error on the LAST call.
  39. -- Note: this will usually fail if the area to emerge intersects the map edge.
  40. -- But usually we don't try to do that, here.
  41. if action == core.EMERGE_CANCELLED or action == core.EMERGE_ERRORED then
  42. return
  43. end
  44. local pos = table.copy(param.target)
  45. local orig_y = pos.y
  46. local pname = param.pname
  47. local get_node = minetest.get_node
  48. -- Locate ground level, or some area where the player can fit in air.
  49. -- Start from sky and work downwards, to reduce chance of tp'ing to cave.
  50. for y = 90, -90, -1 do
  51. pos.y = orig_y + y - 1
  52. local n1 = get_node(pos)
  53. pos.y = orig_y + y
  54. local n2 = get_node(pos)
  55. pos.y = orig_y + y + 1
  56. local n3 = get_node(pos)
  57. -- All 3 nodes must be loaded.
  58. if n1.name ~= "ignore" and n2.name ~= "ignore" and n3.name ~= "ignore" then
  59. local d1 = minetest.registered_nodes[n1.name]
  60. local d2 = minetest.registered_nodes[n2.name]
  61. local d3 = minetest.registered_nodes[n3.name]
  62. if d1 and d2 and d3 then
  63. if d1.walkable and not d2.walkable and not d3.walkable then
  64. pos.y = orig_y + y
  65. local post_cb = function(param)
  66. -- Report publicly, while avoiding chat spam.
  67. local pname = param.pname
  68. if not exile.eviction_notices[pname] then
  69. minetest.chat_send_all("# Server: Law enforcement evicted <" .. rename.gpn(pname) .. "> from town.")
  70. exile.eviction_notices[pname] = true
  71. minetest.after(60, function()
  72. exile.eviction_notices[pname] = nil
  73. end)
  74. end
  75. end
  76. -- Wrapped in minetest.after() to avoid *potential* callstack issues.
  77. minetest.after(0, function()
  78. preload_tp.execute({
  79. player_name = pname,
  80. target_position = pos,
  81. emerge_radius = 8,
  82. post_teleport_callback = post_cb,
  83. callback_param = param,
  84. force_teleport = true,
  85. send_blocks = false,
  86. particle_effects = true,
  87. })
  88. end)
  89. return
  90. end
  91. end
  92. end
  93. end
  94. end
  95. minetest.emerge_area(minp, maxp, callback,
  96. {target=table.copy(target), pname=pname})
  97. end
  98. -- A player is violating their exile if ...
  99. function exile.player_in_violation(pname)
  100. -- They are a registered cheater ...
  101. if sheriff.is_cheater(pname) then
  102. local pref = minetest.get_player_by_name(pname)
  103. -- And they are logged in ...
  104. if pref then
  105. local pos = pref:get_pos()
  106. -- And there's a normal player near them ...
  107. if nearby_noncheater(pname, pos, 100) then
  108. -- And they are in a city area ...
  109. if city_block:in_city_suburbs(pos) then
  110. -- And not currently in jail ...
  111. if not jail.is_player_in_jail(pref) then
  112. return true
  113. end
  114. end
  115. end
  116. end
  117. end
  118. end
  119. function exile.send_to_exile(pname)
  120. local pref = minetest.get_player_by_name(pname)
  121. if pref then
  122. local pos = pref:get_pos()
  123. local rn1 = rc.current_realm_at_pos(pos)
  124. local cb = city_block:nearest_blocks_to_position(pos, 5, 100)
  125. -- No nearby city-blocks? Cannot move player (also avoid divide-by-zero).
  126. if #cb == 0 then
  127. return
  128. end
  129. -- Calculate the average postion of nearby city-blocks.
  130. local x, y, z, n = 0, 0, 0, #cb
  131. for i=1, n, 1 do
  132. local b = cb[i]
  133. local p = b.pos
  134. x = x + p.x
  135. y = y + p.y
  136. z = z + p.z
  137. end
  138. x = x / n
  139. y = y / n
  140. z = z / n
  141. -- Calculate a new position away from the city-blocks.
  142. pos.y = y -- Only move player in the X,Z dimensions.
  143. local center = {x=x, y=y, z=z}
  144. local dir = vector_normalize(vector_subtract(pos, center))
  145. local gpos = vector_round(vector_add(vector_multiply(dir, 100), center))
  146. gpos.y = y -- Only move player in the X,Z dimensions.
  147. local rn2 = rc.current_realm_at_pos(gpos)
  148. -- Only if we wouldn't cause player to change realms, or enter the void.
  149. if rn2 ~= "" and rn1 == rn2 then
  150. move_player_to_exile(pname, gpos)
  151. -- Damage caused by system/server/cheat, bypass regular processing.
  152. pref:set_hp(pref:get_hp() - (1*500))
  153. end
  154. end
  155. end
  156. -- Function shall return 'true' if player was confirmed to be in violation of their exile.
  157. function exile.check_player(pname)
  158. if exile.player_in_violation(pname) then
  159. exile.send_to_exile(pname)
  160. return true
  161. end
  162. end
  163. function exile.repeating_check(pname)
  164. -- Only check confirmed cheaters, as no one else can be exiled.
  165. if sheriff.is_cheater(pname) then
  166. exile.check_player(pname)
  167. -- Schedule another check shortly.
  168. minetest.after(1, exile.repeating_check, pname)
  169. end
  170. end
  171. -- To be called if a cheater is confirmed/registered during game-play time.
  172. function exile.notify_new_exile(pname)
  173. -- Just call the function as if they've just joined.
  174. exile.on_joinplayer(minetest.get_player_by_name(pname))
  175. end
  176. function exile.on_joinplayer(pref)
  177. if pref and pref:is_player() then
  178. local pname = pref:get_player_name()
  179. minetest.after(math_random(1, 10), exile.repeating_check, pname)
  180. end
  181. end
  182. if not exile.registered then
  183. local c = "exile:core"
  184. local f = exile.modpath .. "/init.lua"
  185. reload.register_file(c, f, false)
  186. minetest.register_on_joinplayer(function(...)
  187. exile.on_joinplayer(...) end)
  188. exile.registered = true
  189. end