Skip to content

Instantly share code, notes, and snippets.

@at15four2020
Last active September 23, 2022 15:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save at15four2020/2d69302316f3705dec18e6a04c432896 to your computer and use it in GitHub Desktop.
Save at15four2020/2d69302316f3705dec18e6a04c432896 to your computer and use it in GitHub Desktop.
GProgrammer parsers

Parsers

This is a list of known packages parsers mainly to be used in G-Earth with the GProgrammer extension, but the code may be useful to understand the package structure and read it anywhere.

Return structure

Every parser may share some caracteritcs:

  • The parser is responsable to read the whole package, from the start to the end;
  • The return type is always an object;
  • The object always have an raw attribute with the data of the package in the correct order;
  • Any array of data is always an array of objects;
  • Each object of the array always also have an raw attribute;
  • The length of the arrays are not stored, since in this context this can be reached with the length atribute.

Usage

You can import these file with

load(PARSER_URL)

(changing PARSER_URL with the correct one)

Note: the structure have may change at any time, so if you are not confident to update your code with the changes, do not use the global URL of the parser. Instead, use the revision specific URL.

Global URL

The Gist website allows you to fetch the latest revision of each file by using this pattern: https://gist.github.com/USER_NAME/GIST_ID/raw/FILE_NAME

Revision specific URL

To stop using the latest revision, you have to use this pattern: https://gist.github.com/USER_NAME/GIST_ID/raw/REVISION_ID/FILE_NAME

Available parsers

in MarketPlaceOffers

Received when you search items in the market place.

in NewNavigatorSearchResults

Received when you search rooms in the navigator.

in Objects

Received when you enter in a room.

in Users

Received when you enter in a room.

