Advertisement
Dragonfyre173

Untitled

Aug 28th, 2016
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.16 KB | None | 0 0
  1. -- OpenPeripheral terminal glasses demo
  2. -- by boq
  3.  
  4. local p = peripheral.wrap("top")
  5.  
  6. if p == nil then
  7. print("Peripheral not found")
  8. return
  9. end
  10.  
  11. p.clear()
  12.  
  13. -- helper function and constants
  14. function pack(...)
  15. return {...}
  16. end
  17.  
  18. FORMAT_CHAR = "\194\167"
  19. FORMAT_BOLD = FORMAT_CHAR .. 'l'
  20.  
  21. -- NOTE
  22. -- this program works with multiple users (i.e. multiple players attached to same terminal) so it may be more complicated then single user variant
  23. -- if it's not needed, programs may as well operate only on global surface
  24. local players = {}
  25.  
  26. local attachedCount = 0
  27. local capturedCount = 0
  28.  
  29. -- initialize global display surface
  30. local labelPlayers = p.addText(-1, 0, "Player count: 0/0");
  31. labelPlayers.setScreenAnchor("right", "top") -- screen origin (0,0) for this object will be in top right corner
  32. labelPlayers.setObjectAnchor("right", "bottom") -- "center" of object will be on bottom right corner
  33. labelPlayers.setRotation(-90) -- object will be rotated by 90 degrees counter-clockwise around object anchor (bottom right corner)
  34.  
  35. local function initializePlayer(name, uuid)
  36. local playerData = { name = name, uuid = uuid}
  37.  
  38. -- now we can use private surface, visible only to owner player
  39. playerData.surface = p.getSurfaceByUUID(playerData.uuid)
  40. labelPlayer = playerData.surface.addText(0, 0, "Hello " .. playerData.name)
  41. labelPlayer.setAlignment("middle","top") -- identical as 'labelPlayer.setScreenAnchor("middle","top") labelPlayer.setObjectAnchor("middle","top")'
  42.  
  43. -- Minecraft color codes are interpreted (http://minecraft.gamepedia.com/Formatting_codes) - but since Lua does not support Unicode, you need to use "\194\167" instead of "\x00A7"
  44. playerData.labelWaiting = playerData.surface.addText(0, 0, FORMAT_BOLD .. "CAPTURE MODE: OFF", 0xFF0000)
  45. playerData.labelWaiting.setAlignment("right", "bottom")
  46.  
  47. -- add to global list
  48. -- general hint: it's always safer to use UUID instead of names!
  49. players[playerData.uuid] = playerData
  50. end
  51.  
  52. local function changeCounter(deltaAttached, deltaCaptured)
  53. attachedCount = attachedCount + deltaAttached
  54. capturedCount = capturedCount + deltaCaptured
  55. labelPlayers.setText("Player count: " .. attachedCount .. "/" .. capturedCount)
  56. end
  57.  
  58. -- initialize already attached players
  59. for _, user in pairs(p.getUsers()) do
  60. initializePlayer(user.name, user.uuid)
  61. changeCounter(1, 0)
  62. end
  63.  
  64. local timerCallbacks = {}
  65.  
  66. p.sync() -- this operation is needed to make changes visible to player
  67. -- classic event loop
  68. while true do
  69. evt = pack(os.pullEvent())
  70. -- full list of glasses events: https://gist.github.com/boq/9a098b89ee102cbf1b2b
  71. print(evt[1])
  72. -- easy break condition - it's just ComputerCraft event
  73. if evt[1] == "key" then
  74. break -- exit loop
  75. -- player started wearing glasses
  76. elseif evt[1] == "glasses_attach" then
  77. local name = evt[3]
  78. local uuid = evt[4]
  79. initializePlayer(name, uuid)
  80. changeCounter(1, 0)
  81. -- player logged out or took off glasses
  82. elseif evt[1] == "glasses_detach" then
  83. -- components on private surface are automatically cleared when player removes glasses
  84. local playerUuid = evt[4]
  85. players[playerUuid] = nil
  86. changeCounter(-1,0)
  87. -- player used wireless keyboard - computer will now start getting keyboard and mouse events
  88. elseif evt[1] == "glasses_capture" then
  89. changeCounter(0, 1)
  90. local playerUuid = evt[4]
  91. local playerData = players[playerUuid]
  92.  
  93. if playerData then
  94. local surface = playerData.surface
  95. playerData.labelWaiting.setText(FORMAT_BOLD .. "CAPTURE MODE: ON")
  96. playerData.labelWaiting.setColor(0x00FF00)
  97.  
  98. -- middle boxes - will be used as bottons and to present click position
  99. local function createBox(color)
  100. local box = surface.addBox(0,0, 25, 25, color)
  101. box.setScreenAnchor("middle","middle")
  102. box.setUserdata(color) -- userdata is variable that can be used to store anything (no type or content restrictions, except for functions). It's also not synchronized to clients
  103. return box
  104. end
  105.  
  106. createBox(0xFF0000).setObjectAnchor("left", "top")
  107. createBox(0x00FF00).setObjectAnchor("right", "top")
  108. createBox(0x0000FF).setObjectAnchor("right", "bottom")
  109. createBox(0xFFFFFF).setObjectAnchor("left", "bottom")
  110.  
  111. -- horizontal progress bar
  112. surface.addBox(0,20, 100, 5, 0x000000).setAlignment("middle","top")
  113.  
  114. -- vertical progress bar
  115. surface.addBox(0,0, 5, 100, 0x000000).setAlignment("right","middle")
  116.  
  117. playerData.horizontalMarker = surface.addBox(0, 20, 5, 5, 0xFFFFFF)
  118. playerData.horizontalMarker.setAlignment("middle","top")
  119.  
  120. playerData.verticalMarker = surface.addBox(0, 0, 5, 5, 0xFFFFFF)
  121. playerData.verticalMarker.setAlignment("right","middle")
  122.  
  123. -- pseudo-console stuff
  124. playerData.textInput = surface.addText(0,0,">", 0x00FF00)
  125. playerData.textInput.setScreenAnchor("left", "middle")
  126. playerData.textInput.setObjectAnchor("left", "bottom")
  127.  
  128. playerData.textOutput = surface.addText(0,0,"", 0x0000FF)
  129. playerData.textOutput.setScreenAnchor("left", "middle")
  130. playerData.textOutput.setObjectAnchor("left", "top")
  131. playerData.textOutput.setVisible(false)
  132.  
  133. -- mouse button indicator
  134. surface.addBox(10, 10, 19, 9, 0xAAAAAA).setObjectAnchor("middle","top") -- button indicator background
  135.  
  136. playerData.mouseButtons = {}
  137.  
  138. local function createMouseButton(deltaX)
  139. local button = surface.addBox(10 + deltaX, 12, 5, 5, 0xFF0000)
  140. button.setZ(5) -- move it over box (default Z == 0)
  141. button.setVisible(false)
  142. button.setObjectAnchor("middle","top")
  143. return button
  144. end
  145.  
  146. -- mouse and keyboard codes are same as LWJGL, see http://minecraft.gamepedia.com/Key_codes
  147.  
  148. playerData.mouseButtons[0] = createMouseButton(-5) -- left button
  149. playerData.mouseButtons[1] = createMouseButton(5) -- right button
  150. playerData.mouseButtons[2] = createMouseButton(0) -- middle button
  151. end
  152. -- player exited from keyboard GUI
  153. elseif evt[1] == "glasses_release" then
  154. changeCounter(0, -1)
  155. local playerUuid = evt[4]
  156. local playerData = players[playerUuid]
  157.  
  158. if playerData then
  159. -- recreate display to initial state
  160. playerData.surface.clear()
  161. initializePlayer(playerData.name, playerData.uuid)
  162. end
  163. -- player pressed mouse button anywhere in GUI
  164. elseif evt[1] == "glasses_mouse_down" then
  165. local playerUuid = evt[4]
  166. local playerData = players[playerUuid]
  167.  
  168. if playerData then
  169. local buttonId = evt[5]
  170. -- changing visibility is faster than recreating and removing element every time
  171. local button = playerData.mouseButtons[buttonId]
  172. if button then
  173. button.setVisible(true)
  174. end
  175. end
  176. -- player released mouse button anywhere in GUI
  177. elseif evt[1] == "glasses_mouse_up" then
  178. local playerUuid = evt[4]
  179. local playerData = players[playerUuid]
  180.  
  181. local buttonId = evt[5]
  182.  
  183. if playerData then
  184. button = playerData.mouseButtons[buttonId]
  185. if button then
  186. button.setVisible(false)
  187. end
  188. end
  189.  
  190. -- player clicked on component (if you got this event, then you won't get glasses_mouse_down. Same for glasses_component_mouse_up and glasses_mouse_up)
  191. elseif evt[1] == "glasses_component_mouse_down" then
  192. local isPrivate = evt[6]
  193. if isPrivate then
  194. local playerUuid = evt[4]
  195. local playerData = players[playerUuid]
  196.  
  197. if playerData then
  198. local objectId = evt[5]
  199. local component = playerData.surface.getObjectById(objectId)
  200. local userdata = component.getUserdata()
  201. if userdata then -- only rectangles in middle have that value filled
  202. -- capture control is special object used to control few properties of keyboard GUI
  203. local capture = p.getCaptureControl(playerUuid)
  204. capture.setBackground(userdata)
  205. playerData.horizontalMarker.setColor(userdata)
  206. playerData.verticalMarker.setColor(userdata)
  207. end
  208.  
  209. -- click position is given in pixels from top left component corner
  210. local clickX = evt[7]
  211. local clickY = evt[8]
  212.  
  213. -- -0.5, since anchor is in middle of screen
  214. playerData.horizontalMarker.setX((clickX / 25.0 - 0.5) * 100)
  215. playerData.verticalMarker.setY((clickY / 25.0 - 0.5) * 100)
  216. end
  217. end
  218. elseif evt[1] == "glasses_key_down" then
  219. local playerUuid = evt[4]
  220. local playerData = players[playerUuid]
  221.  
  222. if playerData then
  223. local code = evt[5] -- control code, see http://minecraft.gamepedia.com/Key_codes for keymap
  224. local char = evt[6] -- may be 0 for some control characters
  225.  
  226. local input = playerData.textInput
  227. local contents = input.getText()
  228. if code == 14 then -- backspace
  229. if contents:len() > 1 then
  230. input.setText(contents:sub(0, -2))
  231. end
  232. elseif code == 28 then -- enter
  233. input.setText(">")
  234.  
  235. local function setOutput(text, color)
  236. playerData.textOutput.setText(text)
  237. playerData.textOutput.setColor(color)
  238. playerData.textOutput.setVisible(true)
  239. local timerId = os.startTimer(1)
  240. timerCallbacks[timerId] = function ()
  241. playerData.textOutput.setVisible(false)
  242. end
  243. end
  244.  
  245. -- alternative to writing tons of ifs. Normally would be initialized once before main loop, but this is demo/semi-tutorial
  246. local commands = {}
  247.  
  248. function commands.hello(playerData)
  249. setOutput("Hi!", 0xFFFF00)
  250. end
  251.  
  252. function commands.exit(playerData)
  253. -- manually exit keyboard GUI. Player can do it itself by using escape button (same as normal Minecraft GUIs)
  254. p.getCaptureControl(playerData.uuid).stopCapturing()
  255. end
  256.  
  257. -- sorry, couldn't resist
  258. local function createColorCommand(color)
  259. return function(playerData)
  260. playerData.textInput.setColor(color)
  261. setOutput("OK", color)
  262. end
  263. end
  264.  
  265. commands.red = createColorCommand(0xFF0000)
  266. commands.green = createColorCommand(0x00FF00)
  267. commands.blue = createColorCommand(0x0000FF)
  268.  
  269. command = contents:sub(2, -1)
  270. commandSub = commands[command] -- skip console prompt
  271.  
  272. if commandSub then
  273. commandSub(playerData)
  274. else
  275. setOutput("invalid command: " .. command, 0xFF0000)
  276. end
  277.  
  278. elseif string.byte(char) >= 0x20 then -- skip unprintable control chars
  279. input.setText(contents .. char)
  280. end
  281. end
  282. elseif evt[1] == "timer" then
  283. local timerId = evt[2]
  284. callback = timerCallbacks[timerId]
  285. if callback then callback() end
  286. timerCallbacks[timerId] = nil
  287. end
  288.  
  289. -- sync() shouldn't be called often
  290. -- if called without changes, nothing will happen
  291. -- this method is synchronized - i.e. it can be executed only once per game tick (1/20 s). Other instructions don't have that limit
  292. p.sync()
  293. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement