// ==UserScript==
// @name KPD
// @license MIT
// @version 1.0
// @description Kogama Packet Decoder
// @author 0vC4
// @namespace https://greasyfork.org/users/670183
// @match http://*/*
// @match https://*/*
// @grant none
// @run-at document-start
// ==/UserScript==
const KPD = (() => {
const code2type = code => Object.fromEntries(Object.entries(code).map(a=>a.reverse()));
const PhotonCode = {ClientKey:1,ModeKey:2,ServerKey:1,InitEncryption:0,Ping:1,Ok:0};
const MVOpCode = {RegisterWorldObject:0,UnregisterWorldObject:1,UpdateWorldObject:2,UpdateWorldObjectData:3,UpdateWorldObjectDataPartial:4,RemoveWorldObjectDataPartial:5,TransferOwnership:6,UpdatePrototype:7,UpdatePrototypeScale:8,AddLink:9,RemoveLink:10,PublishPlanet:11,AddPrototypeToInventory:12,RemoveItemFromInventory:13,UpdateInventorySlots:14,RequestFriendshipByProfileId:15,RequestAcceptFriendship:16,RequestRejectFriendship:17,TriggerBoxEnter:18,TriggerBoxExit:19,LockHierarchy:20,UploadScreenshot:21,RequestWoUniquePrototype:22,ReportCaptureFlag:23,ResetLogicChunk:24,UpdateWorldObjectRunTimeData:25,UpdateLineOfFire:26,WorldObjectRPCOperation:27,PostGameMsg:28,SetTeam:29,AddObjectLink:30,RemoveObjectLink:31,TransferWorldObjectsToGroup:32,CloneWorldObjectTree:33,AddPlanetToPlanet:34,PurchaseProduct:35,GetNextGameBatch:36,RequestBuiltInItem:37,AddItemToWorld:38,AddWorldObjectToInventory:39,AddWorldObjectToInventoryDev:40,SetActiveAvatar:41,ResetAvatar:42,GetMarketPlaceItem:43,AddItemToMarketPlace:44,RemoveItemFromMarketPlace:45,SetAvatarAccessorySlot:46,AttachWorldObjectToSeat:47,DetachWorldObjectFromVehicle:48,SpawnVehicleWithDriver:49,ClientLog:50,UpdateAvatarAccessoryOffset:51,RuntimeEvent:52,ResetTerrain:53,AddAvatarToAvatarShopInventory:54,DeleteAvatarFromShopInventory:55,LevelChanged:56,Ban:57,Syncronize:58,SwitchAvatar:59,SyncronizePing:60,JoinNotification:61,UploadBytes:62,Notification:63,CloneWorldObjectTreeWithPosition:64,CloneTempWorldObjectWithOriginalReference:65,LogicActivateRequest:66,AdminOperation:67,OwnerOperation:68,ResetFirstTimeEvents:83,SetFirstTimeEvent:84,OverrideFirstTimeEvent:85,GetResetAvatar:86,ClaimPlayingNewGameRewardedGold:87,PostChatMsg:88,SetSayChatBubbleVisible:93,ReportReachedTimeAttackFlag:94,RequestAccessoryData:95,UnEquipAccessory:96,SetHighlightToSeen:97,ResetHighlights:98,UpdateAvatarAccessoryScale:99,GetThemesData:100,SetMouseSensitivity:101,StartSessionTime:102,ResetPlayerPlanetData:103,GetHighScoreList:104,SetGamePassTierOperation:105,SetGamePassTierToSeenOperation:106,SetEarningsReportToSeenOperation:107,GetTopHighScoreList:108,ClaimGamePointWelcomeReward:109,UpdateGold:110,SetActiveSpawnRole:111,CustomDevCommands:112,CreateSpawnRole:113,GetAvatarBodies:114,SetSpawnRoleBody:115,TogglePreviewTierOperation:116,ClaimRewardedAdXP:117,IncrementStatRequest:118,Undefined:119,Join:255,Leave:254,RaiseEvent:253,SetProperties:252,GetProperties:251,Ping:249};
const MVECode = {NoCodeSet:0,UnregisterWorldObject:1,UpdateWorldObject:2,UpdateWorldObjectData:3,UpdateWorldObjectDataPartial:4,RemoveWorldObjectDataPartial:5,TransferOwnership:6,UpdateNetworkInput:7,RegisterPrototype:8,UnregisterPrototype:9,UpdatePrototype:10,UpdatePrototypeScale:11,UpdateTerrain:12,AddLink:13,RemoveLink:14,RemoveItemFromInventory:15,FriendRequest:16,FriendUpdate:17,TriggerBoxEnter:18,TriggerBoxExit:19,TriggerBoxStayBegin:20,TriggerBoxStayEnd:21,Clone:22,LockHierarchy:23,BlueprintCreationDone:24,WoUniquePrototype:25,GameStateChange:26,SyncAvatarStatus:27,ResetLogicChunk:28,UpdateWorldObjectRunTimeData:29,PickupItemStateChange:30,UpdateLineOfFire:31,WorldObjectRPCEvent:32,XPReceivedEvent:33,PostGameMsgEvent:34,SetTeam:35,AddObjectLink:36,RemoveObjectLink:37,TransferWorldObjectsToGroup:38,CloneWorldObjectTree:39,GetGameBatch:40,GameQueryReady:41,PostWinnerReport:42,CollectiblePickedUp:43,SetWorldObjectsToPurchasedEvent:44,AchievementUnlockedEvent:45,AttachWorldObjectToSeat:46,DetachWorldObjectFromVehicle:47,SpawnVehicleWithDriver:48,Reward:49,RuntimeEvent:50,ResetTerrainEvent:51,UpdateGameStat:52,UpdateGameStatType:53,UpdateAvatarMetaData:54,LevelChanged:55,GameBoostEvent:56,NotificationEvent:57,RequestMaterials:58,GetPlanetOwnershipTypes:59,GetItemCategories:60,SetupUserPlayMode:61,GameSnapshotData:62,SetActorReady:63,RequestFriends:64,GetItemInventory:65,GetItemShopInventory:66,GetBuiltInItemBusinessData:67,LargeDBQueryAvatarShopInventory:68,InitializeAvatarEdit:69,GetActiveAvatar:70,PendingByteDataBatch:71,SwitchAvatar:72,SyncronizePing:73,StartRewardCountDown:74,RewardIsReady:75,NumberOfPendingRewards:76,JoinNotification:77,CloneWorldObjectTreeWithPosition:78,CloneTempWorldObjectWithOriginalReferenceEvent:79,LogicObjectFiringStateChange:80,LogicFrame:81,CollectTheItemDropOff:82,LogicFastForward:83,LogicFastForwardEventImmediate:84,ForceDetachWorldObjectFromVehicle:85,XPReward:86,GetProfileMetaData:87,ServerError:88,SetSayChatBubbleVisible:89,GetPublishedPlanetProfileData:90,PlayerPlanetData:91,PlayerPlanetRemote:92,HighScores:93,GoldRewardedForLevel:94,NextLevelGoldReward:95,PlayerTierStateCalculatorChanged:96,GetProjectEarnings:97,TopHighScores:98,GetKogamaVat:99,GetSubscriptionPerksData:100,SetupUserAvatarEdit:101,SetupUserBuildMode:102,SetActiveSpawnRole:103,ReplicateSpawnRoleData:104,SetSpawnRoleBody:105,XPRewardedAdReady:106,Join:255,Leave:254,PropertiesChanged:253};
const GpCode = {
Unknown: 0,
Null: 42,
Dictionary: 68,
StringArray: 97,
Byte: 98,
Custom: 99,
Double: 100,
EventData: 101,
Float: 102,
Hashtable: 104,
Integer: 105,
Short: 107,
Long: 108,
IntegerArray: 110,
Boolean: 111,
OperationResponse: 112,
OperationRequest: 113,
String: 115,
ByteArray: 120,
Array: 121,
ObjectArray: 122
};
const GpType = code2type(GpCode);
const MVEType = code2type(MVECode);
const MVOpType = code2type(MVOpCode);
const PhotonType = code2type(PhotonCode);
const take = arr => new DataView(Uint8Array.from(arr).buffer);
const put = (num, typed) => [...new Uint8Array(typed.of(num).buffer).reverse()];
const GpValue = {
get: {
Unknown: arr => ({Type: GpType[arr.shift()], Value: null}),
Null: arr => ({Type: GpType[arr.shift()], Value: null}),
Dictionary: arr => {
let Type = GpType[arr.shift()];
let TKey = GpType[arr.shift()];
let TValue = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
if (!(TKey == "Unknown" || TKey == "Null")) arr.unshift(GpCode[TKey]);
let key = GpValue.get[GpType[arr[0]]](arr);
if (!(TValue == "Unknown" || TValue == "Null")) arr.unshift(GpCode[TValue]);
let value = GpValue.get[GpType[arr[0]]](arr);
Value.push([key, value]);
}
return {Type, TKey, TValue, Size, Value,
get (key) {
let slot = this.Value.find(s=>s[0].Value == key);
if (slot) return slot[1];
return null;
},
keys () {
return this.Value.map(s=>s[0].Value);
},
set (key, value) {
let slot = this.Value.find(s=>s[0].Value == key.Value);
if (slot) slot[1] = value;
else this.Value.push([key, value]);
}
};
},
StringArray: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
Byte: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,1)).getUint8()}),
Custom: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
Double: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,8)).getFloat64()}),
EventData: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
Float: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,4)).getFloat32()}),
Hashtable: arr => {
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let key = GpValue.get[GpType[arr[0]]](arr);
let value = GpValue.get[GpType[arr[0]]](arr);
Value.push([key,value]);
}
return {Type, Size, Value};
},
Integer: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,4)).getInt32()}),
Short: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,2)).getInt16()}),
Long: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,8)).getBigInt64()}),
IntegerArray: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
Boolean: arr => ({Type: GpType[arr.shift()], Value: take(arr.splice(0,1)).getUint8() > 0}),
OperationResponse: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
OperationRequest: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
},
String: arr => {
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = new TextDecoder().decode(Uint8Array.from(arr.splice(0, Size)));
return {Type, Size, Value};
},
ByteArray: arr => {
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,4)).getInt32();
let Value = Uint8Array.from(arr.splice(0, Size));
return {Type, Size, Value};
},
Array: arr => {
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let TValue = GpType[arr.shift()];
let Value = [];
let i = 0;
while (i++ < Size) {
arr.unshift(GpCode[TValue]);
let value = GpValue.get[GpType[arr[0]]](arr);
Value.push(value);
}
return {Type, Size, TValue, Value};
},
ObjectArray: arr => {
/*
let Type = GpType[arr.shift()];
let Size = take(arr.splice(0,2)).getInt16();
let Value = [];
let i = 0;
while (i++ < Size) {
let value = GpValue.get[arr[0]](arr);
Value.push(value);
}
return {Type, Size, Value};
*/
console.log(GpType[arr[0]], arr.slice(0));
}
},
set: {
Unknown: data => [GpCode[data.Type]],
Null: data => [GpCode[data.Type]],
Dictionary: data => {
let arr = [GpCode[data.Type], GpCode[data.TKey], GpCode[data.TValue], ...put(data.Size, Int16Array)];
for (let slot of data.Value) {
let key = GpValue.set[slot[0].Type](slot[0]);
if (!(data.TKey == "Unknown" || data.TKey == "Null")) key.splice(0,1);
let value = GpValue.set[slot[1].Type](slot[1]);
if (!(data.TValue == "Unknown" || data.TValue == "Null")) value.splice(0,1);
arr.push(...key, ...value);
}
return arr;
},
StringArray: data => [GpCode[data.Type]],
Byte: data => [GpCode[data.Type], ...put(data.Value, Uint8Array)],
Custom: data => [GpCode[data.Type]],
Double: data => [GpCode[data.Type], ...put(data.Value, Float64Array)],
EventData: data => [GpCode[data.Type]],
Float: data => [GpCode[data.Type], ...put(data.Value, Float32Array)],
Hashtable: data => {
let arr = [GpCode[data.Type], ...put(data.Size, Int16Array)];
for (let slot of data.Value) {
let key = GpValue.set[slot[0].Type](slot[0]);
let value = GpValue.set[slot[1].Type](slot[1]);
arr.push(...key,...value);
}
return arr;
},
Integer: data => [GpCode[data.Type], ...put(data.Value, Int32Array)],
Short: data => [GpCode[data.Type], ...put(data.Value, Int16Array)],
Long: data => [GpCode[data.Type], ...put(data.Value, BigInt64Array)],
IntegerArray: data => [GpCode[data.Type]],
Boolean: data => [GpCode[data.Type], ...put(data.Value > 0, Uint8Array)],
OperationResponse: data => [GpCode[data.Type]],
OperationRequest: data => [GpCode[data.Type]],
String: data => [GpCode[data.Type], ...put(data.Size, Int16Array), ...new TextEncoder().encode(data.Value)],
ByteArray: data => [GpCode[data.Type], ...put(data.Size, Int32Array), ...data.Value],
Array: data => {
let arr = [GpCode[data.Type], ...put(data.Size, Int16Array), GpCode[data.TValue]];
for (let value of data.Value) {
arr.push(...GpValue.set[value.Type](value).slice(1));
}
return arr;
},
ObjectArray: data => [GpCode[data.Type]]
}
};
const typeOf = packet => {
const MagicNumber = packet[0];
const flag = packet[1]&127;
if (MagicNumber == 0xF0) return "Ping";
if (flag == 7 && code == PhotonCode.Ping) return "Ping";
const code = packet[2];
return {
1: "Connected",
2: MVOpType[code],
3: MVOpType[code],
4: MVEType[code],
6: "Ping",
7: MVOpType[code],
8: "UnknownMessage",
9: "Unknown"
}[flag] || "Unknown";
};
const getParams = packet => {
const data = {};
const size = take(packet.splice(0,2)).getInt16();
let i = 0;
while (i < size) {
data[packet.shift()] = GpValue.get[GpType[packet[0]]](packet);
i++;
}
return data;
};
const decode = packet => {
const type = typeOf(packet);
if (type == "Ping" || type == "Unknown" || type == "Connected") return null;
const flag = packet[1]&127;
if (flag != 1 && (packet[1]&128) > 0) return null; //need decrypt message
const data = {};
data.magicNumber = packet.shift();
data.flag = packet.shift();
if (flag == 8) {
data.message = GpValue.get[GpType[packet[0]]](packet);
return data;
}
data.opCode = (flag == 4 ? MVEType : MVOpType)[packet.shift()];
if (flag == 3 || flag == 7) {
data.returnCode = take(packet.splice(0,2)).getInt16();
data.debugMessage = GpValue.get[GpType[packet[0]]](packet);
}
data.params = getParams(packet);
return data;
};
const setParams = data => {
const packet = [];
packet.push(...put(Object.keys(data.params).length, Int16Array));
for (const slot in data.params) {
const value = data.params[slot];
packet.push(+slot, ...GpValue.set[value.Type](value));
}
return packet;
};
const encode = data => {
if (typeof data == null) return null;
if (typeof data !== 'object') return [...data];
const packet = [];
packet.push(data.magicNumber, data.flag);
const flag = data.flag&127;
if (flag == 8) {
packet.push(...GpValue.set[data.message.Type](data.message));
return packet;
}
packet.push((flag == 4 ? MVECode : MVOpCode)[data.opCode]);
if (flag == 3 || flag == 7) {
packet.push(...put(data.returnCode, Int16Array));
packet.push(...GpValue.set[data.debugMessage.Type](data.debugMessage));
}
packet.push(...setParams(data));
return packet;
};
return {
typeOf,
decode,
encode
};
})();
// 0vC4#7152