Guest User

Untitled

a guest
Jan 22nd, 2018
71
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.10 KB | None | 0 0
  1. local pkg = {}
  2.  
  3. require "mickkay.wol.Spell"
  4. local setmultimap = require "adrodoc55.setmultimap"
  5.  
  6. local store
  7. local width = 16
  8. local frequency = 1
  9. local heads = {}
  10. -- Mapping of chunk vector to all head positions with areas that intersect the chunk
  11. local headsByChunk = {}
  12.  
  13.  
  14.  
  15. local datastore = require "mickkay.datastore"
  16.  
  17. function saveData()
  18. datastore.save(store, heads)
  19. end
  20.  
  21. local getChunksIntersecting
  22.  
  23. function loadData()
  24. data = datastore.load(store) or {}
  25. heads = {}
  26. for i,headPos in pairs(data) do
  27. table.insert(heads,Vec3.new(headPos))
  28. end
  29. headsByChunk = {}
  30. for i,head in pairs(heads) do
  31. local chunks = getChunksIntersecting(head)
  32. for j,chunk in pairs(chunks) do
  33. setmultimap.put(headsByChunk, chunk, head)
  34. end
  35. end
  36. end
  37.  
  38.  
  39. local updatePlayer
  40. local removeBrokenHeads
  41. local onRightClickBlockEvent
  42.  
  43. function pkg.start(options)
  44. spell:singleton("mickkay.claim")
  45. store = spell.pos
  46. options = options or {}
  47. width = options.width or width
  48. frequency = options.frequency or frequency
  49. loadData()
  50. local queue = Events.connect("RightClickBlockEvent")
  51. while true do
  52. local players = Entities.find("@a")
  53. for i,player in pairs(players) do
  54. updatePlayer(player)
  55. end
  56. local dirty = removeBrokenHeads()
  57. local event = queue:pop(1)
  58. if event ~= nil then
  59. dirty = dirty or onRightClickBlockEvent(event)
  60. end
  61. if dirty then
  62. saveData()
  63. end
  64. end
  65. end
  66. Help.on(pkg.start) [[
  67. Allows players to 'claim' an area by placing their own head in the center of it. An area is protected by setting other players that enter the area into adventure mode. Areas can be shared between multiple players by placing multiple heads on top of each other (same x and z coordinate). If two areas overlap each other, the intersection is protected from both players.
  68.  
  69. Options:
  70. - width: How many blocks around the skull are protected. Default is 16 which results in 33x33 areas.
  71.  
  72. - frequency: Every 'frequency' ticks the gamemodes of players are updated and all skulls are checked to make sure they are still there.
  73. ]]
  74.  
  75. function pkg.stop()
  76. spell:singleton("mickkay.claim")
  77. end
  78. Help.on(pkg.stop) [[
  79. Disables 'claiming' of areas. Existing areas are kept persistent.
  80. ]]
  81.  
  82.  
  83.  
  84. local isHeadOfOwner
  85.  
  86. function updatePlayer(player)
  87. if player.dimension ~= 0 then
  88. return -- claiming is only supported in the overworld
  89. end
  90. local pos = player.pos
  91. local chunkX = pos.x // 16
  92. local chunkZ = pos.z // 16
  93. local chunk = chunkX..'/'..chunkZ
  94. local heads = headsByChunk[chunk]
  95.  
  96. local ownHeadsXZ = {}
  97. local foreignHeadsXZ = {}
  98. if heads then
  99. for i,head in pairs(heads) do
  100. if head.x - width < pos.x
  101. and head.z - width < pos.z
  102. and head.x + width + 1 > pos.x
  103. and head.z + width + 1 > pos.z
  104. then
  105. local xz = head.x.."/"..head.z
  106. if isHeadOfOwner(head, player.name) then
  107. ownHeadsXZ[xz] = true
  108. else
  109. foreignHeadsXZ[xz] = true
  110. end
  111. end
  112. end
  113. end
  114. for xz,_ in pairs(ownHeadsXZ) do
  115. foreignHeadsXZ[xz] = nil
  116. end
  117. local mayBuild = next(foreignHeadsXZ) == nil
  118. if not mayBuild and player.gamemode == "survival" then
  119. player.gamemode = "adventure"
  120. elseif mayBuild and player.gamemode == "adventure" then
  121. player.gamemode = "survival"
  122. end
  123. end
  124.  
  125.  
  126.  
  127. local getBlock
  128. local isPlayerHead
  129.  
  130. function removeBrokenHeads()
  131. local dirty = false
  132. for i=#heads,1,-1 do
  133. local head = heads[i]
  134. local block = getBlock(head)
  135. if not isPlayerHead(block) then
  136. table.remove(heads, i)
  137.  
  138. local chunks = getChunksIntersecting(head)
  139. for i,chunk in pairs(chunks) do
  140. setmultimap.remove(headsByChunk, chunk, head)
  141. end
  142. dirty = true
  143. end
  144. end
  145. return dirty
  146. end
  147.  
  148. function isHeadOfOwner(pos, owner)
  149. local block = getBlock(pos)
  150. return isPlayerHead(block) and block.nbt.Owner.Name == owner
  151. end
  152.  
  153. function getBlock(pos)
  154. spell.pos = pos
  155. return spell.block
  156. end
  157.  
  158. function isPlayerHead(block)
  159. return block.name == "skull" and block.nbt.Owner
  160. end
  161.  
  162.  
  163.  
  164. local cities = require "mickkay.cities"
  165. local citiesProxy = cities.proxy()
  166.  
  167. function onRightClickBlockEvent(event)
  168. if event.player.dimension ~= 0 then
  169. return false -- claiming is only supported in the overworld
  170. end
  171. spell.pos = event.pos
  172. spell:move(event.face)
  173. local block = spell.block
  174. if block.name ~= "skull" or not block.nbt.Owner then
  175. return false -- not dirty
  176. end
  177. local head = spell.pos
  178. if not citiesProxy.isInsideCityCenter(head) then
  179. spell:execute("setblock "..head.x.." "..head.y.." "..head.z.." air 0 destroy")
  180. return false -- not dirty
  181. end
  182. table.insert(heads, head)
  183.  
  184. local chunks = getChunksIntersecting(head)
  185. for i,chunk in pairs(chunks) do
  186. setmultimap.put(headsByChunk, chunk, head)
  187. end
  188. return true -- dirty
  189. end
  190.  
  191. function getChunksIntersecting(head)
  192. local minChunkX = (head.x - width) // 16
  193. local maxChunkX = (head.x + width + 1) // 16
  194. local minChunkZ = (head.z - width) // 16
  195. local maxChunkZ = (head.z + width + 1) // 16
  196. local chunks = {}
  197. for chunkX=minChunkX,maxChunkX,1 do
  198. for chunkZ=minChunkZ,maxChunkZ,1 do
  199. table.insert(chunks, chunkX..'/'..chunkZ)
  200. end
  201. end
  202. return chunks
  203. end
  204.  
  205. return pkg
Add Comment
Please, Sign In to add comment