PixelPiggy/CS_float
0
1const fs = require('fs'),2 winston = require('winston'),3 vdf = require('simple-vdf'),4 utils = require('./utils');5 6const floatNames = [{7 range: [0, 0.07],8 name: 'SFUI_InvTooltip_Wear_Amount_0'9},{10 range: [0.07, 0.15],11 name: 'SFUI_InvTooltip_Wear_Amount_1'12},{13 range: [0.15, 0.38],14 name: 'SFUI_InvTooltip_Wear_Amount_2'15},{16 range: [0.38, 0.45],17 name: 'SFUI_InvTooltip_Wear_Amount_3'18},{19 range: [0.45, 1.00],20 name: 'SFUI_InvTooltip_Wear_Amount_4'21}];22 23 24const LanguageHandler = {25 get: function(obj, prop) {26 return obj[prop.toLowerCase()];27 },28 has: function (obj, prop) {29 return prop.toLowerCase() in obj;30 }31};32 33class GameData {34 constructor(update_interval, enable_update) {35 this.items_game_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game.txt';36 this.items_game_cdn_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/scripts/items/items_game_cdn.txt';37 this.csgo_english_url = 'https://raw.githubusercontent.com/SteamDatabase/GameTracking-CS2/master/game/csgo/pak01_dir/resource/csgo_english.txt';38 this.schema_url = 'https://raw.githubusercontent.com/SteamDatabase/SteamTracking/b5cba7a22ab899d6d423380cff21cec707b7c947/ItemSchema/CounterStrikeGlobalOffensive.json';39 40 this.items_game = false;41 this.items_game_cdn = false;42 this.csgo_english = false;43 this.schema = false;44 45 // Create the game data folder if it doesn't exist46 if (!utils.isValidDir('game_files')) {47 winston.info('Creating game files directory');48 fs.mkdirSync('game_files');49 }50 else {51 // check if we can load the files from disk52 this.loadFiles();53 }54 55 if (enable_update) {56 // Update the files57 this.update();58 59 // Setup interval60 if (update_interval && update_interval > 0) setInterval(() => {this.update();}, update_interval*1000);61 }62 }63 64 /*65 Loads items_game, csgo_english, and items_game_cdn from disk66 */67 loadFiles() {68 if (fs.existsSync('game_files/items_game.txt')) {69 this.items_game = vdf.parse(fs.readFileSync('game_files/items_game.txt', 'utf8'))['items_game'];70 }71 72 if (fs.existsSync('game_files/csgo_english.txt')) {73 const f = fs.readFileSync('game_files/csgo_english.txt', 'utf8');74 this.csgo_english = this.objectKeysToLowerCase(vdf.parse(f)['lang']['Tokens']);75 this.csgo_english = new Proxy(this.csgo_english, LanguageHandler);76 }77 78 if (fs.existsSync('game_files/items_game_cdn.txt')) {79 let data = fs.readFileSync('game_files/items_game_cdn.txt', 'utf8');80 this.items_game_cdn = this.parseItemsCDN(data);81 }82 83 if (fs.existsSync('game_files/schema.json')) {84 let data = fs.readFileSync('game_files/schema.json', 'utf8');85 this.schema = JSON.parse(data)['result'];86 }87 }88 89 /*90 Parses the data of items_game_cdn91 */92 parseItemsCDN(data) {93 let lines = data.split('\n');94 95 const result = {};96 97 for (let line of lines) {98 let kv = line.split('=');99 100 if (kv[1]) {101 result[kv[0]] = kv[1];102 }103 }104 105 return result;106 }107 108 /*109 Calls toLowerCase on all object shallow keys, modifies in-place, not pure110 */111 objectKeysToLowerCase(obj) {112 const keys = Object.keys(obj);113 let n = keys.length;114 while (n--) {115 const key = keys[n];116 const lower = key.toLowerCase();117 if (key !== lower) {118 obj[lower] = obj[key];119 delete obj[key];120 }121 }122 123 return obj;124 }125 126 /*127 Updates and saves the most recent versions of csgo_english, items_game, and items_game_cdn from the SteamDB Github128 */129 update() {130 winston.info('Updating Game Files...');131 132 utils.downloadFile(this.items_game_url, (data) => {133 if (data) {134 winston.debug('Fetched items_game.txt');135 this.items_game = vdf.parse(data)['items_game'];136 fs.writeFileSync('game_files/items_game.txt', data, 'utf8');137 }138 else winston.error('Failed to fetch items_game.txt');139 });140 141 utils.downloadFile(this.csgo_english_url, (data) => {142 if (data) {143 winston.debug('Fetched csgo_english.txt');144 this.csgo_english = this.objectKeysToLowerCase(vdf.parse(data)['lang']['Tokens']);145 this.csgo_english = new Proxy(this.csgo_english, LanguageHandler);146 147 fs.writeFileSync('game_files/csgo_english.txt', data, 'utf8');148 }149 else winston.error('Failed to fetch csgo_english.txt');150 });151 152 utils.downloadFile(this.items_game_cdn_url, (data) => {153 if (data) {154 winston.debug('Fetched items_game_cdn.txt');155 this.items_game_cdn = this.parseItemsCDN(data);156 fs.writeFileSync('game_files/items_game_cdn.txt', data, 'utf8');157 }158 else winston.error('Failed to fetch items_game_cdn.txt');159 });160 161 utils.downloadFile(this.schema_url, (data) => {162 if (data) {163 winston.debug('Fetched schema.json');164 this.schema = JSON.parse(data)['result'];165 fs.writeFileSync('game_files/schema.json', data, 'utf8');166 }167 else winston.error('Failed to fetch schema.json');168 });169 }170 171 /*172 Given returned iteminfo, finds the item's min/max float, name, weapon type, and image url using CSGO game data173 */174 addAdditionalItemProperties(iteminfo) {175 if (!this.items_game || !this.items_game_cdn || !this.csgo_english) return;176 177 // Get sticker codename/name178 const stickerKits = this.items_game.sticker_kits;179 for (const sticker of iteminfo.stickers || []) {180 const kit = stickerKits[sticker.stickerId];181 182 if (!kit) continue;183 184 sticker.codename = kit.name;185 sticker.material = kit.sticker_material;186 187 let name = this.csgo_english[kit.item_name.replace('#', '')];188 189 if (sticker.tintId) {190 name += ` (${this.csgo_english[`Attrib_SprayTintValue_${sticker.tintId}`]})`;191 }192 193 if (name) sticker.name = name;194 }195 // Get keychain name196 const keychainDefinitions = this.items_game.keychain_definitions;197 for (const keychain of iteminfo.keychains || []) {198 const kit = keychainDefinitions[keychain.sticker_id];199 200 if (!kit) continue;201 202 let name = this.csgo_english[kit.loc_name.replace('#', '')];203 204 if (name) keychain.name = name;205 }206 207 // Get the skin name208 let skin_name = '';209 210 if (iteminfo.paintindex in this.items_game['paint_kits']) {211 skin_name = '_' + this.items_game['paint_kits'][iteminfo.paintindex]['name'];212 213 if (skin_name == '_default') {214 skin_name = '';215 }216 }217 218 // Get the weapon name219 let weapon_name;220 221 if (iteminfo.defindex in this.items_game['items']) {222 weapon_name = this.items_game['items'][iteminfo.defindex]['name'];223 }224 225 // Get the image url226 let image_name = weapon_name + skin_name;227 228 if (image_name in this.items_game_cdn) {229 iteminfo['imageurl'] = this.items_game_cdn[image_name];230 }231 232 // Get the paint data and code name233 let code_name;234 let paint_data;235 236 if (iteminfo.paintindex in this.items_game['paint_kits']) {237 code_name = this.items_game['paint_kits'][iteminfo.paintindex]['description_tag'].replace('#', '');238 paint_data = this.items_game['paint_kits'][iteminfo.paintindex];239 }240 241 // Get the min float242 if (paint_data && 'wear_remap_min' in paint_data) {243 iteminfo['min'] = parseFloat(paint_data['wear_remap_min']);244 }245 else iteminfo['min'] = 0.06;246 247 // Get the max float248 if (paint_data && 'wear_remap_max' in paint_data) {249 iteminfo['max'] = parseFloat(paint_data['wear_remap_max']);250 }251 else iteminfo['max'] = 0.8;252 253 let weapon_data = '';254 255 if (iteminfo.defindex in this.items_game['items']) {256 weapon_data = this.items_game['items'][iteminfo.defindex];257 }258 259 // Get the weapon_hud260 let weapon_hud;261 262 if (weapon_data !== '' && 'item_name' in weapon_data) {263 weapon_hud = weapon_data['item_name'].replace('#', '');264 }265 else {266 // need to find the weapon hud from the prefab267 if (iteminfo.defindex in this.items_game['items']) {268 let prefab_val = this.items_game['items'][iteminfo.defindex]['prefab'];269 weapon_hud = this.items_game['prefabs'][prefab_val]['item_name'].replace('#', '');270 }271 }272 273 // Get the skin name if we can274 if (weapon_hud in this.csgo_english && code_name in this.csgo_english) {275 iteminfo['weapon_type'] = this.csgo_english[weapon_hud];276 iteminfo['item_name'] = this.csgo_english[code_name];277 }278 279 // Get the rarity name (Mil-Spec Grade, Covert etc...)280 const rarityKey = Object.keys(this.items_game['rarities']).find((key) => {281 return parseInt(this.items_game['rarities'][key]['value']) === iteminfo.rarity;282 });283 284 if (rarityKey) {285 const rarity = this.items_game['rarities'][rarityKey];286 287 // Assumes weapons always have a float above 0 and that other items don't288 // TODO: Improve weapon check if this isn't robust289 iteminfo['rarity_name'] = this.csgo_english290 [rarity[iteminfo.floatvalue > 0 ? 'loc_key_weapon' : 'loc_key']];291 }292 293 // Get the quality name (Souvenir, Stattrak, etc...)294 const qualityKey = Object.keys(this.items_game['qualities']).find((key) => {295 return parseInt(this.items_game['qualities'][key]['value']) === iteminfo.quality;296 });297 298 iteminfo['quality_name'] = this.csgo_english[qualityKey];299 300 // Get the origin name301 const origin = this.schema['originNames'].find((o) => o.origin === iteminfo.origin);302 303 if (origin) {304 iteminfo['origin_name'] = origin['name'];305 }306 307 // Get the wear name308 const wearName = this.getWearName(iteminfo.floatvalue);309 if (wearName) {310 iteminfo['wear_name'] = wearName;311 }312 313 const itemName = this.getFullItemName(iteminfo);314 if (itemName) {315 iteminfo['full_item_name'] = itemName;316 }317 }318 319 getWearName(float) {320 const f = floatNames.find((f) => float > f.range[0] && float <= f.range[1]);321 322 if (f) {323 return this.csgo_english[f['name']];324 }325 }326 327 getFullItemName(iteminfo) {328 let name = '';329 330 // Default items have the "unique" quality331 if (iteminfo.quality !== 4) {332 name += `${iteminfo.quality_name} `;333 }334 335 // Patch for items that are stattrak and unusual (ex. Stattrak Karambit)336 if (iteminfo.killeatervalue !== null && iteminfo.quality !== 9) {337 name += `${this.csgo_english['strange']} `;338 }339 340 name += `${iteminfo.weapon_type} `;341 342 if (iteminfo.weapon_type === 'Sticker' || iteminfo.weapon_type === 'Sealed Graffiti') {343 name += `| ${iteminfo.stickers[0].name}`;344 } else if (iteminfo.weapon_type === 'Charm') {345 name += `| ${iteminfo.keychains[0].name}`;346 }347 348 // Vanilla items have an item_name of '-'349 if (iteminfo.item_name && iteminfo.item_name !== '-') {350 name += `| ${iteminfo.item_name} `;351 352 if (iteminfo.wear_name) {353 name += `(${iteminfo.wear_name})`;354 }355 }356 357 return name.trim();358 }359}360 361module.exports = GameData;362 