init.lua 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. --[[ INITIALIZING: basics ]]--
  2. -- global API table
  3. modpol = {
  4. }
  5. -- table for all active governance data
  6. modpol.orgs = {
  7. }
  8. -- record of governance interactions
  9. -- every state change should appear here
  10. modpol.ledger = {
  11. }
  12. -- update from mod_storage
  13. -- https://dev.minetest.net/StorageRef
  14. local mod_storage = minetest.get_mod_storage()
  15. -- load orgs
  16. local stored_orgs = minetest.deserialize(mod_storage:get_string("orgs"))
  17. if (stored_orgs ~= nil) then
  18. modpol.orgs = stored_orgs
  19. end
  20. -- load orgs
  21. local stored_ledger = minetest.deserialize(mod_storage:get_string("ledger"))
  22. if (stored_ledger ~= nil) then
  23. modpol.ledger = stored_ledger
  24. end
  25. --[[ FUNCTIONS:basics ]]--
  26. -- record(message, org)
  27. -- writes all governance events to storage and ledger
  28. function modpol.record(message, org)
  29. -- record to ledger
  30. table.insert(modpol.ledger, message)
  31. -- record to org_ledger
  32. if (modpol.orgs[org] ~= nil) then
  33. local org_ledg = modpol.orgs[org]["ledger"]
  34. if (org_ledg == nil) then
  35. modpol.orgs[org]["ledger"] = {message}
  36. else
  37. modpol.orgs[org]["ledger"] = table.insert(org_ledg,message)
  38. end
  39. end
  40. -- record to storage
  41. mod_storage:set_string("orgs", minetest.serialize(modpol.orgs))
  42. mod_storage:set_string("ledger", minetest.serialize(modpol.ledger))
  43. end
  44. --[[ FUNCTIONS:orgs ]]--
  45. -- new_org()
  46. -- create an org and add it to the list
  47. function modpol.new_org(orgName, orgMembers)
  48. if (orgName == "") then -- blank orgName input
  49. return "-!- Org needs a name"
  50. end
  51. if (modpol.orgs[orgName] == nil) then -- copy check
  52. modpol.orgs[orgName] = {members = orgMembers}
  53. else return "-!- Org already exists"
  54. end
  55. local message = "New org: " .. orgName ..
  56. " (" .. table.concat(orgMembers, ", ") .. ")"
  57. modpol.record(message, orgName)
  58. return message
  59. end
  60. -- /neworg [name]
  61. -- creates a new org with the current user as sole member
  62. minetest.register_chatcommand(
  63. "neworg", {
  64. privs = {},
  65. func = function(user, param)
  66. local result =
  67. modpol.new_org(param,{user})
  68. return true, result
  69. end,
  70. })
  71. -- rename_org()
  72. function modpol.rename_org(oldName, newName)
  73. -- TKTK
  74. local message = "Org renamed: " .. oldName .. " > " .. newName
  75. modpol.record(message, newName)
  76. end
  77. -- /listorgs
  78. -- lists the orgs currently in the game
  79. minetest.register_chatcommand(
  80. "listorgs", {
  81. privs = {},
  82. func = function(user, param)
  83. local orglist = ""
  84. for key, value in pairs(modpol.orgs) do
  85. -- first, set up member list
  86. local membs = modpol.orgs[key]["members"]
  87. if (membs == nil) then membs = ""
  88. else membs = " (" .. table.concat(membs, ", ") .. ")"
  89. end
  90. -- now, assemble the list
  91. if (orglist == "") -- first element only
  92. then orglist = key .. membs
  93. else orglist = orglist .. ", " .. key .. membs
  94. end
  95. end
  96. return true, "Orgs: " .. orglist
  97. end,
  98. })
  99. -- rm_orgs()
  100. -- removes all orgs
  101. function modpol.rm_orgs()
  102. modpol.orgs["instance"] = {members = modpol.list_members()}
  103. local message = "Orgs purged"
  104. modpol.record(message, nil)
  105. return message
  106. end
  107. -- /rmorgs
  108. minetest.register_chatcommand(
  109. "rmorgs", {
  110. privs = {},
  111. func = function(user, param)
  112. modpol.orgs = {}
  113. return true, modpol.rm_orgs()
  114. end,
  115. })
  116. --[[ FUNCTIONS:users ]]--
  117. -- list_members(domain)
  118. -- produces a table with names of players currently in the game
  119. -- if empty, lists all players; if an org name, lists its members
  120. function modpol.list_members(domain)
  121. local members = {}
  122. if (domain == nil) then -- no specified domain; all players
  123. for _,player in ipairs(minetest.get_connected_players()) do
  124. local name = player:get_player_name()
  125. table.insert(members,name)
  126. end
  127. else -- if an org is specified
  128. if (modpol.orgs[domain] ~= nil) then -- org exists
  129. members = modpol.orgs[domain]["members"]
  130. end
  131. end
  132. return members
  133. end
  134. -- /listplayers
  135. minetest.register_chatcommand(
  136. "listplayers", {
  137. privs = {},
  138. func = function(user)
  139. local result = table.concat(modpol.list_members(),", ")
  140. return true, "All players: " .. result
  141. end,
  142. })
  143. function modpol.add_member(org, member)
  144. if (modpol.orgs.org == nil) then
  145. return "-!- No such org"
  146. else
  147. table.insert(modpol.orgs.org["members"], member)
  148. local message = member .. " added to org " .. org
  149. modpol.record(message, org)
  150. return message
  151. end
  152. end
  153. -- /joinorg
  154. minetest.register_chatcommand(
  155. "joinorg", {
  156. privs = {},
  157. func = function(user, param)
  158. local result = modpol.add_member(param, user)
  159. return true, result
  160. end,
  161. })
  162. function modpol.remove_member(org, member)
  163. -- remove from all child orgs also
  164. local message = member .. " removed from org " .. org
  165. modpol.record(message, org)
  166. return message
  167. end
  168. -- /listmembers [org]
  169. -- lists the members of an org
  170. minetest.register_chatcommand(
  171. "listmembers", {
  172. privs = {},
  173. func = function(user, param)
  174. local orglist = modpol.list_members(param)
  175. return true, param .. ": " .. table.concat(orglist,", ")
  176. end,
  177. })
  178. -- PERMISSIONS FUNCTIONS
  179. -- PRIVILEGE FUNCTIONS
  180. -- Minetest-specific
  181. -- manages user privileges according to org membership
  182. function modpol.assign_privilege(org, privilege)
  183. -- add privilege to all members of an org
  184. end
  185. function modpol.remove_privilege(org, privilege)
  186. -- remove privilege from all members of an org, unless they have it from other orgs
  187. end
  188. --[[ USER INTERACTIONS ]]--
  189. -- modpol.binary_poll_user(user, question)
  190. -- presents a yes/no/abstain poll to a user, returns answer
  191. function modpol.binary_poll_user(user, question)
  192. -- set up formspec
  193. local text = "Poll: " .. question
  194. local formspec = {
  195. "formspec_version[4]",
  196. "size[5,3]",
  197. "label[0.375,0.5;", minetest.formspec_escape(text), "]",
  198. "button[1,1.5;1,0.8;yes;Yes]",
  199. "button[2,1.5;1,0.8;no;No]",
  200. "button[3,1.5;1,0.8;abstain;Abstain]"
  201. --TKTK can we enable text wrapping?
  202. }
  203. local formspec_string = table.concat(formspec, "")
  204. -- present to player
  205. minetest.show_formspec(user, "modpol:binary_poll", formspec_string)
  206. end
  207. -- Receiving fields
  208. minetest.register_on_player_receive_fields(function (player, formname, fields)
  209. -- modpol:poll
  210. if formname == "modpol:binary_poll" then
  211. local pname = player:get_player_name()
  212. local vote = nil
  213. if fields.yes then vote = fields.yes
  214. elseif fields.no then vote = fields.no
  215. elseif fields.abstain then vote = fields.abstain
  216. end
  217. if vote then
  218. minetest.chat_send_all(pname .. " voted " .. vote)
  219. end
  220. minetest.close_formspec(pname, formname)
  221. return vote
  222. else -- if the form is not a recognized name
  223. return
  224. end
  225. end)
  226. -- /pollself [question]
  227. -- asks the user a question
  228. minetest.register_chatcommand(
  229. "pollself", {
  230. privs = {},
  231. func = function(user, param)
  232. modpol.binary_poll_user(user, param)
  233. return true, result
  234. end,
  235. })
  236. --[[ TKTK need to enable more complex ineractions
  237. - checkboxes, radio
  238. - write-in
  239. ]]--
  240. -- MESSAGE FUNCTIONS
  241. function modpol.org_message(org, speaker, message)
  242. -- If org doesn't exit, broadcast to all
  243. -- If org doesn't exist, don't broadcast
  244. -- use: minetest.chat_send_player("player1", "This is a chat message for player1")
  245. end
  246. -- register at chat command for this
  247. -- Add HUD interface that shows status: orgs, privileges https://rubenwardy.com/minetest_modding_book/en/players/hud.html
  248. -- toggle it on and off
  249. --[[ INITIALIZING: post-functions ]]--
  250. -- create instance if not present
  251. if (modpol.orgs["instance"] == nil) then
  252. modpol.new_org("instance", modpol.list_members())
  253. end
  254. -- TKTK does this need to be on_joinplayer? still isn't adding the singleplayer