Advertisement
Guest User

Untitled

a guest
Jan 23rd, 2019
130
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.47 KB | None | 0 0
  1. --This file implements the logic that syncs two player's inputs
  2. --author: TheOnlyOne and TestRunner
  3. local sync = {}
  4.  
  5. local messenger = require("bizhawk-co-op\\messenger")
  6. local ram_controller
  7.  
  8. my_ID = nil
  9.  
  10.  
  11. function sync.loadramcontroller()
  12. require_status, ram_controller = pcall(function()
  13. return dofile("bizhawk-co-op\\ramcontroller\\" .. config.ramcode)
  14. end)
  15. if not require_status then
  16. printOutput("The RAM controller file could not be loaded: " .. ram_controller)
  17. return false
  18. end
  19. if (ram_controller.getMessage == nil) or
  20. (ram_controller.processMessage == nil) or
  21. (ram_controller.itemcount == nil) then
  22. printOutput("The RAM controller file is not valid.")
  23. return false
  24. end
  25.  
  26. return ram_controller
  27. end
  28.  
  29.  
  30. --makes sure that configurations are consistent between the two players
  31. function sync.syncconfig(client_socket, their_id)
  32. printOutput("Checking configuration consistency...")
  33.  
  34. local sha1 = require("bizhawk-co-op\\sha1")
  35.  
  36. --construct a value representing the sync code that is in use
  37. local sync_code = ""
  38. for line in io.lines("bizhawk co-op.lua") do sync_code = sync_code .. line .. "\n" end
  39. for line in io.lines("bizhawk-co-op\\host.lua") do sync_code = sync_code .. line .. "\n" end
  40. for line in io.lines("bizhawk-co-op\\messenger.lua") do sync_code = sync_code .. line .. "\n" end
  41. for line in io.lines("bizhawk-co-op\\sync.lua") do sync_code = sync_code .. line .. "\n" end
  42. for line in io.lines("bizhawk-co-op\\ramcontroller\\" .. config.ramcode) do sync_code = sync_code .. line .. "\n" end
  43. local sync_hash = sha1.sha1(sync_code)
  44.  
  45. -- only host sends config
  46. if (their_id == nil) then
  47. config.ramconfig = nil
  48. end
  49.  
  50. --send the configuration
  51. messenger.send(client_socket, config.user, messenger.CONFIG, sync_hash, their_id, config.ramconfig)
  52.  
  53. --receive their configuration
  54. local received_message_type, their_user, received_data = messenger.receive(client_socket)
  55. if (received_message_type == messenger.ERROR) then
  56. printOutput("Configuration consistency check failed: " .. their_user)
  57. return false
  58. end
  59.  
  60. if (received_message_type ~= messenger.CONFIG) then
  61. printOutput("Configuration consistency check failed: Unexpected message type received.")
  62. return false
  63. end
  64.  
  65. if (host.users[their_user]) then
  66. printOutput("Configuration consistency check failed: Username in use")
  67. return false
  68. end
  69.  
  70. local their_sync_hash = received_data[1]
  71. local my_new_id = received_data[2]
  72. local newconfig = received_data[3]
  73.  
  74. --check consistency of configurations
  75. --check sync code
  76. if (sync_hash ~= their_sync_hash) then
  77. printOutput("Configuration consistency check failed: Bad hash")
  78. printOutput("You are not both using the same sync code (perhaps one of you is using an older version?)")
  79. printOutput("Make sure your sync code is the same and try again.")
  80. return false
  81. end
  82.  
  83. if my_new_id ~= nil then
  84. my_ID = my_new_id
  85. host.hostname = their_user
  86. elseif their_id ~= nil then
  87. my_ID = 1
  88. host.hostname = config.user
  89. end
  90.  
  91. if newconfig ~= nil then
  92. config.ramconfig = newconfig
  93. end
  94.  
  95. printOutput("Configuration consistency check passed")
  96. return their_user
  97. end
  98.  
  99.  
  100. function sync.sendItems(itemlist)
  101. for _,client in pairs(host.clients) do
  102. messenger.send(client, config.user, messenger.RAMEVENT, {["i"]=itemlist})
  103. end
  104. ram_controller.processMessage(config.user, {["i"]=itemlist})
  105.  
  106. end
  107.  
  108.  
  109. local close_client = function(clientID, err)
  110. local their_user = "The other player"
  111. for name, id in pairs(host.users) do
  112. if id == clientID then
  113. their_user = name
  114. break
  115. end
  116. end
  117. gui.addmessage(their_user .. " is not responding " .. err)
  118. printOutput("[Error] " .. their_user .. " is not responding " .. err)
  119.  
  120. -- close sockets
  121. if clientID == 1 then
  122. -- host sent the message, room is closed
  123. gui.addmessage("The room is closed.")
  124. host.close()
  125. error("The room is closed.")
  126. else
  127. -- client sent the message, room is still open
  128. gui.addmessage(their_user .. " left the room.")
  129. printOutput(their_user .. " left the room.")
  130. host.client_ping[clientID] = nil
  131. host.clients[clientID]:close()
  132. host.clients[clientID] = nil
  133. host.users[their_user] = nil
  134. end
  135. end
  136.  
  137.  
  138. local ping_func = function()
  139. for clientID, client in pairs(host.clients) do
  140. -- send PING message
  141. messenger.send(client, config.user, messenger.PING)
  142.  
  143. -- check if they have timedout
  144. host.client_ping[clientID] = (host.client_ping[clientID] or 4) - 1
  145. if host.client_ping[clientID] <= 0 then
  146. -- ping timeout
  147. close_client(clientID, "[PING TIMEOUT]")
  148. end
  149. end
  150. return false
  151. end
  152.  
  153.  
  154. function timer_coroutine(time, callback)
  155. local init = os.time()
  156. local now
  157.  
  158. while true do
  159. now = os.time()
  160. if os.difftime(now, init) < time then
  161. coroutine.yield(false)
  162. else
  163. init = now
  164. coroutine.yield(callback())
  165. end
  166. end
  167. end
  168. local ping_timer = coroutine.create(timer_coroutine)
  169. coroutine.resume(ping_timer, 10, ping_func)
  170.  
  171.  
  172. --shares the input between two players, making sure that the same input is
  173. --pressed for both players on every frame. Sends and receives instructions
  174. --that must be performed simultaneously; such as pausing and saving
  175. function sync.syncRAM()
  176. while true do
  177. -- check for PING TIMEOUT and send PINGS
  178. if coroutine.status(ping_timer) == "dead" then
  179. ping_timer = coroutine.create(timer_coroutine)
  180. coroutine.resume(ping_timer, 1, ping_func)
  181. else
  182. local timer_status, err = coroutine.resume(ping_timer)
  183. if not timer_status then
  184. printOutput(err)
  185. end
  186. end
  187.  
  188. --Send Quit request
  189. if sendMessage["Quit"] == true then
  190. sendMessage["Quit"] = nil
  191.  
  192. for _,client in pairs(host.clients) do
  193. messenger.send(client, config.user, messenger.QUIT)
  194. end
  195. gui.addmessage("You closed the connection.")
  196. host.close()
  197. error("You closed the connection.")
  198. end
  199.  
  200. local ram_message = ram_controller.getMessage()
  201. if ram_message then
  202. for _,client in pairs(host.clients) do
  203. messenger.send(client, config.user, messenger.RAMEVENT, ram_message)
  204. end
  205. end
  206.  
  207. --receive this frame's input from the other player and other messages
  208. for clientID, client in pairs(host.clients) do
  209. local received_message_type, their_user, received_data = messenger.receive(client, true)
  210.  
  211. -- close client on error
  212. if (received_message_type == messenger.ERROR) then
  213. close_client(clientID, their_user)
  214. break
  215. end
  216.  
  217. -- echo messages
  218. if (received_message_type ~= nil) then
  219. for otherClientID, otherClient in pairs(host.clients) do
  220. if (otherClientID ~= clientID) then
  221. messenger.send(otherClient, their_user, received_message_type, received_data)
  222. end
  223. end
  224. end
  225.  
  226. if (received_message_type == messenger.MEMORY) then
  227. --we received memory
  228. for adr, mem in pairs(received_data) do
  229. memory.write_u16_le(adr, mem)
  230. end
  231. elseif (received_message_type == messenger.RAMEVENT) then
  232. --we received memory
  233. ram_controller.processMessage(their_user, received_data)
  234. elseif (received_message_type == messenger.QUIT) then
  235. --we received quit
  236. if their_user == host.hostname then
  237. -- host sent the message, room is closed
  238. gui.addmessage(their_user .. " closed the room.")
  239. host.close()
  240. error(their_user .. " closed the room.")
  241. else
  242. -- client sent the message, room is still open
  243. gui.addmessage(their_user .. " left the room.")
  244. printOutput(their_user .. " left the room.")
  245. -- disconnect if player is connected directly
  246. if host.users[their_user] then
  247. local their_id = host.users[their_user]
  248. host.client_ping[their_id] = nil
  249. host.clients[their_id]:close()
  250. host.clients[their_id] = nil
  251. host.users[their_user] = nil
  252. end
  253. end
  254. elseif (received_message_type == messenger.PING) then
  255. host.client_ping[clientID] = 4
  256. elseif (received_message_type == nil) then
  257. --no message received
  258. else
  259. error("Unexpected message type received.")
  260. end
  261. end
  262.  
  263. coroutine.yield()
  264. end
  265. end
  266.  
  267. return sync
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement