├── .cider ├── fromCorona.cider └── toCorona.cider ├── TutorialFiles ├── Options │ ├── .cider │ │ ├── toCorona.cider │ │ └── fromCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── Template │ ├── .cider │ │ ├── fromCorona.cider │ │ └── toCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── CustomBroadcasts │ ├── .cider │ │ ├── toCorona.cider │ │ └── fromCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── FileTransfers │ ├── .cider │ │ ├── fromCorona.cider │ │ └── toCorona.cider │ ├── Icon.png │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── PriorityCallbacks │ ├── .cider │ │ ├── toCorona.cider │ │ └── fromCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── QuickStartClient │ ├── .cider │ │ ├── toCorona.cider │ │ └── fromCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── Server (Mekhu-PC's conflicted copy 2012-04-06).lua │ ├── Client (ricebowl-acer's conflicted copy 2012-04-10).lua │ ├── Server (ricebowl-acer's conflicted copy 2012-04-10).lua │ ├── Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua │ ├── Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua │ ├── build.settings │ └── main.lua ├── QuickStartServer │ ├── .cider │ │ ├── toCorona.cider │ │ └── fromCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── Server (Mekhu-PC's conflicted copy 2012-04-06).lua │ ├── Client (ricebowl-acer's conflicted copy 2012-04-10).lua │ ├── Server (ricebowl-acer's conflicted copy 2012-04-10).lua │ ├── Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua │ ├── Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua │ ├── build.settings │ ├── main.lua │ ├── main (ricebowl-acer's conflicted copy 2012-04-10).lua │ └── main (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua └── SimpleMultipong │ ├── .cider │ ├── fromCorona.cider │ └── toCorona.cider │ ├── player2 │ ├── .cider │ │ ├── fromCorona.cider │ │ └── toCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ ├── main.lua │ └── main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua │ ├── player3 │ ├── .cider │ │ ├── fromCorona.cider │ │ └── toCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ ├── main.lua │ └── main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua │ ├── player2 - Copy │ ├── .cider │ │ ├── fromCorona.cider │ │ └── toCorona.cider │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ ├── main.lua │ └── main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua │ ├── Client.lua │ ├── Server.lua │ ├── build.settings │ └── main.lua ├── DocumentationV120.pdf ├── main.lua ├── testServerTCP.php ├── Readme.txt └── Client.lua /.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/Options/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/Options/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/Template/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/Template/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/.cider/fromCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/.cider/toCorona.cider: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /DocumentationV120.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/DocumentationV120.pdf -------------------------------------------------------------------------------- /TutorialFiles/Options/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/Options/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/Options/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/Options/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/Template/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/Template/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/Template/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/Template/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/FileTransfers/Icon.png -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/FileTransfers/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/FileTransfers/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/CustomBroadcasts/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/CustomBroadcasts/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/PriorityCallbacks/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/PriorityCallbacks/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player2/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player2/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player3/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player3/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/Client.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player2 - Copy/Client.lua -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/Server.lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/SimpleMultipong/player2 - Copy/Server.lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Server (Mekhu-PC's conflicted copy 2012-04-06).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Server (Mekhu-PC's conflicted copy 2012-04-06).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Server (Mekhu-PC's conflicted copy 2012-04-06).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Server (Mekhu-PC's conflicted copy 2012-04-06).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Client (ricebowl-acer's conflicted copy 2012-04-10).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Client (ricebowl-acer's conflicted copy 2012-04-10).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Server (ricebowl-acer's conflicted copy 2012-04-10).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Server (ricebowl-acer's conflicted copy 2012-04-10).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Client (ricebowl-acer's conflicted copy 2012-04-10).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Client (ricebowl-acer's conflicted copy 2012-04-10).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Server (ricebowl-acer's conflicted copy 2012-04-10).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Server (ricebowl-acer's conflicted copy 2012-04-10).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartClient/Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Client (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mydevelopergames/AutoLAN/HEAD/TutorialFiles/QuickStartServer/Server (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua -------------------------------------------------------------------------------- /TutorialFiles/Options/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/Template/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/build.settings: -------------------------------------------------------------------------------- 1 | -- Supported values for orientation: 2 | -- portrait, portraitUpsideDown, landscapeLeft, landscapeRight 3 | 4 | settings = { 5 | 6 | orientation = { 7 | default = "portrait", 8 | supported = { "portrait", } 9 | }, 10 | 11 | iphone = { 12 | plist = { 13 | UIStatusBarHidden = false, 14 | UIPrerenderedIcon = true, -- set to false for "shine" overlay 15 | UIApplicationExitsOnSuspend = true, 16 | } 17 | }, 18 | 19 | --[[ For Android: 20 | 21 | androidPermissions = { 22 | "android.permission.INTERNET", 23 | }, 24 | ]]-- 25 | } 26 | -------------------------------------------------------------------------------- /TutorialFiles/Options/main.lua: -------------------------------------------------------------------------------- 1 | server:setOptions{applicationName = "someUniqueName"} 2 | client:setOptions{applicationName = "someUniqueName"} 3 | ---------------------------------------------------------------------------------------------------------- 4 | ----------------------------Client Specific Options------------------------------------------------------- 5 | ---------------------------------------------------------------------------------------------------------- 6 | function client:setOptions(params) 7 | timeoutTime = params.timeoutTime or timeoutTime --number of ms to wait before the server is considered dead 8 | applicationName = params.applicationName or applicationName --the name of the application. set this to prevent other autoLAN applications from discovering you 9 | circularBufferSize = params.circularBufferSize or circularBufferSize --number of elements to store in the circular buffer for high priority messages and files 10 | packetSize = params.packetSize or packetSize --size of packets for files 11 | end 12 | ---------------------------------------------------------------------------------------------------------- 13 | ----------------------------Server Specific Options------------------------------------------------------- 14 | ---------------------------------------------------------------------------------------------------------- 15 | function server:setOptions(params) 16 | broadcastTime = params.broadcastTime or broadcastTime --number of milliseconds between UDP broadcasts for network discovery 17 | applicationName = params.applicationName or applicationName --the name of the application. set this to prevent other autoLAN applications from discovering you 18 | customBroadcast = params.customBroadcast or customBroadcast --custom broadcast, tells clients about the state of the server 19 | connectTime = params.connectTime or connectTime --frequency to look for new clients 20 | timeoutTime = params.timeoutTime or timeoutTime --number of cycles to wait before client is DC 21 | circularBufferSize = params.circularBufferSize or circularBufferSize --max number of elements in circular buffer for high priorirty messages and files 22 | packetSize = params.packetSize or packetSize --size of packets for files 23 | end -------------------------------------------------------------------------------- /TutorialFiles/FileTransfers/main.lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START SERVER, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Client Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local client = require "Client" 7 | client.start() 8 | client.autoConnect() 9 | 10 | ---------------------------------------------------------------------------------------------------------- 11 | ----------------------------Client Specific Listeners----------------------------------------------------- 12 | ---------------------------------------------------------------------------------------------------------- 13 | local function autolanConnected(event) 14 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 15 | print("serverIP," ,event.serverIP) --this is the user defined broadcast recieved from the server, it tells us about the server state. 16 | --now that we have a connecton, let us just constantly send stuff to the server as an example 17 | print("connection established") 18 | --NOW LET US SEND THE FILE------------------ 19 | client:sendFile("Icon.png", system.ResourcesDirectory) 20 | --client:sendFile("Icon.png", system.ResourcesDirectory, "otherFilename.png") --you can also specify the name on the receiving end 21 | --- this will trigger a file received event on the server when it is completed. 22 | end 23 | Runtime:addEventListener("autolanConnected", autolanConnected) 24 | 25 | local function autolanServerFound(event) 26 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 27 | print("server name," ,event.serverName) --this is the name of the server device (from system.getInfo()). if you need more details just put whatever you need in the customBrodcast 28 | print("server IP:", event.serverIP) --this is the server IP, you must store this in an external table to connect to it later 29 | print("autolanServerFound") 30 | end 31 | Runtime:addEventListener("autolanServerFound", autolanServerFound) 32 | 33 | local function autolanDisconnected(event) 34 | print("disconnected b/c ", event.message) --this can be "closed", "timeout", or "user disonnect" 35 | print("serverIP ", event.serverIP) --this can be "closed", "timeout", or "user disonnect" 36 | print("autolanDisconnected") 37 | end 38 | Runtime:addEventListener("autolanDisconnected", autolanDisconnected) 39 | 40 | local function autolanReceived(event) 41 | print("message = ", event.message) --this is the message we recieved from the server 42 | print("autolanReceived") 43 | end 44 | Runtime:addEventListener("autolanReceived", autolanReceived) 45 | 46 | local function autolanFileReceived(event) 47 | print("filename = ", event.filename) --this is the filename in the system.documents directory 48 | print("autolanFileReceived") 49 | end 50 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) 51 | 52 | local function autolanConnectionFailed(event) 53 | print("serverIP = ", event.serverIP) --this indicates that the server went offline between discovery and connection. the serverIP is returned so you can remove it form your list 54 | print("autolanConnectionFailed") 55 | end 56 | Runtime:addEventListener("autolanConnectionFailed", autolanConnectionFailed) 57 | 58 | 59 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartClient/main.lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START SERVER, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Client Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local client = require "Client" 7 | client:start() 8 | client:autoConnect() 9 | ---and thats it! you will be notified when a connection is availible in the event listener and you will be notified 10 | --when you receive something in the listeners as well 11 | 12 | 13 | 14 | ---------------------------------------------------------------------------------------------------------- 15 | ----------------------------Client Specific Listeners----------------------------------------------------- 16 | ---------------------------------------------------------------------------------------------------------- 17 | local function autolanConnected(event) 18 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 19 | print("serverIP," ,event.serverIP) --this is the user defined broadcast recieved from the server, it tells us about the server state. 20 | --now that we have a connecton, let us just constantly send stuff to the server as an example 21 | local function sendStuff() 22 | client:send("hello world, the time here is"..system.getTimer()) 23 | end 24 | Runtime:addEventListener("enterFrame", sendStuff) 25 | print("connection established") 26 | end 27 | Runtime:addEventListener("autolanConnected", autolanConnected) 28 | 29 | local function autolanServerFound(event) 30 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 31 | print("server name," ,event.serverName) --this is the name of the server device (from system.getInfo()). if you need more details just put whatever you need in the customBrodcast 32 | print("server IP:", event.serverIP) --this is the server IP, you must store this in an external table to connect to it later 33 | print("autolanServerFound") 34 | end 35 | Runtime:addEventListener("autolanServerFound", autolanServerFound) 36 | 37 | local function autolanDisconnected(event) 38 | print("disconnected b/c ", event.message) --this can be "closed", "timeout", or "user disonnect" 39 | print("serverIP ", event.serverIP) --this can be "closed", "timeout", or "user disonnect" 40 | print("autolanDisconnected") 41 | end 42 | Runtime:addEventListener("autolanDisconnected", autolanDisconnected) 43 | 44 | local function autolanReceived(event) 45 | print("message = ", event.message) --this is the message we recieved from the server 46 | print("autolanReceived") 47 | end 48 | Runtime:addEventListener("autolanReceived", autolanReceived) 49 | 50 | local function autolanFileReceived(event) 51 | print("filename = ", event.filename) --this is the filename in the system.documents directory 52 | print("autolanFileReceived") 53 | end 54 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) 55 | 56 | local function autolanConnectionFailed(event) 57 | print("serverIP = ", event.serverIP) --this indicates that the server went offline between discovery and connection. the serverIP is returned so you can remove it form your list 58 | print("autolanConnectionFailed") 59 | end 60 | Runtime:addEventListener("autolanConnectionFailed", autolanConnectionFailed) 61 | 62 | 63 | -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/main.lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START CLIENT, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Server Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local server = require "Server" 7 | server:start() 8 | ---and thats it! you will be notified when a connection is availible in the event listener and you will also start receiving data in the listeners. 9 | local clients = {} --table to store all of our client objects. 10 | local numClients = 0 11 | 12 | --lets just send stuff to all our clients 13 | local function sendStuff() 14 | for i,client in pairs(clients) do 15 | client:send("this server has been up for"..system.getTimer()) 16 | end 17 | end 18 | Runtime:addEventListener("enterFrame", sendStuff) 19 | ---------------------------------------------------------------------------------------------------------- 20 | ----------------------------Server Specific Listeners----------------------------------------------------- 21 | ---------------------------------------------------------------------------------------------------------- 22 | local function autolanPlayerJoined(event)ent 23 | --print("client object: ", client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 24 | --now lets save the client object so we can use it in the future to send messages 25 | clients[client] = client --trick, we can use the table object itself as the key, this will make it easier to determine which client we received a message from 26 | numClients = numClients + 1 27 | client.myJoinTime = system.getTimer() --you can add whatever values you want to the table to retrieve it later in the receved listener 28 | client.myName = "Player "..numClients 29 | --we can begin using the client object to send messages now! 30 | --client:send("Hello Player!") 31 | print("autolanPlayerJoined") 32 | end 33 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 34 | 35 | local function autolanPlayerDropped(event) 36 | local client = event.client 37 | local client = event.cli 38 | print("client object ", client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 39 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 40 | --now let us remove the client from our list 41 | print(clients[client].myName.." Dropped, connection was active for "..system.getTimer()-clients[client].myJoinTime) 42 | clients[client] = nil --clear references to prevent memory leaks 43 | numClients = numClients - 1 44 | 45 | end 46 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 47 | 48 | local function autolanReceived(event) 49 | local client = event.client 50 | --print("Message :"..event.message.." from client: "..client.myName ) --myName is our own property set in the playerJoined event 51 | --we can use the client object here to react to the message 52 | client:send("Recieved it!, thanks!") 53 | end 54 | Runtime:addEventListener("autolanReceived", autolanReceived) 55 | 56 | local function autolanFileReceived(event) 57 | print("filename = ", event.filename) --this is the filename in the system.documents directory 58 | print("autolanFileReceived") 59 | end 60 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/main (ricebowl-acer's conflicted copy 2012-04-10).lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START CLIENT, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Server Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local server = require "Server" 7 | server:start() 8 | ---and thats it! you will be notified when a connection is availible in the event listener and you will also start receiving data in the listeners. 9 | local clients = {} --table to store all of our client objects. 10 | local numClients = 0 11 | 12 | --lets just send stuff to all our clients 13 | local function sendStuff() 14 | for i,client in pairs(clients) do 15 | client:send("this server has been up for"..system.getTimer()) 16 | end 17 | end 18 | Runtime:addEventListener("enterFrame", sendStuff) 19 | ---------------------------------------------------------------------------------------------------------- 20 | ----------------------------Server Specific Listeners----------------------------------------------------- 21 | ---------------------------------------------------------------------------------------------------------- 22 | local function autolanPlayerJoined(event) 23 | local client = event.client 24 | --print("client object: ", client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 25 | --now lets save the client object so we can use it in the future to send messages 26 | clients[client] = client --trick, we can use the table object itself as the key, this will make it easier to determine which client we received a message from 27 | numClients = numClients + 1 28 | client.myJoinTime = system.getTimer() --you can add whatever values you want to the table to retrieve it later in the receved listener 29 | client.myName = "Player "..numClients 30 | --we can begin using the client object to send messages now! 31 | --client:send("Hello Player!") 32 | print("autolanPlayerJoined") 33 | end 34 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 35 | 36 | local function autolanPlayerDropped(event) 37 | local client = event.client 38 | print("client object ", client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 39 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 40 | --now let us remove the client from our list 41 | print(clients[client].myName.." Dropped, connection was active for "..system.getTimer()-clients[client].myJoinTime) 42 | clients[client] = nil --clear references to prevent memory leaks 43 | numClients = numClients - 1 44 | end 45 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 46 | 47 | local function autolanReceived(event) 48 | local client = event.client 49 | print("Message :"..event.message.." from client: "..client.myName ) --myName is our own property set in the playerJoined event 50 | --we can use the client object here to react to the message 51 | --client:send("Recieved it!, thanks!") 52 | end 53 | Runtime:addEventListener("autolanReceived", autolanReceived) 54 | 55 | local function autolanFileReceived(event) 56 | print("filename = ", event.filename) --this is the filename in the system.documents directory 57 | print("autolanFileReceived") 58 | end 59 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /TutorialFiles/QuickStartServer/main (I-HATE-MACINTRASHs-Mac's conflicted copy 2012-04-05).lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START CLIENT, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Server Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local server = require "Server" 7 | server:start() 8 | ---and thats it! you will be notified when a connection is availible in the event listener and you will also start receiving data in the listeners. 9 | local clients = {} --table to store all of our client objects. 10 | local numClients = 0 11 | 12 | --lets just send stuff to all our clients 13 | local function sendStuff() 14 | for i,client in pairs(clients) do 15 | client:send("this server has been up for"..system.getTimer()) 16 | end 17 | end 18 | Runtime:addEventListener("enterFrame", sendStuff) 19 | ---------------------------------------------------------------------------------------------------------- 20 | ----------------------------Server Specific Listeners----------------------------------------------------- 21 | ---------------------------------------------------------------------------------------------------------- 22 | local function autolanPlayerJoined(event) 23 | local client = event.client 24 | --print("client object: ", client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 25 | --now lets save the client object so we can use it in the future to send messages 26 | clients[client] = client --trick, we can use the table object itself as the key, this will make it easier to determine which client we received a message from 27 | numClients = numClients + 1 28 | client.myJoinTime = system.getTimer() --you can add whatever values you want to the table to retrieve it later in the receved listener 29 | client.myName = "Player "..numClients 30 | --we can begin using the client object to send messages now! 31 | --client:send("Hello Player!") 32 | print("autolanPlayerJoined") 33 | end 34 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 35 | 36 | local function autolanPlayerDropped(event) 37 | local client = event.client 38 | print("client object ", client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 39 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 40 | --now let us remove the client from our list 41 | print(clients[client].myName.." Dropped, connection was active for "..system.getTimer()-clients[client].myJoinTime) 42 | clients[client] = nil --clear references to prevent memory leaks 43 | numClients = numClients - 1 44 | end 45 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 46 | 47 | local function autolanReceived(event) 48 | local client = event.client 49 | print("Message :"..event.message.." from client: "..client.myName ) --myName is our own property set in the playerJoined event 50 | --we can use the client object here to react to the message 51 | --client:send("Recieved it!, thanks!") 52 | end 53 | Runtime:addEventListener("autolanReceived", autolanReceived) 54 | 55 | local function autolanFileReceived(event) 56 | print("filename = ", event.filename) --this is the filename in the system.documents directory 57 | print("autolanFileReceived") 58 | end 59 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /TutorialFiles/PriorityCallbacks/main.lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START SERVER, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Client Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local client = require "Client" 7 | client:start() 8 | client:autoConnect() 9 | 10 | --the following is called when we send a priority message and when we get confirmation that it was received 11 | local function priorityCallback(e) 12 | if(e.phase == "complete") then 13 | print("priority message sent and acknowledged") 14 | elseif(e.phase == "cancelled") then 15 | print("message not sent, connection timed out or was closed") 16 | end 17 | client:sendPriority("hello world, the time here is"..system.getTimer(), {callback = priorityCallback}) --this will send packets as fast as they are acknowledged 18 | end 19 | 20 | ---------------------------------------------------------------------------------------------------------- 21 | ----------------------------Client Specific Listeners----------------------------------------------------- 22 | ---------------------------------------------------------------------------------------------------------- 23 | local function autolanConnected(event) 24 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 25 | print("serverIP," ,event.serverIP) --this is the user defined broadcast recieved from the server, it tells us about the server state. 26 | --now that we have a connecton, let us just constantly send stuff to the server as an example 27 | client:sendPriority("hello world, the time here is"..system.getTimer(), {callback = priorityCallback}) 28 | print("connection established") 29 | end 30 | Runtime:addEventListener("autolanConnected", autolanConnected) 31 | 32 | local function autolanServerFound(event) 33 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 34 | print("server name," ,event.serverName) --this is the name of the server device (from system.getInfo()). if you need more details just put whatever you need in the customBrodcast 35 | print("server IP:", event.serverIP) --this is the server IP, you must store this in an external table to connect to it later 36 | print("autolanServerFound") 37 | end 38 | Runtime:addEventListener("autolanServerFound", autolanServerFound) 39 | 40 | local function autolanDisconnected(event) 41 | print("disconnected b/c ", event.message) --this can be "closed", "timeout", or "user disonnect" 42 | print("serverIP ", event.serverIP) --this can be "closed", "timeout", or "user disonnect" 43 | print("autolanDisconnected") 44 | end 45 | Runtime:addEventListener("autolanDisconnected", autolanDisconnected) 46 | 47 | local function autolanReceived(event) 48 | print("message = ", event.message) --this is the message we recieved from the server 49 | print("autolanReceived") 50 | end 51 | Runtime:addEventListener("autolanReceived", autolanReceived) 52 | 53 | local function autolanFileReceived(event) 54 | print("filename = ", event.filename) --this is the filename in the system.documents directory 55 | print("autolanFileReceived") 56 | end 57 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) 58 | 59 | local function autolanConnectionFailed(event) 60 | print("serverIP = ", event.serverIP) --this indicates that the server went offline between discovery and connection. the serverIP is returned so you can remove it form your list 61 | print("autolanConnectionFailed") 62 | end 63 | Runtime:addEventListener("autolanConnectionFailed", autolanConnectionFailed) 64 | 65 | 66 | -------------------------------------------------------------------------------- /TutorialFiles/CustomBroadcasts/main.lua: -------------------------------------------------------------------------------- 1 | --THIS CODE IS DESIGNED TO WORK WITH THE QUICK START CLIENT, PLEASE OPEN THAT AS WELL 2 | ---------------------------------------------------------------------------------------------------------- 3 | ----------------------------Server Specific Startup------------------------------------------------------- 4 | ---------------------------------------------------------------------------------------------------------- 5 | 6 | local server = require "Server" 7 | server:start() 8 | server:setCustomBroadcast("0 Players") 9 | ---and thats it! you will be notified when a connection is availible in the event listener and you will also start receiving data in the listeners. 10 | local clients = {} --table to store all of our client objects. 11 | local numClients = 0 12 | 13 | --lets just send stuff to all our clients 14 | local function sendStuff() 15 | for i,client in pairs(clients) do 16 | client:send("this server has been up for"..system.getTimer()) 17 | end 18 | end 19 | Runtime:addEventListener("enterFrame", sendStuff) 20 | ---------------------------------------------------------------------------------------------------------- 21 | ----------------------------Server Specific Listeners----------------------------------------------------- 22 | ---------------------------------------------------------------------------------------------------------- 23 | local function autolanPlayerJoined(event) 24 | local client = event.client 25 | --print("client object: ", client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 26 | --now lets save the client object so we can use it in the future to send messages 27 | clients[client] = client --trick, we can use the table object itself as the key, this will make it easier to determine which client we received a message from 28 | numClients = numClients + 1 29 | client.myJoinTime = system.getTimer() --you can add whatever values you want to the table to retrieve it later in the receved listener 30 | client.myName = "Player "..numClients 31 | --now let us update the custom broadcast to reflect the new server state 32 | server:setCustomBroadcast(numClients .. " Players") 33 | print("autolanPlayerJoined") 34 | end 35 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 36 | 37 | local function autolanPlayerDropped(event) 38 | local client = event.client 39 | print("client object ", client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 40 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 41 | --now let us remove the client from our list 42 | print(clients[client].myName.." Dropped, connection was active for "..system.getTimer()-clients[client].myJoinTime) 43 | clients[client] = nil --clear references to prevent memory leaks 44 | numClients = numClients - 1 45 | --now let us update the custom broadcast to reflect the new server state 46 | server:setCustomBroadcast(numClients .. " Players") 47 | end 48 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 49 | 50 | local function autolanReceived(event) 51 | local client = event.client 52 | print("Message :"..event.message.." from client: "..client.myName ) --myName is our own property set in the playerJoined event 53 | --we can use the client object here to react to the message 54 | --client:send("Recieved it!, thanks!") 55 | end 56 | Runtime:addEventListener("autolanReceived", autolanReceived) 57 | 58 | local function autolanFileReceived(event) 59 | print("filename = ", event.filename) --this is the filename in the system.documents directory 60 | print("autolanFileReceived") 61 | end 62 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /main.lua: -------------------------------------------------------------------------------- 1 | --This is a useful file to use as a template. All event listeners are here, you may copy and paste the ones that you need. 2 | 3 | ---------------------------------------------------------------------------------------------------------- 4 | ----------------------------Client Specific Listeners----------------------------------------------------- 5 | ---------------------------------------------------------------------------------------------------------- 6 | local function autolanConnected(event) 7 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 8 | print("serverIP," ,event.serverIP) --this is the user defined broadcast recieved from the server, it tells us about the server state. 9 | print("connection established") 10 | end 11 | Runtime:addEventListener("autolanConnected", autolanConnected) 12 | 13 | local function autolanServerFound(event) 14 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 15 | print("server name," ,event.serverName) --this is the name of the server device (from system.getInfo()). if you need more details just put whatever you need in the customBrodcast 16 | print("server IP:", event.serverIP) --this is the server IP, you must store this in an external table to connect to it later 17 | print("autolanServerFound") 18 | end 19 | Runtime:addEventListener("autolanServerFound", autolanServerFound) 20 | 21 | local function autolanDisconnected(event) 22 | print("disconnected b/c ", event.message) --this can be "closed", "timeout", or "user disonnect" 23 | print("serverIP ", event.serverIP) --this can be "closed", "timeout", or "user disonnect" 24 | print("autolanDisconnected") 25 | end 26 | Runtime:addEventListener("autolanDisconnected", autolanDisconnected) 27 | 28 | local function autolanReceived(event) 29 | print("message = ", event.message) --this is the message we recieved from the server 30 | print("autolanReceived") 31 | end 32 | Runtime:addEventListener("autolanReceived", autolanReceived) 33 | 34 | local function autolanFileReceived(event) 35 | print("filename = ", event.filename) --this is the filename in the system.documents directory 36 | print("autolanFileReceived") 37 | end 38 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) 39 | 40 | local function autolanConnectionFailed(event) 41 | print("serverIP = ", event.serverIP) --this indicates that the server went offline between discovery and connection. the serverIP is returned so you can remove it form your list 42 | print("autolanConnectionFailed") 43 | end 44 | Runtime:addEventListener("autolanConnectionFailed", autolanConnectionFailed) 45 | 46 | ---------------------------------------------------------------------------------------------------------- 47 | ----------------------------Server Specific Listeners----------------------------------------------------- 48 | ---------------------------------------------------------------------------------------------------------- 49 | local function autolanPlayerJoined(event) 50 | print("client object: ", event.client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 51 | print("autolanPlayerJoined") 52 | end 53 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 54 | 55 | local function autolanPlayerDropped(event) 56 | print("client object ", event.client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 57 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 58 | print("autolanPlayerDropped") 59 | end 60 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 61 | 62 | local function autolanReceived(event) 63 | print("broadcast", event.client) --this is the object representing the connection. This is the same object given during the playerJoined event and you can use this to find out which client this is coming from 64 | print("message," ,event.message) --this is the message from the client. You must use event.client to find out who it came from. 65 | print("autolanReceived") 66 | end 67 | Runtime:addEventListener("autolanReceived", autolanReceived) 68 | 69 | local function autolanFileReceived(event) 70 | print("filename = ", event.filename) --this is the filename in the system.documents directory 71 | print("autolanFileReceived") 72 | end 73 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /TutorialFiles/Template/main.lua: -------------------------------------------------------------------------------- 1 | --This is a useful file to use as a template. All event listeners are here, you may copy and paste the ones that you need. 2 | 3 | ---------------------------------------------------------------------------------------------------------- 4 | ----------------------------Client Specific Listeners----------------------------------------------------- 5 | ---------------------------------------------------------------------------------------------------------- 6 | local function autolanConnected(event) 7 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 8 | print("serverIP," ,event.serverIP) --this is the user defined broadcast recieved from the server, it tells us about the server state. 9 | print("connection established") 10 | end 11 | Runtime:addEventListener("autolanConnected", autolanConnected) 12 | 13 | local function autolanServerFound(event) 14 | print("broadcast", event.customBroadcast) --this is the user defined broadcast recieved from the server, it tells us about the server state. 15 | print("server name," ,event.serverName) --this is the name of the server device (from system.getInfo()). if you need more details just put whatever you need in the customBrodcast 16 | print("server IP:", event.serverIP) --this is the server IP, you must store this in an external table to connect to it later 17 | print("autolanServerFound") 18 | end 19 | Runtime:addEventListener("autolanServerFound", autolanServerFound) 20 | 21 | local function autolanDisconnected(event) 22 | print("disconnected b/c ", event.message) --this can be "closed", "timeout", or "user disonnect" 23 | print("serverIP ", event.serverIP) --this can be "closed", "timeout", or "user disonnect" 24 | print("autolanDisconnected") 25 | end 26 | Runtime:addEventListener("autolanDisconnected", autolanDisconnected) 27 | 28 | local function autolanReceived(event) 29 | print("message = ", event.message) --this is the message we recieved from the server 30 | print("autolanReceived") 31 | end 32 | Runtime:addEventListener("autolanReceived", autolanReceived) 33 | 34 | local function autolanFileReceived(event) 35 | print("filename = ", event.filename) --this is the filename in the system.documents directory 36 | print("autolanFileReceived") 37 | end 38 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) 39 | 40 | local function autolanConnectionFailed(event) 41 | print("serverIP = ", event.serverIP) --this indicates that the server went offline between discovery and connection. the serverIP is returned so you can remove it form your list 42 | print("autolanConnectionFailed") 43 | end 44 | Runtime:addEventListener("autolanConnectionFailed", autolanConnectionFailed) 45 | 46 | ---------------------------------------------------------------------------------------------------------- 47 | ----------------------------Server Specific Listeners----------------------------------------------------- 48 | ---------------------------------------------------------------------------------------------------------- 49 | local function autolanPlayerJoined(event) 50 | print("client object: ", event.client) --this represents the connection to the client. you can use this to send messages and files to the client. You should save this in a table somewhere. 51 | print("autolanPlayerJoined") 52 | end 53 | Runtime:addEventListener("autolanPlayerJoined", autolanPlayerJoined) 54 | 55 | local function autolanPlayerDropped(event) 56 | print("client object ", event.client) --this is the reference to the client object you use to send messages to the client, you can use this to findout who dropped and react accordingly 57 | print("dropped b/c ," ,event.message) --this is the user defined broadcast recieved from the server, it tells us about the server state. 58 | print("autolanPlayerDropped") 59 | end 60 | Runtime:addEventListener("autolanPlayerDropped", autolanPlayerDropped) 61 | 62 | local function autolanReceived(event) 63 | print("broadcast", event.client) --this is the object representing the connection. This is the same object given during the playerJoined event and you can use this to find out which client this is coming from 64 | print("message," ,event.message) --this is the message from the client. You must use event.client to find out who it came from. 65 | print("autolanReceived") 66 | end 67 | Runtime:addEventListener("autolanReceived", autolanReceived) 68 | 69 | local function autolanFileReceived(event) 70 | print("filename = ", event.filename) --this is the filename in the system.documents directory 71 | print("autolanFileReceived") 72 | end 73 | Runtime:addEventListener("autolanFileReceived", autolanFileReceived) -------------------------------------------------------------------------------- /testServerTCP.php: -------------------------------------------------------------------------------- 1 | locate($clientIP); 43 | $client[$clientIP.$clientPort]["longitude"] = $geoplugin->longitude; 44 | $client[$clientIP.$clientPort]["latitude"] = $geoplugin->latitude; 45 | echo "New client connected $j, with ip $clientIP, port $clientPort"."\n"; 46 | 47 | } 48 | } 49 | 50 | if (@socket_recvfrom($sockUDP, $string, 999999, MSG_DONTWAIT, $from, $port) === 0) 51 | { 52 | } else { 53 | while($string){ 54 | $decoded = json_decode($string); 55 | // var_dump($decoded); 56 | if($decoded[2] == "cs"){ 57 | //here we inform the target client that UDP packets are on the way and to start listening for these packets. 58 | echo "got server UDP message $string"."\n"; 59 | socket_sendto($sockUDP, json_encode(array("c", $from, $port))."\n",9999,0,$decoded[3], $decoded[4]); //n for new connection 60 | } 61 | elseif($decoded[2] == "cc"){ 62 | //the client is informing us to send a connect signal to the server (first we send via tcp) 63 | echo "got client UDP message $string"."\n"; 64 | socket_write($client[$decoded[3]]["socket"], json_encode(array("n", $from, $port))."\n"); //n for new connection 65 | } 66 | // socket_sendto($sockUDP,$string, strlen($string), 0, $from, $port); //echo back via udp 67 | unset($string); 68 | @socket_recvfrom($sockUDP, $string, 999999, MSG_DONTWAIT, $from, $port); 69 | 70 | } 71 | 72 | } 73 | 74 | if (count($client)) 75 | { 76 | foreach ($client as $k => &$v) 77 | { 78 | 79 | 80 | if (@socket_recv($v["socket"], $strings, 999999, MSG_DONTWAIT) === 0) 81 | { 82 | echo "connection closed"."\n"; 83 | socket_close($v["socket"]); 84 | echo "unsetting client $k".count($servers[$v["application"]])."\n"; 85 | unset($servers[$v["application"]][$k]); 86 | echo "unsetting client $k".$v["application"]."\n"; 87 | unset($client[$k]); 88 | unset($v); 89 | continue; 90 | } 91 | else { 92 | 93 | foreach(explode("\n", $strings) as $key => $string) { 94 | 95 | $decoded = json_decode($string); 96 | //var_dump($decoded); 97 | 98 | //the first packet must tell if we are a client or a server 99 | if($decoded and $decoded[0] == "CoronaAutoInternet"){ 100 | //decode message type 101 | if($decoded[2]=="s"){ 102 | //add this to the server list 103 | $v["application"] = $decoded[1]; 104 | $v["deviceName"] = $decoded[3]; 105 | $v["customBroadcast"] = $decoded[4]; 106 | $servers[$decoded[1]][$k] = $v; //decoded[1] is the application id 107 | echo "added to server $string".count($servers[$decoded[1]]).count($servers[$v["application"]])."\n"; 108 | } 109 | elseif($decoded[2]=="c"){ 110 | echo "client detected"."\n"; 111 | //this is a client, sort the lists by geographic distance and return a list of servers and close the connection 112 | //create a array of distance to all servers with same application id 113 | $index = 0; 114 | $clientLat = $v["latitude"]; 115 | $clientLong = $v["longitude"]; 116 | $j = 0; 117 | foreach ($servers[$decoded[1]] as $key => $server){ 118 | $deltaLat = $server["latitude"] - $clientLat; 119 | $deltaLong = $server["longitude"] - $clientLong; 120 | $distanceTable[$key] = $deltaLat*$deltaLat+$deltaLong*$deltaLong; 121 | //TESTING ONLY send all currently availible servers 122 | $sendServers[$j++] = array($server["ip"],$server["port"],$server["deviceName"],$server["customBroadcast"]); 123 | } 124 | @socket_write($v["socket"], json_encode(array("l",$sendServers))."\n");//l for listing, a list of availible servers to connect to. 125 | unset($j); 126 | unset($sendServers); 127 | asort($distanceTable); 128 | } 129 | 130 | } 131 | } 132 | } 133 | } 134 | } 135 | 136 | //echo "."; 137 | 138 | usleep(1000000); 139 | } 140 | 141 | // Close the master sockets 142 | socket_close($sock); 143 | ?> -------------------------------------------------------------------------------- /Readme.txt: -------------------------------------------------------------------------------- 1 | Apache License v 2.0 2 | 3 | Version 2.0, January 2004 4 | 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. 16 | 17 | "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. 18 | 19 | "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. 20 | 21 | "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. 22 | 23 | "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). 24 | 25 | "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. 26 | 27 | "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." 28 | 29 | "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 30 | 31 | 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 32 | 33 | 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 34 | 35 | 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: 36 | 37 | You must give any other recipients of the Work or Derivative Works a copy of this License; and 38 | You must cause any modified files to carry prominent notices stating that You changed the files; and 39 | You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and 40 | If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. 41 | 42 | You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 43 | 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 44 | 45 | 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 46 | 47 | 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 48 | 49 | 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 50 | 51 | 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. 52 | 53 | END OF TERMS AND CONDITIONS 54 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/main.lua: -------------------------------------------------------------------------------- 1 | 2 | ----------------------------------------------------------------------------------------- 3 | -- 4 | -- main.lua 5 | -- 6 | ----------------------------------------------------------------------------------------- 7 | display.setStatusBar( display.HiddenStatusBar ) 8 | -- forward declarations 9 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 10 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 11 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 12 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 13 | local upScore, downScore = 0,0 14 | local clients = {} --contains the client objects that represent connections to clients 15 | local physics = require "physics" 16 | physics.start(); physics.setGravity(0,0); --physics.setTimeStep( 1/60 ); 17 | local function downHit(e) 18 | if(e.phase == "began") then 19 | upScore = upScore+1 20 | textUp.text = "Score: "..upScore 21 | end 22 | end 23 | local function upHit(e) 24 | if(e.phase == "began") then 25 | downScore = downScore+1 26 | textDown.text = "Score: "..downScore 27 | end 28 | end 29 | local function createScoreDisplay(group) 30 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 31 | textUp:setTextColor(255) 32 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 33 | textDown:setTextColor(255) 34 | end 35 | local function createWalls(group) 36 | --draw walls 37 | up = display.newRect(group,0,-20,screenW, 20) 38 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 39 | up:addEventListener("collision", upHit) 40 | down = display.newRect(group,0,screenH,screenW, 20) 41 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 42 | down:addEventListener("collision", downHit) 43 | left = display.newRect(group,-20,0,20, screenH) 44 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 45 | right = display.newRect(group,screenW,0,20, screenH) 46 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 47 | end 48 | local function createPaddle(group, x, y, rotation) 49 | local width, height = 120, 30 50 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 51 | paddle:setReferencePoint(display.CenterReferencePoint) 52 | paddle.x, paddle.y = x,y 53 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 54 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 55 | paddle:rotate(180+rotation) 56 | paddle.isFixedRotation = true 57 | paddle:setFillColor(255,100,100) 58 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 59 | paddle.targetX = x 60 | function paddle:setTarget(x) 61 | self.touchJoint:setTarget(x,self.y) 62 | self.targetX = x 63 | end 64 | return paddle 65 | end 66 | local function createBall(group) 67 | local puck = display.newCircle( halfW,halfH,20) 68 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 69 | puck.isBullet = true 70 | puck:setLinearVelocity(200,200) 71 | puck:setFillColor(100,255,100) 72 | group:insert(puck) 73 | return puck 74 | end 75 | 76 | local function makeClient() 77 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 78 | paddleDown:setFillColor(255,100,100) 79 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 80 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 81 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 82 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 83 | ball:removeEventListener("collision", ballCollision) 84 | timer.cancel(sendFullFrameTimer) 85 | isServer = false 86 | end 87 | print("making client") 88 | client = require("Client") 89 | client:start() 90 | client:scanServersInternet() 91 | isClient = true 92 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 93 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 94 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 95 | end 96 | local function makeServer() 97 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 98 | isClient = false 99 | paddleUp:setFillColor(255,100,100) 100 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 101 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 102 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 103 | end 104 | server = require("Server") 105 | server:setCustomBroadcast("1 Player") 106 | server:startInternet() 107 | isServer = true 108 | menuGroup:removeSelf() 109 | paddleDown:setFillColor(100,100,255) 110 | --add event listeners 111 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 112 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 113 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 114 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 115 | ball:addEventListener("collision", ballCollision) 116 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 117 | end 118 | ---------------------------UI OBJECTS-------------------- 119 | local numberOfServers = 0 120 | local function spawnMenu(group) 121 | --functions to handle button events 122 | local joinText 123 | local function joinPressed() 124 | joinText.text = "Scanning..." 125 | makeClient() 126 | end 127 | local function hostPressed() 128 | makeServer() 129 | end 130 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 131 | title:setReferencePoint(display.CenterReferencePoint) 132 | title.x,title.y = halfW, 50 133 | title:setFillColor(100,100,100) 134 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 135 | titleText:setReferencePoint(display.CenterReferencePoint) 136 | titleText.x, titleText.y = halfW, 50 137 | --host button 138 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 139 | host:setFillColor(100,100,100) 140 | host:addEventListener("tap", hostPressed) 141 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 142 | --host button 143 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 144 | join:addEventListener("tap", joinPressed) 145 | join:setFillColor(100,100,100) 146 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 147 | 148 | 149 | local function createListItem(event) --displays found servers 150 | local item = display.newGroup() 151 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 152 | item.background.strokeWidth = 3 153 | item.background:setFillColor(70, 70, 70) 154 | item.background:setStrokeColor(180, 180, 180) 155 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 156 | if(event.internet) then 157 | item.text:setTextColor( 100,100,255 ) 158 | else 159 | item.text:setTextColor( 255 ) 160 | end 161 | item.serverIP = event.serverIP 162 | --attach a touch listener 163 | function item:tap(e) 164 | client:connect(self.serverIP) 165 | menuGroup:removeSelf() 166 | menuGroup = nil 167 | end 168 | item:addEventListener("tap", item) 169 | 170 | item.y = numberOfServers*70+180 171 | numberOfServers = numberOfServers+1 172 | menuGroup:insert(item) 173 | end 174 | Runtime:addEventListener("autolanServerFound", createListItem) 175 | 176 | end 177 | ----create the scene------------------- 178 | createWalls(physicsGroup) 179 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 180 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 181 | ball = createBall(physicsGroup) 182 | createScoreDisplay(UIGroup) 183 | spawnMenu(menuGroup) 184 | 185 | local speed = 350 186 | local function setBallSpeed() 187 | if(ball) then 188 | if(speed < 500) then 189 | speed = speed+.1 190 | end 191 | --get the direction and set the speed 192 | vx,vy = ball:getLinearVelocity() 193 | local direction = math.atan2(vy,vx) 194 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 195 | end 196 | end 197 | Runtime:addEventListener("enterFrame", setBallSpeed) 198 | 199 | ---------------------------------------------------------------------------------------------- 200 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 201 | ---------------------------------------------------------------------------------------------- 202 | local numPlayers = 0 203 | local clients = {} 204 | local function getFullGameState() 205 | local state = {} 206 | state[1] = 2--protocol id 207 | state[2] = paddleUp.targetX 208 | state[3] = paddleDown.targetX 209 | state[4] = ball.x 210 | state[5] = ball.y 211 | vx, vy = ball:getLinearVelocity() 212 | state[6] = vx 213 | state[7] = vy 214 | state[8] = upScore 215 | state[9] = downScore 216 | return state 217 | end 218 | local function getDifferentialGameState() 219 | local state = {} 220 | state[1] = 4--protocol id 221 | state[2] = paddleUp.targetX 222 | state[3] = paddleDown.targetX 223 | return state 224 | end 225 | local function getBallState() 226 | local state = {} 227 | state[1] = 5--protocol id 228 | state[2] = ball.x 229 | state[3] = ball.y 230 | vx, vy = ball:getLinearVelocity() 231 | state[4] = vx 232 | state[5] = vy 233 | return state 234 | end 235 | playerDropped = function(event) 236 | local clientDropped = event.client 237 | --go through the table and find the client that dropped 238 | for i=1, numPlayers do 239 | if(clients[i] == clientDropped) then 240 | table.remove(clients, i) --remove this client 241 | numPlayers = numPlayers - 1 242 | end 243 | end 244 | server:setCustomBroadcast(numPlayers.." Players") 245 | --now let us try to find a spectator client to retake control of the paddle 246 | if(clients[1]) then 247 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 248 | end 249 | print("player dropped because", event.message) 250 | end 251 | addPlayer = function(event) 252 | local client = event.client --this is the client object, used to send messages 253 | print("player joined",client) 254 | --look for a client slot 255 | numPlayers = numPlayers+1 256 | clients[numPlayers] = client 257 | client:sendPriority({1,numPlayers}) --initialization packet 258 | client:sendPriority(getFullGameState()) --initialization packet 259 | server:setCustomBroadcast(numPlayers.." Players") 260 | end 261 | ballCollision = function(event) 262 | if(event.phase == "ended") then 263 | --send ball update packet to all clients 264 | for i=1, numPlayers do 265 | clients[i]:send(getBallState()) 266 | end 267 | end 268 | end 269 | sendFullFrame = function() 270 | for i=1, numPlayers do 271 | clients[i]:send(getFullGameState()) 272 | end 273 | end 274 | serverReceived = function(event) 275 | local message = event.message 276 | --since this message came from a client, it can only be of type 3: player update 277 | paddleUp:setTarget(message[2]) 278 | --now forward a differential update to all clients (some are spectators) 279 | for i=1, numPlayers do 280 | clients[i]:send(getDifferentialGameState()) 281 | end 282 | end 283 | 284 | dragBodyServer = function(e) 285 | local body = e.target 286 | body.touchJoint:setTarget(e.x, body.y) 287 | body.targetX = e.x 288 | if "began" == e.phase then 289 | display.getCurrentStage():setFocus( body, e.id ) 290 | elseif "ended" == e.phase or "cancelled" == e.phase then 291 | display.getCurrentStage():setFocus( body, nil ) 292 | elseif "moved" ==e.phase then 293 | --now forward a differential update to all clients (some are spectators) 294 | for i=1, numPlayers do 295 | clients[i]:send(getDifferentialGameState()) 296 | end 297 | end 298 | end 299 | 300 | ---------------------------------------------------------------------------------------------- 301 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 302 | ---------------------------------------------------------------------------------------------- 303 | 304 | connectionAttemptFailed = function(event) 305 | print("connection failed, redisplay menu") 306 | numberOfServers = 0 307 | menuGroup = display.newGroup() 308 | spawnMenu(menuGroup) 309 | end 310 | 311 | local function connectedToServer(event) 312 | print("connected, waiting for sync") 313 | end 314 | Runtime:addEventListener("autolanConnected", connectedToServer) 315 | 316 | local function getPlayerUpdate() 317 | local state = {} 318 | state[1] = 4--protocol id 319 | state[2] = paddleUp.targetX 320 | return state 321 | end 322 | dragBodyClient = function(e) 323 | local body = e.target 324 | body.touchJoint:setTarget(e.x, body.y) 325 | body.targetX = e.x 326 | if "began" == e.phase then 327 | display.getCurrentStage():setFocus( body, e.id ) 328 | elseif "ended" == e.phase or "cancelled" == e.phase then 329 | display.getCurrentStage():setFocus( body, nil ) 330 | elseif "moved" ==e.phase then 331 | --now forward an update to the server 332 | client:send(getPlayerUpdate()) 333 | end 334 | end 335 | local function restoreBallState(message) 336 | local dx, dy = message[2]-ball.x, message[3]-ball.y 337 | ball:translate(dx,dy) 338 | ball:setLinearVelocity(message[4],message[5]) 339 | end 340 | local ballControl = false 341 | local function restoreGameState(message) 342 | paddleUp:setTarget(message[2]) 343 | paddleDown:setTarget(message[3]) 344 | ball.x, ball.y = message[4], message[5] 345 | ball:setLinearVelocity(message[6],message[7]) 346 | upScore, downScore = message[8], message[9] 347 | textUp.text = "Score: "..upScore 348 | textDown.text = "Score: "..downScore 349 | end 350 | clientReceived = function (event) 351 | local message = event.message 352 | print("message", message, message[1], message[2]) 353 | --figure out packet type 354 | if(message[1] == 1) then 355 | print("got init packet") 356 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 357 | paddleUp:addEventListener("touch", dragBodyClient) 358 | paddleUp:setFillColor(100,100,255) 359 | ballControl = true 360 | end 361 | elseif(message[1] == 2) then 362 | restoreGameState(message) 363 | elseif(message[1] == 4) then 364 | print("got differential packet",message[2],message[3]) 365 | paddleDown:setTarget(message[3]) 366 | if(not ballControl) then 367 | paddleUp:setTarget(message[2]) 368 | end 369 | elseif(message[1] == 5) then 370 | print("got ball update packet") 371 | restoreBallState(message) 372 | end 373 | end 374 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/main.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); --physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/main.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); --physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/main.lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); --physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2/main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player3/main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /TutorialFiles/SimpleMultipong/player2 - Copy/main (Dev TimeSpaceMagic's conflicted copy 2012-02-19).lua: -------------------------------------------------------------------------------- 1 | ----------------------------------------------------------------------------------------- 2 | -- 3 | -- main.lua 4 | -- 5 | ----------------------------------------------------------------------------------------- 6 | display.setStatusBar( display.HiddenStatusBar ) 7 | -- forward declarations 8 | local up,down,left,right, paddleUp, paddleDown, ball, textUp, textDown, client, server, isClient, isServer, myPlayerID 9 | local serverReceived, clientReceived, dragBodyServer, dragBodyClient, ballCollision, sendFullFrame,sendFullFrameTimer, playerDropped, connectionAttemptFailed 10 | local screenW, screenH, halfW, halfH = display.contentWidth, display.contentHeight, display.contentWidth*0.5, display.contentHeight*0.5 11 | local physicsGroup, UIGroup, menuGroup = display.newGroup(), display.newGroup(), display.newGroup() 12 | local upScore, downScore = 0,0 13 | local clients = {} --contains the client objects that represent connections to clients 14 | local physics = require "physics" 15 | physics.start(); physics.setGravity(0,0); physics.setTimeStep( 1/60 ); 16 | local function downHit(e) 17 | if(e.phase == "began") then 18 | upScore = upScore+1 19 | textUp.text = "Score: "..upScore 20 | end 21 | end 22 | local function upHit(e) 23 | if(e.phase == "began") then 24 | downScore = downScore+1 25 | textDown.text = "Score: "..downScore 26 | end 27 | end 28 | local function createScoreDisplay(group) 29 | textUp = display.newText("Score: 0", 10, 0, native.systemFont, 16) 30 | textUp:setTextColor(255) 31 | textDown = display.newText("Score: 0", 10, screenH-20, native.systemFont, 16) 32 | textDown:setTextColor(255) 33 | end 34 | local function createWalls(group) 35 | --draw walls 36 | up = display.newRect(group,0,-20,screenW, 20) 37 | physics.addBody( up, "static", { density=1.0, friction=0, bounce=0} ) 38 | up:addEventListener("collision", upHit) 39 | down = display.newRect(group,0,screenH,screenW, 20) 40 | physics.addBody( down, "static", { density=1.0, friction=0, bounce=0} ) 41 | down:addEventListener("collision", downHit) 42 | left = display.newRect(group,-20,0,20, screenH) 43 | physics.addBody( left, "static", { density=1.0, friction=0, bounce=0} ) 44 | right = display.newRect(group,screenW,0,20, screenH) 45 | physics.addBody( right, "static", { density=1.0, friction=0, bounce=0} ) 46 | end 47 | local function createPaddle(group, x, y, rotation) 48 | local width, height = 120, 30 49 | local paddle = display.newRoundedRect(group, 0, 0, width, height,10) 50 | paddle:setReferencePoint(display.CenterReferencePoint) 51 | paddle.x, paddle.y = x,y 52 | local shape = {width*.5, -height*.5, width*.5, height*.1, width*.4, height*.5,-width*.4, height*.5,-width*.5, height*.1, -width*.5, -height*.5,} 53 | physics.addBody( paddle, "dynamic", { density=1.0, friction=0, bounce=0, shape = shape} ) 54 | paddle:rotate(180+rotation) 55 | paddle.isFixedRotation = true 56 | paddle:setFillColor(255,100,100) 57 | paddle.touchJoint = physics.newJoint( "touch", paddle, paddle.x, paddle.y ) 58 | paddle.targetX = x 59 | function paddle:setTarget(x) 60 | self.touchJoint:setTarget(x,self.y) 61 | self.targetX = x 62 | end 63 | return paddle 64 | end 65 | local function createBall(group) 66 | local puck = display.newCircle( halfW,halfH,20) 67 | physics.addBody( puck, { density=0, friction=0.3, bounce=1, radius = 20} ) 68 | puck.isBullet = true 69 | puck:setLinearVelocity(200,200) 70 | puck:setFillColor(100,255,100) 71 | group:insert(puck) 72 | return puck 73 | end 74 | 75 | local function makeClient() 76 | if(isServer) then --if we were a server before, we need to unregister all the event listeners 77 | paddleDown:setFillColor(255,100,100) 78 | Runtime:removeEventListener("autolanPlayerDropped", playerDropped) 79 | Runtime:removeEventListener("autolanPlayerJoined", addPlayer) 80 | paddleDown:removeEventListener("touch", dragBodyServer) --assign bottom padle to server 81 | Runtime:removeEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 82 | ball:removeEventListener("collision", ballCollision) 83 | timer.cancel(sendFullFrameTimer) 84 | isServer = false 85 | end 86 | print("making client") 87 | client = require("Client") 88 | client:start() 89 | client:scanServersInternet() 90 | isClient = true 91 | Runtime:addEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 92 | Runtime:addEventListener("autolanConnectionFailed", connectionAttemptFailed) 93 | Runtime:addEventListener("autolanDisconnected", connectionAttemptFailed) 94 | end 95 | local function makeServer() 96 | if(isClient) then --if we were a client before, we need to unregister all the event listeners 97 | isClient = false 98 | paddleUp:setFillColor(255,100,100) 99 | Runtime:removeEventListener("autolanReceived", clientReceived) --all incoming packets are sent to clientReceived 100 | Runtime:removeEventListener("autolanConnectionFailed", connectionAttemptFailed) 101 | Runtime:removeEventListener("autolanDisconnected", connectionAttemptFailed) 102 | end 103 | server = require("Server") 104 | server:setCustomBroadcast("1 Player") 105 | server:startInternet() 106 | isServer = true 107 | menuGroup:removeSelf() 108 | paddleDown:setFillColor(100,100,255) 109 | --add event listeners 110 | Runtime:addEventListener("autolanPlayerDropped", playerDropped) 111 | Runtime:addEventListener("autolanPlayerJoined", addPlayer) 112 | paddleDown:addEventListener("touch", dragBodyServer) --assign bottom padle to server 113 | Runtime:addEventListener("autolanReceived", serverReceived) --all incoming packets sent to serverReceived 114 | ball:addEventListener("collision", ballCollision) 115 | sendFullFrameTimer = timer.performWithDelay(2000, sendFullFrame, -1) 116 | end 117 | ---------------------------UI OBJECTS-------------------- 118 | local numberOfServers = 0 119 | local function spawnMenu(group) 120 | --functions to handle button events 121 | local joinText 122 | local function joinPressed() 123 | joinText.text = "Scanning..." 124 | makeClient() 125 | end 126 | local function hostPressed() 127 | makeServer() 128 | end 129 | local title = display.newRoundedRect(group, 0, 0, screenW*.8,60,20) 130 | title:setReferencePoint(display.CenterReferencePoint) 131 | title.x,title.y = halfW, 50 132 | title:setFillColor(100,100,100) 133 | local titleText = display.newText(group, "Multiplayer Pong", 0, 0, native.systemFont, 24) 134 | titleText:setReferencePoint(display.CenterReferencePoint) 135 | titleText.x, titleText.y = halfW, 50 136 | --host button 137 | local host = display.newRoundedRect(group, 20, 100, 120,60,20) 138 | host:setFillColor(100,100,100) 139 | host:addEventListener("tap", hostPressed) 140 | local hostText = display.newText(group, "Host", 50, 115, native.systemFont, 24) 141 | --host button 142 | local join = display.newRoundedRect(group, 160, 100, 120,60,20) 143 | join:addEventListener("tap", joinPressed) 144 | join:setFillColor(100,100,100) 145 | joinText = display.newText(group, "Join", 195, 115, native.systemFont, 24) 146 | 147 | 148 | local function createListItem(event) --displays found servers 149 | local item = display.newGroup() 150 | item.background = display.newRoundedRect(item,20,0,screenW-50,60,20) 151 | item.background.strokeWidth = 3 152 | item.background:setFillColor(70, 70, 70) 153 | item.background:setStrokeColor(180, 180, 180) 154 | item.text = display.newText(item,event.serverName.." "..event.customBroadcast, 40, 20, "Helvetica-Bold", 18 ) 155 | if(event.internet) then 156 | item.text:setTextColor( 100,100,255 ) 157 | else 158 | item.text:setTextColor( 255 ) 159 | end 160 | item.serverIP = event.serverIP 161 | --attach a touch listener 162 | function item:tap(e) 163 | client:connect(self.serverIP) 164 | menuGroup:removeSelf() 165 | menuGroup = nil 166 | end 167 | item:addEventListener("tap", item) 168 | 169 | item.y = numberOfServers*70+180 170 | numberOfServers = numberOfServers+1 171 | menuGroup:insert(item) 172 | end 173 | Runtime:addEventListener("autolanServerFound", createListItem) 174 | 175 | end 176 | ----create the scene------------------- 177 | createWalls(physicsGroup) 178 | paddleDown = createPaddle(physicsGroup, halfW, screenH*.95, 0) 179 | paddleUp = createPaddle(physicsGroup, halfW, screenH*.05, 180) 180 | ball = createBall(physicsGroup) 181 | createScoreDisplay(UIGroup) 182 | spawnMenu(menuGroup) 183 | 184 | local speed = 350 185 | local function setBallSpeed() 186 | if(ball) then 187 | if(speed < 500) then 188 | speed = speed+.1 189 | end 190 | --get the direction and set the speed 191 | vx,vy = ball:getLinearVelocity() 192 | local direction = math.atan2(vy,vx) 193 | ball:setLinearVelocity(math.cos(direction)*speed, math.sin(direction)*speed) 194 | end 195 | end 196 | Runtime:addEventListener("enterFrame", setBallSpeed) 197 | 198 | ---------------------------------------------------------------------------------------------- 199 | -------------------------------------SERVER SPECIFIC CODE------------------------------------- 200 | ---------------------------------------------------------------------------------------------- 201 | local numPlayers = 0 202 | local clients = {} 203 | local function getFullGameState() 204 | local state = {} 205 | state[1] = 2--protocol id 206 | state[2] = paddleUp.targetX 207 | state[3] = paddleDown.targetX 208 | state[4] = ball.x 209 | state[5] = ball.y 210 | vx, vy = ball:getLinearVelocity() 211 | state[6] = vx 212 | state[7] = vy 213 | state[8] = upScore 214 | state[9] = downScore 215 | return state 216 | end 217 | local function getDifferentialGameState() 218 | local state = {} 219 | state[1] = 4--protocol id 220 | state[2] = paddleUp.targetX 221 | state[3] = paddleDown.targetX 222 | return state 223 | end 224 | local function getBallState() 225 | local state = {} 226 | state[1] = 5--protocol id 227 | state[2] = ball.x 228 | state[3] = ball.y 229 | vx, vy = ball:getLinearVelocity() 230 | state[4] = vx 231 | state[5] = vy 232 | return state 233 | end 234 | playerDropped = function(event) 235 | local clientDropped = event.client 236 | --go through the table and find the client that dropped 237 | for i=1, numPlayers do 238 | if(clients[i] == clientDropped) then 239 | table.remove(clients, i) --remove this client 240 | numPlayers = numPlayers - 1 241 | end 242 | end 243 | server:setCustomBroadcast(numPlayers.." Players") 244 | --now let us try to find a spectator client to retake control of the paddle 245 | if(clients[1]) then 246 | clients[1]:sendPriority({1,1}) --initialization packet with playerID = 1 so client can control paddle 247 | end 248 | print("player dropped because", event.message) 249 | end 250 | addPlayer = function(event) 251 | local client = event.client --this is the client object, used to send messages 252 | print("player joined",client) 253 | --look for a client slot 254 | numPlayers = numPlayers+1 255 | clients[numPlayers] = client 256 | client:sendPriority({1,numPlayers}) --initialization packet 257 | client:sendPriority(getFullGameState()) --initialization packet 258 | server:setCustomBroadcast(numPlayers.." Players") 259 | end 260 | ballCollision = function(event) 261 | if(event.phase == "ended") then 262 | --send ball update packet to all clients 263 | for i=1, numPlayers do 264 | clients[i]:send(getBallState()) 265 | end 266 | end 267 | end 268 | sendFullFrame = function() 269 | for i=1, numPlayers do 270 | clients[i]:send(getFullGameState()) 271 | end 272 | end 273 | serverReceived = function(event) 274 | local message = event.message 275 | --since this message came from a client, it can only be of type 3: player update 276 | paddleUp:setTarget(message[2]) 277 | --now forward a differential update to all clients (some are spectators) 278 | for i=1, numPlayers do 279 | clients[i]:send(getDifferentialGameState()) 280 | end 281 | end 282 | 283 | dragBodyServer = function(e) 284 | local body = e.target 285 | body.touchJoint:setTarget(e.x, body.y) 286 | body.targetX = e.x 287 | if "began" == e.phase then 288 | display.getCurrentStage():setFocus( body, e.id ) 289 | elseif "ended" == e.phase or "cancelled" == e.phase then 290 | display.getCurrentStage():setFocus( body, nil ) 291 | elseif "moved" ==e.phase then 292 | --now forward a differential update to all clients (some are spectators) 293 | for i=1, numPlayers do 294 | clients[i]:send(getDifferentialGameState()) 295 | end 296 | end 297 | end 298 | 299 | ---------------------------------------------------------------------------------------------- 300 | -------------------------------------CLIENT SPECIFIC CODE------------------------------------- 301 | ---------------------------------------------------------------------------------------------- 302 | 303 | connectionAttemptFailed = function(event) 304 | print("connection failed, redisplay menu") 305 | numberOfServers = 0 306 | menuGroup = display.newGroup() 307 | spawnMenu(menuGroup) 308 | end 309 | 310 | local function connectedToServer(event) 311 | print("connected, waiting for sync") 312 | end 313 | Runtime:addEventListener("autolanConnected", connectedToServer) 314 | 315 | local function getPlayerUpdate() 316 | local state = {} 317 | state[1] = 4--protocol id 318 | state[2] = paddleUp.targetX 319 | return state 320 | end 321 | dragBodyClient = function(e) 322 | local body = e.target 323 | body.touchJoint:setTarget(e.x, body.y) 324 | body.targetX = e.x 325 | if "began" == e.phase then 326 | display.getCurrentStage():setFocus( body, e.id ) 327 | elseif "ended" == e.phase or "cancelled" == e.phase then 328 | display.getCurrentStage():setFocus( body, nil ) 329 | elseif "moved" ==e.phase then 330 | --now forward an update to the server 331 | client:send(getPlayerUpdate()) 332 | end 333 | end 334 | local function restoreBallState(message) 335 | local dx, dy = message[2]-ball.x, message[3]-ball.y 336 | ball:translate(dx,dy) 337 | ball:setLinearVelocity(message[4],message[5]) 338 | end 339 | local ballControl = false 340 | local function restoreGameState(message) 341 | paddleUp:setTarget(message[2]) 342 | paddleDown:setTarget(message[3]) 343 | ball.x, ball.y = message[4], message[5] 344 | ball:setLinearVelocity(message[6],message[7]) 345 | upScore, downScore = message[8], message[9] 346 | textUp.text = "Score: "..upScore 347 | textDown.text = "Score: "..downScore 348 | end 349 | clientReceived = function (event) 350 | local message = event.message 351 | print("message", message, message[1], message[2]) 352 | --figure out packet type 353 | if(message[1] == 1) then 354 | print("got init packet") 355 | if(message[2] == 1) then --we are the first player to join, let us take control of the ball 356 | paddleUp:addEventListener("touch", dragBodyClient) 357 | paddleUp:setFillColor(100,100,255) 358 | ballControl = true 359 | end 360 | elseif(message[1] == 2) then 361 | restoreGameState(message) 362 | elseif(message[1] == 4) then 363 | print("got differential packet",message[2],message[3]) 364 | paddleDown:setTarget(message[3]) 365 | if(not ballControl) then 366 | paddleUp:setTarget(message[2]) 367 | end 368 | elseif(message[1] == 5) then 369 | print("got ball update packet") 370 | restoreBallState(message) 371 | end 372 | end 373 | -------------------------------------------------------------------------------- /Client.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Corona� AutoLAN v 1.2 3 | Author: M.Y. Developers 4 | Copyright (C) 2011 M.Y. Developers All Rights Reserved 5 | Support: mydevelopergames@gmail.com 6 | Website: http://www.mygamedevelopers.com/Corona--Profiler.html 7 | License: 8 | You are free to: 9 | to Share — to copy, distribute and transmit the work 10 | to Remix — to adapt the work 11 | to make commercial use of the work. You cannot however sell the 12 | library itself. 13 | 14 | Under the following conditions: 15 | 16 | Attribution — You must attribute the work in the manner specified by the author or licensor (but not in any way that suggests that they endorse you or your use of the work). 17 | With the understanding that: 18 | 19 | Waiver — Any of the above conditions can be waived if you get permission from the copyright holder. 20 | Public Domain — Where the work or any of its elements is in the public domain under applicable law, that status is in no way affected by the license. 21 | Other Rights — In no way are any of the following rights affected by the license: 22 | Your fair dealing or fair use rights, or other applicable copyright exceptions and limitations; 23 | The author's moral rights; 24 | Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy rights. 25 | Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to this web page. 26 | 27 | --]] 28 | 29 | local socket = require "socket" 30 | local json = require "json" 31 | local multiplayer = {} 32 | local applicationName = "Default" 33 | 34 | local client = {} --master object 35 | 36 | ---------------- 37 | --common client/server --takes care of the send queue/priority system 38 | local circularBufferSize = 100 39 | local bufferIndexLow = 1 40 | local bufferIndexLowSend = 1 --last index looked at by send routine 41 | local bufferIndexHigh = 1 42 | local bufferIndexHighSend = 1 --last index looked at by send routine 43 | local sendQueueLow = {} --will be a circular buffer 44 | local sendQueueHigh = {} --will be an associative array 45 | local sendQueueHighCallbacks = {} 46 | local fileQueue = {} 47 | local pendingFiles = {} 48 | local fileQueueNumber = 0 49 | local packetSize = 2000 ---in bytes 50 | local myClientID 51 | local connected = false 52 | local onUpdate 53 | local handshake 54 | 55 | 56 | ---------------- 57 | --UDP packet types 58 | --type 1 = initial handshake, create a client object on server 59 | 60 | ------------client code 61 | local broadcastListener 62 | local listenTime = 1000 63 | local scanTime = 30000 64 | local timers = {} 65 | local availibleServers = {} --key = ip, value = port 66 | local serverIP,serverPort 67 | local myIP,myPort 68 | local handshakeTable = {"CoronaMultiplayer", applicationName} 69 | local broadcastTime = 1000 --in ms, frequency to send broadcast for network discovery 70 | local connectionTimeout = 2000 71 | local connectionAttemptTime = 100 72 | local networkRate = 30 --main loop 73 | local UDPClient, HandshakeClient, tempClient 74 | local HighPriorityRecieved = {0} 75 | local numHighPriorityRecieved = 0 76 | local HighPriorityCounters = {} 77 | local HighPriorityCount = 50 --num cycles to wait before resending 78 | --------hearbeat time 79 | local heartbeatTime = 40 80 | local timeoutPeriod = 150 81 | local timeoutsLeft = timeoutPeriod 82 | local heartbeatTimer = heartbeatTime --called every x frames nothing was sent to maintain connection 83 | local numMessagesRecieved = 0 --keeps track of how many acks to send for flow control 84 | 85 | --------flow control 86 | 87 | local maxCredits = 9999 --num packets to send before waiting for a reply 88 | local sendCredits = 1000 --each time we send one, we deduct a credit, each ACK we add credit 89 | local rechargeRate = 500 --in ms 90 | local rechargeAmount = 10 --if no response by rechargeRate then slowly fill up credits 91 | 92 | ------internet------------------------------------------------------------------------------------ 93 | local peerIP, peerPort = socket.dns.toip("rijl-al-awwa.dreamhost.com"), 54613 94 | local matchmakerTCPclient, pendingConnection 95 | 96 | local function send(input, priority, listener) --adds to send buffer and assigns priority 97 | if(priority == 1) then 98 | if(UDPClient) then 99 | print ("sending interface") 100 | heartbeatTimer = heartbeatTime 101 | local packetTemplate = {} 102 | packetTemplate[1] = input --payload 103 | packetTemplate[2] ={1,numMessagesRecieved} --flow control/acks 104 | packetTemplate[3] = HighPriorityRecieved --high priority acks 105 | numHighPriorityRecieved = 0 106 | HighPriorityRecieved = {0} 107 | numMessagesRecieved = 0 108 | UDPClient:send( json.encode(packetTemplate) ) --send data entry 109 | sendCredits = sendCredits-1 110 | end 111 | 112 | 113 | 114 | else 115 | --high priority 116 | sendQueueHighCallbacks[bufferIndexHigh] = listener 117 | -- numMessagesRecieved = 0 118 | -- heartbeatTimer = heartbeatTime 119 | if(UDPClient) then 120 | local packetTemplate = {} 121 | packetTemplate[1] = input --payload 122 | packetTemplate[2] ={2,numMessagesRecieved,bufferIndexHigh} -- control/acks 123 | packetTemplate[3] = HighPriorityRecieved --high priority acks 124 | numHighPriorityRecieved = 0 125 | numMessagesRecieved = 0 126 | HighPriorityRecieved = {0} 127 | HighPriorityCounters[bufferIndexHigh] = HighPriorityCount --controls when to resend 128 | sendQueueHigh[bufferIndexHigh] = packetTemplate 129 | UDPClient:send( json.encode(packetTemplate) ) --send data entry 130 | sendCredits = sendCredits-1 131 | bufferIndexHigh = bufferIndexHigh+1 132 | if(bufferIndexHigh == circularBufferSize) then 133 | bufferIndexHigh = 1 --wrap 134 | end 135 | 136 | end 137 | 138 | 139 | end 140 | end 141 | 142 | local function sendFile(filename, path, destFile) 143 | path = (system.pathForFile(filename, path)) 144 | filename = destFile or filename 145 | local file = io.open(path, "rb") 146 | if(file) then 147 | 148 | fileQueueNumber = fileQueueNumber+1 149 | local fileTable = {} 150 | fileTable = {} 151 | fileTable.file = file 152 | local fileSize = file:seek("end") 153 | fileTable.filename = filename 154 | fileTable.size = fileSize 155 | fileTable.numPackets = math.ceil(fileSize/packetSize) 156 | fileTable.currentPacket = 1 --must send number of packets in case out of order 157 | fileQueue[fileQueueNumber] = fileTable 158 | file:seek("set",0) -- reset to beginning of file 159 | end 160 | end 161 | 162 | local function addCredits(credit) 163 | sendCredits = sendCredits+credit 164 | if(sendCredits > maxCredits) then 165 | sendCredits = maxCredits 166 | end 167 | end 168 | 169 | ------------ 170 | 171 | local function failedConnection() 172 | timer.cancel(timers.connectionAttempt) 173 | timers.connectionAttempt = nil 174 | ----print("connection attempt failed") 175 | Runtime:dispatchEvent({name = "autolanConnectionFailed", serverIP = serverIP}) 176 | end 177 | 178 | local function receive() 179 | if(UDPClient) then 180 | 181 | local message, error = UDPClient:receive() 182 | 183 | local noError = false 184 | while(message) do 185 | print("message", message) 186 | noError = true 187 | 188 | numMessagesRecieved = numMessagesRecieved+1 189 | --print(#message,numMessagesRecieved) 190 | message = json.decode(message) 191 | if(message[1] == "e" or message[1] == "c") then 192 | return 193 | end 194 | if(message[2][1]==2) then 195 | --high priority,record ack to send 196 | numHighPriorityRecieved = numHighPriorityRecieved+1 197 | HighPriorityRecieved[numHighPriorityRecieved] = message[2][3] --log to send ack in a future packet (pooling) 198 | else 199 | --low priority, dont send ack 200 | ------print(json.encode(message[3])) 201 | end 202 | 203 | if(message[3][1] ~= 0) then --contains a high priorit ack 204 | local acks = message[3] 205 | --contain high priority acks 206 | for i=1,#acks do 207 | local ack = acks[i] 208 | sendQueueHigh[ack] = nil 209 | HighPriorityCounters[ack] = nil 210 | if(sendQueueHighCallbacks[ack]) then 211 | sendQueueHighCallbacks[ack]({phase = "complete"}) 212 | end 213 | end 214 | end 215 | ------print("credits", sendCredits,message[2][2]) 216 | addCredits(message[2][2]) 217 | 218 | -------------------on top of transport layer, figure out message type 219 | local userMessage = message[1] 220 | 221 | if(userMessage[1]==2) then --file transfer 222 | ----print(userMessage[1],userMessage[2],userMessage[3],userMessage[4], #userMessage[5]) 223 | --write file 224 | local filename = userMessage[2] 225 | 226 | if(pendingFiles[filename]==nil) then 227 | pendingFile = {} 228 | pendingFile.file = io.open(system.pathForFile(userMessage[2],system.DocumentsDirectory),"wb") 229 | pendingFile.recieved = {} 230 | pendingFile.buffer = {} 231 | pendingFile.index = 1 --file position 232 | pendingFiles[filename] = pendingFile 233 | end 234 | local pendingFile = pendingFiles[filename] 235 | local packetindex = userMessage[3] 236 | pendingFile.recieved[packetindex] = 1 --1 = recieved but not written, 2 = written, nil = not rec. 237 | pendingFile.buffer[packetindex] = userMessage[5] 238 | local currentBuffer = pendingFile.buffer[pendingFile.index] 239 | while(currentBuffer ~= nil) do --if we reiceve packets out of order wait ultil we have a writable chunk 240 | ----print("writing",pendingFile.index) 241 | pendingFile.file:write(currentBuffer) 242 | currentBuffer = nil 243 | pendingFile.index = pendingFile.index+1 244 | currentBuffer = pendingFile.buffer[pendingFile.index] 245 | end 246 | if(pendingFile.index == userMessage[4]+1) then 247 | --file transfer finished, trigger event 248 | ----print("FILE DONE") 249 | Runtime:dispatchEvent({name = "autolanFileReceived", filename = filename}) 250 | pendingFile.file:close() 251 | pendingFiles[filename] = nil 252 | end 253 | elseif userMessage[1]==1 then 254 | print("client recieved") 255 | Runtime:dispatchEvent({name = "autolanReceived", message = userMessage[2]}) 256 | end 257 | 258 | message, error = UDPClient:receive() 259 | 260 | end 261 | if error and not noError then 262 | if error == "timeout" then 263 | timeoutsLeft = timeoutsLeft-1 --clients responsibility to send alive packets 264 | if(timeoutsLeft == 0) then 265 | --this connection has timed out so kill it 266 | UDPClient:close() 267 | UDPClient = nil 268 | Runtime:dispatchEvent({name = "autolanDisconnected", serverIP = serverIP, message = "timeout"}) 269 | end 270 | elseif error == "closed" then 271 | Runtime:dispatchEvent({name = "autolanDisconnected", serverIP = serverIP, message = "closed"}) 272 | UDPClient:close() 273 | UDPClient = nil 274 | ----print("closed") 275 | end 276 | else 277 | timeoutsLeft = timeoutPeriod --reset timeouts 278 | end 279 | 280 | 281 | end 282 | end 283 | local function mainLoop() 284 | if(sendCredits >0) then 285 | local fileTable = fileQueue[1] --only send 1 file at a time, send the first in fifo 286 | --get the datagram data 287 | if(fileTable) then 288 | local data = fileTable.file:read(packetSize) 289 | local sendPacket = {2,fileTable.filename, fileTable.currentPacket, fileTable.numPackets, data} --first entry (high level) is type of packet 1 = user, 2 = file, 3=command 290 | fileTable.currentPacket = fileTable.currentPacket+1 291 | if(data) then 292 | send(sendPacket,2) 293 | 294 | else 295 | --end of file 296 | table.remove(fileQueue,1) 297 | fileQueueNumber = fileQueueNumber-1 298 | end 299 | end 300 | for i,packet in pairs(sendQueueHigh) do 301 | local count = HighPriorityCounters[i] 302 | if(UDPClient) then 303 | if(count) then 304 | if(count == 0) then 305 | HighPriorityCounters[i] = HighPriorityCount 306 | --resend packet 307 | packet[2][2] = numMessagesRecieved -- control/acks 308 | packet[3] = HighPriorityRecieved --high priority acks 309 | UDPClient:send( json.encode(packetTemplate) ) --send data entry 310 | sendCredits = sendCredits-1 311 | else 312 | HighPriorityCounters[i] = count - 1 313 | end 314 | end 315 | else 316 | --client dead, ACK 317 | sendQueueHigh[i] = nil 318 | HighPriorityCounters[i] = nil 319 | if(sendQueueHighCallbacks[i]) then 320 | sendQueueHighCallbacks[i]({phase = "cancelled"}) 321 | end 322 | end 323 | end 324 | end 325 | ---sending complete, recieve 326 | --heartbeat to send periodically a packet to ensure connection is alive 327 | if(heartbeatTimer==0) then 328 | if(UDPClient) then 329 | local packetTemplate = {} 330 | packetTemplate[1] = {0} --payload 331 | packetTemplate[2] ={0,numMessagesRecieved} --flow control/acks 332 | packetTemplate[3] = HighPriorityRecieved --high priority acks 333 | numHighPriorityRecieved = 0 334 | HighPriorityRecieved = {0} 335 | numMessagesRecieved = 0 336 | UDPClient:send( json.encode(packetTemplate) ) --send data entry 337 | end 338 | heartbeatTimer = heartbeatTime 339 | end 340 | heartbeatTimer = heartbeatTimer-1 341 | end 342 | local sendPhase = true 343 | 344 | local function connectToServer() 345 | if(timers.failedToConnect == nil) then 346 | --print("create timers") 347 | timers.failedToConnect = timer.performWithDelay(connectionTimeout,failedConnection)--stop handshaking and fail 348 | timers.connectionAttempt = timer.performWithDelay(connectionAttemptTime,connectToServer,-1)--try to handshake 349 | end 350 | if(HandshakeClient == nil) then 351 | --print("creating handshake client") 352 | HandshakeClient = socket.udp() 353 | HandshakeClient:setsockname("*", 0) --bind on any availible port and localserver ip address. 354 | HandshakeClient:settimeout(0) 355 | tempClient = socket.udp() --need a temp client b/c loop is still running 356 | tempClient:setsockname("*", 0) --bind on any availible port and localserver ip address. 357 | tempClient:settimeout(0) 358 | myIP, myPort = tempClient:getsockname() 359 | handshakeTable[3] = myPort 360 | handshake = json.encode(handshakeTable) 361 | end 362 | --send a handshake packet telling the server to create a connection for us/ alternate b/w send and recieve 363 | HandshakeClient:sendto(handshake,serverIP,serverPort) 364 | --recieve a confirmation packet telling us all is good for transmission 365 | local message = HandshakeClient:receive() 366 | --print("handshake", message) 367 | while(message) do 368 | ------print("recieved broadcast,", message) 369 | message = json.decode(message) 370 | if(message) then 371 | if(message[1] and message[1]=="CoronaMultiplayer" and message[2] == applicationName) then --this is the protocol id 372 | 373 | HandshakeClient:close() 374 | HandshakeClient = nil 375 | 376 | 377 | tempClient:setpeername(serverIP, message[4]) 378 | UDPClient,tempClient = tempClient,nil 379 | 380 | timer.cancel(timers.connectionAttempt) 381 | timers.connectionAttempt = nil 382 | timer.cancel(timers.failedToConnect) 383 | timers.failedToConnect = nil 384 | myClientID = message[5] 385 | ----print("Connected!",serverIP, message[4]) --this is where we fire off connected event 386 | Runtime:dispatchEvent({name = "autolanConnected", myClientID = myClientID, serverIP = serverIP, customBroadcast = availibleServers[serverIP].customBroadcast}) 387 | timeoutsLeft = timeoutPeriod 388 | --timer.performWithDelay(500,sendtest,-1) 389 | break 390 | end 391 | end 392 | message = HandshakeClient:receive() 393 | end 394 | end 395 | 396 | 397 | 398 | local function stopListening() --we cant just listen forever or else we will have a huge buffer 399 | if(timers.scanTimer) then 400 | timer.cancel(timers.scanTimer) 401 | timers.scanTimer = nil 402 | if(broadcastListener) then 403 | broadcastListener:close() 404 | broadcastListener = nil 405 | end 406 | --here is where we would call the done scanning event listener 407 | --print("done scanning.") 408 | Runtime:dispatchEvent({name = "autolanDoneScanning", servers = availibleServers}) 409 | else 410 | ----print("already not scanning...") 411 | end 412 | end 413 | 414 | local function UDPBroadcastListen() 415 | if(broadcastListener) then 416 | local broadcastMessage, serverIP, serverPort 417 | broadcastMessage,serverIP,serverPort = broadcastListener:receivefrom() 418 | local packets = 1 419 | while(broadcastMessage and type(broadcastMessage)=="string") do 420 | packets = packets+1 421 | broadcastMessage = json.decode(broadcastMessage) 422 | if(broadcastMessage) then 423 | if(broadcastMessage[1] and broadcastMessage[1]=="CoronaMultiplayer" and broadcastMessage[2]==applicationName) then --this is the protocol id 424 | if(availibleServers[serverIP] == nil) then 425 | availibleServers[serverIP] = {name = broadcastMessage[3], broadcastPort = serverPort, port = serverPort, customBroadcast = broadcastMessage[5]} 426 | Runtime:dispatchEvent({name = "autolanServerFound", serverIP = serverIP, port = serverPort, customBroadcast = broadcastMessage[5], serverName = broadcastMessage[3]}) 427 | ----print("found server adding...") --this is where we fire off server found event 428 | end 429 | end 430 | end 431 | if(broadcastListener) then 432 | broadcastMessage = nil 433 | broadcastMessage,serverIP,serverPort = broadcastListener:receivefrom() 434 | end 435 | end 436 | end 437 | end 438 | 439 | local function scanServers(scanTime) 440 | if(scanTimer) then 441 | ----print("already scanning...") 442 | else 443 | if(broadcastListener==nil) then 444 | broadcastListener = socket.udp() 445 | broadcastListener:setsockname("*", 8080) 446 | broadcastListener:settimeout(0) 447 | end 448 | availibleServers = {} 449 | timers.scanTimer = timer.performWithDelay(listenTime,UDPBroadcastListen,-1) 450 | if(scanTime) then 451 | timers.scanStopTimer = timer.performWithDelay(scanTime,stopListening) --only scan for a certian amount of time and then stop and report what servers were found 452 | end 453 | end 454 | end 455 | 456 | local currentServer 457 | local function connectToServerInternet() 458 | if(timers.scanTimerInternet) then 459 | timer.cancel(timers.scanTimerInternet) 460 | timers.scanTimerInternet = nil 461 | timers.connectTimerInternet = timer.performWithDelay(listenTime,connectToServerInternet,-1) 462 | end 463 | if(pendingConnection == nil) then 464 | local udpclient = socket.udp() 465 | udpclient:setsockname("*", 0) --bind on any availible port and localserver ip address. 466 | udpclient:settimeout(0) 467 | pendingConnection = udpclient 468 | end 469 | --assumes a valid pending connection is established 470 | print("establish connection") 471 | if(pendingConnection) then 472 | print("internet Handshake at", serverIP) 473 | pendingConnection:sendto(json.encode{"CoronaAutoInternet",applicationName,"cc",serverIP},peerIP, peerPort+1) --send to server saying I am ready to connect, tell server to create socket, send the server(tcp) ip and port 474 | local msg,ip,port = pendingConnection:receivefrom() 475 | while(msg) do 476 | print("udp", msg) 477 | local decoded = json.decode(msg) 478 | if(decoded and decoded[1]=="c") then 479 | pendingConnection:sendto(json.encode{"e"},decoded[2], decoded[3]) 480 | elseif(decoded and decoded[1]=="e") then 481 | --connection established event 482 | Runtime:dispatchEvent({name = "autolanConnected", myClientID = decoded[1], serverIP = ip, customBroadcast = availibleServers[serverIP].customBroadcast}) 483 | pendingConnection:setpeername(ip,port) 484 | UDPClient = pendingConnection 485 | pendingConnection = nil 486 | timer.cancel(timers.connectTimerInternet) 487 | timers.connectTimerInternet = nil 488 | return 489 | end 490 | msg,ip,port = pendingConnection:receivefrom() 491 | end 492 | end 493 | 494 | print("sending", currentServer[1], currentServer[2]) 495 | 496 | 497 | end 498 | -------------------------------------------INTERNET---------------------------------------------------- 499 | local function MatchmakerServerListen() --listens for a reponse from the matchmaker AND for response fromserverUDP 500 | 501 | local msg = matchmakerTCPclient:receive("*l") 502 | if(msg) then 503 | print(msg) 504 | --resolve message type for the tcp it is only a list of servers. 505 | local decoded = json.decode(msg) 506 | if(decoded) then 507 | if(decoded[1] == "l") then 508 | --send connect request to matchmaker to send request to server for new sock 509 | for i=1,#decoded[2] do 510 | --add each to list 511 | currentServer = decoded[2][i] 512 | print(currentServer[1].." added") 513 | local serverIP = currentServer[1]..currentServer[2] --this is the key we refer the internet server by 514 | availibleServers[serverIP] = {name = currentServer[2], port = currentServer[2], customBroadcast = currentServer[2], internet = true} 515 | Runtime:dispatchEvent({name = "autolanServerFound", serverIP = serverIP, port = currentServer[2], customBroadcast = currentServer[4], serverName = currentServer[3], internet = true}) 516 | end 517 | end 518 | end 519 | end 520 | end 521 | ------------------------------------------INTERNET---------------------------------------------------- 522 | 523 | function client:scanServersInternet(scanTime) 524 | scanServers() 525 | --open a TCP connection to the matchmaking server 526 | matchmakerTCPclient = socket.tcp() 527 | matchmakerTCPclient:settimeout(1) --this is the only blocking operation 528 | local err = matchmakerTCPclient:connect(peerIP, peerPort) --bind on any availible port and localserver ip address. 529 | print(err) 530 | if(err==nil) then 531 | print("server timeout") 532 | return 533 | end 534 | matchmakerTCPclient:send(json.encode({"CoronaAutoInternet",applicationName,"c"}).."\n") --send client token 535 | matchmakerTCPclient:settimeout(0) 536 | timers.scanTimerInternet = timer.performWithDelay(listenTime,MatchmakerServerListen,-1) 537 | end 538 | 539 | -------------------------------------------INTERNET---------------------------------------------------- 540 | 541 | 542 | function client:setOptions(params) 543 | broadcastTime = params.broadcastTime or broadcastTime 544 | applicationName = params.applicationName or applicationName 545 | customBroadcast = params.customBroadcast or customBroadcast 546 | networkRate = params.networkRate or networkRate --feqnuency to run network loop 547 | connectTime = params.connectTime or connectTime --frequency to look for new clients 548 | timeoutTime = params.timeoutTime or timeoutTime --number of cycles to wait before client is DC 549 | maxCredits = params.maxCredits or maxCredits --number of packets to send w/o ACK 550 | rechargeRate = params.rechargeRate or rechargeRate --time to recharge credits 551 | rechargeAmount = params.rechargeAmount or rechargeAmount --time to recharge credits 552 | circularBufferSize = params.circularBufferSize or circularBufferSize --max number of elements in circular buffer, 2^n 553 | packetSize = params.packetSize or packetSize 554 | onUpdate = params.onUpdate or onUpdate 555 | end 556 | function client:stop() 557 | for i,t in pairs(timers) do 558 | timer.cancel(t) 559 | t = nil 560 | end 561 | end 562 | function client:send(message) 563 | send({1,message}, 1) 564 | end 565 | function client:sendPriority(message, params) 566 | params = params or {} 567 | send({1,message}, 2, params.callback) 568 | end 569 | function client:sendFile(filename, path, destFile) 570 | sendFile(filename, path, destFile) 571 | end 572 | function client:start() 573 | timers.recharge = timer.performWithDelay(rechargeRate, function() addCredits(rechargeAmount) end) 574 | timers.mainLoop = timer.performWithDelay(networkRate,mainLoop,-1) 575 | --Runtime:addEventListener("enterFrame", mainLoop) 576 | timers.receive = timer.performWithDelay(1,receive,-1) 577 | end 578 | function client:scanServers() 579 | scanServers() 580 | end 581 | client.RTT = nil 582 | local RTTTime 583 | local sendPing 584 | local function pingListener(e) 585 | if(e.phase == "began") then 586 | RTTTime = system.getTimer() 587 | elseif(e.phase == "complete") then 588 | client.RTT = system.getTimer() - RTTTime 589 | print("pingACK",client.RTT) 590 | sendPing() 591 | else 592 | 593 | end 594 | end 595 | sendPing = function () 596 | send({3,0}, 2, pingListener ) 597 | end 598 | function client:autoRTT() 599 | --send a high priority message to the server and figure out how long it takes 600 | sendPing() 601 | 602 | end 603 | function client:connect(ip) 604 | -- 605 | stopListening() 606 | serverIP,serverPort = ip,availibleServers[ip].port or 8080 607 | if(availibleServers[ip].internet) then 608 | connectToServerInternet() 609 | else 610 | connectToServer() 611 | end 612 | --stopListening() 613 | end 614 | local function autoConnectListener(e) 615 | 616 | print(e.serverIP) 617 | client:connect(e.serverIP) 618 | Runtime:removeEventListener("autolanServerFound",autoConnectListener) 619 | end 620 | 621 | function client:autoConnect() 622 | Runtime:addEventListener("autolanServerFound",autoConnectListener) 623 | scanServers() 624 | end 625 | function client:disconnect() 626 | --this connection has timed out so kill it 627 | if(UDPClient) then 628 | UDPClient:close() 629 | UDPClient = nil 630 | Runtime:dispatchEvent({name = "autolanDisconnected", serverIP = serverIP, message = "user disconnect"}) 631 | end 632 | end 633 | function client:stopScanning() 634 | stopListening() 635 | end 636 | function client:setMatchmakerURL(url,port) 637 | peerIP, peerPort = socket.dns.toip(url),port 638 | end 639 | return client --------------------------------------------------------------------------------