MtnMCG

sethmc atm turtle

Dec 16th, 2025 (edited)
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.31 KB | None | 0 0
  1. -- Turtle ATM Script (turtle_atm.lua) with Gold Standard Validation
  2. -- Secure Transaction Logic: Acquire -> Verify -> Server -> Commit/Revert
  3.  
  4. local modem = peripheral.find("modem")
  5. if not modem then error("No modem found") end
  6. modem.open(1) -- Open channel 1 for communication with server
  7. modem.open(2) -- Open channel 2 for communication with ATM terminal
  8.  
  9. local function debug(message)
  10. print(os.date("%H:%M:%S") .. ": " .. message)
  11. end
  12.  
  13. local function sendToServer(message)
  14. modem.transmit(1, 1, message)
  15. local timer = os.startTimer(5)
  16. while true do
  17. local event, id, channel, replyChannel, response = os.pullEvent()
  18. if event == "modem_message" and channel == 1 then
  19. return response
  20. elseif event == "timer" and id == timer then
  21. return nil
  22. end
  23. end
  24. end
  25.  
  26. local function sendToATM(message)
  27. modem.transmit(2, 2, message)
  28. end
  29.  
  30. local function findBlock(blockType)
  31. for i = 1, 4 do
  32. local success, data = turtle.inspect()
  33. if success and data.name:find(blockType) then
  34. return true
  35. end
  36. turtle.turnRight()
  37. end
  38. return false
  39. end
  40.  
  41. local function isGold(item)
  42. return item and item.name == "minecraft:gold_ingot"
  43. end
  44.  
  45. -- Helper to dump specific item type to front
  46. local function dumpItems(itemCheckFn)
  47. for i = 1, 16 do
  48. local item = turtle.getItemDetail(i)
  49. if item and itemCheckFn(item) then
  50. turtle.select(i)
  51. turtle.drop()
  52. end
  53. end
  54. turtle.select(1)
  55. end
  56.  
  57. -- Securely acquire X gold from front inventory (Barrel or Chest)
  58. -- Keeps gold in turtle inventory. Returns success, message.
  59. -- If targetAmount is "max", grabs everything valid.
  60. local function acquireGold(targetAmount)
  61. local acquired = 0
  62. local isMax = (targetAmount == "max")
  63.  
  64. while true do
  65. local needed = 64
  66. if not isMax then
  67. needed = targetAmount - acquired
  68. if needed > 64 then needed = 64 end
  69. if needed <= 0 then break end
  70. end
  71.  
  72. -- Try to suck needed amount
  73. if turtle.suck(needed) then
  74. -- Verify what we just sucked
  75. local foundInvalid = false
  76. for i = 1, 16 do
  77. local item = turtle.getItemDetail(i)
  78. if item and not isGold(item) then
  79. -- Junk item, spit it back
  80. turtle.select(i)
  81. turtle.drop()
  82. turtle.select(1)
  83. foundInvalid = true
  84. end
  85. end
  86.  
  87. if foundInvalid and not isMax then
  88. -- If we found invalid items during a specific request, we might want to fail or just retry?
  89. -- simple retry logic: just continue loop, we counted valid ones below
  90. end
  91.  
  92. -- Recount total gold in inventory to update progress
  93. local currentTotal = 0
  94. for i = 1, 16 do
  95. local item = turtle.getItemDetail(i)
  96. if item and isGold(item) then
  97. currentTotal = currentTotal + item.count
  98. end
  99. end
  100.  
  101. -- If we haven't increased, break (empty source)
  102. if currentTotal <= acquired then
  103. break
  104. end
  105. acquired = currentTotal
  106. else
  107. break -- Sucking failed (empty)
  108. end
  109. end
  110.  
  111. if isMax then
  112. if acquired > 0 then
  113. return true, acquired
  114. else
  115. return false, "No Gold Found"
  116. end
  117. else
  118. if acquired >= targetAmount then
  119. return true, acquired
  120. else
  121. return false, "Insufficient Gold: Found " .. acquired .. " of " .. targetAmount
  122. end
  123. end
  124. end
  125.  
  126. -- Dumps ALL gold in inventory to front
  127. local function commitGold()
  128. dumpItems(isGold)
  129. end
  130.  
  131. local function handleDeposit(studentId, password, amount)
  132. local isMax = (amount == "max")
  133. local targetGold = 0
  134. if not isMax then
  135. targetGold = amount * 16
  136. end
  137.  
  138. if isMax then
  139. debug("Deposit: MAX Eddies")
  140. else
  141. debug("Deposit: " .. amount .. " Eddies (" .. targetGold .. " Gold)")
  142. end
  143.  
  144. if not findBlock("barrel") then
  145. sendToATM({action="complete", success=false, error="Barrel not found"})
  146. return
  147. end
  148.  
  149. -- 1. Acquire from Barrel
  150. local success, result = acquireGold(isMax and "max" or targetGold)
  151. if not success then
  152. sendToATM({action="complete", success=false, error=result or "Failed to collect gold"})
  153. -- Refund what we grabbed back to Barrel
  154. commitGold()
  155. return
  156. end
  157.  
  158. local totalGold = result
  159. local eddies = math.floor(totalGold / 16)
  160. local remainder = totalGold % 16
  161.  
  162. if eddies <= 0 then
  163. sendToATM({action="complete", success=false, error="Not enough gold for 1 Eddie (Need 16)"})
  164. commitGold()
  165. return
  166. end
  167.  
  168. -- 2. Server Update
  169. local response = sendToServer({type="update_balance", studentId=studentId, password=password, action="deposit", amount=eddies})
  170.  
  171. if response and response.type == "balance_update_response" and response.success then
  172. -- 3. Success: Move processed gold to Chest, remainder to Barrel
  173.  
  174. -- We need to separate the gold.
  175. -- Drop 'remainder' to Barrel first
  176. if remainder > 0 then
  177. -- We need to drop exactly 'remainder' amount.
  178. -- This is tricky because we have stacks.
  179. -- Logic: Select stacks, drop until remainder is gone.
  180. local dropped = 0
  181. for i = 1, 16 do
  182. local item = turtle.getItemDetail(i)
  183. if item and isGold(item) then
  184. local toDrop = math.min(remainder - dropped, item.count)
  185. if toDrop > 0 then
  186. turtle.select(i)
  187. turtle.drop(toDrop)
  188. dropped = dropped + toDrop
  189. end
  190. if dropped >= remainder then break end
  191. end
  192. end
  193. turtle.select(1)
  194. end
  195.  
  196. -- Now find chest and dump the rest (which should be exactly eddies * 16)
  197. if findBlock("chest") then
  198. commitGold() -- Dump valid gold to chest
  199. sendToATM({action="complete", success=true, newBalance=response.result, amountDeposited=eddies, remainder=remainder})
  200. else
  201. -- Critical Error: Chest missing after transaction!
  202. debug("CRITICAL: Chest missing during deposit commit!")
  203. -- Attempt to return to barrel to be safe
  204. if findBlock("barrel") then
  205. commitGold()
  206. sendToATM({action="complete", success=true, newBalance=response.result, warning="System Error: Chest full/missing. Gold returned to barrel but balance updated. Contact Admin.", amountDeposited=eddies, remainder=remainder})
  207. else
  208. sendToATM({action="complete", success=true, newBalance=response.result, warning="System Error: Gold stuck in Turtle.", amountDeposited=eddies, remainder=remainder})
  209. end
  210. end
  211. else
  212. -- 4. Fail: Refund to Barrel
  213. debug("Server deposit failed: " .. (response and response.message or "Timeout"))
  214. if findBlock("barrel") then
  215. commitGold() -- Dump back to barrel
  216. end
  217. sendToATM({action="complete", success=false, error="Server rejected deposit"})
  218. end
  219. end
  220.  
  221. local function handleWithdraw(studentId, password, amount)
  222. local goldAmount = amount * 16
  223. debug("Withdraw: " .. amount .. " Eddies (" .. goldAmount .. " Gold)")
  224.  
  225. -- 0. Check Balance First (Quick fail)
  226. local balanceResponse = sendToServer({type="get_balance", studentId=studentId, password=password})
  227. if not (balanceResponse and balanceResponse.type == "balance_response") then
  228. sendToATM({action="complete", success=false, error="Failed to retrieve balance"})
  229. return
  230. end
  231. if tonumber(balanceResponse.balance) < amount then
  232. sendToATM({action="complete", success=false, error="Insufficient balance"})
  233. return
  234. end
  235.  
  236. if not findBlock("chest") then
  237. sendToATM({action="complete", success=false, error="Chest not found"})
  238. return
  239. end
  240.  
  241. -- 1. Acquire from Chest
  242. local success, msg = acquireGold(goldAmount)
  243. if not success then
  244. sendToATM({action="complete", success=false, error=msg or "ATM empty/low funds"})
  245. -- Revert to Chest
  246. commitGold()
  247. return
  248. end
  249.  
  250. -- 2. Server Update
  251. local response = sendToServer({type="update_balance", studentId=studentId, password=password, action="withdraw", amount=amount})
  252.  
  253. if response and response.type == "balance_update_response" and response.success then
  254. -- 3. Success: Move to Barrel
  255. if findBlock("barrel") then
  256. commitGold() -- Dump to barrel
  257. sendToATM({action="complete", success=true, newBalance=response.result})
  258. else
  259. debug("CRITICAL: Barrel missing during withdraw commit!")
  260. -- Refund to Chest? But user already paid on server.
  261. -- This is a 'money lost' scenario for user if we refund.
  262. -- Better to keep trying or dump?
  263. -- In production, we'd log this. Here, we return to Chest to save the gold and error out.
  264. -- User loses balance but ATM keeps gold. Admin intervention needed.
  265. commitGold()
  266. sendToATM({action="complete", success=false, error="Hardware error: Barrel missing. Gold retained in ATM. Contact Admin."})
  267. end
  268. else
  269. -- 4. Fail: Revert to Chest
  270. commitGold()
  271. sendToATM({action="complete", success=false, error="Server rejected withdraw"})
  272. end
  273. end
  274.  
  275. while true do
  276. local event, side, channel, replyChannel, message = os.pullEvent("modem_message")
  277. if channel == 2 then
  278. if message.action == "deposit" then
  279. handleDeposit(message.studentId, message.password, message.amount)
  280. elseif message.action == "withdraw" then
  281. handleWithdraw(message.studentId, message.password, message.amount)
  282. end
  283. end
  284. end
  285.  
Add Comment
Please, Sign In to add comment