init.lua 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. --------------------------------------------------------------------------------
  2. -- Mapfix, MTS version.
  3. -- Authored by MustTest.
  4. -- License: MIT.
  5. --------------------------------------------------------------------------------
  6. -- Mod is reloadable.
  7. if not minetest.global_exists("mapfix") then mapfix = {} end
  8. mapfix.players = mapfix.players or {}
  9. mapfix.modpath = minetest.get_modpath("mapfix")
  10. -- Localize for performance.
  11. local vector_round = vector.round
  12. local math_floor = math.floor
  13. local max = math.max
  14. local min = math.min
  15. -- Configurable settings.
  16. local MIN_TIMEOUT = 10
  17. local DEFAULT_RADIUS = 30
  18. local MAX_RADIUS = 75
  19. -- Special floatland region where mapfix use must be restricted.
  20. local XEN_BEGIN = 13150
  21. local XEN_BUFFER = XEN_BEGIN - 500
  22. local function work(minp, maxp)
  23. local vm = minetest.get_voxel_manip(minp, maxp)
  24. vm:update_liquids()
  25. vm:write_to_map(true) -- Fix lighting while you're at it.
  26. return vm:get_emerged_area()
  27. end
  28. -- Export this function publicly.
  29. mapfix.work = work
  30. -- Public API function. May be called from other mods.
  31. function mapfix.execute(pos, radius)
  32. pos = vector_round(pos)
  33. radius = math_floor(radius)
  34. local minp = vector.subtract(pos, radius)
  35. local maxp = vector.add(pos, radius)
  36. work(minp, maxp)
  37. end
  38. -- Chat-command callback function.
  39. -- Handles minimum timeout and required privileges.
  40. -- Called by KoC.
  41. mapfix.command = function(pname, param)
  42. -- Profile function execution time.
  43. local t1 = os.clock()
  44. local player = minetest.get_player_by_name(pname)
  45. if not player or not player:is_player() then
  46. return
  47. end
  48. -- Determine radius.
  49. local radius = DEFAULT_RADIUS
  50. if param and param ~= "" then
  51. radius = tonumber(param:trim())
  52. if not radius then
  53. minetest.chat_send_player(pname, "# Server: Usage: /mapfix [<radius>].")
  54. return
  55. end
  56. end
  57. -- Check timeout delay for this user.
  58. if mapfix.players[pname] then
  59. local tnow = os.time()
  60. local prev = mapfix.players[pname]
  61. local diff = tnow - prev
  62. -- Check if function was called too soon.
  63. if diff < MIN_TIMEOUT then
  64. local remain = math.ceil(MIN_TIMEOUT - diff)
  65. -- Grammar adjustment.
  66. local str = "seconds"
  67. if remain == 1 then
  68. str = "second"
  69. end
  70. minetest.chat_send_player(pname,
  71. "# Server: Too soon to run /mapfix again! Wait " .. remain ..
  72. " more " .. str .. ".")
  73. return
  74. end
  75. -- Store time of last call to this function.
  76. mapfix.players[pname] = tnow
  77. else
  78. -- Store time of last call to this function.
  79. mapfix.players[pname] = os.time()
  80. end
  81. local pos = vector_round(player:get_pos())
  82. radius = math_floor(radius)
  83. -- Check privs.
  84. if radius > MAX_RADIUS then
  85. local privs = minetest.check_player_privs(pname, {mapfix=true})
  86. if not privs then
  87. minetest.chat_send_player(pname,
  88. "# Server: You cannot exceed radius " .. MAX_RADIUS ..
  89. "! Your privileges are insufficient.")
  90. return
  91. end
  92. elseif radius < 0 then
  93. minetest.chat_send_player(pname, "# Server: Radius cannot be negative!")
  94. return
  95. end
  96. -- Minimum radius.
  97. radius = max(radius, 10)
  98. local minp = vector.subtract(pos, radius)
  99. local maxp = vector.add(pos, radius)
  100. -- Special handling to protect Carcorsica surface from Ir'xen shadows.
  101. if maxp.y >= XEN_BUFFER and minp.y <= XEN_BEGIN then
  102. -- If the Carcorsica surface extends into Xen space, mapfix is OK here.
  103. if sw.get_ground_y(pos) < XEN_BUFFER then
  104. minetest.chat_send_player(pname,
  105. "# Server: Mapfix forbidden within Ir'xen/Carcorsica intercalate zone.")
  106. return
  107. end
  108. end
  109. minetest.log("action",
  110. "Player <" .. pname .. "> executed /mapfix with radius " .. radius ..
  111. " at " .. minetest.pos_to_string(pos) .. ".")
  112. minp, maxp = work(minp, maxp)
  113. -- Calculate elapsed time.
  114. local t2 = os.clock()
  115. local totalms = math.ceil((t2 - t1) * 1000)
  116. minetest.chat_send_player(pname,
  117. "# Server: Liquid & light recalculation finished! Extents: " ..
  118. rc.pos_to_namestr(minp) .. " to " .. rc.pos_to_namestr(maxp) ..
  119. ". Radius: " .. radius .. ". Took " .. totalms .. " milliseconds.")
  120. end
  121. if not mapfix.registered then
  122. -- Privilege required in order to execute /mapfix for very large areas.
  123. minetest.register_privilege("mapfix", {
  124. description = "Player may execute /mapfix with an arbitrary radius.",
  125. give_to_singleplayer = false,
  126. })
  127. -- Allow players to use command from chat console.
  128. -- No privs required.
  129. minetest.register_chatcommand("mapfix", {
  130. params = "[radius]",
  131. description = "Request a recalculation of nearby liquids and light.",
  132. func = function(...)
  133. mapfix.command(...)
  134. return true
  135. end,
  136. })
  137. -- Register mod as reloadable.
  138. local c = "mapfix:core"
  139. local f = mapfix.modpath .. "/init.lua"
  140. reload.register_file(c, f, false)
  141. mapfix.registered = true
  142. end