Poviem vám jeden príbeh, príbeh o starej platni. Ale čil reálne. Rozpovím krátky príbeh o tom, jak som dlhé roky mal v hlave nápad, ideu, kerá mi došla ždy tak mierne komplikuvaná.
Fascinácia Farming Simulatorom 2008 a 2009 neni v mojom prípade žádna nová vec. Veďá to už šetci. A tí čo to neveďá to určite eventualne zisťá. Hru jako takú, najprv teda LS2008 a potom LS2009 poznám ešte z doby, kedy vlastne existuval iba LS2008. Najprv bol ze mňa hráč, potom sa to časom zmenilo na pokusné vývoje vecí a rýpaní do hry jako takej. Móžem povedať že za posledných 8 rokov som vác zisťuval jak veci fungujú a jak sa čo ohĺadom týchto GIANTS Enginom poháňaných hér týka, jak to že by som tí hry jako také hral. A teda tento engine, kerý má svoje začátky vraj ešte jako vysokoškolský projekt jedného z týpkov, má totiž nedostatek. (teda, tých je tam vác ale to má šecko svoje opodstatnení

GIANTS Software robeu veci na kolene a často to tak vyzíralo. Ide o to, že kreslení fontov a GUI ve Farming Simulator 2008, Farming Simulator 2009, Demolition Company, Farming Simulator 2011, Ski Region Simulator 2012 a Farming Simulator 2013 bolo vázané na 4:3 aspect. Upresním. Keď mal človek 4:3 rozlíšení, tak šecky prvky čo mali byť štvorcové, štvorcovými ostali. Šecko bolo a funguvalo dobre dokedy človek nezačal meniť rozlíšení na 5:4, 16:9, alebo potenciálne ešte širšé aspecty. V tomto prípade to títo 4:3 fixné prvky začalo rozťahuvať, keďže to absolutne nebolo prerátavané na aktuálne rozlíšení.
Celé kreslení UI v engine funguje na spósobe kedy body 0,0 sú presne v ľavom spodnom rohu a body 1,1 sú v pravom hornom. 1,0 je teda pravý dolný, 0,1 je ľavý horný a tak podobne. V podstate klasika jakou funguje aj kreslení grafov a tak.
Vlastne, kašlem na to. Mám to tu storazy vysvetluvať, to radšej raz ukážem.
Čo Čil?
UI v hre je, podobne jak ostatek veškerej logiky, vyskladané Lua kódom. Prístup k tomuto "zdekompiluvanému" kódu máme už strašne dlho. Podobne to je aj pre novšé a staršé verzie hry. Ide o to, že som teda zlepeu taký guiWidescreenFix mód kerý prerátava šecky šírky a pozície UI elementov tak, aby neboli od 0 do 1 s 4:3 aspectom, ale aby boli od 0 do 1 s aspectom rozlíšeňá v jakom hra aktuálne ide.
V podstate to pridalo pár rádkov kódu kerý robí prepočty a hovadiny kde sa šecky body šírky a horizontálne pozicie overlayov a textu prerátajú z toho 4:3 aspectu na aktuálny. Absolutne triviálna sprostosť.
Ťažko sa to jakože vysvetluje tak ale kto má dosť času a chute, pochopí. A ten kto nepochopí, uvidí screenshot dole nižší.
Vec sa podarila! Či?
No, jak sa to vezne. Ono zas prerátať šírky a pozície neni zrovna šecko čo človek mosí spraviť. Čas na názornú ukážku.
Čo je ale s tým fontom? Nemalo to opraviť aj ten?
Toto je vec, kóli kerej sa vlákno volá tak jak sa volá, a dóvod kóli kerému vývoj tejto srandy trval od nápadu k realizácií roky. Idem priblížiť že čo.
Vec sa teda nepodarila. Jako ďalej?
Pojme na to ešte raz. Máme hru, máme fix kerý ríši UI záležitosti ale neporíšilo to problémy s kreslením textu.
Táto problematika spočíva v takom onom, že na kreslení textu sa do enginu volá. Jak sa do neho volá, sa naspák z neho síce neozýva, ale parametre volanej funkcie sú tri floaty a jeden string. Prvým floatom je pozícia x od 0 do 1, jak už víme. Druhý float je pozícia y, ťéž od 0 do 1. Potom je float na veľkosť fontu a posledným je string s daným reťazcom kerý chceme aby nám engine vykresleu.
A tu začína náš problém. My sme síce renderText opatchuvali aby začal reaguvať na aktuálny aspect, ale keďže rátaní šírky znakov, interné rozlíšení pre font render a títo veci sú interné veci v engine samotnom, tak mi neostáva nič inakšé, jak len začať maximálne bolestivý a problematický proces reálnej dekompilácie, porádnej dekompilácie.
Jak už z toť tohto vlákna dávno víme, na Windowsových buildoch neboli nikdy žádne symboly, žádne exporty. V prípade macOS buildov sme síce mali "symboly" v podobe exportov áááále toto je vec, kerá nám úplne extra moc čil nepomóže. Problémom je, že 101% ľudí čo hráva LS2008-LS2013, ho hráva zrovna na Windowse.
A čo je to tá dekompilácia?
Priznám sa. Ja som furt človek značne neskúsený, značne neznalý v celých týchto vecách. Vím ale jedno, neni som úplne inteligencia umelá ale skór čiastočne reálna, tak som vyskúšal že čo je v mojich silách.
Ono jedna vec sa má tak, keď má človek binárku z platformy kde je aspoň volačo, ví to tam vystopuvať a opatchuvať, tak určite bude existuvať spósob, jak to dostať na tú od kerej nemáme absolutne nič.Volákym spósobom... ja nevím.. vytipuvať, pokukať či sú neni voláke zhody se stringami, pokukať že či sa možno voláka zhoda krajná nenájde alebo čo.
Problém číslo 1: nájsť problematickú časť kódu.
Išóv som na istotu. Išóv som hneď zhľadávať veci typu width, size, font, character a tak. Po úspešnom nájdení vecí jako je FontRenderer:FontRenderer, FontRenderer:getGlyphWidth, FontRenderer:print a podobné som dospel k záveru, že getGlyphWidth bude určite volačo, čo má šancu ma dostať najďalej. (ale nejdem tu nič vyprávať dopredu

Problém číslo 2: našli sme to volačo, jako ďalej
No, vec sa skór má tak, že ja som ešte z augusta, kedy vyšlo hento vlákno, mal pár screenshotov experimentov zrovna tejto istej veci. Ak to dočilku neni na mne videť že ja tento problém mám v hlave minimálne od 2020, tak ja nevím čo. Ale naspák k veci. Funkciu getGlyphWidth som nepatchoval, nebral som to proste za logické to robiť na tej macOS verzií keď to tam aj tak nikdy nikto nebude patchuvať.
Čas to nájsť teda na Windowsovej.
Problém číslo 3: jak to je možné že to tam neni?
Bolo by komické, keby som zabeu strašne moc času s tým, že sa snažím nájsť getGlyphWidth. Ano, to je reálne to, čo sa stalo.
Množstvo času kerého som vrazeu do kukaňá v disassembleri na nájdení funkcie sa furt zvyšuvalo. Ponachádzal som šecko možné, našóv som konštruktora, našóv som print funkcie, dokonca som našóv v crossreferenciách aj dodatočné funkcie v kerých sa tí FontRenderer veci nachádzali. Ale getGlyphWidth furt nide. Vedel som že sa poraziť nemóžem nehať, lebo tá hodnota, kerá určuje tí širky tam PROSTE VOLADE BYŤ MOSÍ!!
Problém číslo 4: kde to teda je?
Počas celej plejády nálad a pocitov som došóv minimálne k jednej veci. Treba mi robiť počas disassemblu prestávky. Ono to krátkodobé uvolnení, rozvázaní mysle mi fakt pomóže sa potom k veci vrátiť a dospeť k tomu, že to čo sa snažím nájsť asi aj tak bude možno inde. Keď odmyslím to, že som medzičasom z dekompilácie macOS binárky stihol vyskladať už jako taký struct a ten dokonca prehodil do tej Windowsovej dekompilácie tak som si s ním neskutočne pomohol. Totižto v konštruktori pre FontRenderer sa nastavujú hodnoty pre kopu premenných tej jednej jedinej inštancie čo sa v celom engine používa. To že som konštruktor vytipuval z dekompilácií tej macOSovej a napasuval na Windowsovú je ďalšá vec. Každopádne ide o to, že tam v ňom sa na moje prekvapení po jakomtakom vyplnení structu začali objavuvať zaujímavé veci jako napríklad this->width = 640; a this->height = 480;
(Ne)problém číslo 5: Čo sa stane keď...
zmením hodnotu šírky z 640 na 800 napríklad. V tomto čase som už dávno vedel že zakál títo existujúce funkcie, z kerých sa teda podarilo títo premenné do decompu určiť, šírku a výšku nastavujú, tak nikde sa nepoužívajú a ani nereferencujú. Vyvolávalo to celé ve mne taký pocit že teoreticky to asi ani neni reálne nide využité kompletne, že to je iba voláky pozostatek za tých 5 rokov vývoja čo Christian H. Ammann dal do enginu a hry jako takej.
Ale povedal som si že to teda fakt aj sprobujem. Upraveu som hodnotu inštrukcie tak, aby tam teda nebolo 640 ale 800 a hru som pusteu. Moje emócie sú sice neni nakameruvané, ale sú aspoň zachytené jedným screenshotom.
Dekompilácia úspešná, čo ďál?
Keďže som už zisteu že de je zakopaný pes, tak treba dójsť na to, jak to čo najmenej otravne vymysleť jak to zapatchuvať.
Času na vymyslení runtime patchera neni toľko. Zároveň nestem volačo, kde by človek mosel volačo inštaluvať alebo vymýšlať sprostosti navyše. Voláky alternatívny launcher s patchuvaním je ťéž možnosť, ale to sa mi čil nestelo robiť.
Nakonec som skončeu na tom, že sa spraví clientside patcher s javascriptom. Proste HTMLko v kerom je file picker, políčka na rozlíšení a čudel na patch. Ono takto, ja človek, kerý z duše nerád javascriptuje by sa zrazu išóv púšťať do takéhoto volačoho? Nezdá sa to, ja vím. Ale raz v živote to skúsiť treba.
Vyskladal som teda jednoduchý patcher kerý dynamicky v binárke nájde presne hentú očakávanú časť inštrukcií, vyráta rozlíšení na 32bitový int kerý zároveň dá do little endianity aby v tom nebol bordel. Toto šecko poskladá, narve do binárky a dá ju človeku naspák sťáhnuť. Samozrejme čisto clientside vec, žádne serverové patchuvaní, žádne veci naokolo. Robiť to serverovo by postrádalo jakýkoľvek zmysel a na druhej strane by to aj sprostosť bola také volačo celkovo robiť.
Patcher si našóv teda svoje místo a meno, game_executable_patcher.html neh sa ľúbi.
Funkčnosť patchera bola v čase písaňá vlákna overená a funkčná na LS2008, LS2009 a LS2011, čo je o LS2008 a LS2011 vác, jak bolo póvodne plánuvané. Samozrejme patcher jako taký nejde na macOS buildoch, keďže tam tí vykompiluvané inštrukcie vyzírajú očividne mierne ináč, tak ale to neni volačo, čo by sa eventualne nedalo spraviť.
Jak to teda vyzíra?
Výsledek je fakt perfektný. Šak posúďte sami.
Samozrejme, je tam ešte furt čo vylepšuvať. Hlavne teda napríklad to, aby tí UI prvky boli naspák v krajoch.
Ale zhľadom na to, že za 15 rokov existencie hry tento patch a mód vzniká ešte len čil, tak polla mňa sa neni de toľko náhliť se šeckým.
A teda čo si zebrať na záver?
Pre ostatek ľudí jedno. Majú o mód a fix pre ich obľúbenú hru vác.
Pre mňa? Dekompiluvaní je celkom sranda, lepení týchto vecí ešte vác.
Zakál dekompiluvaní trvalo z celého vývoja najvác a bolo to zrovna to najvác vyčerpávajúce, tak nemóžem povedať že mi to do života nič nedalo. Toto priúčaní s disassemblermi pevne dúfam že svoj účel minimálne ešte raz v živote nájde.