Leaderboard
Popular Content
Showing most liked content on 07/19/17 in Posts
-
1 pointHello everyone, Many Club Penguin Private Servers make use of only one world server, this is generally a good thing as it keeps all of your players together and helps encourage social interaction between players in the game. Club Penguin has always given the players the option to choose which world server they want to join, but if there is only one world server, what's the point in providing users the option? I wrote some code which will give you the ability to remove the world selection screen from the game entirely, this not only makes login faster thanks to not having to ask the user for input, but also because we no longer need a login server at all, we just authenticate with the world server and call it a day. Here is the actionscript code for the dependency shockwave flash file: import com.clubpenguin.util.*; import com.clubpenguin.crypto.*; var SHELL = _global.getCurrentShell(); var AIRTOWER = _global.getCurrentAirtower(); AIRTOWER.connectToLogin = function(in_username, in_pass, login_response) { if (!AIRTOWER.is_logged_in) { AIRTOWER.on_login_response = login_response; AIRTOWER.username = in_username; AIRTOWER.password = in_pass; AIRTOWER.server.onConnection = Delegate.create(AIRTOWER, AIRTOWER.handleLoginConnection); AIRTOWER.server.onExtensionResponse = Delegate.create(AIRTOWER, AIRTOWER.onAirtowerResponse); AIRTOWER.server.debug = true; AIRTOWER.addListener(AIRTOWER.HANDLE_LOGIN, AIRTOWER.handleOnLogin); var _local1 = SHELL.getWorldCrumbs(); var _local2; var _local3; for (_local2 in _local1) { _local3 = _local1[_local2]; break; } SHELL.world_id_holder = _local3.id; AIRTOWER.server.connect(_local3.ip, _local3.port); } else { AIRTOWER.shell.$e("connectToLogin() -> Your already logged in! Cant login again"); } } AIRTOWER.handleLoginConnection = function(success) { if(success) { AIRTOWER.login(); } else { AIRTOWER.on_login_response(false); } } AIRTOWER.login = function() { AIRTOWER.server.login("w1", AIRTOWER.username, AIRTOWER.getLoginHash()); } AIRTOWER.handleOnLogin = function(obj) { AIRTOWER.removeListener(AIRTOWER.HANDLE_LOGIN, AIRTOWER.handleOnLogin); AIRTOWER.shell.setMyPlayerId(obj[1]); AIRTOWER.playerId = obj[1]; AIRTOWER.login_key = obj[2]; AIRTOWER.on_login_response(true); AIRTOWER.is_logged_in = true; SHELL.gotoState(SHELL.PLAY_STATE); } SHELL.connectToWorld = function() { var _local1 = SHELL.getWorldById(SHELL.world_id_holder); SHELL.showLoading((SHELL.getLocalizedString("Joining") + " ") + _local1.name); AIRTOWER.joinWorld(); } AIRTOWER.handleJoinWorld = function(obj) { AIRTOWER.removeListener(AIRTOWER.JOIN_WORLD, AIRTOWER.handleJoinWorld); var _local6 = Boolean(Number(obj[1])); var _local3 = Boolean(Number(obj[2])); var _local5 = Boolean(Number(obj[3])); var _local4 = Boolean(Number(obj[4])); AIRTOWER.on_world_response(true, _local6, _local3, _local5, _local4); AIRTOWER.on_world_response = undefined; } AIRTOWER.joinWorld = function() { AIRTOWER.server.onConnectionLost = Delegate.create(AIRTOWER, AIRTOWER.handleLostConnection); var _local2 = new Array(); _local2.push(AIRTOWER.playerId); _local2.push(AIRTOWER.login_key); _local2.push(AIRTOWER.shell.getLanguageAbbriviation()); if (AIRTOWER.isRedemption) { AIRTOWER.addListener(AIRTOWER.REDEMPTION_JOIN_WORLD, handleJoinRedemption, AIRTOWER); AIRTOWER.send(AIRTOWER.REDEMPTION, AIRTOWER.REDEMPTION_JOIN_WORLD, _local2, "str", -1); return(undefined); } AIRTOWER.on_world_response = SHELL.connectToWorldResponse; AIRTOWER.addListener(AIRTOWER.JOIN_WORLD, AIRTOWER.handleJoinWorld); AIRTOWER.send(AIRTOWER.PLAY_EXT, (AIRTOWER.NAVIGATION + "#") + AIRTOWER.JOIN_WORLD, _local2, "str", -1); } AIRTOWER.getLoginHash = function() { return SHA256.hash(AIRTOWER.password); } Now, since the way that the client authenticates is slightly different, your server will need to be modified to support it. In this case, I actually made mine use SHA256 hashing (thanks @Kevin) instead of MD5. There is also now no real need for a random key. Note you do not need to use SHA256 with this, it was just what I decided I wanted to use, if you want to go back to MD5, or use another authentication method entirely, you can do so by overriding 'AIRTOWER.getLoginHash'. With this code the client connects directly to the first localized world server in the world crumbs, performs the handshake, hashes the password and authenticates, then proceeds to get the players information. This is how the world server auth works: recv: <msg t='sys'><body action='verChk' r='0'><ver v='153' /></body></msg> send: <msg t='sys'><body action='apiOK' r='0'></body></msg> recv: <msg t='sys'><body action='login' r='0'><login z='w1'><nick><![CDATA[Ben_]]></nick><pword><![CDATA[SHA256]]></pword></login></body></msg> A couple of actionscript classes are required for this code to export, everything is zipped below, you'll also find a pre-exported version in there if you are happy to use mine. The SWF file goes in /play/v2/client/ of your media server, please add it to dependencies.json too: { boot: [ { id: 'airtower', title: 'Communication' }, { id: 'sentry', title: 'Communication' } ], login: [ { id: 'cookies', title: 'Login Screen' }, { id: 'login', title: 'Login Screen' } ], join: [ { id: 'engine', title: 'Engine' }, { id: 'interface', title: 'Interface' }, { id: 'gridview', title: 'Gridview' }, { id: 'mail', title: 'Mail' }, { id: 'book', title: 'Mail' }, { id: 'stampbook', title: 'StampBook' } ], create: [ { id: 'create', title: 'Create Penguin' } ], merch: [ { id: 'app', folder: 'merch/', title: 'Communication' } ] } End result: Please suggest improvements, specifically ways to improve the security, I'm sure this is pretty half-assed. Please ask if you're having troubles getting the server sided stuff to work. Works on only legacy private servers, not the new client, but could be easily ported. I'll do it if I ever find the time. cookies.zip
-
1 pointThe biggest difference for the players will be that Kitsune has multiplayer game handlers for find four and sled racing, whereas Sweater doesn't have any. Kitsune also has stampbook handlers, and possibly some others I'm forgetting. The only thing that Sweater really has over Kitsune feature-wise is that it has some puffle functionality, although that's easy to implement yourself. There's also a big difference between the two as far as structure is concerned. Handlers in Kitsune are split up into multiple files to make the code easier to navigate and maintain, whereas Sweater's handlers are all placed into a single file. One major downside to AS2 Kitsune that I've discovered is that it stores data in a format that is inconsistent with the AS2 protocol, this is most noticeable when dealing with igloo data. This is due to the fact that Kitsune was originally designed for the AS3 protocol. A quick run down: Kitsune Multiplayer games (Find Four and Sled Racing) Better code structure Data stored in the database is inconsistent with what you're actually sending (may not be a big deal for you) Creates a new database connection for every client Sweater Puffle handlers All the handlers are stored in a single file A bot plugin Single database connection for everyone