load('https://gist.github.com/at15four2020/2d69302316f3705dec18e6a04c432896/raw/parse_in_MarketPlaceOffers.gprog.js')
load('https://gist.github.com/at15four2020/2d69302316f3705dec18e6a04c432896/raw/parse_in_NewNavigatorSearchResults.gprog.js')
load('https://gist.github.com/at15four2020/2d69302316f3705dec18e6a04c432896/raw/parse_in_Objects.gprog.js')
load('https://gist.github.com/at15four2020/2d69302316f3705dec18e6a04c432896/raw/parse_in_Users.gprog.js')
// parse_in_MarketPlaceOffers.gprog.js
function parse_in_MarketPlaceOffers(packet) {
var initialReadIndex = packet.getReadIndex()
packet.resetReadIndex()
var result = { raw: [] }
result.raw.push(packet.readInteger())
result.items = []
for (var i = 0; i < result.raw[0]; i++) {
var item = { raw: [
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger()
] }
item.offerId = item.raw[0]
item.isTradable = item.raw[1]
item.isTradableReadable = {
1: "normal",
3: "duckets_tradable",
}[item.isTradable] || "unknown"
item.type = item.raw[2]
item.typeReadable = {
1: "floor",
2: "wall",
3: "ltd",
}[item.type] || "unknown"
item.spriteId = item.raw[3]
if (item.type == 1) { // floor
item.raw.push(packet.readInteger())
item.subType = item.raw[item.raw.length - 1]
item.subTypeReadable = {
}[item.subType] || "unknown"
if (item.subType == 0) { // almost everything
item.raw.push(packet.readString())
} else if (item.subType == 1) { // video tv, mannequin
item.customFields = {}
item.raw.push(packet.readInteger())
var fieldsCount = item.raw[item.raw.length - 1]
for (var j = 0; j < fieldsCount; j++) {
item.raw.push(
packet.readString(),
packet.readString()
)
var fieldName = item.raw[item.raw.length - 2]
var fieldValue = item.raw[item.raw.length - 1]
item.customFields[fieldName] = fieldValue
}
} else if (item.subType == 2) { // group items, friendship locks
item.raw.push(packet.readInteger())
var fieldsCount = item.raw[item.raw.length - 1]
for (var j = 0; j < fieldsCount; j++) {
item.raw.push(packet.readString())
}
if (fieldsCount == 5) {
item.group = {
type: item.raw[item.raw.length - 5],
id: item.raw[item.raw.length - 4],
badge: item.raw[item.raw.length - 3],
primaryColor: item.raw[item.raw.length - 2],
secondaryColor: item.raw[item.raw.length - 1]
}
} else if (fieldsCount == 6) {
item.firendshipLock = {
idk: item.raw[item.raw.length - 6], // maybe flag that it is locked
nick1: item.raw[item.raw.length - 5],
nick2: item.raw[item.raw.length - 4],
figureString1: item.raw[item.raw.length - 3],
figureString2: item.raw[item.raw.length - 2],
date: item.raw[item.raw.length - 1]
}
}
} else if (item.subType == 5) { // Background Toner
item.customValues = []
item.raw.push(packet.readInteger())
var valuesCount = item.raw[item.raw.length - 1]
for (var j = 0; j < valuesCount; j++) {
item.raw.push(packet.readInteger())
item.customValues.push(item.raw[item.raw.length - 1])
}
} else if (item.subType == 7) { // items with health (like the cursed flame knight)
item.raw.push(
packet.readString(),
packet.readInteger(),
packet.readInteger()
)
} else {
throw new Error("Unkonwn subtype: "+item.subType+". Sprite: "+item.offerId+" Last: "+JSON.stringify(result.items[i-1], null,2))
}
} else if (item.type == 2) { // wall
item.raw.push(packet.readString())
} else if (item.type == 3) { // ltd
item.raw.push(
packet.readInteger(),
packet.readInteger()
)
item.ltd = {
number: item.raw[item.raw.length - 2],
max: item.raw[item.raw.length - 1]
}
} else {
throw new Error("Unkonwn subtype: "+item.type+". Sprite: "+item.offerId+" Last: "+JSON.stringify(result.items[i-1], null,2))
}
item.raw.push(
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger()
)
item.price = item.raw[item.raw.length - 4]
item.timeLeft = item.raw[item.raw.length - 3]
item.average = item.raw[item.raw.length - 2]
item.amount = item.raw[item.raw.length - 1]
result.items.push(item)
result.raw = result.raw.concat(item.raw)
}
result.raw.push(packet.readInteger())
result.totalResults = result.raw[result.raw.length - 1]
packet.setReadIndex(initialReadIndex)
return result
}
// parse_in_NewNavigatorSearchResults.gprog.js
function parse_in_NewNavigatorSearchResults(packet) {
var initialReadIndex = packet.getReadIndex()
packet.resetReadIndex()
var ROOM_FLAGS = {
hasCustomThumbnail: 1 << 0,
hasGroup: 1 << 1,
hasAdvertisement: 1 << 2,
showOwner: 1 << 3,
allowPets: 1 << 4,
showRoomAd: 1 << 5
}
var ROOM_DOOR_MODE = { // Specifies the types of door modes possible.
0: "open", // Represents a room that is open to everyone.
1: "door_bell", // Represents a room that requires ringing the doorbell to request access.
2: "password", // Represents a room that requires a password to enter.
3: "invisible" // Represents a room that is invisible in the navigator.
}
var ROOM_TRADE_MODE = { // Specifies the types of trade modes possible.
0: "not_allowed", // Represents a room in which trading is not allowed.
1: "controller", // Represents a room in which only the owner and users with room rights are allowed to trade.
2: "allowed" // Represents a room in which everyone is allowed to trade.
}
var ROOM_CATEGORY = { // Specificies a list of all existing room categories.
1: "public_rooms",
2: "party",
3: "habbo_games",
4: "trade", // External flash texts variable for this category is missing.
5: "fansite_square",
6: "help_centers",
7: "habbo_reviews",
8: "builders_club",
10: "personal_space",
11: "building_and_decoration",
12: "char_and_discussion",
13: "trading",
14: "trading",
15: "habbo_life",
16: "agencies",
17: "role_playing"
}
var result = {}
result.searchCode = packet.readString()
result.searchText = packet.readString()
result.qntGroups = packet.readInteger()
if (result.qntGroups) result.groups = []
for (var i = 0; i < result.qntGroups; i++) {
var group = {}
group.groupType = packet.readString()
group.text = packet.readString()
group.actionAllowed = packet.readInteger()
group.forceClosed = packet.readBoolean()
group.viewMode = packet.readInteger()
group.qntRooms = packet.readInteger()
if (group.qntRooms) group.rooms = []
for (var j = 0; j < group.qntRooms; j++) {
var room = {}
room.roomId = packet.readInteger()
room.roomName = packet.readString()
room.ownerId = packet.readInteger()
room.ownerName = packet.readString()
room.doorMode = ROOM_DOOR_MODE[packet.readInteger()]
room.roomUsersCount = packet.readInteger()
room.roomUsersLimit = packet.readInteger()
room.roomDesc = packet.readString()
room.tradeMode = ROOM_TRADE_MODE[packet.readInteger()]
room.roomRate = packet.readInteger()
room.stars = packet.readInteger()
room.roomCategory = ROOM_CATEGORY[packet.readInteger()]
var qntTags = packet.readInteger()
if (qntTags) room.tags = []
for (var k = 0; k < qntTags; k++) {
room.tags[k] = packet.readString()
}
var roomFlags = packet.readInteger()
if (roomFlags & ROOM_FLAGS.hasCustomThumbnail) {
room.thumbnailUrl = packet.readString()
}
if (roomFlags & ROOM_FLAGS.hasGroup) {
room.groupId = packet.readInteger()
room.groupName = packet.readString()
room.badgeHashCode = packet.readString()
}
if (roomFlags & ROOM_FLAGS.hasAdvertisement) {
room.eventName = packet.readString()
room.eventDesc = packet.readString()
room.eventValidity = packet.readInteger()
}
room.showOwner = !!(roomFlags & ROOM_FLAGS.showOwner)
room.allowPets = !!(roomFlags & ROOM_FLAGS.allowPets)
room.showEntryAd = !!(roomFlags & ROOM_FLAGS.showRoomAd)
group.rooms[j] = room
}
result.groups[i] = group
}
packet.setReadIndex(initialReadIndex)
return result
}
// parse_in_Objects.gprog.js
function parse_in_Objects(packet) {
var initialReadIndex = packet.getReadIndex()
packet.resetReadIndex()
var result = { raw: [] }
result.raw.push(packet.readInteger())
var ownersCount = result.raw[0]
result.owners = []
for (var i = 0; i < ownersCount; i++) {
var owner = { raw: [
packet.readInteger(),
packet.readString()
] }
owner.id = owner.raw[0]
owner.nick = owner.raw[1]
result.owners.push(owner)
result.raw = result.raw.concat(owner.raw)
}
result.raw.push(packet.readInteger())
var mobisCount = result.raw[result.raw.length - 1]
result.mobis = []
for (var i = 0; i < mobisCount; i++) {
var mobi = { raw: [] }
mobi.raw.push(
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readString(),
packet.readString(),
packet.readInteger(),
packet.readInteger()
)
mobi.type = mobi.raw[8]
if (mobi.type == 0) { // normal
mobi.raw.push(
packet.readString()
)
} else if (mobi.type == 1) { // custom props, like gifts
// for gifts from users it appears like this:
// "EXTRA_PARAM", "", "MESSAGE", message, "PURCHASER_NAME", purchaser name, "PURCHASER_FIGURE", purchaser figure, "PRODUCT_CODE", gift type
// for figts from hotel it appeas like this:
// "MESSAGE", message, "PRODUCT_CODE", gift type
mobi.raw.push(
packet.readInteger()
)
var customPropsCount = mobi.raw[9]
for (var j = 0; j < customPropsCount; j++) {
mobi.raw.push(
packet.readString(),
packet.readString()
)
}
} else if (mobi.type == 2) { // group items, friendship locks
mobi.raw.push(packet.readInteger())
var fieldsCount = mobi.raw[mobi.raw.length - 1]
for (var j = 0; j < fieldsCount; j++) {
mobi.raw.push(packet.readString())
}
if (fieldsCount == 5) {
mobi.group = {
type: mobi.raw[mobi.raw.length - 5],
id: mobi.raw[mobi.raw.length - 4],
badge: mobi.raw[mobi.raw.length - 3],
primaryColor: mobi.raw[mobi.raw.length - 2],
secondaryColor: mobi.raw[mobi.raw.length - 1]
}
} else if (fieldsCount == 6) {
mobi.firendshipLock = {
idk: mobi.raw[mobi.raw.length - 6], // maybe flag that it is locked
nick1: mobi.raw[mobi.raw.length - 5],
nick2: mobi.raw[mobi.raw.length - 4],
figureString1: mobi.raw[mobi.raw.length - 3],
figureString2: mobi.raw[mobi.raw.length - 2],
date: mobi.raw[mobi.raw.length - 1]
}
}
} else if (mobi.type == 5) { // roombg_color
mobi.raw.push(
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger()
)
} else if (mobi.type == 6) { // highscore
mobi.raw.push(
packet.readString(),
packet.readInteger(),
packet.readInteger(),
packet.readInteger()
)
mobi.highscore = []
var highscoreCount = mobi.raw[mobi.raw.length - 1]
for (var j = 0; j < highscoreCount; j++) {
var highscore = { raw: [] }
highscore.raw.push(
packet.readInteger(),
packet.readInteger()
)
var usersCount = highscore.raw[highscore.raw.length - 1]
for (var k = 0; k < usersCount; k++) {
highscore.raw.push(packet.readString())
}
mobi.highscore.push(highscore)
mobi.raw.concat(highscore.raw)
}
} else if (mobi.type == 7) { // items with health (like the cursed flame knight)
mobi.raw.push(
packet.readString(),
packet.readInteger(),
packet.readInteger()
)
} else if (mobi.type == 256) { // ads_mtv_tv
mobi.raw.push(
packet.readString(),
packet.readInteger(),
packet.readInteger()
)
} else {
throw new Error("Unkonwn type: "+mobi.type+". Sprite: "+mobi.raw[1]+" Last: "+JSON.stringify(result.mobis[i-1], null,2))
}
mobi.raw.push(
packet.readInteger(),
packet.readInteger(),
packet.readInteger()
)
mobi.uid = mobi.raw[0]
mobi.spriteId = mobi.raw[1]
mobi.x = mobi.raw[2]
mobi.y = mobi.raw[3]
mobi.z = Number(mobi.raw[5])
mobi.direction = mobi.raw[4]
mobi.ownerId = mobi.raw[mobi.raw.length - 1]
result.mobis.push(mobi)
result.raw = result.raw.concat(mobi.raw)
}
packet.setReadIndex(initialReadIndex)
return result
}
// parse_in_Users.gprog.js
if (typeof parse_in_Users == "undefined") {
parse_in_Users = (function () {
const users = {
indexToId: {},
idToIndex: {}
}
function parse(packet) {
var initialReadIndex = packet.getReadIndex()
packet.resetReadIndex()
const result = { users: [] }
const usersCount = packet.readInteger()
for (let i = 0; i < usersCount; i++) {
const user = {}
user.id = packet.readInteger()
user.name = packet.readString()
user.motto = packet.readString()
user.figure = packet.readString()
user.index = packet.readInteger()
user.posX = packet.readInteger()
user.posY = packet.readInteger()
user.posZ = packet.readString()
packet.readInteger()
const entityTypeId = packet.readInteger()
switch (entityTypeId) {
case 1: // user
user.gender = packet.readString()
user.groupId = packet.readInteger()
packet.readInteger()
user.groupName = packet.readString()
packet.readString()
packet.readInteger()
packet.readBoolean()
break;
case 2: // pet
packet.readInteger();
packet.readInteger();
packet.readString();
packet.readInteger();
packet.readBoolean();
packet.readBoolean();
packet.readBoolean();
packet.readBoolean();
packet.readBoolean();
packet.readBoolean();
packet.readInteger();
packet.readString();
break;
case 4: // bot
packet.readString();
packet.readInteger();
packet.readString();
for (let j = packet.readInteger(); j > 0; j--) {
packet.readShort()
}
break;
}
users.idToIndex[user.id] = user.index
users.indexToId[user.index] = user.id
result.users.push(user)
}
packet.setReadIndex(initialReadIndex)
return result
}
parse.users = users
return parse
})()
}
// parse_in_UserUpdate.gprog.js
if (typeof parse_in_UserUpdate == "undefined") {
parse_in_UserUpdate = (function () {
function parse(packet) {
var initialReadIndex = packet.getReadIndex()
packet.resetReadIndex()
const result = { users: [] }
const usersCount = packet.readInteger()
for (let i = 0; i < usersCount; i++) {
const user = {}
user.index = packet.readInteger()
user.posX = packet.readInteger()
user.posY = packet.readInteger()
user.posZ = packet.readString()
user.headFacing = packet.readInteger()
user.bodyFacing = packet.readInteger()
user.action = packet.readString()
result.users.push(user)
}
packet.setReadIndex(initialReadIndex)
return result
}
return parse
})()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment