map_reset.lua 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. local function async_reset_map() end
  2. local function reset_node_inventory() end
  3. local on_step = minetest.registered_entities["__builtin:item"].on_step
  4. minetest.registered_entities["__builtin:item"].match_id = -2
  5. minetest.registered_entities["__builtin:item"].last_age = 0
  6. local get_position_from_hash = minetest.get_position_from_hash
  7. local hash_node_position = minetest.hash_node_position
  8. local deserialize = minetest.deserialize
  9. local add_node = minetest.add_node
  10. local get_node = minetest.get_node
  11. local get_inventory = minetest.get_inventory
  12. function skywars.reset_map(arena, debug, debug_data)
  13. if not arena.enabled or arena.is_resetting then return end
  14. skywars.load_mapblocks(arena)
  15. async_reset_map(arena, debug, debug_data)
  16. end
  17. -- Removing drops based on the match_id.
  18. minetest.registered_entities["__builtin:item"].on_step = function(self, dtime, moveresult)
  19. -- Returning if it passed less than 1s from the last check.
  20. if self.age - self.last_age < 1 then
  21. on_step(self, dtime, moveresult)
  22. return
  23. end
  24. local pos = self.object:get_pos()
  25. local arena = skywars.get_arena_by_pos(pos)
  26. self.last_age = self.age
  27. if arena and arena.match_id then
  28. -- If the drop has not been initializated yet.
  29. if self.match_id == -2 then
  30. self.match_id = arena.match_id
  31. elseif self.match_id ~= arena.match_id then
  32. self.object:remove()
  33. return
  34. end
  35. elseif arena then
  36. self.object:remove()
  37. return
  38. end
  39. on_step(self, dtime, moveresult)
  40. end
  41. function async_reset_map(arena, debug, recursive_data)
  42. recursive_data = recursive_data or {}
  43. -- When the function gets called again it uses the same maps table.
  44. local original_maps = recursive_data.original_maps or skywars.load_table("maps")
  45. if not original_maps[arena.name] or not original_maps[arena.name].changed_nodes then
  46. return
  47. end
  48. debug = debug or false
  49. -- The indexes are useful to count the reset nodes.
  50. local current_index = 1
  51. local last_index = recursive_data.last_index or 0
  52. local original_nodes_to_reset = original_maps[arena.name].changed_nodes
  53. local nodes_per_tick = recursive_data.nodes_per_tick or skywars_settings.nodes_per_tick
  54. local initial_time = recursive_data.initial_time or minetest.get_us_time()
  55. -- Resets a node if it hasn't been reset yet and, if it resets more than "nodes_per_tick"
  56. -- nodes, invokes this function again after one step.
  57. arena.is_resetting = true
  58. for hash_pos, node in pairs(original_nodes_to_reset) do
  59. if current_index > last_index then
  60. local pos = get_position_from_hash(hash_pos)
  61. add_node(pos, node)
  62. reset_node_inventory(pos)
  63. end
  64. -- If more than nodes_per_tick nodes have been reset this cycle.
  65. if current_index - last_index >= nodes_per_tick then
  66. minetest.after(0, function()
  67. async_reset_map(arena, debug, {
  68. last_index = current_index,
  69. nodes_per_tick = nodes_per_tick,
  70. original_maps = original_maps,
  71. initial_time = initial_time
  72. })
  73. end)
  74. return
  75. end
  76. current_index = current_index + 1
  77. end
  78. arena.is_resetting = false
  79. -- Removing the reset nodes from the current map table to preserve eventual
  80. -- changes made to the latter during the reset.
  81. local current_maps = skywars.load_table("maps")
  82. if not current_maps[arena.name] or not current_maps[arena.name].changed_nodes then
  83. return
  84. end
  85. local current_nodes_to_reset = current_maps[arena.name].changed_nodes
  86. for hash_pos, node in pairs(current_nodes_to_reset) do
  87. local always_to_be_reset = original_maps[arena.name].always_to_be_reset_nodes[hash_pos]
  88. -- If in the old map this block hadn't been changed or it always has
  89. -- to be reset, continue.
  90. if not original_nodes_to_reset[hash_pos] or always_to_be_reset then
  91. goto continue
  92. end
  93. local old_node = original_nodes_to_reset[hash_pos]
  94. local pos = get_position_from_hash(hash_pos)
  95. local current_node = get_node(pos)
  96. local is_old_node_still_reset = (current_node.name == old_node.name)
  97. -- Checking if the node was modified again DURING the reset process but
  98. -- AFTER being reset already.
  99. if is_old_node_still_reset then
  100. current_nodes_to_reset[hash_pos] = nil
  101. end
  102. ::continue::
  103. end
  104. skywars.overwrite_table("maps", current_maps)
  105. if debug then
  106. local duration = minetest.get_us_time() - initial_time
  107. minetest.log("[Skywars Reset Debug] The reset took " .. duration/1000000 .. " seconds!")
  108. end
  109. end
  110. function reset_node_inventory(pos)
  111. local location = {type="node", pos = pos}
  112. local inv = get_inventory(location)
  113. if inv then
  114. for index, list in ipairs(inv:get_lists()) do
  115. inv:set_list(list, {})
  116. end
  117. end
  118. end
  119. minetest.register_on_mods_loaded(function()
  120. for i, arena in pairs(arena_lib.mods["skywars"].arenas) do
  121. arena.is_resetting = false
  122. end
  123. end)