New online leaderboard idea
- Login to post comments
This is an idea of setting up level records online. I made one written in Chinese and it works well... So I think it can also work for goofans.
Here's a diagram that shows the steps.
Original leaderboard submitting steps:
1. WorldOfGoo.exe makes a request to worldofgoo.com as I described here.
2. worldofgoo.com saves your player name, level record, tower height, etc. to the database.
3. worldofgoo.com asks the database for the rank, other players' tower height, player key, etc.
4. worldofgoo.com makes a response to WorldOfGoo.exe, you can now see other players' clouds if you are playing World of Goo Corporation.
5. The leaderboard asks the database for the biggest height and some level records and display it when it is working.
DIY leaderboard steps:
A. Patch the game.
B. WorldOfGoo.exe makes a request to mygodstudio.tk instead of worldofgoo.com.
C. mygodstudio.tk makes a request to worldofgoo.com with the same arguments.
D-E. Same as 2-3.
F. worldofgoo.com makes a response to mygodstudio.tk.
G. mygodstudio.tk saves the level records to the database. If necessary it will make a request to worldofgoo.com with op=SetLevelStats
to get the player name.
H. mygodstudio.tk makes a response to WorldOfGoo.exe which is same as worldofgoo.com's response.
I. The leaderboard asks the database for the data and display them on the web pages.
Doing this would be easy. Here are some of the source code from my WoGBuddy.aspx.cs
(the background code):
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Web.UI; using System.Xml; using System.Xml.Linq; using Mygod.Website.Public; namespace Mygod.Website { public partial class WoGBuddy : Page { protected void Page_Load(object sender, EventArgs e) { var done = false; try { // ReSharper disable PossibleNullReferenceException string op = Request.Params["op"], playerKey = Request.Params["playerkey"], name = null, version = Request.Params["version"]; if (op == "GetPlayerKey") { var result = Transpond(); Response.Write(result); done = true; var response = GetXmlResponseFromString(result); playerKey = response.Element("playerkey").Value; name = response.Element("name").Value; } else Response.Write(Transpond()); if (string.IsNullOrWhiteSpace(playerKey) || playerKey.Length != 32) return; long id = -1; PublicElements.Operate(database => { var player = database.WoGPlayer.FirstOrDefault(p => p.PlayerKey == playerKey); if (player == null) { if (name == null) name = GetPlayerName(playerKey); database.WoGPlayer.InsertOnSubmit(player = new WoGPlayer { PlayerKey = playerKey, PlayerName = name, CreateTime = DateTime.Now }); } player.LastSeen = DateTime.Now; player.Version = version; database.SubmitChanges(); id = player.ID; }); if (op != "SetLevelStats") return; long balls = long.Parse(Request.Params["balls"]), moves = long.Parse(Request.Params["moves"]), time = long.Parse(Request.Params["time"]); var levelID = Request.Params["levelid"]; // ReSharper disable ImplicitlyCapturedClosure PublicElements.Operate(database => { database.WoGLevelStats.InsertOnSubmit(new WoGLevelStats { PlayerID = id, LevelID = levelID, Balls = balls, Moves = moves, Seconds = time, UploadTime = DateTime.Now }); database.SubmitChanges(); }); // ReSharper restore ImplicitlyCapturedClosure // ReSharper restore PossibleNullReferenceException } catch { if (!done) Response.Clear(); // return empty stuff if errors occurred } } internal const long RecordsPerPage = 100; internal static long GetMaxPage(long items) { return (items + RecordsPerPage - 1) / RecordsPerPage; } private string Transpond() { var param = Request.Params.Keys.OfType<string>().Aggregate(string.Empty, (c, s) => c + '&' + s + '=' + Request.Params[s]).Remove(0, 1); return GetStringResponse(param); } private static readonly WebClient Client = new WebClient(); private static string GetStringResponse(string param) { string s; lock (Client) s = Client.DownloadString("https://worldofgoo.com/wogbuddy2.php?" + param); if (string.IsNullOrEmpty(s)) throw new Exception(); return s; } private static XElement GetXmlResponseFromString(string s) { // ReSharper disable PossibleNullReferenceException XDocument document; try { document = XDocument.Parse(s); } catch (XmlException e) { throw new Exception(s, e); } var response = document.Element("WogResponse"); if (response.Attribute("result").Value.ToLower() != "ok") throw new Exception(s); return response; // ReSharper restore PossibleNullReferenceException } private static XElement GetXmlResponseAdvanced(string param) { return GetXmlResponseFromString(GetStringResponse(param)); } internal static XElement GetXmlResponse(string param, string playerKey = "df97bc13a9a8d0a02e1939055181f9dd") { return GetXmlResponseAdvanced("version=1%2e40win&playerkey=" + playerKey + "&op=" + param); } internal static long GetRank(double height) { // ReSharper disable PossibleNullReferenceException return long.Parse(GetXmlResponse("SetWogcStat&ballCount=1000000&ballCountAttached=3&height=" + height.ToString()) .Element("rank").Value); // ReSharper restore PossibleNullReferenceException } internal static double GetHeight(long rank) { int left = 0, right = 1200, middle = 0; while (left <= right) { middle = (left + right) >> 1; var result = GetRank(middle / 10.0); if (rank < result) left = middle + 1; else right = middle - 1; } return middle / 10.0; } internal static string GetPlayerName(string playerKey) { // ReSharper disable PossibleNullReferenceException return GetXmlResponse("SetLevelStats&balls=4&levelid=GoingUp&moves=10&time=9999", playerKey).Attribute("message").Value .Replace("recorded levelstat for player ", string.Empty).Replace(", levelid GoingUp", string.Empty); // ReSharper restore PossibleNullReferenceException } private static string GetPlayerName(DatabaseDataContext database, long playerID) { var player = database.WoGPlayer.FirstOrDefault(p => p.ID == playerID); return player != null ? player.PlayerName : null; } internal static byte GetSort(string sort) { switch ((sort ?? string.Empty).ToLower()) { case "balls": // desc return 1; case "player": return 2; case "moves": return 3; case "time": return 4; case "level": return 5; default: // desc return 0; } } } }
So...
What's the point of this? Also, how do you patch WorldOfGoo.exe to contact a different website?
New GooFans Rules | My Addins
I think its a leaderboard like the world of goo leaderboard which is not working anymore.
My Profile
Puggsoy: You can use a patcher program or hex editor to change the name of the website in the executable.
Another Planet finally has an official release! Download chapters 1 through 3 here! Thank you for waiting so long while I kept starting over.